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