ccxt 4.1.44 → 4.1.46

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 (242) hide show
  1. package/README.md +3 -3
  2. package/dist/ccxt.browser.js +2132 -768
  3. package/dist/ccxt.browser.min.js +9 -9
  4. package/dist/cjs/ccxt.js +1 -1
  5. package/dist/cjs/src/ace.js +1 -3
  6. package/dist/cjs/src/ascendex.js +1 -3
  7. package/dist/cjs/src/base/Exchange.js +11 -3
  8. package/dist/cjs/src/base/ws/Cache.js +50 -0
  9. package/dist/cjs/src/bigone.js +2 -6
  10. package/dist/cjs/src/binance.js +16 -12
  11. package/dist/cjs/src/bit2c.js +2 -4
  12. package/dist/cjs/src/bitbns.js +5 -15
  13. package/dist/cjs/src/bitfinex.js +1 -3
  14. package/dist/cjs/src/bitfinex2.js +1 -3
  15. package/dist/cjs/src/bitflyer.js +4 -12
  16. package/dist/cjs/src/bitforex.js +4 -8
  17. package/dist/cjs/src/bithumb.js +4 -10
  18. package/dist/cjs/src/bitmart.js +64 -59
  19. package/dist/cjs/src/bitmex.js +2 -6
  20. package/dist/cjs/src/bitopro.js +6 -16
  21. package/dist/cjs/src/bitrue.js +6 -14
  22. package/dist/cjs/src/bitvavo.js +9 -14
  23. package/dist/cjs/src/btctradeua.js +2 -4
  24. package/dist/cjs/src/bybit.js +88 -132
  25. package/dist/cjs/src/cex.js +2 -4
  26. package/dist/cjs/src/coinbasepro.js +2 -2
  27. package/dist/cjs/src/coinex.js +7 -24
  28. package/dist/cjs/src/coinfalcon.js +1 -3
  29. package/dist/cjs/src/coinmate.js +2 -4
  30. package/dist/cjs/src/coinone.js +2 -6
  31. package/dist/cjs/src/coinsph.js +5 -13
  32. package/dist/cjs/src/cryptocom.js +1 -1
  33. package/dist/cjs/src/currencycom.js +2 -6
  34. package/dist/cjs/src/gate.js +5 -7
  35. package/dist/cjs/src/gemini.js +1 -3
  36. package/dist/cjs/src/hitbtc.js +290 -100
  37. package/dist/cjs/src/hollaex.js +1 -3
  38. package/dist/cjs/src/huobi.js +4 -14
  39. package/dist/cjs/src/huobijp.js +1 -3
  40. package/dist/cjs/src/indodax.js +4 -10
  41. package/dist/cjs/src/kucoinfutures.js +2 -7
  42. package/dist/cjs/src/kuna.js +1 -0
  43. package/dist/cjs/src/luno.js +1 -3
  44. package/dist/cjs/src/mercado.js +7 -17
  45. package/dist/cjs/src/mexc.js +5 -15
  46. package/dist/cjs/src/oceanex.js +2 -4
  47. package/dist/cjs/src/okx.js +33 -21
  48. package/dist/cjs/src/phemex.js +12 -33
  49. package/dist/cjs/src/poloniexfutures.js +2 -6
  50. package/dist/cjs/src/pro/binance.js +203 -1
  51. package/dist/cjs/src/pro/bitget.js +181 -0
  52. package/dist/cjs/src/pro/bitmart.js +2 -4
  53. package/dist/cjs/src/pro/bitrue.js +0 -4
  54. package/dist/cjs/src/pro/bitstamp.js +2 -4
  55. package/dist/cjs/src/pro/bitvavo.js +3 -7
  56. package/dist/cjs/src/pro/bybit.js +154 -10
  57. package/dist/cjs/src/pro/cex.js +2 -6
  58. package/dist/cjs/src/pro/cryptocom.js +131 -1
  59. package/dist/cjs/src/pro/gate.js +161 -0
  60. package/dist/cjs/src/pro/huobi.js +128 -4
  61. package/dist/cjs/src/pro/krakenfutures.js +129 -0
  62. package/dist/cjs/src/pro/kucoinfutures.js +182 -0
  63. package/dist/cjs/src/pro/okx.js +121 -0
  64. package/dist/cjs/src/pro/whitebit.js +3 -7
  65. package/dist/cjs/src/probit.js +2 -6
  66. package/dist/cjs/src/tokocrypto.js +3 -7
  67. package/dist/cjs/src/wavesexchange.js +2 -4
  68. package/dist/cjs/src/wazirx.js +4 -10
  69. package/dist/cjs/src/whitebit.js +3 -7
  70. package/dist/cjs/src/woo.js +0 -3
  71. package/dist/cjs/src/yobit.js +3 -7
  72. package/js/ccxt.d.ts +1 -1
  73. package/js/ccxt.js +1 -1
  74. package/js/src/abstract/bequant.d.ts +37 -7
  75. package/js/src/abstract/binance.d.ts +1 -0
  76. package/js/src/abstract/binancecoinm.d.ts +1 -0
  77. package/js/src/abstract/binanceus.d.ts +1 -0
  78. package/js/src/abstract/binanceusdm.d.ts +1 -0
  79. package/js/src/abstract/bitcoincom.d.ts +37 -7
  80. package/js/src/abstract/bybit.d.ts +3 -0
  81. package/js/src/abstract/fmfwio.d.ts +37 -7
  82. package/js/src/abstract/hitbtc.d.ts +37 -7
  83. package/js/src/abstract/hitbtc3.d.ts +37 -7
  84. package/js/src/abstract/okex.d.ts +6 -1
  85. package/js/src/abstract/okex5.d.ts +6 -1
  86. package/js/src/abstract/okx.d.ts +6 -1
  87. package/js/src/ace.d.ts +2 -2
  88. package/js/src/ace.js +2 -4
  89. package/js/src/alpaca.d.ts +2 -2
  90. package/js/src/ascendex.d.ts +2 -2
  91. package/js/src/ascendex.js +1 -3
  92. package/js/src/base/Exchange.d.ts +4 -1
  93. package/js/src/base/Exchange.js +11 -3
  94. package/js/src/base/ws/Cache.d.ts +5 -1
  95. package/js/src/base/ws/Cache.js +50 -1
  96. package/js/src/bigone.d.ts +2 -2
  97. package/js/src/bigone.js +3 -7
  98. package/js/src/binance.d.ts +2 -2
  99. package/js/src/binance.js +16 -12
  100. package/js/src/bingx.d.ts +2 -2
  101. package/js/src/bit2c.d.ts +2 -2
  102. package/js/src/bit2c.js +3 -5
  103. package/js/src/bitbank.d.ts +2 -2
  104. package/js/src/bitbns.d.ts +2 -2
  105. package/js/src/bitbns.js +5 -15
  106. package/js/src/bitfinex.d.ts +2 -2
  107. package/js/src/bitfinex.js +1 -3
  108. package/js/src/bitfinex2.js +1 -3
  109. package/js/src/bitflyer.d.ts +2 -2
  110. package/js/src/bitflyer.js +4 -12
  111. package/js/src/bitforex.d.ts +2 -2
  112. package/js/src/bitforex.js +5 -9
  113. package/js/src/bitget.d.ts +2 -2
  114. package/js/src/bithumb.d.ts +2 -2
  115. package/js/src/bithumb.js +4 -10
  116. package/js/src/bitmart.d.ts +2 -2
  117. package/js/src/bitmart.js +64 -59
  118. package/js/src/bitmex.js +2 -6
  119. package/js/src/bitopro.d.ts +2 -2
  120. package/js/src/bitopro.js +6 -16
  121. package/js/src/bitpanda.d.ts +2 -2
  122. package/js/src/bitrue.d.ts +2 -2
  123. package/js/src/bitrue.js +6 -14
  124. package/js/src/bitso.d.ts +2 -2
  125. package/js/src/bitstamp.d.ts +2 -2
  126. package/js/src/bitstamp1.d.ts +2 -2
  127. package/js/src/bittrex.d.ts +2 -2
  128. package/js/src/bitvavo.d.ts +2 -2
  129. package/js/src/bitvavo.js +9 -14
  130. package/js/src/bl3p.d.ts +2 -2
  131. package/js/src/blockchaincom.d.ts +4 -4
  132. package/js/src/btcalpha.d.ts +2 -2
  133. package/js/src/btcbox.d.ts +2 -2
  134. package/js/src/btcmarkets.d.ts +2 -2
  135. package/js/src/btctradeua.d.ts +2 -2
  136. package/js/src/btctradeua.js +3 -5
  137. package/js/src/btcturk.d.ts +2 -2
  138. package/js/src/bybit.d.ts +2 -4
  139. package/js/src/bybit.js +88 -132
  140. package/js/src/cex.d.ts +2 -2
  141. package/js/src/cex.js +2 -4
  142. package/js/src/coinbase.d.ts +2 -2
  143. package/js/src/coinbasepro.d.ts +2 -2
  144. package/js/src/coinbasepro.js +2 -2
  145. package/js/src/coincheck.d.ts +2 -2
  146. package/js/src/coinex.js +7 -24
  147. package/js/src/coinfalcon.d.ts +2 -2
  148. package/js/src/coinfalcon.js +2 -4
  149. package/js/src/coinlist.d.ts +12 -12
  150. package/js/src/coinmate.d.ts +3 -3
  151. package/js/src/coinmate.js +3 -5
  152. package/js/src/coinone.d.ts +2 -2
  153. package/js/src/coinone.js +2 -6
  154. package/js/src/coinsph.d.ts +2 -2
  155. package/js/src/coinsph.js +5 -13
  156. package/js/src/coinspot.d.ts +2 -2
  157. package/js/src/cryptocom.d.ts +2 -2
  158. package/js/src/cryptocom.js +1 -1
  159. package/js/src/currencycom.d.ts +2 -2
  160. package/js/src/currencycom.js +2 -6
  161. package/js/src/delta.d.ts +2 -2
  162. package/js/src/deribit.d.ts +3 -3
  163. package/js/src/digifinex.d.ts +2 -2
  164. package/js/src/gate.d.ts +2 -2
  165. package/js/src/gate.js +5 -7
  166. package/js/src/gemini.d.ts +3 -3
  167. package/js/src/gemini.js +1 -3
  168. package/js/src/hitbtc.d.ts +3 -0
  169. package/js/src/hitbtc.js +291 -101
  170. package/js/src/hollaex.js +1 -3
  171. package/js/src/huobi.d.ts +2 -2
  172. package/js/src/huobi.js +4 -14
  173. package/js/src/huobijp.d.ts +2 -2
  174. package/js/src/huobijp.js +2 -4
  175. package/js/src/independentreserve.d.ts +2 -2
  176. package/js/src/indodax.d.ts +2 -2
  177. package/js/src/indodax.js +4 -10
  178. package/js/src/kraken.d.ts +2 -2
  179. package/js/src/krakenfutures.d.ts +2 -2
  180. package/js/src/kucoin.d.ts +2 -2
  181. package/js/src/kucoinfutures.d.ts +2 -2
  182. package/js/src/kucoinfutures.js +2 -7
  183. package/js/src/kuna.d.ts +3 -3
  184. package/js/src/kuna.js +1 -0
  185. package/js/src/latoken.d.ts +2 -2
  186. package/js/src/lbank2.d.ts +2 -2
  187. package/js/src/luno.d.ts +2 -2
  188. package/js/src/luno.js +1 -3
  189. package/js/src/lykke.d.ts +2 -2
  190. package/js/src/mercado.d.ts +2 -2
  191. package/js/src/mercado.js +7 -17
  192. package/js/src/mexc.js +5 -15
  193. package/js/src/novadax.d.ts +2 -2
  194. package/js/src/oceanex.d.ts +4 -4
  195. package/js/src/oceanex.js +2 -4
  196. package/js/src/okcoin.d.ts +2 -2
  197. package/js/src/okx.d.ts +2 -2
  198. package/js/src/okx.js +33 -21
  199. package/js/src/paymium.d.ts +2 -2
  200. package/js/src/phemex.js +12 -33
  201. package/js/src/poloniexfutures.d.ts +2 -2
  202. package/js/src/poloniexfutures.js +2 -6
  203. package/js/src/pro/binance.d.ts +6 -0
  204. package/js/src/pro/binance.js +204 -2
  205. package/js/src/pro/bitget.d.ts +3 -0
  206. package/js/src/pro/bitget.js +182 -1
  207. package/js/src/pro/bitmart.js +2 -4
  208. package/js/src/pro/bitrue.js +0 -4
  209. package/js/src/pro/bitstamp.js +3 -5
  210. package/js/src/pro/bitvavo.js +4 -8
  211. package/js/src/pro/bybit.d.ts +5 -1
  212. package/js/src/pro/bybit.js +156 -12
  213. package/js/src/pro/cex.js +3 -7
  214. package/js/src/pro/cryptocom.d.ts +4 -0
  215. package/js/src/pro/cryptocom.js +132 -2
  216. package/js/src/pro/gate.d.ts +5 -0
  217. package/js/src/pro/gate.js +162 -1
  218. package/js/src/pro/huobi.d.ts +2 -0
  219. package/js/src/pro/huobi.js +129 -5
  220. package/js/src/pro/krakenfutures.d.ts +3 -0
  221. package/js/src/pro/krakenfutures.js +129 -0
  222. package/js/src/pro/kucoinfutures.d.ts +5 -0
  223. package/js/src/pro/kucoinfutures.js +182 -0
  224. package/js/src/pro/okx.d.ts +2 -0
  225. package/js/src/pro/okx.js +123 -2
  226. package/js/src/pro/whitebit.js +4 -8
  227. package/js/src/probit.d.ts +2 -2
  228. package/js/src/probit.js +3 -7
  229. package/js/src/timex.d.ts +2 -2
  230. package/js/src/tokocrypto.d.ts +2 -2
  231. package/js/src/tokocrypto.js +4 -8
  232. package/js/src/wavesexchange.js +3 -5
  233. package/js/src/wazirx.d.ts +2 -2
  234. package/js/src/wazirx.js +5 -11
  235. package/js/src/whitebit.d.ts +2 -2
  236. package/js/src/whitebit.js +3 -7
  237. package/js/src/woo.d.ts +2 -2
  238. package/js/src/woo.js +1 -4
  239. package/js/src/yobit.js +3 -7
  240. package/js/src/zaif.d.ts +2 -2
  241. package/package.json +1 -1
  242. package/skip-tests.json +3 -1
@@ -7,7 +7,7 @@
7
7
  // ---------------------------------------------------------------------------
8
8
  import cryptocomRest from '../cryptocom.js';
9
9
  import { AuthenticationError, NetworkError } from '../base/errors.js';
10
- import { ArrayCache, ArrayCacheByTimestamp, ArrayCacheBySymbolById } from '../base/ws/Cache.js';
10
+ import { ArrayCache, ArrayCacheByTimestamp, ArrayCacheBySymbolById, ArrayCacheBySymbolBySide } from '../base/ws/Cache.js';
11
11
  import { sha256 } from '../static_dependencies/noble-hashes/sha256.js';
12
12
  // ---------------------------------------------------------------------------
13
13
  export default class cryptocom extends cryptocomRest {
@@ -25,6 +25,7 @@ export default class cryptocom extends cryptocomRest {
25
25
  'watchOrderBookForSymbols': true,
26
26
  'watchOrders': true,
27
27
  'watchOHLCV': true,
28
+ 'watchPositions': true,
28
29
  'createOrderWs': true,
29
30
  'cancelOrderWs': true,
30
31
  'cancelAllOrders': true,
@@ -41,7 +42,12 @@ export default class cryptocom extends cryptocomRest {
41
42
  'private': 'wss://uat-stream.3ona.co/exchange/v1/user',
42
43
  },
43
44
  },
44
- 'options': {},
45
+ 'options': {
46
+ 'watchPositions': {
47
+ 'fetchPositionsSnapshot': true,
48
+ 'awaitPositionsSnapshot': true, // whether to wait for the positions snapshot before providing updates
49
+ },
50
+ },
45
51
  'streaming': {},
46
52
  });
47
53
  }
@@ -450,6 +456,129 @@ export default class cryptocom extends cryptocomRest {
450
456
  client.resolve(stored, 'user.order');
451
457
  }
452
458
  }
459
+ async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
460
+ /**
461
+ * @method
462
+ * @name cryptocom#watchPositions
463
+ * @description watch all open positions
464
+ * @see https://exchange-docs.crypto.com/exchange/v1/rest-ws/index.html#user-position_balance
465
+ * @param {[string]|undefined} symbols list of unified market symbols
466
+ * @param {object} params extra parameters specific to the cryptocom api endpoint
467
+ * @returns {[object]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
468
+ */
469
+ await this.loadMarkets();
470
+ await this.authenticate();
471
+ const url = this.urls['api']['ws']['private'];
472
+ const id = this.nonce();
473
+ const request = {
474
+ 'method': 'subscribe',
475
+ 'params': {
476
+ 'channels': ['user.position_balance'],
477
+ },
478
+ 'nonce': id,
479
+ };
480
+ let messageHash = 'positions';
481
+ symbols = this.marketSymbols(symbols);
482
+ if (!this.isEmpty(symbols)) {
483
+ messageHash = '::' + symbols.join(',');
484
+ }
485
+ const client = this.client(url);
486
+ this.setPositionsCache(client, symbols);
487
+ const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
488
+ const awaitPositionsSnapshot = this.safeValue('watchPositions', 'awaitPositionsSnapshot', true);
489
+ if (fetchPositionsSnapshot && awaitPositionsSnapshot && this.positions === undefined) {
490
+ const snapshot = await client.future('fetchPositionsSnapshot');
491
+ return this.filterBySymbolsSinceLimit(snapshot, symbols, since, limit, true);
492
+ }
493
+ const newPositions = await this.watch(url, messageHash, this.extend(request, params));
494
+ if (this.newUpdates) {
495
+ return newPositions;
496
+ }
497
+ return this.filterBySymbolsSinceLimit(this.positions, symbols, since, limit, true);
498
+ }
499
+ setPositionsCache(client, type, symbols = undefined) {
500
+ const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', false);
501
+ if (fetchPositionsSnapshot) {
502
+ const messageHash = 'fetchPositionsSnapshot';
503
+ if (!(messageHash in client.futures)) {
504
+ client.future(messageHash);
505
+ this.spawn(this.loadPositionsSnapshot, client, messageHash);
506
+ }
507
+ }
508
+ else {
509
+ this.positions = new ArrayCacheBySymbolBySide();
510
+ }
511
+ }
512
+ async loadPositionsSnapshot(client, messageHash) {
513
+ const positions = await this.fetchPositions();
514
+ this.positions = new ArrayCacheBySymbolBySide();
515
+ const cache = this.positions;
516
+ for (let i = 0; i < positions.length; i++) {
517
+ const position = positions[i];
518
+ const contracts = this.safeNumber(position, 'contracts', 0);
519
+ if (contracts > 0) {
520
+ cache.append(position);
521
+ }
522
+ }
523
+ // don't remove the future from the .futures cache
524
+ const future = client.futures[messageHash];
525
+ future.resolve(cache);
526
+ client.resolve(cache, 'positions');
527
+ }
528
+ handlePositions(client, message) {
529
+ //
530
+ // {
531
+ // subscription: "user.position_balance",
532
+ // channel: "user.position_balance",
533
+ // data: [{
534
+ // balances: [{
535
+ // instrument_name: "USD",
536
+ // quantity: "8.9979961950886",
537
+ // update_timestamp_ms: 1695598760597,
538
+ // }],
539
+ // positions: [{
540
+ // account_id: "96a0edb1-afb5-4c7c-af89-5cb610319e2c",
541
+ // instrument_name: "LTCUSD-PERP",
542
+ // type: "PERPETUAL_SWAP",
543
+ // quantity: "1.8",
544
+ // cost: "114.766",
545
+ // open_position_pnl: "-0.0216206",
546
+ // session_pnl: "0.00962994",
547
+ // update_timestamp_ms: 1695598760597,
548
+ // open_pos_cost: "114.766",
549
+ // }],
550
+ // }],
551
+ // }
552
+ //
553
+ // each account is connected to a different endpoint
554
+ // and has exactly one subscriptionhash which is the account type
555
+ const data = this.safeValue(message, 'data', []);
556
+ const firstData = this.safeValue(data, 0, {});
557
+ const rawPositions = this.safeValue(firstData, 'positions', []);
558
+ if (this.positions === undefined) {
559
+ this.positions = new ArrayCacheBySymbolBySide();
560
+ }
561
+ const cache = this.positions;
562
+ const newPositions = [];
563
+ for (let i = 0; i < rawPositions.length; i++) {
564
+ const rawPosition = rawPositions[i];
565
+ const position = this.parsePosition(rawPosition);
566
+ newPositions.push(position);
567
+ cache.append(position);
568
+ }
569
+ const messageHashes = this.findMessageHashes(client, 'positions::');
570
+ for (let i = 0; i < messageHashes.length; i++) {
571
+ const messageHash = messageHashes[i];
572
+ const parts = messageHash.split('::');
573
+ const symbolsString = parts[1];
574
+ const symbols = symbolsString.split(',');
575
+ const positions = this.filterByArray(newPositions, 'symbol', symbols, false);
576
+ if (!this.isEmpty(positions)) {
577
+ client.resolve(positions, messageHash);
578
+ }
579
+ }
580
+ client.resolve(newPositions, 'positions');
581
+ }
453
582
  async watchBalance(params = {}) {
454
583
  /**
455
584
  * @method
@@ -716,6 +845,7 @@ export default class cryptocom extends cryptocomRest {
716
845
  'user.order': this.handleOrders,
717
846
  'user.trade': this.handleTrades,
718
847
  'user.balance': this.handleBalance,
848
+ 'user.position_balance': this.handlePositions,
719
849
  };
720
850
  const result = this.safeValue2(message, 'result', 'info');
721
851
  const channel = this.safeString(result, 'channel');
@@ -21,6 +21,10 @@ export default class gate extends gateRest {
21
21
  handleMyTrades(client: Client, message: any): void;
22
22
  watchBalance(params?: {}): Promise<any>;
23
23
  handleBalance(client: Client, message: any): void;
24
+ watchPositions(symbols?: string[], since?: Int, limit?: Int, params?: {}): Promise<any>;
25
+ setPositionsCache(client: Client, type: any, symbols?: string[]): void;
26
+ loadPositionsSnapshot(client: any, messageHash: any, type: any): Promise<void>;
27
+ handlePositions(client: any, message: any): void;
24
28
  watchOrders(symbol?: string, since?: Int, limit?: Int, params?: {}): Promise<any>;
25
29
  handleOrder(client: Client, message: any): void;
26
30
  handleErrorMessage(client: Client, message: any): boolean;
@@ -30,6 +34,7 @@ export default class gate extends gateRest {
30
34
  getUrlByMarket(market: any): any;
31
35
  getTypeByMarket(market: any): "spot" | "futures" | "options";
32
36
  getUrlByMarketType(type: any, isInverse?: boolean): any;
37
+ getMarketTypeByUrl(url: string): any;
33
38
  requestId(): any;
34
39
  subscribePublic(url: any, messageHash: any, payload: any, channel: any, params?: {}, subscription?: any): Promise<any>;
35
40
  subscribePrivate(url: any, messageHash: any, payload: any, channel: any, params: any, requiresUid?: boolean): Promise<any>;
@@ -7,7 +7,7 @@
7
7
  // ---------------------------------------------------------------------------
8
8
  import gateRest from '../gate.js';
9
9
  import { AuthenticationError, BadRequest, ArgumentsRequired, InvalidNonce } from '../base/errors.js';
10
- import { ArrayCache, ArrayCacheByTimestamp, ArrayCacheBySymbolById } from '../base/ws/Cache.js';
10
+ import { ArrayCache, ArrayCacheByTimestamp, ArrayCacheBySymbolById, ArrayCacheBySymbolBySide } from '../base/ws/Cache.js';
11
11
  import { sha512 } from '../static_dependencies/noble-hashes/sha512.js';
12
12
  // ---------------------------------------------------------------------------
13
13
  export default class gate extends gateRest {
@@ -24,6 +24,7 @@ export default class gate extends gateRest {
24
24
  'watchOHLCV': true,
25
25
  'watchBalance': true,
26
26
  'watchOrders': true,
27
+ 'watchPositions': true,
27
28
  },
28
29
  'urls': {
29
30
  'api': {
@@ -75,6 +76,10 @@ export default class gate extends gateRest {
75
76
  'settle': 'usdt',
76
77
  'spot': 'spot.balances', // spot.margin_balances, spot.funding_balances or spot.cross_balances
77
78
  },
79
+ 'watchPositions': {
80
+ 'fetchPositionsSnapshot': true,
81
+ 'awaitPositionsSnapshot': true, // whether to wait for the positions snapshot before providing updates
82
+ },
78
83
  },
79
84
  'exceptions': {
80
85
  'ws': {
@@ -753,6 +758,145 @@ export default class gate extends gateRest {
753
758
  this.balance = this.safeBalance(this.balance);
754
759
  client.resolve(this.balance, messageHash);
755
760
  }
761
+ async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
762
+ /**
763
+ * @method
764
+ * @name gate#watchPositions
765
+ * @see https://www.gate.io/docs/developers/futures/ws/en/#positions-subscription
766
+ * @see https://www.gate.io/docs/developers/delivery/ws/en/#positions-subscription
767
+ * @see https://www.gate.io/docs/developers/options/ws/en/#positions-channel
768
+ * @description watch all open positions
769
+ * @param {[string]|undefined} symbols list of unified market symbols
770
+ * @param {object} params extra parameters specific to the gate api endpoint
771
+ * @returns {[object]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
772
+ */
773
+ await this.loadMarkets();
774
+ let market = undefined;
775
+ symbols = this.marketSymbols(symbols);
776
+ const payload = ['!' + 'all'];
777
+ if (!this.isEmpty(symbols)) {
778
+ market = this.getMarketFromSymbols(symbols);
779
+ }
780
+ let type = undefined;
781
+ let query = undefined;
782
+ [type, query] = this.handleMarketTypeAndParams('watchPositions', market, params);
783
+ if (type === 'spot') {
784
+ type = 'swap';
785
+ }
786
+ const typeId = this.getSupportedMapping(type, {
787
+ 'future': 'futures',
788
+ 'swap': 'futures',
789
+ 'option': 'options',
790
+ });
791
+ let messageHash = type + ':positions';
792
+ if (!this.isEmpty(symbols)) {
793
+ messageHash += '::' + symbols.join(',');
794
+ }
795
+ const channel = typeId + '.positions';
796
+ let subType = undefined;
797
+ [subType, query] = this.handleSubTypeAndParams('watchPositions', market, query);
798
+ const isInverse = (subType === 'inverse');
799
+ const url = this.getUrlByMarketType(type, isInverse);
800
+ const client = this.client(url);
801
+ this.setPositionsCache(client, type, symbols);
802
+ const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
803
+ const awaitPositionsSnapshot = this.safeValue('watchPositions', 'awaitPositionsSnapshot', true);
804
+ const cache = this.safeValue(this.positions, type);
805
+ if (fetchPositionsSnapshot && awaitPositionsSnapshot && cache === undefined) {
806
+ return await client.future(type + ':fetchPositionsSnapshot');
807
+ }
808
+ const positions = await this.subscribePrivate(url, messageHash, payload, channel, query, true);
809
+ if (this.newUpdates) {
810
+ return positions;
811
+ }
812
+ return this.filterBySymbolsSinceLimit(this.positions, symbols, since, limit, true);
813
+ }
814
+ setPositionsCache(client, type, symbols = undefined) {
815
+ if (this.positions === undefined) {
816
+ this.positions = {};
817
+ }
818
+ if (type in this.positions) {
819
+ return;
820
+ }
821
+ const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', false);
822
+ if (fetchPositionsSnapshot) {
823
+ const messageHash = type + ':fetchPositionsSnapshot';
824
+ if (!(messageHash in client.futures)) {
825
+ client.future(messageHash);
826
+ this.spawn(this.loadPositionsSnapshot, client, messageHash, type);
827
+ }
828
+ }
829
+ else {
830
+ this.positions[type] = new ArrayCacheBySymbolBySide();
831
+ }
832
+ }
833
+ async loadPositionsSnapshot(client, messageHash, type) {
834
+ const positions = await this.fetchPositions(undefined, { 'type': type });
835
+ this.positions[type] = new ArrayCacheBySymbolBySide();
836
+ const cache = this.positions[type];
837
+ for (let i = 0; i < positions.length; i++) {
838
+ const position = positions[i];
839
+ cache.append(position);
840
+ }
841
+ // don't remove the future from the .futures cache
842
+ const future = client.futures[messageHash];
843
+ future.resolve(cache);
844
+ client.resolve(cache, type + ':position');
845
+ }
846
+ handlePositions(client, message) {
847
+ //
848
+ // {
849
+ // time: 1693158497,
850
+ // time_ms: 1693158497204,
851
+ // channel: 'futures.positions',
852
+ // event: 'update',
853
+ // result: [{
854
+ // contract: 'XRP_USDT',
855
+ // cross_leverage_limit: 0,
856
+ // entry_price: 0.5253,
857
+ // history_pnl: 0,
858
+ // history_point: 0,
859
+ // last_close_pnl: 0,
860
+ // leverage: 0,
861
+ // leverage_max: 50,
862
+ // liq_price: 0.0361,
863
+ // maintenance_rate: 0.01,
864
+ // margin: 4.89609962852,
865
+ // mode: 'single',
866
+ // realised_pnl: -0.0026265,
867
+ // realised_point: 0,
868
+ // risk_limit: 500000,
869
+ // size: 1,
870
+ // time: 1693158497,
871
+ // time_ms: 1693158497195,
872
+ // update_id: 1,
873
+ // user: '10444586'
874
+ // }]
875
+ // }
876
+ //
877
+ const type = this.getMarketTypeByUrl(client.url);
878
+ const data = this.safeValue(message, 'result', []);
879
+ const cache = this.positions[type];
880
+ const newPositions = [];
881
+ for (let i = 0; i < data.length; i++) {
882
+ const rawPosition = data[i];
883
+ const position = this.parsePosition(rawPosition);
884
+ newPositions.push(position);
885
+ cache.append(position);
886
+ }
887
+ const messageHashes = this.findMessageHashes(client, type + ':positions::');
888
+ for (let i = 0; i < messageHashes.length; i++) {
889
+ const messageHash = messageHashes[i];
890
+ const parts = messageHash.split('::');
891
+ const symbolsString = parts[1];
892
+ const symbols = symbolsString.split(',');
893
+ const positions = this.filterByArray(newPositions, 'symbol', symbols, false);
894
+ if (!this.isEmpty(positions)) {
895
+ client.resolve(positions, messageHash);
896
+ }
897
+ }
898
+ client.resolve(newPositions, type + ':positions');
899
+ }
756
900
  async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
757
901
  /**
758
902
  * @method
@@ -1039,6 +1183,7 @@ export default class gate extends gateRest {
1039
1183
  'usertrades': this.handleMyTrades,
1040
1184
  'candlesticks': this.handleOHLCV,
1041
1185
  'orders': this.handleOrder,
1186
+ 'positions': this.handlePositions,
1042
1187
  'tickers': this.handleTicker,
1043
1188
  'book_ticker': this.handleTicker,
1044
1189
  'trades': this.handleTrades,
@@ -1080,6 +1225,22 @@ export default class gate extends gateRest {
1080
1225
  return url;
1081
1226
  }
1082
1227
  }
1228
+ getMarketTypeByUrl(url) {
1229
+ const findBy = {
1230
+ 'op-': 'option',
1231
+ 'delivery': 'future',
1232
+ 'fx': 'swap',
1233
+ };
1234
+ const keys = Object.keys(findBy);
1235
+ for (let i = 0; i < keys.length; i++) {
1236
+ const key = keys[i];
1237
+ const value = findBy[key];
1238
+ if (url.indexOf(key) >= 0) {
1239
+ return value;
1240
+ }
1241
+ }
1242
+ return 'spot';
1243
+ }
1083
1244
  requestId() {
1084
1245
  // their support said that reqid must be an int32, not documented
1085
1246
  const reqid = this.sum(this.safeInteger(this.options, 'reqid', 0), 1);
@@ -24,6 +24,8 @@ export default class huobi extends huobiRest {
24
24
  handleOrder(client: Client, message: any): void;
25
25
  parseWsOrder(order: any, market?: any): import("../base/types.js").Order;
26
26
  parseOrderTrade(trade: any, market?: any): import("../base/types.js").Trade;
27
+ watchPositions(symbols?: string[], since?: Int, limit?: Int, params?: {}): Promise<any>;
28
+ handlePositions(client: any, message: any): void;
27
29
  watchBalance(params?: {}): Promise<any>;
28
30
  handleBalance(client: Client, message: any): void;
29
31
  handleSubscriptionStatus(client: Client, message: any): any;
@@ -7,7 +7,7 @@
7
7
  // ---------------------------------------------------------------------------
8
8
  import huobiRest from '../huobi.js';
9
9
  import { ExchangeError, InvalidNonce, ArgumentsRequired, BadRequest, BadSymbol, AuthenticationError, NetworkError } from '../base/errors.js';
10
- import { ArrayCache, ArrayCacheByTimestamp, ArrayCacheBySymbolById } from '../base/ws/Cache.js';
10
+ import { ArrayCache, ArrayCacheByTimestamp, ArrayCacheBySymbolById, ArrayCacheBySymbolBySide } from '../base/ws/Cache.js';
11
11
  import { sha256 } from '../static_dependencies/noble-hashes/sha256.js';
12
12
  // ---------------------------------------------------------------------------
13
13
  export default class huobi extends huobiRest {
@@ -70,14 +70,14 @@ export default class huobi extends huobiRest {
70
70
  },
71
71
  },
72
72
  'swap': {
73
- 'inverse': {
74
- 'public': 'wss://api.hbdm.vn/swap-ws',
75
- 'private': 'wss://api.hbdm.vn/swap-notification',
76
- },
77
73
  'linear': {
78
74
  'public': 'wss://api.hbdm.vn/linear-swap-ws',
79
75
  'private': 'wss://api.hbdm.vn/linear-swap-notification',
80
76
  },
77
+ 'inverse': {
78
+ 'public': 'wss://api.hbdm.vn/swap-ws',
79
+ 'private': 'wss://api.hbdm.vn/swap-notification',
80
+ },
81
81
  },
82
82
  },
83
83
  },
@@ -1190,6 +1190,127 @@ export default class huobi extends huobiRest {
1190
1190
  'fee': undefined,
1191
1191
  }, market);
1192
1192
  }
1193
+ async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
1194
+ /**
1195
+ * @method
1196
+ * @name huobi#watchPositions
1197
+ * @see https://www.huobi.com/en-in/opend/newApiPages/?id=8cb7de1c-77b5-11ed-9966-0242ac110003
1198
+ * @see https://www.huobi.com/en-in/opend/newApiPages/?id=8cb7df0f-77b5-11ed-9966-0242ac110003
1199
+ * @see https://www.huobi.com/en-in/opend/newApiPages/?id=28c34a7d-77ae-11ed-9966-0242ac110003
1200
+ * @see https://www.huobi.com/en-in/opend/newApiPages/?id=5d5156b5-77b6-11ed-9966-0242ac110003
1201
+ * @description watch all open positions. Note: huobi has one channel for each marginMode and type
1202
+ * @param {[string]|undefined} symbols list of unified market symbols
1203
+ * @param {object} params extra parameters specific to the huobi api endpoint
1204
+ * @returns {[object]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
1205
+ */
1206
+ await this.loadMarkets();
1207
+ let market = undefined;
1208
+ let messageHash = '';
1209
+ if (!this.isEmpty(symbols)) {
1210
+ market = this.getMarketFromSymbols(symbols);
1211
+ messageHash = '::' + symbols.join(',');
1212
+ }
1213
+ let type = undefined;
1214
+ let subType = undefined;
1215
+ if (market !== undefined) {
1216
+ type = market['type'];
1217
+ subType = market['linear'] ? 'linear' : 'inverse';
1218
+ }
1219
+ else {
1220
+ [type, params] = this.handleMarketTypeAndParams('watchPositions', market, params);
1221
+ if (type === 'spot') {
1222
+ type = 'future';
1223
+ }
1224
+ [subType, params] = this.handleOptionAndParams(params, 'watchPositions', 'subType', subType);
1225
+ }
1226
+ symbols = this.marketSymbols(symbols);
1227
+ let marginMode = undefined;
1228
+ [marginMode, params] = this.handleMarginModeAndParams('watchPositions', params, 'cross');
1229
+ const isLinear = (subType === 'linear');
1230
+ const url = this.getUrlByMarketType(type, isLinear, true);
1231
+ messageHash = marginMode + ':positions' + messageHash;
1232
+ const channel = (marginMode === 'cross') ? 'positions_cross.*' : 'positions.*';
1233
+ const newPositions = await this.subscribePrivate(channel, messageHash, type, subType, params);
1234
+ if (this.newUpdates) {
1235
+ return newPositions;
1236
+ }
1237
+ return this.filterBySymbolsSinceLimit(this.positions[url][marginMode], symbols, since, limit, false);
1238
+ }
1239
+ handlePositions(client, message) {
1240
+ //
1241
+ // {
1242
+ // op: 'notify',
1243
+ // topic: 'positions_cross',
1244
+ // ts: 1696767149650,
1245
+ // event: 'snapshot',
1246
+ // data: [
1247
+ // {
1248
+ // contract_type: 'swap',
1249
+ // pair: 'BTC-USDT',
1250
+ // business_type: 'swap',
1251
+ // liquidation_price: null,
1252
+ // symbol: 'BTC',
1253
+ // contract_code: 'BTC-USDT',
1254
+ // volume: 1,
1255
+ // available: 1,
1256
+ // frozen: 0,
1257
+ // cost_open: 27802.2,
1258
+ // cost_hold: 27802.2,
1259
+ // profit_unreal: 0.0175,
1260
+ // profit_rate: 0.000629446590557581,
1261
+ // profit: 0.0175,
1262
+ // margin_asset: 'USDT',
1263
+ // position_margin: 27.8197,
1264
+ // lever_rate: 1,
1265
+ // direction: 'buy',
1266
+ // last_price: 27819.7,
1267
+ // margin_mode: 'cross',
1268
+ // margin_account: 'USDT',
1269
+ // trade_partition: 'USDT',
1270
+ // position_mode: 'dual_side'
1271
+ // },
1272
+ // ]
1273
+ // }
1274
+ //
1275
+ const url = client.url;
1276
+ const topic = this.safeString(message, 'topic', '');
1277
+ const marginMode = (topic === 'positions_cross') ? 'cross' : 'isolated';
1278
+ if (this.positions === undefined) {
1279
+ this.positions = {};
1280
+ }
1281
+ const clientPositions = this.safeValue(this.positions, url);
1282
+ if (clientPositions === undefined) {
1283
+ this.positions[url] = {};
1284
+ }
1285
+ const clientMarginModePositions = this.safeValue(clientPositions, marginMode);
1286
+ if (clientMarginModePositions === undefined) {
1287
+ this.positions[url][marginMode] = new ArrayCacheBySymbolBySide();
1288
+ }
1289
+ const cache = this.positions[url][marginMode];
1290
+ const rawPositions = this.safeValue(message, 'data', []);
1291
+ const newPositions = [];
1292
+ const timestamp = this.safeInteger(message, 'ts');
1293
+ for (let i = 0; i < rawPositions.length; i++) {
1294
+ const rawPosition = rawPositions[i];
1295
+ const position = this.parsePosition(rawPosition);
1296
+ position['timestamp'] = timestamp;
1297
+ position['datetime'] = this.iso8601(timestamp);
1298
+ newPositions.push(position);
1299
+ cache.append(position);
1300
+ }
1301
+ const messageHashes = this.findMessageHashes(client, marginMode + ':positions::');
1302
+ for (let i = 0; i < messageHashes.length; i++) {
1303
+ const messageHash = messageHashes[i];
1304
+ const parts = messageHash.split('::');
1305
+ const symbolsString = parts[1];
1306
+ const symbols = symbolsString.split(',');
1307
+ const positions = this.filterByArray(newPositions, 'symbol', symbols, false);
1308
+ if (!this.isEmpty(positions)) {
1309
+ client.resolve(positions, messageHash);
1310
+ }
1311
+ }
1312
+ client.resolve(newPositions, marginMode + ':positions');
1313
+ }
1193
1314
  async watchBalance(params = {}) {
1194
1315
  /**
1195
1316
  * @method
@@ -1693,6 +1814,9 @@ export default class huobi extends huobiRest {
1693
1814
  if (topic.indexOf('account') >= 0) {
1694
1815
  this.handleBalance(client, message);
1695
1816
  }
1817
+ if (topic.indexOf('positions') >= 0) {
1818
+ this.handlePositions(client, message);
1819
+ }
1696
1820
  }
1697
1821
  }
1698
1822
  async pong(client, message) {
@@ -10,6 +10,9 @@ export default class krakenfutures extends krakenfuturesRest {
10
10
  watchTickers(symbols?: string[], params?: {}): Promise<any>;
11
11
  watchTrades(symbol?: string, since?: Int, limit?: Int, params?: {}): Promise<any>;
12
12
  watchOrderBook(symbol: string, limit?: Int, params?: {}): Promise<any>;
13
+ watchPositions(symbols?: string[], since?: Int, limit?: Int, params?: {}): Promise<any>;
14
+ handlePositions(client: any, message: any): void;
15
+ parseWsPosition(position: any, market?: any): import("../base/types.js").Position;
13
16
  watchOrders(symbol?: string, since?: Int, limit?: Int, params?: {}): Promise<any>;
14
17
  watchMyTrades(symbol?: string, since?: Int, limit?: Int, params?: {}): Promise<any>;
15
18
  watchBalance(params?: {}): Promise<any>;