Skip to content

Commit 21bfb4f

Browse files
committed
feat: add exchanges table
1 parent 0e35e91 commit 21bfb4f

16 files changed

+457
-117
lines changed

src/components/Counter.tsx

Lines changed: 0 additions & 16 deletions
This file was deleted.
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import { For, onCleanup, onMount } from 'solid-js';
2+
3+
import { BinanceFuturesWebsocket } from '~/exchanges/binance-futures.ws';
4+
import { BinanceSpotWebsocket } from '~/exchanges/binance-spot.ws';
5+
import { BybitFuturesv3Websocket } from '~/exchanges/bybit-futures-v3.ws';
6+
import { BybitFuturesWebsocket } from '~/exchanges/bybit-futures.ws';
7+
import { BybitSpotv1Websocket } from '~/exchanges/bybit-spot-v1.ws';
8+
import { BybitSpotv3Websocket } from '~/exchanges/bybit-spot-v3.ws';
9+
import { BybitSpotWebsocket } from '~/exchanges/bybit-spot.ws';
10+
import { OKXFuturesWebsocket } from '~/exchanges/okx-futures.ws';
11+
import { OKXSpotWebsocket } from '~/exchanges/okx-spot.ws';
12+
13+
const bybitSpot = new BybitSpotWebsocket();
14+
const bybitFutures = new BybitFuturesWebsocket();
15+
16+
const bybitFuturesv3 = new BybitFuturesv3Websocket();
17+
const bybitSpotv3 = new BybitSpotv3Websocket();
18+
19+
const bybitSpotv1 = new BybitSpotv1Websocket();
20+
21+
const binanceSpot = new BinanceSpotWebsocket();
22+
const binanceFutures = new BinanceFuturesWebsocket();
23+
24+
const okxSpot = new OKXSpotWebsocket();
25+
const okxFutures = new OKXFuturesWebsocket();
26+
27+
const LatencyTable = () => {
28+
onMount(() => {
29+
bybitSpot.connect();
30+
bybitFutures.connect();
31+
bybitFuturesv3.connect();
32+
bybitSpotv3.connect();
33+
bybitSpotv1.connect();
34+
binanceSpot.connect();
35+
binanceFutures.connect();
36+
okxSpot.connect();
37+
okxFutures.connect();
38+
});
39+
40+
onCleanup(() => {
41+
bybitSpot.close();
42+
bybitFutures.close();
43+
bybitFuturesv3.close();
44+
bybitSpotv3.close();
45+
bybitSpotv1.close();
46+
binanceSpot.close();
47+
binanceFutures.close();
48+
okxSpot.close();
49+
okxFutures.close();
50+
});
51+
52+
const exchanges = [
53+
{
54+
name: 'Bybit Spot v5',
55+
stream: 'tickers.BTCUSDT',
56+
latency: bybitSpot.latency,
57+
link: 'https://partner.bybit.com/b/safecex',
58+
},
59+
{
60+
name: 'Bybit Futures v5',
61+
stream: 'tickers.BTCUSDT',
62+
latency: bybitFutures.latency,
63+
link: 'https://partner.bybit.com/b/safecex',
64+
},
65+
{
66+
name: 'Bybit Futures v3',
67+
stream: 'tickers.BTCUSDT',
68+
latency: bybitFuturesv3.latency,
69+
link: 'https://partner.bybit.com/b/safecex',
70+
},
71+
{
72+
name: 'Bybit Spot v3',
73+
stream: 'tickers.BTCUSDT',
74+
latency: bybitSpotv3.latency,
75+
link: 'https://partner.bybit.com/b/safecex',
76+
},
77+
{
78+
name: 'Bybit Spot v1',
79+
stream: 'instrument_info.100ms.BTCUSDT',
80+
latency: bybitSpotv1.latency,
81+
link: 'https://partner.bybit.com/b/safecex',
82+
},
83+
{
84+
name: 'Binance Spot',
85+
stream: 'BTCUSDT@trade',
86+
latency: binanceSpot.latency,
87+
link: 'https://accounts.binance.com/en/register?ref=KOLLSXK0',
88+
},
89+
{
90+
name: 'Binance USD-M Futures',
91+
stream: 'BTCUSDT@trade',
92+
latency: binanceFutures.latency,
93+
link: 'https://accounts.binance.com/en/register?ref=KOLLSXK0',
94+
},
95+
{
96+
name: 'OKX Spot',
97+
stream: 'trades.BTC-USDT',
98+
latency: okxSpot.latency,
99+
link: 'https://www.okx.com/join/SAFECEX',
100+
},
101+
{
102+
name: 'OKX Futures',
103+
stream: 'trades.BTC-USDT-SWAP',
104+
latency: okxFutures.latency,
105+
link: 'https://www.okx.com/join/SAFECEX',
106+
},
107+
];
108+
109+
return (
110+
<table class="table table-auto w-[700px] mx-auto">
111+
<thead>
112+
<tr>
113+
<th class="text-left uppercase">Exchange</th>
114+
<th class="text-left uppercase">Stream</th>
115+
<th class="text-right uppercase">Latency</th>
116+
</tr>
117+
</thead>
118+
<tbody>
119+
<For each={exchanges}>
120+
{(exchange) => (
121+
<tr>
122+
<td class="text-left">
123+
<a href={exchange.link} class="border-b border-dotted">
124+
{exchange.name}
125+
</a>
126+
</td>
127+
<td class="text-left font-mono text-xs">{exchange.stream}</td>
128+
<td class="text-right font-mono">{exchange.latency()}ms</td>
129+
</tr>
130+
)}
131+
</For>
132+
</tbody>
133+
</table>
134+
);
135+
};
136+
137+
export default LatencyTable;

src/exchanges/binance-futures.ws.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { SharedWebsocket } from './shared.ws';
2+
3+
export class BinanceFuturesWebsocket extends SharedWebsocket {
4+
constructor() {
5+
super('wss://fstream.binance.com/ws');
6+
}
7+
8+
onOpen = () => {
9+
if (!this.isDisposed) {
10+
this.ws?.send?.(
11+
JSON.stringify({
12+
method: 'SUBSCRIBE',
13+
params: ['btcusdt@trade'],
14+
id: 1,
15+
})
16+
);
17+
}
18+
};
19+
20+
onMessage = ({ data }: MessageEvent) => {
21+
if (!this.isDisposed) {
22+
try {
23+
const ts = Number(data.match(/"E":(\d+)/)?.[1]);
24+
const now = Number(new Date());
25+
const diff = now - ts;
26+
this.setLatency(diff);
27+
} catch {
28+
// do nothing
29+
}
30+
}
31+
};
32+
}

src/exchanges/binance-spot.ws.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { SharedWebsocket } from './shared.ws';
2+
3+
export class BinanceSpotWebsocket extends SharedWebsocket {
4+
constructor() {
5+
super('wss://stream.binance.com/ws');
6+
}
7+
8+
onOpen = () => {
9+
if (!this.isDisposed) {
10+
this.ws?.send?.(
11+
JSON.stringify({
12+
method: 'SUBSCRIBE',
13+
params: ['btcusdt@trade'],
14+
id: 1,
15+
})
16+
);
17+
}
18+
};
19+
20+
onMessage = ({ data }: MessageEvent) => {
21+
if (!this.isDisposed) {
22+
try {
23+
const ts = Number(data.match(/"E":(\d+)/)?.[1]);
24+
const now = Number(new Date());
25+
const diff = now - ts;
26+
this.setLatency(diff);
27+
} catch {
28+
// do nothing
29+
}
30+
}
31+
};
32+
}

src/exchanges/bybit-futures-v3.ws.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { SharedWebsocket } from './shared.ws';
2+
3+
export class BybitFuturesv3Websocket extends SharedWebsocket {
4+
constructor() {
5+
super('wss://stream.bybit.com/contract/usdt/public/v3');
6+
}
7+
8+
onOpen = () => {
9+
if (!this.isDisposed) {
10+
this.ws?.send?.(
11+
JSON.stringify({ op: 'subscribe', args: ['tickers.BTCUSDT'] })
12+
);
13+
}
14+
};
15+
16+
onMessage = ({ data }: MessageEvent) => {
17+
if (!this.isDisposed) {
18+
try {
19+
const ts = Number(data.match(/"ts":(\d+)/)?.[1]);
20+
const now = Number(new Date());
21+
const diff = now - ts;
22+
this.setLatency(diff);
23+
} catch {
24+
// do nothing
25+
}
26+
}
27+
};
28+
}

src/exchanges/bybit-futures.ws.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { SharedWebsocket } from './shared.ws';
2+
3+
export class BybitFuturesWebsocket extends SharedWebsocket {
4+
constructor() {
5+
super('wss://stream.bybit.com/v5/public/linear');
6+
}
7+
8+
onOpen = () => {
9+
if (!this.isDisposed) {
10+
this.ws?.send?.(
11+
JSON.stringify({ op: 'subscribe', args: ['tickers.BTCUSDT'] })
12+
);
13+
}
14+
};
15+
16+
onMessage = ({ data }: MessageEvent) => {
17+
if (!this.isDisposed) {
18+
try {
19+
const ts = Number(data.match(/"ts":(\d+)/)?.[1]);
20+
const now = Number(new Date());
21+
const diff = now - ts;
22+
this.setLatency(diff);
23+
} catch {
24+
// do nothing
25+
}
26+
}
27+
};
28+
}

src/exchanges/bybit-spot-v1.ws.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { SharedWebsocket } from './shared.ws';
2+
3+
export class BybitSpotv1Websocket extends SharedWebsocket {
4+
constructor() {
5+
super('wss://stream.bybit.com/realtime_public');
6+
}
7+
8+
onOpen = () => {
9+
if (!this.isDisposed) {
10+
this.ws?.send?.(
11+
JSON.stringify({
12+
op: 'subscribe',
13+
args: ['instrument_info.100ms.BTCUSDT'],
14+
})
15+
);
16+
}
17+
};
18+
19+
onMessage = ({ data }: MessageEvent) => {
20+
if (!this.isDisposed) {
21+
try {
22+
const ts = Number(data.match(/"timestamp_e6":"(\d+)"/)?.[1]) / 1000;
23+
const now = Number(new Date());
24+
const diff = Math.round(now - ts);
25+
this.setLatency(diff);
26+
} catch {
27+
// do nothing
28+
}
29+
}
30+
};
31+
}

src/exchanges/bybit-spot-v3.ws.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { SharedWebsocket } from './shared.ws';
2+
3+
export class BybitSpotv3Websocket extends SharedWebsocket {
4+
constructor() {
5+
super('wss://stream-testnet.bybit.com/spot/public/v3 ');
6+
}
7+
8+
onOpen = () => {
9+
if (!this.isDisposed) {
10+
this.ws?.send?.(
11+
JSON.stringify({
12+
op: 'subscribe',
13+
args: ['tickers.BTCUSDT'],
14+
})
15+
);
16+
}
17+
};
18+
19+
onMessage = ({ data }: MessageEvent) => {
20+
if (!this.isDisposed) {
21+
try {
22+
const ts = Number(data.match(/"ts":(\d+)/)?.[1]);
23+
const now = Number(new Date());
24+
const diff = Math.round(now - ts);
25+
this.setLatency(diff);
26+
} catch {
27+
// do nothing
28+
}
29+
}
30+
};
31+
}

src/exchanges/bybit-spot.ws.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { SharedWebsocket } from './shared.ws';
2+
3+
export class BybitSpotWebsocket extends SharedWebsocket {
4+
constructor() {
5+
super('wss://stream.bybit.com/v5/public/spot');
6+
}
7+
8+
onOpen = () => {
9+
if (!this.isDisposed) {
10+
this.ws?.send?.(
11+
JSON.stringify({ op: 'subscribe', args: ['tickers.BTCUSDT'] })
12+
);
13+
}
14+
};
15+
16+
onMessage = ({ data }: MessageEvent) => {
17+
if (!this.isDisposed) {
18+
try {
19+
const ts = Number(data.match(/"ts":(\d+)/)?.[1]);
20+
const now = Number(new Date());
21+
const diff = now - ts;
22+
this.setLatency(diff);
23+
} catch {
24+
// do nothing
25+
}
26+
}
27+
};
28+
}

0 commit comments

Comments
 (0)