@xapy/orderbook 0.1.2 → 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/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 +139 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +139 -31
- 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 {
|