ccxt 4.4.75 → 4.4.78
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 +3 -3
- package/dist/ccxt.browser.min.js +7 -7
- package/dist/cjs/ccxt.js +8 -4
- package/dist/cjs/src/abstract/apex.js +9 -0
- package/dist/cjs/src/apex.js +1949 -0
- package/dist/cjs/src/base/Exchange.js +49 -3
- package/dist/cjs/src/binance.js +44 -220
- package/dist/cjs/src/bitget.js +139 -71
- package/dist/cjs/src/bitmex.js +4 -4
- package/dist/cjs/src/bitrue.js +48 -0
- package/dist/cjs/src/cex.js +1 -1
- package/dist/cjs/src/coinbase.js +32 -3
- package/dist/cjs/src/coincatch.js +68 -0
- package/dist/cjs/src/coinex.js +3 -0
- package/dist/cjs/src/coinlist.js +85 -1
- package/dist/cjs/src/hitbtc.js +3 -0
- package/dist/cjs/src/hyperliquid.js +13 -4
- package/dist/cjs/src/mexc.js +50 -57
- package/dist/cjs/src/okx.js +23 -8
- package/dist/cjs/src/paradex.js +3 -12
- package/dist/cjs/src/phemex.js +2 -1
- package/dist/cjs/src/poloniex.js +1 -1
- package/dist/cjs/src/pro/apex.js +1043 -0
- package/dist/cjs/src/pro/coinbase.js +4 -8
- package/dist/cjs/src/pro/gate.js +27 -2
- package/dist/cjs/src/pro/hollaex.js +2 -2
- package/dist/cjs/src/pro/hyperliquid.js +1 -1
- package/dist/cjs/src/pro/p2b.js +2 -2
- package/dist/cjs/src/pro/tradeogre.js +283 -0
- package/dist/cjs/src/probit.js +1 -0
- package/dist/cjs/src/static_dependencies/zklink/zklink-sdk-web.js +2645 -0
- package/dist/cjs/src/tradeogre.js +2 -1
- package/dist/cjs/src/upbit.js +299 -93
- package/dist/cjs/src/whitebit.js +1 -0
- package/dist/cjs/src/woo.js +3 -1
- package/dist/cjs/src/xt.js +131 -4
- package/js/ccxt.d.ts +11 -5
- package/js/ccxt.js +8 -4
- package/js/src/abstract/apex.d.ts +34 -0
- package/js/src/abstract/myokx.d.ts +4 -0
- package/js/src/abstract/okx.d.ts +4 -0
- package/js/src/abstract/upbit.d.ts +15 -1
- package/js/src/abstract/xt.d.ts +3 -0
- package/js/src/apex.d.ts +333 -0
- package/js/src/apex.js +1951 -0
- package/js/src/ascendex.d.ts +3 -3
- package/js/src/base/Exchange.d.ts +3 -0
- package/js/src/base/Exchange.js +49 -2
- package/js/src/binance.d.ts +9 -7
- package/js/src/binance.js +44 -220
- package/js/src/bitfinex.d.ts +3 -3
- package/js/src/bitflyer.d.ts +2 -2
- package/js/src/bitget.d.ts +2 -0
- package/js/src/bitget.js +139 -71
- package/js/src/bitmart.d.ts +4 -4
- package/js/src/bitmex.d.ts +3 -3
- package/js/src/bitmex.js +4 -4
- package/js/src/bitrue.js +48 -0
- package/js/src/cex.js +1 -1
- package/js/src/coinbase.d.ts +6 -4
- package/js/src/coinbase.js +32 -3
- package/js/src/coinbaseexchange.d.ts +1 -1
- package/js/src/coincatch.d.ts +11 -0
- package/js/src/coincatch.js +68 -0
- package/js/src/coinex.js +3 -0
- package/js/src/coinlist.d.ts +12 -1
- package/js/src/coinlist.js +85 -1
- package/js/src/cryptocom.d.ts +4 -4
- package/js/src/deribit.d.ts +4 -4
- package/js/src/derive.d.ts +3 -3
- package/js/src/digifinex.d.ts +4 -4
- package/js/src/hitbtc.js +3 -0
- package/js/src/htx.d.ts +4 -4
- package/js/src/hyperliquid.d.ts +1 -0
- package/js/src/hyperliquid.js +13 -4
- package/js/src/kraken.d.ts +3 -3
- package/js/src/krakenfutures.d.ts +2 -2
- package/js/src/kucoinfutures.d.ts +5 -5
- package/js/src/mexc.d.ts +1 -0
- package/js/src/mexc.js +50 -57
- package/js/src/okx.js +23 -8
- package/js/src/oxfun.d.ts +3 -3
- package/js/src/paradex.js +3 -12
- package/js/src/phemex.d.ts +3 -3
- package/js/src/phemex.js +2 -1
- package/js/src/poloniex.d.ts +3 -3
- package/js/src/poloniex.js +1 -1
- package/js/src/pro/apex.d.ts +160 -0
- package/js/src/pro/apex.js +1044 -0
- package/js/src/pro/coinbase.js +4 -8
- package/js/src/pro/gate.js +27 -2
- package/js/src/pro/hollaex.js +2 -2
- package/js/src/pro/hyperliquid.js +1 -1
- package/js/src/pro/p2b.js +2 -2
- package/js/src/pro/tradeogre.d.ts +49 -0
- package/js/src/pro/tradeogre.js +284 -0
- package/js/src/probit.js +1 -0
- package/js/src/static_dependencies/zklink/zklink-sdk-web.d.ts +1279 -0
- package/js/src/static_dependencies/zklink/zklink-sdk-web.js +4282 -0
- package/js/src/tradeogre.js +2 -1
- package/js/src/upbit.d.ts +34 -4
- package/js/src/upbit.js +299 -93
- package/js/src/vertex.d.ts +3 -3
- package/js/src/whitebit.js +1 -0
- package/js/src/woo.d.ts +4 -4
- package/js/src/woo.js +3 -1
- package/js/src/woofipro.d.ts +4 -4
- package/js/src/xt.d.ts +23 -4
- package/js/src/xt.js +131 -4
- package/package.json +2 -2
- package/js/src/abstract/ace.d.ts +0 -18
- package/js/src/ace.d.ts +0 -158
- package/js/src/ace.js +0 -1181
- /package/js/src/abstract/{ace.js → apex.js} +0 -0
|
@@ -0,0 +1,1044 @@
|
|
|
1
|
+
// ----------------------------------------------------------------------------
|
|
2
|
+
|
|
3
|
+
// PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
|
4
|
+
// https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
|
5
|
+
// EDIT THE CORRESPONDENT .ts FILE INSTEAD
|
|
6
|
+
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
import apexRest from '../apex.js';
|
|
9
|
+
import { ArrayCache, ArrayCacheBySymbolById, ArrayCacheBySymbolBySide, ArrayCacheByTimestamp } from '../base/ws/Cache.js';
|
|
10
|
+
import { ArgumentsRequired, AuthenticationError, ExchangeError } from '../base/errors.js';
|
|
11
|
+
import { sha256 } from '../static_dependencies/noble-hashes/sha256.js';
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
export default class apex extends apexRest {
|
|
14
|
+
describe() {
|
|
15
|
+
return this.deepExtend(super.describe(), {
|
|
16
|
+
'has': {
|
|
17
|
+
'ws': true,
|
|
18
|
+
'watchTicker': true,
|
|
19
|
+
'watchTickers': true,
|
|
20
|
+
'watchOrderBook': true,
|
|
21
|
+
'watchOrders': true,
|
|
22
|
+
'watchTrades': true,
|
|
23
|
+
'watchTradesForSymbols': false,
|
|
24
|
+
'watchPositions': true,
|
|
25
|
+
'watchMyTrades': true,
|
|
26
|
+
'watchBalance': false,
|
|
27
|
+
'watchOHLCV': true,
|
|
28
|
+
},
|
|
29
|
+
'urls': {
|
|
30
|
+
'logo': 'https://omni.apex.exchange/assets/logo_content-CY9uyFbz.svg',
|
|
31
|
+
'api': {
|
|
32
|
+
'ws': {
|
|
33
|
+
'public': 'wss://quote.omni.apex.exchange/realtime_public?v=2',
|
|
34
|
+
'private': 'wss://quote.omni.apex.exchange/realtime_private?v=2',
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
'test': {
|
|
38
|
+
'ws': {
|
|
39
|
+
'public': 'wss://qa-quote.omni.apex.exchange/realtime_public?v=2',
|
|
40
|
+
'private': 'wss://qa-quote.omni.apex.exchange/realtime_private?v=2',
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
'www': 'https://apex.exchange/',
|
|
44
|
+
'doc': 'https://api-docs.pro.apex.exchange',
|
|
45
|
+
'fees': 'https://apex-pro.gitbook.io/apex-pro/apex-omni-live-now/trading-perpetual-contracts/trading-fees',
|
|
46
|
+
'referral': 'https://omni.apex.exchange/trade',
|
|
47
|
+
},
|
|
48
|
+
'options': {},
|
|
49
|
+
'streaming': {
|
|
50
|
+
'ping': this.ping,
|
|
51
|
+
'keepAlive': 18000,
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* @method
|
|
57
|
+
* @name apex#watchTrades
|
|
58
|
+
* @description watches information on multiple trades made in a market
|
|
59
|
+
* @see https://api-docs.pro.apex.exchange/#websocket-v3-for-omni-websocket-endpoint
|
|
60
|
+
* @param {string} symbol unified market symbol of the market trades were made in
|
|
61
|
+
* @param {int} [since] the earliest time in ms to fetch trades for
|
|
62
|
+
* @param {int} [limit] the maximum number of trade structures to retrieve
|
|
63
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
64
|
+
* @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure}
|
|
65
|
+
*/
|
|
66
|
+
async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
|
|
67
|
+
return await this.watchTradesForSymbols([symbol], since, limit, params);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* @method
|
|
71
|
+
* @name apex#watchTradesForSymbols
|
|
72
|
+
* @description get the list of most recent trades for a list of symbols
|
|
73
|
+
* @see https://api-docs.pro.apex.exchange/#websocket-v3-for-omni-websocket-endpoint
|
|
74
|
+
* @param {string[]} symbols unified symbol of the market to fetch trades for
|
|
75
|
+
* @param {int} [since] timestamp in ms of the earliest trade to fetch
|
|
76
|
+
* @param {int} [limit] the maximum amount of trades to fetch
|
|
77
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
78
|
+
* @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
|
|
79
|
+
*/
|
|
80
|
+
async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
|
|
81
|
+
await this.loadMarkets();
|
|
82
|
+
symbols = this.marketSymbols(symbols);
|
|
83
|
+
const symbolsLength = symbols.length;
|
|
84
|
+
if (symbolsLength === 0) {
|
|
85
|
+
throw new ArgumentsRequired(this.id + ' watchTradesForSymbols() requires a non-empty array of symbols');
|
|
86
|
+
}
|
|
87
|
+
const timeStamp = this.milliseconds().toString();
|
|
88
|
+
const url = this.urls['api']['ws']['public'] + '×tamp=' + timeStamp;
|
|
89
|
+
const topics = [];
|
|
90
|
+
const messageHashes = [];
|
|
91
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
92
|
+
const symbol = symbols[i];
|
|
93
|
+
const market = this.market(symbol);
|
|
94
|
+
const topic = 'recentlyTrade.H.' + market['id2'];
|
|
95
|
+
topics.push(topic);
|
|
96
|
+
const messageHash = 'trade:' + symbol;
|
|
97
|
+
messageHashes.push(messageHash);
|
|
98
|
+
}
|
|
99
|
+
const trades = await this.watchTopics(url, messageHashes, topics, params);
|
|
100
|
+
if (this.newUpdates) {
|
|
101
|
+
const first = this.safeValue(trades, 0);
|
|
102
|
+
const tradeSymbol = this.safeString(first, 'symbol');
|
|
103
|
+
limit = trades.getLimit(tradeSymbol, limit);
|
|
104
|
+
}
|
|
105
|
+
return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
|
|
106
|
+
}
|
|
107
|
+
handleTrades(client, message) {
|
|
108
|
+
//
|
|
109
|
+
// {
|
|
110
|
+
// "topic": "recentlyTrade.H.BTCUSDT",
|
|
111
|
+
// "type": "snapshot",
|
|
112
|
+
// "ts": 1672304486868,
|
|
113
|
+
// "data": [
|
|
114
|
+
// {
|
|
115
|
+
// "T": 1672304486865,
|
|
116
|
+
// "s": "BTCUSDT",
|
|
117
|
+
// "S": "Buy",
|
|
118
|
+
// "v": "0.001",
|
|
119
|
+
// "p": "16578.50",
|
|
120
|
+
// "L": "PlusTick",
|
|
121
|
+
// "i": "20f43950-d8dd-5b31-9112-a178eb6023af",
|
|
122
|
+
// "BT": false
|
|
123
|
+
// }
|
|
124
|
+
// ]
|
|
125
|
+
// }
|
|
126
|
+
//
|
|
127
|
+
const data = this.safeValue(message, 'data', {});
|
|
128
|
+
const topic = this.safeString(message, 'topic');
|
|
129
|
+
const trades = data;
|
|
130
|
+
const parts = topic.split('.');
|
|
131
|
+
const marketId = this.safeString(parts, 2);
|
|
132
|
+
const market = this.safeMarket(marketId, undefined, undefined);
|
|
133
|
+
const symbol = market['symbol'];
|
|
134
|
+
let stored = this.safeValue(this.trades, symbol);
|
|
135
|
+
if (stored === undefined) {
|
|
136
|
+
const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
|
|
137
|
+
stored = new ArrayCache(limit);
|
|
138
|
+
this.trades[symbol] = stored;
|
|
139
|
+
}
|
|
140
|
+
for (let j = 0; j < trades.length; j++) {
|
|
141
|
+
const parsed = this.parseWsTrade(trades[j], market);
|
|
142
|
+
stored.append(parsed);
|
|
143
|
+
}
|
|
144
|
+
const messageHash = 'trade' + ':' + symbol;
|
|
145
|
+
client.resolve(stored, messageHash);
|
|
146
|
+
}
|
|
147
|
+
parseWsTrade(trade, market = undefined) {
|
|
148
|
+
//
|
|
149
|
+
// public
|
|
150
|
+
// {
|
|
151
|
+
// "T": 1672304486865,
|
|
152
|
+
// "s": "BTCUSDT",
|
|
153
|
+
// "S": "Buy",
|
|
154
|
+
// "v": "0.001",
|
|
155
|
+
// "p": "16578.50",
|
|
156
|
+
// "L": "PlusTick",
|
|
157
|
+
// "i": "20f43950-d8dd-5b31-9112-a178eb6023af",
|
|
158
|
+
// "BT": false
|
|
159
|
+
// }
|
|
160
|
+
//
|
|
161
|
+
const id = this.safeStringN(trade, ['i', 'id', 'v']);
|
|
162
|
+
const marketId = this.safeStringN(trade, ['s', 'symbol']);
|
|
163
|
+
market = this.safeMarket(marketId, market, undefined);
|
|
164
|
+
const symbol = market['symbol'];
|
|
165
|
+
const timestamp = this.safeIntegerN(trade, ['t', 'T', 'createdAt']);
|
|
166
|
+
const side = this.safeStringLowerN(trade, ['S', 'side']);
|
|
167
|
+
const price = this.safeStringN(trade, ['p', 'price']);
|
|
168
|
+
const amount = this.safeStringN(trade, ['q', 'v', 'size']);
|
|
169
|
+
return this.safeTrade({
|
|
170
|
+
'id': id,
|
|
171
|
+
'info': trade,
|
|
172
|
+
'timestamp': timestamp,
|
|
173
|
+
'datetime': this.iso8601(timestamp),
|
|
174
|
+
'symbol': symbol,
|
|
175
|
+
'order': undefined,
|
|
176
|
+
'type': undefined,
|
|
177
|
+
'side': side,
|
|
178
|
+
'takerOrMaker': undefined,
|
|
179
|
+
'price': price,
|
|
180
|
+
'amount': amount,
|
|
181
|
+
'cost': undefined,
|
|
182
|
+
'fee': undefined,
|
|
183
|
+
}, market);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* @method
|
|
187
|
+
* @name apex#watchOrderBook
|
|
188
|
+
* @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
|
|
189
|
+
* @see https://api-docs.pro.apex.exchange/#websocket-v3-for-omni-websocket-endpoint
|
|
190
|
+
* @param {string} symbol unified symbol of the market to fetch the order book for
|
|
191
|
+
* @param {int} [limit] the maximum amount of order book entries to return.
|
|
192
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
193
|
+
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
|
|
194
|
+
*/
|
|
195
|
+
async watchOrderBook(symbol, limit = undefined, params = {}) {
|
|
196
|
+
return await this.watchOrderBookForSymbols([symbol], limit, params);
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* @method
|
|
200
|
+
* @name apex#watchOrderBookForSymbols
|
|
201
|
+
* @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
|
|
202
|
+
* @see https://api-docs.pro.apex.exchange/#websocket-v3-for-omni-websocket-endpoint
|
|
203
|
+
* @param {string[]} symbols unified array of symbols
|
|
204
|
+
* @param {int} [limit] the maximum amount of order book entries to return.
|
|
205
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
206
|
+
* @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
|
|
207
|
+
*/
|
|
208
|
+
async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
|
|
209
|
+
await this.loadMarkets();
|
|
210
|
+
const symbolsLength = symbols.length;
|
|
211
|
+
if (symbolsLength === 0) {
|
|
212
|
+
throw new ArgumentsRequired(this.id + ' watchOrderBookForSymbols() requires a non-empty array of symbols');
|
|
213
|
+
}
|
|
214
|
+
symbols = this.marketSymbols(symbols);
|
|
215
|
+
const timeStamp = this.milliseconds().toString();
|
|
216
|
+
const url = this.urls['api']['ws']['public'] + '×tamp=' + timeStamp;
|
|
217
|
+
const topics = [];
|
|
218
|
+
const messageHashes = [];
|
|
219
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
220
|
+
const symbol = symbols[i];
|
|
221
|
+
const market = this.market(symbol);
|
|
222
|
+
if (limit === undefined) {
|
|
223
|
+
limit = 25;
|
|
224
|
+
}
|
|
225
|
+
const topic = 'orderBook' + limit.toString() + '.H.' + market['id2'];
|
|
226
|
+
topics.push(topic);
|
|
227
|
+
const messageHash = 'orderbook:' + symbol;
|
|
228
|
+
messageHashes.push(messageHash);
|
|
229
|
+
}
|
|
230
|
+
const orderbook = await this.watchTopics(url, messageHashes, topics, params);
|
|
231
|
+
return orderbook.limit();
|
|
232
|
+
}
|
|
233
|
+
async watchTopics(url, messageHashes, topics, params = {}) {
|
|
234
|
+
const request = {
|
|
235
|
+
'op': 'subscribe',
|
|
236
|
+
'args': topics,
|
|
237
|
+
};
|
|
238
|
+
const message = this.extend(request, params);
|
|
239
|
+
return await this.watchMultiple(url, messageHashes, message, messageHashes);
|
|
240
|
+
}
|
|
241
|
+
handleOrderBook(client, message) {
|
|
242
|
+
//
|
|
243
|
+
// {
|
|
244
|
+
// "topic": "orderbook25.H.BTCUSDT",
|
|
245
|
+
// "type": "snapshot",
|
|
246
|
+
// "ts": 1672304484978,
|
|
247
|
+
// "data": {
|
|
248
|
+
// "s": "BTCUSDT",
|
|
249
|
+
// "b": [
|
|
250
|
+
// ...,
|
|
251
|
+
// [
|
|
252
|
+
// "16493.50",
|
|
253
|
+
// "0.006"
|
|
254
|
+
// ],
|
|
255
|
+
// [
|
|
256
|
+
// "16493.00",
|
|
257
|
+
// "0.100"
|
|
258
|
+
// ]
|
|
259
|
+
// ],
|
|
260
|
+
// "a": [
|
|
261
|
+
// [
|
|
262
|
+
// "16611.00",
|
|
263
|
+
// "0.029"
|
|
264
|
+
// ],
|
|
265
|
+
// [
|
|
266
|
+
// "16612.00",
|
|
267
|
+
// "0.213"
|
|
268
|
+
// ],
|
|
269
|
+
// ],
|
|
270
|
+
// "u": 18521288,
|
|
271
|
+
// "seq": 7961638724
|
|
272
|
+
// }
|
|
273
|
+
// }
|
|
274
|
+
//
|
|
275
|
+
const type = this.safeString(message, 'type');
|
|
276
|
+
const isSnapshot = (type === 'snapshot');
|
|
277
|
+
const data = this.safeDict(message, 'data', {});
|
|
278
|
+
const marketId = this.safeString(data, 's');
|
|
279
|
+
const market = this.safeMarket(marketId, undefined, undefined);
|
|
280
|
+
const symbol = market['symbol'];
|
|
281
|
+
const timestamp = this.safeIntegerProduct(message, 'ts', 0.001);
|
|
282
|
+
if (!(symbol in this.orderbooks)) {
|
|
283
|
+
this.orderbooks[symbol] = this.orderBook();
|
|
284
|
+
}
|
|
285
|
+
const orderbook = this.orderbooks[symbol];
|
|
286
|
+
if (isSnapshot) {
|
|
287
|
+
const snapshot = this.parseOrderBook(data, symbol, timestamp, 'b', 'a');
|
|
288
|
+
orderbook.reset(snapshot);
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
const asks = this.safeList(data, 'a', []);
|
|
292
|
+
const bids = this.safeList(data, 'b', []);
|
|
293
|
+
this.handleDeltas(orderbook['asks'], asks);
|
|
294
|
+
this.handleDeltas(orderbook['bids'], bids);
|
|
295
|
+
orderbook['timestamp'] = timestamp;
|
|
296
|
+
orderbook['datetime'] = this.iso8601(timestamp);
|
|
297
|
+
}
|
|
298
|
+
const messageHash = 'orderbook' + ':' + symbol;
|
|
299
|
+
this.orderbooks[symbol] = orderbook;
|
|
300
|
+
client.resolve(orderbook, messageHash);
|
|
301
|
+
}
|
|
302
|
+
handleDelta(bookside, delta) {
|
|
303
|
+
const bidAsk = this.parseBidAsk(delta, 0, 1);
|
|
304
|
+
bookside.storeArray(bidAsk);
|
|
305
|
+
}
|
|
306
|
+
handleDeltas(bookside, deltas) {
|
|
307
|
+
for (let i = 0; i < deltas.length; i++) {
|
|
308
|
+
this.handleDelta(bookside, deltas[i]);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* @method
|
|
313
|
+
* @name apex#watchTicker
|
|
314
|
+
* @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
|
315
|
+
* @see https://api-docs.pro.apex.exchange/#websocket-v3-for-omni-websocket-endpoint
|
|
316
|
+
* @param {string} symbol unified symbol of the market to fetch the ticker for
|
|
317
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
318
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
319
|
+
*/
|
|
320
|
+
async watchTicker(symbol, params = {}) {
|
|
321
|
+
await this.loadMarkets();
|
|
322
|
+
const market = this.market(symbol);
|
|
323
|
+
symbol = market['symbol'];
|
|
324
|
+
const timeStamp = this.milliseconds().toString();
|
|
325
|
+
const url = this.urls['api']['ws']['public'] + '×tamp=' + timeStamp;
|
|
326
|
+
const messageHash = 'ticker:' + symbol;
|
|
327
|
+
const topic = 'instrumentInfo' + '.H.' + market['id2'];
|
|
328
|
+
const topics = [topic];
|
|
329
|
+
return await this.watchTopics(url, [messageHash], topics, params);
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* @method
|
|
333
|
+
* @name apex#watchTickers
|
|
334
|
+
* @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
|
|
335
|
+
* @see https://api-docs.pro.apex.exchange/#websocket-v3-for-omni-websocket-endpoint
|
|
336
|
+
* @param {string[]} symbols unified symbol of the market to fetch the ticker for
|
|
337
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
338
|
+
* @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
|
|
339
|
+
*/
|
|
340
|
+
async watchTickers(symbols = undefined, params = {}) {
|
|
341
|
+
await this.loadMarkets();
|
|
342
|
+
symbols = this.marketSymbols(symbols, undefined, false);
|
|
343
|
+
const messageHashes = [];
|
|
344
|
+
const timeStamp = this.milliseconds().toString();
|
|
345
|
+
const url = this.urls['api']['ws']['public'] + '×tamp=' + timeStamp;
|
|
346
|
+
const topics = [];
|
|
347
|
+
for (let i = 0; i < symbols.length; i++) {
|
|
348
|
+
const symbol = symbols[i];
|
|
349
|
+
const market = this.market(symbol);
|
|
350
|
+
const topic = 'instrumentInfo' + '.H.' + market['id2'];
|
|
351
|
+
topics.push(topic);
|
|
352
|
+
const messageHash = 'ticker:' + symbol;
|
|
353
|
+
messageHashes.push(messageHash);
|
|
354
|
+
}
|
|
355
|
+
const ticker = await this.watchTopics(url, messageHashes, topics, params);
|
|
356
|
+
if (this.newUpdates) {
|
|
357
|
+
const result = {};
|
|
358
|
+
result[ticker['symbol']] = ticker;
|
|
359
|
+
return result;
|
|
360
|
+
}
|
|
361
|
+
return this.filterByArray(this.tickers, 'symbol', symbols);
|
|
362
|
+
}
|
|
363
|
+
handleTicker(client, message) {
|
|
364
|
+
// "topic":"instrumentInfo.H.BTCUSDT",
|
|
365
|
+
// "type":"snapshot",
|
|
366
|
+
// "data":{
|
|
367
|
+
// "symbol":"BTCUSDT",
|
|
368
|
+
// "lastPrice":"21572.5",
|
|
369
|
+
// "price24hPcnt":"-0.0194318181818182",
|
|
370
|
+
// "highPrice24h":"25306.5",
|
|
371
|
+
// "lowPrice24h":"17001.5",
|
|
372
|
+
// "turnover24h":"1334891.4545",
|
|
373
|
+
// "volume24h":"64.896",
|
|
374
|
+
// "nextFundingTime":"2022-08-26T08:00:00Z",
|
|
375
|
+
// "oraclePrice":"21412.060000000002752512",
|
|
376
|
+
// "indexPrice":"21409.82",
|
|
377
|
+
// "openInterest":"49.598",
|
|
378
|
+
// "tradeCount":"0",
|
|
379
|
+
// "fundingRate":"0.0000125",
|
|
380
|
+
// "predictedFundingRate":"0.0000125"
|
|
381
|
+
// },
|
|
382
|
+
// "cs":44939063,
|
|
383
|
+
// "ts":1661500091955487
|
|
384
|
+
// }
|
|
385
|
+
const topic = this.safeString(message, 'topic', '');
|
|
386
|
+
const updateType = this.safeString(message, 'type', '');
|
|
387
|
+
const data = this.safeDict(message, 'data', {});
|
|
388
|
+
let symbol = undefined;
|
|
389
|
+
let parsed = undefined;
|
|
390
|
+
if ((updateType === 'snapshot')) {
|
|
391
|
+
parsed = this.parseTicker(data);
|
|
392
|
+
symbol = parsed['symbol'];
|
|
393
|
+
}
|
|
394
|
+
else if (updateType === 'delta') {
|
|
395
|
+
const topicParts = topic.split('.');
|
|
396
|
+
const topicLength = topicParts.length;
|
|
397
|
+
const marketId = this.safeString(topicParts, topicLength - 1);
|
|
398
|
+
const market = this.safeMarket(marketId, undefined, undefined);
|
|
399
|
+
symbol = market['symbol'];
|
|
400
|
+
const ticker = this.safeDict(this.tickers, symbol, {});
|
|
401
|
+
const rawTicker = this.safeDict(ticker, 'info', {});
|
|
402
|
+
const merged = this.extend(rawTicker, data);
|
|
403
|
+
parsed = this.parseTicker(merged);
|
|
404
|
+
}
|
|
405
|
+
const timestamp = this.safeIntegerProduct(message, 'ts', 0.001);
|
|
406
|
+
parsed['timestamp'] = timestamp;
|
|
407
|
+
parsed['datetime'] = this.iso8601(timestamp);
|
|
408
|
+
this.tickers[symbol] = parsed;
|
|
409
|
+
const messageHash = 'ticker:' + symbol;
|
|
410
|
+
client.resolve(this.tickers[symbol], messageHash);
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* @method
|
|
414
|
+
* @name apex#watchOHLCV
|
|
415
|
+
* @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
416
|
+
* @see https://api-docs.pro.apex.exchange/#websocket-v3-for-omni-websocket-endpoint
|
|
417
|
+
* @param {string} symbol unified symbol of the market to fetch OHLCV data for
|
|
418
|
+
* @param {string} timeframe the length of time each candle represents
|
|
419
|
+
* @param {int} [since] timestamp in ms of the earliest candle to fetch
|
|
420
|
+
* @param {int} [limit] the maximum amount of candles to fetch
|
|
421
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
422
|
+
* @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
|
|
423
|
+
*/
|
|
424
|
+
async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
|
|
425
|
+
params['callerMethodName'] = 'watchOHLCV';
|
|
426
|
+
const result = await this.watchOHLCVForSymbols([[symbol, timeframe]], since, limit, params);
|
|
427
|
+
return result[symbol][timeframe];
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* @method
|
|
431
|
+
* @name apex#watchOHLCVForSymbols
|
|
432
|
+
* @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
433
|
+
* @see https://api-docs.pro.apex.exchange/#websocket-v3-for-omni-websocket-endpoint
|
|
434
|
+
* @param {string[][]} symbolsAndTimeframes array of arrays containing unified symbols and timeframes to fetch OHLCV data for, example [['BTC/USDT', '1m'], ['LTC/USDT', '5m']]
|
|
435
|
+
* @param {int} [since] timestamp in ms of the earliest candle to fetch
|
|
436
|
+
* @param {int} [limit] the maximum amount of candles to fetch
|
|
437
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
438
|
+
* @returns {object} A list of candles ordered as timestamp, open, high, low, close, volume
|
|
439
|
+
*/
|
|
440
|
+
async watchOHLCVForSymbols(symbolsAndTimeframes, since = undefined, limit = undefined, params = {}) {
|
|
441
|
+
await this.loadMarkets();
|
|
442
|
+
const timeStamp = this.milliseconds().toString();
|
|
443
|
+
const url = this.urls['api']['ws']['public'] + '×tamp=' + timeStamp;
|
|
444
|
+
const rawHashes = [];
|
|
445
|
+
const messageHashes = [];
|
|
446
|
+
for (let i = 0; i < symbolsAndTimeframes.length; i++) {
|
|
447
|
+
const data = symbolsAndTimeframes[i];
|
|
448
|
+
let symbolString = this.safeString(data, 0);
|
|
449
|
+
const market = this.market(symbolString);
|
|
450
|
+
symbolString = market['id2'];
|
|
451
|
+
const unfiedTimeframe = this.safeString(data, 1, '1');
|
|
452
|
+
const timeframeId = this.safeString(this.timeframes, unfiedTimeframe, unfiedTimeframe);
|
|
453
|
+
rawHashes.push('candle.' + timeframeId + '.' + symbolString);
|
|
454
|
+
messageHashes.push('ohlcv::' + symbolString + '::' + unfiedTimeframe);
|
|
455
|
+
}
|
|
456
|
+
const [symbol, timeframe, stored] = await this.watchTopics(url, messageHashes, rawHashes, params);
|
|
457
|
+
if (this.newUpdates) {
|
|
458
|
+
limit = stored.getLimit(symbol, limit);
|
|
459
|
+
}
|
|
460
|
+
const filtered = this.filterBySinceLimit(stored, since, limit, 0, true);
|
|
461
|
+
return this.createOHLCVObject(symbol, timeframe, filtered);
|
|
462
|
+
}
|
|
463
|
+
handleOHLCV(client, message) {
|
|
464
|
+
//
|
|
465
|
+
// {
|
|
466
|
+
// "topic": "candle.5.BTCUSDT",
|
|
467
|
+
// "data": [
|
|
468
|
+
// {
|
|
469
|
+
// "start": 1672324800000,
|
|
470
|
+
// "end": 1672325099999,
|
|
471
|
+
// "interval": "5",
|
|
472
|
+
// "open": "16649.5",
|
|
473
|
+
// "close": "16677",
|
|
474
|
+
// "high": "16677",
|
|
475
|
+
// "low": "16608",
|
|
476
|
+
// "volume": "2.081",
|
|
477
|
+
// "turnover": "34666.4005",
|
|
478
|
+
// "confirm": false,
|
|
479
|
+
// "timestamp": 1672324988882
|
|
480
|
+
// }
|
|
481
|
+
// ],
|
|
482
|
+
// "ts": 1672324988882,
|
|
483
|
+
// "type": "snapshot"
|
|
484
|
+
// }
|
|
485
|
+
//
|
|
486
|
+
const data = this.safeValue(message, 'data', {});
|
|
487
|
+
const topic = this.safeString(message, 'topic');
|
|
488
|
+
const topicParts = topic.split('.');
|
|
489
|
+
const topicLength = topicParts.length;
|
|
490
|
+
const timeframeId = this.safeString(topicParts, 1);
|
|
491
|
+
const timeframe = this.findTimeframe(timeframeId);
|
|
492
|
+
const marketId = this.safeString(topicParts, topicLength - 1);
|
|
493
|
+
const isSpot = client.url.indexOf('spot') > -1;
|
|
494
|
+
const marketType = isSpot ? 'spot' : 'contract';
|
|
495
|
+
const market = this.safeMarket(marketId, undefined, undefined, marketType);
|
|
496
|
+
const symbol = market['symbol'];
|
|
497
|
+
const ohlcvsByTimeframe = this.safeValue(this.ohlcvs, symbol);
|
|
498
|
+
if (ohlcvsByTimeframe === undefined) {
|
|
499
|
+
this.ohlcvs[symbol] = {};
|
|
500
|
+
}
|
|
501
|
+
if (this.safeValue(ohlcvsByTimeframe, timeframe) === undefined) {
|
|
502
|
+
const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
|
|
503
|
+
this.ohlcvs[symbol][timeframe] = new ArrayCacheByTimestamp(limit);
|
|
504
|
+
}
|
|
505
|
+
const stored = this.ohlcvs[symbol][timeframe];
|
|
506
|
+
for (let i = 0; i < data.length; i++) {
|
|
507
|
+
const parsed = this.parseWsOHLCV(data[i]);
|
|
508
|
+
stored.append(parsed);
|
|
509
|
+
}
|
|
510
|
+
const messageHash = 'ohlcv::' + symbol + '::' + timeframe;
|
|
511
|
+
const resolveData = [symbol, timeframe, stored];
|
|
512
|
+
client.resolve(resolveData, messageHash);
|
|
513
|
+
}
|
|
514
|
+
parseWsOHLCV(ohlcv, market = undefined) {
|
|
515
|
+
//
|
|
516
|
+
// {
|
|
517
|
+
// "start": 1670363160000,
|
|
518
|
+
// "end": 1670363219999,
|
|
519
|
+
// "interval": "1",
|
|
520
|
+
// "open": "16987.5",
|
|
521
|
+
// "close": "16987.5",
|
|
522
|
+
// "high": "16988",
|
|
523
|
+
// "low": "16987.5",
|
|
524
|
+
// "volume": "23.511",
|
|
525
|
+
// "turnover": "399396.344",
|
|
526
|
+
// "confirm": false,
|
|
527
|
+
// "timestamp": 1670363219614
|
|
528
|
+
// }
|
|
529
|
+
//
|
|
530
|
+
return [
|
|
531
|
+
this.safeInteger(ohlcv, 'start'),
|
|
532
|
+
this.safeNumber(ohlcv, 'open'),
|
|
533
|
+
this.safeNumber(ohlcv, 'high'),
|
|
534
|
+
this.safeNumber(ohlcv, 'low'),
|
|
535
|
+
this.safeNumber(ohlcv, 'close'),
|
|
536
|
+
this.safeNumber2(ohlcv, 'volume', 'turnover'),
|
|
537
|
+
];
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* @method
|
|
541
|
+
* @name apex#watchMyTrades
|
|
542
|
+
* @description watches information on multiple trades made by the user
|
|
543
|
+
* @see https://api-docs.pro.apex.exchange/#private-websocket
|
|
544
|
+
* @param {string} symbol unified market symbol of the market orders were made in
|
|
545
|
+
* @param {int} [since] the earliest time in ms to fetch orders for
|
|
546
|
+
* @param {int} [limit] the maximum number of order structures to retrieve
|
|
547
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
548
|
+
* @param {boolean} [params.unifiedMargin] use unified margin account
|
|
549
|
+
* @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
550
|
+
*/
|
|
551
|
+
async watchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
552
|
+
let messageHash = 'myTrades';
|
|
553
|
+
await this.loadMarkets();
|
|
554
|
+
if (symbol !== undefined) {
|
|
555
|
+
symbol = this.symbol(symbol);
|
|
556
|
+
messageHash += ':' + symbol;
|
|
557
|
+
}
|
|
558
|
+
const timeStamp = this.milliseconds().toString();
|
|
559
|
+
const url = this.urls['api']['ws']['private'] + '×tamp=' + timeStamp;
|
|
560
|
+
await this.authenticate(url);
|
|
561
|
+
const trades = await this.watchTopics(url, [messageHash], ['myTrades'], params);
|
|
562
|
+
if (this.newUpdates) {
|
|
563
|
+
limit = trades.getLimit(symbol, limit);
|
|
564
|
+
}
|
|
565
|
+
return this.filterBySymbolSinceLimit(trades, symbol, since, limit, true);
|
|
566
|
+
}
|
|
567
|
+
/**
|
|
568
|
+
* @method
|
|
569
|
+
* @name apex#watchPositions
|
|
570
|
+
* @see https://api-docs.pro.apex.exchange/#private-websocket
|
|
571
|
+
* @description watch all open positions
|
|
572
|
+
* @param {string[]} [symbols] list of unified market symbols
|
|
573
|
+
* @param {int} [since] the earliest time in ms to fetch positions for
|
|
574
|
+
* @param {int} [limit] the maximum number of positions to retrieve
|
|
575
|
+
* @param {object} params extra parameters specific to the exchange API endpoint
|
|
576
|
+
* @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
|
|
577
|
+
*/
|
|
578
|
+
async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
|
|
579
|
+
await this.loadMarkets();
|
|
580
|
+
let messageHash = '';
|
|
581
|
+
if (!this.isEmpty(symbols)) {
|
|
582
|
+
symbols = this.marketSymbols(symbols);
|
|
583
|
+
messageHash = '::' + symbols.join(',');
|
|
584
|
+
}
|
|
585
|
+
const timeStamp = this.milliseconds().toString();
|
|
586
|
+
const url = this.urls['api']['ws']['private'] + '×tamp=' + timeStamp;
|
|
587
|
+
messageHash = 'positions' + messageHash;
|
|
588
|
+
const client = this.client(url);
|
|
589
|
+
await this.authenticate(url);
|
|
590
|
+
this.setPositionsCache(client, symbols);
|
|
591
|
+
const cache = this.positions;
|
|
592
|
+
if (cache === undefined) {
|
|
593
|
+
const snapshot = await client.future('fetchPositionsSnapshot');
|
|
594
|
+
return this.filterBySymbolsSinceLimit(snapshot, symbols, since, limit, true);
|
|
595
|
+
}
|
|
596
|
+
const topics = ['positions'];
|
|
597
|
+
const newPositions = await this.watchTopics(url, [messageHash], topics, params);
|
|
598
|
+
if (this.newUpdates) {
|
|
599
|
+
return newPositions;
|
|
600
|
+
}
|
|
601
|
+
return this.filterBySymbolsSinceLimit(cache, symbols, since, limit, true);
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* @method
|
|
605
|
+
* @name apex#watchOrders
|
|
606
|
+
* @description watches information on multiple orders made by the user
|
|
607
|
+
* @see https://api-docs.pro.apex.exchange/#private-websocket
|
|
608
|
+
* @param {string} symbol unified market symbol of the market orders were made in
|
|
609
|
+
* @param {int} [since] the earliest time in ms to fetch orders for
|
|
610
|
+
* @param {int} [limit] the maximum number of order structures to retrieve
|
|
611
|
+
* @param {object} [params] extra parameters specific to the exchange API endpoint
|
|
612
|
+
* @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
|
|
613
|
+
*/
|
|
614
|
+
async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
|
|
615
|
+
await this.loadMarkets();
|
|
616
|
+
let messageHash = 'orders';
|
|
617
|
+
if (symbol !== undefined) {
|
|
618
|
+
symbol = this.symbol(symbol);
|
|
619
|
+
messageHash += ':' + symbol;
|
|
620
|
+
}
|
|
621
|
+
const timeStamp = this.milliseconds().toString();
|
|
622
|
+
const url = this.urls['api']['ws']['private'] + '×tamp=' + timeStamp;
|
|
623
|
+
await this.authenticate(url);
|
|
624
|
+
const topics = ['orders'];
|
|
625
|
+
const orders = await this.watchTopics(url, [messageHash], topics, params);
|
|
626
|
+
if (this.newUpdates) {
|
|
627
|
+
limit = orders.getLimit(symbol, limit);
|
|
628
|
+
}
|
|
629
|
+
return this.filterBySymbolSinceLimit(orders, symbol, since, limit, true);
|
|
630
|
+
}
|
|
631
|
+
handleMyTrades(client, lists) {
|
|
632
|
+
// [
|
|
633
|
+
// {
|
|
634
|
+
// "symbol":"ETH-USDT",
|
|
635
|
+
// "side":"BUY",
|
|
636
|
+
// "orderId":"2048046080",
|
|
637
|
+
// "fee":"0.625000",
|
|
638
|
+
// "liquidity":"TAKER",
|
|
639
|
+
// "accountId":"1024000",
|
|
640
|
+
// "createdAt":1652185521361,
|
|
641
|
+
// "isOpen":true,
|
|
642
|
+
// "size":"0.500",
|
|
643
|
+
// "price":"2500.0",
|
|
644
|
+
// "quoteAmount":"1250.0000",
|
|
645
|
+
// "id":"2048000182272",
|
|
646
|
+
// "updatedAt":1652185678345
|
|
647
|
+
// }
|
|
648
|
+
// ]
|
|
649
|
+
if (this.myTrades === undefined) {
|
|
650
|
+
const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
|
|
651
|
+
this.myTrades = new ArrayCacheBySymbolById(limit);
|
|
652
|
+
}
|
|
653
|
+
const trades = this.myTrades;
|
|
654
|
+
const symbols = {};
|
|
655
|
+
for (let i = 0; i < lists.length; i++) {
|
|
656
|
+
const rawTrade = lists[i];
|
|
657
|
+
let parsed = undefined;
|
|
658
|
+
parsed = this.parseWsTrade(rawTrade);
|
|
659
|
+
const symbol = parsed['symbol'];
|
|
660
|
+
symbols[symbol] = true;
|
|
661
|
+
trades.append(parsed);
|
|
662
|
+
}
|
|
663
|
+
const keys = Object.keys(symbols);
|
|
664
|
+
for (let i = 0; i < keys.length; i++) {
|
|
665
|
+
const currentMessageHash = 'myTrades:' + keys[i];
|
|
666
|
+
client.resolve(trades, currentMessageHash);
|
|
667
|
+
}
|
|
668
|
+
// non-symbol specific
|
|
669
|
+
const messageHash = 'myTrades';
|
|
670
|
+
client.resolve(trades, messageHash);
|
|
671
|
+
}
|
|
672
|
+
handleOrder(client, lists) {
|
|
673
|
+
// [
|
|
674
|
+
// {
|
|
675
|
+
// "symbol":"ETH-USDT",
|
|
676
|
+
// "cumSuccessFillFee":"0.625000",
|
|
677
|
+
// "trailingPercent":"0",
|
|
678
|
+
// "type":"LIMIT",
|
|
679
|
+
// "unfillableAt":1654779600000,
|
|
680
|
+
// "isDeleverage":false,
|
|
681
|
+
// "createdAt":1652185521339,
|
|
682
|
+
// "price":"2500.0",
|
|
683
|
+
// "cumSuccessFillValue":"0",
|
|
684
|
+
// "id":"2048046080",
|
|
685
|
+
// "cancelReason":"",
|
|
686
|
+
// "timeInForce":1,
|
|
687
|
+
// "updatedAt":1652185521392,
|
|
688
|
+
// "limitFee":"0.625000",
|
|
689
|
+
// "side":"BUY",
|
|
690
|
+
// "clientOrderId":"522843990",
|
|
691
|
+
// "triggerPrice":"",
|
|
692
|
+
// "expiresAt":1654779600000,
|
|
693
|
+
// "cumSuccessFillSize":"0",
|
|
694
|
+
// "accountId":"1024000",
|
|
695
|
+
// "size":"0.500",
|
|
696
|
+
// "reduceOnly":false,
|
|
697
|
+
// "isLiquidate":false,
|
|
698
|
+
// "remainingSize":"0.000",
|
|
699
|
+
// "status":"PENDING"
|
|
700
|
+
// }
|
|
701
|
+
// ]
|
|
702
|
+
if (this.orders === undefined) {
|
|
703
|
+
const limit = this.safeInteger(this.options, 'ordersLimit', 1000);
|
|
704
|
+
this.orders = new ArrayCacheBySymbolById(limit);
|
|
705
|
+
}
|
|
706
|
+
const orders = this.orders;
|
|
707
|
+
const symbols = {};
|
|
708
|
+
for (let i = 0; i < lists.length; i++) {
|
|
709
|
+
let parsed = undefined;
|
|
710
|
+
parsed = this.parseOrder(lists[i]);
|
|
711
|
+
const symbol = parsed['symbol'];
|
|
712
|
+
symbols[symbol] = true;
|
|
713
|
+
orders.append(parsed);
|
|
714
|
+
}
|
|
715
|
+
const symbolsArray = Object.keys(symbols);
|
|
716
|
+
for (let i = 0; i < symbolsArray.length; i++) {
|
|
717
|
+
const currentMessageHash = 'orders:' + symbolsArray[i];
|
|
718
|
+
client.resolve(orders, currentMessageHash);
|
|
719
|
+
}
|
|
720
|
+
const messageHash = 'orders';
|
|
721
|
+
client.resolve(orders, messageHash);
|
|
722
|
+
}
|
|
723
|
+
setPositionsCache(client, symbols = undefined) {
|
|
724
|
+
if (this.positions !== undefined) {
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
const messageHash = 'fetchPositionsSnapshot';
|
|
728
|
+
if (!(messageHash in client.futures)) {
|
|
729
|
+
client.future(messageHash);
|
|
730
|
+
this.spawn(this.loadPositionsSnapshot, client, messageHash);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
async loadPositionsSnapshot(client, messageHash) {
|
|
734
|
+
// as only one ws channel gives positions for all types, for snapshot must load all positions
|
|
735
|
+
const fetchFunctions = [
|
|
736
|
+
this.fetchPositions(undefined),
|
|
737
|
+
];
|
|
738
|
+
const promises = await Promise.all(fetchFunctions);
|
|
739
|
+
this.positions = new ArrayCacheBySymbolBySide();
|
|
740
|
+
const cache = this.positions;
|
|
741
|
+
for (let i = 0; i < promises.length; i++) {
|
|
742
|
+
const positions = promises[i];
|
|
743
|
+
for (let ii = 0; ii < positions.length; ii++) {
|
|
744
|
+
const position = positions[ii];
|
|
745
|
+
cache.append(position);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
// don't remove the future from the .futures cache
|
|
749
|
+
const future = client.futures[messageHash];
|
|
750
|
+
future.resolve(cache);
|
|
751
|
+
client.resolve(cache, 'positions');
|
|
752
|
+
}
|
|
753
|
+
handlePositions(client, lists) {
|
|
754
|
+
//
|
|
755
|
+
// [
|
|
756
|
+
// {
|
|
757
|
+
// "symbol":"ETH-USDT",
|
|
758
|
+
// "exitPrice":"0",
|
|
759
|
+
// "side":"LONG",
|
|
760
|
+
// "maxSize":"2820.000",
|
|
761
|
+
// "sumOpen":"1.820",
|
|
762
|
+
// "sumClose":"0.000",
|
|
763
|
+
// "netFunding":"0.000000",
|
|
764
|
+
// "entryPrice":"2500.000000000000000000",
|
|
765
|
+
// "accountId":"1024000",
|
|
766
|
+
// "createdAt":1652179377769,
|
|
767
|
+
// "size":"1.820",
|
|
768
|
+
// "realizedPnl":"0",
|
|
769
|
+
// "closedAt":1652185521392,
|
|
770
|
+
// "updatedAt":1652185521392
|
|
771
|
+
// }
|
|
772
|
+
// ]
|
|
773
|
+
//
|
|
774
|
+
// each account is connected to a different endpoint
|
|
775
|
+
// and has exactly one subscriptionhash which is the account type
|
|
776
|
+
if (this.positions === undefined) {
|
|
777
|
+
this.positions = new ArrayCacheBySymbolBySide();
|
|
778
|
+
}
|
|
779
|
+
const cache = this.positions;
|
|
780
|
+
const newPositions = [];
|
|
781
|
+
for (let i = 0; i < lists.length; i++) {
|
|
782
|
+
const rawPosition = lists[i];
|
|
783
|
+
const position = this.parsePosition(rawPosition);
|
|
784
|
+
const side = this.safeString(position, 'side');
|
|
785
|
+
// hacky solution to handle closing positions
|
|
786
|
+
// without crashing, we should handle this properly later
|
|
787
|
+
newPositions.push(position);
|
|
788
|
+
if (side === undefined || side === '') {
|
|
789
|
+
// closing update, adding both sides to "reset" both sides
|
|
790
|
+
// since we don't know which side is being closed
|
|
791
|
+
position['side'] = 'long';
|
|
792
|
+
cache.append(position);
|
|
793
|
+
position['side'] = 'short';
|
|
794
|
+
cache.append(position);
|
|
795
|
+
position['side'] = undefined;
|
|
796
|
+
}
|
|
797
|
+
else {
|
|
798
|
+
// regular update
|
|
799
|
+
cache.append(position);
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
const messageHashes = this.findMessageHashes(client, 'positions::');
|
|
803
|
+
for (let i = 0; i < messageHashes.length; i++) {
|
|
804
|
+
const messageHash = messageHashes[i];
|
|
805
|
+
const parts = messageHash.split('::');
|
|
806
|
+
const symbolsString = parts[1];
|
|
807
|
+
const symbols = symbolsString.split(',');
|
|
808
|
+
const positions = this.filterByArray(newPositions, 'symbol', symbols, false);
|
|
809
|
+
if (!this.isEmpty(positions)) {
|
|
810
|
+
client.resolve(positions, messageHash);
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
client.resolve(newPositions, 'positions');
|
|
814
|
+
}
|
|
815
|
+
async authenticate(url, params = {}) {
|
|
816
|
+
this.checkRequiredCredentials();
|
|
817
|
+
const timestamp = this.milliseconds().toString();
|
|
818
|
+
const request_path = '/ws/accounts';
|
|
819
|
+
const http_method = 'GET';
|
|
820
|
+
const messageString = (timestamp + http_method + request_path);
|
|
821
|
+
const signature = this.hmac(this.encode(messageString), this.encode(this.stringToBase64(this.secret)), sha256, 'base64');
|
|
822
|
+
const messageHash = 'authenticated';
|
|
823
|
+
const client = this.client(url);
|
|
824
|
+
const future = client.future(messageHash);
|
|
825
|
+
const authenticated = this.safeValue(client.subscriptions, messageHash);
|
|
826
|
+
if (authenticated === undefined) {
|
|
827
|
+
// auth sign
|
|
828
|
+
const request = {
|
|
829
|
+
'type': 'login',
|
|
830
|
+
'topics': ['ws_zk_accounts_v3'],
|
|
831
|
+
'httpMethod': http_method,
|
|
832
|
+
'requestPath': request_path,
|
|
833
|
+
'apiKey': this.apiKey,
|
|
834
|
+
'passphrase': this.password,
|
|
835
|
+
'timestamp': timestamp,
|
|
836
|
+
'signature': signature,
|
|
837
|
+
};
|
|
838
|
+
const message = {
|
|
839
|
+
'op': 'login',
|
|
840
|
+
'args': [JSON.stringify(request)],
|
|
841
|
+
};
|
|
842
|
+
this.watch(url, messageHash, message, messageHash);
|
|
843
|
+
}
|
|
844
|
+
return await future;
|
|
845
|
+
}
|
|
846
|
+
handleErrorMessage(client, message) {
|
|
847
|
+
//
|
|
848
|
+
// {
|
|
849
|
+
// "success": false,
|
|
850
|
+
// "ret_msg": "error:invalid op",
|
|
851
|
+
// "conn_id": "5e079fdd-9c7f-404d-9dbf-969d650838b5",
|
|
852
|
+
// "request": { op: '', args: null }
|
|
853
|
+
// }
|
|
854
|
+
//
|
|
855
|
+
// auth error
|
|
856
|
+
//
|
|
857
|
+
// {
|
|
858
|
+
// "success": false,
|
|
859
|
+
// "ret_msg": "error:USVC1111",
|
|
860
|
+
// "conn_id": "e73770fb-a0dc-45bd-8028-140e20958090",
|
|
861
|
+
// "request": {
|
|
862
|
+
// "op": "auth",
|
|
863
|
+
// "args": [
|
|
864
|
+
// "9rFT6uR4uz9Imkw4Wx",
|
|
865
|
+
// "1653405853543",
|
|
866
|
+
// "542e71bd85597b4db0290f0ce2d13ed1fd4bb5df3188716c1e9cc69a879f7889"
|
|
867
|
+
// ]
|
|
868
|
+
// }
|
|
869
|
+
//
|
|
870
|
+
// { code: '-10009', desc: "Invalid period!" }
|
|
871
|
+
//
|
|
872
|
+
// {
|
|
873
|
+
// "reqId":"1",
|
|
874
|
+
// "retCode":170131,
|
|
875
|
+
// "retMsg":"Insufficient balance.",
|
|
876
|
+
// "op":"order.create",
|
|
877
|
+
// "data":{
|
|
878
|
+
//
|
|
879
|
+
// },
|
|
880
|
+
// "header":{
|
|
881
|
+
// "X-Bapi-Limit":"20",
|
|
882
|
+
// "X-Bapi-Limit-Status":"19",
|
|
883
|
+
// "X-Bapi-Limit-Reset-Timestamp":"1714236608944",
|
|
884
|
+
// "Traceid":"3d7168a137bf32a947b7e5e6a575ac7f",
|
|
885
|
+
// "Timenow":"1714236608946"
|
|
886
|
+
// },
|
|
887
|
+
// "connId":"cojifin88smerbj9t560-406"
|
|
888
|
+
// }
|
|
889
|
+
//
|
|
890
|
+
const code = this.safeStringN(message, ['code', 'ret_code', 'retCode']);
|
|
891
|
+
try {
|
|
892
|
+
if (code !== undefined && code !== '0') {
|
|
893
|
+
const feedback = this.id + ' ' + this.json(message);
|
|
894
|
+
this.throwExactlyMatchedException(this.exceptions['exact'], code, feedback);
|
|
895
|
+
const msg = this.safeString2(message, 'retMsg', 'ret_msg');
|
|
896
|
+
this.throwBroadlyMatchedException(this.exceptions['broad'], msg, feedback);
|
|
897
|
+
throw new ExchangeError(feedback);
|
|
898
|
+
}
|
|
899
|
+
const success = this.safeValue(message, 'success');
|
|
900
|
+
if (success !== undefined && !success) {
|
|
901
|
+
const ret_msg = this.safeString(message, 'ret_msg');
|
|
902
|
+
const request = this.safeValue(message, 'request', {});
|
|
903
|
+
const op = this.safeString(request, 'op');
|
|
904
|
+
if (op === 'auth') {
|
|
905
|
+
throw new AuthenticationError('Authentication failed: ' + ret_msg);
|
|
906
|
+
}
|
|
907
|
+
else {
|
|
908
|
+
throw new ExchangeError(this.id + ' ' + ret_msg);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
return false;
|
|
912
|
+
}
|
|
913
|
+
catch (error) {
|
|
914
|
+
if (error instanceof AuthenticationError) {
|
|
915
|
+
const messageHash = 'authenticated';
|
|
916
|
+
client.reject(error, messageHash);
|
|
917
|
+
if (messageHash in client.subscriptions) {
|
|
918
|
+
delete client.subscriptions[messageHash];
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
else {
|
|
922
|
+
const messageHash = this.safeString(message, 'reqId');
|
|
923
|
+
client.reject(error, messageHash);
|
|
924
|
+
}
|
|
925
|
+
return true;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
handleMessage(client, message) {
|
|
929
|
+
if (this.handleErrorMessage(client, message)) {
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
932
|
+
const topic = this.safeString2(message, 'topic', 'op', '');
|
|
933
|
+
const methods = {
|
|
934
|
+
'ws_zk_accounts_v3': this.handleAccount,
|
|
935
|
+
'orderBook': this.handleOrderBook,
|
|
936
|
+
'depth': this.handleOrderBook,
|
|
937
|
+
'candle': this.handleOHLCV,
|
|
938
|
+
'kline': this.handleOHLCV,
|
|
939
|
+
'ticker': this.handleTicker,
|
|
940
|
+
'instrumentInfo': this.handleTicker,
|
|
941
|
+
'trade': this.handleTrades,
|
|
942
|
+
'recentlyTrade': this.handleTrades,
|
|
943
|
+
'pong': this.handlePong,
|
|
944
|
+
'auth': this.handleAuthenticate,
|
|
945
|
+
};
|
|
946
|
+
const exacMethod = this.safeValue(methods, topic);
|
|
947
|
+
if (exacMethod !== undefined) {
|
|
948
|
+
exacMethod.call(this, client, message);
|
|
949
|
+
return;
|
|
950
|
+
}
|
|
951
|
+
const keys = Object.keys(methods);
|
|
952
|
+
for (let i = 0; i < keys.length; i++) {
|
|
953
|
+
const key = keys[i];
|
|
954
|
+
if (topic.indexOf(keys[i]) >= 0) {
|
|
955
|
+
const method = methods[key];
|
|
956
|
+
method.call(this, client, message);
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
959
|
+
}
|
|
960
|
+
// unified auth acknowledgement
|
|
961
|
+
const type = this.safeString(message, 'type');
|
|
962
|
+
if (type === 'AUTH_RESP') {
|
|
963
|
+
this.handleAuthenticate(client, message);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
ping(client) {
|
|
967
|
+
const timeStamp = this.milliseconds().toString();
|
|
968
|
+
return {
|
|
969
|
+
'args': [timeStamp],
|
|
970
|
+
'op': 'ping',
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
handlePong(client, message) {
|
|
974
|
+
//
|
|
975
|
+
// {
|
|
976
|
+
// "success": true,
|
|
977
|
+
// "ret_msg": "pong",
|
|
978
|
+
// "conn_id": "db3158a0-8960-44b9-a9de-ac350ee13158",
|
|
979
|
+
// "request": { op: "ping", args: null }
|
|
980
|
+
// }
|
|
981
|
+
//
|
|
982
|
+
// { pong: 1653296711335 }
|
|
983
|
+
//
|
|
984
|
+
client.lastPong = this.safeInteger(message, 'pong');
|
|
985
|
+
return message;
|
|
986
|
+
}
|
|
987
|
+
handleAccount(client, message) {
|
|
988
|
+
const contents = this.safeDict(message, 'contents', {});
|
|
989
|
+
const fills = this.safeList(contents, 'fills', []);
|
|
990
|
+
if (fills !== undefined) {
|
|
991
|
+
this.handleMyTrades(client, fills);
|
|
992
|
+
}
|
|
993
|
+
const positions = this.safeList(contents, 'positions', []);
|
|
994
|
+
if (positions !== undefined) {
|
|
995
|
+
this.handlePositions(client, positions);
|
|
996
|
+
}
|
|
997
|
+
const orders = this.safeList(contents, 'orders', []);
|
|
998
|
+
if (orders !== undefined) {
|
|
999
|
+
this.handleOrder(client, orders);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
handleAuthenticate(client, message) {
|
|
1003
|
+
//
|
|
1004
|
+
// {
|
|
1005
|
+
// "success": true,
|
|
1006
|
+
// "ret_msg": '',
|
|
1007
|
+
// "op": "auth",
|
|
1008
|
+
// "conn_id": "ce3dpomvha7dha97tvp0-2xh"
|
|
1009
|
+
// }
|
|
1010
|
+
//
|
|
1011
|
+
const success = this.safeValue(message, 'success');
|
|
1012
|
+
const code = this.safeInteger(message, 'retCode');
|
|
1013
|
+
const messageHash = 'authenticated';
|
|
1014
|
+
if (success || code === 0) {
|
|
1015
|
+
const future = this.safeValue(client.futures, messageHash);
|
|
1016
|
+
future.resolve(true);
|
|
1017
|
+
}
|
|
1018
|
+
else {
|
|
1019
|
+
const error = new AuthenticationError(this.id + ' ' + this.json(message));
|
|
1020
|
+
client.reject(error, messageHash);
|
|
1021
|
+
if (messageHash in client.subscriptions) {
|
|
1022
|
+
delete client.subscriptions[messageHash];
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
return message;
|
|
1026
|
+
}
|
|
1027
|
+
handleSubscriptionStatus(client, message) {
|
|
1028
|
+
//
|
|
1029
|
+
// {
|
|
1030
|
+
// "topic": "kline",
|
|
1031
|
+
// "event": "sub",
|
|
1032
|
+
// "params": {
|
|
1033
|
+
// "symbol": "LTCUSDT",
|
|
1034
|
+
// "binary": "false",
|
|
1035
|
+
// "klineType": "1m",
|
|
1036
|
+
// "symbolName": "LTCUSDT"
|
|
1037
|
+
// },
|
|
1038
|
+
// "code": "0",
|
|
1039
|
+
// "msg": "Success"
|
|
1040
|
+
// }
|
|
1041
|
+
//
|
|
1042
|
+
return message;
|
|
1043
|
+
}
|
|
1044
|
+
}
|