ccxt 4.3.72__py2.py3-none-any.whl → 4.3.74__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.
ccxt/__init__.py CHANGED
@@ -22,7 +22,7 @@
22
22
 
23
23
  # ----------------------------------------------------------------------------
24
24
 
25
- __version__ = '4.3.72'
25
+ __version__ = '4.3.74'
26
26
 
27
27
  # ----------------------------------------------------------------------------
28
28
 
ccxt/abstract/binance.py CHANGED
@@ -523,6 +523,8 @@ class ImplicitAPI:
523
523
  fapiprivate_get_trade_asyn = fapiPrivateGetTradeAsyn = Entry('trade/asyn', 'fapiPrivate', 'GET', {'cost': 1000})
524
524
  fapiprivate_get_trade_asyn_id = fapiPrivateGetTradeAsynId = Entry('trade/asyn/id', 'fapiPrivate', 'GET', {'cost': 10})
525
525
  fapiprivate_get_feeburn = fapiPrivateGetFeeBurn = Entry('feeBurn', 'fapiPrivate', 'GET', {'cost': 1})
526
+ fapiprivate_get_symbolconfig = fapiPrivateGetSymbolConfig = Entry('symbolConfig', 'fapiPrivate', 'GET', {'cost': 5})
527
+ fapiprivate_get_accountconfig = fapiPrivateGetAccountConfig = Entry('accountConfig', 'fapiPrivate', 'GET', {'cost': 5})
526
528
  fapiprivate_post_batchorders = fapiPrivatePostBatchOrders = Entry('batchOrders', 'fapiPrivate', 'POST', {'cost': 5})
527
529
  fapiprivate_post_positionside_dual = fapiPrivatePostPositionSideDual = Entry('positionSide/dual', 'fapiPrivate', 'POST', {'cost': 1})
528
530
  fapiprivate_post_positionmargin = fapiPrivatePostPositionMargin = Entry('positionMargin', 'fapiPrivate', 'POST', {'cost': 1})
@@ -546,6 +548,9 @@ class ImplicitAPI:
546
548
  fapiprivatev2_get_account = fapiPrivateV2GetAccount = Entry('account', 'fapiPrivateV2', 'GET', {'cost': 1})
547
549
  fapiprivatev2_get_balance = fapiPrivateV2GetBalance = Entry('balance', 'fapiPrivateV2', 'GET', {'cost': 1})
548
550
  fapiprivatev2_get_positionrisk = fapiPrivateV2GetPositionRisk = Entry('positionRisk', 'fapiPrivateV2', 'GET', {'cost': 1})
551
+ fapiprivatev3_get_account = fapiPrivateV3GetAccount = Entry('account', 'fapiPrivateV3', 'GET', {'cost': 1})
552
+ fapiprivatev3_get_balance = fapiPrivateV3GetBalance = Entry('balance', 'fapiPrivateV3', 'GET', {'cost': 1})
553
+ fapiprivatev3_get_positionrisk = fapiPrivateV3GetPositionRisk = Entry('positionRisk', 'fapiPrivateV3', 'GET', {'cost': 1})
549
554
  eapipublic_get_ping = eapiPublicGetPing = Entry('ping', 'eapiPublic', 'GET', {'cost': 1})
550
555
  eapipublic_get_time = eapiPublicGetTime = Entry('time', 'eapiPublic', 'GET', {'cost': 1})
551
556
  eapipublic_get_exchangeinfo = eapiPublicGetExchangeInfo = Entry('exchangeInfo', 'eapiPublic', 'GET', {'cost': 1})
@@ -523,6 +523,8 @@ class ImplicitAPI:
523
523
  fapiprivate_get_trade_asyn = fapiPrivateGetTradeAsyn = Entry('trade/asyn', 'fapiPrivate', 'GET', {'cost': 1000})
524
524
  fapiprivate_get_trade_asyn_id = fapiPrivateGetTradeAsynId = Entry('trade/asyn/id', 'fapiPrivate', 'GET', {'cost': 10})
525
525
  fapiprivate_get_feeburn = fapiPrivateGetFeeBurn = Entry('feeBurn', 'fapiPrivate', 'GET', {'cost': 1})
526
+ fapiprivate_get_symbolconfig = fapiPrivateGetSymbolConfig = Entry('symbolConfig', 'fapiPrivate', 'GET', {'cost': 5})
527
+ fapiprivate_get_accountconfig = fapiPrivateGetAccountConfig = Entry('accountConfig', 'fapiPrivate', 'GET', {'cost': 5})
526
528
  fapiprivate_post_batchorders = fapiPrivatePostBatchOrders = Entry('batchOrders', 'fapiPrivate', 'POST', {'cost': 5})
527
529
  fapiprivate_post_positionside_dual = fapiPrivatePostPositionSideDual = Entry('positionSide/dual', 'fapiPrivate', 'POST', {'cost': 1})
528
530
  fapiprivate_post_positionmargin = fapiPrivatePostPositionMargin = Entry('positionMargin', 'fapiPrivate', 'POST', {'cost': 1})
@@ -546,6 +548,9 @@ class ImplicitAPI:
546
548
  fapiprivatev2_get_account = fapiPrivateV2GetAccount = Entry('account', 'fapiPrivateV2', 'GET', {'cost': 1})
547
549
  fapiprivatev2_get_balance = fapiPrivateV2GetBalance = Entry('balance', 'fapiPrivateV2', 'GET', {'cost': 1})
548
550
  fapiprivatev2_get_positionrisk = fapiPrivateV2GetPositionRisk = Entry('positionRisk', 'fapiPrivateV2', 'GET', {'cost': 1})
551
+ fapiprivatev3_get_account = fapiPrivateV3GetAccount = Entry('account', 'fapiPrivateV3', 'GET', {'cost': 1})
552
+ fapiprivatev3_get_balance = fapiPrivateV3GetBalance = Entry('balance', 'fapiPrivateV3', 'GET', {'cost': 1})
553
+ fapiprivatev3_get_positionrisk = fapiPrivateV3GetPositionRisk = Entry('positionRisk', 'fapiPrivateV3', 'GET', {'cost': 1})
549
554
  eapipublic_get_ping = eapiPublicGetPing = Entry('ping', 'eapiPublic', 'GET', {'cost': 1})
550
555
  eapipublic_get_time = eapiPublicGetTime = Entry('time', 'eapiPublic', 'GET', {'cost': 1})
551
556
  eapipublic_get_exchangeinfo = eapiPublicGetExchangeInfo = Entry('exchangeInfo', 'eapiPublic', 'GET', {'cost': 1})
@@ -575,6 +575,8 @@ class ImplicitAPI:
575
575
  fapiprivate_get_trade_asyn = fapiPrivateGetTradeAsyn = Entry('trade/asyn', 'fapiPrivate', 'GET', {'cost': 1000})
576
576
  fapiprivate_get_trade_asyn_id = fapiPrivateGetTradeAsynId = Entry('trade/asyn/id', 'fapiPrivate', 'GET', {'cost': 10})
577
577
  fapiprivate_get_feeburn = fapiPrivateGetFeeBurn = Entry('feeBurn', 'fapiPrivate', 'GET', {'cost': 1})
578
+ fapiprivate_get_symbolconfig = fapiPrivateGetSymbolConfig = Entry('symbolConfig', 'fapiPrivate', 'GET', {'cost': 5})
579
+ fapiprivate_get_accountconfig = fapiPrivateGetAccountConfig = Entry('accountConfig', 'fapiPrivate', 'GET', {'cost': 5})
578
580
  fapiprivate_post_batchorders = fapiPrivatePostBatchOrders = Entry('batchOrders', 'fapiPrivate', 'POST', {'cost': 5})
579
581
  fapiprivate_post_positionside_dual = fapiPrivatePostPositionSideDual = Entry('positionSide/dual', 'fapiPrivate', 'POST', {'cost': 1})
580
582
  fapiprivate_post_positionmargin = fapiPrivatePostPositionMargin = Entry('positionMargin', 'fapiPrivate', 'POST', {'cost': 1})
@@ -598,6 +600,9 @@ class ImplicitAPI:
598
600
  fapiprivatev2_get_account = fapiPrivateV2GetAccount = Entry('account', 'fapiPrivateV2', 'GET', {'cost': 1})
599
601
  fapiprivatev2_get_balance = fapiPrivateV2GetBalance = Entry('balance', 'fapiPrivateV2', 'GET', {'cost': 1})
600
602
  fapiprivatev2_get_positionrisk = fapiPrivateV2GetPositionRisk = Entry('positionRisk', 'fapiPrivateV2', 'GET', {'cost': 1})
603
+ fapiprivatev3_get_account = fapiPrivateV3GetAccount = Entry('account', 'fapiPrivateV3', 'GET', {'cost': 1})
604
+ fapiprivatev3_get_balance = fapiPrivateV3GetBalance = Entry('balance', 'fapiPrivateV3', 'GET', {'cost': 1})
605
+ fapiprivatev3_get_positionrisk = fapiPrivateV3GetPositionRisk = Entry('positionRisk', 'fapiPrivateV3', 'GET', {'cost': 1})
601
606
  eapipublic_get_ping = eapiPublicGetPing = Entry('ping', 'eapiPublic', 'GET', {'cost': 1})
602
607
  eapipublic_get_time = eapiPublicGetTime = Entry('time', 'eapiPublic', 'GET', {'cost': 1})
603
608
  eapipublic_get_exchangeinfo = eapiPublicGetExchangeInfo = Entry('exchangeInfo', 'eapiPublic', 'GET', {'cost': 1})
@@ -523,6 +523,8 @@ class ImplicitAPI:
523
523
  fapiprivate_get_trade_asyn = fapiPrivateGetTradeAsyn = Entry('trade/asyn', 'fapiPrivate', 'GET', {'cost': 1000})
524
524
  fapiprivate_get_trade_asyn_id = fapiPrivateGetTradeAsynId = Entry('trade/asyn/id', 'fapiPrivate', 'GET', {'cost': 10})
525
525
  fapiprivate_get_feeburn = fapiPrivateGetFeeBurn = Entry('feeBurn', 'fapiPrivate', 'GET', {'cost': 1})
526
+ fapiprivate_get_symbolconfig = fapiPrivateGetSymbolConfig = Entry('symbolConfig', 'fapiPrivate', 'GET', {'cost': 5})
527
+ fapiprivate_get_accountconfig = fapiPrivateGetAccountConfig = Entry('accountConfig', 'fapiPrivate', 'GET', {'cost': 5})
526
528
  fapiprivate_post_batchorders = fapiPrivatePostBatchOrders = Entry('batchOrders', 'fapiPrivate', 'POST', {'cost': 5})
527
529
  fapiprivate_post_positionside_dual = fapiPrivatePostPositionSideDual = Entry('positionSide/dual', 'fapiPrivate', 'POST', {'cost': 1})
528
530
  fapiprivate_post_positionmargin = fapiPrivatePostPositionMargin = Entry('positionMargin', 'fapiPrivate', 'POST', {'cost': 1})
@@ -546,6 +548,9 @@ class ImplicitAPI:
546
548
  fapiprivatev2_get_account = fapiPrivateV2GetAccount = Entry('account', 'fapiPrivateV2', 'GET', {'cost': 1})
547
549
  fapiprivatev2_get_balance = fapiPrivateV2GetBalance = Entry('balance', 'fapiPrivateV2', 'GET', {'cost': 1})
548
550
  fapiprivatev2_get_positionrisk = fapiPrivateV2GetPositionRisk = Entry('positionRisk', 'fapiPrivateV2', 'GET', {'cost': 1})
551
+ fapiprivatev3_get_account = fapiPrivateV3GetAccount = Entry('account', 'fapiPrivateV3', 'GET', {'cost': 1})
552
+ fapiprivatev3_get_balance = fapiPrivateV3GetBalance = Entry('balance', 'fapiPrivateV3', 'GET', {'cost': 1})
553
+ fapiprivatev3_get_positionrisk = fapiPrivateV3GetPositionRisk = Entry('positionRisk', 'fapiPrivateV3', 'GET', {'cost': 1})
549
554
  eapipublic_get_ping = eapiPublicGetPing = Entry('ping', 'eapiPublic', 'GET', {'cost': 1})
550
555
  eapipublic_get_time = eapiPublicGetTime = Entry('time', 'eapiPublic', 'GET', {'cost': 1})
551
556
  eapipublic_get_exchangeinfo = eapiPublicGetExchangeInfo = Entry('exchangeInfo', 'eapiPublic', 'GET', {'cost': 1})
ccxt/ace.py CHANGED
@@ -353,7 +353,7 @@ class ace(Exchange, ImplicitAPI):
353
353
  for i in range(0, len(pairs)):
354
354
  marketId = pairs[i]
355
355
  market = self.safe_market(marketId)
356
- rawTicker = self.safe_dict(response, marketId)
356
+ rawTicker = self.safe_dict(response, marketId, {})
357
357
  ticker = self.parse_ticker(rawTicker, market)
358
358
  tickers.append(ticker)
359
359
  return self.filter_by_array_tickers(tickers, 'symbol', symbols)
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.3.72'
7
+ __version__ = '4.3.74'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
ccxt/async_support/ace.py CHANGED
@@ -353,7 +353,7 @@ class ace(Exchange, ImplicitAPI):
353
353
  for i in range(0, len(pairs)):
354
354
  marketId = pairs[i]
355
355
  market = self.safe_market(marketId)
356
- rawTicker = self.safe_dict(response, marketId)
356
+ rawTicker = self.safe_dict(response, marketId, {})
357
357
  ticker = self.parse_ticker(rawTicker, market)
358
358
  tickers.append(ticker)
359
359
  return self.filter_by_array_tickers(tickers, 'symbol', symbols)
@@ -2,7 +2,7 @@
2
2
 
3
3
  # -----------------------------------------------------------------------------
4
4
 
5
- __version__ = '4.3.72'
5
+ __version__ = '4.3.74'
6
6
 
7
7
  # -----------------------------------------------------------------------------
8
8
 
@@ -15,7 +15,7 @@ class Client(object):
15
15
  subscriptions = {}
16
16
  rejections = {}
17
17
  message_queue = {}
18
- useMessageQueue = True
18
+ useMessageQueue = False
19
19
  on_message_callback = None
20
20
  on_error_callback = None
21
21
  on_close_callback = None
@@ -213,8 +213,10 @@ class binance(Exchange, ImplicitAPI):
213
213
  'dapiPrivateV2': 'https://testnet.binancefuture.com/dapi/v2',
214
214
  'fapiPublic': 'https://testnet.binancefuture.com/fapi/v1',
215
215
  'fapiPublicV2': 'https://testnet.binancefuture.com/fapi/v2',
216
+ 'fapiPublicV3': 'https://testnet.binancefuture.com/fapi/v3',
216
217
  'fapiPrivate': 'https://testnet.binancefuture.com/fapi/v1',
217
218
  'fapiPrivateV2': 'https://testnet.binancefuture.com/fapi/v2',
219
+ 'fapiPrivateV3': 'https://testnet.binancefuture.com/fapi/v3',
218
220
  'public': 'https://testnet.binance.vision/api/v3',
219
221
  'private': 'https://testnet.binance.vision/api/v3',
220
222
  'v1': 'https://testnet.binance.vision/api/v1',
@@ -232,9 +234,11 @@ class binance(Exchange, ImplicitAPI):
232
234
  'dapiData': 'https://dapi.binance.com/futures/data',
233
235
  'fapiPublic': 'https://fapi.binance.com/fapi/v1',
234
236
  'fapiPublicV2': 'https://fapi.binance.com/fapi/v2',
237
+ 'fapiPublicV3': 'https://fapi.binance.com/fapi/v3',
235
238
  'fapiPrivate': 'https://fapi.binance.com/fapi/v1',
236
- 'fapiData': 'https://fapi.binance.com/futures/data',
237
239
  'fapiPrivateV2': 'https://fapi.binance.com/fapi/v2',
240
+ 'fapiPrivateV3': 'https://fapi.binance.com/fapi/v3',
241
+ 'fapiData': 'https://fapi.binance.com/futures/data',
238
242
  'public': 'https://api.binance.com/api/v3',
239
243
  'private': 'https://api.binance.com/api/v3',
240
244
  'v1': 'https://api.binance.com/api/v1',
@@ -870,6 +874,8 @@ class binance(Exchange, ImplicitAPI):
870
874
  'trade/asyn': 1000,
871
875
  'trade/asyn/id': 10,
872
876
  'feeBurn': 1,
877
+ 'symbolConfig': 5,
878
+ 'accountConfig': 5,
873
879
  },
874
880
  'post': {
875
881
  'batchOrders': 5,
@@ -910,6 +916,16 @@ class binance(Exchange, ImplicitAPI):
910
916
  'positionRisk': 1,
911
917
  },
912
918
  },
919
+ 'fapiPublicV3': {
920
+ 'get': {},
921
+ },
922
+ 'fapiPrivateV3': {
923
+ 'get': {
924
+ 'account': 1,
925
+ 'balance': 1,
926
+ 'positionRisk': 1,
927
+ },
928
+ },
913
929
  'eapiPublic': {
914
930
  'get': {
915
931
  'ping': 1,
@@ -3348,7 +3364,7 @@ class binance(Exchange, ImplicitAPI):
3348
3364
  response = await self.papiGetBalance(self.extend(request, query))
3349
3365
  elif self.is_linear(type, subType):
3350
3366
  type = 'linear'
3351
- response = await self.fapiPrivateV2GetAccount(self.extend(request, query))
3367
+ response = await self.fapiPrivateV3GetAccount(self.extend(request, query))
3352
3368
  elif self.is_inverse(type, subType):
3353
3369
  type = 'inverse'
3354
3370
  response = await self.dapiPrivateGetAccount(self.extend(request, query))
@@ -8766,24 +8782,29 @@ class binance(Exchange, ImplicitAPI):
8766
8782
  #
8767
8783
  # usdm
8768
8784
  #
8785
+ # v3(similar for cross & isolated)
8786
+ #
8769
8787
  # {
8770
- # "symbol": "BTCBUSD",
8771
- # "initialMargin": "0",
8772
- # "maintMargin": "0",
8773
- # "unrealizedProfit": "0.00000000",
8774
- # "positionInitialMargin": "0",
8775
- # "openOrderInitialMargin": "0",
8776
- # "leverage": "20",
8777
- # "isolated": False,
8778
- # "entryPrice": "0.0000",
8779
- # "maxNotional": "100000",
8780
- # "positionSide": "BOTH",
8781
- # "positionAmt": "0.000",
8782
- # "notional": "0",
8783
- # "isolatedWallet": "0",
8784
- # "updateTime": "0",
8785
- # "crossMargin": "100.93634809",
8786
- # }
8788
+ # "symbol": "WLDUSDT",
8789
+ # "positionSide": "BOTH",
8790
+ # "positionAmt": "-849",
8791
+ # "unrealizedProfit": "11.17920750",
8792
+ # "notional": "-1992.46079250",
8793
+ # "isolatedMargin": "0",
8794
+ # "isolatedWallet": "0",
8795
+ # "initialMargin": "99.62303962",
8796
+ # "maintMargin": "11.95476475",
8797
+ # "updateTime": "1721995760449"
8798
+ # "leverage": "50", # in v2
8799
+ # "entryPrice": "2.34", # in v2
8800
+ # "positionInitialMargin": "118.82116614", # in v2
8801
+ # "openOrderInitialMargin": "0", # in v2
8802
+ # "isolated": False, # in v2
8803
+ # "breakEvenPrice": "2.3395788", # in v2
8804
+ # "maxNotional": "25000", # in v2
8805
+ # "bidNotional": "0", # in v2
8806
+ # "askNotional": "0" # in v2
8807
+ # }
8787
8808
  #
8788
8809
  # coinm
8789
8810
  #
@@ -8849,13 +8870,15 @@ class binance(Exchange, ImplicitAPI):
8849
8870
  market = self.safe_market(marketId, market, None, 'contract')
8850
8871
  symbol = self.safe_string(market, 'symbol')
8851
8872
  leverageString = self.safe_string(position, 'leverage')
8852
- leverage = int(leverageString)
8873
+ leverage = int(leverageString) if (leverageString is not None) else None
8853
8874
  initialMarginString = self.safe_string(position, 'initialMargin')
8854
8875
  initialMargin = self.parse_number(initialMarginString)
8855
- initialMarginPercentageString = Precise.string_div('1', leverageString, 8)
8856
- rational = self.is_round_number(1000 % leverage)
8857
- if not rational:
8858
- initialMarginPercentageString = Precise.string_div(Precise.string_add(initialMarginPercentageString, '1e-8'), '1', 8)
8876
+ initialMarginPercentageString = None
8877
+ if leverageString is not None:
8878
+ initialMarginPercentageString = Precise.string_div('1', leverageString, 8)
8879
+ rational = self.is_round_number(1000 % leverage)
8880
+ if not rational:
8881
+ initialMarginPercentageString = Precise.string_div(Precise.string_add(initialMarginPercentageString, '1e-8'), '1', 8)
8859
8882
  # to notionalValue
8860
8883
  usdm = ('notional' in position)
8861
8884
  maintenanceMarginString = self.safe_string(position, 'maintMargin')
@@ -8888,6 +8911,9 @@ class binance(Exchange, ImplicitAPI):
8888
8911
  if timestamp == 0:
8889
8912
  timestamp = None
8890
8913
  isolated = self.safe_bool(position, 'isolated')
8914
+ if isolated is None:
8915
+ isolatedMarginRaw = self.safe_string(position, 'isolatedMargin')
8916
+ isolated = not Precise.string_eq(isolatedMarginRaw, '0')
8891
8917
  marginMode = None
8892
8918
  collateralString = None
8893
8919
  walletBalance = None
@@ -8992,23 +9018,34 @@ class binance(Exchange, ImplicitAPI):
8992
9018
  #
8993
9019
  # usdm
8994
9020
  #
8995
- # {
8996
- # "symbol": "BTCUSDT",
8997
- # "positionAmt": "0.001",
8998
- # "entryPrice": "43578.07000",
8999
- # "markPrice": "43532.30000000",
9000
- # "unRealizedProfit": "-0.04577000",
9001
- # "liquidationPrice": "21841.24993976",
9002
- # "leverage": "2",
9003
- # "maxNotionalValue": "300000000",
9004
- # "marginType": "isolated",
9005
- # "isolatedMargin": "21.77841506",
9006
- # "isAutoAddMargin": "false",
9007
- # "positionSide": "BOTH",
9008
- # "notional": "43.53230000",
9009
- # "isolatedWallet": "21.82418506",
9010
- # "updateTime": "1621358023886"
9011
- # }
9021
+ # {
9022
+ # symbol: "WLDUSDT",
9023
+ # positionSide: "BOTH",
9024
+ # positionAmt: "5",
9025
+ # entryPrice: "2.3483",
9026
+ # breakEvenPrice: "2.349356735",
9027
+ # markPrice: "2.39560000",
9028
+ # unRealizedProfit: "0.23650000",
9029
+ # liquidationPrice: "0",
9030
+ # isolatedMargin: "0",
9031
+ # notional: "11.97800000",
9032
+ # isolatedWallet: "0",
9033
+ # updateTime: "1722062678998",
9034
+ # initialMargin: "2.39560000", # not in v2
9035
+ # maintMargin: "0.07186800", # not in v2
9036
+ # positionInitialMargin: "2.39560000", # not in v2
9037
+ # openOrderInitialMargin: "0", # not in v2
9038
+ # adl: "2", # not in v2
9039
+ # bidNotional: "0", # not in v2
9040
+ # askNotional: "0", # not in v2
9041
+ # marginAsset: "USDT", # not in v2
9042
+ # # the below fields are only in v2
9043
+ # leverage: "5",
9044
+ # maxNotionalValue: "6000000",
9045
+ # marginType: "cross",
9046
+ # isAutoAddMargin: "false",
9047
+ # isolated: False,
9048
+ # adlQuantile: "2",
9012
9049
  #
9013
9050
  # coinm
9014
9051
  #
@@ -9066,6 +9103,7 @@ class binance(Exchange, ImplicitAPI):
9066
9103
  marketId = self.safe_string(position, 'symbol')
9067
9104
  market = self.safe_market(marketId, market, None, 'contract')
9068
9105
  symbol = self.safe_string(market, 'symbol')
9106
+ isolatedMarginString = self.safe_string(position, 'isolatedMargin')
9069
9107
  leverageBrackets = self.safe_dict(self.options, 'leverageBrackets', {})
9070
9108
  leverageBracket = self.safe_list(leverageBrackets, symbol, [])
9071
9109
  notionalString = self.safe_string_2(position, 'notional', 'notionalValue')
@@ -9081,12 +9119,12 @@ class binance(Exchange, ImplicitAPI):
9081
9119
  contracts = self.parse_number(contractsAbs)
9082
9120
  unrealizedPnlString = self.safe_string(position, 'unRealizedProfit')
9083
9121
  unrealizedPnl = self.parse_number(unrealizedPnlString)
9084
- leverageString = self.safe_string(position, 'leverage')
9085
- leverage = int(leverageString)
9086
9122
  liquidationPriceString = self.omit_zero(self.safe_string(position, 'liquidationPrice'))
9087
9123
  liquidationPrice = self.parse_number(liquidationPriceString)
9088
9124
  collateralString = None
9089
9125
  marginMode = self.safe_string(position, 'marginType')
9126
+ if marginMode is None and isolatedMarginString:
9127
+ marginMode = 'cross' if Precise.string_eq(isolatedMarginString, '0') else 'isolated'
9090
9128
  side = None
9091
9129
  if Precise.string_gt(notionalString, '0'):
9092
9130
  side = 'long'
@@ -9143,13 +9181,25 @@ class binance(Exchange, ImplicitAPI):
9143
9181
  timestamp = None
9144
9182
  maintenanceMarginPercentage = self.parse_number(maintenanceMarginPercentageString)
9145
9183
  maintenanceMarginString = Precise.string_mul(maintenanceMarginPercentageString, notionalStringAbs)
9184
+ if maintenanceMarginString is None:
9185
+ # for a while, self new value was a backup to the existing calculations, but in future we might prioritize self
9186
+ maintenanceMarginString = self.safe_string(position, 'maintMargin')
9146
9187
  maintenanceMargin = self.parse_number(maintenanceMarginString)
9147
- initialMarginPercentageString = Precise.string_div('1', leverageString, 8)
9148
- rational = self.is_round_number(1000 % leverage)
9149
- if not rational:
9150
- initialMarginPercentageString = Precise.string_add(initialMarginPercentageString, '1e-8')
9151
- initialMarginString = Precise.string_div(Precise.string_mul(notionalStringAbs, initialMarginPercentageString), '1', 8)
9152
- initialMargin = self.parse_number(initialMarginString)
9188
+ initialMarginString = None
9189
+ initialMarginPercentageString = None
9190
+ leverageString = self.safe_string(position, 'leverage')
9191
+ if leverageString is not None:
9192
+ leverage = int(leverageString)
9193
+ rational = self.is_round_number(1000 % leverage)
9194
+ initialMarginPercentageString = Precise.string_div('1', leverageString, 8)
9195
+ if not rational:
9196
+ initialMarginPercentageString = Precise.string_add(initialMarginPercentageString, '1e-8')
9197
+ unrounded = Precise.string_mul(notionalStringAbs, initialMarginPercentageString)
9198
+ initialMarginString = Precise.string_div(unrounded, '1', 8)
9199
+ else:
9200
+ initialMarginString = self.safe_string(position, 'initialMargin')
9201
+ unrounded = Precise.string_mul(initialMarginString, '1')
9202
+ initialMarginPercentageString = Precise.string_div(unrounded, notionalStringAbs, 8)
9153
9203
  marginRatio = None
9154
9204
  percentage = None
9155
9205
  if not Precise.string_equals(collateralString, '0'):
@@ -9171,7 +9221,7 @@ class binance(Exchange, ImplicitAPI):
9171
9221
  'markPrice': markPrice,
9172
9222
  'entryPrice': entryPrice,
9173
9223
  'timestamp': timestamp,
9174
- 'initialMargin': initialMargin,
9224
+ 'initialMargin': self.parse_number(initialMarginString),
9175
9225
  'initialMarginPercentage': self.parse_number(initialMarginPercentageString),
9176
9226
  'maintenanceMargin': maintenanceMargin,
9177
9227
  'maintenanceMarginPercentage': maintenanceMarginPercentage,
@@ -9501,9 +9551,14 @@ class binance(Exchange, ImplicitAPI):
9501
9551
  :param str [method]: method name to call, "positionRisk", "account" or "option", default is "positionRisk"
9502
9552
  :returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
9503
9553
  """
9504
- defaultValue = self.safe_string(self.options, 'fetchPositions', 'positionRisk')
9505
9554
  defaultMethod = None
9506
- defaultMethod, params = self.handle_option_and_params(params, 'fetchPositions', 'method', defaultValue)
9555
+ defaultMethod, params = self.handle_option_and_params(params, 'fetchPositions', 'method')
9556
+ if defaultMethod is None:
9557
+ options = self.safe_dict(self.options, 'fetchPositions')
9558
+ if options is None:
9559
+ defaultMethod = self.safe_string(self.options, 'fetchPositions', 'positionRisk')
9560
+ else:
9561
+ defaultMethod = 'positionRisk'
9507
9562
  if defaultMethod == 'positionRisk':
9508
9563
  return await self.fetch_positions_risk(symbols, params)
9509
9564
  elif defaultMethod == 'account':
@@ -9511,7 +9566,7 @@ class binance(Exchange, ImplicitAPI):
9511
9566
  elif defaultMethod == 'option':
9512
9567
  return await self.fetch_option_positions(symbols, params)
9513
9568
  else:
9514
- raise NotSupported(self.id + '.options["fetchPositions"]/params["method"] = "' + defaultMethod + '" is invalid, please choose between "account", "positionRisk" and "option"')
9569
+ raise NotSupported(self.id + '.options["fetchPositions"]["method"] or params["method"] = "' + defaultMethod + '" is invalid, please choose between "account", "positionRisk" and "option"')
9515
9570
 
9516
9571
  async def fetch_account_positions(self, symbols: Strings = None, params={}):
9517
9572
  """
@@ -9526,6 +9581,7 @@ class binance(Exchange, ImplicitAPI):
9526
9581
  :param boolean [params.portfolioMargin]: set to True if you would like to fetch positions in a portfolio margin account
9527
9582
  :param str [params.subType]: "linear" or "inverse"
9528
9583
  :param boolean [params.filterClosed]: set to True if you would like to filter out closed positions, default is False
9584
+ :param boolean [params.useV2]: set to True if you want to use obsolete endpoint, where some more additional fields were provided
9529
9585
  :returns dict: data on account positions
9530
9586
  """
9531
9587
  if symbols is not None:
@@ -9545,7 +9601,78 @@ class binance(Exchange, ImplicitAPI):
9545
9601
  if isPortfolioMargin:
9546
9602
  response = await self.papiGetUmAccount(params)
9547
9603
  else:
9548
- response = await self.fapiPrivateV2GetAccount(params)
9604
+ useV2 = None
9605
+ useV2, params = self.handle_option_and_params(params, 'fetchAccountPositions', 'useV2', False)
9606
+ if not useV2:
9607
+ response = await self.fapiPrivateV3GetAccount(params)
9608
+ else:
9609
+ response = await self.fapiPrivateV2GetAccount(params)
9610
+ #
9611
+ # {
9612
+ # "totalInitialMargin": "99.62112386",
9613
+ # "totalMaintMargin": "11.95453485",
9614
+ # "totalWalletBalance": "99.84331553",
9615
+ # "totalUnrealizedProfit": "11.17675690",
9616
+ # "totalMarginBalance": "111.02007243",
9617
+ # "totalPositionInitialMargin": "99.62112386",
9618
+ # "totalOpenOrderInitialMargin": "0.00000000",
9619
+ # "totalCrossWalletBalance": "99.84331553",
9620
+ # "totalCrossUnPnl": "11.17675690",
9621
+ # "availableBalance": "11.39894857",
9622
+ # "maxWithdrawAmount": "11.39894857",
9623
+ # "feeTier": "0", # in v2
9624
+ # "canTrade": True, # in v2
9625
+ # "canDeposit": True, # in v2
9626
+ # "canWithdraw": True, # in v2
9627
+ # "feeBurn": True, # in v2
9628
+ # "tradeGroupId": "-1",// in v2
9629
+ # "updateTime": "0", # in v2
9630
+ # "multiAssetsMargin": True # in v2
9631
+ # "assets": [
9632
+ # {
9633
+ # "asset": "USDT",
9634
+ # "walletBalance": "72.72317863",
9635
+ # "unrealizedProfit": "11.17920750",
9636
+ # "marginBalance": "83.90238613",
9637
+ # "maintMargin": "11.95476475",
9638
+ # "initialMargin": "99.62303962",
9639
+ # "positionInitialMargin": "99.62303962",
9640
+ # "openOrderInitialMargin": "0.00000000",
9641
+ # "crossWalletBalance": "72.72317863",
9642
+ # "crossUnPnl": "11.17920750",
9643
+ # "availableBalance": "11.39916777",
9644
+ # "maxWithdrawAmount": "11.39916777",
9645
+ # "updateTime": "1721995605338",
9646
+ # "marginAvailable": True # in v2
9647
+ # },
9648
+ # ... and some few supported settle currencies: USDC, BTC, ETH, BNB ..
9649
+ # ],
9650
+ # "positions": [
9651
+ # {
9652
+ # "symbol": "WLDUSDT",
9653
+ # "positionSide": "BOTH",
9654
+ # "positionAmt": "-849",
9655
+ # "unrealizedProfit": "11.17920750",
9656
+ # "isolatedMargin": "0",
9657
+ # "isolatedWallet": "0",
9658
+ # "notional": "-1992.46079250",
9659
+ # "initialMargin": "99.62303962",
9660
+ # "maintMargin": "11.95476475",
9661
+ # "updateTime": "1721995760449"
9662
+ # "leverage": "50", # in v2
9663
+ # "entryPrice": "2.34", # in v2
9664
+ # "positionInitialMargin": "118.82116614", # in v2
9665
+ # "openOrderInitialMargin": "0", # in v2
9666
+ # "isolated": False, # in v2
9667
+ # "breakEvenPrice": "2.3395788", # in v2
9668
+ # "maxNotional": "25000", # in v2
9669
+ # "bidNotional": "0", # in v2
9670
+ # "askNotional": "0" # in v2
9671
+ # },
9672
+ # ...
9673
+ # ]
9674
+ # }
9675
+ #
9549
9676
  elif self.is_inverse(type, subType):
9550
9677
  if isPortfolioMargin:
9551
9678
  response = await self.papiGetCmAccount(params)
@@ -9592,7 +9719,33 @@ class binance(Exchange, ImplicitAPI):
9592
9719
  if isPortfolioMargin:
9593
9720
  response = await self.papiGetUmPositionRisk(self.extend(request, params))
9594
9721
  else:
9595
- response = await self.fapiPrivateV2GetPositionRisk(self.extend(request, params))
9722
+ response = await self.fapiPrivateV3GetPositionRisk(self.extend(request, params))
9723
+ #
9724
+ # [
9725
+ # {
9726
+ # symbol: "WLDUSDT",
9727
+ # positionSide: "BOTH",
9728
+ # positionAmt: "5",
9729
+ # entryPrice: "2.3483",
9730
+ # breakEvenPrice: "2.349356735",
9731
+ # markPrice: "2.39560000",
9732
+ # unRealizedProfit: "0.23650000",
9733
+ # liquidationPrice: "0",
9734
+ # isolatedMargin: "0",
9735
+ # notional: "11.97800000",
9736
+ # isolatedWallet: "0",
9737
+ # updateTime: "1722062678998",
9738
+ # initialMargin: "2.39560000", # added in v3
9739
+ # maintMargin: "0.07186800", # added in v3
9740
+ # positionInitialMargin: "2.39560000", # added in v3
9741
+ # openOrderInitialMargin: "0", # added in v3
9742
+ # adl: "2", # added in v3
9743
+ # bidNotional: "0", # added in v3
9744
+ # askNotional: "0", # added in v3
9745
+ # marginAsset: "USDT", # added in v3
9746
+ # },
9747
+ # ]
9748
+ #
9596
9749
  elif self.is_inverse(type, subType):
9597
9750
  if isPortfolioMargin:
9598
9751
  response = await self.papiGetCmPositionRisk(self.extend(request, params))
@@ -9606,18 +9759,18 @@ class binance(Exchange, ImplicitAPI):
9606
9759
  #
9607
9760
  # [
9608
9761
  # {
9762
+ # "symbol": "BTCUSDT",
9763
+ # "positionSide": "BOTH",
9764
+ # "positionAmt": "0.000",
9609
9765
  # "entryPrice": "0.00000",
9766
+ # "markPrice": "6679.50671178",
9767
+ # "unRealizedProfit": "0.00000000",
9768
+ # "liquidationPrice": "0",
9769
+ # "isolatedMargin": "0.00000000",
9610
9770
  # "marginType": "isolated",
9611
9771
  # "isAutoAddMargin": "false",
9612
- # "isolatedMargin": "0.00000000",
9613
9772
  # "leverage": "10",
9614
- # "liquidationPrice": "0",
9615
- # "markPrice": "6679.50671178",
9616
9773
  # "maxNotionalValue": "20000000",
9617
- # "positionAmt": "0.000",
9618
- # "symbol": "BTCUSDT",
9619
- # "unRealizedProfit": "0.00000000",
9620
- # "positionSide": "BOTH",
9621
9774
  # "updateTime": 0
9622
9775
  # }
9623
9776
  # ]
@@ -9634,27 +9787,13 @@ class binance(Exchange, ImplicitAPI):
9634
9787
  # "liquidationPrice": "5930.78",
9635
9788
  # "markPrice": "6679.50671178",
9636
9789
  # "maxNotionalValue": "20000000",
9637
- # "positionAmt": "20.000",
9790
+ # "positionSide": "LONG",
9791
+ # "positionAmt": "20.000", # negative value for 'SHORT'
9638
9792
  # "symbol": "BTCUSDT",
9639
9793
  # "unRealizedProfit": "2316.83423560"
9640
- # "positionSide": "LONG",
9641
9794
  # "updateTime": 1625474304765
9642
9795
  # },
9643
- # {
9644
- # "entryPrice": "0.00000",
9645
- # "marginType": "isolated",
9646
- # "isAutoAddMargin": "false",
9647
- # "isolatedMargin": "5413.95799991",
9648
- # "leverage": "10",
9649
- # "liquidationPrice": "7189.95",
9650
- # "markPrice": "6679.50671178",
9651
- # "maxNotionalValue": "20000000",
9652
- # "positionAmt": "-10.000",
9653
- # "symbol": "BTCUSDT",
9654
- # "unRealizedProfit": "-1156.46711780",
9655
- # "positionSide": "SHORT",
9656
- # "updateTime": 0
9657
- # }
9796
+ # .. second dict is similar, but with `positionSide: SHORT`
9658
9797
  # ]
9659
9798
  #
9660
9799
  # inverse portfolio margin:
@@ -9698,10 +9837,9 @@ class binance(Exchange, ImplicitAPI):
9698
9837
  result = []
9699
9838
  for i in range(0, len(response)):
9700
9839
  rawPosition = response[i]
9701
- entryPrice = self.safe_string(rawPosition, 'entryPrice')
9702
- if (entryPrice != '0') and (entryPrice != '0.0') and (entryPrice != '0.00000000'):
9703
- parsed = self.parse_position_risk(response[i])
9704
- result.append(parsed)
9840
+ entryPriceString = self.safe_string(rawPosition, 'entryPrice')
9841
+ if Precise.string_gt(entryPriceString, '0'):
9842
+ result.append(self.parse_position_risk(response[i]))
9705
9843
  symbols = self.market_symbols(symbols)
9706
9844
  return self.filter_by_array_positions(result, 'symbol', symbols, False)
9707
9845
 
@@ -10336,7 +10474,7 @@ class binance(Exchange, ImplicitAPI):
10336
10474
  body = self.urlencode(params)
10337
10475
  else:
10338
10476
  raise AuthenticationError(self.id + ' userDataStream endpoint requires `apiKey` credential')
10339
- elif (api == 'private') or (api == 'eapiPrivate') or (api == 'sapi' and path != 'system/status') or (api == 'sapiV2') or (api == 'sapiV3') or (api == 'sapiV4') or (api == 'dapiPrivate') or (api == 'dapiPrivateV2') or (api == 'fapiPrivate') or (api == 'fapiPrivateV2') or (api == 'papi' and path != 'ping'):
10477
+ elif (api == 'private') or (api == 'eapiPrivate') or (api == 'sapi' and path != 'system/status') or (api == 'sapiV2') or (api == 'sapiV3') or (api == 'sapiV4') or (api == 'dapiPrivate') or (api == 'dapiPrivateV2') or (api == 'fapiPrivate') or (api == 'fapiPrivateV2') or (api == 'fapiPrivateV3') or (api == 'papi' and path != 'ping'):
10340
10478
  self.check_required_credentials()
10341
10479
  if method == 'POST' and ((path == 'order') or (path == 'sor/order')):
10342
10480
  # inject in implicit API calls