ccxt 4.1.45 → 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 (54) hide show
  1. package/README.md +3 -3
  2. package/dist/ccxt.browser.js +1591 -188
  3. package/dist/ccxt.browser.min.js +2 -2
  4. package/dist/cjs/ccxt.js +1 -1
  5. package/dist/cjs/src/base/Exchange.js +11 -3
  6. package/dist/cjs/src/base/ws/Cache.js +50 -0
  7. package/dist/cjs/src/bitvavo.js +6 -5
  8. package/dist/cjs/src/bybit.js +84 -132
  9. package/dist/cjs/src/cryptocom.js +1 -1
  10. package/dist/cjs/src/gate.js +3 -1
  11. package/dist/cjs/src/huobi.js +1 -2
  12. package/dist/cjs/src/okx.js +19 -2
  13. package/dist/cjs/src/pro/binance.js +203 -1
  14. package/dist/cjs/src/pro/bitget.js +181 -0
  15. package/dist/cjs/src/pro/bybit.js +154 -10
  16. package/dist/cjs/src/pro/cryptocom.js +131 -1
  17. package/dist/cjs/src/pro/gate.js +161 -0
  18. package/dist/cjs/src/pro/huobi.js +128 -4
  19. package/dist/cjs/src/pro/krakenfutures.js +129 -0
  20. package/dist/cjs/src/pro/kucoinfutures.js +182 -0
  21. package/dist/cjs/src/pro/okx.js +121 -0
  22. package/js/ccxt.d.ts +1 -1
  23. package/js/ccxt.js +1 -1
  24. package/js/src/base/Exchange.d.ts +4 -1
  25. package/js/src/base/Exchange.js +11 -3
  26. package/js/src/base/ws/Cache.d.ts +5 -1
  27. package/js/src/base/ws/Cache.js +50 -1
  28. package/js/src/bitvavo.js +6 -5
  29. package/js/src/bybit.d.ts +0 -2
  30. package/js/src/bybit.js +84 -132
  31. package/js/src/cryptocom.js +1 -1
  32. package/js/src/gate.js +3 -1
  33. package/js/src/huobi.js +1 -2
  34. package/js/src/okx.js +19 -2
  35. package/js/src/pro/binance.d.ts +6 -0
  36. package/js/src/pro/binance.js +204 -2
  37. package/js/src/pro/bitget.d.ts +3 -0
  38. package/js/src/pro/bitget.js +182 -1
  39. package/js/src/pro/bybit.d.ts +5 -1
  40. package/js/src/pro/bybit.js +156 -12
  41. package/js/src/pro/cryptocom.d.ts +4 -0
  42. package/js/src/pro/cryptocom.js +132 -2
  43. package/js/src/pro/gate.d.ts +5 -0
  44. package/js/src/pro/gate.js +162 -1
  45. package/js/src/pro/huobi.d.ts +2 -0
  46. package/js/src/pro/huobi.js +129 -5
  47. package/js/src/pro/krakenfutures.d.ts +3 -0
  48. package/js/src/pro/krakenfutures.js +129 -0
  49. package/js/src/pro/kucoinfutures.d.ts +5 -0
  50. package/js/src/pro/kucoinfutures.js +182 -0
  51. package/js/src/pro/okx.d.ts +2 -0
  52. package/js/src/pro/okx.js +123 -2
  53. package/package.json +1 -1
  54. package/skip-tests.json +3 -1
@@ -6811,7 +6811,6 @@ class Exchange {
6811
6811
  this.orders = undefined;
6812
6812
  this.triggerOrders = undefined;
6813
6813
  this.transactions = {};
6814
- this.positions = {};
6815
6814
  this.requiresWeb3 = false;
6816
6815
  this.requiresEddsa = false;
6817
6816
  this.enableLastJsonResponse = true;
@@ -7005,7 +7004,7 @@ class Exchange {
7005
7004
  this.transactions = {};
7006
7005
  this.ohlcvs = {};
7007
7006
  this.myTrades = undefined;
7008
- this.positions = {};
7007
+ this.positions = undefined;
7009
7008
  // web3 and cryptography flags
7010
7009
  this.requiresWeb3 = false;
7011
7010
  this.requiresEddsa = false;
@@ -9498,7 +9497,7 @@ class Exchange {
9498
9497
  const symbol = this.safeString(position, 'symbol');
9499
9498
  let market = undefined;
9500
9499
  if (symbol !== undefined) {
9501
- market = this.market(symbol);
9500
+ market = this.safeValue(this.markets, symbol);
9502
9501
  }
9503
9502
  if (contractSize === undefined && market !== undefined) {
9504
9503
  contractSize = this.safeNumber(market, 'contractSize');
@@ -9719,6 +9718,15 @@ class Exchange {
9719
9718
  async fetchPosition(symbol, params = {}) {
9720
9719
  throw new _errors_js__WEBPACK_IMPORTED_MODULE_3__.NotSupported(this.id + ' fetchPosition() is not supported yet');
9721
9720
  }
9721
+ async watchPosition(symbol = undefined, params = {}) {
9722
+ throw new _errors_js__WEBPACK_IMPORTED_MODULE_3__.NotSupported(this.id + ' watchPosition() is not supported yet');
9723
+ }
9724
+ async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
9725
+ throw new _errors_js__WEBPACK_IMPORTED_MODULE_3__.NotSupported(this.id + ' watchPositions() is not supported yet');
9726
+ }
9727
+ async watchPositionForSymbols(symbols = undefined, since = undefined, limit = undefined, params = {}) {
9728
+ return this.watchPositions(symbols, since, limit, params);
9729
+ }
9722
9730
  async fetchPositionsBySymbol(symbol, params = {}) {
9723
9731
  /**
9724
9732
  * @method
@@ -13423,7 +13431,8 @@ const safeStringUpperN = (o, k, $default) => {
13423
13431
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
13424
13432
  /* harmony export */ "Py": () => (/* binding */ ArrayCacheByTimestamp),
13425
13433
  /* harmony export */ "ZL": () => (/* binding */ ArrayCache),
13426
- /* harmony export */ "hl": () => (/* binding */ ArrayCacheBySymbolById)
13434
+ /* harmony export */ "hl": () => (/* binding */ ArrayCacheBySymbolById),
13435
+ /* harmony export */ "tU": () => (/* binding */ ArrayCacheBySymbolBySide)
13427
13436
  /* harmony export */ });
13428
13437
  /* eslint-disable max-classes-per-file */
13429
13438
  // @ts-nocheck
@@ -13621,6 +13630,55 @@ class ArrayCacheBySymbolById extends ArrayCache {
13621
13630
  this.allNewUpdates = (this.allNewUpdates || 0) + (afterLength - beforeLength);
13622
13631
  }
13623
13632
  }
13633
+ class ArrayCacheBySymbolBySide extends ArrayCache {
13634
+ constructor() {
13635
+ super();
13636
+ this.nestedNewUpdatesBySymbol = true;
13637
+ Object.defineProperty(this, 'hashmap', {
13638
+ __proto__: null,
13639
+ value: {},
13640
+ writable: true,
13641
+ });
13642
+ }
13643
+ append(item) {
13644
+ const bySide = this.hashmap[item.symbol] = this.hashmap[item.symbol] || {};
13645
+ if (item.side in bySide) {
13646
+ const reference = bySide[item.side];
13647
+ if (reference !== item) {
13648
+ for (const prop in item) {
13649
+ reference[prop] = item[prop];
13650
+ }
13651
+ }
13652
+ item = reference;
13653
+ const index = this.findIndex((x) => x.symbol === item.symbol && x.side === item.side);
13654
+ // move the order to the end of the array
13655
+ this.splice(index, 1);
13656
+ }
13657
+ else {
13658
+ bySide[item.side] = item;
13659
+ }
13660
+ this.push(item);
13661
+ if (this.clearAllUpdates) {
13662
+ this.clearAllUpdates = false;
13663
+ this.clearUpdatesBySymbol = {};
13664
+ this.allNewUpdates = 0;
13665
+ this.newUpdatesBySymbol = {};
13666
+ }
13667
+ if (this.newUpdatesBySymbol[item.symbol] === undefined) {
13668
+ this.newUpdatesBySymbol[item.symbol] = new Set();
13669
+ }
13670
+ if (this.clearUpdatesBySymbol[item.symbol]) {
13671
+ this.clearUpdatesBySymbol[item.symbol] = false;
13672
+ this.newUpdatesBySymbol[item.symbol].clear();
13673
+ }
13674
+ // in case an exchange updates the same order id twice
13675
+ const sideSet = this.newUpdatesBySymbol[item.symbol];
13676
+ const beforeLength = sideSet.size;
13677
+ sideSet.add(item.side);
13678
+ const afterLength = sideSet.size;
13679
+ this.allNewUpdates = (this.allNewUpdates || 0) + (afterLength - beforeLength);
13680
+ }
13681
+ }
13624
13682
 
13625
13683
 
13626
13684
 
@@ -66910,8 +66968,8 @@ class bitvavo extends _abstract_bitvavo_js__WEBPACK_IMPORTED_MODULE_0__/* ["defa
66910
66968
  * @returns {object[]} an array of objects representing market data
66911
66969
  */
66912
66970
  const response = await this.publicGetMarkets(params);
66913
- const currencies = this.currencies;
66914
- const currenciesById = this.indexBy(currencies, 'symbol');
66971
+ const currencies = await this.fetchCurrencies();
66972
+ const currenciesById = this.indexBy(currencies, 'id');
66915
66973
  //
66916
66974
  // [
66917
66975
  // {
@@ -66936,7 +66994,8 @@ class bitvavo extends _abstract_bitvavo_js__WEBPACK_IMPORTED_MODULE_0__/* ["defa
66936
66994
  const quote = this.safeCurrencyCode(quoteId);
66937
66995
  const status = this.safeString(market, 'status');
66938
66996
  const baseCurrency = this.safeValue(currenciesById, baseId);
66939
- result.push({
66997
+ const basePrecision = this.safeInteger(baseCurrency, 'precision');
66998
+ result.push(this.safeMarketStructure({
66940
66999
  'id': id,
66941
67000
  'symbol': base + '/' + quote,
66942
67001
  'base': base,
@@ -66961,7 +67020,7 @@ class bitvavo extends _abstract_bitvavo_js__WEBPACK_IMPORTED_MODULE_0__/* ["defa
66961
67020
  'strike': undefined,
66962
67021
  'optionType': undefined,
66963
67022
  'precision': {
66964
- 'amount': this.safeInteger(baseCurrency, 'decimals', 8),
67023
+ 'amount': this.safeInteger(baseCurrency, 'decimals', basePrecision),
66965
67024
  'price': this.safeInteger(market, 'pricePrecision'),
66966
67025
  },
66967
67026
  'limits': {
@@ -66984,7 +67043,7 @@ class bitvavo extends _abstract_bitvavo_js__WEBPACK_IMPORTED_MODULE_0__/* ["defa
66984
67043
  },
66985
67044
  'created': undefined,
66986
67045
  'info': market,
66987
- });
67046
+ }));
66988
67047
  }
66989
67048
  return result;
66990
67049
  }
@@ -76980,88 +77039,8 @@ class bybit extends _abstract_bybit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"
76980
77039
  return this.filterBySymbolSinceLimit(sorted, symbol, since, limit);
76981
77040
  }
76982
77041
  parseTrade(trade, market = undefined) {
76983
- const isSpotTrade = ('isBuyerMaker' in trade) || ('feeTokenId' in trade);
76984
- if (isSpotTrade) {
76985
- return this.parseSpotTrade(trade, market);
76986
- }
76987
- else {
76988
- return this.parseContractTrade(trade, market);
76989
- }
76990
- }
76991
- parseSpotTrade(trade, market = undefined) {
76992
77042
  //
76993
- // public:
76994
- // {
76995
- // "price": "39548.68",
76996
- // "time": "1651748717850",
76997
- // "qty": "0.166872",
76998
- // "isBuyerMaker": 0
76999
- // }
77000
- //
77001
- // private:
77002
- // {
77003
- // "orderPrice": "82.5",
77004
- // "creatTime": "1666702226326",
77005
- // "orderQty": "0.016",
77006
- // "isBuyer": "0",
77007
- // "isMaker": "0",
77008
- // "symbol": "AAVEUSDT",
77009
- // "id": "1274785101965716992",
77010
- // "orderId": "1274784252359089664",
77011
- // "tradeId": "2270000000031365639",
77012
- // "execFee": "0",
77013
- // "feeTokenId": "AAVE",
77014
- // "matchOrderId": "1274785101865076224",
77015
- // "makerRebate": "0",
77016
- // "executionTime": "1666702226335"
77017
- // }
77018
- //
77019
- const timestamp = this.safeIntegerN(trade, ['time', 'creatTime']);
77020
- let takerOrMaker = undefined;
77021
- let side = undefined;
77022
- const isBuyerMaker = this.safeInteger(trade, 'isBuyerMaker');
77023
- if (isBuyerMaker !== undefined) {
77024
- // if public response
77025
- side = (isBuyerMaker === 1) ? 'buy' : 'sell';
77026
- }
77027
- else {
77028
- // if private response
77029
- const isBuyer = this.safeInteger(trade, 'isBuyer');
77030
- const isMaker = this.safeInteger(trade, 'isMaker');
77031
- takerOrMaker = (isMaker === 0) ? 'maker' : 'taker';
77032
- side = (isBuyer === 0) ? 'buy' : 'sell';
77033
- }
77034
- const marketId = this.safeString(trade, 'symbol');
77035
- market = this.safeMarket(marketId, market, undefined, 'spot');
77036
- let fee = undefined;
77037
- const feeCost = this.safeString(trade, 'execFee');
77038
- if (feeCost !== undefined) {
77039
- const feeToken = this.safeString(trade, 'feeTokenId');
77040
- const feeCurrency = this.safeCurrencyCode(feeToken);
77041
- fee = {
77042
- 'cost': feeCost,
77043
- 'currency': feeCurrency,
77044
- };
77045
- }
77046
- return this.safeTrade({
77047
- 'id': this.safeString(trade, 'tradeId'),
77048
- 'info': trade,
77049
- 'timestamp': timestamp,
77050
- 'datetime': this.iso8601(timestamp),
77051
- 'symbol': market['symbol'],
77052
- 'order': this.safeString(trade, 'orderId'),
77053
- 'type': undefined,
77054
- 'side': side,
77055
- 'takerOrMaker': takerOrMaker,
77056
- 'price': this.safeString2(trade, 'price', 'orderPrice'),
77057
- 'amount': this.safeString2(trade, 'qty', 'orderQty'),
77058
- 'cost': undefined,
77059
- 'fee': fee,
77060
- }, market);
77061
- }
77062
- parseContractTrade(trade, market = undefined) {
77063
- //
77064
- // public contract
77043
+ // public https://bybit-exchange.github.io/docs/v5/market/recent-trade
77065
77044
  //
77066
77045
  // {
77067
77046
  // "execId": "666042b4-50c6-58f3-bd9c-89b2088663ff",
@@ -77073,59 +77052,66 @@ class bybit extends _abstract_bybit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"
77073
77052
  // "isBlockTrade": false
77074
77053
  // }
77075
77054
  //
77076
- // public unified margin
77077
- //
77078
- // {
77079
- // "execId": "da66abbc-f358-5864-8d34-84ef7274d853",
77080
- // "symbol": "BTCUSDT",
77081
- // "price": "20802.50",
77082
- // "size": "0.200",
77083
- // "side": "Sell",
77084
- // "time": "1657870316630"
77085
- // }
77086
- //
77087
- // private contract trades
77055
+ // private trades classic spot https://bybit-exchange.github.io/docs/v5/position/execution
77088
77056
  //
77089
77057
  // {
77090
- // "symbol": "ETHUSD",
77091
- // "execFee": "0.00005484",
77092
- // "execId": "acf78206-d464-589b-b888-51bd130821c1",
77093
- // "execPrice": "1367.80",
77094
- // "execQty": "100",
77095
- // "execType": "Trade",
77096
- // "execValue": "0.0731101",
77097
- // "feeRate": "0.00075",
77098
- // "lastLiquidityInd": "RemovedLiquidity",
77099
- // "leavesQty": "0",
77100
- // "orderId": "fdc584c3-be5d-41ff-8f54-5be7649b1d1c",
77058
+ // "symbol": "QNTUSDT",
77059
+ // "orderId": "1538686353240339712",
77101
77060
  // "orderLinkId": "",
77102
- // "orderPrice": "1299.50",
77103
- // "orderQty": "100",
77104
- // "orderType": "Market",
77105
- // "stopOrderType": "UNKNOWN",
77106
77061
  // "side": "Sell",
77107
- // "execTime": "1611528105547",
77108
- // "closedSize": "100"
77062
+ // "orderPrice": "",
77063
+ // "orderQty": "",
77064
+ // "leavesQty": "",
77065
+ // "orderType": "Limit",
77066
+ // "stopOrderType": "",
77067
+ // "execFee": "0.040919",
77068
+ // "execId": "2210000000097330907",
77069
+ // "execPrice": "98.6",
77070
+ // "execQty": "0.415",
77071
+ // "execType": "",
77072
+ // "execValue": "",
77073
+ // "execTime": "1698161716634",
77074
+ // "isMaker": true,
77075
+ // "feeRate": "",
77076
+ // "tradeIv": "",
77077
+ // "markIv": "",
77078
+ // "markPrice": "",
77079
+ // "indexPrice": "",
77080
+ // "underlyingPrice": "",
77081
+ // "blockTradeId": ""
77109
77082
  // }
77110
77083
  //
77111
- // private unified margin
77084
+ // private trades unified https://bybit-exchange.github.io/docs/v5/position/execution
77112
77085
  //
77113
77086
  // {
77114
- // "symbol": "AAVEUSDT",
77115
- // "id": "1274785101965716991",
77116
- // "orderId": "1274784252359089664",
77117
- // "tradeId": "2270000000031365639",
77118
- // "orderPrice": "82.5",
77119
- // "orderQty": "0.016",
77120
- // "execFee": "0",
77121
- // "feeTokenId": "AAVE",
77122
- // "creatTime": "1666702226326",
77123
- // "isBuyer": "0",
77124
- // "isMaker": "0",
77125
- // "matchOrderId": "1274785101865076224",
77126
- // "makerRebate": "0",
77127
- // "executionTime": "1666702226335"
77128
- // }
77087
+ // "symbol": "QNTUSDT",
77088
+ // "orderType": "Limit",
77089
+ // "underlyingPrice": "",
77090
+ // "orderLinkId": "1549452573428424449",
77091
+ // "orderId": "1549452573428424448",
77092
+ // "stopOrderType": "",
77093
+ // "execTime": "1699445151998",
77094
+ // "feeRate": "0.00025",
77095
+ // "tradeIv": "",
77096
+ // "blockTradeId": "",
77097
+ // "markPrice": "",
77098
+ // "execPrice": "102.8",
77099
+ // "markIv": "",
77100
+ // "orderQty": "3.652",
77101
+ // "orderPrice": "102.8",
77102
+ // "execValue": "1.028",
77103
+ // "closedSize": "",
77104
+ // "execType": "Trade",
77105
+ // "seq": "19157444346",
77106
+ // "side": "Buy",
77107
+ // "indexPrice": "",
77108
+ // "leavesQty": "3.642",
77109
+ // "isMaker": true,
77110
+ // "execFee": "0.0000025",
77111
+ // "execId": "2210000000101610464",
77112
+ // "execQty": "0.01",
77113
+ // "nextPageCursor": "267951%3A0%2C38567%3A0"
77114
+ // },
77129
77115
  //
77130
77116
  // private USDC settled trades
77131
77117
  //
@@ -77197,9 +77183,25 @@ class bybit extends _abstract_bybit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"
77197
77183
  const feeCostString = this.safeString(trade, 'execFee');
77198
77184
  let fee = undefined;
77199
77185
  if (feeCostString !== undefined) {
77186
+ const feeRateString = this.safeString(trade, 'feeRate');
77200
77187
  let feeCurrencyCode = undefined;
77201
77188
  if (market['spot']) {
77202
- feeCurrencyCode = this.safeString(trade, 'commissionAsset');
77189
+ if (_base_Precise_js__WEBPACK_IMPORTED_MODULE_3__/* .Precise.stringGt */ .O.stringGt(feeCostString, '0')) {
77190
+ if (side === 'buy') {
77191
+ feeCurrencyCode = market['base'];
77192
+ }
77193
+ else {
77194
+ feeCurrencyCode = market['quote'];
77195
+ }
77196
+ }
77197
+ else {
77198
+ if (side === 'buy') {
77199
+ feeCurrencyCode = market['quote'];
77200
+ }
77201
+ else {
77202
+ feeCurrencyCode = market['base'];
77203
+ }
77204
+ }
77203
77205
  }
77204
77206
  else {
77205
77207
  feeCurrencyCode = market['inverse'] ? market['base'] : market['settle'];
@@ -77207,6 +77209,7 @@ class bybit extends _abstract_bybit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"
77207
77209
  fee = {
77208
77210
  'cost': feeCostString,
77209
77211
  'currency': feeCurrencyCode,
77212
+ 'rate': feeRateString,
77210
77213
  };
77211
77214
  }
77212
77215
  return this.safeTrade({
@@ -80212,11 +80215,19 @@ class bybit extends _abstract_bybit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"
80212
80215
  }
80213
80216
  if (type === 'linear' || type === 'inverse') {
80214
80217
  const baseCoin = this.safeString(params, 'baseCoin');
80215
- if (symbol === undefined && baseCoin === undefined) {
80216
- const defaultSettle = this.safeString(this.options, 'defaultSettle', 'USDT');
80217
- const settleCoin = this.safeString(params, 'settleCoin', defaultSettle);
80218
- request['settleCoin'] = settleCoin;
80219
- isUsdcSettled = (settleCoin === 'USDC');
80218
+ if (type === 'linear') {
80219
+ if (symbol === undefined && baseCoin === undefined) {
80220
+ const defaultSettle = this.safeString(this.options, 'defaultSettle', 'USDT');
80221
+ const settleCoin = this.safeString(params, 'settleCoin', defaultSettle);
80222
+ request['settleCoin'] = settleCoin;
80223
+ isUsdcSettled = (settleCoin === 'USDC');
80224
+ }
80225
+ }
80226
+ else {
80227
+ // inverse
80228
+ if (symbol === undefined && baseCoin === undefined) {
80229
+ request['category'] = 'inverse';
80230
+ }
80220
80231
  }
80221
80232
  }
80222
80233
  if (((type === 'option') || isUsdcSettled) && !isUnifiedAccount) {
@@ -105197,7 +105208,7 @@ class cryptocom extends _abstract_cryptocom_js__WEBPACK_IMPORTED_MODULE_0__/* ["
105197
105208
  'datetime': this.iso8601(timestamp),
105198
105209
  'hedged': undefined,
105199
105210
  'side': undefined,
105200
- 'contracts': undefined,
105211
+ 'contracts': this.safeNumber(position, 'quantity'),
105201
105212
  'contractSize': market['contractSize'],
105202
105213
  'entryPrice': undefined,
105203
105214
  'markPrice': undefined,
@@ -125581,13 +125592,14 @@ class gate extends _abstract_gate_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"]
125581
125592
  const takerFee = '0.00075';
125582
125593
  const feePaid = _base_Precise_js__WEBPACK_IMPORTED_MODULE_3__/* .Precise.stringMul */ .O.stringMul(takerFee, notional);
125583
125594
  const initialMarginString = _base_Precise_js__WEBPACK_IMPORTED_MODULE_3__/* .Precise.stringAdd */ .O.stringAdd(_base_Precise_js__WEBPACK_IMPORTED_MODULE_3__/* .Precise.stringDiv */ .O.stringDiv(notional, leverage), feePaid);
125595
+ const timestamp = this.safeInteger(position, 'time_ms');
125584
125596
  return this.safePosition({
125585
125597
  'info': position,
125586
125598
  'id': undefined,
125587
125599
  'symbol': this.safeString(market, 'symbol'),
125588
125600
  'timestamp': undefined,
125589
125601
  'datetime': undefined,
125590
- 'lastUpdateTimestamp': undefined,
125602
+ 'lastUpdateTimestamp': timestamp,
125591
125603
  'initialMargin': this.parseNumber(initialMarginString),
125592
125604
  'initialMarginPercentage': this.parseNumber(_base_Precise_js__WEBPACK_IMPORTED_MODULE_3__/* .Precise.stringDiv */ .O.stringDiv(initialMarginString, notional)),
125593
125605
  'maintenanceMargin': this.parseNumber(_base_Precise_js__WEBPACK_IMPORTED_MODULE_3__/* .Precise.stringMul */ .O.stringMul(maintenanceRate, notional)),
@@ -125596,6 +125608,7 @@ class gate extends _abstract_gate_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"]
125596
125608
  'notional': this.parseNumber(notional),
125597
125609
  'leverage': this.safeNumber(position, 'leverage'),
125598
125610
  'unrealizedPnl': this.parseNumber(unrealisedPnl),
125611
+ 'realizedPnl': this.safeNumber(position, 'realised_pnl'),
125599
125612
  'contracts': this.parseNumber(_base_Precise_js__WEBPACK_IMPORTED_MODULE_3__/* .Precise.stringAbs */ .O.stringAbs(size)),
125600
125613
  'contractSize': this.safeValue(market, 'contractSize'),
125601
125614
  // 'realisedPnl': position['realised_pnl'],
@@ -141304,8 +141317,7 @@ class huobi extends _abstract_huobi_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"
141304
141317
  market = this.market(first);
141305
141318
  }
141306
141319
  let marginMode = undefined;
141307
- [marginMode, params] = this.handleMarginModeAndParams('fetchPositions', params);
141308
- marginMode = (marginMode === undefined) ? 'cross' : marginMode;
141320
+ [marginMode, params] = this.handleMarginModeAndParams('fetchPositions', params, 'cross');
141309
141321
  let subType = undefined;
141310
141322
  [subType, params] = this.handleSubTypeAndParams('fetchPositions', market, params, 'linear');
141311
141323
  let marketType = undefined;
@@ -186838,6 +186850,13 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
186838
186850
  request['tdMode'] = tradeMode;
186839
186851
  }
186840
186852
  else if (contract) {
186853
+ if (market['swap'] || market['future']) {
186854
+ let positionSide = undefined;
186855
+ [positionSide, params] = this.handleOptionAndParams(params, 'createOrder', 'positionSide');
186856
+ if (positionSide !== undefined) {
186857
+ request['posSide'] = positionSide;
186858
+ }
186859
+ }
186841
186860
  request['tdMode'] = marginMode;
186842
186861
  }
186843
186862
  const isMarketOrder = type === 'market';
@@ -187034,7 +187053,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
187034
187053
  * @param {float} amount how much of currency you want to trade in units of base currency
187035
187054
  * @param {float} [price] the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
187036
187055
  * @param {object} [params] extra parameters specific to the okx api endpoint
187037
- * @param {bool} [params.reduceOnly] MARGIN orders only, or swap/future orders in net mode
187056
+ * @param {bool} [params.reduceOnly] a mark to reduce the position size for margin, swap and future orders
187038
187057
  * @param {bool} [params.postOnly] true to place a post only order
187039
187058
  * @param {object} [params.takeProfit] *takeProfit object in params* containing the triggerPrice at which the attached take profit order will be triggered (perpetual swap markets only)
187040
187059
  * @param {float} [params.takeProfit.triggerPrice] take profit trigger price
@@ -187044,6 +187063,7 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
187044
187063
  * @param {float} [params.stopLoss.triggerPrice] stop loss trigger price
187045
187064
  * @param {float} [params.stopLoss.price] used for stop loss limit orders, not used for stop loss market price orders
187046
187065
  * @param {string} [params.stopLoss.type] 'market' or 'limit' used to specify the stop loss price type
187066
+ * @param {string} [params.positionSide] if position mode is one-way: set to 'net', if position mode is hedge-mode: set to 'long' or 'short'
187047
187067
  * @returns {object} an [order structure]{@link https://github.com/ccxt/ccxt/wiki/Manual#order-structure}
187048
187068
  */
187049
187069
  await this.loadMarkets();
@@ -187063,7 +187083,16 @@ class okx extends _abstract_okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
187063
187083
  // because it has a lower ratelimit
187064
187084
  request = [request];
187065
187085
  }
187066
- const response = await this[method](request);
187086
+ let response = undefined;
187087
+ if (method === 'privatePostTradeOrder') {
187088
+ response = await this.privatePostTradeOrder(request);
187089
+ }
187090
+ else if (method === 'privatePostTradeOrderAlgo') {
187091
+ response = await this.privatePostTradeOrderAlgo(request);
187092
+ }
187093
+ else {
187094
+ response = await this.privatePostTradeBatchOrders(request);
187095
+ }
187067
187096
  const data = this.safeValue(response, 'data', []);
187068
187097
  const first = this.safeValue(data, 0);
187069
187098
  const order = this.parseOrder(first, market);
@@ -202196,6 +202225,7 @@ class binance extends _binance_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
202196
202225
  'watchOrderBook': true,
202197
202226
  'watchOrderBookForSymbols': true,
202198
202227
  'watchOrders': true,
202228
+ 'watchPositions': true,
202199
202229
  'watchTicker': true,
202200
202230
  'watchTickers': true,
202201
202231
  'watchTrades': true,
@@ -202270,6 +202300,10 @@ class binance extends _binance_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
202270
202300
  'fetchBalanceSnapshot': false,
202271
202301
  'awaitBalanceSnapshot': true, // whether to wait for the balance snapshot before providing updates
202272
202302
  },
202303
+ 'watchPositions': {
202304
+ 'fetchPositionsSnapshot': true,
202305
+ 'awaitPositionsSnapshot': true, // whether to wait for the positions snapshot before providing updates
202306
+ },
202273
202307
  'wallet': 'wb',
202274
202308
  'listenKeyRefreshRate': 1200000,
202275
202309
  'ws': {
@@ -203652,6 +203686,7 @@ class binance extends _binance_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
203652
203686
  const url = this.urls['api']['ws'][type] + '/' + this.options[type]['listenKey'];
203653
203687
  const client = this.client(url);
203654
203688
  this.setBalanceCache(client, type);
203689
+ this.setPositionsCache(client, type);
203655
203690
  const options = this.safeValue(this.options, 'watchBalance');
203656
203691
  const fetchBalanceSnapshot = this.safeValue(options, 'fetchBalanceSnapshot', false);
203657
203692
  const awaitBalanceSnapshot = this.safeValue(options, 'awaitBalanceSnapshot', true);
@@ -203726,6 +203761,9 @@ class binance extends _binance_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
203726
203761
  const subscriptions = Object.keys(client.subscriptions);
203727
203762
  const accountType = subscriptions[0];
203728
203763
  const messageHash = accountType + ':balance';
203764
+ if (this.balance[accountType] === undefined) {
203765
+ this.balance[accountType] = {};
203766
+ }
203729
203767
  this.balance[accountType]['info'] = message;
203730
203768
  const event = this.safeString(message, 'e');
203731
203769
  if (event === 'balanceUpdate') {
@@ -204257,6 +204295,7 @@ class binance extends _binance_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
204257
204295
  const url = this.urls['api']['ws'][urlType] + '/' + this.options[type]['listenKey'];
204258
204296
  const client = this.client(url);
204259
204297
  this.setBalanceCache(client, type);
204298
+ this.setPositionsCache(client, type);
204260
204299
  const message = undefined;
204261
204300
  const orders = await this.watch(url, messageHash, message, type);
204262
204301
  if (this.newUpdates) {
@@ -204504,6 +204543,193 @@ class binance extends _binance_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
204504
204543
  this.handleMyTrade(client, message);
204505
204544
  this.handleOrder(client, message);
204506
204545
  }
204546
+ async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
204547
+ /**
204548
+ * @method
204549
+ * @name binance#watchPositions
204550
+ * @description watch all open positions
204551
+ * @param {[string]|undefined} symbols list of unified market symbols
204552
+ * @param {object} params extra parameters specific to the binance api endpoint
204553
+ * @returns {[object]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
204554
+ */
204555
+ await this.loadMarkets();
204556
+ await this.authenticate(params);
204557
+ let market = undefined;
204558
+ let messageHash = '';
204559
+ symbols = this.marketSymbols(symbols);
204560
+ if (!this.isEmpty(symbols)) {
204561
+ market = this.getMarketFromSymbols(symbols);
204562
+ messageHash = '::' + symbols.join(',');
204563
+ }
204564
+ const defaultType = this.safeString2(this.options, 'watchPositions', 'defaultType', 'future');
204565
+ let type = this.safeString(params, 'type', defaultType);
204566
+ let subType = undefined;
204567
+ [subType, params] = this.handleSubTypeAndParams('watchPositions', market, params);
204568
+ if (this.isLinear(type, subType)) {
204569
+ type = 'future';
204570
+ }
204571
+ else if (this.isInverse(type, subType)) {
204572
+ type = 'delivery';
204573
+ }
204574
+ messageHash = type + ':positions' + messageHash;
204575
+ const url = this.urls['api']['ws'][type] + '/' + this.options[type]['listenKey'];
204576
+ const client = this.client(url);
204577
+ this.setBalanceCache(client, type);
204578
+ this.setPositionsCache(client, type, symbols);
204579
+ const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
204580
+ const awaitPositionsSnapshot = this.safeValue('watchPositions', 'awaitPositionsSnapshot', true);
204581
+ const cache = this.safeValue(this.positions, type);
204582
+ if (fetchPositionsSnapshot && awaitPositionsSnapshot && cache === undefined) {
204583
+ const snapshot = await client.future(type + ':fetchPositionsSnapshot');
204584
+ return this.filterBySymbolsSinceLimit(snapshot, symbols, since, limit, true);
204585
+ }
204586
+ const newPositions = await this.watch(url, messageHash, undefined, type);
204587
+ if (this.newUpdates) {
204588
+ return newPositions;
204589
+ }
204590
+ return this.filterBySymbolsSinceLimit(cache, symbols, since, limit, true);
204591
+ }
204592
+ setPositionsCache(client, type, symbols = undefined) {
204593
+ if (this.positions === undefined) {
204594
+ this.positions = {};
204595
+ }
204596
+ if (type in this.positions) {
204597
+ return;
204598
+ }
204599
+ const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', false);
204600
+ if (fetchPositionsSnapshot) {
204601
+ const messageHash = type + ':fetchPositionsSnapshot';
204602
+ if (!(messageHash in client.futures)) {
204603
+ client.future(messageHash);
204604
+ this.spawn(this.loadPositionsSnapshot, client, messageHash, type);
204605
+ }
204606
+ }
204607
+ else {
204608
+ this.positions[type] = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_3__/* .ArrayCacheBySymbolBySide */ .tU();
204609
+ }
204610
+ }
204611
+ async loadPositionsSnapshot(client, messageHash, type) {
204612
+ const positions = await this.fetchPositions(undefined, { 'type': type });
204613
+ this.positions[type] = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_3__/* .ArrayCacheBySymbolBySide */ .tU();
204614
+ const cache = this.positions[type];
204615
+ for (let i = 0; i < positions.length; i++) {
204616
+ const position = positions[i];
204617
+ const contracts = this.safeNumber(position, 'contracts', 0);
204618
+ if (contracts > 0) {
204619
+ cache.append(position);
204620
+ }
204621
+ }
204622
+ // don't remove the future from the .futures cache
204623
+ const future = client.futures[messageHash];
204624
+ future.resolve(cache);
204625
+ client.resolve(cache, type + ':position');
204626
+ }
204627
+ handlePositions(client, message) {
204628
+ //
204629
+ // {
204630
+ // e: 'ACCOUNT_UPDATE',
204631
+ // T: 1667881353112,
204632
+ // E: 1667881353115,
204633
+ // a: {
204634
+ // B: [{
204635
+ // a: 'USDT',
204636
+ // wb: '1127.95750089',
204637
+ // cw: '1040.82091149',
204638
+ // bc: '0'
204639
+ // }],
204640
+ // P: [{
204641
+ // s: 'BTCUSDT',
204642
+ // pa: '-0.089',
204643
+ // ep: '19700.03933',
204644
+ // cr: '-1260.24809979',
204645
+ // up: '1.53058860',
204646
+ // mt: 'isolated',
204647
+ // iw: '87.13658940',
204648
+ // ps: 'BOTH',
204649
+ // ma: 'USDT'
204650
+ // }],
204651
+ // m: 'ORDER'
204652
+ // }
204653
+ // }
204654
+ //
204655
+ // each account is connected to a different endpoint
204656
+ // and has exactly one subscriptionhash which is the account type
204657
+ const subscriptions = Object.keys(client.subscriptions);
204658
+ const accountType = subscriptions[0];
204659
+ if (this.positions === undefined) {
204660
+ this.positions = {};
204661
+ }
204662
+ if (!(accountType in this.positions)) {
204663
+ this.positions[accountType] = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_3__/* .ArrayCacheBySymbolBySide */ .tU();
204664
+ }
204665
+ const cache = this.positions[accountType];
204666
+ const data = this.safeValue(message, 'a', {});
204667
+ const rawPositions = this.safeValue(data, 'P', []);
204668
+ const newPositions = [];
204669
+ for (let i = 0; i < rawPositions.length; i++) {
204670
+ const rawPosition = rawPositions[i];
204671
+ const position = this.parseWsPosition(rawPosition);
204672
+ const timestamp = this.safeInteger(message, 'E');
204673
+ position['timestamp'] = timestamp;
204674
+ position['datetime'] = this.iso8601(timestamp);
204675
+ newPositions.push(position);
204676
+ cache.append(position);
204677
+ }
204678
+ const messageHashes = this.findMessageHashes(client, accountType + ':positions::');
204679
+ for (let i = 0; i < messageHashes.length; i++) {
204680
+ const messageHash = messageHashes[i];
204681
+ const parts = messageHash.split('::');
204682
+ const symbolsString = parts[1];
204683
+ const symbols = symbolsString.split(',');
204684
+ const positions = this.filterByArray(newPositions, 'symbol', symbols, false);
204685
+ if (!this.isEmpty(positions)) {
204686
+ client.resolve(positions, messageHash);
204687
+ }
204688
+ }
204689
+ client.resolve(newPositions, accountType + ':positions');
204690
+ }
204691
+ parseWsPosition(position, market = undefined) {
204692
+ //
204693
+ // {
204694
+ // "s": "BTCUSDT", // Symbol
204695
+ // "pa": "0", // Position Amount
204696
+ // "ep": "0.00000", // Entry Price
204697
+ // "cr": "200", // (Pre-fee) Accumulated Realized
204698
+ // "up": "0", // Unrealized PnL
204699
+ // "mt": "isolated", // Margin Type
204700
+ // "iw": "0.00000000", // Isolated Wallet (if isolated position)
204701
+ // "ps": "BOTH" // Position Side
204702
+ // }
204703
+ //
204704
+ const marketId = this.safeString(position, 's');
204705
+ const positionSide = this.safeStringLower(position, 'ps');
204706
+ const hedged = positionSide !== 'both';
204707
+ return this.safePosition({
204708
+ 'info': position,
204709
+ 'id': undefined,
204710
+ 'symbol': this.safeSymbol(marketId),
204711
+ 'notional': undefined,
204712
+ 'marginMode': this.safeString(position, 'mt'),
204713
+ 'liquidationPrice': undefined,
204714
+ 'entryPrice': this.safeNumber(position, 'ep'),
204715
+ 'unrealizedPnl': this.safeNumber(position, 'up'),
204716
+ 'percentage': undefined,
204717
+ 'contracts': this.safeNumber(position, 'pa'),
204718
+ 'contractSize': undefined,
204719
+ 'markPrice': undefined,
204720
+ 'side': positionSide,
204721
+ 'hedged': hedged,
204722
+ 'timestamp': undefined,
204723
+ 'datetime': undefined,
204724
+ 'maintenanceMargin': undefined,
204725
+ 'maintenanceMarginPercentage': undefined,
204726
+ 'collateral': undefined,
204727
+ 'initialMargin': undefined,
204728
+ 'initialMarginPercentage': undefined,
204729
+ 'leverage': undefined,
204730
+ 'marginRatio': undefined,
204731
+ });
204732
+ }
204507
204733
  async fetchMyTradesWs(symbol = undefined, since = undefined, limit = undefined, params = {}) {
204508
204734
  /**
204509
204735
  * @method
@@ -204623,6 +204849,7 @@ class binance extends _binance_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
204623
204849
  const url = this.urls['api']['ws'][urlType] + '/' + this.options[type]['listenKey'];
204624
204850
  const client = this.client(url);
204625
204851
  this.setBalanceCache(client, type);
204852
+ this.setPositionsCache(client, type);
204626
204853
  const message = undefined;
204627
204854
  const trades = await this.watch(url, messageHash, message, type);
204628
204855
  if (this.newUpdates) {
@@ -204734,6 +204961,10 @@ class binance extends _binance_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
204734
204961
  client.resolve(this.orders, messageHashSymbol);
204735
204962
  }
204736
204963
  }
204964
+ handleAcountUpdate(client, message) {
204965
+ this.handleBalance(client, message);
204966
+ this.handlePositions(client, message);
204967
+ }
204737
204968
  handleWsError(client, message) {
204738
204969
  //
204739
204970
  // {
@@ -204802,7 +205033,7 @@ class binance extends _binance_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */
204802
205033
  'bookTicker': this.handleTicker,
204803
205034
  'outboundAccountPosition': this.handleBalance,
204804
205035
  'balanceUpdate': this.handleBalance,
204805
- 'ACCOUNT_UPDATE': this.handleBalance,
205036
+ 'ACCOUNT_UPDATE': this.handleAcountUpdate,
204806
205037
  'executionReport': this.handleOrderUpdate,
204807
205038
  'ORDER_TRADE_UPDATE': this.handleOrderUpdate,
204808
205039
  };
@@ -207791,6 +208022,7 @@ class bitget extends _bitget_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z
207791
208022
  'watchTickers': true,
207792
208023
  'watchTrades': true,
207793
208024
  'watchTradesForSymbols': true,
208025
+ 'watchPositions': true,
207794
208026
  },
207795
208027
  'urls': {
207796
208028
  'api': {
@@ -208512,6 +208744,185 @@ class bitget extends _bitget_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z
208512
208744
  'fee': undefined,
208513
208745
  }, market);
208514
208746
  }
208747
+ async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
208748
+ /**
208749
+ * @method
208750
+ * @name bitget#watchPositions
208751
+ * @description watch all open positions
208752
+ * @see https://bitgetlimited.github.io/apidoc/en/mix/#positions-channel
208753
+ * @param {[string]|undefined} symbols list of unified market symbols
208754
+ * @param {object} params extra parameters specific to the bitget api endpoint
208755
+ * @param {string} params.instType Instrument Type umcbl:USDT Perpetual Contract Private Channel; dmcbl:Coin Margin Perpetual Contract Private Channel; cmcbl: USDC margin Perpetual Contract Private Channel
208756
+ * @returns {[object]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
208757
+ */
208758
+ await this.loadMarkets();
208759
+ let market = undefined;
208760
+ let messageHash = '';
208761
+ const subscriptionHash = 'positions';
208762
+ let instType = 'umcbl';
208763
+ symbols = this.marketSymbols(symbols);
208764
+ if (!this.isEmpty(symbols)) {
208765
+ instType = 'dmcbl';
208766
+ market = this.getMarketFromSymbols(symbols);
208767
+ messageHash = '::' + symbols.join(',');
208768
+ if (market['settle'] === 'USDT') {
208769
+ instType = 'umcbl';
208770
+ }
208771
+ else if (market['settle'] === 'USDC') {
208772
+ instType = 'cmcbl';
208773
+ }
208774
+ }
208775
+ [instType, params] = this.handleOptionAndParams(params, 'watchPositions', 'instType', instType);
208776
+ messageHash = instType + ':positions' + messageHash;
208777
+ const args = {
208778
+ 'instType': instType,
208779
+ 'channel': 'positions',
208780
+ 'instId': 'default',
208781
+ };
208782
+ const newPositions = await this.watchPrivate(messageHash, subscriptionHash, args, params);
208783
+ if (this.newUpdates) {
208784
+ return newPositions;
208785
+ }
208786
+ return this.filterBySymbolsSinceLimit(newPositions, symbols, since, limit, true);
208787
+ }
208788
+ handlePositions(client, message) {
208789
+ //
208790
+ // {
208791
+ // action: 'snapshot',
208792
+ // arg: {
208793
+ // instType: 'umcbl',
208794
+ // channel: 'positions',
208795
+ // instId: 'default'
208796
+ // },
208797
+ // data: [{
208798
+ // posId: '926036334386778112',
208799
+ // instId: 'LTCUSDT_UMCBL',
208800
+ // instName: 'LTCUSDT',
208801
+ // marginCoin: 'USDT',
208802
+ // margin: '9.667',
208803
+ // marginMode: 'crossed',
208804
+ // holdSide: 'long',
208805
+ // holdMode: 'double_hold',
208806
+ // total: '0.3',
208807
+ // available: '0.3',
208808
+ // locked: '0',
208809
+ // averageOpenPrice: '64.44',
208810
+ // leverage: 2,
208811
+ // achievedProfits: '0',
208812
+ // upl: '0.0759',
208813
+ // uplRate: '0.0078',
208814
+ // liqPx: '-153.32',
208815
+ // keepMarginRate: '0.010',
208816
+ // marginRate: '0.005910309637',
208817
+ // cTime: '1656510187717',
208818
+ // uTime: '1694880005480',
208819
+ // markPrice: '64.7',
208820
+ // autoMargin: 'off'
208821
+ // },
208822
+ // ...
208823
+ // ]
208824
+ // }
208825
+ //
208826
+ const arg = this.safeValue(message, 'arg', {});
208827
+ const instType = this.safeString(arg, 'instType', '');
208828
+ if (this.positions === undefined) {
208829
+ this.positions = {};
208830
+ }
208831
+ if (!(instType in this.positions)) {
208832
+ this.positions[instType] = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_2__/* .ArrayCacheBySymbolBySide */ .tU();
208833
+ }
208834
+ const cache = this.positions[instType];
208835
+ const rawPositions = this.safeValue(message, 'data', []);
208836
+ const dataLength = rawPositions.length;
208837
+ if (dataLength === 0) {
208838
+ return;
208839
+ }
208840
+ const newPositions = [];
208841
+ for (let i = 0; i < rawPositions.length; i++) {
208842
+ const rawPosition = rawPositions[i];
208843
+ const position = this.parseWsPosition(rawPosition);
208844
+ newPositions.push(position);
208845
+ cache.append(position);
208846
+ }
208847
+ const messageHashes = this.findMessageHashes(client, instType + ':positions::');
208848
+ for (let i = 0; i < messageHashes.length; i++) {
208849
+ const messageHash = messageHashes[i];
208850
+ const parts = messageHash.split('::');
208851
+ const symbolsString = parts[1];
208852
+ const symbols = symbolsString.split(',');
208853
+ const positions = this.filterByArray(newPositions, 'symbol', symbols, false);
208854
+ if (!this.isEmpty(positions)) {
208855
+ client.resolve(positions, messageHash);
208856
+ }
208857
+ }
208858
+ client.resolve(newPositions, instType + ':positions');
208859
+ }
208860
+ parseWsPosition(position, market = undefined) {
208861
+ //
208862
+ // {
208863
+ // posId: '926036334386778112',
208864
+ // instId: 'LTCUSDT_UMCBL',
208865
+ // instName: 'LTCUSDT',
208866
+ // marginCoin: 'USDT',
208867
+ // margin: '9.667',
208868
+ // marginMode: 'crossed',
208869
+ // holdSide: 'long',
208870
+ // holdMode: 'double_hold',
208871
+ // total: '0.3',
208872
+ // available: '0.3',
208873
+ // locked: '0',
208874
+ // averageOpenPrice: '64.44',
208875
+ // leverage: 2,
208876
+ // achievedProfits: '0',
208877
+ // upl: '0.0759',
208878
+ // uplRate: '0.0078',
208879
+ // liqPx: '-153.32',
208880
+ // keepMarginRate: '0.010',
208881
+ // marginRate: '0.005910309637',
208882
+ // cTime: '1656510187717',
208883
+ // uTime: '1694880005480',
208884
+ // markPrice: '64.7',
208885
+ // autoMargin: 'off'
208886
+ // }
208887
+ //
208888
+ const marketId = this.safeString(position, 'instId');
208889
+ const marginModeId = this.safeString(position, 'marginMode');
208890
+ const marginMode = this.getSupportedMapping(marginModeId, {
208891
+ 'crossed': 'cross',
208892
+ 'fixed': 'isolated',
208893
+ });
208894
+ const hedgedId = this.safeString(position, 'holdMode');
208895
+ const hedged = this.getSupportedMapping(hedgedId, {
208896
+ 'double_hold': true,
208897
+ 'single_hold': false,
208898
+ });
208899
+ const timestamp = this.safeInteger2(position, 'uTime', 'cTime');
208900
+ return this.safePosition({
208901
+ 'info': position,
208902
+ 'id': this.safeString(position, 'posId'),
208903
+ 'symbol': this.safeSymbol(marketId, market),
208904
+ 'notional': undefined,
208905
+ 'marginMode': marginMode,
208906
+ 'liquidationPrice': undefined,
208907
+ 'entryPrice': this.safeNumber(position, 'averageOpenPrice'),
208908
+ 'unrealizedPnl': this.safeNumber(position, 'upl'),
208909
+ 'percentage': this.safeNumber(position, 'uplRate'),
208910
+ 'contracts': this.safeNumber(position, 'total'),
208911
+ 'contractSize': undefined,
208912
+ 'markPrice': this.safeNumber(position, 'markPrice'),
208913
+ 'side': this.safeString(position, 'holdSide'),
208914
+ 'hedged': hedged,
208915
+ 'timestamp': timestamp,
208916
+ 'datetime': this.iso8601(timestamp),
208917
+ 'maintenanceMargin': undefined,
208918
+ 'maintenanceMarginPercentage': this.safeNumber(position, 'keepMarginRate'),
208919
+ 'collateral': undefined,
208920
+ 'initialMargin': undefined,
208921
+ 'initialMarginPercentage': undefined,
208922
+ 'leverage': this.safeNumber(position, 'leverage'),
208923
+ 'marginRatio': this.safeNumber(position, 'marginRate'),
208924
+ });
208925
+ }
208515
208926
  async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
208516
208927
  /**
208517
208928
  * @method
@@ -209226,6 +209637,7 @@ class bitget extends _bitget_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z
209226
209637
  'orders': this.handleOrder,
209227
209638
  'ordersAlgo': this.handleOrder,
209228
209639
  'account': this.handleBalance,
209640
+ 'positions': this.handlePositions,
209229
209641
  };
209230
209642
  const arg = this.safeValue(message, 'arg', {});
209231
209643
  const topic = this.safeValue(arg, 'channel', '');
@@ -216530,8 +216942,8 @@ class bybit extends _bybit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
216530
216942
  'watchTicker': true,
216531
216943
  'watchTickers': true,
216532
216944
  'watchTrades': true,
216945
+ 'watchPositions': true,
216533
216946
  'watchTradesForSymbols': true,
216534
- 'watchPosition': undefined,
216535
216947
  },
216536
216948
  'urls': {
216537
216949
  'api': {
@@ -216575,6 +216987,10 @@ class bybit extends _bybit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
216575
216987
  'watchTicker': {
216576
216988
  'name': 'tickers', // 'tickers' for 24hr statistical ticker or 'tickers_lt' for leverage token ticker
216577
216989
  },
216990
+ 'watchPositions': {
216991
+ 'fetchPositionsSnapshot': true,
216992
+ 'awaitPositionsSnapshot': true, // whether to wait for the positions snapshot before providing updates
216993
+ },
216578
216994
  'spot': {
216579
216995
  'timeframes': {
216580
216996
  '1m': '1m',
@@ -216688,7 +217104,7 @@ class bybit extends _bybit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
216688
217104
  }
216689
217105
  topic += '.' + market['id'];
216690
217106
  const topics = [topic];
216691
- return await this.watchTopics(url, messageHash, topics, params);
217107
+ return await this.watchTopics(url, messageHash, topics, messageHash, params);
216692
217108
  }
216693
217109
  async watchTickers(symbols = undefined, params = {}) {
216694
217110
  /**
@@ -216885,7 +217301,7 @@ class bybit extends _bybit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
216885
217301
  const timeframeId = this.safeString(this.timeframes, timeframe, timeframe);
216886
217302
  const topics = ['kline.' + timeframeId + '.' + market['id']];
216887
217303
  const messageHash = 'kline' + ':' + timeframeId + ':' + symbol;
216888
- ohlcv = await this.watchTopics(url, messageHash, topics, params);
217304
+ ohlcv = await this.watchTopics(url, messageHash, topics, messageHash, params);
216889
217305
  if (this.newUpdates) {
216890
217306
  limit = ohlcv.getLimit(symbol, limit);
216891
217307
  }
@@ -217042,7 +217458,7 @@ class bybit extends _bybit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
217042
217458
  }
217043
217459
  }
217044
217460
  const topics = ['orderbook.' + limit.toString() + '.' + market['id']];
217045
- const orderbook = await this.watchTopics(url, messageHash, topics, params);
217461
+ const orderbook = await this.watchTopics(url, messageHash, topics, messageHash, params);
217046
217462
  return orderbook.limit();
217047
217463
  }
217048
217464
  async watchOrderBookForSymbols(symbols, limit = undefined, params = {}) {
@@ -217180,7 +217596,7 @@ class bybit extends _bybit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
217180
217596
  params = this.cleanParams(params);
217181
217597
  const messageHash = 'trade:' + symbol;
217182
217598
  const topic = 'publicTrade.' + market['id'];
217183
- const trades = await this.watchTopics(url, messageHash, [topic], params);
217599
+ const trades = await this.watchTopics(url, messageHash, [topic], messageHash, params);
217184
217600
  if (this.newUpdates) {
217185
217601
  limit = trades.getLimit(symbol, limit);
217186
217602
  }
@@ -217376,7 +217792,7 @@ class bybit extends _bybit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
217376
217792
  'usdc': 'user.openapi.perp.trade',
217377
217793
  };
217378
217794
  const topic = this.safeValue(topicByMarket, this.getPrivateType(url));
217379
- const trades = await this.watchTopics(url, messageHash, [topic], params);
217795
+ const trades = await this.watchTopics(url, messageHash, [topic], messageHash, params);
217380
217796
  if (this.newUpdates) {
217381
217797
  limit = trades.getLimit(symbol, limit);
217382
217798
  }
@@ -217474,6 +217890,145 @@ class bybit extends _bybit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
217474
217890
  const messageHash = 'myTrades';
217475
217891
  client.resolve(trades, messageHash);
217476
217892
  }
217893
+ async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
217894
+ /**
217895
+ * @method
217896
+ * @name bybit#watchPositions
217897
+ * @see https://bybit-exchange.github.io/docs/v5/websocket/private/position
217898
+ * @description watch all open positions
217899
+ * @param {[string]|undefined} symbols list of unified market symbols
217900
+ * @param {object} params extra parameters specific to the bybit api endpoint
217901
+ * @returns {[object]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
217902
+ */
217903
+ await this.loadMarkets();
217904
+ const method = 'watchPositions';
217905
+ let messageHash = '';
217906
+ if (!this.isEmpty(symbols)) {
217907
+ symbols = this.marketSymbols(symbols);
217908
+ messageHash = '::' + symbols.join(',');
217909
+ }
217910
+ const firstSymbol = this.safeString(symbols, 0);
217911
+ const url = this.getUrlByMarketType(firstSymbol, true, method, params);
217912
+ messageHash = 'positions' + messageHash;
217913
+ const client = this.client(url);
217914
+ await this.authenticate(url);
217915
+ this.setPositionsCache(client, symbols);
217916
+ const cache = this.positions;
217917
+ const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
217918
+ const awaitPositionsSnapshot = this.safeValue('watchPositions', 'awaitPositionsSnapshot', true);
217919
+ if (fetchPositionsSnapshot && awaitPositionsSnapshot && cache === undefined) {
217920
+ const snapshot = await client.future('fetchPositionsSnapshot');
217921
+ return this.filterBySymbolsSinceLimit(snapshot, symbols, since, limit, true);
217922
+ }
217923
+ const topics = ['position'];
217924
+ const newPositions = await this.watchTopics(url, messageHash, topics, 'position', params);
217925
+ if (this.newUpdates) {
217926
+ return newPositions;
217927
+ }
217928
+ return this.filterBySymbolsSinceLimit(cache, symbols, since, limit, true);
217929
+ }
217930
+ setPositionsCache(client, symbols = undefined) {
217931
+ if (this.positions !== undefined) {
217932
+ return this.positions;
217933
+ }
217934
+ const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
217935
+ if (fetchPositionsSnapshot) {
217936
+ const messageHash = 'fetchPositionsSnapshot';
217937
+ if (!(messageHash in client.futures)) {
217938
+ client.future(messageHash);
217939
+ this.spawn(this.loadPositionsSnapshot, client, messageHash);
217940
+ }
217941
+ }
217942
+ else {
217943
+ this.positions = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_2__/* .ArrayCacheBySymbolBySide */ .tU();
217944
+ }
217945
+ }
217946
+ async loadPositionsSnapshot(client, messageHash) {
217947
+ // as only one ws channel gives positions for all types, for snapshot must load all positions
217948
+ const fetchFunctions = [
217949
+ this.fetchPositions(undefined, { 'type': 'swap', 'subType': 'linear' }),
217950
+ this.fetchPositions(undefined, { 'type': 'swap', 'subType': 'inverse' }),
217951
+ ];
217952
+ const promises = await Promise.all(fetchFunctions);
217953
+ this.positions = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_2__/* .ArrayCacheBySymbolBySide */ .tU();
217954
+ const cache = this.positions;
217955
+ for (let i = 0; i < promises.length; i++) {
217956
+ const positions = promises[i];
217957
+ for (let ii = 0; ii < positions.length; ii++) {
217958
+ const position = positions[ii];
217959
+ cache.append(position);
217960
+ }
217961
+ }
217962
+ // don't remove the future from the .futures cache
217963
+ const future = client.futures[messageHash];
217964
+ future.resolve(cache);
217965
+ client.resolve(cache, 'position');
217966
+ }
217967
+ handlePositions(client, message) {
217968
+ //
217969
+ // {
217970
+ // topic: 'position',
217971
+ // id: '504b2671629b08e3c4f6960382a59363:3bc4028023786545:0:01',
217972
+ // creationTime: 1694566055295,
217973
+ // data: [{
217974
+ // bustPrice: '15.00',
217975
+ // category: 'inverse',
217976
+ // createdTime: '1670083436351',
217977
+ // cumRealisedPnl: '0.00011988',
217978
+ // entryPrice: '19358.58553268',
217979
+ // leverage: '10',
217980
+ // liqPrice: '15.00',
217981
+ // markPrice: '25924.00',
217982
+ // positionBalance: '0.0000156',
217983
+ // positionIdx: 0,
217984
+ // positionMM: '0.001',
217985
+ // positionIM: '0.0000015497',
217986
+ // positionStatus: 'Normal',
217987
+ // positionValue: '0.00015497',
217988
+ // riskId: 1,
217989
+ // riskLimitValue: '150',
217990
+ // side: 'Buy',
217991
+ // size: '3',
217992
+ // stopLoss: '0.00',
217993
+ // symbol: 'BTCUSD',
217994
+ // takeProfit: '0.00',
217995
+ // tpslMode: 'Full',
217996
+ // tradeMode: 0,
217997
+ // autoAddMargin: 1,
217998
+ // trailingStop: '0.00',
217999
+ // unrealisedPnl: '0.00003925',
218000
+ // updatedTime: '1694566055293',
218001
+ // adlRankIndicator: 3
218002
+ // }]
218003
+ // }
218004
+ //
218005
+ // each account is connected to a different endpoint
218006
+ // and has exactly one subscriptionhash which is the account type
218007
+ if (this.positions === undefined) {
218008
+ this.positions = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_2__/* .ArrayCacheBySymbolBySide */ .tU();
218009
+ }
218010
+ const cache = this.positions;
218011
+ const newPositions = [];
218012
+ const rawPositions = this.safeValue(message, 'data', []);
218013
+ for (let i = 0; i < rawPositions.length; i++) {
218014
+ const rawPosition = rawPositions[i];
218015
+ const position = this.parsePosition(rawPosition);
218016
+ newPositions.push(position);
218017
+ cache.append(position);
218018
+ }
218019
+ const messageHashes = this.findMessageHashes(client, 'positions::');
218020
+ for (let i = 0; i < messageHashes.length; i++) {
218021
+ const messageHash = messageHashes[i];
218022
+ const parts = messageHash.split('::');
218023
+ const symbolsString = parts[1];
218024
+ const symbols = symbolsString.split(',');
218025
+ const positions = this.filterByArray(newPositions, 'symbol', symbols, false);
218026
+ if (!this.isEmpty(positions)) {
218027
+ client.resolve(positions, messageHash);
218028
+ }
218029
+ }
218030
+ client.resolve(newPositions, 'positions');
218031
+ }
217477
218032
  async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
217478
218033
  /**
217479
218034
  * @method
@@ -217501,7 +218056,7 @@ class bybit extends _bybit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
217501
218056
  'usdc': ['user.openapi.perp.order'],
217502
218057
  };
217503
218058
  const topics = this.safeValue(topicsByMarket, this.getPrivateType(url));
217504
- const orders = await this.watchTopics(url, messageHash, topics, params);
218059
+ const orders = await this.watchTopics(url, messageHash, topics, messageHash, params);
217505
218060
  if (this.newUpdates) {
217506
218061
  limit = orders.getLimit(symbol, limit);
217507
218062
  }
@@ -217818,7 +218373,7 @@ class bybit extends _bybit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
217818
218373
  }
217819
218374
  }
217820
218375
  const topics = [this.safeValue(topicByMarket, this.getPrivateType(url))];
217821
- return await this.watchTopics(url, messageHash, topics, params);
218376
+ return await this.watchTopics(url, messageHash, topics, messageHash, params);
217822
218377
  }
217823
218378
  handleBalance(client, message) {
217824
218379
  //
@@ -218056,14 +218611,14 @@ class bybit extends _bybit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
218056
218611
  this.balance[code] = account;
218057
218612
  }
218058
218613
  }
218059
- async watchTopics(url, messageHash, topics = [], params = {}) {
218614
+ async watchTopics(url, messageHash, topics, subscriptionHash, params = {}) {
218060
218615
  const request = {
218061
218616
  'op': 'subscribe',
218062
218617
  'req_id': this.requestId(),
218063
218618
  'args': topics,
218064
218619
  };
218065
218620
  const message = this.extend(request, params);
218066
- return await this.watch(url, messageHash, message, messageHash);
218621
+ return await this.watch(url, messageHash, message, subscriptionHash);
218067
218622
  }
218068
218623
  async authenticate(url, params = {}) {
218069
218624
  this.checkRequiredCredentials();
@@ -218190,6 +218745,7 @@ class bybit extends _bybit_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
218190
218745
  'execution': this.handleMyTrades,
218191
218746
  'ticketInfo': this.handleMyTrades,
218192
218747
  'user.openapi.perp.trade': this.handleMyTrades,
218748
+ 'position': this.handlePositions,
218193
218749
  };
218194
218750
  const exacMethod = this.safeValue(methods, topic);
218195
218751
  if (exacMethod !== undefined) {
@@ -222208,6 +222764,7 @@ class cryptocom extends _cryptocom_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"]
222208
222764
  'watchOrderBookForSymbols': true,
222209
222765
  'watchOrders': true,
222210
222766
  'watchOHLCV': true,
222767
+ 'watchPositions': true,
222211
222768
  'createOrderWs': true,
222212
222769
  'cancelOrderWs': true,
222213
222770
  'cancelAllOrders': true,
@@ -222224,7 +222781,12 @@ class cryptocom extends _cryptocom_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"]
222224
222781
  'private': 'wss://uat-stream.3ona.co/exchange/v1/user',
222225
222782
  },
222226
222783
  },
222227
- 'options': {},
222784
+ 'options': {
222785
+ 'watchPositions': {
222786
+ 'fetchPositionsSnapshot': true,
222787
+ 'awaitPositionsSnapshot': true, // whether to wait for the positions snapshot before providing updates
222788
+ },
222789
+ },
222228
222790
  'streaming': {},
222229
222791
  });
222230
222792
  }
@@ -222633,6 +223195,129 @@ class cryptocom extends _cryptocom_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"]
222633
223195
  client.resolve(stored, 'user.order');
222634
223196
  }
222635
223197
  }
223198
+ async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
223199
+ /**
223200
+ * @method
223201
+ * @name cryptocom#watchPositions
223202
+ * @description watch all open positions
223203
+ * @see https://exchange-docs.crypto.com/exchange/v1/rest-ws/index.html#user-position_balance
223204
+ * @param {[string]|undefined} symbols list of unified market symbols
223205
+ * @param {object} params extra parameters specific to the cryptocom api endpoint
223206
+ * @returns {[object]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
223207
+ */
223208
+ await this.loadMarkets();
223209
+ await this.authenticate();
223210
+ const url = this.urls['api']['ws']['private'];
223211
+ const id = this.nonce();
223212
+ const request = {
223213
+ 'method': 'subscribe',
223214
+ 'params': {
223215
+ 'channels': ['user.position_balance'],
223216
+ },
223217
+ 'nonce': id,
223218
+ };
223219
+ let messageHash = 'positions';
223220
+ symbols = this.marketSymbols(symbols);
223221
+ if (!this.isEmpty(symbols)) {
223222
+ messageHash = '::' + symbols.join(',');
223223
+ }
223224
+ const client = this.client(url);
223225
+ this.setPositionsCache(client, symbols);
223226
+ const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
223227
+ const awaitPositionsSnapshot = this.safeValue('watchPositions', 'awaitPositionsSnapshot', true);
223228
+ if (fetchPositionsSnapshot && awaitPositionsSnapshot && this.positions === undefined) {
223229
+ const snapshot = await client.future('fetchPositionsSnapshot');
223230
+ return this.filterBySymbolsSinceLimit(snapshot, symbols, since, limit, true);
223231
+ }
223232
+ const newPositions = await this.watch(url, messageHash, this.extend(request, params));
223233
+ if (this.newUpdates) {
223234
+ return newPositions;
223235
+ }
223236
+ return this.filterBySymbolsSinceLimit(this.positions, symbols, since, limit, true);
223237
+ }
223238
+ setPositionsCache(client, type, symbols = undefined) {
223239
+ const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', false);
223240
+ if (fetchPositionsSnapshot) {
223241
+ const messageHash = 'fetchPositionsSnapshot';
223242
+ if (!(messageHash in client.futures)) {
223243
+ client.future(messageHash);
223244
+ this.spawn(this.loadPositionsSnapshot, client, messageHash);
223245
+ }
223246
+ }
223247
+ else {
223248
+ this.positions = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_2__/* .ArrayCacheBySymbolBySide */ .tU();
223249
+ }
223250
+ }
223251
+ async loadPositionsSnapshot(client, messageHash) {
223252
+ const positions = await this.fetchPositions();
223253
+ this.positions = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_2__/* .ArrayCacheBySymbolBySide */ .tU();
223254
+ const cache = this.positions;
223255
+ for (let i = 0; i < positions.length; i++) {
223256
+ const position = positions[i];
223257
+ const contracts = this.safeNumber(position, 'contracts', 0);
223258
+ if (contracts > 0) {
223259
+ cache.append(position);
223260
+ }
223261
+ }
223262
+ // don't remove the future from the .futures cache
223263
+ const future = client.futures[messageHash];
223264
+ future.resolve(cache);
223265
+ client.resolve(cache, 'positions');
223266
+ }
223267
+ handlePositions(client, message) {
223268
+ //
223269
+ // {
223270
+ // subscription: "user.position_balance",
223271
+ // channel: "user.position_balance",
223272
+ // data: [{
223273
+ // balances: [{
223274
+ // instrument_name: "USD",
223275
+ // quantity: "8.9979961950886",
223276
+ // update_timestamp_ms: 1695598760597,
223277
+ // }],
223278
+ // positions: [{
223279
+ // account_id: "96a0edb1-afb5-4c7c-af89-5cb610319e2c",
223280
+ // instrument_name: "LTCUSD-PERP",
223281
+ // type: "PERPETUAL_SWAP",
223282
+ // quantity: "1.8",
223283
+ // cost: "114.766",
223284
+ // open_position_pnl: "-0.0216206",
223285
+ // session_pnl: "0.00962994",
223286
+ // update_timestamp_ms: 1695598760597,
223287
+ // open_pos_cost: "114.766",
223288
+ // }],
223289
+ // }],
223290
+ // }
223291
+ //
223292
+ // each account is connected to a different endpoint
223293
+ // and has exactly one subscriptionhash which is the account type
223294
+ const data = this.safeValue(message, 'data', []);
223295
+ const firstData = this.safeValue(data, 0, {});
223296
+ const rawPositions = this.safeValue(firstData, 'positions', []);
223297
+ if (this.positions === undefined) {
223298
+ this.positions = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_2__/* .ArrayCacheBySymbolBySide */ .tU();
223299
+ }
223300
+ const cache = this.positions;
223301
+ const newPositions = [];
223302
+ for (let i = 0; i < rawPositions.length; i++) {
223303
+ const rawPosition = rawPositions[i];
223304
+ const position = this.parsePosition(rawPosition);
223305
+ newPositions.push(position);
223306
+ cache.append(position);
223307
+ }
223308
+ const messageHashes = this.findMessageHashes(client, 'positions::');
223309
+ for (let i = 0; i < messageHashes.length; i++) {
223310
+ const messageHash = messageHashes[i];
223311
+ const parts = messageHash.split('::');
223312
+ const symbolsString = parts[1];
223313
+ const symbols = symbolsString.split(',');
223314
+ const positions = this.filterByArray(newPositions, 'symbol', symbols, false);
223315
+ if (!this.isEmpty(positions)) {
223316
+ client.resolve(positions, messageHash);
223317
+ }
223318
+ }
223319
+ client.resolve(newPositions, 'positions');
223320
+ }
222636
223321
  async watchBalance(params = {}) {
222637
223322
  /**
222638
223323
  * @method
@@ -222899,6 +223584,7 @@ class cryptocom extends _cryptocom_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"]
222899
223584
  'user.order': this.handleOrders,
222900
223585
  'user.trade': this.handleTrades,
222901
223586
  'user.balance': this.handleBalance,
223587
+ 'user.position_balance': this.handlePositions,
222902
223588
  };
222903
223589
  const result = this.safeValue2(message, 'result', 'info');
222904
223590
  const channel = this.safeString(result, 'channel');
@@ -225111,6 +225797,7 @@ class gate extends _gate_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
225111
225797
  'watchOHLCV': true,
225112
225798
  'watchBalance': true,
225113
225799
  'watchOrders': true,
225800
+ 'watchPositions': true,
225114
225801
  },
225115
225802
  'urls': {
225116
225803
  'api': {
@@ -225162,6 +225849,10 @@ class gate extends _gate_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
225162
225849
  'settle': 'usdt',
225163
225850
  'spot': 'spot.balances', // spot.margin_balances, spot.funding_balances or spot.cross_balances
225164
225851
  },
225852
+ 'watchPositions': {
225853
+ 'fetchPositionsSnapshot': true,
225854
+ 'awaitPositionsSnapshot': true, // whether to wait for the positions snapshot before providing updates
225855
+ },
225165
225856
  },
225166
225857
  'exceptions': {
225167
225858
  'ws': {
@@ -225840,6 +226531,145 @@ class gate extends _gate_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
225840
226531
  this.balance = this.safeBalance(this.balance);
225841
226532
  client.resolve(this.balance, messageHash);
225842
226533
  }
226534
+ async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
226535
+ /**
226536
+ * @method
226537
+ * @name gate#watchPositions
226538
+ * @see https://www.gate.io/docs/developers/futures/ws/en/#positions-subscription
226539
+ * @see https://www.gate.io/docs/developers/delivery/ws/en/#positions-subscription
226540
+ * @see https://www.gate.io/docs/developers/options/ws/en/#positions-channel
226541
+ * @description watch all open positions
226542
+ * @param {[string]|undefined} symbols list of unified market symbols
226543
+ * @param {object} params extra parameters specific to the gate api endpoint
226544
+ * @returns {[object]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
226545
+ */
226546
+ await this.loadMarkets();
226547
+ let market = undefined;
226548
+ symbols = this.marketSymbols(symbols);
226549
+ const payload = ['!' + 'all'];
226550
+ if (!this.isEmpty(symbols)) {
226551
+ market = this.getMarketFromSymbols(symbols);
226552
+ }
226553
+ let type = undefined;
226554
+ let query = undefined;
226555
+ [type, query] = this.handleMarketTypeAndParams('watchPositions', market, params);
226556
+ if (type === 'spot') {
226557
+ type = 'swap';
226558
+ }
226559
+ const typeId = this.getSupportedMapping(type, {
226560
+ 'future': 'futures',
226561
+ 'swap': 'futures',
226562
+ 'option': 'options',
226563
+ });
226564
+ let messageHash = type + ':positions';
226565
+ if (!this.isEmpty(symbols)) {
226566
+ messageHash += '::' + symbols.join(',');
226567
+ }
226568
+ const channel = typeId + '.positions';
226569
+ let subType = undefined;
226570
+ [subType, query] = this.handleSubTypeAndParams('watchPositions', market, query);
226571
+ const isInverse = (subType === 'inverse');
226572
+ const url = this.getUrlByMarketType(type, isInverse);
226573
+ const client = this.client(url);
226574
+ this.setPositionsCache(client, type, symbols);
226575
+ const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', true);
226576
+ const awaitPositionsSnapshot = this.safeValue('watchPositions', 'awaitPositionsSnapshot', true);
226577
+ const cache = this.safeValue(this.positions, type);
226578
+ if (fetchPositionsSnapshot && awaitPositionsSnapshot && cache === undefined) {
226579
+ return await client.future(type + ':fetchPositionsSnapshot');
226580
+ }
226581
+ const positions = await this.subscribePrivate(url, messageHash, payload, channel, query, true);
226582
+ if (this.newUpdates) {
226583
+ return positions;
226584
+ }
226585
+ return this.filterBySymbolsSinceLimit(this.positions, symbols, since, limit, true);
226586
+ }
226587
+ setPositionsCache(client, type, symbols = undefined) {
226588
+ if (this.positions === undefined) {
226589
+ this.positions = {};
226590
+ }
226591
+ if (type in this.positions) {
226592
+ return;
226593
+ }
226594
+ const fetchPositionsSnapshot = this.handleOption('watchPositions', 'fetchPositionsSnapshot', false);
226595
+ if (fetchPositionsSnapshot) {
226596
+ const messageHash = type + ':fetchPositionsSnapshot';
226597
+ if (!(messageHash in client.futures)) {
226598
+ client.future(messageHash);
226599
+ this.spawn(this.loadPositionsSnapshot, client, messageHash, type);
226600
+ }
226601
+ }
226602
+ else {
226603
+ this.positions[type] = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_2__/* .ArrayCacheBySymbolBySide */ .tU();
226604
+ }
226605
+ }
226606
+ async loadPositionsSnapshot(client, messageHash, type) {
226607
+ const positions = await this.fetchPositions(undefined, { 'type': type });
226608
+ this.positions[type] = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_2__/* .ArrayCacheBySymbolBySide */ .tU();
226609
+ const cache = this.positions[type];
226610
+ for (let i = 0; i < positions.length; i++) {
226611
+ const position = positions[i];
226612
+ cache.append(position);
226613
+ }
226614
+ // don't remove the future from the .futures cache
226615
+ const future = client.futures[messageHash];
226616
+ future.resolve(cache);
226617
+ client.resolve(cache, type + ':position');
226618
+ }
226619
+ handlePositions(client, message) {
226620
+ //
226621
+ // {
226622
+ // time: 1693158497,
226623
+ // time_ms: 1693158497204,
226624
+ // channel: 'futures.positions',
226625
+ // event: 'update',
226626
+ // result: [{
226627
+ // contract: 'XRP_USDT',
226628
+ // cross_leverage_limit: 0,
226629
+ // entry_price: 0.5253,
226630
+ // history_pnl: 0,
226631
+ // history_point: 0,
226632
+ // last_close_pnl: 0,
226633
+ // leverage: 0,
226634
+ // leverage_max: 50,
226635
+ // liq_price: 0.0361,
226636
+ // maintenance_rate: 0.01,
226637
+ // margin: 4.89609962852,
226638
+ // mode: 'single',
226639
+ // realised_pnl: -0.0026265,
226640
+ // realised_point: 0,
226641
+ // risk_limit: 500000,
226642
+ // size: 1,
226643
+ // time: 1693158497,
226644
+ // time_ms: 1693158497195,
226645
+ // update_id: 1,
226646
+ // user: '10444586'
226647
+ // }]
226648
+ // }
226649
+ //
226650
+ const type = this.getMarketTypeByUrl(client.url);
226651
+ const data = this.safeValue(message, 'result', []);
226652
+ const cache = this.positions[type];
226653
+ const newPositions = [];
226654
+ for (let i = 0; i < data.length; i++) {
226655
+ const rawPosition = data[i];
226656
+ const position = this.parsePosition(rawPosition);
226657
+ newPositions.push(position);
226658
+ cache.append(position);
226659
+ }
226660
+ const messageHashes = this.findMessageHashes(client, type + ':positions::');
226661
+ for (let i = 0; i < messageHashes.length; i++) {
226662
+ const messageHash = messageHashes[i];
226663
+ const parts = messageHash.split('::');
226664
+ const symbolsString = parts[1];
226665
+ const symbols = symbolsString.split(',');
226666
+ const positions = this.filterByArray(newPositions, 'symbol', symbols, false);
226667
+ if (!this.isEmpty(positions)) {
226668
+ client.resolve(positions, messageHash);
226669
+ }
226670
+ }
226671
+ client.resolve(newPositions, type + ':positions');
226672
+ }
225843
226673
  async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
225844
226674
  /**
225845
226675
  * @method
@@ -226126,6 +226956,7 @@ class gate extends _gate_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
226126
226956
  'usertrades': this.handleMyTrades,
226127
226957
  'candlesticks': this.handleOHLCV,
226128
226958
  'orders': this.handleOrder,
226959
+ 'positions': this.handlePositions,
226129
226960
  'tickers': this.handleTicker,
226130
226961
  'book_ticker': this.handleTicker,
226131
226962
  'trades': this.handleTrades,
@@ -226167,6 +226998,22 @@ class gate extends _gate_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
226167
226998
  return url;
226168
226999
  }
226169
227000
  }
227001
+ getMarketTypeByUrl(url) {
227002
+ const findBy = {
227003
+ 'op-': 'option',
227004
+ 'delivery': 'future',
227005
+ 'fx': 'swap',
227006
+ };
227007
+ const keys = Object.keys(findBy);
227008
+ for (let i = 0; i < keys.length; i++) {
227009
+ const key = keys[i];
227010
+ const value = findBy[key];
227011
+ if (url.indexOf(key) >= 0) {
227012
+ return value;
227013
+ }
227014
+ }
227015
+ return 'spot';
227016
+ }
226170
227017
  requestId() {
226171
227018
  // their support said that reqid must be an int32, not documented
226172
227019
  const reqid = this.sum(this.safeInteger(this.options, 'reqid', 0), 1);
@@ -228647,14 +229494,14 @@ class huobi extends _huobi_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
228647
229494
  },
228648
229495
  },
228649
229496
  'swap': {
228650
- 'inverse': {
228651
- 'public': 'wss://api.hbdm.vn/swap-ws',
228652
- 'private': 'wss://api.hbdm.vn/swap-notification',
228653
- },
228654
229497
  'linear': {
228655
229498
  'public': 'wss://api.hbdm.vn/linear-swap-ws',
228656
229499
  'private': 'wss://api.hbdm.vn/linear-swap-notification',
228657
229500
  },
229501
+ 'inverse': {
229502
+ 'public': 'wss://api.hbdm.vn/swap-ws',
229503
+ 'private': 'wss://api.hbdm.vn/swap-notification',
229504
+ },
228658
229505
  },
228659
229506
  },
228660
229507
  },
@@ -229767,6 +230614,127 @@ class huobi extends _huobi_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
229767
230614
  'fee': undefined,
229768
230615
  }, market);
229769
230616
  }
230617
+ async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
230618
+ /**
230619
+ * @method
230620
+ * @name huobi#watchPositions
230621
+ * @see https://www.huobi.com/en-in/opend/newApiPages/?id=8cb7de1c-77b5-11ed-9966-0242ac110003
230622
+ * @see https://www.huobi.com/en-in/opend/newApiPages/?id=8cb7df0f-77b5-11ed-9966-0242ac110003
230623
+ * @see https://www.huobi.com/en-in/opend/newApiPages/?id=28c34a7d-77ae-11ed-9966-0242ac110003
230624
+ * @see https://www.huobi.com/en-in/opend/newApiPages/?id=5d5156b5-77b6-11ed-9966-0242ac110003
230625
+ * @description watch all open positions. Note: huobi has one channel for each marginMode and type
230626
+ * @param {[string]|undefined} symbols list of unified market symbols
230627
+ * @param {object} params extra parameters specific to the huobi api endpoint
230628
+ * @returns {[object]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
230629
+ */
230630
+ await this.loadMarkets();
230631
+ let market = undefined;
230632
+ let messageHash = '';
230633
+ if (!this.isEmpty(symbols)) {
230634
+ market = this.getMarketFromSymbols(symbols);
230635
+ messageHash = '::' + symbols.join(',');
230636
+ }
230637
+ let type = undefined;
230638
+ let subType = undefined;
230639
+ if (market !== undefined) {
230640
+ type = market['type'];
230641
+ subType = market['linear'] ? 'linear' : 'inverse';
230642
+ }
230643
+ else {
230644
+ [type, params] = this.handleMarketTypeAndParams('watchPositions', market, params);
230645
+ if (type === 'spot') {
230646
+ type = 'future';
230647
+ }
230648
+ [subType, params] = this.handleOptionAndParams(params, 'watchPositions', 'subType', subType);
230649
+ }
230650
+ symbols = this.marketSymbols(symbols);
230651
+ let marginMode = undefined;
230652
+ [marginMode, params] = this.handleMarginModeAndParams('watchPositions', params, 'cross');
230653
+ const isLinear = (subType === 'linear');
230654
+ const url = this.getUrlByMarketType(type, isLinear, true);
230655
+ messageHash = marginMode + ':positions' + messageHash;
230656
+ const channel = (marginMode === 'cross') ? 'positions_cross.*' : 'positions.*';
230657
+ const newPositions = await this.subscribePrivate(channel, messageHash, type, subType, params);
230658
+ if (this.newUpdates) {
230659
+ return newPositions;
230660
+ }
230661
+ return this.filterBySymbolsSinceLimit(this.positions[url][marginMode], symbols, since, limit, false);
230662
+ }
230663
+ handlePositions(client, message) {
230664
+ //
230665
+ // {
230666
+ // op: 'notify',
230667
+ // topic: 'positions_cross',
230668
+ // ts: 1696767149650,
230669
+ // event: 'snapshot',
230670
+ // data: [
230671
+ // {
230672
+ // contract_type: 'swap',
230673
+ // pair: 'BTC-USDT',
230674
+ // business_type: 'swap',
230675
+ // liquidation_price: null,
230676
+ // symbol: 'BTC',
230677
+ // contract_code: 'BTC-USDT',
230678
+ // volume: 1,
230679
+ // available: 1,
230680
+ // frozen: 0,
230681
+ // cost_open: 27802.2,
230682
+ // cost_hold: 27802.2,
230683
+ // profit_unreal: 0.0175,
230684
+ // profit_rate: 0.000629446590557581,
230685
+ // profit: 0.0175,
230686
+ // margin_asset: 'USDT',
230687
+ // position_margin: 27.8197,
230688
+ // lever_rate: 1,
230689
+ // direction: 'buy',
230690
+ // last_price: 27819.7,
230691
+ // margin_mode: 'cross',
230692
+ // margin_account: 'USDT',
230693
+ // trade_partition: 'USDT',
230694
+ // position_mode: 'dual_side'
230695
+ // },
230696
+ // ]
230697
+ // }
230698
+ //
230699
+ const url = client.url;
230700
+ const topic = this.safeString(message, 'topic', '');
230701
+ const marginMode = (topic === 'positions_cross') ? 'cross' : 'isolated';
230702
+ if (this.positions === undefined) {
230703
+ this.positions = {};
230704
+ }
230705
+ const clientPositions = this.safeValue(this.positions, url);
230706
+ if (clientPositions === undefined) {
230707
+ this.positions[url] = {};
230708
+ }
230709
+ const clientMarginModePositions = this.safeValue(clientPositions, marginMode);
230710
+ if (clientMarginModePositions === undefined) {
230711
+ this.positions[url][marginMode] = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_2__/* .ArrayCacheBySymbolBySide */ .tU();
230712
+ }
230713
+ const cache = this.positions[url][marginMode];
230714
+ const rawPositions = this.safeValue(message, 'data', []);
230715
+ const newPositions = [];
230716
+ const timestamp = this.safeInteger(message, 'ts');
230717
+ for (let i = 0; i < rawPositions.length; i++) {
230718
+ const rawPosition = rawPositions[i];
230719
+ const position = this.parsePosition(rawPosition);
230720
+ position['timestamp'] = timestamp;
230721
+ position['datetime'] = this.iso8601(timestamp);
230722
+ newPositions.push(position);
230723
+ cache.append(position);
230724
+ }
230725
+ const messageHashes = this.findMessageHashes(client, marginMode + ':positions::');
230726
+ for (let i = 0; i < messageHashes.length; i++) {
230727
+ const messageHash = messageHashes[i];
230728
+ const parts = messageHash.split('::');
230729
+ const symbolsString = parts[1];
230730
+ const symbols = symbolsString.split(',');
230731
+ const positions = this.filterByArray(newPositions, 'symbol', symbols, false);
230732
+ if (!this.isEmpty(positions)) {
230733
+ client.resolve(positions, messageHash);
230734
+ }
230735
+ }
230736
+ client.resolve(newPositions, marginMode + ':positions');
230737
+ }
229770
230738
  async watchBalance(params = {}) {
229771
230739
  /**
229772
230740
  * @method
@@ -230270,6 +231238,9 @@ class huobi extends _huobi_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
230270
231238
  if (topic.indexOf('account') >= 0) {
230271
231239
  this.handleBalance(client, message);
230272
231240
  }
231241
+ if (topic.indexOf('positions') >= 0) {
231242
+ this.handlePositions(client, message);
231243
+ }
230273
231244
  }
230274
231245
  }
230275
231246
  async pong(client, message) {
@@ -233840,9 +234811,9 @@ class kraken extends _kraken_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z
233840
234811
  /* harmony export */ "Z": () => (/* binding */ krakenfutures)
233841
234812
  /* harmony export */ });
233842
234813
  /* harmony import */ var _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(4470);
233843
- /* harmony import */ var _base_errors_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6689);
233844
- /* harmony import */ var _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3020);
233845
- /* harmony import */ var _base_Precise_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(2194);
234814
+ /* harmony import */ var _base_errors_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(6689);
234815
+ /* harmony import */ var _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3020);
234816
+ /* harmony import */ var _base_Precise_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(2194);
233846
234817
  /* harmony import */ var _static_dependencies_noble_hashes_sha256_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(1372);
233847
234818
  /* harmony import */ var _static_dependencies_noble_hashes_sha512_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(7110);
233848
234819
  // ---------------------------------------------------------------------------
@@ -233867,6 +234838,7 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
233867
234838
  // 'watchStatus': true, // https://docs.futures.kraken.com/#websocket-api-public-feeds-heartbeat
233868
234839
  'watchOrders': true,
233869
234840
  'watchMyTrades': true,
234841
+ 'watchPositions': true,
233870
234842
  },
233871
234843
  'urls': {
233872
234844
  'api': {
@@ -234048,6 +235020,133 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
234048
235020
  const orderbook = await this.subscribePublic('book', [symbol], params);
234049
235021
  return orderbook.limit();
234050
235022
  }
235023
+ async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
235024
+ /**
235025
+ * @method
235026
+ * @name krakenfutures#watchPositions
235027
+ * @see https://docs.futures.kraken.com/#websocket-api-private-feeds-open-positions
235028
+ * @description watch all open positions
235029
+ * @param {[string]|undefined} symbols list of unified market symbols
235030
+ * @param {object} params extra parameters specific to the krakenfutures api endpoint
235031
+ * @returns {[object]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
235032
+ */
235033
+ await this.loadMarkets();
235034
+ let messageHash = '';
235035
+ symbols = this.marketSymbols(symbols);
235036
+ if (!this.isEmpty(symbols)) {
235037
+ messageHash = '::' + symbols.join(',');
235038
+ }
235039
+ messageHash = 'positions' + messageHash;
235040
+ const newPositions = await this.subscribePrivate('open_positions', messageHash, params);
235041
+ if (this.newUpdates) {
235042
+ return newPositions;
235043
+ }
235044
+ return this.filterBySymbolsSinceLimit(this.positions, symbols, since, limit, true);
235045
+ }
235046
+ handlePositions(client, message) {
235047
+ //
235048
+ // {
235049
+ // feed: 'open_positions',
235050
+ // account: '3b111acc-4fcc-45be-a622-57e611fe9f7f',
235051
+ // positions: [
235052
+ // {
235053
+ // instrument: 'PF_LTCUSD',
235054
+ // balance: 0.5,
235055
+ // pnl: -0.8628305877699987,
235056
+ // entry_price: 70.53,
235057
+ // mark_price: 68.80433882446,
235058
+ // index_price: 68.8091,
235059
+ // liquidation_threshold: 0,
235060
+ // effective_leverage: 0.007028866753648637,
235061
+ // return_on_equity: -1.2233525985679834,
235062
+ // unrealized_funding: 0.0000690610530935388,
235063
+ // initial_margin: 0.7053,
235064
+ // initial_margin_with_orders: 0.7053,
235065
+ // maintenance_margin: 0.35265,
235066
+ // pnl_currency: 'USD'
235067
+ // }
235068
+ // ],
235069
+ // seq: 0,
235070
+ // timestamp: 1698608414910
235071
+ // }
235072
+ //
235073
+ if (this.positions === undefined) {
235074
+ this.positions = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_1__/* .ArrayCacheBySymbolById */ .hl();
235075
+ }
235076
+ const cache = this.positions;
235077
+ const rawPositions = this.safeValue(message, 'positions', []);
235078
+ const newPositions = [];
235079
+ for (let i = 0; i < rawPositions.length; i++) {
235080
+ const rawPosition = rawPositions[i];
235081
+ const position = this.parseWsPosition(rawPosition);
235082
+ const timestamp = this.safeInteger(message, 'timestamp');
235083
+ position['timestamp'] = timestamp;
235084
+ position['datetime'] = this.iso8601(timestamp);
235085
+ newPositions.push(position);
235086
+ cache.append(position);
235087
+ }
235088
+ const messageHashes = this.findMessageHashes(client, 'positions::');
235089
+ for (let i = 0; i < messageHashes.length; i++) {
235090
+ const messageHash = messageHashes[i];
235091
+ const parts = messageHash.split('::');
235092
+ const symbolsString = parts[1];
235093
+ const symbols = symbolsString.split(',');
235094
+ const positions = this.filterByArray(newPositions, 'symbol', symbols, false);
235095
+ if (!this.isEmpty(positions)) {
235096
+ client.resolve(positions, messageHash);
235097
+ }
235098
+ }
235099
+ client.resolve(newPositions, 'positions');
235100
+ }
235101
+ parseWsPosition(position, market = undefined) {
235102
+ //
235103
+ // {
235104
+ // instrument: 'PF_LTCUSD',
235105
+ // balance: 0.5,
235106
+ // pnl: -0.8628305877699987,
235107
+ // entry_price: 70.53,
235108
+ // mark_price: 68.80433882446,
235109
+ // index_price: 68.8091,
235110
+ // liquidation_threshold: 0,
235111
+ // effective_leverage: 0.007028866753648637,
235112
+ // return_on_equity: -1.2233525985679834,
235113
+ // unrealized_funding: 0.0000690610530935388,
235114
+ // initial_margin: 0.7053,
235115
+ // initial_margin_with_orders: 0.7053,
235116
+ // maintenance_margin: 0.35265,
235117
+ // pnl_currency: 'USD'
235118
+ // }
235119
+ //
235120
+ const marketId = this.safeString(position, 'instrument');
235121
+ const hedged = 'both';
235122
+ const balance = this.safeNumber(position, 'balance');
235123
+ const side = (balance > 0) ? 'long' : 'short';
235124
+ return this.safePosition({
235125
+ 'info': position,
235126
+ 'id': undefined,
235127
+ 'symbol': this.safeSymbol(marketId),
235128
+ 'notional': undefined,
235129
+ 'marginMode': undefined,
235130
+ 'liquidationPrice': this.safeNumber(position, 'liquidation_threshold'),
235131
+ 'entryPrice': this.safeNumber(position, 'entry_price'),
235132
+ 'unrealizedPnl': this.safeNumber(position, 'pnl'),
235133
+ 'percentage': this.safeNumber(position, 'return_on_equity'),
235134
+ 'contracts': this.parseNumber(_base_Precise_js__WEBPACK_IMPORTED_MODULE_2__/* .Precise.stringAbs */ .O.stringAbs(this.numberToString(balance))),
235135
+ 'contractSize': undefined,
235136
+ 'markPrice': this.safeNumber(position, 'mark_price'),
235137
+ 'side': side,
235138
+ 'hedged': hedged,
235139
+ 'timestamp': undefined,
235140
+ 'datetime': undefined,
235141
+ 'maintenanceMargin': this.safeNumber(position, 'maintenance_margin'),
235142
+ 'maintenanceMarginPercentage': undefined,
235143
+ 'collateral': undefined,
235144
+ 'initialMargin': this.safeNumber(position, 'initial_margin'),
235145
+ 'initialMarginPercentage': undefined,
235146
+ 'leverage': undefined,
235147
+ 'marginRatio': undefined,
235148
+ });
235149
+ }
234051
235150
  async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
234052
235151
  /**
234053
235152
  * @method
@@ -234119,7 +235218,7 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
234119
235218
  [account, params] = this.handleOptionAndParams(params, 'watchBalance', 'account');
234120
235219
  if (account !== undefined) {
234121
235220
  if (account !== 'futures' && account !== 'flex_futures') {
234122
- throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.ArgumentsRequired(this.id + ' watchBalance account must be either \'futures\' or \'flex_futures\'');
235221
+ throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_3__.ArgumentsRequired(this.id + ' watchBalance account must be either \'futures\' or \'flex_futures\'');
234123
235222
  }
234124
235223
  messageHash += ':' + account;
234125
235224
  }
@@ -234171,7 +235270,7 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
234171
235270
  let tradesArray = this.safeValue(this.trades, symbol);
234172
235271
  if (tradesArray === undefined) {
234173
235272
  const tradesLimit = this.safeInteger(this.options, 'tradesLimit', 1000);
234174
- tradesArray = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_2__/* .ArrayCache */ .ZL(tradesLimit);
235273
+ tradesArray = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_1__/* .ArrayCache */ .ZL(tradesLimit);
234175
235274
  this.trades[symbol] = tradesArray;
234176
235275
  }
234177
235276
  if (channel === 'trade_snapshot') {
@@ -234331,7 +235430,7 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
234331
235430
  let orders = this.orders;
234332
235431
  if (orders === undefined) {
234333
235432
  const limit = this.safeInteger(this.options, 'ordersLimit');
234334
- orders = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_2__/* .ArrayCacheBySymbolById */ .hl(limit);
235433
+ orders = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_1__/* .ArrayCacheBySymbolById */ .hl(limit);
234335
235434
  this.orders = orders;
234336
235435
  }
234337
235436
  const order = this.safeValue(message, 'order');
@@ -234360,17 +235459,17 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
234360
235459
  const trades = previousOrder['trades'];
234361
235460
  for (let i = 0; i < trades.length; i++) {
234362
235461
  const currentTrade = trades[i];
234363
- totalCost = _base_Precise_js__WEBPACK_IMPORTED_MODULE_3__/* .Precise.stringAdd */ .O.stringAdd(totalCost, this.numberToString(currentTrade['cost']));
234364
- totalAmount = _base_Precise_js__WEBPACK_IMPORTED_MODULE_3__/* .Precise.stringAdd */ .O.stringAdd(totalAmount, this.numberToString(currentTrade['amount']));
235462
+ totalCost = _base_Precise_js__WEBPACK_IMPORTED_MODULE_2__/* .Precise.stringAdd */ .O.stringAdd(totalCost, this.numberToString(currentTrade['cost']));
235463
+ totalAmount = _base_Precise_js__WEBPACK_IMPORTED_MODULE_2__/* .Precise.stringAdd */ .O.stringAdd(totalAmount, this.numberToString(currentTrade['amount']));
234365
235464
  }
234366
- if (_base_Precise_js__WEBPACK_IMPORTED_MODULE_3__/* .Precise.stringGt */ .O.stringGt(totalAmount, '0')) {
234367
- previousOrder['average'] = _base_Precise_js__WEBPACK_IMPORTED_MODULE_3__/* .Precise.stringDiv */ .O.stringDiv(totalCost, totalAmount);
235465
+ if (_base_Precise_js__WEBPACK_IMPORTED_MODULE_2__/* .Precise.stringGt */ .O.stringGt(totalAmount, '0')) {
235466
+ previousOrder['average'] = _base_Precise_js__WEBPACK_IMPORTED_MODULE_2__/* .Precise.stringDiv */ .O.stringDiv(totalCost, totalAmount);
234368
235467
  }
234369
235468
  previousOrder['cost'] = totalCost;
234370
235469
  if (previousOrder['filled'] !== undefined) {
234371
- previousOrder['filled'] = _base_Precise_js__WEBPACK_IMPORTED_MODULE_3__/* .Precise.stringAdd */ .O.stringAdd(previousOrder['filled'], this.numberToString(trade['amount']));
235470
+ previousOrder['filled'] = _base_Precise_js__WEBPACK_IMPORTED_MODULE_2__/* .Precise.stringAdd */ .O.stringAdd(previousOrder['filled'], this.numberToString(trade['amount']));
234372
235471
  if (previousOrder['amount'] !== undefined) {
234373
- previousOrder['remaining'] = _base_Precise_js__WEBPACK_IMPORTED_MODULE_3__/* .Precise.stringSub */ .O.stringSub(previousOrder['amount'], previousOrder['filled']);
235472
+ previousOrder['remaining'] = _base_Precise_js__WEBPACK_IMPORTED_MODULE_2__/* .Precise.stringSub */ .O.stringSub(previousOrder['amount'], previousOrder['filled']);
234374
235473
  }
234375
235474
  }
234376
235475
  if (previousOrder['fee'] === undefined) {
@@ -234383,7 +235482,7 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
234383
235482
  if ((previousOrder['fee']['cost'] !== undefined) && (trade['fee']['cost'] !== undefined)) {
234384
235483
  const stringOrderCost = this.numberToString(previousOrder['fee']['cost']);
234385
235484
  const stringTradeCost = this.numberToString(trade['fee']['cost']);
234386
- previousOrder['fee']['cost'] = _base_Precise_js__WEBPACK_IMPORTED_MODULE_3__/* .Precise.stringAdd */ .O.stringAdd(stringOrderCost, stringTradeCost);
235485
+ previousOrder['fee']['cost'] = _base_Precise_js__WEBPACK_IMPORTED_MODULE_2__/* .Precise.stringAdd */ .O.stringAdd(stringOrderCost, stringTradeCost);
234387
235486
  }
234388
235487
  // update the newUpdates count
234389
235488
  orders.append(this.safeOrder(previousOrder));
@@ -234460,7 +235559,7 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
234460
235559
  // }
234461
235560
  const orders = this.safeValue(message, 'orders', []);
234462
235561
  const limit = this.safeInteger(this.options, 'ordersLimit');
234463
- this.orders = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_2__/* .ArrayCacheBySymbolById */ .hl(limit);
235562
+ this.orders = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_1__/* .ArrayCacheBySymbolById */ .hl(limit);
234464
235563
  const symbols = {};
234465
235564
  const cachedOrders = this.orders;
234466
235565
  for (let i = 0; i < orders.length; i++) {
@@ -235035,7 +236134,7 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
235035
236134
  let stored = this.myTrades;
235036
236135
  if (stored === undefined) {
235037
236136
  const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
235038
- stored = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_2__/* .ArrayCacheBySymbolById */ .hl(limit);
236137
+ stored = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_1__/* .ArrayCacheBySymbolById */ .hl(limit);
235039
236138
  this.myTrades = stored;
235040
236139
  }
235041
236140
  const tradeSymbols = {};
@@ -235123,6 +236222,7 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
235123
236222
  'open_orders_snapshot': this.handleOrderSnapshot,
235124
236223
  'balances': this.handleBalance,
235125
236224
  'balances_snapshot': this.handleBalance,
236225
+ 'open_positions': this.handlePositions,
235126
236226
  };
235127
236227
  const method = this.safeValue(methods, feed);
235128
236228
  if (method !== undefined) {
@@ -235154,7 +236254,7 @@ class krakenfutures extends _krakenfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
235154
236254
  client.resolve(message, messageHash);
235155
236255
  }
235156
236256
  else {
235157
- const error = new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.AuthenticationError(this.id + ' ' + this.json(message));
236257
+ const error = new _base_errors_js__WEBPACK_IMPORTED_MODULE_3__.AuthenticationError(this.id + ' ' + this.json(message));
235158
236258
  client.reject(error, messageHash);
235159
236259
  if (messageHash in client.subscriptions) {
235160
236260
  delete client.subscriptions[messageHash];
@@ -236219,8 +237319,8 @@ class kucoin extends _kucoin_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z
236219
237319
  /* harmony export */ "Z": () => (/* binding */ kucoinfutures)
236220
237320
  /* harmony export */ });
236221
237321
  /* harmony import */ var _kucoinfutures_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1924);
236222
- /* harmony import */ var _base_errors_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(6689);
236223
- /* harmony import */ var _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3020);
237322
+ /* harmony import */ var _base_errors_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6689);
237323
+ /* harmony import */ var _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(3020);
236224
237324
  // ---------------------------------------------------------------------------
236225
237325
 
236226
237326
 
@@ -236236,6 +237336,9 @@ class kucoinfutures extends _kucoinfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
236236
237336
  'watchOrderBook': true,
236237
237337
  'watchOrders': true,
236238
237338
  'watchBalance': true,
237339
+ 'watchPosition': true,
237340
+ 'watchPositions': false,
237341
+ 'watchPositionForSymbols': false,
236239
237342
  'watchTradesForSymbols': true,
236240
237343
  'watchOrderBookForSymbols': true,
236241
237344
  },
@@ -236261,6 +237364,10 @@ class kucoinfutures extends _kucoinfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
236261
237364
  'watchTicker': {
236262
237365
  'name': 'contractMarket/tickerV2', // market/ticker
236263
237366
  },
237367
+ 'watchPosition': {
237368
+ 'fetchPositionSnapshot': true,
237369
+ 'awaitPositionSnapshot': true, // whether to wait for the position snapshot before providing updates
237370
+ },
236264
237371
  },
236265
237372
  'streaming': {
236266
237373
  // kucoin does not support built-in ws protocol-level ping-pong
@@ -236397,6 +237504,178 @@ class kucoinfutures extends _kucoinfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
236397
237504
  client.resolve(ticker, messageHash);
236398
237505
  return message;
236399
237506
  }
237507
+ async watchPosition(symbol = undefined, params = {}) {
237508
+ /**
237509
+ * @method
237510
+ * @name kucoinfutures#watchPosition
237511
+ * @description watch open positions for a specific symbol
237512
+ * @see https://docs.kucoin.com/futures/#position-change-events
237513
+ * @param {string|undefined} symbol unified market symbol
237514
+ * @param {object} params extra parameters specific to the kucoinfutures api endpoint
237515
+ * @returns {object} a [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
237516
+ */
237517
+ this.checkRequiredSymbol('watchPosition', symbol);
237518
+ await this.loadMarkets();
237519
+ const url = await this.negotiate(true);
237520
+ const market = this.market(symbol);
237521
+ const topic = '/contract/position:' + market['id'];
237522
+ const request = {
237523
+ 'privateChannel': true,
237524
+ };
237525
+ const messageHash = 'position:' + market['symbol'];
237526
+ const client = this.client(url);
237527
+ this.setPositionCache(client, symbol);
237528
+ const fetchPositionSnapshot = this.handleOption('watchPosition', 'fetchPositionSnapshot', true);
237529
+ const awaitPositionSnapshot = this.safeValue('watchPosition', 'awaitPositionSnapshot', true);
237530
+ const currentPosition = this.getCurrentPosition(symbol);
237531
+ if (fetchPositionSnapshot && awaitPositionSnapshot && currentPosition === undefined) {
237532
+ const snapshot = await client.future('fetchPositionSnapshot:' + symbol);
237533
+ return snapshot;
237534
+ }
237535
+ return await this.subscribe(url, messageHash, topic, undefined, this.extend(request, params));
237536
+ }
237537
+ getCurrentPosition(symbol) {
237538
+ if (this.positions === undefined) {
237539
+ return undefined;
237540
+ }
237541
+ const cache = this.positions.hashmap;
237542
+ const symbolCache = this.safeValue(cache, symbol, {});
237543
+ const values = Object.values(symbolCache);
237544
+ return this.safeValue(values, 0);
237545
+ }
237546
+ setPositionCache(client, symbol) {
237547
+ const fetchPositionSnapshot = this.handleOption('watchPosition', 'fetchPositionSnapshot', false);
237548
+ if (fetchPositionSnapshot) {
237549
+ const messageHash = 'fetchPositionSnapshot:' + symbol;
237550
+ if (!(messageHash in client.futures)) {
237551
+ client.future(messageHash);
237552
+ this.spawn(this.loadPositionSnapshot, client, messageHash, symbol);
237553
+ }
237554
+ }
237555
+ }
237556
+ async loadPositionSnapshot(client, messageHash, symbol) {
237557
+ const position = await this.fetchPosition(symbol);
237558
+ this.positions = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_1__/* .ArrayCacheBySymbolById */ .hl();
237559
+ const cache = this.positions;
237560
+ cache.append(position);
237561
+ // don't remove the future from the .futures cache
237562
+ const future = client.futures[messageHash];
237563
+ future.resolve(cache);
237564
+ client.resolve(position, 'position:' + symbol);
237565
+ }
237566
+ handlePosition(client, message) {
237567
+ //
237568
+ // Position Changes Caused Operations
237569
+ // {
237570
+ // "type": "message",
237571
+ // "userId": "5c32d69203aa676ce4b543c7", // Deprecated, will detele later
237572
+ // "channelType": "private",
237573
+ // "topic": "/contract/position:XBTUSDM",
237574
+ // "subject": "position.change",
237575
+ // "data": {
237576
+ // "realisedGrossPnl": 0E-8, //Accumulated realised profit and loss
237577
+ // "symbol": "XBTUSDM", //Symbol
237578
+ // "crossMode": false, //Cross mode or not
237579
+ // "liquidationPrice": 1000000.0, //Liquidation price
237580
+ // "posLoss": 0E-8, //Manually added margin amount
237581
+ // "avgEntryPrice": 7508.22, //Average entry price
237582
+ // "unrealisedPnl": -0.00014735, //Unrealised profit and loss
237583
+ // "markPrice": 7947.83, //Mark price
237584
+ // "posMargin": 0.00266779, //Position margin
237585
+ // "autoDeposit": false, //Auto deposit margin or not
237586
+ // "riskLimit": 100000, //Risk limit
237587
+ // "unrealisedCost": 0.00266375, //Unrealised value
237588
+ // "posComm": 0.00000392, //Bankruptcy cost
237589
+ // "posMaint": 0.00001724, //Maintenance margin
237590
+ // "posCost": 0.00266375, //Position value
237591
+ // "maintMarginReq": 0.005, //Maintenance margin rate
237592
+ // "bankruptPrice": 1000000.0, //Bankruptcy price
237593
+ // "realisedCost": 0.00000271, //Currently accumulated realised position value
237594
+ // "markValue": 0.00251640, //Mark value
237595
+ // "posInit": 0.00266375, //Position margin
237596
+ // "realisedPnl": -0.00000253, //Realised profit and losts
237597
+ // "maintMargin": 0.00252044, //Position margin
237598
+ // "realLeverage": 1.06, //Leverage of the order
237599
+ // "changeReason": "positionChange", //changeReason:marginChange、positionChange、liquidation、autoAppendMarginStatusChange、adl
237600
+ // "currentCost": 0.00266375, //Current position value
237601
+ // "openingTimestamp": 1558433191000, //Open time
237602
+ // "currentQty": -20, //Current position
237603
+ // "delevPercentage": 0.52, //ADL ranking percentile
237604
+ // "currentComm": 0.00000271, //Current commission
237605
+ // "realisedGrossCost": 0E-8, //Accumulated reliased gross profit value
237606
+ // "isOpen": true, //Opened position or not
237607
+ // "posCross": 1.2E-7, //Manually added margin
237608
+ // "currentTimestamp": 1558506060394, //Current timestamp
237609
+ // "unrealisedRoePcnt": -0.0553, //Rate of return on investment
237610
+ // "unrealisedPnlPcnt": -0.0553, //Position profit and loss ratio
237611
+ // "settleCurrency": "XBT" //Currency used to clear and settle the trades
237612
+ // }
237613
+ // }
237614
+ // Position Changes Caused by Mark Price
237615
+ // {
237616
+ // "userId": "5cd3f1a7b7ebc19ae9558591", // Deprecated, will detele later
237617
+ // "topic": "/contract/position:XBTUSDM",
237618
+ // "subject": "position.change",
237619
+ // "data": {
237620
+ // "markPrice": 7947.83, //Mark price
237621
+ // "markValue": 0.00251640, //Mark value
237622
+ // "maintMargin": 0.00252044, //Position margin
237623
+ // "realLeverage": 10.06, //Leverage of the order
237624
+ // "unrealisedPnl": -0.00014735, //Unrealised profit and lost
237625
+ // "unrealisedRoePcnt": -0.0553, //Rate of return on investment
237626
+ // "unrealisedPnlPcnt": -0.0553, //Position profit and loss ratio
237627
+ // "delevPercentage": 0.52, //ADL ranking percentile
237628
+ // "currentTimestamp": 1558087175068, //Current timestamp
237629
+ // "settleCurrency": "XBT" //Currency used to clear and settle the trades
237630
+ // }
237631
+ // }
237632
+ // Funding Settlement
237633
+ // {
237634
+ // "userId": "xbc453tg732eba53a88ggyt8c", // Deprecated, will detele later
237635
+ // "topic": "/contract/position:XBTUSDM",
237636
+ // "subject": "position.settlement",
237637
+ // "data": {
237638
+ // "fundingTime": 1551770400000, //Funding time
237639
+ // "qty": 100, //Position siz
237640
+ // "markPrice": 3610.85, //Settlement price
237641
+ // "fundingRate": -0.002966, //Funding rate
237642
+ // "fundingFee": -296, //Funding fees
237643
+ // "ts": 1547697294838004923, //Current time (nanosecond)
237644
+ // "settleCurrency": "XBT" //Currency used to clear and settle the trades
237645
+ // }
237646
+ // }
237647
+ // Adjustmet result of risk limit level
237648
+ // {
237649
+ // "userId": "xbc453tg732eba53a88ggyt8c",
237650
+ // "topic": "/contract/position:ADAUSDTM",
237651
+ // "subject": "position.adjustRiskLimit",
237652
+ // "data": {
237653
+ // "success": true, // Successful or not
237654
+ // "riskLimitLevel": 1, // Current risk limit level
237655
+ // "msg": "" // Failure reason
237656
+ // }
237657
+ // }
237658
+ //
237659
+ const topic = this.safeString(message, 'topic', '');
237660
+ const parts = topic.split(':');
237661
+ const marketId = this.safeString(parts, 1);
237662
+ const symbol = this.safeSymbol(marketId, undefined, '');
237663
+ const cache = this.positions;
237664
+ const currentPosition = this.getCurrentPosition(symbol);
237665
+ const messageHash = 'position:' + symbol;
237666
+ const data = this.safeValue(message, 'data', {});
237667
+ const newPosition = this.parsePosition(data);
237668
+ const keys = Object.keys(newPosition);
237669
+ for (let i = 0; i < keys.length; i++) {
237670
+ const key = keys[i];
237671
+ if (newPosition[key] === undefined) {
237672
+ delete newPosition[key];
237673
+ }
237674
+ }
237675
+ const position = this.extend(currentPosition, newPosition);
237676
+ cache.append(position);
237677
+ client.resolve(position, messageHash);
237678
+ }
236400
237679
  async watchTrades(symbol, since = undefined, limit = undefined, params = {}) {
236401
237680
  /**
236402
237681
  * @method
@@ -236434,7 +237713,7 @@ class kucoinfutures extends _kucoinfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
236434
237713
  */
236435
237714
  const symbolsLength = symbols.length;
236436
237715
  if (symbolsLength === 0) {
236437
- throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.ArgumentsRequired(this.id + ' watchTradesForSymbols() requires a non-empty array of symbols');
237716
+ throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.ArgumentsRequired(this.id + ' watchTradesForSymbols() requires a non-empty array of symbols');
236438
237717
  }
236439
237718
  await this.loadMarkets();
236440
237719
  symbols = this.marketSymbols(symbols);
@@ -236478,7 +237757,7 @@ class kucoinfutures extends _kucoinfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
236478
237757
  let trades = this.safeValue(this.trades, symbol);
236479
237758
  if (trades === undefined) {
236480
237759
  const limit = this.safeInteger(this.options, 'tradesLimit', 1000);
236481
- trades = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_2__/* .ArrayCache */ .ZL(limit);
237760
+ trades = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_1__/* .ArrayCache */ .ZL(limit);
236482
237761
  this.trades[symbol] = trades;
236483
237762
  }
236484
237763
  trades.append(trade);
@@ -236506,7 +237785,7 @@ class kucoinfutures extends _kucoinfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
236506
237785
  */
236507
237786
  if (limit !== undefined) {
236508
237787
  if ((limit !== 20) && (limit !== 100)) {
236509
- throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.ExchangeError(this.id + " watchOrderBook 'limit' argument must be undefined, 20 or 100");
237788
+ throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.ExchangeError(this.id + " watchOrderBook 'limit' argument must be undefined, 20 or 100");
236510
237789
  }
236511
237790
  }
236512
237791
  await this.loadMarkets();
@@ -236535,11 +237814,11 @@ class kucoinfutures extends _kucoinfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
236535
237814
  */
236536
237815
  const symbolsLength = symbols.length;
236537
237816
  if (symbolsLength === 0) {
236538
- throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.ArgumentsRequired(this.id + ' watchOrderBookForSymbols() requires a non-empty array of symbols');
237817
+ throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.ArgumentsRequired(this.id + ' watchOrderBookForSymbols() requires a non-empty array of symbols');
236539
237818
  }
236540
237819
  if (limit !== undefined) {
236541
237820
  if ((limit !== 20) && (limit !== 100)) {
236542
- throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.ExchangeError(this.id + " watchOrderBook 'limit' argument must be undefined, 20 or 100");
237821
+ throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_2__.ExchangeError(this.id + " watchOrderBook 'limit' argument must be undefined, 20 or 100");
236543
237822
  }
236544
237823
  }
236545
237824
  await this.loadMarkets();
@@ -236803,7 +238082,7 @@ class kucoinfutures extends _kucoinfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
236803
238082
  if (symbol !== undefined) {
236804
238083
  if (this.orders === undefined) {
236805
238084
  const limit = this.safeInteger(this.options, 'ordersLimit', 1000);
236806
- this.orders = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_2__/* .ArrayCacheBySymbolById */ .hl(limit);
238085
+ this.orders = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_1__/* .ArrayCacheBySymbolById */ .hl(limit);
236807
238086
  }
236808
238087
  const cachedOrders = this.orders;
236809
238088
  const orders = this.safeValue(cachedOrders.hashmap, symbol, {});
@@ -236949,6 +238228,9 @@ class kucoinfutures extends _kucoinfutures_js__WEBPACK_IMPORTED_MODULE_0__/* ["d
236949
238228
  'match': this.handleTrade,
236950
238229
  'orderChange': this.handleOrder,
236951
238230
  'orderUpdated': this.handleOrder,
238231
+ 'position.change': this.handlePosition,
238232
+ 'position.settlement': this.handlePosition,
238233
+ 'position.adjustRiskLimit': this.handlePosition,
236952
238234
  };
236953
238235
  const method = this.safeValue(methods, subject);
236954
238236
  if (method === undefined) {
@@ -239900,6 +241182,7 @@ class okx extends _okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
239900
241182
  'watchOHLCV': true,
239901
241183
  'watchOrders': true,
239902
241184
  'watchMyTrades': true,
241185
+ 'watchPositions': true,
239903
241186
  'createOrderWs': true,
239904
241187
  'editOrderWs': true,
239905
241188
  'cancelOrderWs': true,
@@ -240728,6 +242011,125 @@ class okx extends _okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
240728
242011
  }
240729
242012
  return this.filterBySymbolSinceLimit(orders, symbol, since, limit, true);
240730
242013
  }
242014
+ async watchPositions(symbols = undefined, since = undefined, limit = undefined, params = {}) {
242015
+ /**
242016
+ * @method
242017
+ * @name okx#watchPositions
242018
+ * @see https://www.okx.com/docs-v5/en/#trading-account-websocket-positions-channel
242019
+ * @description watch all open positions
242020
+ * @param {[string]|undefined} symbols list of unified market symbols
242021
+ * @param {object} params extra parameters specific to the okx api endpoint
242022
+ * @returns {[object]} a list of [position structure]{@link https://docs.ccxt.com/en/latest/manual.html#position-structure}
242023
+ */
242024
+ if (this.isEmpty(symbols)) {
242025
+ throw new _base_errors_js__WEBPACK_IMPORTED_MODULE_1__.ArgumentsRequired(this.id + ' watchPositions requires a list of symbols');
242026
+ }
242027
+ await this.loadMarkets();
242028
+ await this.authenticate(params);
242029
+ symbols = this.marketSymbols(symbols);
242030
+ const request = {
242031
+ 'instType': 'ANY',
242032
+ };
242033
+ const channel = 'positions';
242034
+ const newPositions = await this.subscribeMultiple('private', channel, symbols, this.extend(request, params));
242035
+ if (this.newUpdates) {
242036
+ return newPositions;
242037
+ }
242038
+ return this.filterBySymbolsSinceLimit(this.positions, symbols, since, limit, true);
242039
+ }
242040
+ handlePositions(client, message) {
242041
+ //
242042
+ // {
242043
+ // arg: {
242044
+ // channel: 'positions',
242045
+ // instType: 'ANY',
242046
+ // instId: 'XRP-USDT-SWAP',
242047
+ // uid: '464737184507959869'
242048
+ // },
242049
+ // data: [{
242050
+ // adl: '1',
242051
+ // availPos: '',
242052
+ // avgPx: '0.52668',
242053
+ // baseBal: '',
242054
+ // baseBorrowed: '',
242055
+ // baseInterest: '',
242056
+ // bizRefId: '',
242057
+ // bizRefType: '',
242058
+ // cTime: '1693151444408',
242059
+ // ccy: 'USDT',
242060
+ // closeOrderAlgo: [],
242061
+ // deltaBS: '',
242062
+ // deltaPA: '',
242063
+ // gammaBS: '',
242064
+ // gammaPA: '',
242065
+ // idxPx: '0.52683',
242066
+ // imr: '17.564000000000004',
242067
+ // instId: 'XRP-USDT-SWAP',
242068
+ // instType: 'SWAP',
242069
+ // interest: '',
242070
+ // last: '0.52691',
242071
+ // lever: '3',
242072
+ // liab: '',
242073
+ // liabCcy: '',
242074
+ // liqPx: '0.3287514731020614',
242075
+ // margin: '',
242076
+ // markPx: '0.52692',
242077
+ // mgnMode: 'cross',
242078
+ // mgnRatio: '69.00363001456147',
242079
+ // mmr: '0.26346',
242080
+ // notionalUsd: '52.68620388000001',
242081
+ // optVal: '',
242082
+ // pTime: '1693151906023',
242083
+ // pendingCloseOrdLiabVal: '',
242084
+ // pos: '1',
242085
+ // posCcy: '',
242086
+ // posId: '616057041198907393',
242087
+ // posSide: 'net',
242088
+ // quoteBal: '',
242089
+ // quoteBorrowed: '',
242090
+ // quoteInterest: '',
242091
+ // spotInUseAmt: '',
242092
+ // spotInUseCcy: '',
242093
+ // thetaBS: '',
242094
+ // thetaPA: '',
242095
+ // tradeId: '138745402',
242096
+ // uTime: '1693151444408',
242097
+ // upl: '0.0240000000000018',
242098
+ // uplLastPx: '0.0229999999999952',
242099
+ // uplRatio: '0.0013670539986328',
242100
+ // uplRatioLastPx: '0.001310093415356',
242101
+ // usdPx: '',
242102
+ // vegaBS: '',
242103
+ // vegaPA: ''
242104
+ // }]
242105
+ // }
242106
+ //
242107
+ const arg = this.safeValue(message, 'arg', {});
242108
+ const channel = this.safeString(arg, 'channel', '');
242109
+ const data = this.safeValue(message, 'data', []);
242110
+ if (this.positions === undefined) {
242111
+ this.positions = new _base_ws_Cache_js__WEBPACK_IMPORTED_MODULE_2__/* .ArrayCacheBySymbolBySide */ .tU();
242112
+ }
242113
+ const cache = this.positions;
242114
+ const newPositions = [];
242115
+ for (let i = 0; i < data.length; i++) {
242116
+ const rawPosition = data[i];
242117
+ const position = this.parsePosition(rawPosition);
242118
+ newPositions.push(position);
242119
+ cache.append(position);
242120
+ }
242121
+ const messageHashes = this.findMessageHashes(client, channel + '::');
242122
+ for (let i = 0; i < messageHashes.length; i++) {
242123
+ const messageHash = messageHashes[i];
242124
+ const parts = messageHash.split('::');
242125
+ const symbolsString = parts[1];
242126
+ const symbols = symbolsString.split(',');
242127
+ const positions = this.filterByArray(newPositions, 'symbol', symbols, false);
242128
+ if (!this.isEmpty(positions)) {
242129
+ client.resolve(positions, messageHash);
242130
+ }
242131
+ }
242132
+ }
240731
242133
  async watchOrders(symbol = undefined, since = undefined, limit = undefined, params = {}) {
240732
242134
  /**
240733
242135
  * @method
@@ -241300,6 +242702,7 @@ class okx extends _okx_js__WEBPACK_IMPORTED_MODULE_0__/* ["default"] */ .Z {
241300
242702
  'books50-l2-tbt': this.handleOrderBook,
241301
242703
  'books-l2-tbt': this.handleOrderBook,
241302
242704
  'tickers': this.handleTicker,
242705
+ 'positions': this.handlePositions,
241303
242706
  'index-tickers': this.handleTicker,
241304
242707
  'sprd-tickers': this.handleTicker,
241305
242708
  'block-tickers': this.handleTicker,
@@ -284081,7 +285484,7 @@ SOFTWARE.
284081
285484
 
284082
285485
  //-----------------------------------------------------------------------------
284083
285486
  // this is updated by vss.js when building
284084
- const version = '4.1.45';
285487
+ const version = '4.1.46';
284085
285488
  _src_base_Exchange_js__WEBPACK_IMPORTED_MODULE_0__/* .Exchange.ccxtVersion */ .e.ccxtVersion = version;
284086
285489
  //-----------------------------------------------------------------------------
284087
285490