@xapy/orderbook 0.1.27 → 0.1.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/exchanges/binance/index.d.cts +1 -1
- package/dist/exchanges/binance/index.d.ts +1 -1
- package/dist/exchanges/bingx/index.d.cts +1 -1
- package/dist/exchanges/bingx/index.d.ts +1 -1
- package/dist/exchanges/bitget/index.d.cts +1 -1
- package/dist/exchanges/bitget/index.d.ts +1 -1
- package/dist/exchanges/bybit/index.d.cts +1 -1
- package/dist/exchanges/bybit/index.d.ts +1 -1
- package/dist/exchanges/coinex/index.d.cts +1 -1
- package/dist/exchanges/coinex/index.d.ts +1 -1
- package/dist/exchanges/deribit/index.d.cts +1 -1
- package/dist/exchanges/deribit/index.d.ts +1 -1
- package/dist/exchanges/edgex/index.d.cts +1 -1
- package/dist/exchanges/edgex/index.d.ts +1 -1
- package/dist/exchanges/gate/index.d.cts +1 -1
- package/dist/exchanges/gate/index.d.ts +1 -1
- package/dist/exchanges/hyperliquid/index.d.cts +1 -1
- package/dist/exchanges/hyperliquid/index.d.ts +1 -1
- package/dist/exchanges/kucoin/index.d.cts +1 -1
- package/dist/exchanges/kucoin/index.d.ts +1 -1
- package/dist/exchanges/lighter/index.d.cts +1 -1
- package/dist/exchanges/lighter/index.d.ts +1 -1
- package/dist/exchanges/okx/index.d.cts +1 -1
- package/dist/exchanges/okx/index.d.ts +1 -1
- package/dist/exchanges/{grvt → whitebit}/index.cjs +98 -116
- package/dist/exchanges/whitebit/index.cjs.map +1 -0
- package/dist/exchanges/whitebit/index.d.cts +57 -0
- package/dist/exchanges/whitebit/index.d.ts +57 -0
- package/dist/exchanges/{grvt → whitebit}/index.js +93 -114
- package/dist/exchanges/whitebit/index.js.map +1 -0
- package/dist/index.cjs +214 -235
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +214 -235
- package/dist/index.js.map +1 -1
- package/dist/{stream-YYPvjMV4.d.cts → stream-D8ErAue9.d.cts} +1 -1
- package/dist/{stream-YYPvjMV4.d.ts → stream-D8ErAue9.d.ts} +1 -1
- package/package.json +12 -12
- package/dist/exchanges/grvt/index.cjs.map +0 -1
- package/dist/exchanges/grvt/index.d.cts +0 -47
- package/dist/exchanges/grvt/index.d.ts +0 -47
- package/dist/exchanges/grvt/index.js.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -2714,232 +2714,6 @@ var DeribitClient = class {
|
|
|
2714
2714
|
}
|
|
2715
2715
|
};
|
|
2716
2716
|
|
|
2717
|
-
// src/exchanges/grvt/symbols.ts
|
|
2718
|
-
function toGrvtSymbol(symbol, market) {
|
|
2719
|
-
const [base, quote] = symbol.split("/");
|
|
2720
|
-
if (!base || !quote) {
|
|
2721
|
-
throw new Error(`invalid symbol "${symbol}" \u2014 expected "BASE/QUOTE"`);
|
|
2722
|
-
}
|
|
2723
|
-
if (market !== "perpetual") {
|
|
2724
|
-
throw new Error(
|
|
2725
|
-
`grvt only lists perpetuals; use "${base.toUpperCase()}/${quote.toUpperCase()}:${quote.toUpperCase()}"`
|
|
2726
|
-
);
|
|
2727
|
-
}
|
|
2728
|
-
return `${base.toUpperCase()}_${quote.toUpperCase()}_Perp`;
|
|
2729
|
-
}
|
|
2730
|
-
function fromGrvtSymbol(instrument) {
|
|
2731
|
-
const parts = instrument.split("_");
|
|
2732
|
-
const [base, quote] = parts;
|
|
2733
|
-
return base && quote ? `${base.toUpperCase()}/${quote.toUpperCase()}` : instrument;
|
|
2734
|
-
}
|
|
2735
|
-
|
|
2736
|
-
// src/exchanges/grvt/rest.ts
|
|
2737
|
-
var BASE9 = "https://market-data.grvt.io";
|
|
2738
|
-
var ALLOWED_DEPTHS2 = [10, 50, 100, 500];
|
|
2739
|
-
function snapDepth(depth) {
|
|
2740
|
-
return ALLOWED_DEPTHS2.find((d) => d >= depth) ?? ALLOWED_DEPTHS2[ALLOWED_DEPTHS2.length - 1];
|
|
2741
|
-
}
|
|
2742
|
-
function nsToMs(ns) {
|
|
2743
|
-
const n = Number(ns);
|
|
2744
|
-
return Number.isFinite(n) && n > 0 ? Math.floor(n / 1e6) : Date.now();
|
|
2745
|
-
}
|
|
2746
|
-
var toLevels = (rows) => (rows ?? []).map((l) => ({ price: Number(l.price), size: Number(l.size) }));
|
|
2747
|
-
async function fetchGrvtOrderbook(opts) {
|
|
2748
|
-
const instrument = toGrvtSymbol(opts.symbol, opts.market);
|
|
2749
|
-
const depth = snapDepth(opts.depth ?? 50);
|
|
2750
|
-
const res = await httpJson({
|
|
2751
|
-
url: `${BASE9}/full/v1/book`,
|
|
2752
|
-
method: "POST",
|
|
2753
|
-
headers: { "Content-Type": "application/json" },
|
|
2754
|
-
body: JSON.stringify({ instrument, depth }),
|
|
2755
|
-
timeoutMs: opts.timeoutMs,
|
|
2756
|
-
transformUrl: opts.transformUrl
|
|
2757
|
-
});
|
|
2758
|
-
if (!res.result) {
|
|
2759
|
-
throw new ExchangeError(
|
|
2760
|
-
"grvt",
|
|
2761
|
-
res.code ? `${res.code}: ${res.message}` : "empty orderbook response"
|
|
2762
|
-
);
|
|
2763
|
-
}
|
|
2764
|
-
const ts = nsToMs(res.result.event_time);
|
|
2765
|
-
return {
|
|
2766
|
-
exchange: "grvt",
|
|
2767
|
-
symbol: fromGrvtSymbol(res.result.instrument ?? instrument),
|
|
2768
|
-
market: opts.market,
|
|
2769
|
-
bids: toLevels(res.result.bids),
|
|
2770
|
-
asks: toLevels(res.result.asks),
|
|
2771
|
-
timestamp: ts,
|
|
2772
|
-
sequence: ts
|
|
2773
|
-
};
|
|
2774
|
-
}
|
|
2775
|
-
|
|
2776
|
-
// src/exchanges/grvt/ws.ts
|
|
2777
|
-
var WS_FULL = "wss://market-data.grvt.io/ws/full";
|
|
2778
|
-
var STREAM = "v1.book.d";
|
|
2779
|
-
function streamGrvtOrderbook(opts) {
|
|
2780
|
-
const instrument = toGrvtSymbol(opts.symbol, opts.market);
|
|
2781
|
-
const selector = `${instrument}@${opts.rate ?? 500}`;
|
|
2782
|
-
const merger = new BookMerger();
|
|
2783
|
-
let ws = null;
|
|
2784
|
-
let sock = null;
|
|
2785
|
-
let recovering = false;
|
|
2786
|
-
let awaitingFirstDelta = false;
|
|
2787
|
-
let snapshotSequence = 0;
|
|
2788
|
-
let ackSequence = null;
|
|
2789
|
-
const stream = new OrderbookStream(() => ws?.close());
|
|
2790
|
-
let nextId = 1;
|
|
2791
|
-
const subscribeIds = /* @__PURE__ */ new Set();
|
|
2792
|
-
const rpc = (method) => {
|
|
2793
|
-
const id = nextId++;
|
|
2794
|
-
sock?.send(
|
|
2795
|
-
JSON.stringify({
|
|
2796
|
-
jsonrpc: "2.0",
|
|
2797
|
-
method,
|
|
2798
|
-
params: { stream: STREAM, selectors: [selector] },
|
|
2799
|
-
id
|
|
2800
|
-
})
|
|
2801
|
-
);
|
|
2802
|
-
return id;
|
|
2803
|
-
};
|
|
2804
|
-
const subscribe = () => subscribeIds.add(rpc("subscribe"));
|
|
2805
|
-
const emit = (r) => {
|
|
2806
|
-
const book = {
|
|
2807
|
-
exchange: "grvt",
|
|
2808
|
-
symbol: fromGrvtSymbol(instrument),
|
|
2809
|
-
market: opts.market,
|
|
2810
|
-
bids: r.bids,
|
|
2811
|
-
asks: r.asks,
|
|
2812
|
-
timestamp: r.timestamp,
|
|
2813
|
-
sequence: r.sequence
|
|
2814
|
-
};
|
|
2815
|
-
stream.emit("update", book);
|
|
2816
|
-
};
|
|
2817
|
-
const resync = () => {
|
|
2818
|
-
if (recovering) return;
|
|
2819
|
-
recovering = true;
|
|
2820
|
-
merger.reset();
|
|
2821
|
-
rpc("unsubscribe");
|
|
2822
|
-
subscribe();
|
|
2823
|
-
};
|
|
2824
|
-
const buildEvent2 = (feed, seq) => {
|
|
2825
|
-
const bids = toLevels(feed.bids);
|
|
2826
|
-
const asks = toLevels(feed.asks);
|
|
2827
|
-
const timestamp = nsToMs(feed.event_time);
|
|
2828
|
-
if (seq === 0) {
|
|
2829
|
-
snapshotSequence = ackSequence ?? 0;
|
|
2830
|
-
awaitingFirstDelta = true;
|
|
2831
|
-
return {
|
|
2832
|
-
kind: "snapshot",
|
|
2833
|
-
bids,
|
|
2834
|
-
asks,
|
|
2835
|
-
sequence: snapshotSequence,
|
|
2836
|
-
timestamp
|
|
2837
|
-
};
|
|
2838
|
-
}
|
|
2839
|
-
const prevSequence = awaitingFirstDelta ? snapshotSequence : seq - 1;
|
|
2840
|
-
awaitingFirstDelta = false;
|
|
2841
|
-
return { kind: "delta", bids, asks, sequence: seq, prevSequence, timestamp };
|
|
2842
|
-
};
|
|
2843
|
-
const handleFeed = (msg) => {
|
|
2844
|
-
if (!msg.feed) return;
|
|
2845
|
-
const seq = Number(msg.sequence_number ?? 0);
|
|
2846
|
-
if (!Number.isFinite(seq)) return;
|
|
2847
|
-
if (seq === 0) recovering = false;
|
|
2848
|
-
else if (recovering) return;
|
|
2849
|
-
const r = merger.apply(buildEvent2(msg.feed, seq));
|
|
2850
|
-
if (r.ok) {
|
|
2851
|
-
emit(r);
|
|
2852
|
-
} else if (r.reason === "gap" || r.reason === "no-snapshot") {
|
|
2853
|
-
resync();
|
|
2854
|
-
}
|
|
2855
|
-
};
|
|
2856
|
-
const onMessage = (raw) => {
|
|
2857
|
-
if (typeof raw !== "string") return;
|
|
2858
|
-
let msg;
|
|
2859
|
-
try {
|
|
2860
|
-
msg = JSON.parse(raw);
|
|
2861
|
-
} catch {
|
|
2862
|
-
return;
|
|
2863
|
-
}
|
|
2864
|
-
if (msg.feed) {
|
|
2865
|
-
if (msg.selector && msg.selector !== selector) return;
|
|
2866
|
-
handleFeed(msg);
|
|
2867
|
-
return;
|
|
2868
|
-
}
|
|
2869
|
-
if (msg.id === void 0) return;
|
|
2870
|
-
if (msg.error) {
|
|
2871
|
-
stream.emit(
|
|
2872
|
-
"error",
|
|
2873
|
-
new ExchangeError("grvt", `${msg.error.code}: ${msg.error.message}`)
|
|
2874
|
-
);
|
|
2875
|
-
return;
|
|
2876
|
-
}
|
|
2877
|
-
if (subscribeIds.delete(msg.id)) {
|
|
2878
|
-
const subs = msg.result?.subs ?? [];
|
|
2879
|
-
const latest = Number(msg.result?.latest_sequence_number?.[0]);
|
|
2880
|
-
ackSequence = Number.isFinite(latest) ? latest : null;
|
|
2881
|
-
if (!subs.includes(selector)) {
|
|
2882
|
-
stream.emit(
|
|
2883
|
-
"error",
|
|
2884
|
-
new ExchangeError(
|
|
2885
|
-
"grvt",
|
|
2886
|
-
`subscribe rejected for "${STREAM}" selector "${selector}"`
|
|
2887
|
-
)
|
|
2888
|
-
);
|
|
2889
|
-
}
|
|
2890
|
-
}
|
|
2891
|
-
};
|
|
2892
|
-
ws = new WSClient({
|
|
2893
|
-
url: WS_FULL,
|
|
2894
|
-
onOpen: (handle) => {
|
|
2895
|
-
sock = handle;
|
|
2896
|
-
merger.reset();
|
|
2897
|
-
recovering = false;
|
|
2898
|
-
awaitingFirstDelta = false;
|
|
2899
|
-
subscribeIds.clear();
|
|
2900
|
-
subscribe();
|
|
2901
|
-
},
|
|
2902
|
-
onMessage
|
|
2903
|
-
});
|
|
2904
|
-
ws.on("open", () => stream.emit("connected"));
|
|
2905
|
-
ws.on("close", (r) => stream.emit("disconnected", r));
|
|
2906
|
-
ws.on("reconnecting", (a, w) => stream.emit("reconnecting", a, w));
|
|
2907
|
-
ws.on("error", (e) => stream.emit("error", e));
|
|
2908
|
-
ws.connect().catch((e) => stream.emit("error", e));
|
|
2909
|
-
return stream;
|
|
2910
|
-
}
|
|
2911
|
-
|
|
2912
|
-
// src/exchanges/grvt/index.ts
|
|
2913
|
-
var GrvtClient = class {
|
|
2914
|
-
exchange = "grvt";
|
|
2915
|
-
transformUrl;
|
|
2916
|
-
timeoutMs;
|
|
2917
|
-
constructor(opts = {}) {
|
|
2918
|
-
this.transformUrl = opts.transformUrl;
|
|
2919
|
-
this.timeoutMs = opts.timeoutMs;
|
|
2920
|
-
}
|
|
2921
|
-
fetchOrderbook(symbol, opts = {}) {
|
|
2922
|
-
const { pair, market } = parseSymbol(symbol);
|
|
2923
|
-
return fetchGrvtOrderbook({
|
|
2924
|
-
symbol: pair,
|
|
2925
|
-
market,
|
|
2926
|
-
depth: opts.depth,
|
|
2927
|
-
timeoutMs: this.timeoutMs,
|
|
2928
|
-
transformUrl: this.transformUrl
|
|
2929
|
-
});
|
|
2930
|
-
}
|
|
2931
|
-
streamOrderbook(symbol, opts = {}) {
|
|
2932
|
-
const { pair, market } = parseSymbol(symbol);
|
|
2933
|
-
return streamGrvtOrderbook({
|
|
2934
|
-
symbol: pair,
|
|
2935
|
-
market,
|
|
2936
|
-
depth: opts.depth,
|
|
2937
|
-
transformUrl: this.transformUrl,
|
|
2938
|
-
timeoutMs: this.timeoutMs
|
|
2939
|
-
});
|
|
2940
|
-
}
|
|
2941
|
-
};
|
|
2942
|
-
|
|
2943
2717
|
// src/exchanges/lighter/markets.ts
|
|
2944
2718
|
var LIGHTER_REST = "https://mainnet.zklighter.elliot.ai";
|
|
2945
2719
|
var cache = null;
|
|
@@ -3065,7 +2839,7 @@ async function fetchLighterOrderbook(opts) {
|
|
|
3065
2839
|
// src/exchanges/lighter/ws.ts
|
|
3066
2840
|
var WS_URL2 = "wss://mainnet.zklighter.elliot.ai/stream";
|
|
3067
2841
|
var PING_INTERVAL_MS = 6e4;
|
|
3068
|
-
var
|
|
2842
|
+
var toLevels = (rows) => (rows ?? []).map((l) => ({ price: Number(l.price), size: Number(l.size) }));
|
|
3069
2843
|
function streamLighterOrderbook(opts) {
|
|
3070
2844
|
const name = toLighterSymbol(opts.symbol, opts.market);
|
|
3071
2845
|
const symbol = fromLighterSymbol(name);
|
|
@@ -3104,8 +2878,8 @@ function streamLighterOrderbook(opts) {
|
|
|
3104
2878
|
};
|
|
3105
2879
|
const buildEvent2 = (msg, snapshot) => {
|
|
3106
2880
|
const ob = msg.order_book ?? {};
|
|
3107
|
-
const bids =
|
|
3108
|
-
const asks =
|
|
2881
|
+
const bids = toLevels(ob.bids);
|
|
2882
|
+
const asks = toLevels(ob.asks);
|
|
3109
2883
|
const timestamp = msg.timestamp ?? usToMs(ob.last_updated_at);
|
|
3110
2884
|
const sequence = Number(ob.nonce ?? 0);
|
|
3111
2885
|
return snapshot ? { kind: "snapshot", bids, asks, sequence, timestamp } : {
|
|
@@ -3284,7 +3058,7 @@ var ALLOWED_LEVELS = [15, 200];
|
|
|
3284
3058
|
function snapLevel(depth) {
|
|
3285
3059
|
return ALLOWED_LEVELS.find((l) => l >= depth) ?? ALLOWED_LEVELS[ALLOWED_LEVELS.length - 1];
|
|
3286
3060
|
}
|
|
3287
|
-
var
|
|
3061
|
+
var toLevels2 = (rows) => (rows ?? []).map((l) => ({ price: Number(l.price), size: Number(l.size) }));
|
|
3288
3062
|
async function fetchEdgexOrderbook(opts) {
|
|
3289
3063
|
const contractName = toEdgexSymbol(opts.symbol, opts.market);
|
|
3290
3064
|
const contract = await resolveEdgexContract(contractName, opts);
|
|
@@ -3306,8 +3080,8 @@ async function fetchEdgexOrderbook(opts) {
|
|
|
3306
3080
|
exchange: "edgex",
|
|
3307
3081
|
symbol: fromEdgexSymbol(depth.contractName ?? contractName),
|
|
3308
3082
|
market: opts.market,
|
|
3309
|
-
bids:
|
|
3310
|
-
asks:
|
|
3083
|
+
bids: toLevels2(depth.bids),
|
|
3084
|
+
asks: toLevels2(depth.asks),
|
|
3311
3085
|
timestamp,
|
|
3312
3086
|
sequence: Number(depth.endVersion ?? 0)
|
|
3313
3087
|
};
|
|
@@ -3353,8 +3127,8 @@ function streamEdgexOrderbook(opts) {
|
|
|
3353
3127
|
send("subscribe");
|
|
3354
3128
|
};
|
|
3355
3129
|
const buildEvent2 = (d, snapshot) => {
|
|
3356
|
-
const bids =
|
|
3357
|
-
const asks =
|
|
3130
|
+
const bids = toLevels2(d.bids);
|
|
3131
|
+
const asks = toLevels2(d.asks);
|
|
3358
3132
|
const timestamp = Date.now();
|
|
3359
3133
|
const sequence = Number(d.endVersion ?? 0);
|
|
3360
3134
|
return snapshot ? { kind: "snapshot", bids, asks, sequence, timestamp } : {
|
|
@@ -3458,6 +3232,211 @@ var EdgexClient = class {
|
|
|
3458
3232
|
}
|
|
3459
3233
|
};
|
|
3460
3234
|
|
|
3235
|
+
// src/exchanges/whitebit/symbols.ts
|
|
3236
|
+
function toWhitebitSymbol(symbol, market) {
|
|
3237
|
+
const [base, quote] = symbol.split("/");
|
|
3238
|
+
if (!base || !quote) {
|
|
3239
|
+
throw new Error(`invalid symbol "${symbol}" \u2014 expected "BASE/QUOTE"`);
|
|
3240
|
+
}
|
|
3241
|
+
if (market === "perpetual") {
|
|
3242
|
+
if (quote.toUpperCase() !== "USDT") {
|
|
3243
|
+
throw new Error(
|
|
3244
|
+
`whitebit perpetuals are USDT-margined; got "${quote}"`
|
|
3245
|
+
);
|
|
3246
|
+
}
|
|
3247
|
+
return `${base.toUpperCase()}_PERP`;
|
|
3248
|
+
}
|
|
3249
|
+
return `${base.toUpperCase()}_${quote.toUpperCase()}`;
|
|
3250
|
+
}
|
|
3251
|
+
function fromWhitebitSymbol(market) {
|
|
3252
|
+
const name = market.toUpperCase();
|
|
3253
|
+
if (name.endsWith("_PERP")) return `${name.slice(0, -5)}/USDT`;
|
|
3254
|
+
const [base, quote] = name.split("_");
|
|
3255
|
+
return base && quote ? `${base}/${quote}` : name;
|
|
3256
|
+
}
|
|
3257
|
+
|
|
3258
|
+
// src/exchanges/whitebit/rest.ts
|
|
3259
|
+
var WHITEBIT_REST = "https://whitebit.com";
|
|
3260
|
+
var MAX_REST_LIMIT = 100;
|
|
3261
|
+
function secToMs(sec) {
|
|
3262
|
+
return Number.isFinite(sec) && sec > 0 ? Math.round(sec * 1e3) : Date.now();
|
|
3263
|
+
}
|
|
3264
|
+
var toLevels3 = (rows) => (rows ?? []).map(([price, size]) => ({
|
|
3265
|
+
price: Number(price),
|
|
3266
|
+
size: Number(size)
|
|
3267
|
+
}));
|
|
3268
|
+
async function fetchWhitebitOrderbook(opts) {
|
|
3269
|
+
const market = toWhitebitSymbol(opts.symbol, opts.market);
|
|
3270
|
+
const limit = Math.min(opts.depth ?? 50, MAX_REST_LIMIT);
|
|
3271
|
+
const res = await httpJson({
|
|
3272
|
+
url: `${WHITEBIT_REST}/api/v4/public/orderbook/${market}?limit=${limit}`,
|
|
3273
|
+
timeoutMs: opts.timeoutMs,
|
|
3274
|
+
transformUrl: opts.transformUrl
|
|
3275
|
+
});
|
|
3276
|
+
if (!res.asks && !res.bids) {
|
|
3277
|
+
const detail = res.message ?? (res.errors ? JSON.stringify(res.errors) : "empty orderbook response");
|
|
3278
|
+
throw new ExchangeError("whitebit", detail);
|
|
3279
|
+
}
|
|
3280
|
+
const timestamp = secToMs(res.timestamp);
|
|
3281
|
+
return {
|
|
3282
|
+
exchange: "whitebit",
|
|
3283
|
+
symbol: fromWhitebitSymbol(res.ticker_id ?? market),
|
|
3284
|
+
market: opts.market,
|
|
3285
|
+
bids: toLevels3(res.bids),
|
|
3286
|
+
asks: toLevels3(res.asks),
|
|
3287
|
+
timestamp,
|
|
3288
|
+
// REST publishes no `update_id`; the WS chain is where ordering is enforced.
|
|
3289
|
+
sequence: timestamp
|
|
3290
|
+
};
|
|
3291
|
+
}
|
|
3292
|
+
|
|
3293
|
+
// src/exchanges/whitebit/ws.ts
|
|
3294
|
+
var WS_URL4 = "wss://api.whitebit.com/ws";
|
|
3295
|
+
var PING_INTERVAL_MS2 = 5e4;
|
|
3296
|
+
var ALLOWED_LIMITS = [1, 5, 10, 20, 30, 50, 100];
|
|
3297
|
+
function snapLimit(depth) {
|
|
3298
|
+
return ALLOWED_LIMITS.find((l) => l >= depth) ?? ALLOWED_LIMITS[ALLOWED_LIMITS.length - 1];
|
|
3299
|
+
}
|
|
3300
|
+
function streamWhitebitOrderbook(opts) {
|
|
3301
|
+
const market = toWhitebitSymbol(opts.symbol, opts.market);
|
|
3302
|
+
const symbol = fromWhitebitSymbol(market);
|
|
3303
|
+
const limit = snapLimit(opts.depth ?? 50);
|
|
3304
|
+
const merger = new BookMerger();
|
|
3305
|
+
let ws = null;
|
|
3306
|
+
let sock = null;
|
|
3307
|
+
let recovering = false;
|
|
3308
|
+
const stream = new OrderbookStream(() => ws?.close());
|
|
3309
|
+
let nextId = 1;
|
|
3310
|
+
const subscribeIds = /* @__PURE__ */ new Set();
|
|
3311
|
+
const call = (method, params) => {
|
|
3312
|
+
const id = nextId++;
|
|
3313
|
+
sock?.send(JSON.stringify({ id, method, params }));
|
|
3314
|
+
return id;
|
|
3315
|
+
};
|
|
3316
|
+
const subscribe = () => {
|
|
3317
|
+
subscribeIds.add(call("depth_subscribe", [market, limit, "0", true]));
|
|
3318
|
+
};
|
|
3319
|
+
const emit = (r) => {
|
|
3320
|
+
const book = {
|
|
3321
|
+
exchange: "whitebit",
|
|
3322
|
+
symbol,
|
|
3323
|
+
market: opts.market,
|
|
3324
|
+
bids: r.bids,
|
|
3325
|
+
asks: r.asks,
|
|
3326
|
+
timestamp: r.timestamp,
|
|
3327
|
+
sequence: r.sequence
|
|
3328
|
+
};
|
|
3329
|
+
stream.emit("update", book);
|
|
3330
|
+
};
|
|
3331
|
+
const resync = () => {
|
|
3332
|
+
if (recovering) return;
|
|
3333
|
+
recovering = true;
|
|
3334
|
+
merger.reset();
|
|
3335
|
+
call("depth_unsubscribe", []);
|
|
3336
|
+
subscribe();
|
|
3337
|
+
};
|
|
3338
|
+
const buildEvent2 = (d, snapshot) => {
|
|
3339
|
+
const bids = toLevels3(d.bids);
|
|
3340
|
+
const asks = toLevels3(d.asks);
|
|
3341
|
+
const timestamp = secToMs(d.timestamp ?? d.event_time);
|
|
3342
|
+
const sequence = Number(d.update_id ?? 0);
|
|
3343
|
+
return snapshot ? { kind: "snapshot", bids, asks, sequence, timestamp } : {
|
|
3344
|
+
kind: "delta",
|
|
3345
|
+
bids,
|
|
3346
|
+
asks,
|
|
3347
|
+
sequence,
|
|
3348
|
+
prevSequence: Number(d.past_update_id ?? 0),
|
|
3349
|
+
timestamp
|
|
3350
|
+
};
|
|
3351
|
+
};
|
|
3352
|
+
const handleDepth = (d, snapshot) => {
|
|
3353
|
+
if (snapshot) recovering = false;
|
|
3354
|
+
else if (recovering) return;
|
|
3355
|
+
const r = merger.apply(buildEvent2(d, snapshot));
|
|
3356
|
+
if (r.ok) {
|
|
3357
|
+
emit(r);
|
|
3358
|
+
} else if (r.reason === "gap" || r.reason === "no-snapshot") {
|
|
3359
|
+
resync();
|
|
3360
|
+
}
|
|
3361
|
+
};
|
|
3362
|
+
const onMessage = (raw) => {
|
|
3363
|
+
if (typeof raw !== "string") return;
|
|
3364
|
+
let msg;
|
|
3365
|
+
try {
|
|
3366
|
+
msg = JSON.parse(raw);
|
|
3367
|
+
} catch {
|
|
3368
|
+
return;
|
|
3369
|
+
}
|
|
3370
|
+
if (msg.method === "depth_update") {
|
|
3371
|
+
const [snapshot, data, frameMarket] = msg.params ?? [];
|
|
3372
|
+
if (!data || frameMarket && frameMarket !== market) return;
|
|
3373
|
+
handleDepth(data, snapshot === true);
|
|
3374
|
+
return;
|
|
3375
|
+
}
|
|
3376
|
+
if (msg.error) {
|
|
3377
|
+
stream.emit(
|
|
3378
|
+
"error",
|
|
3379
|
+
new ExchangeError(
|
|
3380
|
+
"whitebit",
|
|
3381
|
+
`${msg.error.code}: ${msg.error.message}`
|
|
3382
|
+
)
|
|
3383
|
+
);
|
|
3384
|
+
return;
|
|
3385
|
+
}
|
|
3386
|
+
if (typeof msg.id === "number") subscribeIds.delete(msg.id);
|
|
3387
|
+
};
|
|
3388
|
+
ws = new WSClient({
|
|
3389
|
+
url: WS_URL4,
|
|
3390
|
+
onOpen: (handle) => {
|
|
3391
|
+
sock = handle;
|
|
3392
|
+
merger.reset();
|
|
3393
|
+
recovering = false;
|
|
3394
|
+
subscribeIds.clear();
|
|
3395
|
+
subscribe();
|
|
3396
|
+
},
|
|
3397
|
+
onMessage,
|
|
3398
|
+
pingIntervalMs: PING_INTERVAL_MS2,
|
|
3399
|
+
pingPayload: () => JSON.stringify({ id: 0, method: "ping", params: [] })
|
|
3400
|
+
});
|
|
3401
|
+
ws.on("open", () => stream.emit("connected"));
|
|
3402
|
+
ws.on("close", (r) => stream.emit("disconnected", r));
|
|
3403
|
+
ws.on("reconnecting", (a, w) => stream.emit("reconnecting", a, w));
|
|
3404
|
+
ws.on("error", (e) => stream.emit("error", e));
|
|
3405
|
+
ws.connect().catch((e) => stream.emit("error", e));
|
|
3406
|
+
return stream;
|
|
3407
|
+
}
|
|
3408
|
+
|
|
3409
|
+
// src/exchanges/whitebit/index.ts
|
|
3410
|
+
var WhitebitClient = class {
|
|
3411
|
+
exchange = "whitebit";
|
|
3412
|
+
transformUrl;
|
|
3413
|
+
timeoutMs;
|
|
3414
|
+
constructor(opts = {}) {
|
|
3415
|
+
this.transformUrl = opts.transformUrl;
|
|
3416
|
+
this.timeoutMs = opts.timeoutMs;
|
|
3417
|
+
}
|
|
3418
|
+
fetchOrderbook(symbol, opts = {}) {
|
|
3419
|
+
const { pair, market } = parseSymbol(symbol);
|
|
3420
|
+
return fetchWhitebitOrderbook({
|
|
3421
|
+
symbol: pair,
|
|
3422
|
+
market,
|
|
3423
|
+
depth: opts.depth,
|
|
3424
|
+
timeoutMs: this.timeoutMs,
|
|
3425
|
+
transformUrl: this.transformUrl
|
|
3426
|
+
});
|
|
3427
|
+
}
|
|
3428
|
+
streamOrderbook(symbol, opts = {}) {
|
|
3429
|
+
const { pair, market } = parseSymbol(symbol);
|
|
3430
|
+
return streamWhitebitOrderbook({
|
|
3431
|
+
symbol: pair,
|
|
3432
|
+
market,
|
|
3433
|
+
depth: opts.depth,
|
|
3434
|
+
transformUrl: this.transformUrl,
|
|
3435
|
+
timeoutMs: this.timeoutMs
|
|
3436
|
+
});
|
|
3437
|
+
}
|
|
3438
|
+
};
|
|
3439
|
+
|
|
3461
3440
|
exports.Backoff = Backoff;
|
|
3462
3441
|
exports.BinanceClient = BinanceClient;
|
|
3463
3442
|
exports.BingxClient = BingxClient;
|
|
@@ -3469,7 +3448,6 @@ exports.DeribitClient = DeribitClient;
|
|
|
3469
3448
|
exports.EdgexClient = EdgexClient;
|
|
3470
3449
|
exports.ExchangeError = ExchangeError;
|
|
3471
3450
|
exports.GateClient = GateClient;
|
|
3472
|
-
exports.GrvtClient = GrvtClient;
|
|
3473
3451
|
exports.HyperliquidClient = HyperliquidClient;
|
|
3474
3452
|
exports.KucoinClient = KucoinClient;
|
|
3475
3453
|
exports.LighterClient = LighterClient;
|
|
@@ -3477,6 +3455,7 @@ exports.OkxClient = OkxClient;
|
|
|
3477
3455
|
exports.OrderbookStream = OrderbookStream;
|
|
3478
3456
|
exports.RateLimitError = RateLimitError;
|
|
3479
3457
|
exports.SequenceGapError = SequenceGapError;
|
|
3458
|
+
exports.WhitebitClient = WhitebitClient;
|
|
3480
3459
|
exports.parseSymbol = parseSymbol;
|
|
3481
3460
|
//# sourceMappingURL=index.cjs.map
|
|
3482
3461
|
//# sourceMappingURL=index.cjs.map
|