ccxt 4.4.37__py2.py3-none-any.whl → 4.4.39__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 (49) hide show
  1. ccxt/__init__.py +1 -1
  2. ccxt/abstract/bingx.py +0 -1
  3. ccxt/abstract/digifinex.py +1 -0
  4. ccxt/abstract/mexc.py +1 -0
  5. ccxt/abstract/woo.py +2 -2
  6. ccxt/alpaca.py +74 -3
  7. ccxt/async_support/__init__.py +1 -1
  8. ccxt/async_support/alpaca.py +74 -3
  9. ccxt/async_support/base/exchange.py +1 -1
  10. ccxt/async_support/binance.py +0 -2
  11. ccxt/async_support/bingx.py +89 -8
  12. ccxt/async_support/bitget.py +2 -4
  13. ccxt/async_support/bithumb.py +1 -1
  14. ccxt/async_support/bitmart.py +160 -13
  15. ccxt/async_support/bybit.py +3 -2
  16. ccxt/async_support/digifinex.py +57 -18
  17. ccxt/async_support/htx.py +154 -32
  18. ccxt/async_support/kucoin.py +76 -2
  19. ccxt/async_support/kucoinfutures.py +92 -5
  20. ccxt/async_support/mexc.py +36 -25
  21. ccxt/async_support/ndax.py +5 -1
  22. ccxt/async_support/okx.py +1 -1
  23. ccxt/async_support/probit.py +3 -1
  24. ccxt/async_support/woo.py +6 -6
  25. ccxt/base/exchange.py +24 -11
  26. ccxt/binance.py +0 -2
  27. ccxt/bingx.py +89 -8
  28. ccxt/bitget.py +2 -4
  29. ccxt/bithumb.py +1 -1
  30. ccxt/bitmart.py +160 -13
  31. ccxt/bybit.py +3 -2
  32. ccxt/digifinex.py +57 -18
  33. ccxt/htx.py +154 -32
  34. ccxt/kucoin.py +76 -2
  35. ccxt/kucoinfutures.py +92 -5
  36. ccxt/mexc.py +36 -25
  37. ccxt/ndax.py +5 -1
  38. ccxt/okx.py +1 -1
  39. ccxt/pro/__init__.py +1 -1
  40. ccxt/pro/woo.py +1 -1
  41. ccxt/probit.py +3 -1
  42. ccxt/test/tests_async.py +5 -1
  43. ccxt/test/tests_sync.py +5 -1
  44. ccxt/woo.py +6 -6
  45. {ccxt-4.4.37.dist-info → ccxt-4.4.39.dist-info}/METADATA +4 -4
  46. {ccxt-4.4.37.dist-info → ccxt-4.4.39.dist-info}/RECORD +49 -49
  47. {ccxt-4.4.37.dist-info → ccxt-4.4.39.dist-info}/LICENSE.txt +0 -0
  48. {ccxt-4.4.37.dist-info → ccxt-4.4.39.dist-info}/WHEEL +0 -0
  49. {ccxt-4.4.37.dist-info → ccxt-4.4.39.dist-info}/top_level.txt +0 -0
ccxt/bitmart.py CHANGED
@@ -704,6 +704,151 @@ class bitmart(Exchange, ImplicitAPI):
704
704
  'createMarketBuyOrderRequiresPrice': True,
705
705
  'brokerId': 'CCXTxBitmart000',
706
706
  },
707
+ 'features': {
708
+ 'default': {
709
+ 'sandbox': False,
710
+ 'createOrder': {
711
+ 'marginMode': True,
712
+ 'triggerPrice': False,
713
+ 'triggerPriceType': None,
714
+ 'triggerDirection': False,
715
+ 'stopLossPrice': False,
716
+ 'takeProfitPrice': False,
717
+ 'attachedStopLossTakeProfit': None,
718
+ 'timeInForce': {
719
+ 'IOC': True,
720
+ 'FOK': False,
721
+ 'PO': True,
722
+ 'GTD': False,
723
+ },
724
+ 'hedged': False,
725
+ 'trailing': False,
726
+ 'marketBuyRequiresPrice': True,
727
+ 'marketBuyByCost': True,
728
+ # exchange-supported features
729
+ # 'leverage': True,
730
+ # 'selfTradePrevention': False,
731
+ # 'twap': False,
732
+ # 'iceberg': False,
733
+ # 'oco': False,
734
+ },
735
+ 'createOrders': {
736
+ 'max': 10,
737
+ },
738
+ 'fetchMyTrades': {
739
+ 'marginMode': True,
740
+ 'limit': 200,
741
+ 'daysBack': None,
742
+ 'untilDays': 99999,
743
+ },
744
+ 'fetchOrder': {
745
+ 'marginMode': False,
746
+ 'trigger': False,
747
+ 'trailing': False,
748
+ },
749
+ 'fetchOpenOrders': {
750
+ 'marginMode': True,
751
+ 'limit': 200,
752
+ 'trigger': False,
753
+ 'trailing': False,
754
+ },
755
+ 'fetchOrders': None,
756
+ 'fetchClosedOrders': {
757
+ 'marginMode': True,
758
+ 'limit': 200,
759
+ 'daysBackClosed': None,
760
+ 'daysBackCanceled': None,
761
+ 'untilDays': None,
762
+ 'trigger': False,
763
+ 'trailing': False,
764
+ },
765
+ 'fetchOHLCV': {
766
+ 'limit': 1000, # variable timespans for recent endpoint, 200 for historical
767
+ },
768
+ },
769
+ 'forDerivatives': {
770
+ 'extends': 'default',
771
+ 'createOrder': {
772
+ 'marginMode': True,
773
+ 'triggerPrice': True,
774
+ 'triggerPriceType': {
775
+ 'last': True,
776
+ 'mark': True,
777
+ 'index': False,
778
+ },
779
+ 'triggerDirection': True, # todo: implementation broken
780
+ 'stopLossPrice': True,
781
+ 'takeProfitPrice': True,
782
+ 'attachedStopLossTakeProfit': {
783
+ 'triggerPriceType': {
784
+ 'last': True,
785
+ 'mark': True,
786
+ 'index': False,
787
+ },
788
+ 'limitPrice': False,
789
+ },
790
+ 'timeInForce': {
791
+ 'IOC': True,
792
+ 'FOK': True,
793
+ 'PO': True,
794
+ 'GTD': False,
795
+ },
796
+ 'hedged': False,
797
+ 'trailing': True,
798
+ 'marketBuyRequiresPrice': True,
799
+ 'marketBuyByCost': True,
800
+ # exchange-supported features
801
+ # 'selfTradePrevention': True,
802
+ # 'twap': False,
803
+ # 'iceberg': False,
804
+ # 'oco': False,
805
+ },
806
+ 'fetchMyTrades': {
807
+ 'marginMode': True,
808
+ 'limit': None,
809
+ 'daysBack': None,
810
+ 'untilDays': 99999,
811
+ },
812
+ 'fetchOrder': {
813
+ 'marginMode': False,
814
+ 'trigger': False,
815
+ 'trailing': True,
816
+ },
817
+ 'fetchOpenOrders': {
818
+ 'marginMode': False,
819
+ 'limit': 100,
820
+ 'trigger': True,
821
+ 'trailing': False,
822
+ },
823
+ 'fetchClosedOrders': {
824
+ 'marginMode': True,
825
+ 'limit': 200,
826
+ 'daysBackClosed': None,
827
+ 'daysBackCanceled': None,
828
+ 'untilDays': None,
829
+ 'trigger': False,
830
+ 'trailing': False,
831
+ },
832
+ 'fetchOHLCV': {
833
+ 'limit': 500,
834
+ },
835
+ },
836
+ 'spot': {
837
+ 'extends': 'default',
838
+ },
839
+ 'swap': {
840
+ 'linear': {
841
+ 'extends': 'forDerivatives',
842
+ },
843
+ 'inverse': {
844
+ 'extends': 'forDerivatives',
845
+ },
846
+ },
847
+ 'future': {
848
+ 'linear': None,
849
+ 'inverse': None,
850
+ },
851
+ },
707
852
  })
708
853
 
709
854
  def fetch_time(self, params={}):
@@ -1906,10 +2051,11 @@ class bitmart(Exchange, ImplicitAPI):
1906
2051
  if marginMode == 'isolated':
1907
2052
  request['orderMode'] = 'iso_margin'
1908
2053
  options = self.safe_dict(self.options, 'fetchMyTrades', {})
1909
- defaultLimit = self.safe_integer(options, 'limit', 200)
2054
+ maxLimit = 200
2055
+ defaultLimit = self.safe_integer(options, 'limit', maxLimit)
1910
2056
  if limit is None:
1911
2057
  limit = defaultLimit
1912
- request['limit'] = limit
2058
+ request['limit'] = min(limit, maxLimit)
1913
2059
  if since is not None:
1914
2060
  request['startTime'] = since
1915
2061
  if until is not None:
@@ -2549,8 +2695,7 @@ class bitmart(Exchange, ImplicitAPI):
2549
2695
  """
2550
2696
  @ignore
2551
2697
  create a trade order
2552
- https://developer-pro.bitmart.com/en/futures/#submit-order-signed
2553
- https://developer-pro.bitmart.com/en/futures/#submit-plan-order-signed
2698
+ https://developer-pro.bitmart.com/en/futuresv2/#submit-order-signed
2554
2699
  https://developer-pro.bitmart.com/en/futuresv2/#submit-plan-order-signed
2555
2700
  https://developer-pro.bitmart.com/en/futuresv2/#submit-tp-or-sl-order-signed
2556
2701
  :param str symbol: unified symbol of the market to create an order in
@@ -2996,12 +3141,12 @@ class bitmart(Exchange, ImplicitAPI):
2996
3141
  if symbol is not None:
2997
3142
  market = self.market(symbol)
2998
3143
  request['symbol'] = market['id']
2999
- if limit is not None:
3000
- request['limit'] = limit
3001
3144
  type = None
3002
3145
  response = None
3003
3146
  type, params = self.handle_market_type_and_params('fetchOpenOrders', market, params)
3004
3147
  if type == 'spot':
3148
+ if limit is not None:
3149
+ request['limit'] = min(limit, 200)
3005
3150
  marginMode = None
3006
3151
  marginMode, params = self.handle_margin_mode_and_params('fetchOpenOrders', params)
3007
3152
  if marginMode == 'isolated':
@@ -3014,9 +3159,11 @@ class bitmart(Exchange, ImplicitAPI):
3014
3159
  request['endTime'] = until
3015
3160
  response = self.privatePostSpotV4QueryOpenOrders(self.extend(request, params))
3016
3161
  elif type == 'swap':
3017
- isStop = self.safe_bool_2(params, 'stop', 'trigger')
3162
+ if limit is not None:
3163
+ request['limit'] = min(limit, 100)
3164
+ isTrigger = self.safe_bool_2(params, 'stop', 'trigger')
3018
3165
  params = self.omit(params, ['stop', 'trigger'])
3019
- if isStop:
3166
+ if isTrigger:
3020
3167
  response = self.privateGetContractPrivateCurrentPlanOrder(self.extend(request, params))
3021
3168
  else:
3022
3169
  trailing = self.safe_bool(params, 'trailing', False)
@@ -3113,12 +3260,8 @@ class bitmart(Exchange, ImplicitAPI):
3113
3260
  if type != 'spot':
3114
3261
  if symbol is None:
3115
3262
  raise ArgumentsRequired(self.id + ' fetchClosedOrders() requires a symbol argument')
3116
- marginMode = None
3117
- marginMode, params = self.handle_margin_mode_and_params('fetchClosedOrders', params)
3118
- if marginMode == 'isolated':
3119
- request['orderMode'] = 'iso_margin'
3120
- startTimeKey = 'startTime' if (type == 'spot') else 'start_time'
3121
3263
  if since is not None:
3264
+ startTimeKey = 'startTime' if (type == 'spot') else 'start_time'
3122
3265
  request[startTimeKey] = since
3123
3266
  endTimeKey = 'endTime' if (type == 'spot') else 'end_time'
3124
3267
  until = self.safe_integer_2(params, 'until', endTimeKey)
@@ -3127,6 +3270,10 @@ class bitmart(Exchange, ImplicitAPI):
3127
3270
  request[endTimeKey] = until
3128
3271
  response = None
3129
3272
  if type == 'spot':
3273
+ marginMode = None
3274
+ marginMode, params = self.handle_margin_mode_and_params('fetchClosedOrders', params)
3275
+ if marginMode == 'isolated':
3276
+ request['orderMode'] = 'iso_margin'
3130
3277
  response = self.privatePostSpotV4QueryHistoryOrders(self.extend(request, params))
3131
3278
  else:
3132
3279
  response = self.privateGetContractPrivateOrderHistory(self.extend(request, params))
ccxt/bybit.py CHANGED
@@ -676,6 +676,9 @@ class bybit(Exchange, ImplicitAPI):
676
676
  '110071': ExchangeError, # Sorry, we're revamping the Unified Margin Account! Currently, new upgrades are not supported. If you have any questions, please contact our 24/7 customer support.
677
677
  '110072': InvalidOrder, # OrderLinkedID is duplicate
678
678
  '110073': ExchangeError, # Set margin mode failed
679
+ '110092': InvalidOrder, # expect Rising, but trigger_price[XXXXX] <= current[XXXXX]
680
+ '110093': InvalidOrder, # expect Falling, but trigger_price[XXXXX] >= current[XXXXX]
681
+ '110094': InvalidOrder, # Order notional value below the lower limit
679
682
  '130006': InvalidOrder, # {"ret_code":130006,"ret_msg":"The number of contracts exceeds maximum limit allowed: too large","ext_code":"","ext_info":"","result":null,"time_now":"1658397095.099030","rate_limit_status":99,"rate_limit_reset_ms":1658397095097,"rate_limit":100}
680
683
  '130021': InsufficientFunds, # {"ret_code":130021,"ret_msg":"orderfix price failed for CannotAffordOrderCost.","ext_code":"","ext_info":"","result":null,"time_now":"1644588250.204878","rate_limit_status":98,"rate_limit_reset_ms":1644588250200,"rate_limit":100} | {"ret_code":130021,"ret_msg":"oc_diff[1707966351], new_oc[1707966351] with ob[....]+AB[....]","ext_code":"","ext_info":"","result":null,"time_now":"1658395300.872766","rate_limit_status":99,"rate_limit_reset_ms":1658395300855,"rate_limit":100} caused issues/9149#issuecomment-1146559498
681
684
  '130074': InvalidOrder, # {"ret_code":130074,"ret_msg":"expect Rising, but trigger_price[190000000] \u003c= current[211280000]??LastPrice","ext_code":"","ext_info":"","result":null,"time_now":"1655386638.067076","rate_limit_status":97,"rate_limit_reset_ms":1655386638065,"rate_limit":100}
@@ -1115,7 +1118,6 @@ class bybit(Exchange, ImplicitAPI):
1115
1118
  'limitPrice': True,
1116
1119
  },
1117
1120
  'timeInForce': {
1118
- 'GTC': True,
1119
1121
  'IOC': True,
1120
1122
  'FOK': True,
1121
1123
  'PO': True,
@@ -1177,7 +1179,6 @@ class bybit(Exchange, ImplicitAPI):
1177
1179
  'limitPrice': True,
1178
1180
  },
1179
1181
  'timeInForce': {
1180
- 'GTC': True,
1181
1182
  'IOC': True,
1182
1183
  'FOK': True,
1183
1184
  'PO': True,
ccxt/digifinex.py CHANGED
@@ -230,6 +230,7 @@ class digifinex(Exchange, ImplicitAPI):
230
230
  'trade/order_info',
231
231
  ],
232
232
  'post': [
233
+ 'account/transfer',
233
234
  'account/leverage',
234
235
  'account/position_mode',
235
236
  'account/position_margin',
@@ -2748,12 +2749,23 @@ class digifinex(Exchange, ImplicitAPI):
2748
2749
 
2749
2750
  def parse_transfer(self, transfer: dict, currency: Currency = None) -> TransferEntry:
2750
2751
  #
2751
- # transfer
2752
+ # transfer between spot, margin and OTC
2752
2753
  #
2753
2754
  # {
2754
2755
  # "code": 0
2755
2756
  # }
2756
2757
  #
2758
+ # transfer between spot and swap
2759
+ #
2760
+ # {
2761
+ # "code": 0,
2762
+ # "data": {
2763
+ # "type": 2,
2764
+ # "currency": "USDT",
2765
+ # "transfer_amount": "5"
2766
+ # }
2767
+ # }
2768
+ #
2757
2769
  # fetchTransfers
2758
2770
  #
2759
2771
  # {
@@ -2766,7 +2778,8 @@ class digifinex(Exchange, ImplicitAPI):
2766
2778
  #
2767
2779
  fromAccount = None
2768
2780
  toAccount = None
2769
- type = self.safe_integer(transfer, 'type')
2781
+ data = self.safe_dict(transfer, 'data', transfer)
2782
+ type = self.safe_integer(data, 'type')
2770
2783
  if type == 1:
2771
2784
  fromAccount = 'spot'
2772
2785
  toAccount = 'swap'
@@ -2779,8 +2792,8 @@ class digifinex(Exchange, ImplicitAPI):
2779
2792
  'id': self.safe_string(transfer, 'transfer_id'),
2780
2793
  'timestamp': timestamp,
2781
2794
  'datetime': self.iso8601(timestamp),
2782
- 'currency': self.safe_currency_code(self.safe_string(transfer, 'currency'), currency),
2783
- 'amount': self.safe_number(transfer, 'amount'),
2795
+ 'currency': self.safe_currency_code(self.safe_string(data, 'currency'), currency),
2796
+ 'amount': self.safe_number_2(data, 'amount', 'transfer_amount'),
2784
2797
  'fromAccount': fromAccount,
2785
2798
  'toAccount': toAccount,
2786
2799
  'status': self.parse_transfer_status(self.safe_string(transfer, 'code')),
@@ -2789,30 +2802,56 @@ class digifinex(Exchange, ImplicitAPI):
2789
2802
  def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}) -> TransferEntry:
2790
2803
  """
2791
2804
  transfer currency internally between wallets on the same account
2805
+
2806
+ https://docs.digifinex.com/en-ww/spot/v3/rest.html#transfer-assets-among-accounts
2807
+ https://docs.digifinex.com/en-ww/swap/v2/rest.html#accounttransfer
2808
+
2792
2809
  :param str code: unified currency code
2793
2810
  :param float amount: amount to transfer
2794
- :param str fromAccount: account to transfer from
2795
- :param str toAccount: account to transfer to
2811
+ :param str fromAccount: 'spot', 'swap', 'margin', 'OTC' - account to transfer from
2812
+ :param str toAccount: 'spot', 'swap', 'margin', 'OTC' - account to transfer to
2796
2813
  :param dict [params]: extra parameters specific to the exchange API endpoint
2797
2814
  :returns dict: a `transfer structure <https://docs.ccxt.com/#/?id=transfer-structure>`
2798
2815
  """
2799
2816
  self.load_markets()
2800
2817
  currency = self.currency(code)
2818
+ currencyId = currency['id']
2801
2819
  accountsByType = self.safe_value(self.options, 'accountsByType', {})
2802
2820
  fromId = self.safe_string(accountsByType, fromAccount, fromAccount)
2803
2821
  toId = self.safe_string(accountsByType, toAccount, toAccount)
2804
- request: dict = {
2805
- 'currency_mark': currency['id'],
2806
- 'num': self.currency_to_precision(code, amount),
2807
- 'from': fromId, # 1 = SPOT, 2 = MARGIN, 3 = OTC
2808
- 'to': toId, # 1 = SPOT, 2 = MARGIN, 3 = OTC
2809
- }
2810
- response = self.privateSpotPostTransfer(self.extend(request, params))
2811
- #
2812
- # {
2813
- # "code": 0
2814
- # }
2815
- #
2822
+ request = {}
2823
+ fromSwap = (fromAccount == 'swap')
2824
+ toSwap = (toAccount == 'swap')
2825
+ response = None
2826
+ amountString = self.currency_to_precision(code, amount)
2827
+ if fromSwap or toSwap:
2828
+ if (fromId != '1') and (toId != '1'):
2829
+ raise ExchangeError(self.id + ' transfer() supports transferring between spot and swap, spot and margin, spot and OTC only')
2830
+ request['type'] = 1 if toSwap else 2 # 1 = spot to swap, 2 = swap to spot
2831
+ request['currency'] = currencyId
2832
+ request['transfer_amount'] = amountString
2833
+ #
2834
+ # {
2835
+ # "code": 0,
2836
+ # "data": {
2837
+ # "type": 2,
2838
+ # "currency": "USDT",
2839
+ # "transfer_amount": "5"
2840
+ # }
2841
+ # }
2842
+ #
2843
+ response = self.privateSwapPostAccountTransfer(self.extend(request, params))
2844
+ else:
2845
+ request['currency_mark'] = currencyId
2846
+ request['num'] = amountString
2847
+ request['from'] = fromId # 1 = SPOT, 2 = MARGIN, 3 = OTC
2848
+ request['to'] = toId # 1 = SPOT, 2 = MARGIN, 3 = OTC
2849
+ #
2850
+ # {
2851
+ # "code": 0
2852
+ # }
2853
+ #
2854
+ response = self.privateSpotPostTransfer(self.extend(request, params))
2816
2855
  return self.parse_transfer(response, currency)
2817
2856
 
2818
2857
  def withdraw(self, code: str, amount: float, address: str, tag=None, params={}) -> Transaction: