ccxt 4.3.4__py2.py3-none-any.whl → 4.3.5__py2.py3-none-any.whl

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.

Potentially problematic release.


This version of ccxt might be problematic. Click here for more details.

ccxt/pro/binance.py CHANGED
@@ -46,9 +46,14 @@ class binance(ccxt.async_support.binance):
46
46
  'fetchMarketsWs': False,
47
47
  'fetchMyTradesWs': True,
48
48
  'fetchOHLCVWs': True,
49
+ 'fetchOrderBookWs': True,
49
50
  'fetchOpenOrdersWs': True,
50
51
  'fetchOrderWs': True,
51
52
  'fetchOrdersWs': True,
53
+ 'fetchPositionWs': True,
54
+ 'fetchPositionForSymbolWs': True,
55
+ 'fetchPositionsWs': True,
56
+ 'fetchTickerWs': True,
52
57
  'fetchTradesWs': True,
53
58
  'fetchTradingFeesWs': False,
54
59
  'fetchWithdrawalsWs': False,
@@ -60,7 +65,10 @@ class binance(ccxt.async_support.binance):
60
65
  'margin': 'wss://testnet.binance.vision/ws',
61
66
  'future': 'wss://fstream.binancefuture.com/ws',
62
67
  'delivery': 'wss://dstream.binancefuture.com/ws',
63
- 'ws': 'wss://testnet.binance.vision/ws-api/v3',
68
+ 'ws-api': {
69
+ 'spot': 'wss://testnet.binance.vision/ws-api/v3',
70
+ 'future': 'wss://testnet.binancefuture.com/ws-fapi/v1',
71
+ },
64
72
  },
65
73
  },
66
74
  'api': {
@@ -69,7 +77,10 @@ class binance(ccxt.async_support.binance):
69
77
  'margin': 'wss://stream.binance.com:9443/ws',
70
78
  'future': 'wss://fstream.binance.com/ws',
71
79
  'delivery': 'wss://dstream.binance.com/ws',
72
- 'ws': 'wss://ws-api.binance.com:443/ws-api/v3',
80
+ 'ws-api': {
81
+ 'spot': 'wss://ws-api.binance.com:443/ws-api/v3',
82
+ 'future': 'wss://ws-fapi.binance.com/ws-fapi/v1',
83
+ },
73
84
  'papi': 'wss://fstream.binance.com/pm/ws',
74
85
  },
75
86
  },
@@ -270,6 +281,75 @@ class binance(ccxt.async_support.binance):
270
281
  orderbook = await self.watch_multiple(url, messageHashes, message, messageHashes, subscription)
271
282
  return orderbook.limit()
272
283
 
284
+ async def fetch_order_book_ws(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
285
+ """
286
+ fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
287
+ :see: https://binance-docs.github.io/apidocs/futures/en/#order-book-2
288
+ :param str symbol: unified symbol of the market to fetch the order book for
289
+ :param int [limit]: the maximum amount of order book entries to return
290
+ :param dict [params]: extra parameters specific to the exchange API endpoint
291
+ :returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
292
+ """
293
+ await self.load_markets()
294
+ market = self.market(symbol)
295
+ payload = {
296
+ 'symbol': market['id'],
297
+ }
298
+ if limit is not None:
299
+ payload['limit'] = limit
300
+ marketType = self.get_market_type('fetchOrderBookWs', market, params)
301
+ if marketType != 'future':
302
+ raise BadRequest(self.id + ' fetchOrderBookWs only supports swap markets')
303
+ url = self.urls['api']['ws']['ws-api'][marketType]
304
+ requestId = self.request_id(url)
305
+ messageHash = str(requestId)
306
+ returnRateLimits = False
307
+ returnRateLimits, params = self.handle_option_and_params(params, 'createOrderWs', 'returnRateLimits', False)
308
+ payload['returnRateLimits'] = returnRateLimits
309
+ params = self.omit(params, 'test')
310
+ message = {
311
+ 'id': messageHash,
312
+ 'method': 'depth',
313
+ 'params': self.sign_params(self.extend(payload, params)),
314
+ }
315
+ subscription = {
316
+ 'method': self.handle_fetch_order_book,
317
+ }
318
+ orderbook = await self.watch(url, messageHash, message, messageHash, subscription)
319
+ orderbook['symbol'] = market['symbol']
320
+ return orderbook
321
+
322
+ def handle_fetch_order_book(self, client: Client, message):
323
+ #
324
+ # {
325
+ # "id":"51e2affb-0aba-4821-ba75-f2625006eb43",
326
+ # "status":200,
327
+ # "result":{
328
+ # "lastUpdateId":1027024,
329
+ # "E":1589436922972,
330
+ # "T":1589436922959,
331
+ # "bids":[
332
+ # [
333
+ # "4.00000000",
334
+ # "431.00000000"
335
+ # ]
336
+ # ],
337
+ # "asks":[
338
+ # [
339
+ # "4.00000200",
340
+ # "12.00000000"
341
+ # ]
342
+ # ]
343
+ # }
344
+ # }
345
+ #
346
+ messageHash = self.safe_string(message, 'id')
347
+ result = self.safe_dict(message, 'result')
348
+ timestamp = self.safe_integer(result, 'T')
349
+ orderbook = self.parse_order_book(result, None, timestamp)
350
+ orderbook['nonce'] = self.safe_integer_2(result, 'lastUpdateId', 'u')
351
+ client.resolve(orderbook, messageHash)
352
+
273
353
  async def fetch_order_book_snapshot(self, client, message, subscription):
274
354
  name = self.safe_string(subscription, 'name')
275
355
  symbol = self.safe_string(subscription, 'symbol')
@@ -794,6 +874,44 @@ class binance(ccxt.async_support.binance):
794
874
  stored.append(parsed)
795
875
  client.resolve(stored, messageHash)
796
876
 
877
+ async def fetch_ticker_ws(self, symbol: str, params={}) -> Ticker:
878
+ """
879
+ fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
880
+ :see: https://binance-docs.github.io/apidocs/voptions/en/#24hr-ticker-price-change-statistics
881
+ :param str symbol: unified symbol of the market to fetch the ticker for
882
+ :param dict [params]: extra parameters specific to the exchange API endpoint
883
+ :param str [params.method]: method to use can be ticker.price or ticker.book
884
+ :param boolean [params.returnRateLimits]: return the rate limits for the exchange
885
+ :returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
886
+ """
887
+ await self.load_markets()
888
+ market = self.market(symbol)
889
+ payload = {
890
+ 'symbol': market['id'],
891
+ }
892
+ type = self.get_market_type('fetchTickerWs', market, params)
893
+ if type != 'future':
894
+ raise BadRequest(self.id + ' fetchTickerWs only supports swap markets')
895
+ url = self.urls['api']['ws']['ws-api'][type]
896
+ requestId = self.request_id(url)
897
+ messageHash = str(requestId)
898
+ subscription = {
899
+ 'method': self.handle_ticker_ws,
900
+ }
901
+ returnRateLimits = False
902
+ returnRateLimits, params = self.handle_option_and_params(params, 'fetchTickerWs', 'returnRateLimits', False)
903
+ payload['returnRateLimits'] = returnRateLimits
904
+ params = self.omit(params, 'test')
905
+ method = None
906
+ method, params = self.handle_option_and_params(params, 'fetchTickerWs', 'method', 'ticker.book')
907
+ message = {
908
+ 'id': messageHash,
909
+ 'method': method,
910
+ 'params': self.sign_params(self.extend(payload, params)),
911
+ }
912
+ ticker = await self.watch(url, messageHash, message, messageHash, subscription)
913
+ return ticker
914
+
797
915
  async def fetch_ohlcv_ws(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
798
916
  """
799
917
  :see: https://binance-docs.github.io/apidocs/websocket_api/en/#klines
@@ -810,8 +928,11 @@ class binance(ccxt.async_support.binance):
810
928
  :returns int[][]: A list of candles ordered, open, high, low, close, volume
811
929
  """
812
930
  await self.load_markets()
813
- self.check_is_spot('fetchOHLCVWs', symbol, params)
814
- url = self.urls['api']['ws']['ws']
931
+ market = self.market(symbol)
932
+ marketType = self.get_market_type('fetchOHLCVWs', market, params)
933
+ if marketType != 'spot' and marketType != 'future':
934
+ raise BadRequest(self.id + ' fetchOHLCVWs only supports spot or swap markets')
935
+ url = self.urls['api']['ws']['ws-api'][marketType]
815
936
  requestId = self.request_id(url)
816
937
  messageHash = str(requestId)
817
938
  returnRateLimits = False
@@ -1022,6 +1143,22 @@ class binance(ccxt.async_support.binance):
1022
1143
  # "v": "2109995.32000000",
1023
1144
  # "q": "2019254.05788000"
1024
1145
  # }
1146
+ # fetchTickerWs
1147
+ # {
1148
+ # "symbol":"BTCUSDT",
1149
+ # "price":"72606.70",
1150
+ # "time":1712526204284
1151
+ # }
1152
+ # fetchTickerWs - ticker.book
1153
+ # {
1154
+ # "lastUpdateId":1027024,
1155
+ # "symbol":"BTCUSDT",
1156
+ # "bidPrice":"4.00000000",
1157
+ # "bidQty":"431.00000000",
1158
+ # "askPrice":"4.00000200",
1159
+ # "askQty":"9.00000000",
1160
+ # "time":1589437530011,
1161
+ # }
1025
1162
  #
1026
1163
  event = self.safe_string(message, 'e', 'bookTicker')
1027
1164
  if event == '24hrTicker':
@@ -1029,24 +1166,24 @@ class binance(ccxt.async_support.binance):
1029
1166
  timestamp = None
1030
1167
  if event == 'bookTicker':
1031
1168
  # take the event timestamp, if available, for spot tickers it is not
1032
- timestamp = self.safe_integer(message, 'E')
1169
+ timestamp = self.safe_integer_2(message, 'E', 'time')
1033
1170
  else:
1034
1171
  # take the timestamp of the closing price for candlestick streams
1035
- timestamp = self.safe_integer_2(message, 'C', 'E')
1036
- marketId = self.safe_string(message, 's')
1172
+ timestamp = self.safe_integer_n(message, ['C', 'E', 'time'])
1173
+ marketId = self.safe_string_2(message, 's', 'symbol')
1037
1174
  symbol = self.safe_symbol(marketId, None, None, marketType)
1038
1175
  market = self.safe_market(marketId, None, None, marketType)
1039
- last = self.safe_string(message, 'c')
1176
+ last = self.safe_string_2(message, 'c', 'price')
1040
1177
  return self.safe_ticker({
1041
1178
  'symbol': symbol,
1042
1179
  'timestamp': timestamp,
1043
1180
  'datetime': self.iso8601(timestamp),
1044
1181
  'high': self.safe_string(message, 'h'),
1045
1182
  'low': self.safe_string(message, 'l'),
1046
- 'bid': self.safe_string(message, 'b'),
1047
- 'bidVolume': self.safe_string(message, 'B'),
1048
- 'ask': self.safe_string(message, 'a'),
1049
- 'askVolume': self.safe_string(message, 'A'),
1183
+ 'bid': self.safe_string_2(message, 'b', 'bidPrice'),
1184
+ 'bidVolume': self.safe_string_2(message, 'B', 'bidQty'),
1185
+ 'ask': self.safe_string_2(message, 'a', 'askPrice'),
1186
+ 'askVolume': self.safe_string_2(message, 'A', 'askQty'),
1050
1187
  'vwap': self.safe_string(message, 'w'),
1051
1188
  'open': self.safe_string(message, 'o'),
1052
1189
  'close': last,
@@ -1060,6 +1197,38 @@ class binance(ccxt.async_support.binance):
1060
1197
  'info': message,
1061
1198
  }, market)
1062
1199
 
1200
+ def handle_ticker_ws(self, client: Client, message):
1201
+ #
1202
+ # ticker.price
1203
+ # {
1204
+ # "id":"1",
1205
+ # "status":200,
1206
+ # "result":{
1207
+ # "symbol":"BTCUSDT",
1208
+ # "price":"73178.50",
1209
+ # "time":1712527052374
1210
+ # }
1211
+ # }
1212
+ # ticker.book
1213
+ # {
1214
+ # "id":"9d32157c-a556-4d27-9866-66760a174b57",
1215
+ # "status":200,
1216
+ # "result":{
1217
+ # "lastUpdateId":1027024,
1218
+ # "symbol":"BTCUSDT",
1219
+ # "bidPrice":"4.00000000",
1220
+ # "bidQty":"431.00000000",
1221
+ # "askPrice":"4.00000200",
1222
+ # "askQty":"9.00000000",
1223
+ # "time":1589437530011 # Transaction time
1224
+ # }
1225
+ # }
1226
+ #
1227
+ messageHash = self.safe_string(message, 'id')
1228
+ result = self.safe_value(message, 'result', {})
1229
+ ticker = self.parse_ws_ticker(result, 'future')
1230
+ client.resolve(ticker, messageHash)
1231
+
1063
1232
  def handle_bids_asks(self, client: Client, message):
1064
1233
  #
1065
1234
  # arrives one symbol dict or array of symbol dicts
@@ -1317,33 +1486,51 @@ class binance(ccxt.async_support.binance):
1317
1486
  """
1318
1487
  fetch balance and get the amount of funds available for trading or funds locked in orders
1319
1488
  :see: https://binance-docs.github.io/apidocs/websocket_api/en/#account-information-user_data
1489
+ :see: https://binance-docs.github.io/apidocs/futures/en/#account-information-user_data
1490
+ :see: https://binance-docs.github.io/apidocs/futures/en/#futures-account-balance-user_data
1320
1491
  :param dict [params]: extra parameters specific to the exchange API endpoint
1321
1492
  :param str|None [params.type]: 'future', 'delivery', 'savings', 'funding', or 'spot'
1322
1493
  :param str|None [params.marginMode]: 'cross' or 'isolated', for margin trading, uses self.options.defaultMarginMode if not passed, defaults to None/None/None
1323
1494
  :param str[]|None [params.symbols]: unified market symbols, only used in isolated margin mode
1495
+ :param str|None [params.method]: method to use. Can be account.balance or account.status
1324
1496
  :returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
1325
1497
  """
1326
1498
  await self.load_markets()
1327
- url = self.urls['api']['ws']['ws']
1499
+ type = self.get_market_type('fetchBalanceWs', None, params)
1500
+ if type != 'spot' and type != 'future':
1501
+ raise BadRequest(self.id + ' fetchBalanceWs only supports spot or swap markets')
1502
+ url = self.urls['api']['ws']['ws-api'][type]
1328
1503
  requestId = self.request_id(url)
1329
1504
  messageHash = str(requestId)
1330
1505
  returnRateLimits = False
1331
- returnRateLimits, params = self.handle_option_and_params(params, 'createOrderWs', 'returnRateLimits', False)
1506
+ returnRateLimits, params = self.handle_option_and_params(params, 'fetchBalanceWs', 'returnRateLimits', False)
1332
1507
  payload = {
1333
1508
  'returnRateLimits': returnRateLimits,
1334
1509
  }
1510
+ method = None
1511
+ method, params = self.handle_option_and_params(params, 'fetchBalanceWs', 'method', 'account.status')
1335
1512
  message = {
1336
1513
  'id': messageHash,
1337
- 'method': 'account.status',
1514
+ 'method': method,
1338
1515
  'params': self.sign_params(self.extend(payload, params)),
1339
1516
  }
1340
1517
  subscription = {
1341
- 'method': self.handle_balance_ws,
1518
+ 'method': self.handle_account_status_ws if (method == 'account.status') else self.handle_balance_ws,
1342
1519
  }
1343
1520
  return await self.watch(url, messageHash, message, messageHash, subscription)
1344
1521
 
1345
1522
  def handle_balance_ws(self, client: Client, message):
1346
1523
  #
1524
+ #
1525
+ messageHash = self.safe_string(message, 'id')
1526
+ result = self.safe_dict(message, 'result', {})
1527
+ rawBalance = self.safe_list(result, 0, [])
1528
+ parsedBalances = self.parseBalanceCustom(rawBalance)
1529
+ client.resolve(parsedBalances, messageHash)
1530
+
1531
+ def handle_account_status_ws(self, client: Client, message):
1532
+ #
1533
+ # spot
1347
1534
  # {
1348
1535
  # "id": "605a6d20-6588-4cb9-afa0-b0ab087507ba",
1349
1536
  # "status": 200,
@@ -1386,12 +1573,97 @@ class binance(ccxt.async_support.binance):
1386
1573
  # ]
1387
1574
  # }
1388
1575
  # }
1576
+ # swap
1389
1577
  #
1390
1578
  messageHash = self.safe_string(message, 'id')
1391
- result = self.safe_value(message, 'result', {})
1392
- parsedBalances = self.parse_balance(result)
1579
+ result = self.safe_dict(message, 'result', {})
1580
+ parsedBalances = self.parseBalanceCustom(result)
1393
1581
  client.resolve(parsedBalances, messageHash)
1394
1582
 
1583
+ async def fetch_position_ws(self, symbol: str, params={}) -> List[Position]:
1584
+ """
1585
+ :see: https://binance-docs.github.io/apidocs/futures/en/#position-information-user_data
1586
+ fetch data on an open position
1587
+ :param str symbol: unified market symbol of the market the position is held in
1588
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1589
+ :returns dict: a `position structure <https://docs.ccxt.com/#/?id=position-structure>`
1590
+ """
1591
+ return await self.fetch_positions_ws([symbol], params)
1592
+
1593
+ async def fetch_positions_ws(self, symbols: Strings = None, params={}) -> List[Position]:
1594
+ """
1595
+ fetch all open positions
1596
+ :see: https://binance-docs.github.io/apidocs/futures/en/#position-information-user_data
1597
+ :param str[] [symbols]: list of unified market symbols
1598
+ :param dict [params]: extra parameters specific to the exchange API endpoint
1599
+ :param boolean [params.returnRateLimits]: set to True to return rate limit informations, defaults to False.
1600
+ :returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
1601
+ """
1602
+ await self.load_markets()
1603
+ symbols = self.market_symbols(symbols, 'swap', True, True, True)
1604
+ url = self.urls['api']['ws']['ws-api']['future']
1605
+ requestId = self.request_id(url)
1606
+ messageHash = str(requestId)
1607
+ payload = {}
1608
+ if symbols is not None:
1609
+ symbolsLength = len(symbols)
1610
+ if symbolsLength == 1:
1611
+ payload['symbol'] = self.market_id(symbols[0])
1612
+ returnRateLimits = False
1613
+ returnRateLimits, params = self.handle_option_and_params(params, 'fetchPositionsWs', 'returnRateLimits', False)
1614
+ payload['returnRateLimits'] = returnRateLimits
1615
+ message = {
1616
+ 'id': messageHash,
1617
+ 'method': 'account.position',
1618
+ 'params': self.sign_params(self.extend(payload, params)),
1619
+ }
1620
+ subscription = {
1621
+ 'method': self.handle_positions_ws,
1622
+ }
1623
+ result = await self.watch(url, messageHash, message, messageHash, subscription)
1624
+ return self.filter_by_array_positions(result, 'symbol', symbols, False)
1625
+
1626
+ def handle_positions_ws(self, client: Client, message):
1627
+ #
1628
+ # {
1629
+ # id: '1',
1630
+ # status: 200,
1631
+ # result: [
1632
+ # {
1633
+ # symbol: 'BTCUSDT',
1634
+ # positionAmt: '-0.014',
1635
+ # entryPrice: '42901.1',
1636
+ # breakEvenPrice: '30138.83333142',
1637
+ # markPrice: '71055.98470333',
1638
+ # unRealizedProfit: '-394.16838584',
1639
+ # liquidationPrice: '137032.02272908',
1640
+ # leverage: '123',
1641
+ # maxNotionalValue: '50000',
1642
+ # marginType: 'cross',
1643
+ # isolatedMargin: '0.00000000',
1644
+ # isAutoAddMargin: 'false',
1645
+ # positionSide: 'BOTH',
1646
+ # notional: '-994.78378584',
1647
+ # isolatedWallet: '0',
1648
+ # updateTime: 1708906343111,
1649
+ # isolated: False,
1650
+ # adlQuantile: 2
1651
+ # },
1652
+ # ...
1653
+ # ]
1654
+ # }
1655
+ #
1656
+ #
1657
+ messageHash = self.safe_string(message, 'id')
1658
+ result = self.safe_list(message, 'result', [])
1659
+ positions = []
1660
+ for i in range(0, len(result)):
1661
+ parsed = self.parse_position_risk(result[i])
1662
+ entryPrice = self.safe_string(parsed, 'entryPrice')
1663
+ if (entryPrice != '0') and (entryPrice != '0.0') and (entryPrice != '0.00000000'):
1664
+ positions.append(parsed)
1665
+ client.resolve(positions, messageHash)
1666
+
1395
1667
  async def watch_balance(self, params={}) -> Balances:
1396
1668
  """
1397
1669
  watch balance and get the amount of funds available for trading or funds locked in orders
@@ -1418,7 +1690,7 @@ class binance(ccxt.async_support.binance):
1418
1690
  client = self.client(url)
1419
1691
  self.set_balance_cache(client, type, isPortfolioMargin)
1420
1692
  self.set_positions_cache(client, type, None, isPortfolioMargin)
1421
- options = self.safe_value(self.options, 'watchBalance')
1693
+ options = self.safe_dict(self.options, 'watchBalance')
1422
1694
  fetchBalanceSnapshot = self.safe_bool(options, 'fetchBalanceSnapshot', False)
1423
1695
  awaitBalanceSnapshot = self.safe_bool(options, 'awaitBalanceSnapshot', True)
1424
1696
  if fetchBalanceSnapshot and awaitBalanceSnapshot:
@@ -1485,7 +1757,7 @@ class binance(ccxt.async_support.binance):
1485
1757
  # }
1486
1758
  # }
1487
1759
  #
1488
- wallet = self.safe_value(self.options, 'wallet', 'wb') # cw for cross wallet
1760
+ wallet = self.safe_string(self.options, 'wallet', 'wb') # cw for cross wallet
1489
1761
  # each account is connected to a different endpoint
1490
1762
  # and has exactly one subscriptionhash which is the account type
1491
1763
  subscriptions = list(client.subscriptions.keys())
@@ -1509,8 +1781,8 @@ class binance(ccxt.async_support.binance):
1509
1781
  account['free'] = delta
1510
1782
  self.balance[accountType][code] = account
1511
1783
  else:
1512
- message = self.safe_value(message, 'a', message)
1513
- B = self.safe_value(message, 'B')
1784
+ message = self.safe_dict(message, 'a', message)
1785
+ B = self.safe_list(message, 'B')
1514
1786
  for i in range(0, len(B)):
1515
1787
  entry = B[i]
1516
1788
  currencyId = self.safe_string(entry, 'a')
@@ -1526,26 +1798,21 @@ class binance(ccxt.async_support.binance):
1526
1798
  self.balance[accountType] = self.safe_balance(self.balance[accountType])
1527
1799
  client.resolve(self.balance[accountType], messageHash)
1528
1800
 
1529
- def check_is_spot(self, method: str, symbol: str, params={}):
1530
- """
1531
- * @ignore
1532
- checks if symbols is a spot market if not throws an error
1533
- :param str method: name of the method to be checked
1534
- :param str symbol: symbol or marketId of the market to be checked
1535
- """
1536
- if symbol is None:
1537
- type = self.safe_string(params, 'type', 'spot')
1538
- defaultType = self.safe_string(self.options, 'defaultType', type)
1539
- if defaultType == 'spot':
1540
- return
1541
- raise BadRequest(self.id + ' ' + method + ' only supports spot markets')
1542
- market = self.market(symbol)
1543
- if not market['spot']:
1544
- raise BadRequest(self.id + ' ' + method + ' only supports spot markets')
1801
+ def get_market_type(self, method, market, params={}):
1802
+ type = None
1803
+ type, params = self.handle_market_type_and_params(method, market, params)
1804
+ subType = None
1805
+ subType, params = self.handle_sub_type_and_params(method, market, params)
1806
+ if self.isLinear(type, subType):
1807
+ type = 'future'
1808
+ elif self.isInverse(type, subType):
1809
+ type = 'delivery'
1810
+ return type
1545
1811
 
1546
1812
  async def create_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}) -> Order:
1547
1813
  """
1548
1814
  :see: https://binance-docs.github.io/apidocs/websocket_api/en/#place-new-order-trade
1815
+ :see: https://binance-docs.github.io/apidocs/futures/en/#new-order-trade-2
1549
1816
  create a trade order
1550
1817
  :param str symbol: unified symbol of the market to create an order in
1551
1818
  :param str type: 'market' or 'limit'
@@ -1554,14 +1821,18 @@ class binance(ccxt.async_support.binance):
1554
1821
  :param float|None [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
1555
1822
  :param dict [params]: extra parameters specific to the exchange API endpoint
1556
1823
  :param boolean params['test']: test order, default False
1824
+ :param boolean params['returnRateLimits']: set to True to return rate limit information, default False
1557
1825
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1558
1826
  """
1559
1827
  await self.load_markets()
1560
- self.check_is_spot('createOrderWs', symbol, params)
1561
- url = self.urls['api']['ws']['ws']
1828
+ market = self.market(symbol)
1829
+ marketType = self.get_market_type('createOrderWs', market, params)
1830
+ if marketType != 'spot' and marketType != 'future':
1831
+ raise BadRequest(self.id + ' createOrderWs only supports spot or swap markets')
1832
+ url = self.urls['api']['ws']['ws-api'][marketType]
1562
1833
  requestId = self.request_id(url)
1563
1834
  messageHash = str(requestId)
1564
- sor = self.safe_value_2(params, 'sor', 'SOR', False)
1835
+ sor = self.safe_bool_2(params, 'sor', 'SOR', False)
1565
1836
  params = self.omit(params, 'sor', 'SOR')
1566
1837
  payload = self.create_order_request(symbol, type, side, amount, price, params)
1567
1838
  returnRateLimits = False
@@ -1633,7 +1904,7 @@ class binance(ccxt.async_support.binance):
1633
1904
  # }
1634
1905
  #
1635
1906
  messageHash = self.safe_string(message, 'id')
1636
- result = self.safe_value(message, 'result', {})
1907
+ result = self.safe_dict(message, 'result', {})
1637
1908
  order = self.parse_order(result)
1638
1909
  client.resolve(order, messageHash)
1639
1910
 
@@ -1676,7 +1947,7 @@ class binance(ccxt.async_support.binance):
1676
1947
  # }
1677
1948
  #
1678
1949
  messageHash = self.safe_string(message, 'id')
1679
- result = self.safe_value(message, 'result', [])
1950
+ result = self.safe_list(message, 'result', [])
1680
1951
  orders = self.parse_orders(result)
1681
1952
  client.resolve(orders, messageHash)
1682
1953
 
@@ -1684,6 +1955,7 @@ class binance(ccxt.async_support.binance):
1684
1955
  """
1685
1956
  edit a trade order
1686
1957
  :see: https://binance-docs.github.io/apidocs/websocket_api/en/#cancel-and-replace-order-trade
1958
+ :see: https://binance-docs.github.io/apidocs/futures/en/#modify-order-trade-2
1687
1959
  :param str id: order id
1688
1960
  :param str symbol: unified symbol of the market to create an order in
1689
1961
  :param str type: 'market' or 'limit'
@@ -1694,17 +1966,24 @@ class binance(ccxt.async_support.binance):
1694
1966
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
1695
1967
  """
1696
1968
  await self.load_markets()
1697
- self.check_is_spot('editOrderWs', symbol, params)
1698
- url = self.urls['api']['ws']['ws']
1969
+ market = self.market(symbol)
1970
+ marketType = self.get_market_type('editOrderWs', market, params)
1971
+ if marketType != 'spot' and marketType != 'future':
1972
+ raise BadRequest(self.id + ' editOrderWs only supports spot or swap markets')
1973
+ url = self.urls['api']['ws']['ws-api'][marketType]
1699
1974
  requestId = self.request_id(url)
1700
1975
  messageHash = str(requestId)
1701
- payload = self.editSpotOrderRequest(id, symbol, type, side, amount, price, params)
1976
+ payload = None
1977
+ if marketType == 'spot':
1978
+ payload = self.editSpotOrderRequest(id, symbol, type, side, amount, price, params)
1979
+ elif marketType == 'future':
1980
+ payload = self.editContractOrderRequest(id, symbol, type, side, amount, price, params)
1702
1981
  returnRateLimits = False
1703
1982
  returnRateLimits, params = self.handle_option_and_params(params, 'editOrderWs', 'returnRateLimits', False)
1704
1983
  payload['returnRateLimits'] = returnRateLimits
1705
1984
  message = {
1706
1985
  'id': messageHash,
1707
- 'method': 'order.cancelReplace',
1986
+ 'method': 'order.modify' if (marketType == 'future') else 'order.cancelReplace',
1708
1987
  'params': self.sign_params(self.extend(payload, params)),
1709
1988
  }
1710
1989
  subscription = {
@@ -1714,6 +1993,7 @@ class binance(ccxt.async_support.binance):
1714
1993
 
1715
1994
  def handle_edit_order_ws(self, client: Client, message):
1716
1995
  #
1996
+ # spot
1717
1997
  # {
1718
1998
  # "id": 1,
1719
1999
  # "status": 200,
@@ -1778,16 +2058,52 @@ class binance(ccxt.async_support.binance):
1778
2058
  # }
1779
2059
  # ]
1780
2060
  # }
2061
+ # swap
2062
+ # {
2063
+ # "id":"1",
2064
+ # "status":200,
2065
+ # "result":{
2066
+ # "orderId":667061487,
2067
+ # "symbol":"LTCUSDT",
2068
+ # "status":"NEW",
2069
+ # "clientOrderId":"x-xcKtGhcu91a74c818749ee42c0f70",
2070
+ # "price":"82.00",
2071
+ # "avgPrice":"0.00",
2072
+ # "origQty":"1.000",
2073
+ # "executedQty":"0.000",
2074
+ # "cumQty":"0.000",
2075
+ # "cumQuote":"0.00000",
2076
+ # "timeInForce":"GTC",
2077
+ # "type":"LIMIT",
2078
+ # "reduceOnly":false,
2079
+ # "closePosition":false,
2080
+ # "side":"BUY",
2081
+ # "positionSide":"BOTH",
2082
+ # "stopPrice":"0.00",
2083
+ # "workingType":"CONTRACT_PRICE",
2084
+ # "priceProtect":false,
2085
+ # "origType":"LIMIT",
2086
+ # "priceMatch":"NONE",
2087
+ # "selfTradePreventionMode":"NONE",
2088
+ # "goodTillDate":0,
2089
+ # "updateTime":1712918927511
2090
+ # }
2091
+ # }
1781
2092
  #
1782
2093
  messageHash = self.safe_string(message, 'id')
1783
- result = self.safe_value(message, 'result', {})
1784
- rawOrder = self.safe_value(result, 'newOrderResponse', {})
1785
- order = self.parse_order(rawOrder)
2094
+ result = self.safe_dict(message, 'result', {})
2095
+ newSpotOrder = self.safe_dict(result, 'newOrderResponse')
2096
+ order = None
2097
+ if newSpotOrder is not None:
2098
+ order = self.parse_order(newSpotOrder)
2099
+ else:
2100
+ order = self.parse_order(result)
1786
2101
  client.resolve(order, messageHash)
1787
2102
 
1788
2103
  async def cancel_order_ws(self, id: str, symbol: Str = None, params={}) -> Order:
1789
2104
  """
1790
2105
  :see: https://binance-docs.github.io/apidocs/websocket_api/en/#cancel-order-trade
2106
+ :see: https://binance-docs.github.io/apidocs/futures/en/#cancel-order-trade-2
1791
2107
  cancel multiple orders
1792
2108
  :param str id: order id
1793
2109
  :param str symbol: unified market symbol, default is None
@@ -1798,8 +2114,9 @@ class binance(ccxt.async_support.binance):
1798
2114
  await self.load_markets()
1799
2115
  if symbol is None:
1800
2116
  raise BadRequest(self.id + ' cancelOrderWs requires a symbol')
1801
- self.check_is_spot('cancelOrderWs', symbol, params)
1802
- url = self.urls['api']['ws']['ws']
2117
+ market = self.market(symbol)
2118
+ type = self.get_market_type('cancelOrderWs', market, params)
2119
+ url = self.urls['api']['ws']['ws-api'][type]
1803
2120
  requestId = self.request_id(url)
1804
2121
  messageHash = str(requestId)
1805
2122
  returnRateLimits = False
@@ -1808,7 +2125,7 @@ class binance(ccxt.async_support.binance):
1808
2125
  'symbol': self.market_id(symbol),
1809
2126
  'returnRateLimits': returnRateLimits,
1810
2127
  }
1811
- clientOrderId = self.safe_value_2(params, 'origClientOrderId', 'clientOrderId')
2128
+ clientOrderId = self.safe_string_2(params, 'origClientOrderId', 'clientOrderId')
1812
2129
  if clientOrderId is not None:
1813
2130
  payload['origClientOrderId'] = clientOrderId
1814
2131
  else:
@@ -1833,7 +2150,11 @@ class binance(ccxt.async_support.binance):
1833
2150
  :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1834
2151
  """
1835
2152
  await self.load_markets()
1836
- url = self.urls['api']['ws']['ws']
2153
+ market = self.market(symbol)
2154
+ type = self.get_market_type('cancelAllOrdersWs', market, params)
2155
+ if type != 'spot' and type != 'future':
2156
+ raise BadRequest(self.id + ' cancelAllOrdersWs only supports spot or swap markets')
2157
+ url = self.urls['api']['ws']['ws-api'][type]
1837
2158
  requestId = self.request_id(url)
1838
2159
  messageHash = str(requestId)
1839
2160
  returnRateLimits = False
@@ -1855,6 +2176,7 @@ class binance(ccxt.async_support.binance):
1855
2176
  async def fetch_order_ws(self, id: str, symbol: Str = None, params={}) -> Order:
1856
2177
  """
1857
2178
  :see: https://binance-docs.github.io/apidocs/websocket_api/en/#query-order-user_data
2179
+ :see: https://binance-docs.github.io/apidocs/futures/en/#query-order-user_data-2
1858
2180
  fetches information on an order made by the user
1859
2181
  :param str symbol: unified symbol of the market the order was made in
1860
2182
  :param dict params: extra parameters specific to the exchange API endpoint
@@ -1863,8 +2185,11 @@ class binance(ccxt.async_support.binance):
1863
2185
  await self.load_markets()
1864
2186
  if symbol is None:
1865
2187
  raise BadRequest(self.id + ' cancelOrderWs requires a symbol')
1866
- self.check_is_spot('fetchOrderWs', symbol, params)
1867
- url = self.urls['api']['ws']['ws']
2188
+ market = self.market(symbol)
2189
+ type = self.get_market_type('fetchOrderWs', market, params)
2190
+ if type != 'spot' and type != 'future':
2191
+ raise BadRequest(self.id + ' fetchOrderWs only supports spot or swap markets')
2192
+ url = self.urls['api']['ws']['ws-api'][type]
1868
2193
  requestId = self.request_id(url)
1869
2194
  messageHash = str(requestId)
1870
2195
  returnRateLimits = False
@@ -1873,7 +2198,7 @@ class binance(ccxt.async_support.binance):
1873
2198
  'symbol': self.market_id(symbol),
1874
2199
  'returnRateLimits': returnRateLimits,
1875
2200
  }
1876
- clientOrderId = self.safe_value_2(params, 'origClientOrderId', 'clientOrderId')
2201
+ clientOrderId = self.safe_string_2(params, 'origClientOrderId', 'clientOrderId')
1877
2202
  if clientOrderId is not None:
1878
2203
  payload['origClientOrderId'] = clientOrderId
1879
2204
  else:
@@ -1905,8 +2230,11 @@ class binance(ccxt.async_support.binance):
1905
2230
  await self.load_markets()
1906
2231
  if symbol is None:
1907
2232
  raise BadRequest(self.id + ' fetchOrdersWs requires a symbol')
1908
- self.check_is_spot('fetchOrdersWs', symbol, params)
1909
- url = self.urls['api']['ws']['ws']
2233
+ market = self.market(symbol)
2234
+ type = self.get_market_type('fetchOrdersWs', market, params)
2235
+ if type != 'spot':
2236
+ raise BadRequest(self.id + ' fetchOrdersWs only supports spot markets')
2237
+ url = self.urls['api']['ws']['ws-api'][type]
1910
2238
  requestId = self.request_id(url)
1911
2239
  messageHash = str(requestId)
1912
2240
  returnRateLimits = False
@@ -1955,8 +2283,11 @@ class binance(ccxt.async_support.binance):
1955
2283
  :returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
1956
2284
  """
1957
2285
  await self.load_markets()
1958
- self.check_is_spot('fetchOpenOrdersWs', symbol)
1959
- url = self.urls['api']['ws']['ws']
2286
+ market = self.market(symbol)
2287
+ type = self.get_market_type('fetchOpenOrdersWs', market, params)
2288
+ if type != 'spot' and type != 'future':
2289
+ raise BadRequest(self.id + ' fetchOpenOrdersWs only supports spot or swap markets')
2290
+ url = self.urls['api']['ws']['ws-api'][type]
1960
2291
  requestId = self.request_id(url)
1961
2292
  messageHash = str(requestId)
1962
2293
  returnRateLimits = False
@@ -2157,7 +2488,7 @@ class binance(ccxt.async_support.binance):
2157
2488
  'type': type,
2158
2489
  'timeInForce': timeInForce,
2159
2490
  'postOnly': None,
2160
- 'reduceOnly': self.safe_value(order, 'R'),
2491
+ 'reduceOnly': self.safe_bool(order, 'R'),
2161
2492
  'side': side,
2162
2493
  'price': price,
2163
2494
  'stopPrice': stopPrice,
@@ -2256,7 +2587,7 @@ class binance(ccxt.async_support.binance):
2256
2587
  #
2257
2588
  e = self.safe_string(message, 'e')
2258
2589
  if e == 'ORDER_TRADE_UPDATE':
2259
- message = self.safe_value(message, 'o', message)
2590
+ message = self.safe_dict(message, 'o', message)
2260
2591
  self.handle_my_trade(client, message)
2261
2592
  self.handle_order(client, message)
2262
2593
 
@@ -2383,8 +2714,8 @@ class binance(ccxt.async_support.binance):
2383
2714
  if not (accountType in self.positions):
2384
2715
  self.positions[accountType] = ArrayCacheBySymbolBySide()
2385
2716
  cache = self.positions[accountType]
2386
- data = self.safe_value(message, 'a', {})
2387
- rawPositions = self.safe_value(data, 'P', [])
2717
+ data = self.safe_dict(message, 'a', {})
2718
+ rawPositions = self.safe_list(data, 'P', [])
2388
2719
  newPositions = []
2389
2720
  for i in range(0, len(rawPositions)):
2390
2721
  rawPosition = rawPositions[i]
@@ -2471,8 +2802,11 @@ class binance(ccxt.async_support.binance):
2471
2802
  await self.load_markets()
2472
2803
  if symbol is None:
2473
2804
  raise BadRequest(self.id + ' fetchMyTradesWs requires a symbol')
2474
- self.check_is_spot('fetchMyTradesWs', symbol, params)
2475
- url = self.urls['api']['ws']['ws']
2805
+ market = self.market(symbol)
2806
+ type = self.get_market_type('fetchMyTradesWs', market, params)
2807
+ if type != 'spot' and type != 'future':
2808
+ raise BadRequest(self.id + ' fetchMyTradesWs does not support ' + type + ' markets')
2809
+ url = self.urls['api']['ws']['ws-api'][type]
2476
2810
  requestId = self.request_id(url)
2477
2811
  messageHash = str(requestId)
2478
2812
  returnRateLimits = False
@@ -2515,8 +2849,11 @@ class binance(ccxt.async_support.binance):
2515
2849
  await self.load_markets()
2516
2850
  if symbol is None:
2517
2851
  raise BadRequest(self.id + ' fetchTradesWs() requires a symbol argument')
2518
- self.check_is_spot('fetchTradesWs', symbol, params)
2519
- url = self.urls['api']['ws']['ws']
2852
+ market = self.market(symbol)
2853
+ type = self.get_market_type('fetchTradesWs', market, params)
2854
+ if type != 'spot' and type != 'future':
2855
+ raise BadRequest(self.id + ' fetchTradesWs does not support ' + type + ' markets')
2856
+ url = self.urls['api']['ws']['ws-api'][type]
2520
2857
  requestId = self.request_id(url)
2521
2858
  messageHash = str(requestId)
2522
2859
  returnRateLimits = False
@@ -2585,7 +2922,7 @@ class binance(ccxt.async_support.binance):
2585
2922
  # }
2586
2923
  #
2587
2924
  messageHash = self.safe_string(message, 'id')
2588
- result = self.safe_value(message, 'result', [])
2925
+ result = self.safe_list(message, 'result', [])
2589
2926
  trades = self.parse_trades(result)
2590
2927
  client.resolve(trades, messageHash)
2591
2928
 
@@ -2641,7 +2978,7 @@ class binance(ccxt.async_support.binance):
2641
2978
  if executionType == 'TRADE':
2642
2979
  trade = self.parse_ws_trade(message)
2643
2980
  orderId = self.safe_string(trade, 'order')
2644
- tradeFee = self.safe_value(trade, 'fee', {})
2981
+ tradeFee = self.safe_dict(trade, 'fee', {})
2645
2982
  tradeFee = self.extend({}, tradeFee)
2646
2983
  symbol = self.safe_string(trade, 'symbol')
2647
2984
  if orderId is not None and tradeFee is not None and symbol is not None:
@@ -2676,7 +3013,7 @@ class binance(ccxt.async_support.binance):
2676
3013
  else:
2677
3014
  order['fee'] = tradeFee
2678
3015
  # save self trade in the order
2679
- orderTrades = self.safe_value(order, 'trades', [])
3016
+ orderTrades = self.safe_list(order, 'trades', [])
2680
3017
  orderTrades.append(trade)
2681
3018
  order['trades'] = orderTrades
2682
3019
  # don't append twice cause it breaks newUpdates mode
@@ -2735,7 +3072,7 @@ class binance(ccxt.async_support.binance):
2735
3072
  #
2736
3073
  id = self.safe_string(message, 'id')
2737
3074
  rejected = False
2738
- error = self.safe_value(message, 'error', {})
3075
+ error = self.safe_dict(message, 'error', {})
2739
3076
  code = self.safe_integer(error, 'code')
2740
3077
  msg = self.safe_string(error, 'msg')
2741
3078
  try: