ccxt 4.3.4 → 4.3.5

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.
@@ -40,9 +40,14 @@ class binance extends binance$1 {
40
40
  'fetchMarketsWs': false,
41
41
  'fetchMyTradesWs': true,
42
42
  'fetchOHLCVWs': true,
43
+ 'fetchOrderBookWs': true,
43
44
  'fetchOpenOrdersWs': true,
44
45
  'fetchOrderWs': true,
45
46
  'fetchOrdersWs': true,
47
+ 'fetchPositionWs': true,
48
+ 'fetchPositionForSymbolWs': true,
49
+ 'fetchPositionsWs': true,
50
+ 'fetchTickerWs': true,
46
51
  'fetchTradesWs': true,
47
52
  'fetchTradingFeesWs': false,
48
53
  'fetchWithdrawalsWs': false,
@@ -54,7 +59,10 @@ class binance extends binance$1 {
54
59
  'margin': 'wss://testnet.binance.vision/ws',
55
60
  'future': 'wss://fstream.binancefuture.com/ws',
56
61
  'delivery': 'wss://dstream.binancefuture.com/ws',
57
- 'ws': 'wss://testnet.binance.vision/ws-api/v3',
62
+ 'ws-api': {
63
+ 'spot': 'wss://testnet.binance.vision/ws-api/v3',
64
+ 'future': 'wss://testnet.binancefuture.com/ws-fapi/v1',
65
+ },
58
66
  },
59
67
  },
60
68
  'api': {
@@ -63,7 +71,10 @@ class binance extends binance$1 {
63
71
  'margin': 'wss://stream.binance.com:9443/ws',
64
72
  'future': 'wss://fstream.binance.com/ws',
65
73
  'delivery': 'wss://dstream.binance.com/ws',
66
- 'ws': 'wss://ws-api.binance.com:443/ws-api/v3',
74
+ 'ws-api': {
75
+ 'spot': 'wss://ws-api.binance.com:443/ws-api/v3',
76
+ 'future': 'wss://ws-fapi.binance.com/ws-fapi/v1',
77
+ },
67
78
  'papi': 'wss://fstream.binance.com/pm/ws',
68
79
  },
69
80
  },
@@ -275,6 +286,79 @@ class binance extends binance$1 {
275
286
  const orderbook = await this.watchMultiple(url, messageHashes, message, messageHashes, subscription);
276
287
  return orderbook.limit();
277
288
  }
289
+ async fetchOrderBookWs(symbol, limit = undefined, params = {}) {
290
+ /**
291
+ * @method
292
+ * @name binance#fetchOrderBookWs
293
+ * @description fetches information on open orders with bid (buy) and ask (sell) prices, volumes and other data
294
+ * @see https://binance-docs.github.io/apidocs/futures/en/#order-book-2
295
+ * @param {string} symbol unified symbol of the market to fetch the order book for
296
+ * @param {int} [limit] the maximum amount of order book entries to return
297
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
298
+ * @returns {object} A dictionary of [order book structures]{@link https://docs.ccxt.com/#/?id=order-book-structure} indexed by market symbols
299
+ */
300
+ await this.loadMarkets();
301
+ const market = this.market(symbol);
302
+ const payload = {
303
+ 'symbol': market['id'],
304
+ };
305
+ if (limit !== undefined) {
306
+ payload['limit'] = limit;
307
+ }
308
+ const marketType = this.getMarketType('fetchOrderBookWs', market, params);
309
+ if (marketType !== 'future') {
310
+ throw new errors.BadRequest(this.id + ' fetchOrderBookWs only supports swap markets');
311
+ }
312
+ const url = this.urls['api']['ws']['ws-api'][marketType];
313
+ const requestId = this.requestId(url);
314
+ const messageHash = requestId.toString();
315
+ let returnRateLimits = false;
316
+ [returnRateLimits, params] = this.handleOptionAndParams(params, 'createOrderWs', 'returnRateLimits', false);
317
+ payload['returnRateLimits'] = returnRateLimits;
318
+ params = this.omit(params, 'test');
319
+ const message = {
320
+ 'id': messageHash,
321
+ 'method': 'depth',
322
+ 'params': this.signParams(this.extend(payload, params)),
323
+ };
324
+ const subscription = {
325
+ 'method': this.handleFetchOrderBook,
326
+ };
327
+ const orderbook = await this.watch(url, messageHash, message, messageHash, subscription);
328
+ orderbook['symbol'] = market['symbol'];
329
+ return orderbook;
330
+ }
331
+ handleFetchOrderBook(client, message) {
332
+ //
333
+ // {
334
+ // "id":"51e2affb-0aba-4821-ba75-f2625006eb43",
335
+ // "status":200,
336
+ // "result":{
337
+ // "lastUpdateId":1027024,
338
+ // "E":1589436922972,
339
+ // "T":1589436922959,
340
+ // "bids":[
341
+ // [
342
+ // "4.00000000",
343
+ // "431.00000000"
344
+ // ]
345
+ // ],
346
+ // "asks":[
347
+ // [
348
+ // "4.00000200",
349
+ // "12.00000000"
350
+ // ]
351
+ // ]
352
+ // }
353
+ // }
354
+ //
355
+ const messageHash = this.safeString(message, 'id');
356
+ const result = this.safeDict(message, 'result');
357
+ const timestamp = this.safeInteger(result, 'T');
358
+ const orderbook = this.parseOrderBook(result, undefined, timestamp);
359
+ orderbook['nonce'] = this.safeInteger2(result, 'lastUpdateId', 'u');
360
+ client.resolve(orderbook, messageHash);
361
+ }
278
362
  async fetchOrderBookSnapshot(client, message, subscription) {
279
363
  const name = this.safeString(subscription, 'name');
280
364
  const symbol = this.safeString(subscription, 'symbol');
@@ -856,6 +940,47 @@ class binance extends binance$1 {
856
940
  stored.append(parsed);
857
941
  client.resolve(stored, messageHash);
858
942
  }
943
+ async fetchTickerWs(symbol, params = {}) {
944
+ /**
945
+ * @method
946
+ * @name binance#fetchTickerWs
947
+ * @description fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
948
+ * @see https://binance-docs.github.io/apidocs/voptions/en/#24hr-ticker-price-change-statistics
949
+ * @param {string} symbol unified symbol of the market to fetch the ticker for
950
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
951
+ * @param {string} [params.method] method to use can be ticker.price or ticker.book
952
+ * @param {boolean} [params.returnRateLimits] return the rate limits for the exchange
953
+ * @returns {object} a [ticker structure]{@link https://docs.ccxt.com/#/?id=ticker-structure}
954
+ */
955
+ await this.loadMarkets();
956
+ const market = this.market(symbol);
957
+ const payload = {
958
+ 'symbol': market['id'],
959
+ };
960
+ const type = this.getMarketType('fetchTickerWs', market, params);
961
+ if (type !== 'future') {
962
+ throw new errors.BadRequest(this.id + ' fetchTickerWs only supports swap markets');
963
+ }
964
+ const url = this.urls['api']['ws']['ws-api'][type];
965
+ const requestId = this.requestId(url);
966
+ const messageHash = requestId.toString();
967
+ const subscription = {
968
+ 'method': this.handleTickerWs,
969
+ };
970
+ let returnRateLimits = false;
971
+ [returnRateLimits, params] = this.handleOptionAndParams(params, 'fetchTickerWs', 'returnRateLimits', false);
972
+ payload['returnRateLimits'] = returnRateLimits;
973
+ params = this.omit(params, 'test');
974
+ let method = undefined;
975
+ [method, params] = this.handleOptionAndParams(params, 'fetchTickerWs', 'method', 'ticker.book');
976
+ const message = {
977
+ 'id': messageHash,
978
+ 'method': method,
979
+ 'params': this.signParams(this.extend(payload, params)),
980
+ };
981
+ const ticker = await this.watch(url, messageHash, message, messageHash, subscription);
982
+ return ticker;
983
+ }
859
984
  async fetchOHLCVWs(symbol, timeframe = '1m', since = undefined, limit = undefined, params = {}) {
860
985
  /**
861
986
  * @method
@@ -874,8 +999,12 @@ class binance extends binance$1 {
874
999
  * @returns {int[][]} A list of candles ordered as timestamp, open, high, low, close, volume
875
1000
  */
876
1001
  await this.loadMarkets();
877
- this.checkIsSpot('fetchOHLCVWs', symbol, params);
878
- const url = this.urls['api']['ws']['ws'];
1002
+ const market = this.market(symbol);
1003
+ const marketType = this.getMarketType('fetchOHLCVWs', market, params);
1004
+ if (marketType !== 'spot' && marketType !== 'future') {
1005
+ throw new errors.BadRequest(this.id + ' fetchOHLCVWs only supports spot or swap markets');
1006
+ }
1007
+ const url = this.urls['api']['ws']['ws-api'][marketType];
879
1008
  const requestId = this.requestId(url);
880
1009
  const messageHash = requestId.toString();
881
1010
  let returnRateLimits = false;
@@ -1112,6 +1241,22 @@ class binance extends binance$1 {
1112
1241
  // "v": "2109995.32000000",
1113
1242
  // "q": "2019254.05788000"
1114
1243
  // }
1244
+ // fetchTickerWs
1245
+ // {
1246
+ // "symbol":"BTCUSDT",
1247
+ // "price":"72606.70",
1248
+ // "time":1712526204284
1249
+ // }
1250
+ // fetchTickerWs - ticker.book
1251
+ // {
1252
+ // "lastUpdateId":1027024,
1253
+ // "symbol":"BTCUSDT",
1254
+ // "bidPrice":"4.00000000",
1255
+ // "bidQty":"431.00000000",
1256
+ // "askPrice":"4.00000200",
1257
+ // "askQty":"9.00000000",
1258
+ // "time":1589437530011,
1259
+ // }
1115
1260
  //
1116
1261
  let event = this.safeString(message, 'e', 'bookTicker');
1117
1262
  if (event === '24hrTicker') {
@@ -1120,26 +1265,26 @@ class binance extends binance$1 {
1120
1265
  let timestamp = undefined;
1121
1266
  if (event === 'bookTicker') {
1122
1267
  // take the event timestamp, if available, for spot tickers it is not
1123
- timestamp = this.safeInteger(message, 'E');
1268
+ timestamp = this.safeInteger2(message, 'E', 'time');
1124
1269
  }
1125
1270
  else {
1126
1271
  // take the timestamp of the closing price for candlestick streams
1127
- timestamp = this.safeInteger2(message, 'C', 'E');
1272
+ timestamp = this.safeIntegerN(message, ['C', 'E', 'time']);
1128
1273
  }
1129
- const marketId = this.safeString(message, 's');
1274
+ const marketId = this.safeString2(message, 's', 'symbol');
1130
1275
  const symbol = this.safeSymbol(marketId, undefined, undefined, marketType);
1131
1276
  const market = this.safeMarket(marketId, undefined, undefined, marketType);
1132
- const last = this.safeString(message, 'c');
1277
+ const last = this.safeString2(message, 'c', 'price');
1133
1278
  return this.safeTicker({
1134
1279
  'symbol': symbol,
1135
1280
  'timestamp': timestamp,
1136
1281
  'datetime': this.iso8601(timestamp),
1137
1282
  'high': this.safeString(message, 'h'),
1138
1283
  'low': this.safeString(message, 'l'),
1139
- 'bid': this.safeString(message, 'b'),
1140
- 'bidVolume': this.safeString(message, 'B'),
1141
- 'ask': this.safeString(message, 'a'),
1142
- 'askVolume': this.safeString(message, 'A'),
1284
+ 'bid': this.safeString2(message, 'b', 'bidPrice'),
1285
+ 'bidVolume': this.safeString2(message, 'B', 'bidQty'),
1286
+ 'ask': this.safeString2(message, 'a', 'askPrice'),
1287
+ 'askVolume': this.safeString2(message, 'A', 'askQty'),
1143
1288
  'vwap': this.safeString(message, 'w'),
1144
1289
  'open': this.safeString(message, 'o'),
1145
1290
  'close': last,
@@ -1153,6 +1298,38 @@ class binance extends binance$1 {
1153
1298
  'info': message,
1154
1299
  }, market);
1155
1300
  }
1301
+ handleTickerWs(client, message) {
1302
+ //
1303
+ // ticker.price
1304
+ // {
1305
+ // "id":"1",
1306
+ // "status":200,
1307
+ // "result":{
1308
+ // "symbol":"BTCUSDT",
1309
+ // "price":"73178.50",
1310
+ // "time":1712527052374
1311
+ // }
1312
+ // }
1313
+ // ticker.book
1314
+ // {
1315
+ // "id":"9d32157c-a556-4d27-9866-66760a174b57",
1316
+ // "status":200,
1317
+ // "result":{
1318
+ // "lastUpdateId":1027024,
1319
+ // "symbol":"BTCUSDT",
1320
+ // "bidPrice":"4.00000000",
1321
+ // "bidQty":"431.00000000",
1322
+ // "askPrice":"4.00000200",
1323
+ // "askQty":"9.00000000",
1324
+ // "time":1589437530011 // Transaction time
1325
+ // }
1326
+ // }
1327
+ //
1328
+ const messageHash = this.safeString(message, 'id');
1329
+ const result = this.safeValue(message, 'result', {});
1330
+ const ticker = this.parseWsTicker(result, 'future');
1331
+ client.resolve(ticker, messageHash);
1332
+ }
1156
1333
  handleBidsAsks(client, message) {
1157
1334
  //
1158
1335
  // arrives one symbol dict or array of symbol dicts
@@ -1459,33 +1636,52 @@ class binance extends binance$1 {
1459
1636
  * @name binance#fetchBalanceWs
1460
1637
  * @description fetch balance and get the amount of funds available for trading or funds locked in orders
1461
1638
  * @see https://binance-docs.github.io/apidocs/websocket_api/en/#account-information-user_data
1639
+ * @see https://binance-docs.github.io/apidocs/futures/en/#account-information-user_data
1640
+ * @see https://binance-docs.github.io/apidocs/futures/en/#futures-account-balance-user_data
1462
1641
  * @param {object} [params] extra parameters specific to the exchange API endpoint
1463
1642
  * @param {string|undefined} [params.type] 'future', 'delivery', 'savings', 'funding', or 'spot'
1464
1643
  * @param {string|undefined} [params.marginMode] 'cross' or 'isolated', for margin trading, uses this.options.defaultMarginMode if not passed, defaults to undefined/None/null
1465
1644
  * @param {string[]|undefined} [params.symbols] unified market symbols, only used in isolated margin mode
1645
+ * @param {string|undefined} [params.method] method to use. Can be account.balance or account.status
1466
1646
  * @returns {object} a [balance structure]{@link https://docs.ccxt.com/#/?id=balance-structure}
1467
1647
  */
1468
1648
  await this.loadMarkets();
1469
- const url = this.urls['api']['ws']['ws'];
1649
+ const type = this.getMarketType('fetchBalanceWs', undefined, params);
1650
+ if (type !== 'spot' && type !== 'future') {
1651
+ throw new errors.BadRequest(this.id + ' fetchBalanceWs only supports spot or swap markets');
1652
+ }
1653
+ const url = this.urls['api']['ws']['ws-api'][type];
1470
1654
  const requestId = this.requestId(url);
1471
1655
  const messageHash = requestId.toString();
1472
1656
  let returnRateLimits = false;
1473
- [returnRateLimits, params] = this.handleOptionAndParams(params, 'createOrderWs', 'returnRateLimits', false);
1657
+ [returnRateLimits, params] = this.handleOptionAndParams(params, 'fetchBalanceWs', 'returnRateLimits', false);
1474
1658
  const payload = {
1475
1659
  'returnRateLimits': returnRateLimits,
1476
1660
  };
1661
+ let method = undefined;
1662
+ [method, params] = this.handleOptionAndParams(params, 'fetchBalanceWs', 'method', 'account.status');
1477
1663
  const message = {
1478
1664
  'id': messageHash,
1479
- 'method': 'account.status',
1665
+ 'method': method,
1480
1666
  'params': this.signParams(this.extend(payload, params)),
1481
1667
  };
1482
1668
  const subscription = {
1483
- 'method': this.handleBalanceWs,
1669
+ 'method': (method === 'account.status') ? this.handleAccountStatusWs : this.handleBalanceWs,
1484
1670
  };
1485
1671
  return await this.watch(url, messageHash, message, messageHash, subscription);
1486
1672
  }
1487
1673
  handleBalanceWs(client, message) {
1488
1674
  //
1675
+ //
1676
+ const messageHash = this.safeString(message, 'id');
1677
+ const result = this.safeDict(message, 'result', {});
1678
+ const rawBalance = this.safeList(result, 0, []);
1679
+ const parsedBalances = this.parseBalanceCustom(rawBalance);
1680
+ client.resolve(parsedBalances, messageHash);
1681
+ }
1682
+ handleAccountStatusWs(client, message) {
1683
+ //
1684
+ // spot
1489
1685
  // {
1490
1686
  // "id": "605a6d20-6588-4cb9-afa0-b0ab087507ba",
1491
1687
  // "status": 200,
@@ -1528,12 +1724,105 @@ class binance extends binance$1 {
1528
1724
  // ]
1529
1725
  // }
1530
1726
  // }
1727
+ // swap
1531
1728
  //
1532
1729
  const messageHash = this.safeString(message, 'id');
1533
- const result = this.safeValue(message, 'result', {});
1534
- const parsedBalances = this.parseBalance(result);
1730
+ const result = this.safeDict(message, 'result', {});
1731
+ const parsedBalances = this.parseBalanceCustom(result);
1535
1732
  client.resolve(parsedBalances, messageHash);
1536
1733
  }
1734
+ async fetchPositionWs(symbol, params = {}) {
1735
+ /**
1736
+ * @method
1737
+ * @name binance#fetchPositionWs
1738
+ * @see https://binance-docs.github.io/apidocs/futures/en/#position-information-user_data
1739
+ * @description fetch data on an open position
1740
+ * @param {string} symbol unified market symbol of the market the position is held in
1741
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1742
+ * @returns {object} a [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
1743
+ */
1744
+ return await this.fetchPositionsWs([symbol], params);
1745
+ }
1746
+ async fetchPositionsWs(symbols = undefined, params = {}) {
1747
+ /**
1748
+ * @method
1749
+ * @name binance#fetchPositionsWs
1750
+ * @description fetch all open positions
1751
+ * @see https://binance-docs.github.io/apidocs/futures/en/#position-information-user_data
1752
+ * @param {string[]} [symbols] list of unified market symbols
1753
+ * @param {object} [params] extra parameters specific to the exchange API endpoint
1754
+ * @param {boolean} [params.returnRateLimits] set to true to return rate limit informations, defaults to false.
1755
+ * @returns {object[]} a list of [position structure]{@link https://docs.ccxt.com/#/?id=position-structure}
1756
+ */
1757
+ await this.loadMarkets();
1758
+ symbols = this.marketSymbols(symbols, 'swap', true, true, true);
1759
+ const url = this.urls['api']['ws']['ws-api']['future'];
1760
+ const requestId = this.requestId(url);
1761
+ const messageHash = requestId.toString();
1762
+ const payload = {};
1763
+ if (symbols !== undefined) {
1764
+ const symbolsLength = symbols.length;
1765
+ if (symbolsLength === 1) {
1766
+ payload['symbol'] = this.marketId(symbols[0]);
1767
+ }
1768
+ }
1769
+ let returnRateLimits = false;
1770
+ [returnRateLimits, params] = this.handleOptionAndParams(params, 'fetchPositionsWs', 'returnRateLimits', false);
1771
+ payload['returnRateLimits'] = returnRateLimits;
1772
+ const message = {
1773
+ 'id': messageHash,
1774
+ 'method': 'account.position',
1775
+ 'params': this.signParams(this.extend(payload, params)),
1776
+ };
1777
+ const subscription = {
1778
+ 'method': this.handlePositionsWs,
1779
+ };
1780
+ const result = await this.watch(url, messageHash, message, messageHash, subscription);
1781
+ return this.filterByArrayPositions(result, 'symbol', symbols, false);
1782
+ }
1783
+ handlePositionsWs(client, message) {
1784
+ //
1785
+ // {
1786
+ // id: '1',
1787
+ // status: 200,
1788
+ // result: [
1789
+ // {
1790
+ // symbol: 'BTCUSDT',
1791
+ // positionAmt: '-0.014',
1792
+ // entryPrice: '42901.1',
1793
+ // breakEvenPrice: '30138.83333142',
1794
+ // markPrice: '71055.98470333',
1795
+ // unRealizedProfit: '-394.16838584',
1796
+ // liquidationPrice: '137032.02272908',
1797
+ // leverage: '123',
1798
+ // maxNotionalValue: '50000',
1799
+ // marginType: 'cross',
1800
+ // isolatedMargin: '0.00000000',
1801
+ // isAutoAddMargin: 'false',
1802
+ // positionSide: 'BOTH',
1803
+ // notional: '-994.78378584',
1804
+ // isolatedWallet: '0',
1805
+ // updateTime: 1708906343111,
1806
+ // isolated: false,
1807
+ // adlQuantile: 2
1808
+ // },
1809
+ // ...
1810
+ // ]
1811
+ // }
1812
+ //
1813
+ //
1814
+ const messageHash = this.safeString(message, 'id');
1815
+ const result = this.safeList(message, 'result', []);
1816
+ const positions = [];
1817
+ for (let i = 0; i < result.length; i++) {
1818
+ const parsed = this.parsePositionRisk(result[i]);
1819
+ const entryPrice = this.safeString(parsed, 'entryPrice');
1820
+ if ((entryPrice !== '0') && (entryPrice !== '0.0') && (entryPrice !== '0.00000000')) {
1821
+ positions.push(parsed);
1822
+ }
1823
+ }
1824
+ client.resolve(positions, messageHash);
1825
+ }
1537
1826
  async watchBalance(params = {}) {
1538
1827
  /**
1539
1828
  * @method
@@ -1565,7 +1854,7 @@ class binance extends binance$1 {
1565
1854
  const client = this.client(url);
1566
1855
  this.setBalanceCache(client, type, isPortfolioMargin);
1567
1856
  this.setPositionsCache(client, type, undefined, isPortfolioMargin);
1568
- const options = this.safeValue(this.options, 'watchBalance');
1857
+ const options = this.safeDict(this.options, 'watchBalance');
1569
1858
  const fetchBalanceSnapshot = this.safeBool(options, 'fetchBalanceSnapshot', false);
1570
1859
  const awaitBalanceSnapshot = this.safeBool(options, 'awaitBalanceSnapshot', true);
1571
1860
  if (fetchBalanceSnapshot && awaitBalanceSnapshot) {
@@ -1633,7 +1922,7 @@ class binance extends binance$1 {
1633
1922
  // }
1634
1923
  // }
1635
1924
  //
1636
- const wallet = this.safeValue(this.options, 'wallet', 'wb'); // cw for cross wallet
1925
+ const wallet = this.safeString(this.options, 'wallet', 'wb'); // cw for cross wallet
1637
1926
  // each account is connected to a different endpoint
1638
1927
  // and has exactly one subscriptionhash which is the account type
1639
1928
  const subscriptions = Object.keys(client.subscriptions);
@@ -1662,8 +1951,8 @@ class binance extends binance$1 {
1662
1951
  this.balance[accountType][code] = account;
1663
1952
  }
1664
1953
  else {
1665
- message = this.safeValue(message, 'a', message);
1666
- const B = this.safeValue(message, 'B');
1954
+ message = this.safeDict(message, 'a', message);
1955
+ const B = this.safeList(message, 'B');
1667
1956
  for (let i = 0; i < B.length; i++) {
1668
1957
  const entry = B[i];
1669
1958
  const currencyId = this.safeString(entry, 'a');
@@ -1681,32 +1970,25 @@ class binance extends binance$1 {
1681
1970
  this.balance[accountType] = this.safeBalance(this.balance[accountType]);
1682
1971
  client.resolve(this.balance[accountType], messageHash);
1683
1972
  }
1684
- checkIsSpot(method, symbol, params = {}) {
1685
- /**
1686
- * @method
1687
- * @ignore
1688
- * @description checks if symbols is a spot market if not throws an error
1689
- * @param {string} method name of the method to be checked
1690
- * @param {string} symbol symbol or marketId of the market to be checked
1691
- */
1692
- if (symbol === undefined) {
1693
- const type = this.safeString(params, 'type', 'spot');
1694
- const defaultType = this.safeString(this.options, 'defaultType', type);
1695
- if (defaultType === 'spot') {
1696
- return;
1697
- }
1698
- throw new errors.BadRequest(this.id + ' ' + method + ' only supports spot markets');
1973
+ getMarketType(method, market, params = {}) {
1974
+ let type = undefined;
1975
+ [type, params] = this.handleMarketTypeAndParams(method, market, params);
1976
+ let subType = undefined;
1977
+ [subType, params] = this.handleSubTypeAndParams(method, market, params);
1978
+ if (this.isLinear(type, subType)) {
1979
+ type = 'future';
1699
1980
  }
1700
- const market = this.market(symbol);
1701
- if (!market['spot']) {
1702
- throw new errors.BadRequest(this.id + ' ' + method + ' only supports spot markets');
1981
+ else if (this.isInverse(type, subType)) {
1982
+ type = 'delivery';
1703
1983
  }
1984
+ return type;
1704
1985
  }
1705
1986
  async createOrderWs(symbol, type, side, amount, price = undefined, params = {}) {
1706
1987
  /**
1707
1988
  * @method
1708
1989
  * @name binance#createOrderWs
1709
1990
  * @see https://binance-docs.github.io/apidocs/websocket_api/en/#place-new-order-trade
1991
+ * @see https://binance-docs.github.io/apidocs/futures/en/#new-order-trade-2
1710
1992
  * @description create a trade order
1711
1993
  * @param {string} symbol unified symbol of the market to create an order in
1712
1994
  * @param {string} type 'market' or 'limit'
@@ -1715,14 +1997,19 @@ class binance extends binance$1 {
1715
1997
  * @param {float|undefined} [price] the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1716
1998
  * @param {object} [params] extra parameters specific to the exchange API endpoint
1717
1999
  * @param {boolean} params.test test order, default false
2000
+ * @param {boolean} params.returnRateLimits set to true to return rate limit information, default false
1718
2001
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1719
2002
  */
1720
2003
  await this.loadMarkets();
1721
- this.checkIsSpot('createOrderWs', symbol, params);
1722
- const url = this.urls['api']['ws']['ws'];
2004
+ const market = this.market(symbol);
2005
+ const marketType = this.getMarketType('createOrderWs', market, params);
2006
+ if (marketType !== 'spot' && marketType !== 'future') {
2007
+ throw new errors.BadRequest(this.id + ' createOrderWs only supports spot or swap markets');
2008
+ }
2009
+ const url = this.urls['api']['ws']['ws-api'][marketType];
1723
2010
  const requestId = this.requestId(url);
1724
2011
  const messageHash = requestId.toString();
1725
- const sor = this.safeValue2(params, 'sor', 'SOR', false);
2012
+ const sor = this.safeBool2(params, 'sor', 'SOR', false);
1726
2013
  params = this.omit(params, 'sor', 'SOR');
1727
2014
  const payload = this.createOrderRequest(symbol, type, side, amount, price, params);
1728
2015
  let returnRateLimits = false;
@@ -1797,7 +2084,7 @@ class binance extends binance$1 {
1797
2084
  // }
1798
2085
  //
1799
2086
  const messageHash = this.safeString(message, 'id');
1800
- const result = this.safeValue(message, 'result', {});
2087
+ const result = this.safeDict(message, 'result', {});
1801
2088
  const order = this.parseOrder(result);
1802
2089
  client.resolve(order, messageHash);
1803
2090
  }
@@ -1840,7 +2127,7 @@ class binance extends binance$1 {
1840
2127
  // }
1841
2128
  //
1842
2129
  const messageHash = this.safeString(message, 'id');
1843
- const result = this.safeValue(message, 'result', []);
2130
+ const result = this.safeList(message, 'result', []);
1844
2131
  const orders = this.parseOrders(result);
1845
2132
  client.resolve(orders, messageHash);
1846
2133
  }
@@ -1850,6 +2137,7 @@ class binance extends binance$1 {
1850
2137
  * @name binance#editOrderWs
1851
2138
  * @description edit a trade order
1852
2139
  * @see https://binance-docs.github.io/apidocs/websocket_api/en/#cancel-and-replace-order-trade
2140
+ * @see https://binance-docs.github.io/apidocs/futures/en/#modify-order-trade-2
1853
2141
  * @param {string} id order id
1854
2142
  * @param {string} symbol unified symbol of the market to create an order in
1855
2143
  * @param {string} type 'market' or 'limit'
@@ -1860,17 +2148,27 @@ class binance extends binance$1 {
1860
2148
  * @returns {object} an [order structure]{@link https://docs.ccxt.com/#/?id=order-structure}
1861
2149
  */
1862
2150
  await this.loadMarkets();
1863
- this.checkIsSpot('editOrderWs', symbol, params);
1864
- const url = this.urls['api']['ws']['ws'];
2151
+ const market = this.market(symbol);
2152
+ const marketType = this.getMarketType('editOrderWs', market, params);
2153
+ if (marketType !== 'spot' && marketType !== 'future') {
2154
+ throw new errors.BadRequest(this.id + ' editOrderWs only supports spot or swap markets');
2155
+ }
2156
+ const url = this.urls['api']['ws']['ws-api'][marketType];
1865
2157
  const requestId = this.requestId(url);
1866
2158
  const messageHash = requestId.toString();
1867
- const payload = this.editSpotOrderRequest(id, symbol, type, side, amount, price, params);
2159
+ let payload = undefined;
2160
+ if (marketType === 'spot') {
2161
+ payload = this.editSpotOrderRequest(id, symbol, type, side, amount, price, params);
2162
+ }
2163
+ else if (marketType === 'future') {
2164
+ payload = this.editContractOrderRequest(id, symbol, type, side, amount, price, params);
2165
+ }
1868
2166
  let returnRateLimits = false;
1869
2167
  [returnRateLimits, params] = this.handleOptionAndParams(params, 'editOrderWs', 'returnRateLimits', false);
1870
2168
  payload['returnRateLimits'] = returnRateLimits;
1871
2169
  const message = {
1872
2170
  'id': messageHash,
1873
- 'method': 'order.cancelReplace',
2171
+ 'method': (marketType === 'future') ? 'order.modify' : 'order.cancelReplace',
1874
2172
  'params': this.signParams(this.extend(payload, params)),
1875
2173
  };
1876
2174
  const subscription = {
@@ -1880,6 +2178,7 @@ class binance extends binance$1 {
1880
2178
  }
1881
2179
  handleEditOrderWs(client, message) {
1882
2180
  //
2181
+ // spot
1883
2182
  // {
1884
2183
  // "id": 1,
1885
2184
  // "status": 200,
@@ -1944,11 +2243,48 @@ class binance extends binance$1 {
1944
2243
  // }
1945
2244
  // ]
1946
2245
  // }
2246
+ // swap
2247
+ // {
2248
+ // "id":"1",
2249
+ // "status":200,
2250
+ // "result":{
2251
+ // "orderId":667061487,
2252
+ // "symbol":"LTCUSDT",
2253
+ // "status":"NEW",
2254
+ // "clientOrderId":"x-xcKtGhcu91a74c818749ee42c0f70",
2255
+ // "price":"82.00",
2256
+ // "avgPrice":"0.00",
2257
+ // "origQty":"1.000",
2258
+ // "executedQty":"0.000",
2259
+ // "cumQty":"0.000",
2260
+ // "cumQuote":"0.00000",
2261
+ // "timeInForce":"GTC",
2262
+ // "type":"LIMIT",
2263
+ // "reduceOnly":false,
2264
+ // "closePosition":false,
2265
+ // "side":"BUY",
2266
+ // "positionSide":"BOTH",
2267
+ // "stopPrice":"0.00",
2268
+ // "workingType":"CONTRACT_PRICE",
2269
+ // "priceProtect":false,
2270
+ // "origType":"LIMIT",
2271
+ // "priceMatch":"NONE",
2272
+ // "selfTradePreventionMode":"NONE",
2273
+ // "goodTillDate":0,
2274
+ // "updateTime":1712918927511
2275
+ // }
2276
+ // }
1947
2277
  //
1948
2278
  const messageHash = this.safeString(message, 'id');
1949
- const result = this.safeValue(message, 'result', {});
1950
- const rawOrder = this.safeValue(result, 'newOrderResponse', {});
1951
- const order = this.parseOrder(rawOrder);
2279
+ const result = this.safeDict(message, 'result', {});
2280
+ const newSpotOrder = this.safeDict(result, 'newOrderResponse');
2281
+ let order = undefined;
2282
+ if (newSpotOrder !== undefined) {
2283
+ order = this.parseOrder(newSpotOrder);
2284
+ }
2285
+ else {
2286
+ order = this.parseOrder(result);
2287
+ }
1952
2288
  client.resolve(order, messageHash);
1953
2289
  }
1954
2290
  async cancelOrderWs(id, symbol = undefined, params = {}) {
@@ -1956,6 +2292,7 @@ class binance extends binance$1 {
1956
2292
  * @method
1957
2293
  * @name binance#cancelOrderWs
1958
2294
  * @see https://binance-docs.github.io/apidocs/websocket_api/en/#cancel-order-trade
2295
+ * @see https://binance-docs.github.io/apidocs/futures/en/#cancel-order-trade-2
1959
2296
  * @description cancel multiple orders
1960
2297
  * @param {string} id order id
1961
2298
  * @param {string} symbol unified market symbol, default is undefined
@@ -1967,8 +2304,9 @@ class binance extends binance$1 {
1967
2304
  if (symbol === undefined) {
1968
2305
  throw new errors.BadRequest(this.id + ' cancelOrderWs requires a symbol');
1969
2306
  }
1970
- this.checkIsSpot('cancelOrderWs', symbol, params);
1971
- const url = this.urls['api']['ws']['ws'];
2307
+ const market = this.market(symbol);
2308
+ const type = this.getMarketType('cancelOrderWs', market, params);
2309
+ const url = this.urls['api']['ws']['ws-api'][type];
1972
2310
  const requestId = this.requestId(url);
1973
2311
  const messageHash = requestId.toString();
1974
2312
  let returnRateLimits = false;
@@ -1977,7 +2315,7 @@ class binance extends binance$1 {
1977
2315
  'symbol': this.marketId(symbol),
1978
2316
  'returnRateLimits': returnRateLimits,
1979
2317
  };
1980
- const clientOrderId = this.safeValue2(params, 'origClientOrderId', 'clientOrderId');
2318
+ const clientOrderId = this.safeString2(params, 'origClientOrderId', 'clientOrderId');
1981
2319
  if (clientOrderId !== undefined) {
1982
2320
  payload['origClientOrderId'] = clientOrderId;
1983
2321
  }
@@ -2006,7 +2344,12 @@ class binance extends binance$1 {
2006
2344
  * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2007
2345
  */
2008
2346
  await this.loadMarkets();
2009
- const url = this.urls['api']['ws']['ws'];
2347
+ const market = this.market(symbol);
2348
+ const type = this.getMarketType('cancelAllOrdersWs', market, params);
2349
+ if (type !== 'spot' && type !== 'future') {
2350
+ throw new errors.BadRequest(this.id + ' cancelAllOrdersWs only supports spot or swap markets');
2351
+ }
2352
+ const url = this.urls['api']['ws']['ws-api'][type];
2010
2353
  const requestId = this.requestId(url);
2011
2354
  const messageHash = requestId.toString();
2012
2355
  let returnRateLimits = false;
@@ -2030,6 +2373,7 @@ class binance extends binance$1 {
2030
2373
  * @method
2031
2374
  * @name binance#fetchOrderWs
2032
2375
  * @see https://binance-docs.github.io/apidocs/websocket_api/en/#query-order-user_data
2376
+ * @see https://binance-docs.github.io/apidocs/futures/en/#query-order-user_data-2
2033
2377
  * @description fetches information on an order made by the user
2034
2378
  * @param {string} symbol unified symbol of the market the order was made in
2035
2379
  * @param {object} params extra parameters specific to the exchange API endpoint
@@ -2039,8 +2383,12 @@ class binance extends binance$1 {
2039
2383
  if (symbol === undefined) {
2040
2384
  throw new errors.BadRequest(this.id + ' cancelOrderWs requires a symbol');
2041
2385
  }
2042
- this.checkIsSpot('fetchOrderWs', symbol, params);
2043
- const url = this.urls['api']['ws']['ws'];
2386
+ const market = this.market(symbol);
2387
+ const type = this.getMarketType('fetchOrderWs', market, params);
2388
+ if (type !== 'spot' && type !== 'future') {
2389
+ throw new errors.BadRequest(this.id + ' fetchOrderWs only supports spot or swap markets');
2390
+ }
2391
+ const url = this.urls['api']['ws']['ws-api'][type];
2044
2392
  const requestId = this.requestId(url);
2045
2393
  const messageHash = requestId.toString();
2046
2394
  let returnRateLimits = false;
@@ -2049,7 +2397,7 @@ class binance extends binance$1 {
2049
2397
  'symbol': this.marketId(symbol),
2050
2398
  'returnRateLimits': returnRateLimits,
2051
2399
  };
2052
- const clientOrderId = this.safeValue2(params, 'origClientOrderId', 'clientOrderId');
2400
+ const clientOrderId = this.safeString2(params, 'origClientOrderId', 'clientOrderId');
2053
2401
  if (clientOrderId !== undefined) {
2054
2402
  payload['origClientOrderId'] = clientOrderId;
2055
2403
  }
@@ -2086,8 +2434,12 @@ class binance extends binance$1 {
2086
2434
  if (symbol === undefined) {
2087
2435
  throw new errors.BadRequest(this.id + ' fetchOrdersWs requires a symbol');
2088
2436
  }
2089
- this.checkIsSpot('fetchOrdersWs', symbol, params);
2090
- const url = this.urls['api']['ws']['ws'];
2437
+ const market = this.market(symbol);
2438
+ const type = this.getMarketType('fetchOrdersWs', market, params);
2439
+ if (type !== 'spot') {
2440
+ throw new errors.BadRequest(this.id + ' fetchOrdersWs only supports spot markets');
2441
+ }
2442
+ const url = this.urls['api']['ws']['ws-api'][type];
2091
2443
  const requestId = this.requestId(url);
2092
2444
  const messageHash = requestId.toString();
2093
2445
  let returnRateLimits = false;
@@ -2142,8 +2494,12 @@ class binance extends binance$1 {
2142
2494
  * @returns {object[]} a list of [order structures]{@link https://docs.ccxt.com/#/?id=order-structure}
2143
2495
  */
2144
2496
  await this.loadMarkets();
2145
- this.checkIsSpot('fetchOpenOrdersWs', symbol);
2146
- const url = this.urls['api']['ws']['ws'];
2497
+ const market = this.market(symbol);
2498
+ const type = this.getMarketType('fetchOpenOrdersWs', market, params);
2499
+ if (type !== 'spot' && type !== 'future') {
2500
+ throw new errors.BadRequest(this.id + ' fetchOpenOrdersWs only supports spot or swap markets');
2501
+ }
2502
+ const url = this.urls['api']['ws']['ws-api'][type];
2147
2503
  const requestId = this.requestId(url);
2148
2504
  const messageHash = requestId.toString();
2149
2505
  let returnRateLimits = false;
@@ -2359,7 +2715,7 @@ class binance extends binance$1 {
2359
2715
  'type': type,
2360
2716
  'timeInForce': timeInForce,
2361
2717
  'postOnly': undefined,
2362
- 'reduceOnly': this.safeValue(order, 'R'),
2718
+ 'reduceOnly': this.safeBool(order, 'R'),
2363
2719
  'side': side,
2364
2720
  'price': price,
2365
2721
  'stopPrice': stopPrice,
@@ -2458,7 +2814,7 @@ class binance extends binance$1 {
2458
2814
  //
2459
2815
  const e = this.safeString(message, 'e');
2460
2816
  if (e === 'ORDER_TRADE_UPDATE') {
2461
- message = this.safeValue(message, 'o', message);
2817
+ message = this.safeDict(message, 'o', message);
2462
2818
  }
2463
2819
  this.handleMyTrade(client, message);
2464
2820
  this.handleOrder(client, message);
@@ -2607,8 +2963,8 @@ class binance extends binance$1 {
2607
2963
  this.positions[accountType] = new Cache.ArrayCacheBySymbolBySide();
2608
2964
  }
2609
2965
  const cache = this.positions[accountType];
2610
- const data = this.safeValue(message, 'a', {});
2611
- const rawPositions = this.safeValue(data, 'P', []);
2966
+ const data = this.safeDict(message, 'a', {});
2967
+ const rawPositions = this.safeList(data, 'P', []);
2612
2968
  const newPositions = [];
2613
2969
  for (let i = 0; i < rawPositions.length; i++) {
2614
2970
  const rawPosition = rawPositions[i];
@@ -2705,8 +3061,12 @@ class binance extends binance$1 {
2705
3061
  if (symbol === undefined) {
2706
3062
  throw new errors.BadRequest(this.id + ' fetchMyTradesWs requires a symbol');
2707
3063
  }
2708
- this.checkIsSpot('fetchMyTradesWs', symbol, params);
2709
- const url = this.urls['api']['ws']['ws'];
3064
+ const market = this.market(symbol);
3065
+ const type = this.getMarketType('fetchMyTradesWs', market, params);
3066
+ if (type !== 'spot' && type !== 'future') {
3067
+ throw new errors.BadRequest(this.id + ' fetchMyTradesWs does not support ' + type + ' markets');
3068
+ }
3069
+ const url = this.urls['api']['ws']['ws-api'][type];
2710
3070
  const requestId = this.requestId(url);
2711
3071
  const messageHash = requestId.toString();
2712
3072
  let returnRateLimits = false;
@@ -2755,8 +3115,12 @@ class binance extends binance$1 {
2755
3115
  if (symbol === undefined) {
2756
3116
  throw new errors.BadRequest(this.id + ' fetchTradesWs () requires a symbol argument');
2757
3117
  }
2758
- this.checkIsSpot('fetchTradesWs', symbol, params);
2759
- const url = this.urls['api']['ws']['ws'];
3118
+ const market = this.market(symbol);
3119
+ const type = this.getMarketType('fetchTradesWs', market, params);
3120
+ if (type !== 'spot' && type !== 'future') {
3121
+ throw new errors.BadRequest(this.id + ' fetchTradesWs does not support ' + type + ' markets');
3122
+ }
3123
+ const url = this.urls['api']['ws']['ws-api'][type];
2760
3124
  const requestId = this.requestId(url);
2761
3125
  const messageHash = requestId.toString();
2762
3126
  let returnRateLimits = false;
@@ -2826,7 +3190,7 @@ class binance extends binance$1 {
2826
3190
  // }
2827
3191
  //
2828
3192
  const messageHash = this.safeString(message, 'id');
2829
- const result = this.safeValue(message, 'result', []);
3193
+ const result = this.safeList(message, 'result', []);
2830
3194
  const trades = this.parseTrades(result);
2831
3195
  client.resolve(trades, messageHash);
2832
3196
  }
@@ -2891,7 +3255,7 @@ class binance extends binance$1 {
2891
3255
  if (executionType === 'TRADE') {
2892
3256
  const trade = this.parseWsTrade(message);
2893
3257
  const orderId = this.safeString(trade, 'order');
2894
- let tradeFee = this.safeValue(trade, 'fee', {});
3258
+ let tradeFee = this.safeDict(trade, 'fee', {});
2895
3259
  tradeFee = this.extend({}, tradeFee);
2896
3260
  const symbol = this.safeString(trade, 'symbol');
2897
3261
  if (orderId !== undefined && tradeFee !== undefined && symbol !== undefined) {
@@ -2935,7 +3299,7 @@ class binance extends binance$1 {
2935
3299
  order['fee'] = tradeFee;
2936
3300
  }
2937
3301
  // save this trade in the order
2938
- const orderTrades = this.safeValue(order, 'trades', []);
3302
+ const orderTrades = this.safeList(order, 'trades', []);
2939
3303
  orderTrades.push(trade);
2940
3304
  order['trades'] = orderTrades;
2941
3305
  // don't append twice cause it breaks newUpdates mode
@@ -3005,7 +3369,7 @@ class binance extends binance$1 {
3005
3369
  //
3006
3370
  const id = this.safeString(message, 'id');
3007
3371
  let rejected = false;
3008
- const error = this.safeValue(message, 'error', {});
3372
+ const error = this.safeDict(message, 'error', {});
3009
3373
  const code = this.safeInteger(error, 'code');
3010
3374
  const msg = this.safeString(error, 'msg');
3011
3375
  try {