@xapy/orderbook 0.1.1 → 0.1.3
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/dist/exchanges/bingx/index.cjs +5 -8
- package/dist/exchanges/bingx/index.cjs.map +1 -1
- package/dist/exchanges/bingx/index.d.cts +3 -0
- package/dist/exchanges/bingx/index.d.ts +3 -0
- package/dist/exchanges/bingx/index.js +5 -8
- package/dist/exchanges/bingx/index.js.map +1 -1
- package/dist/exchanges/gate/index.cjs +139 -31
- package/dist/exchanges/gate/index.cjs.map +1 -1
- package/dist/exchanges/gate/index.d.cts +7 -14
- package/dist/exchanges/gate/index.d.ts +7 -14
- package/dist/exchanges/gate/index.js +139 -31
- package/dist/exchanges/gate/index.js.map +1 -1
- package/dist/index.cjs +144 -39
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +144 -39
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -847,9 +847,131 @@ function parseObjectLevels(rows) {
|
|
|
847
847
|
var WS_SPOT2 = "wss://api.gateio.ws/ws/v4/";
|
|
848
848
|
var WS_FUTURES = "wss://fx-ws.gateio.ws/v4/ws/usdt";
|
|
849
849
|
function streamGateOrderbook(opts) {
|
|
850
|
-
|
|
850
|
+
return opts.market === "perpetual" ? streamGateFuturesObu(opts) : streamGateSpot(opts);
|
|
851
|
+
}
|
|
852
|
+
function streamGateFuturesObu(opts) {
|
|
853
|
+
const gateSymbol = toGateSymbol(opts.symbol);
|
|
854
|
+
const level = snapFuturesLevel(opts.depth ?? 50);
|
|
855
|
+
const streamName = `ob.${gateSymbol}.${level}`;
|
|
856
|
+
const merger = new BookMerger();
|
|
857
|
+
let lastU = -1;
|
|
858
|
+
let ws = null;
|
|
859
|
+
const stream = new OrderbookStream(() => ws?.close());
|
|
860
|
+
const wsMsg = (event) => JSON.stringify({
|
|
861
|
+
time: Math.floor(Date.now() / 1e3),
|
|
862
|
+
channel: "futures.obu",
|
|
863
|
+
event,
|
|
864
|
+
payload: [streamName]
|
|
865
|
+
});
|
|
866
|
+
const pingMsg = () => JSON.stringify({
|
|
867
|
+
time: Math.floor(Date.now() / 1e3),
|
|
868
|
+
channel: "futures.ping"
|
|
869
|
+
});
|
|
870
|
+
const emitBook = (bids, asks, sequence, timestamp) => {
|
|
871
|
+
const book = {
|
|
872
|
+
exchange: "gate",
|
|
873
|
+
symbol: fromGateSymbol(gateSymbol),
|
|
874
|
+
market: "perpetual",
|
|
875
|
+
bids,
|
|
876
|
+
asks,
|
|
877
|
+
timestamp,
|
|
878
|
+
sequence
|
|
879
|
+
};
|
|
880
|
+
stream.emit("update", book);
|
|
881
|
+
};
|
|
882
|
+
const resubscribe = () => {
|
|
883
|
+
if (!ws) return;
|
|
884
|
+
merger.reset();
|
|
885
|
+
lastU = -1;
|
|
886
|
+
try {
|
|
887
|
+
ws.send(wsMsg("unsubscribe"));
|
|
888
|
+
ws.send(wsMsg("subscribe"));
|
|
889
|
+
} catch (err) {
|
|
890
|
+
stream.emit("error", err);
|
|
891
|
+
}
|
|
892
|
+
};
|
|
893
|
+
const processFrame = (frame) => {
|
|
894
|
+
const bids = parseObuLevels(frame.b);
|
|
895
|
+
const asks = parseObuLevels(frame.a);
|
|
896
|
+
if (frame.full) {
|
|
897
|
+
const r2 = merger.apply({
|
|
898
|
+
kind: "snapshot",
|
|
899
|
+
bids,
|
|
900
|
+
asks,
|
|
901
|
+
sequence: frame.u,
|
|
902
|
+
timestamp: frame.t
|
|
903
|
+
});
|
|
904
|
+
lastU = frame.u;
|
|
905
|
+
if (r2.ok) emitBook(r2.bids, r2.asks, r2.sequence, r2.timestamp);
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
if (!merger.isReady() || lastU < 0 || frame.U === void 0) return;
|
|
909
|
+
if (frame.u <= lastU) return;
|
|
910
|
+
if (frame.U !== lastU + 1) {
|
|
911
|
+
resubscribe();
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
914
|
+
const r = merger.apply({
|
|
915
|
+
kind: "delta",
|
|
916
|
+
bids,
|
|
917
|
+
asks,
|
|
918
|
+
sequence: frame.u,
|
|
919
|
+
prevSequence: lastU,
|
|
920
|
+
timestamp: frame.t
|
|
921
|
+
});
|
|
922
|
+
if (r.ok) {
|
|
923
|
+
lastU = frame.u;
|
|
924
|
+
emitBook(r.bids, r.asks, r.sequence, r.timestamp);
|
|
925
|
+
} else if (r.reason === "gap") {
|
|
926
|
+
resubscribe();
|
|
927
|
+
}
|
|
928
|
+
};
|
|
929
|
+
const onMessage = (raw) => {
|
|
930
|
+
if (typeof raw !== "string") return;
|
|
931
|
+
let msg;
|
|
932
|
+
try {
|
|
933
|
+
msg = JSON.parse(raw);
|
|
934
|
+
} catch {
|
|
935
|
+
return;
|
|
936
|
+
}
|
|
937
|
+
if (msg.error) {
|
|
938
|
+
stream.emit("error", new Error(`gate: ${msg.error.message}`));
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
if (msg.channel !== "futures.obu") return;
|
|
942
|
+
if (msg.event === "subscribe" || msg.event === "unsubscribe") return;
|
|
943
|
+
if (msg.event !== "update" || !msg.result) return;
|
|
944
|
+
processFrame(msg.result);
|
|
945
|
+
};
|
|
946
|
+
ws = new WSClient({
|
|
947
|
+
url: WS_FUTURES,
|
|
948
|
+
onOpen: (sock) => {
|
|
949
|
+
merger.reset();
|
|
950
|
+
lastU = -1;
|
|
951
|
+
sock.send(wsMsg("subscribe"));
|
|
952
|
+
},
|
|
953
|
+
onMessage,
|
|
954
|
+
pingIntervalMs: 15e3,
|
|
955
|
+
pingPayload: pingMsg
|
|
956
|
+
});
|
|
957
|
+
ws.on("open", () => stream.emit("connected"));
|
|
958
|
+
ws.on("close", (r) => stream.emit("disconnected", r));
|
|
959
|
+
ws.on("reconnecting", (a, w) => stream.emit("reconnecting", a, w));
|
|
960
|
+
ws.on("error", (e) => stream.emit("error", e));
|
|
961
|
+
ws.connect().catch((e) => stream.emit("error", e));
|
|
962
|
+
return stream;
|
|
963
|
+
}
|
|
964
|
+
function snapFuturesLevel(depth) {
|
|
965
|
+
return depth <= 50 ? 50 : 400;
|
|
966
|
+
}
|
|
967
|
+
function parseObuLevels(rows) {
|
|
968
|
+
if (!rows) return [];
|
|
969
|
+
const out = [];
|
|
970
|
+
for (const [p, s] of rows) out.push({ price: Number(p), size: Number(s) });
|
|
971
|
+
return out;
|
|
972
|
+
}
|
|
973
|
+
function streamGateSpot(opts) {
|
|
851
974
|
const gateSymbol = toGateSymbol(opts.symbol);
|
|
852
|
-
const channel = isFutures ? "futures.order_book_update" : "spot.order_book_update";
|
|
853
975
|
const interval = `${opts.intervalMs ?? 100}ms`;
|
|
854
976
|
const depth = String(opts.depth ?? 100);
|
|
855
977
|
const merger = new BookMerger();
|
|
@@ -861,22 +983,21 @@ function streamGateOrderbook(opts) {
|
|
|
861
983
|
let recovering = false;
|
|
862
984
|
let ws = null;
|
|
863
985
|
const stream = new OrderbookStream(() => ws?.close());
|
|
864
|
-
const payload = isFutures ? [gateSymbol, interval, depth] : [gateSymbol, depth, interval];
|
|
865
986
|
const subscribeMsg = () => JSON.stringify({
|
|
866
987
|
time: Math.floor(Date.now() / 1e3),
|
|
867
|
-
channel,
|
|
988
|
+
channel: "spot.order_book_update",
|
|
868
989
|
event: "subscribe",
|
|
869
|
-
payload
|
|
990
|
+
payload: [gateSymbol, depth, interval]
|
|
870
991
|
});
|
|
871
992
|
const pingMsg = () => JSON.stringify({
|
|
872
993
|
time: Math.floor(Date.now() / 1e3),
|
|
873
|
-
channel:
|
|
994
|
+
channel: "spot.ping"
|
|
874
995
|
});
|
|
875
996
|
const emitBook = (bids, asks, sequence, timestamp) => {
|
|
876
997
|
const book = {
|
|
877
998
|
exchange: "gate",
|
|
878
999
|
symbol: fromGateSymbol(gateSymbol),
|
|
879
|
-
market:
|
|
1000
|
+
market: "spot",
|
|
880
1001
|
bids,
|
|
881
1002
|
asks,
|
|
882
1003
|
timestamp,
|
|
@@ -889,7 +1010,7 @@ function streamGateOrderbook(opts) {
|
|
|
889
1010
|
snapshotInFlight = true;
|
|
890
1011
|
fetchGateOrderbook({
|
|
891
1012
|
symbol: opts.symbol,
|
|
892
|
-
market:
|
|
1013
|
+
market: "spot",
|
|
893
1014
|
depth: opts.depth ?? 100,
|
|
894
1015
|
timeoutMs: opts.timeoutMs,
|
|
895
1016
|
transformUrl: opts.transformUrl
|
|
@@ -965,9 +1086,16 @@ function streamGateOrderbook(opts) {
|
|
|
965
1086
|
stream.emit("error", new Error(`gate: ${msg.error.message}`));
|
|
966
1087
|
return;
|
|
967
1088
|
}
|
|
968
|
-
if (msg.channel !==
|
|
1089
|
+
if (msg.channel !== "spot.order_book_update" || !msg.result) return;
|
|
969
1090
|
if (msg.event !== "update") return;
|
|
970
|
-
const
|
|
1091
|
+
const r = msg.result;
|
|
1092
|
+
const ev = {
|
|
1093
|
+
U: r.U,
|
|
1094
|
+
u: r.u,
|
|
1095
|
+
t: r.t,
|
|
1096
|
+
bids: r.b.map(([p, s]) => ({ price: Number(p), size: Number(s) })),
|
|
1097
|
+
asks: r.a.map(([p, s]) => ({ price: Number(p), size: Number(s) }))
|
|
1098
|
+
};
|
|
971
1099
|
if (!snapshotDone) {
|
|
972
1100
|
buffered.push(ev);
|
|
973
1101
|
if (!snapshotInFlight) triggerSnapshot();
|
|
@@ -976,7 +1104,7 @@ function streamGateOrderbook(opts) {
|
|
|
976
1104
|
processDelta(ev);
|
|
977
1105
|
};
|
|
978
1106
|
ws = new WSClient({
|
|
979
|
-
url:
|
|
1107
|
+
url: WS_SPOT2,
|
|
980
1108
|
onOpen: (sock) => {
|
|
981
1109
|
merger.reset();
|
|
982
1110
|
snapshotSequence = -1;
|
|
@@ -996,26 +1124,6 @@ function streamGateOrderbook(opts) {
|
|
|
996
1124
|
ws.connect().catch((e) => stream.emit("error", e));
|
|
997
1125
|
return stream;
|
|
998
1126
|
}
|
|
999
|
-
function normalize(ev, isFutures) {
|
|
1000
|
-
if (isFutures) {
|
|
1001
|
-
const f = ev;
|
|
1002
|
-
return {
|
|
1003
|
-
U: f.U,
|
|
1004
|
-
u: f.u,
|
|
1005
|
-
t: f.t,
|
|
1006
|
-
bids: f.b.map((row) => ({ price: Number(row.p), size: Number(row.s) })),
|
|
1007
|
-
asks: f.a.map((row) => ({ price: Number(row.p), size: Number(row.s) }))
|
|
1008
|
-
};
|
|
1009
|
-
}
|
|
1010
|
-
const s = ev;
|
|
1011
|
-
return {
|
|
1012
|
-
U: s.U,
|
|
1013
|
-
u: s.u,
|
|
1014
|
-
t: s.t,
|
|
1015
|
-
bids: s.b.map(([p, sz]) => ({ price: Number(p), size: Number(sz) })),
|
|
1016
|
-
asks: s.a.map(([p, sz]) => ({ price: Number(p), size: Number(sz) }))
|
|
1017
|
-
};
|
|
1018
|
-
}
|
|
1019
1127
|
|
|
1020
1128
|
// src/exchanges/gate/index.ts
|
|
1021
1129
|
var GateClient = class {
|
|
@@ -1056,10 +1164,6 @@ function toBingxSymbol(symbol) {
|
|
|
1056
1164
|
}
|
|
1057
1165
|
return `${base}_${quote}`.toUpperCase();
|
|
1058
1166
|
}
|
|
1059
|
-
function toBingxTopic(symbol, market, depth = 0.1) {
|
|
1060
|
-
const prefix = market === "spot" ? "market-depth" : "swap-depth";
|
|
1061
|
-
return `${prefix}.${toBingxSymbol(symbol)}.${depth}`;
|
|
1062
|
-
}
|
|
1063
1167
|
function fromBingxSymbol(s) {
|
|
1064
1168
|
return s.toUpperCase().replace("_", "/");
|
|
1065
1169
|
}
|
|
@@ -1124,9 +1228,10 @@ var WS_SPOT3 = "wss://open-api-ws.bingx.com/market";
|
|
|
1124
1228
|
var WS_SWAP = "wss://open-api-swap.bingx.com/swap-market";
|
|
1125
1229
|
function streamBingxOrderbook(opts) {
|
|
1126
1230
|
const isSpot = opts.market === "spot";
|
|
1127
|
-
const
|
|
1128
|
-
const
|
|
1129
|
-
const
|
|
1231
|
+
const wsSymbol = opts.symbol.toUpperCase().replace("/", "-");
|
|
1232
|
+
const level = opts.depth ?? 20;
|
|
1233
|
+
const interval = opts.interval ?? "500ms";
|
|
1234
|
+
const dataType = `${wsSymbol}@depth${level}@${interval}`;
|
|
1130
1235
|
const merger = new BookMerger();
|
|
1131
1236
|
let ws = null;
|
|
1132
1237
|
const stream = new OrderbookStream(() => ws?.close());
|
|
@@ -1161,7 +1266,7 @@ function streamBingxOrderbook(opts) {
|
|
|
1161
1266
|
if (!r.ok) return;
|
|
1162
1267
|
const book = {
|
|
1163
1268
|
exchange: "bingx",
|
|
1164
|
-
symbol:
|
|
1269
|
+
symbol: opts.symbol,
|
|
1165
1270
|
market: opts.market,
|
|
1166
1271
|
bids: r.bids,
|
|
1167
1272
|
asks: r.asks,
|