ccxt 4.2.89 → 4.2.91

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 (90) hide show
  1. package/CHANGELOG.md +44 -16
  2. package/README.md +3 -3
  3. package/build.sh +1 -1
  4. package/dist/ccxt.browser.js +1167 -274
  5. package/dist/ccxt.browser.min.js +6 -4
  6. package/dist/cjs/ccxt.js +1 -1
  7. package/dist/cjs/src/ascendex.js +1 -0
  8. package/dist/cjs/src/base/Exchange.js +39 -9
  9. package/dist/cjs/src/base/functions/crypto.js +37 -0
  10. package/dist/cjs/src/base/functions/rsa.js +19 -4
  11. package/dist/cjs/src/binance.js +90 -9
  12. package/dist/cjs/src/bingx.js +101 -1
  13. package/dist/cjs/src/bitfinex2.js +1 -0
  14. package/dist/cjs/src/bitget.js +2 -0
  15. package/dist/cjs/src/bitmex.js +1 -0
  16. package/dist/cjs/src/bitrue.js +1 -0
  17. package/dist/cjs/src/bybit.js +61 -0
  18. package/dist/cjs/src/coinbase.js +51 -25
  19. package/dist/cjs/src/coinbaseinternational.js +1 -0
  20. package/dist/cjs/src/coinex.js +102 -8
  21. package/dist/cjs/src/cryptocom.js +1 -0
  22. package/dist/cjs/src/delta.js +1 -0
  23. package/dist/cjs/src/digifinex.js +1 -0
  24. package/dist/cjs/src/exmo.js +1 -0
  25. package/dist/cjs/src/gate.js +2 -0
  26. package/dist/cjs/src/gemini.js +12 -10
  27. package/dist/cjs/src/hitbtc.js +1 -0
  28. package/dist/cjs/src/htx.js +1 -0
  29. package/dist/cjs/src/hyperliquid.js +1 -0
  30. package/dist/cjs/src/kraken.js +11 -9
  31. package/dist/cjs/src/kucoin.js +1 -0
  32. package/dist/cjs/src/kucoinfutures.js +34 -3
  33. package/dist/cjs/src/mexc.js +1 -0
  34. package/dist/cjs/src/okx.js +187 -38
  35. package/dist/cjs/src/phemex.js +1 -0
  36. package/dist/cjs/src/pro/bitmex.js +39 -18
  37. package/dist/cjs/src/pro/kucoin.js +91 -0
  38. package/dist/cjs/src/pro/kucoinfutures.js +151 -82
  39. package/dist/cjs/src/static_dependencies/noble-curves/p256.js +48 -0
  40. package/dist/cjs/src/woo.js +1 -0
  41. package/js/ccxt.d.ts +1 -1
  42. package/js/ccxt.js +1 -1
  43. package/js/src/abstract/bingx.d.ts +2 -0
  44. package/js/src/abstract/bybit.d.ts +2 -0
  45. package/js/src/ascendex.js +1 -0
  46. package/js/src/base/Exchange.d.ts +5 -0
  47. package/js/src/base/Exchange.js +39 -9
  48. package/js/src/base/functions/crypto.js +37 -0
  49. package/js/src/base/functions/rsa.d.ts +1 -1
  50. package/js/src/base/functions/rsa.js +21 -5
  51. package/js/src/base/types.d.ts +1 -0
  52. package/js/src/binance.d.ts +1 -0
  53. package/js/src/binance.js +90 -9
  54. package/js/src/bingx.d.ts +1 -0
  55. package/js/src/bingx.js +101 -1
  56. package/js/src/bitfinex2.js +1 -0
  57. package/js/src/bitget.js +2 -0
  58. package/js/src/bitmex.js +1 -0
  59. package/js/src/bitrue.js +1 -0
  60. package/js/src/bybit.d.ts +2 -0
  61. package/js/src/bybit.js +61 -0
  62. package/js/src/coinbase.js +51 -25
  63. package/js/src/coinbaseinternational.js +1 -0
  64. package/js/src/coinex.d.ts +2 -0
  65. package/js/src/coinex.js +102 -8
  66. package/js/src/cryptocom.js +1 -0
  67. package/js/src/delta.js +1 -0
  68. package/js/src/digifinex.js +1 -0
  69. package/js/src/exmo.js +1 -0
  70. package/js/src/gate.js +2 -0
  71. package/js/src/gemini.js +12 -10
  72. package/js/src/hitbtc.js +1 -0
  73. package/js/src/htx.js +1 -0
  74. package/js/src/hyperliquid.js +1 -0
  75. package/js/src/kraken.js +11 -9
  76. package/js/src/kucoin.js +1 -0
  77. package/js/src/kucoinfutures.d.ts +2 -9
  78. package/js/src/kucoinfutures.js +34 -3
  79. package/js/src/mexc.js +1 -0
  80. package/js/src/okx.d.ts +1 -0
  81. package/js/src/okx.js +187 -38
  82. package/js/src/phemex.js +1 -0
  83. package/js/src/pro/bitmex.d.ts +1 -0
  84. package/js/src/pro/bitmex.js +39 -18
  85. package/js/src/pro/kucoin.d.ts +4 -0
  86. package/js/src/pro/kucoin.js +91 -0
  87. package/js/src/pro/kucoinfutures.d.ts +9 -5
  88. package/js/src/pro/kucoinfutures.js +151 -82
  89. package/js/src/woo.js +1 -0
  90. package/package.json +1 -1
package/js/src/okx.js CHANGED
@@ -87,6 +87,7 @@ export default class okx extends Exchange {
87
87
  'fetchLedgerEntry': undefined,
88
88
  'fetchLeverage': true,
89
89
  'fetchLeverageTiers': false,
90
+ 'fetchMarginAdjustmentHistory': true,
90
91
  'fetchMarketLeverageTiers': true,
91
92
  'fetchMarkets': true,
92
93
  'fetchMarkOHLCV': true,
@@ -1221,7 +1222,7 @@ export default class okx extends Exchange {
1221
1222
  // ]
1222
1223
  // }
1223
1224
  //
1224
- const data = this.safeValue(response, 'data', []);
1225
+ const data = this.safeList(response, 'data', []);
1225
1226
  const dataLength = data.length;
1226
1227
  const update = {
1227
1228
  'updated': undefined,
@@ -1269,8 +1270,8 @@ export default class okx extends Exchange {
1269
1270
  // "msg": ""
1270
1271
  // }
1271
1272
  //
1272
- const data = this.safeValue(response, 'data', []);
1273
- const first = this.safeValue(data, 0, {});
1273
+ const data = this.safeList(response, 'data', []);
1274
+ const first = this.safeDict(data, 0, {});
1274
1275
  return this.safeInteger(first, 'ts');
1275
1276
  }
1276
1277
  async fetchAccounts(params = {}) {
@@ -1302,7 +1303,7 @@ export default class okx extends Exchange {
1302
1303
  // "msg": ""
1303
1304
  // }
1304
1305
  //
1305
- const data = this.safeValue(response, 'data', []);
1306
+ const data = this.safeList(response, 'data', []);
1306
1307
  const result = [];
1307
1308
  for (let i = 0; i < data.length; i++) {
1308
1309
  const account = data[i];
@@ -1327,7 +1328,7 @@ export default class okx extends Exchange {
1327
1328
  * @param {object} [params] extra parameters specific to the exchange API endpoint
1328
1329
  * @returns {object[]} an array of objects representing market data
1329
1330
  */
1330
- const types = this.safeValue(this.options, 'fetchMarkets');
1331
+ const types = this.safeList(this.options, 'fetchMarkets', []);
1331
1332
  let promises = [];
1332
1333
  let result = [];
1333
1334
  for (let i = 0; i < types.length; i++) {
@@ -1431,7 +1432,7 @@ export default class okx extends Exchange {
1431
1432
  }
1432
1433
  }
1433
1434
  const tickSize = this.safeString(market, 'tickSz');
1434
- const fees = this.safeValue2(this.fees, type, 'trading', {});
1435
+ const fees = this.safeDict2(this.fees, type, 'trading', {});
1435
1436
  let maxLeverage = this.safeString(market, 'lever', '1');
1436
1437
  maxLeverage = Precise.stringMax(maxLeverage, '1');
1437
1438
  const maxSpotCost = this.safeNumber(market, 'maxMktSz');
@@ -1490,7 +1491,7 @@ export default class okx extends Exchange {
1490
1491
  'instType': this.convertToInstrumentType(type),
1491
1492
  };
1492
1493
  if (type === 'option') {
1493
- const optionsUnderlying = this.safeValue(this.options, 'defaultUnderlying', ['BTC-USD', 'ETH-USD']);
1494
+ const optionsUnderlying = this.safeList(this.options, 'defaultUnderlying', ['BTC-USD', 'ETH-USD']);
1494
1495
  const promises = [];
1495
1496
  for (let i = 0; i < optionsUnderlying.length; i++) {
1496
1497
  const underlying = optionsUnderlying[i];
@@ -1500,8 +1501,8 @@ export default class okx extends Exchange {
1500
1501
  const promisesResult = await Promise.all(promises);
1501
1502
  let markets = [];
1502
1503
  for (let i = 0; i < promisesResult.length; i++) {
1503
- const res = this.safeValue(promisesResult, i, {});
1504
- const options = this.safeValue(res, 'data', []);
1504
+ const res = this.safeDict(promisesResult, i, {});
1505
+ const options = this.safeList(res, 'data', []);
1505
1506
  markets = this.arrayConcat(markets, options);
1506
1507
  }
1507
1508
  return this.parseMarkets(markets);
@@ -1540,7 +1541,7 @@ export default class okx extends Exchange {
1540
1541
  // "msg": ""
1541
1542
  // }
1542
1543
  //
1543
- const dataResponse = this.safeValue(response, 'data', []);
1544
+ const dataResponse = this.safeList(response, 'data', []);
1544
1545
  return this.parseMarkets(dataResponse);
1545
1546
  }
1546
1547
  safeNetwork(networkId) {
@@ -1617,7 +1618,7 @@ export default class okx extends Exchange {
1617
1618
  // "msg": ""
1618
1619
  // }
1619
1620
  //
1620
- const data = this.safeValue(response, 'data', []);
1621
+ const data = this.safeList(response, 'data', []);
1621
1622
  const result = {};
1622
1623
  const dataByCurrencyId = this.groupBy(data, 'ccy');
1623
1624
  const currencyIds = Object.keys(dataByCurrencyId);
@@ -1633,11 +1634,11 @@ export default class okx extends Exchange {
1633
1634
  let maxPrecision = undefined;
1634
1635
  for (let j = 0; j < chains.length; j++) {
1635
1636
  const chain = chains[j];
1636
- const canDeposit = this.safeValue(chain, 'canDep');
1637
+ const canDeposit = this.safeBool(chain, 'canDep');
1637
1638
  depositEnabled = (canDeposit) ? canDeposit : depositEnabled;
1638
- const canWithdraw = this.safeValue(chain, 'canWd');
1639
+ const canWithdraw = this.safeBool(chain, 'canWd');
1639
1640
  withdrawEnabled = (canWithdraw) ? canWithdraw : withdrawEnabled;
1640
- const canInternal = this.safeValue(chain, 'canInternal');
1641
+ const canInternal = this.safeBool(chain, 'canInternal');
1641
1642
  const active = (canDeposit && canWithdraw && canInternal) ? true : false;
1642
1643
  currencyActive = (active) ? active : currencyActive;
1643
1644
  const networkId = this.safeString(chain, 'chain');
@@ -1670,7 +1671,7 @@ export default class okx extends Exchange {
1670
1671
  };
1671
1672
  }
1672
1673
  }
1673
- const firstChain = this.safeValue(chains, 0);
1674
+ const firstChain = this.safeDict(chains, 0, {});
1674
1675
  result[code] = {
1675
1676
  'info': undefined,
1676
1677
  'code': code,
@@ -1746,8 +1747,8 @@ export default class okx extends Exchange {
1746
1747
  // ]
1747
1748
  // }
1748
1749
  //
1749
- const data = this.safeValue(response, 'data', []);
1750
- const first = this.safeValue(data, 0, {});
1750
+ const data = this.safeList(response, 'data', []);
1751
+ const first = this.safeDict(data, 0, {});
1751
1752
  const timestamp = this.safeInteger(first, 'ts');
1752
1753
  return this.parseOrderBook(first, symbol, timestamp);
1753
1754
  }
@@ -1848,7 +1849,7 @@ export default class okx extends Exchange {
1848
1849
  // ]
1849
1850
  // }
1850
1851
  //
1851
- const data = this.safeValue(response, 'data', []);
1852
+ const data = this.safeList(response, 'data', []);
1852
1853
  const first = this.safeDict(data, 0, {});
1853
1854
  return this.parseTicker(first, market);
1854
1855
  }
@@ -1871,7 +1872,7 @@ export default class okx extends Exchange {
1871
1872
  'instType': this.convertToInstrumentType(marketType),
1872
1873
  };
1873
1874
  if (marketType === 'option') {
1874
- const defaultUnderlying = this.safeValue(this.options, 'defaultUnderlying', 'BTC-USD');
1875
+ const defaultUnderlying = this.safeString(this.options, 'defaultUnderlying', 'BTC-USD');
1875
1876
  const currencyId = this.safeString2(params, 'uly', 'marketId', defaultUnderlying);
1876
1877
  if (currencyId === undefined) {
1877
1878
  throw new ArgumentsRequired(this.id + ' fetchTickers() requires an underlying uly or marketId parameter for options markets');
@@ -2137,7 +2138,7 @@ export default class okx extends Exchange {
2137
2138
  }
2138
2139
  const price = this.safeString(params, 'price');
2139
2140
  params = this.omit(params, 'price');
2140
- const options = this.safeValue(this.options, 'fetchOHLCV', {});
2141
+ const options = this.safeDict(this.options, 'fetchOHLCV', {});
2141
2142
  const timezone = this.safeString(options, 'timezone', 'UTC');
2142
2143
  if (limit === undefined) {
2143
2144
  limit = 100; // default 100, max 100
@@ -2270,7 +2271,7 @@ export default class okx extends Exchange {
2270
2271
  // }
2271
2272
  //
2272
2273
  const rates = [];
2273
- const data = this.safeValue(response, 'data', []);
2274
+ const data = this.safeList(response, 'data', []);
2274
2275
  for (let i = 0; i < data.length; i++) {
2275
2276
  const rate = data[i];
2276
2277
  const timestamp = this.safeInteger(rate, 'fundingTime');
@@ -2295,10 +2296,10 @@ export default class okx extends Exchange {
2295
2296
  }
2296
2297
  parseTradingBalance(response) {
2297
2298
  const result = { 'info': response };
2298
- const data = this.safeValue(response, 'data', []);
2299
- const first = this.safeValue(data, 0, {});
2299
+ const data = this.safeList(response, 'data', []);
2300
+ const first = this.safeDict(data, 0, {});
2300
2301
  const timestamp = this.safeInteger(first, 'uTime');
2301
- const details = this.safeValue(first, 'details', []);
2302
+ const details = this.safeList(first, 'details', []);
2302
2303
  for (let i = 0; i < details.length; i++) {
2303
2304
  const balance = details[i];
2304
2305
  const currencyId = this.safeString(balance, 'ccy');
@@ -2323,7 +2324,7 @@ export default class okx extends Exchange {
2323
2324
  }
2324
2325
  parseFundingBalance(response) {
2325
2326
  const result = { 'info': response };
2326
- const data = this.safeValue(response, 'data', []);
2327
+ const data = this.safeList(response, 'data', []);
2327
2328
  for (let i = 0; i < data.length; i++) {
2328
2329
  const balance = data[i];
2329
2330
  const currencyId = this.safeString(balance, 'ccy');
@@ -2407,8 +2408,8 @@ export default class okx extends Exchange {
2407
2408
  // "msg": ""
2408
2409
  // }
2409
2410
  //
2410
- const data = this.safeValue(response, 'data', []);
2411
- const first = this.safeValue(data, 0, {});
2411
+ const data = this.safeList(response, 'data', []);
2412
+ const first = this.safeDict(data, 0, {});
2412
2413
  return this.parseTradingFee(first, market);
2413
2414
  }
2414
2415
  async fetchBalance(params = {}) {
@@ -2896,8 +2897,8 @@ export default class okx extends Exchange {
2896
2897
  else {
2897
2898
  response = await this.privatePostTradeBatchOrders(request);
2898
2899
  }
2899
- const data = this.safeValue(response, 'data', []);
2900
- const first = this.safeValue(data, 0);
2900
+ const data = this.safeList(response, 'data', []);
2901
+ const first = this.safeDict(data, 0, {});
2901
2902
  const order = this.parseOrder(first, market);
2902
2903
  order['type'] = type;
2903
2904
  order['side'] = side;
@@ -4408,7 +4409,7 @@ export default class okx extends Exchange {
4408
4409
  // ]
4409
4410
  // }
4410
4411
  //
4411
- const data = this.safeValue(response, 'data', []);
4412
+ const data = this.safeList(response, 'data', []);
4412
4413
  return this.parseLedger(data, currency, since, limit);
4413
4414
  }
4414
4415
  parseLedgerEntryType(type) {
@@ -6466,9 +6467,9 @@ export default class okx extends Exchange {
6466
6467
  // }
6467
6468
  //
6468
6469
  const data = this.safeList(response, 'data', []);
6470
+ const entry = this.safeDict(data, 0, {});
6469
6471
  const errorCode = this.safeString(response, 'code');
6470
- const item = this.safeDict(data, 0, {});
6471
- return this.extend(this.parseMarginModification(item, market), {
6472
+ return this.extend(this.parseMarginModification(entry, market), {
6472
6473
  'status': (errorCode === '0') ? 'ok' : 'failed',
6473
6474
  });
6474
6475
  }
@@ -6483,22 +6484,68 @@ export default class okx extends Exchange {
6483
6484
  // "type": "reduce"
6484
6485
  // }
6485
6486
  //
6486
- const amountRaw = this.safeNumber(data, 'amt');
6487
+ // fetchMarginAdjustmentHistory
6488
+ //
6489
+ // {
6490
+ // bal: '67621.4325135010619812',
6491
+ // balChg: '-10.0000000000000000',
6492
+ // billId: '691293628710342659',
6493
+ // ccy: 'USDT',
6494
+ // clOrdId: '',
6495
+ // execType: '',
6496
+ // fee: '0',
6497
+ // fillFwdPx: '',
6498
+ // fillIdxPx: '',
6499
+ // fillMarkPx: '',
6500
+ // fillMarkVol: '',
6501
+ // fillPxUsd: '',
6502
+ // fillPxVol: '',
6503
+ // fillTime: '1711089244850',
6504
+ // from: '',
6505
+ // instId: 'XRP-USDT-SWAP',
6506
+ // instType: 'SWAP',
6507
+ // interest: '0',
6508
+ // mgnMode: 'isolated',
6509
+ // notes: '',
6510
+ // ordId: '',
6511
+ // pnl: '0',
6512
+ // posBal: '73.12',
6513
+ // posBalChg: '10.00',
6514
+ // px: '',
6515
+ // subType: '160',
6516
+ // sz: '10',
6517
+ // tag: '',
6518
+ // to: '',
6519
+ // tradeId: '0',
6520
+ // ts: '1711089244699',
6521
+ // type: '6'
6522
+ // }
6523
+ //
6524
+ const amountRaw = this.safeString2(data, 'amt', 'posBalChg');
6487
6525
  const typeRaw = this.safeString(data, 'type');
6488
- const type = (typeRaw === 'reduce') ? 'reduce' : 'add';
6526
+ let type = undefined;
6527
+ if (typeRaw === '6') {
6528
+ type = Precise.stringGt(amountRaw, '0') ? 'add' : 'reduce';
6529
+ }
6530
+ else {
6531
+ type = typeRaw;
6532
+ }
6533
+ const amount = Precise.stringAbs(amountRaw);
6489
6534
  const marketId = this.safeString(data, 'instId');
6490
6535
  const responseMarket = this.safeMarket(marketId, market);
6491
6536
  const code = responseMarket['inverse'] ? responseMarket['base'] : responseMarket['quote'];
6537
+ const timestamp = this.safeInteger(data, 'ts');
6492
6538
  return {
6493
6539
  'info': data,
6494
6540
  'symbol': responseMarket['symbol'],
6495
6541
  'type': type,
6496
- 'amount': amountRaw,
6497
- 'total': undefined,
6542
+ 'marginMode': 'isolated',
6543
+ 'amount': this.parseNumber(amount),
6498
6544
  'code': code,
6545
+ 'total': undefined,
6499
6546
  'status': undefined,
6500
- 'timestamp': undefined,
6501
- 'datetime': undefined,
6547
+ 'timestamp': timestamp,
6548
+ 'datetime': this.iso8601(timestamp),
6502
6549
  };
6503
6550
  }
6504
6551
  async reduceMargin(symbol, amount, params = {}) {
@@ -7600,4 +7647,106 @@ export default class okx extends Exchange {
7600
7647
  }
7601
7648
  return undefined;
7602
7649
  }
7650
+ async fetchMarginAdjustmentHistory(symbol = undefined, type = undefined, since = undefined, limit = undefined, params = {}) {
7651
+ /**
7652
+ * @method
7653
+ * @name okx#fetchMarginAdjustmentHistory
7654
+ * @description fetches the history of margin added or reduced from contract isolated positions
7655
+ * @see https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-bills-details-last-7-days
7656
+ * @see https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-bills-details-last-3-months
7657
+ * @param {string} [symbol] not used by okx fetchMarginAdjustmentHistory
7658
+ * @param {string} [type] "add" or "reduce"
7659
+ * @param {object} params extra parameters specific to the exchange api endpoint
7660
+ * @param {boolean} [params.auto] true if fetching auto margin increases
7661
+ * @returns {object[]} a list of [margin structures]{@link https://docs.ccxt.com/#/?id=margin-loan-structure}
7662
+ */
7663
+ await this.loadMarkets();
7664
+ const auto = this.safeBool(params, 'auto');
7665
+ if (type === undefined) {
7666
+ throw new ArgumentsRequired(this.id + ' fetchMarginAdjustmentHistory () requires a type argument');
7667
+ }
7668
+ const isAdd = type === 'add';
7669
+ let subType = isAdd ? '160' : '161';
7670
+ if (auto) {
7671
+ if (isAdd) {
7672
+ subType = '162';
7673
+ }
7674
+ else {
7675
+ throw new BadRequest(this.id + ' cannot fetch margin adjustments for type ' + type);
7676
+ }
7677
+ }
7678
+ const request = {
7679
+ 'subType': subType,
7680
+ 'mgnMode': 'isolated',
7681
+ };
7682
+ const until = this.safeInteger(params, 'until');
7683
+ params = this.omit(params, 'until');
7684
+ if (since !== undefined) {
7685
+ request['startTime'] = since;
7686
+ }
7687
+ if (limit !== undefined) {
7688
+ request['limit'] = limit;
7689
+ }
7690
+ if (until !== undefined) {
7691
+ request['endTime'] = until;
7692
+ }
7693
+ let response = undefined;
7694
+ const now = this.milliseconds();
7695
+ const oneWeekAgo = now - 604800000;
7696
+ const threeMonthsAgo = now - 7776000000;
7697
+ if ((since === undefined) || (since > oneWeekAgo)) {
7698
+ response = await this.privateGetAccountBills(this.extend(request, params));
7699
+ }
7700
+ else if (since > threeMonthsAgo) {
7701
+ response = await this.privateGetAccountBillsArchive(this.extend(request, params));
7702
+ }
7703
+ else {
7704
+ throw new BadRequest(this.id + ' fetchMarginAdjustmentHistory () cannot fetch margin adjustments older than 3 months');
7705
+ }
7706
+ //
7707
+ // {
7708
+ // code: '0',
7709
+ // data: [
7710
+ // {
7711
+ // bal: '67621.4325135010619812',
7712
+ // balChg: '-10.0000000000000000',
7713
+ // billId: '691293628710342659',
7714
+ // ccy: 'USDT',
7715
+ // clOrdId: '',
7716
+ // execType: '',
7717
+ // fee: '0',
7718
+ // fillFwdPx: '',
7719
+ // fillIdxPx: '',
7720
+ // fillMarkPx: '',
7721
+ // fillMarkVol: '',
7722
+ // fillPxUsd: '',
7723
+ // fillPxVol: '',
7724
+ // fillTime: '1711089244850',
7725
+ // from: '',
7726
+ // instId: 'XRP-USDT-SWAP',
7727
+ // instType: 'SWAP',
7728
+ // interest: '0',
7729
+ // mgnMode: 'isolated',
7730
+ // notes: '',
7731
+ // ordId: '',
7732
+ // pnl: '0',
7733
+ // posBal: '73.12',
7734
+ // posBalChg: '10.00',
7735
+ // px: '',
7736
+ // subType: '160',
7737
+ // sz: '10',
7738
+ // tag: '',
7739
+ // to: '',
7740
+ // tradeId: '0',
7741
+ // ts: '1711089244699',
7742
+ // type: '6'
7743
+ // }
7744
+ // ],
7745
+ // msg: ''
7746
+ // }
7747
+ //
7748
+ const data = this.safeList(response, 'data');
7749
+ const modifications = this.parseMarginModifications(data);
7750
+ return this.filterBySymbolSinceLimit(modifications, symbol, since, limit);
7751
+ }
7603
7752
  }
package/js/src/phemex.js CHANGED
@@ -4065,6 +4065,7 @@ export default class phemex extends Exchange {
4065
4065
  'info': data,
4066
4066
  'symbol': this.safeSymbol(undefined, market),
4067
4067
  'type': 'set',
4068
+ 'marginMode': 'isolated',
4068
4069
  'amount': undefined,
4069
4070
  'total': undefined,
4070
4071
  'code': market[codeCurrency],
@@ -20,6 +20,7 @@ export default class bitmex extends bitmexRest {
20
20
  handleMyTrades(client: Client, message: any): void;
21
21
  watchOrderBook(symbol: string, limit?: Int, params?: {}): Promise<OrderBook>;
22
22
  watchOrderBookForSymbols(symbols: string[], limit?: Int, params?: {}): Promise<OrderBook>;
23
+ watchTradesForSymbols(symbols: string[], since?: Int, limit?: Int, params?: {}): Promise<Trade[]>;
23
24
  watchOHLCV(symbol: string, timeframe?: string, since?: Int, limit?: Int, params?: {}): Promise<OHLCV[]>;
24
25
  handleOHLCV(client: Client, message: any): void;
25
26
  watchHeartbeat(params?: {}): Promise<any>;
@@ -546,8 +546,8 @@ export default class bitmex extends bitmexRest {
546
546
  for (let i = 0; i < marketIds.length; i++) {
547
547
  const marketId = marketIds[i];
548
548
  const market = this.safeMarket(marketId);
549
- const messageHash = table + ':' + marketId;
550
549
  const symbol = market['symbol'];
550
+ const messageHash = table + ':' + symbol;
551
551
  const trades = this.parseTrades(dataByMarketIds[marketId], market);
552
552
  let stored = this.safeValue(this.trades, symbol);
553
553
  if (stored === undefined) {
@@ -572,23 +572,7 @@ export default class bitmex extends bitmexRest {
572
572
  * @param {object} [params] extra parameters specific to the exchange API endpoint
573
573
  * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
574
574
  */
575
- await this.loadMarkets();
576
- const market = this.market(symbol);
577
- symbol = market['symbol'];
578
- const table = 'trade';
579
- const messageHash = table + ':' + market['id'];
580
- const url = this.urls['api']['ws'];
581
- const request = {
582
- 'op': 'subscribe',
583
- 'args': [
584
- messageHash,
585
- ],
586
- };
587
- const trades = await this.watch(url, messageHash, this.extend(request, params), messageHash);
588
- if (this.newUpdates) {
589
- limit = trades.getLimit(symbol, limit);
590
- }
591
- return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
575
+ return await this.watchTradesForSymbols([symbol], since, limit, params);
592
576
  }
593
577
  async authenticate(params = {}) {
594
578
  const url = this.urls['api']['ws'];
@@ -1221,6 +1205,43 @@ export default class bitmex extends bitmexRest {
1221
1205
  const orderbook = await this.watchMultiple(url, messageHashes, this.deepExtend(request, params), topics);
1222
1206
  return orderbook.limit();
1223
1207
  }
1208
+ async watchTradesForSymbols(symbols, since = undefined, limit = undefined, params = {}) {
1209
+ /**
1210
+ * @method
1211
+ * @name bitmex#watchTradesForSymbols
1212
+ * @description get the list of most recent trades for a list of symbols
1213
+ * @param {string[]} symbols unified symbol of the market to fetch trades for
1214
+ * @param {int} [since] timestamp in ms of the earliest trade to fetch
1215
+ * @param {int} [limit] the maximum amount of trades to fetch
1216
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1217
+ * @returns {object[]} a list of [trade structures]{@link https://docs.ccxt.com/#/?id=public-trades}
1218
+ */
1219
+ await this.loadMarkets();
1220
+ symbols = this.marketSymbols(symbols, undefined, false);
1221
+ const table = 'trade';
1222
+ const topics = [];
1223
+ const messageHashes = [];
1224
+ for (let i = 0; i < symbols.length; i++) {
1225
+ const symbol = symbols[i];
1226
+ const market = this.market(symbol);
1227
+ const topic = table + ':' + market['id'];
1228
+ topics.push(topic);
1229
+ const messageHash = table + ':' + symbol;
1230
+ messageHashes.push(messageHash);
1231
+ }
1232
+ const url = this.urls['api']['ws'];
1233
+ const request = {
1234
+ 'op': 'subscribe',
1235
+ 'args': topics,
1236
+ };
1237
+ const trades = await this.watchMultiple(url, messageHashes, this.deepExtend(request, params), topics);
1238
+ if (this.newUpdates) {
1239
+ const first = this.safeValue(trades, 0);
1240
+ const tradeSymbol = this.safeString(first, 'symbol');
1241
+ limit = trades.getLimit(tradeSymbol, limit);
1242
+ }
1243
+ return this.filterBySinceLimit(trades, since, limit, 'timestamp', true);
1244
+ }
1224
1245
  async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
1225
1246
  /**
1226
1247
  * @method
@@ -11,6 +11,10 @@ export default class kucoin extends kucoinRest {
11
11
  watchTicker(symbol: string, params?: {}): Promise<Ticker>;
12
12
  watchTickers(symbols?: Strings, params?: {}): Promise<Tickers>;
13
13
  handleTicker(client: Client, message: any): void;
14
+ watchBidsAsks(symbols?: Strings, params?: {}): Promise<Tickers>;
15
+ watchMultiHelper(methodName: any, channelName: string, symbols?: Strings, params?: {}): Promise<any>;
16
+ handleBidAsk(client: Client, message: any): void;
17
+ parseWsBidAsk(ticker: any, market?: any): Ticker;
14
18
  watchOHLCV(symbol: string, timeframe?: string, since?: Int, limit?: Int, params?: {}): Promise<OHLCV[]>;
15
19
  handleOHLCV(client: Client, message: any): void;
16
20
  watchTrades(symbol: string, since?: Int, limit?: Int, params?: {}): Promise<Trade[]>;
@@ -21,6 +21,7 @@ export default class kucoin extends kucoinRest {
21
21
  'cancelOrderWs': false,
22
22
  'cancelOrdersWs': false,
23
23
  'cancelAllOrdersWs': false,
24
+ 'watchBidsAsks': true,
24
25
  'watchOrderBook': true,
25
26
  'watchOrders': true,
26
27
  'watchMyTrades': true,
@@ -288,6 +289,92 @@ export default class kucoin extends kucoinRest {
288
289
  }
289
290
  }
290
291
  }
292
+ async watchBidsAsks(symbols = undefined, params = {}) {
293
+ /**
294
+ * @method
295
+ * @name kucoin#watchBidsAsks
296
+ * @see https://www.kucoin.com/docs/websocket/spot-trading/public-channels/level1-bbo-market-data
297
+ * @description watches best bid & ask for symbols
298
+ * @param {string[]} symbols unified symbol of the market to fetch the ticker for
299
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
300
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
301
+ */
302
+ const ticker = await this.watchMultiHelper('watchBidsAsks', '/spotMarket/level1:', symbols, params);
303
+ if (this.newUpdates) {
304
+ const tickers = {};
305
+ tickers[ticker['symbol']] = ticker;
306
+ return tickers;
307
+ }
308
+ return this.filterByArray(this.bidsasks, 'symbol', symbols);
309
+ }
310
+ async watchMultiHelper(methodName, channelName, symbols = undefined, params = {}) {
311
+ await this.loadMarkets();
312
+ symbols = this.marketSymbols(symbols, undefined, false, true, false);
313
+ const length = symbols.length;
314
+ if (length > 100) {
315
+ throw new ArgumentsRequired(this.id + ' ' + methodName + '() accepts a maximum of 100 symbols');
316
+ }
317
+ const messageHashes = [];
318
+ for (let i = 0; i < symbols.length; i++) {
319
+ const symbol = symbols[i];
320
+ const market = this.market(symbol);
321
+ messageHashes.push('bidask@' + market['symbol']);
322
+ }
323
+ const url = await this.negotiate(false);
324
+ const marketIds = this.marketIds(symbols);
325
+ const joined = marketIds.join(',');
326
+ const requestId = this.requestId().toString();
327
+ const request = {
328
+ 'id': requestId,
329
+ 'type': 'subscribe',
330
+ 'topic': channelName + joined,
331
+ 'response': true,
332
+ };
333
+ const message = this.extend(request, params);
334
+ return await this.watchMultiple(url, messageHashes, message, messageHashes);
335
+ }
336
+ handleBidAsk(client, message) {
337
+ //
338
+ // arrives one symbol dict
339
+ //
340
+ // {
341
+ // topic: '/spotMarket/level1:ETH-USDT',
342
+ // type: 'message',
343
+ // data: {
344
+ // asks: [ '3347.42', '2.0778387' ],
345
+ // bids: [ '3347.41', '6.0411697' ],
346
+ // timestamp: 1712231142085
347
+ // },
348
+ // subject: 'level1'
349
+ // }
350
+ //
351
+ const parsedTicker = this.parseWsBidAsk(message);
352
+ const symbol = parsedTicker['symbol'];
353
+ this.bidsasks[symbol] = parsedTicker;
354
+ const messageHash = 'bidask@' + symbol;
355
+ client.resolve(parsedTicker, messageHash);
356
+ }
357
+ parseWsBidAsk(ticker, market = undefined) {
358
+ const topic = this.safeString(ticker, 'topic');
359
+ const parts = topic.split(':');
360
+ const marketId = parts[1];
361
+ market = this.safeMarket(marketId, market);
362
+ const symbol = this.safeString(market, 'symbol');
363
+ const data = this.safeDict(ticker, 'data', {});
364
+ const ask = this.safeList(data, 'asks', []);
365
+ const bid = this.safeList(data, 'bids', []);
366
+ const timestamp = this.safeInteger(data, 'timestamp');
367
+ return this.safeTicker({
368
+ 'symbol': symbol,
369
+ 'timestamp': timestamp,
370
+ 'datetime': this.iso8601(timestamp),
371
+ 'ask': this.safeNumber(ask, 0),
372
+ 'askVolume': this.safeNumber(ask, 1),
373
+ 'bid': this.safeNumber(bid, 0),
374
+ 'bidVolume': this.safeNumber(bid, 1),
375
+ 'info': ticker,
376
+ }, market);
377
+ }
291
378
  async watchOHLCV(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
292
379
  /**
293
380
  * @method
@@ -679,6 +766,9 @@ export default class kucoin extends kucoinRest {
679
766
  // }
680
767
  //
681
768
  const id = this.safeString(message, 'id');
769
+ if (!(id in client.subscriptions)) {
770
+ return;
771
+ }
682
772
  const subscriptionHash = this.safeString(client.subscriptions, id);
683
773
  const subscription = this.safeValue(client.subscriptions, subscriptionHash);
684
774
  delete client.subscriptions[id];
@@ -1052,6 +1142,7 @@ export default class kucoin extends kucoinRest {
1052
1142
  }
1053
1143
  const subject = this.safeString(message, 'subject');
1054
1144
  const methods = {
1145
+ 'level1': this.handleBidAsk,
1055
1146
  'level2': this.handleOrderBook,
1056
1147
  'trade.l2update': this.handleOrderBook,
1057
1148
  'trade.ticker': this.handleTicker,