ccxt 4.4.21__py2.py3-none-any.whl → 4.4.23__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.
Files changed (76) hide show
  1. ccxt/__init__.py +3 -1
  2. ccxt/abstract/binance.py +64 -43
  3. ccxt/abstract/binancecoinm.py +64 -43
  4. ccxt/abstract/binanceus.py +64 -43
  5. ccxt/abstract/binanceusdm.py +64 -43
  6. ccxt/abstract/bitflyer.py +1 -0
  7. ccxt/abstract/bitget.py +3 -0
  8. ccxt/abstract/cex.py +28 -29
  9. ccxt/abstract/coincatch.py +94 -0
  10. ccxt/abstract/gate.py +5 -0
  11. ccxt/abstract/gateio.py +5 -0
  12. ccxt/abstract/kucoin.py +1 -0
  13. ccxt/abstract/kucoinfutures.py +1 -0
  14. ccxt/abstract/okx.py +1 -0
  15. ccxt/alpaca.py +1 -0
  16. ccxt/async_support/__init__.py +3 -1
  17. ccxt/async_support/alpaca.py +1 -0
  18. ccxt/async_support/base/exchange.py +7 -1
  19. ccxt/async_support/bigone.py +3 -0
  20. ccxt/async_support/binance.py +183 -63
  21. ccxt/async_support/bitfinex.py +4 -0
  22. ccxt/async_support/bitflyer.py +57 -1
  23. ccxt/async_support/bitget.py +73 -1
  24. ccxt/async_support/bitrue.py +3 -0
  25. ccxt/async_support/bybit.py +76 -3
  26. ccxt/async_support/cex.py +1247 -1322
  27. ccxt/async_support/coinbase.py +1 -1
  28. ccxt/async_support/coinbaseexchange.py +3 -0
  29. ccxt/async_support/coincatch.py +4955 -0
  30. ccxt/async_support/coinex.py +60 -1
  31. ccxt/async_support/cryptocom.py +1 -1
  32. ccxt/async_support/gate.py +97 -2
  33. ccxt/async_support/htx.py +1 -5
  34. ccxt/async_support/hyperliquid.py +10 -8
  35. ccxt/async_support/kucoin.py +27 -57
  36. ccxt/async_support/latoken.py +6 -0
  37. ccxt/async_support/mexc.py +1 -1
  38. ccxt/async_support/oceanex.py +2 -0
  39. ccxt/async_support/okcoin.py +1 -0
  40. ccxt/async_support/okx.py +67 -1
  41. ccxt/async_support/poloniex.py +5 -0
  42. ccxt/base/exchange.py +21 -1
  43. ccxt/base/types.py +9 -0
  44. ccxt/bigone.py +3 -0
  45. ccxt/binance.py +183 -63
  46. ccxt/bitfinex.py +4 -0
  47. ccxt/bitflyer.py +57 -1
  48. ccxt/bitget.py +73 -1
  49. ccxt/bitrue.py +3 -0
  50. ccxt/bybit.py +76 -3
  51. ccxt/cex.py +1246 -1322
  52. ccxt/coinbase.py +1 -1
  53. ccxt/coinbaseexchange.py +3 -0
  54. ccxt/coincatch.py +4955 -0
  55. ccxt/coinex.py +60 -1
  56. ccxt/cryptocom.py +1 -1
  57. ccxt/gate.py +97 -2
  58. ccxt/htx.py +1 -5
  59. ccxt/hyperliquid.py +10 -8
  60. ccxt/kucoin.py +27 -57
  61. ccxt/latoken.py +6 -0
  62. ccxt/mexc.py +1 -1
  63. ccxt/oceanex.py +2 -0
  64. ccxt/okcoin.py +1 -0
  65. ccxt/okx.py +67 -1
  66. ccxt/poloniex.py +5 -0
  67. ccxt/pro/__init__.py +3 -1
  68. ccxt/pro/coincatch.py +1429 -0
  69. ccxt/test/tests_async.py +19 -5
  70. ccxt/test/tests_sync.py +19 -5
  71. ccxt-4.4.23.dist-info/METADATA +636 -0
  72. {ccxt-4.4.21.dist-info → ccxt-4.4.23.dist-info}/RECORD +75 -71
  73. ccxt-4.4.21.dist-info/METADATA +0 -635
  74. {ccxt-4.4.21.dist-info → ccxt-4.4.23.dist-info}/LICENSE.txt +0 -0
  75. {ccxt-4.4.21.dist-info → ccxt-4.4.23.dist-info}/WHEEL +0 -0
  76. {ccxt-4.4.21.dist-info → ccxt-4.4.23.dist-info}/top_level.txt +0 -0
@@ -59,6 +59,8 @@ class coinex(Exchange, ImplicitAPI):
59
59
  'cancelAllOrders': True,
60
60
  'cancelOrder': True,
61
61
  'cancelOrders': True,
62
+ 'closeAllPositions': False,
63
+ 'closePosition': True,
62
64
  'createDepositAddress': True,
63
65
  'createMarketBuyOrderWithCost': True,
64
66
  'createMarketOrderWithCost': False,
@@ -1730,7 +1732,7 @@ class coinex(Exchange, ImplicitAPI):
1730
1732
  # "stop_id": 117180138153
1731
1733
  # }
1732
1734
  #
1733
- # Swap createOrder, createOrders, editOrder, cancelOrders, cancelOrder, fetchOpenOrders, fetchClosedOrders
1735
+ # Swap createOrder, createOrders, editOrder, cancelOrders, cancelOrder, fetchOpenOrders, fetchClosedOrders, closePosition
1734
1736
  #
1735
1737
  # {
1736
1738
  # "amount": "0.0001",
@@ -5364,6 +5366,63 @@ class coinex(Exchange, ImplicitAPI):
5364
5366
  positions = self.parse_positions(records)
5365
5367
  return self.filter_by_symbol_since_limit(positions, symbol, since, limit)
5366
5368
 
5369
+ async def close_position(self, symbol: str, side: OrderSide = None, params={}) -> Order:
5370
+ """
5371
+ closes an open position for a market
5372
+ :see: https://docs.coinex.com/api/v2/futures/position/http/close-position
5373
+ :param str symbol: unified CCXT market symbol
5374
+ :param str [side]: buy or sell, not used by coinex
5375
+ :param dict [params]: extra parameters specific to the exchange API endpoint
5376
+ :param str params['type']: required by coinex, one of: limit, market, maker_only, ioc or fok, default is *market*
5377
+ :param str [params.price]: the price to fulfill the order, ignored in market orders
5378
+ :param str [params.amount]: the amount to trade in units of the base currency
5379
+ :param str [params.clientOrderId]: the client id of the order
5380
+ :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
5381
+ """
5382
+ await self.load_markets()
5383
+ market = self.market(symbol)
5384
+ type = self.safe_string(params, 'type', 'market')
5385
+ request: dict = {
5386
+ 'market': market['id'],
5387
+ 'market_type': 'FUTURES',
5388
+ 'type': type,
5389
+ }
5390
+ clientOrderId = self.safe_string_2(params, 'client_id', 'clientOrderId')
5391
+ if clientOrderId is not None:
5392
+ request['client_id'] = clientOrderId
5393
+ params = self.omit(params, 'clientOrderId')
5394
+ response = await self.v2PrivatePostFuturesClosePosition(self.extend(request, params))
5395
+ #
5396
+ # {
5397
+ # "code": 0,
5398
+ # "data": {
5399
+ # "amount": "0.0001",
5400
+ # "client_id": "",
5401
+ # "created_at": 1729666043969,
5402
+ # "fee": "0.00335858",
5403
+ # "fee_ccy": "USDT",
5404
+ # "filled_amount": "0.0001",
5405
+ # "filled_value": "6.717179",
5406
+ # "last_filled_amount": "0.0001",
5407
+ # "last_filled_price": "67171.79",
5408
+ # "maker_fee_rate": "0",
5409
+ # "market": "BTCUSDT",
5410
+ # "market_type": "FUTURES",
5411
+ # "order_id": 155477479761,
5412
+ # "price": "0",
5413
+ # "realized_pnl": "-0.001823",
5414
+ # "side": "sell",
5415
+ # "taker_fee_rate": "0.0005",
5416
+ # "type": "market",
5417
+ # "unfilled_amount": "0",
5418
+ # "updated_at": 1729666043969
5419
+ # },
5420
+ # "message": "OK"
5421
+ # }
5422
+ #
5423
+ data = self.safe_dict(response, 'data', {})
5424
+ return self.parse_order(data, market)
5425
+
5367
5426
  def handle_margin_mode_and_params(self, methodName, params={}, defaultValue=None):
5368
5427
  """
5369
5428
  * @ignore
@@ -1496,7 +1496,7 @@ class cryptocom(Exchange, ImplicitAPI):
1496
1496
  paginate = False
1497
1497
  paginate, params = self.handle_option_and_params(params, 'fetchMyTrades', 'paginate')
1498
1498
  if paginate:
1499
- return await self.fetch_paginated_call_dynamic('fetchMyTrades', symbol, since, limit, params)
1499
+ return await self.fetch_paginated_call_dynamic('fetchMyTrades', symbol, since, limit, params, 100)
1500
1500
  request: dict = {}
1501
1501
  market = None
1502
1502
  if symbol is not None:
@@ -340,10 +340,17 @@ class gate(Exchange, ImplicitAPI):
340
340
  'interest_records': 20 / 15,
341
341
  'estimate_rate': 20 / 15,
342
342
  'currency_discount_tiers': 20 / 15,
343
+ 'risk_units': 20 / 15,
344
+ 'unified_mode': 20 / 15,
345
+ 'loan_margin_tiers': 20 / 15,
343
346
  },
344
347
  'post': {
345
348
  'account_mode': 20 / 15,
346
349
  'loans': 200 / 15, # 15r/10s cost = 20 / 1.5 = 13.33
350
+ 'portfolio_calculator': 20 / 15,
351
+ },
352
+ 'put': {
353
+ 'unified_mode': 20 / 15,
347
354
  },
348
355
  },
349
356
  'spot': {
@@ -645,6 +652,7 @@ class gate(Exchange, ImplicitAPI):
645
652
  },
646
653
  'options': {
647
654
  'sandboxMode': False,
655
+ 'unifiedAccount': None,
648
656
  'createOrder': {
649
657
  'expiration': 86400, # for conditional orders
650
658
  },
@@ -906,6 +914,34 @@ class gate(Exchange, ImplicitAPI):
906
914
  super(gate, self).set_sandbox_mode(enable)
907
915
  self.options['sandboxMode'] = enable
908
916
 
917
+ async def load_unified_status(self, params={}):
918
+ """
919
+ returns unifiedAccount so the user can check if the unified account is enabled
920
+ :see: https://www.gate.io/docs/developers/apiv4/#get-account-detail
921
+ :returns boolean: True or False if the enabled unified account is enabled or not and sets the unifiedAccount option if it is None
922
+ """
923
+ unifiedAccount = self.safe_bool(self.options, 'unifiedAccount')
924
+ if unifiedAccount is None:
925
+ response = await self.privateAccountGetDetail(params)
926
+ #
927
+ # {
928
+ # "user_id": 10406147,
929
+ # "ip_whitelist": [],
930
+ # "currency_pairs": [],
931
+ # "key": {
932
+ # "mode": 1
933
+ # },
934
+ # "tier": 0,
935
+ # "tier_expire_time": "0001-01-01T00:00:00Z",
936
+ # "copy_trading_role": 0
937
+ # }
938
+ #
939
+ result = self.safe_dict(response, 'key', {})
940
+ self.options['unifiedAccount'] = self.safe_integer(result, 'mode') == 2
941
+
942
+ async def upgrade_unified_trade_account(self, params={}):
943
+ return await self.privateUnifiedPutUnifiedMode(params)
944
+
909
945
  def create_expired_option_market(self, symbol: str):
910
946
  # support expired option contracts
911
947
  quote = 'USDT'
@@ -1550,6 +1586,8 @@ class gate(Exchange, ImplicitAPI):
1550
1586
  apiBackup = self.safe_value(self.urls, 'apiBackup')
1551
1587
  if apiBackup is not None:
1552
1588
  return None
1589
+ if self.check_required_credentials(False):
1590
+ await self.load_unified_status()
1553
1591
  response = await self.publicSpotGetCurrencies(params)
1554
1592
  #
1555
1593
  # {
@@ -2574,10 +2612,14 @@ class gate(Exchange, ImplicitAPI):
2574
2612
  :param str [params.settle]: 'btc' or 'usdt' - settle currency for perpetual swap and future - default="usdt" for swap and "btc" for future
2575
2613
  :param str [params.marginMode]: 'cross' or 'isolated' - marginMode for margin trading if not provided self.options['defaultMarginMode'] is used
2576
2614
  :param str [params.symbol]: margin only - unified ccxt symbol
2615
+ :param boolean [params.unifiedAccount]: default False, set to True for fetching the unified account balance
2577
2616
  """
2578
2617
  await self.load_markets()
2618
+ await self.load_unified_status()
2579
2619
  symbol = self.safe_string(params, 'symbol')
2580
2620
  params = self.omit(params, 'symbol')
2621
+ isUnifiedAccount = False
2622
+ isUnifiedAccount, params = self.handle_option_and_params(params, 'fetchBalance', 'unifiedAccount')
2581
2623
  type, query = self.handle_market_type_and_params('fetchBalance', None, params)
2582
2624
  request, requestParams = self.prepare_request(None, type, query)
2583
2625
  marginMode, requestQuery = self.get_margin_mode(False, requestParams)
@@ -2585,7 +2627,9 @@ class gate(Exchange, ImplicitAPI):
2585
2627
  market = self.market(symbol)
2586
2628
  request['currency_pair'] = market['id']
2587
2629
  response = None
2588
- if type == 'spot':
2630
+ if isUnifiedAccount:
2631
+ response = await self.privateUnifiedGetAccounts(self.extend(request, params))
2632
+ elif type == 'spot':
2589
2633
  if marginMode == 'spot':
2590
2634
  response = await self.privateSpotGetAccounts(self.extend(request, requestQuery))
2591
2635
  elif marginMode == 'margin':
@@ -2748,12 +2792,63 @@ class gate(Exchange, ImplicitAPI):
2748
2792
  # "orders_limit": 10
2749
2793
  # }
2750
2794
  #
2795
+ # unified
2796
+ #
2797
+ # {
2798
+ # "user_id": 10001,
2799
+ # "locked": False,
2800
+ # "balances": {
2801
+ # "ETH": {
2802
+ # "available": "0",
2803
+ # "freeze": "0",
2804
+ # "borrowed": "0.075393666654",
2805
+ # "negative_liab": "0",
2806
+ # "futures_pos_liab": "0",
2807
+ # "equity": "1016.1",
2808
+ # "total_freeze": "0",
2809
+ # "total_liab": "0"
2810
+ # },
2811
+ # "POINT": {
2812
+ # "available": "9999999999.017023138734",
2813
+ # "freeze": "0",
2814
+ # "borrowed": "0",
2815
+ # "negative_liab": "0",
2816
+ # "futures_pos_liab": "0",
2817
+ # "equity": "12016.1",
2818
+ # "total_freeze": "0",
2819
+ # "total_liab": "0"
2820
+ # },
2821
+ # "USDT": {
2822
+ # "available": "0.00000062023",
2823
+ # "freeze": "0",
2824
+ # "borrowed": "0",
2825
+ # "negative_liab": "0",
2826
+ # "futures_pos_liab": "0",
2827
+ # "equity": "16.1",
2828
+ # "total_freeze": "0",
2829
+ # "total_liab": "0"
2830
+ # }
2831
+ # },
2832
+ # "total": "230.94621713",
2833
+ # "borrowed": "161.66395521",
2834
+ # "total_initial_margin": "1025.0524665088",
2835
+ # "total_margin_balance": "3382495.944473949183",
2836
+ # "total_maintenance_margin": "205.01049330176",
2837
+ # "total_initial_margin_rate": "3299.827135672679",
2838
+ # "total_maintenance_margin_rate": "16499.135678363399",
2839
+ # "total_available_margin": "3381470.892007440383",
2840
+ # "unified_account_total": "3381470.892007440383",
2841
+ # "unified_account_total_liab": "0",
2842
+ # "unified_account_total_equity": "100016.1",
2843
+ # "leverage": "2"
2844
+ # }
2845
+ #
2751
2846
  result: dict = {
2752
2847
  'info': response,
2753
2848
  }
2754
2849
  isolated = marginMode == 'margin'
2755
2850
  data = response
2756
- if 'balances' in data: # True for cross_margin
2851
+ if 'balances' in data: # True for cross_margin and unified
2757
2852
  flatBalances = []
2758
2853
  balances = self.safe_value(data, 'balances', [])
2759
2854
  # inject currency and create an artificial balance object
ccxt/async_support/htx.py CHANGED
@@ -4780,11 +4780,7 @@ class htx(Exchange, ImplicitAPI):
4780
4780
  cost = None
4781
4781
  amount = None
4782
4782
  if (type is not None) and (type.find('market') >= 0):
4783
- # for market orders amount is in quote currency, meaning it is the cost
4784
- if side == 'sell':
4785
- cost = self.safe_string(order, 'field-cash-amount')
4786
- else:
4787
- cost = self.safe_string(order, 'amount')
4783
+ cost = self.safe_string(order, 'field-cash-amount')
4788
4784
  else:
4789
4785
  amount = self.safe_string_2(order, 'volume', 'amount')
4790
4786
  cost = self.safe_string_n(order, ['filled-cash-amount', 'field-cash-amount', 'trade_turnover']) # same typo here
@@ -2113,14 +2113,16 @@ class hyperliquid(Exchange, ImplicitAPI):
2113
2113
  leverage = self.safe_dict(entry, 'leverage', {})
2114
2114
  marginMode = self.safe_string(leverage, 'type')
2115
2115
  isIsolated = (marginMode == 'isolated')
2116
- size = self.safe_string(entry, 'szi')
2116
+ rawSize = self.safe_string(entry, 'szi')
2117
+ size = rawSize
2117
2118
  side = None
2118
2119
  if size is not None:
2119
- side = 'long' if Precise.string_gt(size, '0') else 'short'
2120
+ side = 'long' if Precise.string_gt(rawSize, '0') else 'short'
2120
2121
  size = Precise.string_abs(size)
2121
- unrealizedPnl = self.safe_number(entry, 'unrealizedPnl')
2122
- initialMargin = self.safe_number(entry, 'marginUsed')
2123
- percentage = unrealizedPnl / initialMargin * 100
2122
+ rawUnrealizedPnl = self.safe_string(entry, 'unrealizedPnl')
2123
+ absRawUnrealizedPnl = Precise.string_abs(rawUnrealizedPnl)
2124
+ initialMargin = self.safe_string(entry, 'marginUsed')
2125
+ percentage = Precise.string_mul(Precise.string_div(absRawUnrealizedPnl, initialMargin), '100')
2124
2126
  return self.safe_position({
2125
2127
  'info': position,
2126
2128
  'id': None,
@@ -2130,7 +2132,7 @@ class hyperliquid(Exchange, ImplicitAPI):
2130
2132
  'isolated': isIsolated,
2131
2133
  'hedged': None,
2132
2134
  'side': side,
2133
- 'contracts': size,
2135
+ 'contracts': self.parse_number(size),
2134
2136
  'contractSize': None,
2135
2137
  'entryPrice': self.safe_number(entry, 'entryPx'),
2136
2138
  'markPrice': None,
@@ -2141,10 +2143,10 @@ class hyperliquid(Exchange, ImplicitAPI):
2141
2143
  'maintenanceMargin': None,
2142
2144
  'initialMarginPercentage': None,
2143
2145
  'maintenanceMarginPercentage': None,
2144
- 'unrealizedPnl': unrealizedPnl,
2146
+ 'unrealizedPnl': self.parse_number(rawUnrealizedPnl),
2145
2147
  'liquidationPrice': self.safe_number(entry, 'liquidationPx'),
2146
2148
  'marginMode': marginMode,
2147
- 'percentage': percentage,
2149
+ 'percentage': self.parse_number(percentage),
2148
2150
  })
2149
2151
 
2150
2152
  async def set_margin_mode(self, marginMode: str, symbol: Str = None, params={}):
@@ -308,6 +308,7 @@ class kucoin(Exchange, ImplicitAPI):
308
308
  # ws
309
309
  'bullet-private': 10, # 10SW
310
310
  'position/update-user-leverage': 5,
311
+ 'deposit-address/create': 20,
311
312
  },
312
313
  'delete': {
313
314
  # account
@@ -727,6 +728,7 @@ class kucoin(Exchange, ImplicitAPI):
727
728
  'accounts/sub-transfer': 'v2',
728
729
  'accounts/inner-transfer': 'v2',
729
730
  'transfer-out': 'v3',
731
+ 'deposit-address/create': 'v3',
730
732
  # spot trading
731
733
  'oco/order': 'v3',
732
734
  # margin trading
@@ -738,6 +740,7 @@ class kucoin(Exchange, ImplicitAPI):
738
740
  'redeem': 'v3',
739
741
  'lend/purchase/update': 'v3',
740
742
  'position/update-user-leverage': 'v3',
743
+ 'withdrawals': 'v3',
741
744
  },
742
745
  'DELETE': {
743
746
  # account
@@ -803,7 +806,7 @@ class kucoin(Exchange, ImplicitAPI):
803
806
  'TLOS': 'tlos', # tlosevm is different
804
807
  'CFX': 'cfx',
805
808
  'ACA': 'aca',
806
- 'OPTIMISM': 'optimism',
809
+ 'OP': 'optimism',
807
810
  'ONT': 'ont',
808
811
  'GLMR': 'glmr',
809
812
  'CSPR': 'cspr',
@@ -1863,7 +1866,7 @@ class kucoin(Exchange, ImplicitAPI):
1863
1866
 
1864
1867
  async def create_deposit_address(self, code: str, params={}):
1865
1868
  """
1866
- :see: https://docs.kucoin.com/#create-deposit-address
1869
+ :see: https://www.kucoin.com/docs/rest/funding/deposit/create-deposit-address-v3-
1867
1870
  create a currency deposit address
1868
1871
  :param str code: unified currency code of the currency for the deposit address
1869
1872
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -1878,11 +1881,23 @@ class kucoin(Exchange, ImplicitAPI):
1878
1881
  networkCode = None
1879
1882
  networkCode, params = self.handle_network_code_and_params(params)
1880
1883
  if networkCode is not None:
1881
- request['chain'] = self.network_code_to_id(networkCode).lower()
1882
- response = await self.privatePostDepositAddresses(self.extend(request, params))
1884
+ request['chain'] = self.network_code_to_id(networkCode) # docs mention "chain-name", but seems "chain-id" is used, like in "fetchDepositAddress"
1885
+ response = await self.privatePostDepositAddressCreate(self.extend(request, params))
1883
1886
  # {"code":"260000","msg":"Deposit address already exists."}
1884
- # BCH {"code":"200000","data":{"address":"bitcoincash:qza3m4nj9rx7l9r0cdadfqxts6f92shvhvr5ls4q7z","memo":""}}
1885
- # BTC {"code":"200000","data":{"address":"36SjucKqQpQSvsak9A7h6qzFjrVXpRNZhE","memo":""}}
1887
+ #
1888
+ # {
1889
+ # "code": "200000",
1890
+ # "data": {
1891
+ # "address": "0x2336d1834faab10b2dac44e468f2627138417431",
1892
+ # "memo": null,
1893
+ # "chainId": "bsc",
1894
+ # "to": "MAIN",
1895
+ # "expirationDate": 0,
1896
+ # "currency": "BNB",
1897
+ # "chainName": "BEP20"
1898
+ # }
1899
+ # }
1900
+ #
1886
1901
  data = self.safe_dict(response, 'data', {})
1887
1902
  return self.parse_deposit_address(data, currency)
1888
1903
 
@@ -1932,7 +1947,7 @@ class kucoin(Exchange, ImplicitAPI):
1932
1947
  return {
1933
1948
  'info': depositAddress,
1934
1949
  'currency': code,
1935
- 'network': self.network_id_to_code(self.safe_string(depositAddress, 'chain')),
1950
+ 'network': self.network_id_to_code(self.safe_string(depositAddress, 'chainId')),
1936
1951
  'address': address,
1937
1952
  'tag': self.safe_string(depositAddress, 'memo'),
1938
1953
  }
@@ -3239,7 +3254,7 @@ class kucoin(Exchange, ImplicitAPI):
3239
3254
  async def withdraw(self, code: str, amount: float, address: str, tag=None, params={}):
3240
3255
  """
3241
3256
  make a withdrawal
3242
- :see: https://www.kucoin.com/docs/rest/funding/withdrawals/apply-withdraw
3257
+ :see: https://www.kucoin.com/docs/rest/funding/withdrawals/apply-withdraw-v3-
3243
3258
  :param str code: unified currency code
3244
3259
  :param float amount: the amount to withdraw
3245
3260
  :param str address: the address to withdraw to
@@ -3253,7 +3268,8 @@ class kucoin(Exchange, ImplicitAPI):
3253
3268
  currency = self.currency(code)
3254
3269
  request: dict = {
3255
3270
  'currency': currency['id'],
3256
- 'address': address,
3271
+ 'toAddress': address,
3272
+ 'withdrawType': 'ADDRESS',
3257
3273
  # 'memo': tag,
3258
3274
  # 'isInner': False, # internal transfer or external withdrawal
3259
3275
  # 'remark': 'optional',
@@ -3265,15 +3281,14 @@ class kucoin(Exchange, ImplicitAPI):
3265
3281
  networkCode, params = self.handle_network_code_and_params(params)
3266
3282
  if networkCode is not None:
3267
3283
  request['chain'] = self.network_code_to_id(networkCode).lower()
3268
- await self.load_currency_precision(currency, networkCode)
3269
- request['amount'] = self.currency_to_precision(code, amount, networkCode)
3284
+ request['amount'] = float(self.currency_to_precision(code, amount, networkCode))
3270
3285
  includeFee = None
3271
3286
  includeFee, params = self.handle_option_and_params(params, 'withdraw', 'includeFee', False)
3272
3287
  if includeFee:
3273
3288
  request['feeDeductType'] = 'INTERNAL'
3274
3289
  response = await self.privatePostWithdrawals(self.extend(request, params))
3275
3290
  #
3276
- # https://github.com/ccxt/ccxt/issues/5558
3291
+ # the id is inside "data"
3277
3292
  #
3278
3293
  # {
3279
3294
  # "code": 200000,
@@ -3285,51 +3300,6 @@ class kucoin(Exchange, ImplicitAPI):
3285
3300
  data = self.safe_dict(response, 'data', {})
3286
3301
  return self.parse_transaction(data, currency)
3287
3302
 
3288
- async def load_currency_precision(self, currency, networkCode: Str = None):
3289
- # might not have network specific precisions defined in fetchCurrencies(because of webapi failure)
3290
- # we should check and refetch precision once-per-instance for that specific currency & network
3291
- # so avoids thorwing exceptions and burden to users
3292
- # Note: self needs to be executed only if networkCode was provided
3293
- if networkCode is not None:
3294
- networks = currency['networks']
3295
- network = self.safe_dict(networks, networkCode)
3296
- if self.safe_number(network, 'precision') is not None:
3297
- # if precision exists, no need to refetch
3298
- return
3299
- # otherwise try to fetch and store in instance
3300
- request: dict = {
3301
- 'currency': currency['id'],
3302
- 'chain': self.network_code_to_id(networkCode).lower(),
3303
- }
3304
- response = await self.privateGetWithdrawalsQuotas(request)
3305
- #
3306
- # {
3307
- # "code": "200000",
3308
- # "data": {
3309
- # "currency": "USDT",
3310
- # "limitBTCAmount": "14.24094850",
3311
- # "usedBTCAmount": "0.00000000",
3312
- # "quotaCurrency": "USDT",
3313
- # "limitQuotaCurrencyAmount": "999999.00000000",
3314
- # "usedQuotaCurrencyAmount": "0",
3315
- # "remainAmount": "999999.0000",
3316
- # "availableAmount": "10.77545071",
3317
- # "withdrawMinFee": "1",
3318
- # "innerWithdrawMinFee": "0",
3319
- # "withdrawMinSize": "10",
3320
- # "isWithdrawEnabled": True,
3321
- # "precision": 4,
3322
- # "chain": "EOS",
3323
- # "reason": null,
3324
- # "lockedAmount": "0"
3325
- # }
3326
- # }
3327
- #
3328
- data = self.safe_dict(response, 'data', {})
3329
- precision = self.parse_number(self.parse_precision(self.safe_string(data, 'precision')))
3330
- code = currency['code']
3331
- self.currencies[code]['networks'][networkCode]['precision'] = precision
3332
-
3333
3303
  def parse_transaction_status(self, status: Str):
3334
3304
  statuses: dict = {
3335
3305
  'SUCCESS': 'ok',
@@ -60,6 +60,12 @@ class latoken(Exchange, ImplicitAPI):
60
60
  'fetchDepositAddressesByNetwork': False,
61
61
  'fetchDepositsWithdrawals': True,
62
62
  'fetchDepositWithdrawFees': False,
63
+ 'fetchFundingHistory': False,
64
+ 'fetchFundingInterval': False,
65
+ 'fetchFundingIntervals': False,
66
+ 'fetchFundingRate': False,
67
+ 'fetchFundingRateHistory': False,
68
+ 'fetchFundingRates': False,
63
69
  'fetchIsolatedBorrowRate': False,
64
70
  'fetchIsolatedBorrowRates': False,
65
71
  'fetchMarginMode': False,
@@ -94,7 +94,7 @@ class mexc(Exchange, ImplicitAPI):
94
94
  'fetchFundingIntervals': False,
95
95
  'fetchFundingRate': True,
96
96
  'fetchFundingRateHistory': True,
97
- 'fetchFundingRates': None,
97
+ 'fetchFundingRates': False,
98
98
  'fetchIndexOHLCV': True,
99
99
  'fetchIsolatedBorrowRate': False,
100
100
  'fetchIsolatedBorrowRates': False,
@@ -57,6 +57,8 @@ class oceanex(Exchange, ImplicitAPI):
57
57
  'fetchDepositAddress': 'emulated',
58
58
  'fetchDepositAddresses': None,
59
59
  'fetchDepositAddressesByNetwork': True,
60
+ 'fetchFundingRateHistory': False,
61
+ 'fetchFundingRates': False,
60
62
  'fetchIsolatedBorrowRate': False,
61
63
  'fetchIsolatedBorrowRates': False,
62
64
  'fetchMarkets': True,
@@ -72,6 +72,7 @@ class okcoin(Exchange, ImplicitAPI):
72
72
  'fetchFundingHistory': False,
73
73
  'fetchFundingRate': False,
74
74
  'fetchFundingRateHistory': False,
75
+ 'fetchFundingRates': False,
75
76
  'fetchLedger': True,
76
77
  'fetchMarkets': True,
77
78
  'fetchMyTrades': True,
ccxt/async_support/okx.py CHANGED
@@ -7,7 +7,7 @@ from ccxt.async_support.base.exchange import Exchange
7
7
  from ccxt.abstract.okx import ImplicitAPI
8
8
  import asyncio
9
9
  import hashlib
10
- from ccxt.base.types import Account, Balances, Conversion, CrossBorrowRate, CrossBorrowRates, Currencies, Currency, DepositAddress, Greeks, Int, LedgerEntry, Leverage, LeverageTier, MarginModification, Market, MarketInterface, Num, Option, OptionChain, Order, OrderBook, OrderRequest, CancellationRequest, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, FundingRate, Trade, TradingFeeInterface, Transaction, TransferEntry
10
+ from ccxt.base.types import Account, LongShortRatio, Balances, Conversion, CrossBorrowRate, CrossBorrowRates, Currencies, Currency, DepositAddress, Greeks, Int, LedgerEntry, Leverage, LeverageTier, MarginModification, Market, MarketInterface, Num, Option, OptionChain, Order, OrderBook, OrderRequest, CancellationRequest, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, FundingRate, Trade, TradingFeeInterface, Transaction, TransferEntry
11
11
  from typing import List
12
12
  from typing import Any
13
13
  from ccxt.base.errors import ExchangeError
@@ -120,6 +120,8 @@ class okx(Exchange, ImplicitAPI):
120
120
  'fetchLedgerEntry': None,
121
121
  'fetchLeverage': True,
122
122
  'fetchLeverageTiers': False,
123
+ 'fetchLongShortRatio': False,
124
+ 'fetchLongShortRatioHistory': True,
123
125
  'fetchMarginAdjustmentHistory': True,
124
126
  'fetchMarketLeverageTiers': True,
125
127
  'fetchMarkets': True,
@@ -262,6 +264,7 @@ class okx(Exchange, ImplicitAPI):
262
264
  'rubik/stat/margin/loan-ratio': 4,
263
265
  # long/short
264
266
  'rubik/stat/contracts/long-short-account-ratio': 4,
267
+ 'rubik/stat/contracts/long-short-account-ratio-contract': 4,
265
268
  'rubik/stat/contracts/open-interest-volume': 4,
266
269
  'rubik/stat/option/open-interest-volume': 4,
267
270
  # put/call
@@ -7930,3 +7933,66 @@ class okx(Exchange, ImplicitAPI):
7930
7933
  data = self.safe_list(response, 'data')
7931
7934
  positions = self.parse_positions(data, symbols, params)
7932
7935
  return self.filter_by_since_limit(positions, since, limit)
7936
+
7937
+ async def fetch_long_short_ratio_history(self, symbol: Str = None, timeframe: Str = None, since: Int = None, limit: Int = None, params={}) -> List[LongShortRatio]:
7938
+ """
7939
+ fetches the long short ratio history for a unified market symbol
7940
+ :see: https://www.okx.com/docs-v5/en/#trading-statistics-rest-api-get-contract-long-short-ratio
7941
+ :param str symbol: unified symbol of the market to fetch the long short ratio for
7942
+ :param str [timeframe]: the period for the ratio
7943
+ :param int [since]: the earliest time in ms to fetch ratios for
7944
+ :param int [limit]: the maximum number of long short ratio structures to retrieve
7945
+ :param dict [params]: extra parameters specific to the exchange API endpoint
7946
+ :param int [params.until]: timestamp in ms of the latest ratio to fetch
7947
+ :returns dict[]: an array of `long short ratio structures <https://docs.ccxt.com/#/?id=long-short-ratio-structure>`
7948
+ """
7949
+ await self.load_markets()
7950
+ market = self.market(symbol)
7951
+ request: dict = {
7952
+ 'instId': market['id'],
7953
+ }
7954
+ until = self.safe_string_2(params, 'until', 'end')
7955
+ params = self.omit(params, 'until')
7956
+ if until is not None:
7957
+ request['end'] = until
7958
+ if timeframe is not None:
7959
+ request['period'] = timeframe
7960
+ if since is not None:
7961
+ request['begin'] = since
7962
+ if limit is not None:
7963
+ request['limit'] = limit
7964
+ response = await self.publicGetRubikStatContractsLongShortAccountRatioContract(self.extend(request, params))
7965
+ #
7966
+ # {
7967
+ # "code": "0",
7968
+ # "data": [
7969
+ # ["1729323600000", "0.9398602814619824"],
7970
+ # ["1729323300000", "0.9398602814619824"],
7971
+ # ["1729323000000", "0.9398602814619824"],
7972
+ # ],
7973
+ # "msg": ""
7974
+ # }
7975
+ #
7976
+ data = self.safe_list(response, 'data', [])
7977
+ result = []
7978
+ for i in range(0, len(data)):
7979
+ entry = data[i]
7980
+ result.append({
7981
+ 'timestamp': self.safe_string(entry, 0),
7982
+ 'longShortRatio': self.safe_string(entry, 1),
7983
+ })
7984
+ return self.parse_long_short_ratio_history(result, market)
7985
+
7986
+ def parse_long_short_ratio(self, info: dict, market: Market = None) -> LongShortRatio:
7987
+ timestamp = self.safe_integer(info, 'timestamp')
7988
+ symbol = None
7989
+ if market is not None:
7990
+ symbol = market['symbol']
7991
+ return {
7992
+ 'info': info,
7993
+ 'symbol': symbol,
7994
+ 'timestamp': timestamp,
7995
+ 'datetime': self.iso8601(timestamp),
7996
+ 'timeframe': None,
7997
+ 'longShortRatio': self.safe_number(info, 'longShortRatio'),
7998
+ }
@@ -62,7 +62,12 @@ class poloniex(Exchange, ImplicitAPI):
62
62
  'fetchDepositsWithdrawals': True,
63
63
  'fetchDepositWithdrawFee': 'emulated',
64
64
  'fetchDepositWithdrawFees': True,
65
+ 'fetchFundingHistory': False,
66
+ 'fetchFundingInterval': False,
67
+ 'fetchFundingIntervals': False,
65
68
  'fetchFundingRate': False,
69
+ 'fetchFundingRateHistory': False,
70
+ 'fetchFundingRates': False,
66
71
  'fetchMarginMode': False,
67
72
  'fetchMarkets': True,
68
73
  'fetchMyTrades': True,