ccxt 4.3.65 → 4.3.67

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.
Files changed (48) hide show
  1. package/README.md +4 -3
  2. package/dist/ccxt.browser.min.js +2 -2
  3. package/dist/cjs/ccxt.js +1 -1
  4. package/dist/cjs/src/base/Exchange.js +2 -2
  5. package/dist/cjs/src/bingx.js +151 -19
  6. package/dist/cjs/src/bithumb.js +61 -17
  7. package/dist/cjs/src/hyperliquid.js +63 -7
  8. package/dist/cjs/src/independentreserve.js +0 -1
  9. package/dist/cjs/src/kraken.js +27 -0
  10. package/dist/cjs/src/pro/hyperliquid.js +103 -1
  11. package/dist/cjs/src/pro/okx.js +22 -9
  12. package/js/ccxt.d.ts +1 -1
  13. package/js/ccxt.js +1 -1
  14. package/js/src/abstract/bingx.d.ts +7 -0
  15. package/js/src/base/Exchange.d.ts +14 -13
  16. package/js/src/base/Exchange.js +2 -2
  17. package/js/src/bingx.js +151 -19
  18. package/js/src/bithumb.js +61 -17
  19. package/js/src/hyperliquid.d.ts +3 -1
  20. package/js/src/hyperliquid.js +63 -7
  21. package/js/src/independentreserve.js +1 -1
  22. package/js/src/kraken.d.ts +7 -0
  23. package/js/src/kraken.js +27 -0
  24. package/js/src/pro/bitget.d.ts +1 -1
  25. package/js/src/pro/bybit.d.ts +1 -1
  26. package/js/src/pro/coinone.d.ts +1 -1
  27. package/js/src/pro/currencycom.d.ts +1 -1
  28. package/js/src/pro/hollaex.d.ts +1 -1
  29. package/js/src/pro/hyperliquid.d.ts +5 -2
  30. package/js/src/pro/hyperliquid.js +103 -1
  31. package/js/src/pro/kucoin.d.ts +1 -1
  32. package/js/src/pro/kucoinfutures.d.ts +1 -1
  33. package/js/src/pro/mexc.d.ts +1 -1
  34. package/js/src/pro/okcoin.d.ts +1 -1
  35. package/js/src/pro/okx.d.ts +2 -2
  36. package/js/src/pro/okx.js +23 -10
  37. package/js/src/pro/oxfun.d.ts +1 -1
  38. package/js/src/pro/p2b.d.ts +1 -1
  39. package/js/src/pro/poloniex.d.ts +1 -1
  40. package/js/src/pro/whitebit.d.ts +1 -1
  41. package/package.json +1 -1
  42. package/dist/cjs/src/abstract/bittrex.js +0 -9
  43. package/dist/cjs/src/bittrex.js +0 -2308
  44. package/dist/cjs/src/pro/bittrex.js +0 -959
  45. package/js/src/bittrex.d.ts +0 -97
  46. package/js/src/bittrex.js +0 -2309
  47. package/js/src/pro/bittrex.d.ts +0 -69
  48. package/js/src/pro/bittrex.js +0 -960
@@ -1,960 +0,0 @@
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 bittrexRest from '../bittrex.js';
9
- import { InvalidNonce, BadRequest, ExchangeError, AuthenticationError } from '../base/errors.js';
10
- import { ArrayCache, ArrayCacheByTimestamp, ArrayCacheBySymbolById } from '../base/ws/Cache.js';
11
- import { sha512 } from '../static_dependencies/noble-hashes/sha512.js';
12
- import { inflateSync as inflate } from '../static_dependencies/fflake/browser.js';
13
- // ---------------------------------------------------------------------------
14
- export default class bittrex extends bittrexRest {
15
- describe() {
16
- return this.deepExtend(super.describe(), {
17
- 'has': {
18
- 'ws': true,
19
- 'cancelAllOrdersWs': false,
20
- 'cancelOrdersWs': false,
21
- 'cancelOrderWs': false,
22
- 'createOrderWs': false,
23
- 'editOrderWs': false,
24
- 'fetchBalanceWs': false,
25
- 'fetchOpenOrdersWs': false,
26
- 'fetchOrderWs': false,
27
- 'fetchTradesWs': false,
28
- 'watchBalance': true,
29
- 'watchHeartbeat': true,
30
- 'watchMyTrades': true,
31
- 'watchOHLCV': true,
32
- 'watchOrderBook': true,
33
- 'watchOrders': true,
34
- 'watchTicker': true,
35
- 'watchTickers': false,
36
- 'watchTrades': true,
37
- },
38
- 'urls': {
39
- 'api': {
40
- 'ws': 'wss://socket-v3.bittrex.com/signalr/connect',
41
- 'signalr': 'https://socket-v3.bittrex.com/signalr',
42
- },
43
- },
44
- 'api': {
45
- 'signalr': {
46
- 'get': [
47
- 'negotiate',
48
- 'start',
49
- ],
50
- },
51
- },
52
- 'options': {
53
- 'tradesLimit': 1000,
54
- 'OHLCVLimit': 1000,
55
- 'hub': 'c3',
56
- 'I': this.milliseconds(),
57
- 'watchOrderBook': {
58
- 'maxRetries': 3,
59
- },
60
- },
61
- 'exceptions': {
62
- 'exact': {
63
- 'INVALID_APIKEY': AuthenticationError,
64
- 'UNAUTHORIZED_USER': AuthenticationError,
65
- },
66
- },
67
- });
68
- }
69
- getSignalRUrl(negotiation) {
70
- const connectionToken = this.safeString(negotiation['response'], 'ConnectionToken');
71
- const query = this.extend(negotiation['request'], {
72
- 'connectionToken': connectionToken,
73
- // 'tid': this.milliseconds () % 10,
74
- });
75
- return this.urls['api']['ws'] + '?' + this.urlencode(query);
76
- }
77
- makeRequest(requestId, method, args) {
78
- const hub = this.safeString(this.options, 'hub', 'c3');
79
- return {
80
- 'H': hub,
81
- 'M': method,
82
- 'A': args,
83
- 'I': requestId, // invocation request id
84
- };
85
- }
86
- makeRequestToSubscribe(requestId, args) {
87
- const method = 'Subscribe';
88
- return this.makeRequest(requestId, method, args);
89
- }
90
- makeRequestToAuthenticate(requestId) {
91
- const timestamp = this.milliseconds();
92
- const uuid = this.uuid();
93
- const auth = timestamp.toString() + uuid;
94
- const signature = this.hmac(this.encode(auth), this.encode(this.secret), sha512);
95
- const args = [this.apiKey, timestamp, uuid, signature];
96
- const method = 'Authenticate';
97
- return this.makeRequest(requestId, method, args);
98
- }
99
- requestId() {
100
- // their support said that reqid must be an int32, not documented
101
- const reqid = this.sum(this.safeInteger(this.options, 'I', 0), 1);
102
- this.options['I'] = reqid;
103
- return reqid;
104
- }
105
- async sendRequestToSubscribe(negotiation, messageHash, subscription, params = {}) {
106
- const args = [messageHash];
107
- const requestId = this.requestId().toString();
108
- const request = this.makeRequestToSubscribe(requestId, [args]);
109
- subscription = this.extend({
110
- 'id': requestId,
111
- 'negotiation': negotiation,
112
- }, subscription);
113
- const url = this.getSignalRUrl(negotiation);
114
- return await this.watch(url, messageHash, request, messageHash, subscription);
115
- }
116
- async authenticate(params = {}) {
117
- this.checkRequiredCredentials();
118
- await this.loadMarkets();
119
- const request = await this.negotiate();
120
- return await this.sendRequestToAuthenticate(request, false, params);
121
- }
122
- async sendRequestToAuthenticate(negotiation, expired = false, params = {}) {
123
- const url = this.getSignalRUrl(negotiation);
124
- const client = this.client(url);
125
- const messageHash = 'authenticate';
126
- let future = this.safeValue(client.subscriptions, messageHash);
127
- if ((future === undefined) || expired) {
128
- future = client.future(messageHash);
129
- client.subscriptions[messageHash] = future;
130
- const requestId = this.requestId().toString();
131
- const request = this.makeRequestToAuthenticate(requestId);
132
- const subscription = {
133
- 'id': requestId,
134
- 'params': params,
135
- 'negotiation': negotiation,
136
- 'method': this.handleAuthenticate,
137
- };
138
- this.watch(url, messageHash, request, requestId, subscription);
139
- }
140
- return await future;
141
- }
142
- async sendAuthenticatedRequestToSubscribe(authentication, messageHash, params = {}) {
143
- const negotiation = this.safeValue(authentication, 'negotiation');
144
- const subscription = { 'params': params };
145
- return await this.sendRequestToSubscribe(negotiation, messageHash, subscription, params);
146
- }
147
- handleAuthenticate(client, message, subscription) {
148
- const requestId = this.safeString(subscription, 'id');
149
- if (requestId in client.subscriptions) {
150
- delete client.subscriptions[requestId];
151
- }
152
- client.resolve(subscription, 'authenticate');
153
- }
154
- async handleAuthenticationExpiringHelper() {
155
- const negotiation = await this.negotiate();
156
- return await this.sendRequestToAuthenticate(negotiation, true);
157
- }
158
- handleAuthenticationExpiring(client, message) {
159
- //
160
- // {
161
- // "C": "d-B1733F58-B,0|vT7,1|vT8,2|vBR,3",
162
- // "M": [ { H: "C3", M: "authenticationExpiring", A: [] } ]
163
- // }
164
- //
165
- // resend the authentication request and refresh the subscription
166
- //
167
- this.spawn(this.handleAuthenticationExpiringHelper);
168
- }
169
- createSignalRQuery(params = {}) {
170
- const hub = this.safeString(this.options, 'hub', 'c3');
171
- const hubs = [
172
- { 'name': hub },
173
- ];
174
- const ms = this.milliseconds();
175
- return this.extend({
176
- 'transport': 'webSockets',
177
- 'connectionData': this.json(hubs),
178
- 'clientProtocol': 1.5,
179
- '_': ms,
180
- 'tid': this.sum(ms % 10, 1), // random
181
- }, params);
182
- }
183
- async negotiate(params = {}) {
184
- const client = this.client(this.urls['api']['ws']);
185
- const messageHash = 'negotiate';
186
- let future = this.safeValue(client.subscriptions, messageHash);
187
- if (future === undefined) {
188
- future = client.future(messageHash);
189
- client.subscriptions[messageHash] = future;
190
- const request = this.createSignalRQuery(params);
191
- const response = await this.signalrGetNegotiate(this.extend(request, params));
192
- //
193
- // {
194
- // "Url": "/signalr/v1.1/signalr",
195
- // "ConnectionToken": "lT/sa19+FcrEb4W53On2v+Pcc3d4lVCHV5/WJtmQw1RQNQMpm7K78w/WnvfTN2EgwQopTUiFX1dioHN7Bd1p8jAbfdxrqf5xHAMntJfOrw1tON0O",
196
- // "ConnectionId": "a2afb0f7-346f-4f32-b7c7-01e04584b86a",
197
- // "KeepAliveTimeout": 20,
198
- // "DisconnectTimeout": 30,
199
- // "ConnectionTimeout": 110,
200
- // "TryWebSockets": true,
201
- // "ProtocolVersion": "1.5",
202
- // "TransportConnectTimeout": 5,
203
- // "LongPollDelay": 0
204
- // }
205
- //
206
- const result = {
207
- 'request': request,
208
- 'response': response,
209
- };
210
- client.resolve(result, messageHash);
211
- }
212
- return await future;
213
- }
214
- async start(negotiation, params = {}) {
215
- const connectionToken = this.safeString(negotiation['response'], 'ConnectionToken');
216
- const request = this.createSignalRQuery(this.extend(negotiation['request'], {
217
- 'connectionToken': connectionToken,
218
- }));
219
- return await this.signalrGetStart(request);
220
- }
221
- async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
222
- /**
223
- * @method
224
- * @name bittrex#watchOrders
225
- * @description watches information on multiple orders made by the user
226
- * @param {string} symbol unified market symbol of the market orders were made in
227
- * @param {int} [since] the earliest time in ms to fetch orders for
228
- * @param {int} [limit] the maximum number of orde structures to retrieve
229
- * @param {object} [params] extra parameters specific to the exchange API endpoint
230
- * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
231
- */
232
- await this.loadMarkets();
233
- if (symbol !== undefined) {
234
- symbol = this.symbol(symbol);
235
- }
236
- const authentication = await this.authenticate();
237
- const orders = await this.subscribeToOrders(authentication, params);
238
- if (this.newUpdates) {
239
- limit = orders.getLimit(symbol, limit);
240
- }
241
- return this.filterBySymbolSinceLimit(orders, symbol, since, limit, true);
242
- }
243
- async subscribeToOrders(authentication, params = {}) {
244
- const messageHash = 'order';
245
- return await this.sendAuthenticatedRequestToSubscribe(authentication, messageHash, params);
246
- }
247
- handleOrder(client, message) {
248
- //
249
- // {
250
- // "accountId": "2832c5c6-ac7a-493e-bc16-ebca06c73670",
251
- // "sequence": 41,
252
- // "delta": {
253
- // "id": "b91eff76-10eb-4382-834a-b753b770283e",
254
- // "marketSymbol": "BTC-USDT",
255
- // "direction": "BUY",
256
- // "type": "LIMIT",
257
- // "quantity": "0.01000000",
258
- // "limit": "3000.00000000",
259
- // "timeInForce": "GOOD_TIL_CANCELLED",
260
- // "fillQuantity": "0.00000000",
261
- // "commission": "0.00000000",
262
- // "proceeds": "0.00000000",
263
- // "status": "OPEN",
264
- // "createdAt": "2020-10-07T12:51:43.16Z",
265
- // "updatedAt": "2020-10-07T12:51:43.16Z"
266
- // }
267
- // }
268
- //
269
- const delta = this.safeValue(message, 'delta', {});
270
- const parsed = this.parseOrder(delta);
271
- if (this.orders === undefined) {
272
- const limit = this.safeInteger(this.options, 'ordersLimit', 1000);
273
- this.orders = new ArrayCacheBySymbolById(limit);
274
- }
275
- const orders = this.orders;
276
- orders.append(parsed);
277
- const messageHash = 'order';
278
- client.resolve(this.orders, messageHash);
279
- }
280
- async watchBalance(params = {}) {
281
- /**
282
- * @method
283
- * @name bittrex#watchBalance
284
- * @description watch balance and get the amount of funds available for trading or funds locked in orders
285
- * @param {object} [params] extra parameters specific to the exchange API endpoint
286
- * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
287
- */
288
- await this.loadMarkets();
289
- const authentication = await this.authenticate();
290
- return await this.subscribeToBalance(authentication, params);
291
- }
292
- async subscribeToBalance(authentication, params = {}) {
293
- const messageHash = 'balance';
294
- return await this.sendAuthenticatedRequestToSubscribe(authentication, messageHash, params);
295
- }
296
- handleBalance(client, message) {
297
- //
298
- // {
299
- // "accountId": "2832c5c6-ac7a-493e-bc16-ebca06c73670",
300
- // "sequence": 9,
301
- // "delta": {
302
- // "currencySymbol": "USDT",
303
- // "total": "32.88918476",
304
- // "available": "2.82918476",
305
- // "updatedAt": "2020-10-06T13:49:20.29Z"
306
- // }
307
- // }
308
- //
309
- const delta = this.safeValue(message, 'delta', {});
310
- this.balance['info'] = delta;
311
- const currencyId = this.safeString(delta, 'currencySymbol');
312
- const code = this.safeCurrencyCode(currencyId);
313
- const account = this.account();
314
- account['free'] = this.safeString(delta, 'available');
315
- account['total'] = this.safeString(delta, 'total');
316
- this.balance[code] = account;
317
- this.balance = this.safeBalance(this.balance);
318
- const messageHash = 'balance';
319
- client.resolve(this.balance, messageHash);
320
- }
321
- async watchHeartbeat(params = {}) {
322
- await this.loadMarkets();
323
- const negotiation = await this.negotiate();
324
- return await this.subscribeToHeartbeat(negotiation, params);
325
- }
326
- async subscribeToHeartbeat(negotiation, params = {}) {
327
- await this.loadMarkets();
328
- const url = this.getSignalRUrl(negotiation);
329
- const requestId = this.milliseconds().toString();
330
- const messageHash = 'heartbeat';
331
- const args = [messageHash];
332
- const request = this.makeRequestToSubscribe(requestId, [args]);
333
- const subscription = {
334
- 'id': requestId,
335
- 'params': params,
336
- 'negotiation': negotiation,
337
- };
338
- return await this.watch(url, messageHash, request, messageHash, subscription);
339
- }
340
- handleHeartbeat(client, message) {
341
- //
342
- // every 20 seconds (approx) if no other updates are sent
343
- //
344
- // {}
345
- //
346
- client.resolve(message, 'heartbeat');
347
- }
348
- async watchTicker(symbol, params = {}) {
349
- /**
350
- * @method
351
- * @name bittrex#watchTicker
352
- * @description watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
353
- * @param {string} symbol unified symbol of the market to fetch the ticker for
354
- * @param {object} [params] extra parameters specific to the exchange API endpoint
355
- * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
356
- */
357
- await this.loadMarkets();
358
- const negotiation = await this.negotiate();
359
- return await this.subscribeToTicker(negotiation, symbol, params);
360
- }
361
- async subscribeToTicker(negotiation, symbol, params = {}) {
362
- await this.loadMarkets();
363
- const market = this.market(symbol);
364
- symbol = market['symbol'];
365
- const name = 'ticker';
366
- const messageHash = name + '_' + market['id'];
367
- const subscription = {
368
- 'marketId': market['id'],
369
- 'symbol': symbol,
370
- 'params': params,
371
- };
372
- return await this.sendRequestToSubscribe(negotiation, messageHash, subscription);
373
- }
374
- handleTicker(client, message) {
375
- //
376
- // summary subscription update
377
- //
378
- // ...
379
- //
380
- // ticker subscription update
381
- //
382
- // {
383
- // "symbol": "BTC-USDT",
384
- // "lastTradeRate": "10701.02140008",
385
- // "bidRate": "10701.02140007",
386
- // "askRate": "10705.71049998"
387
- // }
388
- //
389
- const ticker = this.parseTicker(message);
390
- const symbol = ticker['symbol'];
391
- const market = this.market(symbol);
392
- this.tickers[symbol] = ticker;
393
- const name = 'ticker';
394
- const messageHash = name + '_' + market['id'];
395
- client.resolve(ticker, messageHash);
396
- }
397
- async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
398
- /**
399
- * @method
400
- * @name bittrex#watchOHLCV
401
- * @description watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
402
- * @param {string} symbol unified symbol of the market to fetch OHLCV data for
403
- * @param {string} timeframe the length of time each candle represents
404
- * @param {int} [since] timestamp in ms of the earliest candle to fetch
405
- * @param {int} [limit] the maximum amount of candles to fetch
406
- * @param {object} [params] extra parameters specific to the exchange API endpoint
407
- * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
408
- */
409
- await this.loadMarkets();
410
- symbol = this.symbol(symbol);
411
- const negotiation = await this.negotiate();
412
- const ohlcv = await this.subscribeToOHLCV(negotiation, symbol, timeframe, params);
413
- if (this.newUpdates) {
414
- limit = ohlcv.getLimit(symbol, limit);
415
- }
416
- return this.filterBySinceLimit(ohlcv, since, limit, 0, true);
417
- }
418
- async subscribeToOHLCV(negotiation, symbol, timeframe = '1m', params = {}) {
419
- await this.loadMarkets();
420
- const market = this.market(symbol);
421
- const interval = this.safeString(this.timeframes, timeframe, timeframe);
422
- const name = 'candle';
423
- const messageHash = name + '_' + market['id'] + '_' + interval;
424
- const subscription = {
425
- 'symbol': symbol,
426
- 'timeframe': timeframe,
427
- 'messageHash': messageHash,
428
- 'params': params,
429
- };
430
- return await this.sendRequestToSubscribe(negotiation, messageHash, subscription);
431
- }
432
- handleOHLCV(client, message) {
433
- //
434
- // {
435
- // "sequence": 28286,
436
- // "marketSymbol": "BTC-USD",
437
- // "interval": "MINUTE_1",
438
- // "delta": {
439
- // "startsAt": "2020-10-05T18:52:00Z",
440
- // "open": "10706.62600000",
441
- // "high": "10706.62600000",
442
- // "low": "10703.25900000",
443
- // "close": "10703.26000000",
444
- // "volume": "0.86822264",
445
- // "quoteVolume": "9292.84594774"
446
- // }
447
- // }
448
- //
449
- const name = 'candle';
450
- const marketId = this.safeString(message, 'marketSymbol');
451
- const symbol = this.safeSymbol(marketId, undefined, '-');
452
- const interval = this.safeString(message, 'interval');
453
- const messageHash = name + '_' + marketId + '_' + interval;
454
- const timeframe = this.findTimeframe(interval);
455
- const delta = this.safeValue(message, 'delta', {});
456
- const parsed = this.parseOHLCV(delta);
457
- this.ohlcvs[symbol] = this.safeValue(this.ohlcvs, symbol, {});
458
- let stored = this.safeValue(this.ohlcvs[symbol], timeframe);
459
- if (stored === undefined) {
460
- const limit = this.safeInteger(this.options, 'OHLCVLimit', 1000);
461
- stored = new ArrayCacheByTimestamp(limit);
462
- this.ohlcvs[symbol][timeframe] = stored;
463
- }
464
- stored.append(parsed);
465
- client.resolve(stored, messageHash);
466
- }
467
- async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
468
- /**
469
- * @method
470
- * @name bittrex#watchTrades
471
- * @description get the list of most recent trades for a particular symbol
472
- * @param {string} symbol unified symbol of the market to fetch trades for
473
- * @param {int} [since] timestamp in ms of the earliest trade to fetch
474
- * @param {int} [limit] the maximum amount of trades to fetch
475
- * @param {object} [params] extra parameters specific to the exchange API endpoint
476
- * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
477
- */
478
- await this.loadMarkets();
479
- symbol = this.symbol(symbol);
480
- const negotiation = await this.negotiate();
481
- const trades = await this.subscribeToTrades(negotiation, symbol, params);
482
- if (this.newUpdates) {
483
- limit = trades.getLimit(symbol, limit);
484
- }
485
- return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
486
- }
487
- async subscribeToTrades(negotiation, symbol, params = {}) {
488
- await this.loadMarkets();
489
- const market = this.market(symbol);
490
- const name = 'trade';
491
- const messageHash = name + '_' + market['id'];
492
- const subscription = {
493
- 'symbol': symbol,
494
- 'messageHash': messageHash,
495
- 'params': params,
496
- };
497
- return await this.sendRequestToSubscribe(negotiation, messageHash, subscription);
498
- }
499
- handleTrades(client, message) {
500
- //
501
- // {
502
- // "deltas": [
503
- // {
504
- // "id": "5bf67885-a0a8-4c62-b73d-534e480e3332",
505
- // "executedAt": "2020-10-05T23:02:17.49Z",
506
- // "quantity": "0.00166790",
507
- // "rate": "10763.97000000",
508
- // "takerSide": "BUY"
509
- // }
510
- // ],
511
- // "sequence": 24391,
512
- // "marketSymbol": "BTC-USD"
513
- // }
514
- //
515
- const deltas = this.safeValue(message, 'deltas', []);
516
- const marketId = this.safeString(message, 'marketSymbol');
517
- const symbol = this.safeSymbol(marketId, undefined, '-');
518
- const market = this.market(symbol);
519
- const name = 'trade';
520
- const messageHash = name + '_' + marketId;
521
- let stored = this.safeValue(this.trades, symbol);
522
- if (stored === undefined) {
523
- const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
524
- stored = new ArrayCache(limit);
525
- }
526
- const trades = this.parseTrades(deltas, market);
527
- for (let i = 0; i < trades.length; i++) {
528
- stored.append(trades[i]);
529
- }
530
- this.trades[symbol] = stored;
531
- client.resolve(stored, messageHash);
532
- }
533
- async watchMyTrades(symbol = undefined, since = undefined, limit = undefined, params = {}) {
534
- /**
535
- * @method
536
- * @name bittrex#watchMyTrades
537
- * @description watches information on multiple trades made by the user
538
- * @param {string} symbol unified market symbol of the market trades were made in
539
- * @param {int} [since] the earliest time in ms to fetch trades for
540
- * @param {int} [limit] the maximum number of trade structures to retrieve
541
- * @param {object} [params] extra parameters specific to the exchange API endpoint
542
- * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=trade-structure
543
- */
544
- await this.loadMarkets();
545
- if (symbol !== undefined) {
546
- symbol = this.symbol(symbol);
547
- }
548
- const authentication = await this.authenticate();
549
- const trades = await this.subscribeToMyTrades(authentication, params);
550
- if (this.newUpdates) {
551
- limit = trades.getLimit(symbol, limit);
552
- }
553
- return this.filterBySymbolSinceLimit(trades, symbol, since, limit, true);
554
- }
555
- async subscribeToMyTrades(authentication, params = {}) {
556
- const messageHash = 'execution';
557
- return await this.sendAuthenticatedRequestToSubscribe(authentication, messageHash, params);
558
- }
559
- handleMyTrades(client, message) {
560
- //
561
- // {
562
- // "accountId": "2832c5c6-ac7a-493e-bc16-ebca06c73670",
563
- // "sequence": 42,
564
- // "deltas": [
565
- // {
566
- // "id": "5bf67885-a0a8-4c62-b73d-534e480e3332",
567
- // "marketSymbol": "BTC-USDT",
568
- // "executedAt": "2020-10-05T23:02:17.49Z",
569
- // "quantity": "0.00166790",
570
- // "rate": "10763.97000000",
571
- // "orderId": "string (uuid)",
572
- // "commission": "0.00000000",
573
- // "isTaker": False
574
- // }
575
- // ]
576
- // }
577
- //
578
- const deltas = this.safeValue(message, 'deltas', {});
579
- const trades = this.parseTrades(deltas);
580
- let stored = this.myTrades;
581
- if (stored === undefined) {
582
- const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
583
- stored = new ArrayCacheBySymbolById(limit);
584
- this.myTrades = stored;
585
- }
586
- for (let i = 0; i < trades.length; i++) {
587
- stored.append(trades[i]);
588
- }
589
- const messageHash = 'execution';
590
- client.resolve(stored, messageHash);
591
- }
592
- async watchOrderBook(symbol, limit = undefined, params = {}) {
593
- /**
594
- * @method
595
- * @name bittrex#watchOrderBook
596
- * @description watches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
597
- * @param {string} symbol unified symbol of the market to fetch the order book for
598
- * @param {int} [limit] the maximum amount of order book entries to return
599
- * @param {object} [params] extra parameters specific to the exchange API endpoint
600
- * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
601
- */
602
- limit = (limit === undefined) ? 25 : limit; // 25 by default
603
- if ((limit !== 1) && (limit !== 25) && (limit !== 500)) {
604
- throw new BadRequest(this.id + ' watchOrderBook() limit argument must be undefined, 1, 25 or 500, default is 25');
605
- }
606
- await this.loadMarkets();
607
- symbol = this.symbol(symbol);
608
- const negotiation = await this.negotiate();
609
- //
610
- // 1. Subscribe to the relevant socket streams
611
- // 2. Begin to queue up messages without processing them
612
- // 3. Call the equivalent v3 REST API and record both the results and the value of the returned Sequence header. Refer to the descriptions of individual streams to find the corresponding REST API. Note that you must call the REST API with the same parameters as you used to subscribed to the stream to get the right snapshot. For example, orderbook snapshots of different depths will have different sequence numbers.
613
- // 4. If the Sequence header is less than the sequence number of the first queued socket message received (unlikely), discard the results of step 3 and then repeat step 3 until this check passes.
614
- // 5. Discard all socket messages where the sequence number is less than or equal to the Sequence header retrieved from the REST call
615
- // 6. Apply the remaining socket messages in order on top of the results of the REST call. The objects received in the socket deltas have the same schemas as the objects returned by the REST API. Each socket delta is a snapshot of an object. The identity of the object is defined by a unique key made up of one or more fields in the message (see documentation of individual streams for details). To apply socket deltas to a local cache of data, simply replace the objects in the cache with those coming from the socket where the keys match.
616
- // 7. Continue to apply messages as they are received from the socket as long as sequence number on the stream is always increasing by 1 each message (Note: for private streams, the sequence number is scoped to a single account or subaccount).
617
- // 8. If a message is received that is not the next in order, return to step 2 in this process
618
- //
619
- const market = this.market(symbol);
620
- const name = 'orderbook';
621
- const messageHash = name + '_' + market['id'] + '_' + limit.toString();
622
- const subscription = {
623
- 'symbol': symbol,
624
- 'messageHash': messageHash,
625
- 'method': this.handleOrderBookSubscription,
626
- 'limit': limit,
627
- 'params': params,
628
- };
629
- const orderbook = await this.sendRequestToSubscribe(negotiation, messageHash, subscription);
630
- return orderbook.limit();
631
- }
632
- async fetchOrderBookSnapshot(client, message, subscription) {
633
- const symbol = this.safeString(subscription, 'symbol');
634
- const limit = this.safeInteger(subscription, 'limit');
635
- const messageHash = this.safeString(subscription, 'messageHash');
636
- try {
637
- // 2. Initiate a REST request to get the snapshot data of Level 2 order book.
638
- // todo: this is a synch blocking call in ccxt.php - make it async
639
- const snapshot = await this.fetchRestOrderBookSafe(symbol, limit);
640
- const orderbook = this.orderbooks[symbol];
641
- const messages = orderbook.cache;
642
- // make sure we have at least one delta before fetching the snapshot
643
- // otherwise we cannot synchronize the feed with the snapshot
644
- // and that will lead to a bidask cross as reported here
645
- // https://github.com/ccxt/ccxt/issues/6762
646
- const firstMessage = this.safeValue(messages, 0, {});
647
- const sequence = this.safeInteger(firstMessage, 'sequence');
648
- const nonce = this.safeInteger(snapshot, 'nonce');
649
- // if the received snapshot is earlier than the first cached delta
650
- // then we cannot align it with the cached deltas and we need to
651
- // retry synchronizing in maxAttempts
652
- if ((sequence !== undefined) && (nonce < sequence)) {
653
- const maxAttempts = this.handleOption('watchOrderBook', 'maxRetries', 3);
654
- let numAttempts = this.safeInteger(subscription, 'numAttempts', 0);
655
- // retry to syncrhonize if we haven't reached maxAttempts yet
656
- if (numAttempts < maxAttempts) {
657
- // safety guard
658
- if (messageHash in client.subscriptions) {
659
- numAttempts = this.sum(numAttempts, 1);
660
- subscription['numAttempts'] = numAttempts;
661
- client.subscriptions[messageHash] = subscription;
662
- this.spawn(this.fetchOrderBookSnapshot, client, message, subscription);
663
- }
664
- }
665
- else {
666
- // throw upon failing to synchronize in maxAttempts
667
- throw new InvalidNonce(this.id + ' failed to synchronize WebSocket feed with the snapshot for symbol ' + symbol + ' in ' + maxAttempts.toString() + ' attempts');
668
- }
669
- }
670
- else {
671
- orderbook.reset(snapshot);
672
- // unroll the accumulated deltas
673
- // 3. Playback the cached Level 2 data flow.
674
- for (let i = 0; i < messages.length; i++) {
675
- const messageItem = messages[i];
676
- this.handleOrderBookMessage(client, messageItem, orderbook);
677
- }
678
- this.orderbooks[symbol] = orderbook;
679
- client.resolve(orderbook, messageHash);
680
- }
681
- }
682
- catch (e) {
683
- client.reject(e, messageHash);
684
- }
685
- }
686
- handleOrderBookSubscription(client, message, subscription) {
687
- const symbol = this.safeString(subscription, 'symbol');
688
- const limit = this.safeInteger(subscription, 'limit');
689
- if (symbol in this.orderbooks) {
690
- delete this.orderbooks[symbol];
691
- }
692
- this.orderbooks[symbol] = this.orderBook({}, limit);
693
- this.spawn(this.fetchOrderBookSnapshot, client, message, subscription);
694
- }
695
- handleDelta(bookside, delta) {
696
- //
697
- // {
698
- // "quantity": "0.05100000",
699
- // "rate": "10694.86410031"
700
- // }
701
- //
702
- const price = this.safeFloat(delta, 'rate');
703
- const amount = this.safeFloat(delta, 'quantity');
704
- bookside.store(price, amount);
705
- }
706
- handleDeltas(bookside, deltas) {
707
- //
708
- // [
709
- // { quantity: '0.05100000', rate: "10694.86410031" },
710
- // { quantity: "0", rate: "10665.72578226" }
711
- // ]
712
- //
713
- for (let i = 0; i < deltas.length; i++) {
714
- this.handleDelta(bookside, deltas[i]);
715
- }
716
- }
717
- handleOrderBook(client, message) {
718
- //
719
- // {
720
- // "marketSymbol": "BTC-USDT",
721
- // "depth": 25,
722
- // "sequence": 3009387,
723
- // "bidDeltas": [
724
- // { quantity: '0.05100000', rate: "10694.86410031" },
725
- // { quantity: "0", rate: "10665.72578226" }
726
- // ],
727
- // "askDeltas": []
728
- // }
729
- //
730
- const marketId = this.safeString(message, 'marketSymbol');
731
- const symbol = this.safeSymbol(marketId, undefined, '-');
732
- const limit = this.safeInteger(message, 'depth');
733
- let orderbook = this.safeValue(this.orderbooks, symbol);
734
- if (orderbook === undefined) {
735
- orderbook = this.orderBook({}, limit);
736
- }
737
- if (orderbook['nonce'] !== undefined) {
738
- this.handleOrderBookMessage(client, message, orderbook);
739
- }
740
- else {
741
- orderbook.cache.push(message);
742
- }
743
- }
744
- handleOrderBookMessage(client, message, orderbook) {
745
- //
746
- // {
747
- // "marketSymbol": "BTC-USDT",
748
- // "depth": 25,
749
- // "sequence": 3009387,
750
- // "bidDeltas": [
751
- // { quantity: '0.05100000', rate: "10694.86410031" },
752
- // { quantity: "0", rate: "10665.72578226" }
753
- // ],
754
- // "askDeltas": []
755
- // }
756
- //
757
- const marketId = this.safeString(message, 'marketSymbol');
758
- const depth = this.safeString(message, 'depth');
759
- const name = 'orderbook';
760
- const messageHash = name + '_' + marketId + '_' + depth;
761
- const nonce = this.safeInteger(message, 'sequence');
762
- if (nonce > orderbook['nonce']) {
763
- this.handleDeltas(orderbook['asks'], this.safeValue(message, 'askDeltas', []));
764
- this.handleDeltas(orderbook['bids'], this.safeValue(message, 'bidDeltas', []));
765
- orderbook['nonce'] = nonce;
766
- client.resolve(orderbook, messageHash);
767
- }
768
- return orderbook;
769
- }
770
- async handleSystemStatusHelper() {
771
- const negotiation = await this.negotiate();
772
- await this.start(negotiation);
773
- }
774
- handleSystemStatus(client, message) {
775
- // send signalR protocol start() call
776
- this.spawn(this.handleSystemStatusHelper);
777
- return message;
778
- }
779
- handleSubscriptionStatus(client, message) {
780
- //
781
- // success
782
- //
783
- // { R: [ { Success: true, ErrorCode: null } ], I: "1601891513224" }
784
- //
785
- // failure
786
- // todo add error handling and future rejections
787
- //
788
- // {
789
- // "I": "1601942374563",
790
- // "E": "There was an error invoking Hub method "c3.Authenticate"."
791
- // }
792
- //
793
- const I = this.safeString(message, 'I'); // noqa: E741
794
- let subscription = this.safeValue(client.subscriptions, I);
795
- if (subscription === undefined) {
796
- const subscriptionsById = this.indexBy(client.subscriptions, 'id');
797
- subscription = this.safeValue(subscriptionsById, I, {});
798
- }
799
- else {
800
- // clear if subscriptionHash === requestId (one-time request)
801
- delete client.subscriptions[I];
802
- }
803
- const method = this.safeValue(subscription, 'method');
804
- if (method === undefined) {
805
- client.resolve(message, I);
806
- }
807
- else {
808
- method.call(this, client, message, subscription);
809
- }
810
- return message;
811
- }
812
- handleErrorMessage(client, message) {
813
- //
814
- // {
815
- // "R": [{ Success: false, ErrorCode: "UNAUTHORIZED_USER" }, ... ],
816
- // "I": "1698601759267"
817
- // }
818
- // {
819
- // "R": { Success: false, ErrorCode: "INVALID_APIKEY" },
820
- // "I": "1698601759266"
821
- // }
822
- //
823
- const R = this.safeValue(message, 'R');
824
- if (R === undefined) {
825
- // Return there is no error
826
- return false;
827
- }
828
- const I = this.safeString(message, 'I');
829
- let errorCode = undefined;
830
- if (Array.isArray(R)) {
831
- for (let i = 0; i < R.length; i++) {
832
- const response = this.safeValue(R, i);
833
- const success = this.safeValue(response, 'Success', true);
834
- if (!success) {
835
- errorCode = this.safeString(response, 'ErrorCode');
836
- break;
837
- }
838
- }
839
- }
840
- else {
841
- const success = this.safeValue(R, 'Success', true);
842
- if (!success) {
843
- errorCode = this.safeString(R, 'ErrorCode');
844
- }
845
- }
846
- if (errorCode === undefined) {
847
- // Return there is no error
848
- return false;
849
- }
850
- const feedback = this.id + ' ' + errorCode;
851
- try {
852
- this.throwExactlyMatchedException(this.exceptions['exact'], errorCode, feedback);
853
- if (message !== undefined) {
854
- this.throwBroadlyMatchedException(this.exceptions['broad'], errorCode, feedback);
855
- }
856
- throw new ExchangeError(feedback);
857
- }
858
- catch (e) {
859
- if (e instanceof AuthenticationError) {
860
- client.reject(e, 'authenticate');
861
- }
862
- client.reject(e, I);
863
- }
864
- return true;
865
- }
866
- handleMessage(client, message) {
867
- //
868
- // subscription confirmation
869
- //
870
- // {
871
- // "R": [
872
- // { Success: true, ErrorCode: null }
873
- // ],
874
- // "I": "1601899375696"
875
- // }
876
- //
877
- // heartbeat subscription update
878
- //
879
- // {
880
- // "C": "d-6010FB90-B,0|o_b,0|o_c,2|8,1F4E",
881
- // "M": [
882
- // { H: "C3", M: "heartbeat", A: [] }
883
- // ]
884
- // }
885
- //
886
- // heartbeat empty message
887
- //
888
- // {}
889
- //
890
- // subscription update
891
- //
892
- // {
893
- // "C": "d-ED78B69D-E,0|rq4,0|rq5,2|puI,60C",
894
- // "M": [
895
- // {
896
- // "H": "C3",
897
- // "M": "ticker", // orderBook, trade, candle, balance, order
898
- // "A": [
899
- // "q1YqrsxNys9RslJyCnHWDQ12CVHSUcpJLC4JKUpMSQ1KLEkFShkamBsa6VkYm5paGJuZAhUkZaYgpAws9QwszAwsDY1MgFKJxdlIuiz0jM3MLIHATKkWAA=="
900
- // ]
901
- // }
902
- // ]
903
- // }
904
- //
905
- // authentication expiry notification
906
- //
907
- // {
908
- // "C": "d-B1733F58-B,0|vT7,1|vT8,2|vBR,3",
909
- // "M": [ { H: "C3", M: "authenticationExpiring", A: [] } ]
910
- // }
911
- //
912
- if (this.handleErrorMessage(client, message)) {
913
- return;
914
- }
915
- const methods = {
916
- 'authenticationExpiring': this.handleAuthenticationExpiring,
917
- 'order': this.handleOrder,
918
- 'balance': this.handleBalance,
919
- 'trade': this.handleTrades,
920
- 'candle': this.handleOHLCV,
921
- 'orderBook': this.handleOrderBook,
922
- 'heartbeat': this.handleHeartbeat,
923
- 'ticker': this.handleTicker,
924
- 'execution': this.handleMyTrades,
925
- };
926
- const M = this.safeValue(message, 'M', []);
927
- for (let i = 0; i < M.length; i++) {
928
- const methodType = this.safeValue(M[i], 'M');
929
- const method = this.safeValue(methods, methodType);
930
- if (method !== undefined) {
931
- if (methodType === 'heartbeat') {
932
- method.call(this, client, message);
933
- }
934
- else if (methodType === 'authenticationExpiring') {
935
- method.call(this, client, message);
936
- }
937
- else {
938
- const A = this.safeValue(M[i], 'A', []);
939
- for (let k = 0; k < A.length; k++) {
940
- const inflated = this.decode(inflate(this.base64ToBinary(A[k])));
941
- const update = JSON.parse(inflated);
942
- method.call(this, client, update);
943
- }
944
- }
945
- }
946
- }
947
- // resolve invocations by request id
948
- if ('I' in message) {
949
- this.handleSubscriptionStatus(client, message);
950
- }
951
- if ('S' in message) {
952
- this.handleSystemStatus(client, message);
953
- }
954
- const keys = Object.keys(message);
955
- const numKeys = keys.length;
956
- if (numKeys < 1) {
957
- this.handleHeartbeat(client, message);
958
- }
959
- }
960
- }