ccxt 4.4.10__py2.py3-none-any.whl → 4.4.12__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.4.10'
25
+ __version__ = '4.4.12'
26
26
 
27
27
  # ----------------------------------------------------------------------------
28
28
 
ccxt/abstract/binance.py CHANGED
@@ -703,6 +703,7 @@ class ImplicitAPI:
703
703
  papi_post_listenkey = papiPostListenKey = Entry('listenKey', 'papi', 'POST', {'cost': 1})
704
704
  papi_post_asset_collection = papiPostAssetCollection = Entry('asset-collection', 'papi', 'POST', {'cost': 3})
705
705
  papi_post_margin_repay_debt = papiPostMarginRepayDebt = Entry('margin/repay-debt', 'papi', 'POST', {'cost': 0.4})
706
+ papi_post_um_feeburn = papiPostUmFeeBurn = Entry('um/feeBurn', 'papi', 'POST', {'cost': 1})
706
707
  papi_put_listenkey = papiPutListenKey = Entry('listenKey', 'papi', 'PUT', {'cost': 1})
707
708
  papi_delete_um_order = papiDeleteUmOrder = Entry('um/order', 'papi', 'DELETE', {'cost': 1})
708
709
  papi_delete_um_conditional_order = papiDeleteUmConditionalOrder = Entry('um/conditional/order', 'papi', 'DELETE', {'cost': 1})
@@ -703,6 +703,7 @@ class ImplicitAPI:
703
703
  papi_post_listenkey = papiPostListenKey = Entry('listenKey', 'papi', 'POST', {'cost': 1})
704
704
  papi_post_asset_collection = papiPostAssetCollection = Entry('asset-collection', 'papi', 'POST', {'cost': 3})
705
705
  papi_post_margin_repay_debt = papiPostMarginRepayDebt = Entry('margin/repay-debt', 'papi', 'POST', {'cost': 0.4})
706
+ papi_post_um_feeburn = papiPostUmFeeBurn = Entry('um/feeBurn', 'papi', 'POST', {'cost': 1})
706
707
  papi_put_listenkey = papiPutListenKey = Entry('listenKey', 'papi', 'PUT', {'cost': 1})
707
708
  papi_delete_um_order = papiDeleteUmOrder = Entry('um/order', 'papi', 'DELETE', {'cost': 1})
708
709
  papi_delete_um_conditional_order = papiDeleteUmConditionalOrder = Entry('um/conditional/order', 'papi', 'DELETE', {'cost': 1})
@@ -755,6 +755,7 @@ class ImplicitAPI:
755
755
  papi_post_listenkey = papiPostListenKey = Entry('listenKey', 'papi', 'POST', {'cost': 1})
756
756
  papi_post_asset_collection = papiPostAssetCollection = Entry('asset-collection', 'papi', 'POST', {'cost': 3})
757
757
  papi_post_margin_repay_debt = papiPostMarginRepayDebt = Entry('margin/repay-debt', 'papi', 'POST', {'cost': 0.4})
758
+ papi_post_um_feeburn = papiPostUmFeeBurn = Entry('um/feeBurn', 'papi', 'POST', {'cost': 1})
758
759
  papi_put_listenkey = papiPutListenKey = Entry('listenKey', 'papi', 'PUT', {'cost': 1})
759
760
  papi_delete_um_order = papiDeleteUmOrder = Entry('um/order', 'papi', 'DELETE', {'cost': 1})
760
761
  papi_delete_um_conditional_order = papiDeleteUmConditionalOrder = Entry('um/conditional/order', 'papi', 'DELETE', {'cost': 1})
@@ -703,6 +703,7 @@ class ImplicitAPI:
703
703
  papi_post_listenkey = papiPostListenKey = Entry('listenKey', 'papi', 'POST', {'cost': 1})
704
704
  papi_post_asset_collection = papiPostAssetCollection = Entry('asset-collection', 'papi', 'POST', {'cost': 3})
705
705
  papi_post_margin_repay_debt = papiPostMarginRepayDebt = Entry('margin/repay-debt', 'papi', 'POST', {'cost': 0.4})
706
+ papi_post_um_feeburn = papiPostUmFeeBurn = Entry('um/feeBurn', 'papi', 'POST', {'cost': 1})
706
707
  papi_put_listenkey = papiPutListenKey = Entry('listenKey', 'papi', 'PUT', {'cost': 1})
707
708
  papi_delete_um_order = papiDeleteUmOrder = Entry('um/order', 'papi', 'DELETE', {'cost': 1})
708
709
  papi_delete_um_conditional_order = papiDeleteUmConditionalOrder = Entry('um/conditional/order', 'papi', 'DELETE', {'cost': 1})
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.4.10'
7
+ __version__ = '4.4.12'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  # -----------------------------------------------------------------------------
4
4
 
5
- __version__ = '4.4.10'
5
+ __version__ = '4.4.12'
6
6
 
7
7
  # -----------------------------------------------------------------------------
8
8
 
@@ -1116,6 +1116,7 @@ class binance(Exchange, ImplicitAPI):
1116
1116
  'listenKey': 1, # 1
1117
1117
  'asset-collection': 3,
1118
1118
  'margin/repay-debt': 0.4, # Weight(Order): 0.4 =>(1000 / (50 * 0.4)) * 60 = 3000
1119
+ 'um/feeBurn': 1,
1119
1120
  },
1120
1121
  'put': {
1121
1122
  'listenKey': 1, # 1
@@ -5595,6 +5596,8 @@ class binance(Exchange, ImplicitAPI):
5595
5596
  :param float [params.takeProfitPrice]: the price that a take profit order is triggered at
5596
5597
  :param boolean [params.portfolioMargin]: set to True if you would like to create an order in a portfolio margin account
5597
5598
  :param str [params.stopLossOrTakeProfit]: 'stopLoss' or 'takeProfit', required for spot trailing orders
5599
+ :param str [params.positionSide]: *swap and portfolio margin only* "BOTH" for one-way mode, "LONG" for buy side of hedged mode, "SHORT" for sell side of hedged mode
5600
+ :param bool [params.hedged]: *swap and portfolio margin only* True for hedged mode, False for one way mode, default is False
5598
5601
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
5599
5602
  """
5600
5603
  await self.load_markets()
@@ -5680,9 +5683,9 @@ class binance(Exchange, ImplicitAPI):
5680
5683
  isPortfolioMargin, params = self.handle_option_and_params_2(params, 'createOrder', 'papi', 'portfolioMargin', False)
5681
5684
  marginMode = None
5682
5685
  marginMode, params = self.handle_margin_mode_and_params('createOrder', params)
5686
+ reduceOnly = self.safe_bool(params, 'reduceOnly', False)
5683
5687
  if (marketType == 'margin') or (marginMode is not None) or market['option']:
5684
5688
  # for swap and future reduceOnly is a string that cant be sent with close position set to True or in hedge mode
5685
- reduceOnly = self.safe_bool(params, 'reduceOnly', False)
5686
5689
  params = self.omit(params, 'reduceOnly')
5687
5690
  if market['option']:
5688
5691
  request['reduceOnly'] = reduceOnly
@@ -5883,7 +5886,13 @@ class binance(Exchange, ImplicitAPI):
5883
5886
  # remove timeInForce from params because PO is only used by self.is_post_only and it's not a valid value for Binance
5884
5887
  if self.safe_string(params, 'timeInForce') == 'PO':
5885
5888
  params = self.omit(params, 'timeInForce')
5886
- requestParams = self.omit(params, ['type', 'newClientOrderId', 'clientOrderId', 'postOnly', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'triggerPrice', 'trailingTriggerPrice', 'trailingPercent', 'quoteOrderQty', 'cost', 'test'])
5889
+ hedged = self.safe_bool(params, 'hedged', False)
5890
+ if not market['spot'] and not market['option'] and hedged:
5891
+ if reduceOnly:
5892
+ params = self.omit(params, 'reduceOnly')
5893
+ side = 'sell' if (side == 'buy') else 'buy'
5894
+ request['positionSide'] = 'LONG' if (side == 'buy') else 'SHORT'
5895
+ requestParams = self.omit(params, ['type', 'newClientOrderId', 'clientOrderId', 'postOnly', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'triggerPrice', 'trailingTriggerPrice', 'trailingPercent', 'quoteOrderQty', 'cost', 'test', 'hedged'])
5887
5896
  return self.extend(request, requestParams)
5888
5897
 
5889
5898
  async def create_market_order_with_cost(self, symbol: str, side: OrderSide, cost: float, params={}):
@@ -2458,6 +2458,7 @@ class bingx(Exchange, ImplicitAPI):
2458
2458
  :param dict [params.stopLoss]: *stopLoss object in params* containing the triggerPrice at which the attached stop loss order will be triggered
2459
2459
  :param float [params.stopLoss.triggerPrice]: stop loss trigger price
2460
2460
  :param boolean [params.test]: *swap only* whether to use the test endpoint or not, default is False
2461
+ :param str [params.positionSide]: *contracts only* "BOTH" for one way mode, "LONG" for buy side of hedged mode, "SHORT" for sell side of hedged mode
2461
2462
  :param boolean [params.hedged]: *swap only* whether the order is in hedged mode or one way mode
2462
2463
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2463
2464
  """
@@ -4184,13 +4185,25 @@ class bingx(Exchange, ImplicitAPI):
4184
4185
  currencyId = self.safe_string(depositAddress, 'coin')
4185
4186
  currency = self.safe_currency(currencyId, currency)
4186
4187
  code = currency['code']
4187
- network = self.safe_string(depositAddress, 'network')
4188
+ # the exchange API returns deposit addresses without the leading '0x' prefix
4189
+ # however, the exchange API does require the 0x prefix to withdraw
4190
+ # so we append the prefix before returning the address to the user
4191
+ # that is only if the underlying contract address has the 0x prefix
4192
+ networkCode = self.safe_string(depositAddress, 'network')
4193
+ if networkCode is not None:
4194
+ if networkCode in currency['networks']:
4195
+ network = currency['networks'][networkCode]
4196
+ contractAddress = self.safe_string(network['info'], 'contractAddress')
4197
+ if contractAddress is not None:
4198
+ if contractAddress[0] == '0' and contractAddress[1] == 'x':
4199
+ if address[0] != '0' or address[1] != 'x':
4200
+ address = '0x' + address
4188
4201
  self.check_address(address)
4189
4202
  return {
4190
4203
  'currency': code,
4191
4204
  'address': address,
4192
4205
  'tag': tag,
4193
- 'network': network,
4206
+ 'network': networkCode,
4194
4207
  'info': depositAddress,
4195
4208
  }
4196
4209
 
@@ -1435,7 +1435,7 @@ class bitget(Exchange, ImplicitAPI):
1435
1435
  },
1436
1436
  'sandboxMode': False,
1437
1437
  'networks': {
1438
- 'TRX': 'TRC20',
1438
+ 'TRC20': 'TRC20',
1439
1439
  'ERC20': 'ERC20',
1440
1440
  'BEP20': 'BSC',
1441
1441
  'ARB': 'ArbitrumOne',
@@ -3948,6 +3948,7 @@ class bitget(Exchange, ImplicitAPI):
3948
3948
  :param str [params.trailingTriggerPrice]: *swap and future only* the price to trigger a trailing stop order, default uses the price argument
3949
3949
  :param str [params.triggerType]: *swap and future only* 'fill_price', 'mark_price' or 'index_price'
3950
3950
  :param boolean [params.oneWayMode]: *swap and future only* required to set self to True in one_way_mode and you can leave self in hedge_mode, can adjust the mode using the setPositionMode() method
3951
+ :param bool [params.hedged]: *swap and future only* True for hedged mode, False for one way mode, default is False
3951
3952
  :param bool [params.reduceOnly]: True or False whether the order is reduce-only
3952
3953
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
3953
3954
  """
@@ -3431,7 +3431,8 @@ class bybit(Exchange, ImplicitAPI):
3431
3431
  :param str [params.timeInForce]: "GTC", "IOC", "FOK"
3432
3432
  :param bool [params.postOnly]: True or False whether the order is post-only
3433
3433
  :param bool [params.reduceOnly]: True or False whether the order is reduce-only
3434
- :param str [params.positionIdx]: *contracts only* 0 for one-way mode, 1 buy side of hedged mode, 2 sell side of hedged mode
3434
+ :param str [params.positionIdx]: *contracts only* 0 for one-way mode, 1 buy side of hedged mode, 2 sell side of hedged mode
3435
+ :param bool [params.hedged]: *contracts only* True for hedged mode, False for one way mode, default is False
3435
3436
  :param boolean [params.isLeverage]: *unified spot only* False then spot trading True then margin trading
3436
3437
  :param str [params.tpslMode]: *contract only* 'full' or 'partial'
3437
3438
  :param str [params.mmp]: *option only* market maker protection
ccxt/async_support/htx.py CHANGED
@@ -1237,6 +1237,7 @@ class htx(Exchange, ImplicitAPI):
1237
1237
  # https://github.com/ccxt/ccxt/issues/6081
1238
1238
  # https://github.com/ccxt/ccxt/issues/3365
1239
1239
  # https://github.com/ccxt/ccxt/issues/2873
1240
+ 'NGL': 'GFNGL',
1240
1241
  'GET': 'THEMIS', # conflict with GET(Guaranteed Entrance Token, GET Protocol)
1241
1242
  'GTC': 'GAMECOM', # conflict with Gitcoin and Gastrocoin
1242
1243
  'HIT': 'HITCHAIN',
@@ -1248,6 +1249,7 @@ class htx(Exchange, ImplicitAPI):
1248
1249
  'SBTC': 'SUPERBITCOIN',
1249
1250
  'SOUL': 'SOULSAVER',
1250
1251
  'BIFI': 'BITCOINFILE', # conflict with Beefy.Finance https://github.com/ccxt/ccxt/issues/8706
1252
+ 'FUD': 'FTX Users\' Debt',
1251
1253
  },
1252
1254
  })
1253
1255
 
@@ -3480,6 +3482,12 @@ class htx(Exchange, ImplicitAPI):
3480
3482
  async def fetch_order(self, id: str, symbol: Str = None, params={}):
3481
3483
  """
3482
3484
  fetches information on an order made by the user
3485
+ :see: https://huobiapi.github.io/docs/spot/v1/en/#get-the-order-detail-of-an-order-based-on-client-order-id
3486
+ :see: https://huobiapi.github.io/docs/spot/v1/en/#get-the-order-detail-of-an-order
3487
+ :see: https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-get-information-of-an-order
3488
+ :see: https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-get-information-of-order
3489
+ :see: https://huobiapi.github.io/docs/dm/v1/en/#get-information-of-an-order
3490
+ :see: https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#get-information-of-an-order
3483
3491
  :param str symbol: unified symbol of the market the order was made in
3484
3492
  :param dict [params]: extra parameters specific to the exchange API endpoint
3485
3493
  :returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
@@ -6854,6 +6862,10 @@ class htx(Exchange, ImplicitAPI):
6854
6862
  async def set_leverage(self, leverage: Int, symbol: Str = None, params={}):
6855
6863
  """
6856
6864
  set the level of leverage for a market
6865
+ :see: https://huobiapi.github.io/docs/usdt_swap/v1/en/#isolated-switch-leverage
6866
+ :see: https://huobiapi.github.io/docs/usdt_swap/v1/en/#cross-switch-leverage
6867
+ :see: https://huobiapi.github.io/docs/coin_margined_swap/v1/en/#switch-leverage
6868
+ :see: https://huobiapi.github.io/docs/dm/v1/en/#switch-leverage # Coin-m futures
6857
6869
  :param float leverage: the rate of leverage
6858
6870
  :param str symbol: unified market symbol
6859
6871
  :param dict [params]: extra parameters specific to the exchange API endpoint
@@ -66,6 +66,7 @@ class kraken(Exchange, ImplicitAPI):
66
66
  'createStopMarketOrder': True,
67
67
  'createStopOrder': True,
68
68
  'createTrailingAmountOrder': True,
69
+ 'createTrailingPercentOrder': True,
69
70
  'editOrder': True,
70
71
  'fetchBalance': True,
71
72
  'fetchBorrowInterest': False,
@@ -456,7 +457,9 @@ class kraken(Exchange, ImplicitAPI):
456
457
  'EGeneral:Internal error': ExchangeNotAvailable,
457
458
  'EGeneral:Temporary lockout': DDoSProtection,
458
459
  'EGeneral:Permission denied': PermissionDenied,
460
+ 'EGeneral:Invalid arguments:price': InvalidOrder,
459
461
  'EOrder:Unknown order': InvalidOrder,
462
+ 'EOrder:Invalid price:Invalid price argument': InvalidOrder,
460
463
  'EOrder:Order minimum not met': InvalidOrder,
461
464
  'EGeneral:Invalid arguments': BadRequest,
462
465
  'ESession:Invalid session': AuthenticationError,
@@ -1397,8 +1400,8 @@ class kraken(Exchange, ImplicitAPI):
1397
1400
 
1398
1401
  async def create_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
1399
1402
  """
1400
- :see: https://docs.kraken.com/rest/#tag/Spot-Trading/operation/addOrder
1401
1403
  create a trade order
1404
+ :see: https://docs.kraken.com/api/docs/rest-api/add-order
1402
1405
  :param str symbol: unified symbol of the market to create an order in
1403
1406
  :param str type: 'market' or 'limit'
1404
1407
  :param str side: 'buy' or 'sell'
@@ -1410,7 +1413,9 @@ class kraken(Exchange, ImplicitAPI):
1410
1413
  :param float [params.stopLossPrice]: *margin only* the price that a stop loss order is triggered at
1411
1414
  :param float [params.takeProfitPrice]: *margin only* the price that a take profit order is triggered at
1412
1415
  :param str [params.trailingAmount]: *margin only* the quote amount to trail away from the current market price
1416
+ :param str [params.trailingPercent]: *margin only* the percent to trail away from the current market price
1413
1417
  :param str [params.trailingLimitAmount]: *margin only* the quote amount away from the trailingAmount
1418
+ :param str [params.trailingLimitPercent]: *margin only* the percent away from the trailingAmount
1414
1419
  :param str [params.offset]: *margin only* '+' or '-' whether you want the trailingLimitAmount value to be positive or negative, default is negative '-'
1415
1420
  :param str [params.trigger]: *margin only* the activation price type, 'last' or 'index', default is 'last'
1416
1421
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
@@ -1717,8 +1722,11 @@ class kraken(Exchange, ImplicitAPI):
1717
1722
  isTakeProfitTriggerOrder = takeProfitTriggerPrice is not None
1718
1723
  isStopLossOrTakeProfitTrigger = isStopLossTriggerOrder or isTakeProfitTriggerOrder
1719
1724
  trailingAmount = self.safe_string(params, 'trailingAmount')
1725
+ trailingPercent = self.safe_string(params, 'trailingPercent')
1720
1726
  trailingLimitAmount = self.safe_string(params, 'trailingLimitAmount')
1727
+ trailingLimitPercent = self.safe_string(params, 'trailingLimitPercent')
1721
1728
  isTrailingAmountOrder = trailingAmount is not None
1729
+ isTrailingPercentOrder = trailingPercent is not None
1722
1730
  isLimitOrder = type.endswith('limit') # supporting limit, stop-loss-limit, take-profit-limit, etc
1723
1731
  isMarketOrder = type == 'market'
1724
1732
  cost = self.safe_string(params, 'cost')
@@ -1732,7 +1740,7 @@ class kraken(Exchange, ImplicitAPI):
1732
1740
  request['volume'] = self.cost_to_precision(symbol, cost)
1733
1741
  extendedOflags = flags + ',viqc' if (flags is not None) else 'viqc'
1734
1742
  request['oflags'] = extendedOflags
1735
- elif isLimitOrder and not isTrailingAmountOrder:
1743
+ elif isLimitOrder and not isTrailingAmountOrder and not isTrailingPercentOrder:
1736
1744
  request['price'] = self.price_to_precision(symbol, price)
1737
1745
  reduceOnly = self.safe_bool_2(params, 'reduceOnly', 'reduce_only')
1738
1746
  if isStopLossOrTakeProfitTrigger:
@@ -1750,19 +1758,30 @@ class kraken(Exchange, ImplicitAPI):
1750
1758
  request['ordertype'] = 'take-profit'
1751
1759
  if isLimitOrder:
1752
1760
  request['price2'] = self.price_to_precision(symbol, price)
1753
- elif isTrailingAmountOrder:
1761
+ elif isTrailingAmountOrder or isTrailingPercentOrder:
1762
+ trailingPercentString = None
1763
+ if trailingPercent is not None:
1764
+ trailingPercentString = ('+' + trailingPercent) if (trailingPercent.endswith('%')) else ('+' + trailingPercent + '%')
1765
+ trailingAmountString = '+' + trailingAmount if (trailingAmount is not None) else None # must use + for self
1766
+ offset = self.safe_string(params, 'offset', '-') # can use + or - for self
1767
+ trailingLimitAmountString = offset + self.number_to_string(trailingLimitAmount) if (trailingLimitAmount is not None) else None
1754
1768
  trailingActivationPriceType = self.safe_string(params, 'trigger', 'last')
1755
- trailingAmountString = '+' + trailingAmount
1756
1769
  request['trigger'] = trailingActivationPriceType
1757
- if isLimitOrder or (trailingLimitAmount is not None):
1758
- offset = self.safe_string(params, 'offset', '-')
1759
- trailingLimitAmountString = offset + self.number_to_string(trailingLimitAmount)
1760
- request['price'] = trailingAmountString
1761
- request['price2'] = trailingLimitAmountString
1770
+ if isLimitOrder or (trailingLimitAmount is not None) or (trailingLimitPercent is not None):
1762
1771
  request['ordertype'] = 'trailing-stop-limit'
1772
+ if trailingLimitPercent is not None:
1773
+ trailingLimitPercentString = (offset + trailingLimitPercent) if (trailingLimitPercent.endswith('%')) else (offset + trailingLimitPercent + '%')
1774
+ request['price'] = trailingPercentString
1775
+ request['price2'] = trailingLimitPercentString
1776
+ elif trailingLimitAmount is not None:
1777
+ request['price'] = trailingAmountString
1778
+ request['price2'] = trailingLimitAmountString
1763
1779
  else:
1764
- request['price'] = trailingAmountString
1765
1780
  request['ordertype'] = 'trailing-stop'
1781
+ if trailingPercent is not None:
1782
+ request['price'] = trailingPercentString
1783
+ else:
1784
+ request['price'] = trailingAmountString
1766
1785
  if reduceOnly:
1767
1786
  if method == 'createOrderWs':
1768
1787
  request['reduce_only'] = True # ws request can't have stringified bool
@@ -1789,7 +1808,7 @@ class kraken(Exchange, ImplicitAPI):
1789
1808
  request['oflags'] = extendedPostFlags
1790
1809
  if (flags is not None) and not ('oflags' in request):
1791
1810
  request['oflags'] = flags
1792
- params = self.omit(params, ['timeInForce', 'reduceOnly', 'stopLossPrice', 'takeProfitPrice', 'trailingAmount', 'trailingLimitAmount', 'offset'])
1811
+ params = self.omit(params, ['timeInForce', 'reduceOnly', 'stopLossPrice', 'takeProfitPrice', 'trailingAmount', 'trailingPercent', 'trailingLimitAmount', 'trailingLimitPercent', 'offset'])
1793
1812
  return [request, params]
1794
1813
 
1795
1814
  async def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}):
@@ -2916,11 +2935,15 @@ class kraken(Exchange, ImplicitAPI):
2916
2935
  # urlencodeNested is used to address https://github.com/ccxt/ccxt/issues/12872
2917
2936
  url += '?' + self.urlencode_nested(params)
2918
2937
  elif api == 'private':
2938
+ price = self.safe_string(params, 'price')
2939
+ isTriggerPercent = False
2940
+ if price is not None:
2941
+ isTriggerPercent = True if (price.endswith('%')) else False
2919
2942
  isCancelOrderBatch = (path == 'CancelOrderBatch')
2920
2943
  self.check_required_credentials()
2921
2944
  nonce = str(self.nonce())
2922
2945
  # urlencodeNested is used to address https://github.com/ccxt/ccxt/issues/12872
2923
- if isCancelOrderBatch:
2946
+ if isCancelOrderBatch or isTriggerPercent:
2924
2947
  body = self.json(self.extend({'nonce': nonce}, params))
2925
2948
  else:
2926
2949
  body = self.urlencode_nested(self.extend({'nonce': nonce}, params))
@@ -2933,9 +2956,8 @@ class kraken(Exchange, ImplicitAPI):
2933
2956
  headers = {
2934
2957
  'API-Key': self.apiKey,
2935
2958
  'API-Sign': signature,
2936
- # 'Content-Type': 'application/x-www-form-urlencoded',
2937
2959
  }
2938
- if isCancelOrderBatch:
2960
+ if isCancelOrderBatch or isTriggerPercent:
2939
2961
  headers['Content-Type'] = 'application/json'
2940
2962
  else:
2941
2963
  headers['Content-Type'] = 'application/x-www-form-urlencoded'
@@ -2055,6 +2055,7 @@ class mexc(Exchange, ImplicitAPI):
2055
2055
  :param float [params.triggerPrice]: The price at which a trigger order is triggered at
2056
2056
  :param bool [params.postOnly]: if True, the order will only be posted if it will be a maker order
2057
2057
  :param bool [params.reduceOnly]: *contract only* indicates if self order is to reduce the size of a position
2058
+ :param bool [params.hedged]: *swap only* True for hedged mode, False for one way mode, default is False
2058
2059
  *
2059
2060
  * EXCHANGE SPECIFIC PARAMETERS
2060
2061
  :param int [params.leverage]: *contract only* leverage is necessary on isolated margin
@@ -2180,6 +2181,7 @@ class mexc(Exchange, ImplicitAPI):
2180
2181
  :param float [params.triggerPrice]: The price at which a trigger order is triggered at
2181
2182
  :param bool [params.postOnly]: if True, the order will only be posted if it will be a maker order
2182
2183
  :param bool [params.reduceOnly]: indicates if self order is to reduce the size of a position
2184
+ :param bool [params.hedged]: *swap only* True for hedged mode, False for one way mode, default is False
2183
2185
  *
2184
2186
  * EXCHANGE SPECIFIC PARAMETERS
2185
2187
  :param int [params.leverage]: leverage is necessary on isolated margin
@@ -2247,15 +2249,25 @@ class mexc(Exchange, ImplicitAPI):
2247
2249
  if leverage is None:
2248
2250
  raise ArgumentsRequired(self.id + ' createSwapOrder() requires a leverage parameter for isolated margin orders')
2249
2251
  reduceOnly = self.safe_bool(params, 'reduceOnly', False)
2250
- if reduceOnly:
2251
- request['side'] = 2 if (side == 'buy') else 4
2252
+ hedged = self.safe_bool(params, 'hedged', False)
2253
+ sideInteger = None
2254
+ if hedged:
2255
+ if reduceOnly:
2256
+ params = self.omit(params, 'reduceOnly') # hedged mode does not accept self parameter
2257
+ side = 'sell' if (side == 'buy') else 'buy'
2258
+ sideInteger = 1 if (side == 'buy') else 3
2259
+ request['positionMode'] = 1
2252
2260
  else:
2253
- request['side'] = 1 if (side == 'buy') else 3
2261
+ if reduceOnly:
2262
+ sideInteger = 2 if (side == 'buy') else 4
2263
+ else:
2264
+ sideInteger = 1 if (side == 'buy') else 3
2265
+ request['side'] = sideInteger
2254
2266
  clientOrderId = self.safe_string_2(params, 'clientOrderId', 'externalOid')
2255
2267
  if clientOrderId is not None:
2256
2268
  request['externalOid'] = clientOrderId
2257
2269
  stopPrice = self.safe_number_2(params, 'triggerPrice', 'stopPrice')
2258
- params = self.omit(params, ['clientOrderId', 'externalOid', 'postOnly', 'stopPrice', 'triggerPrice'])
2270
+ params = self.omit(params, ['clientOrderId', 'externalOid', 'postOnly', 'stopPrice', 'triggerPrice', 'hedged'])
2259
2271
  response = None
2260
2272
  if stopPrice:
2261
2273
  request['triggerPrice'] = self.price_to_precision(symbol, stopPrice)
@@ -3616,23 +3628,29 @@ class mexc(Exchange, ImplicitAPI):
3616
3628
  :param int [since]: the earliest time in ms to fetch trades for
3617
3629
  :param int [limit]: the maximum number of trades structures to retrieve
3618
3630
  :param dict [params]: extra parameters specific to the exchange API endpoint
3631
+ :param int [params.until]: the latest time in ms to fetch trades for
3619
3632
  :returns Trade[]: a list of `trade structures <https://docs.ccxt.com/#/?id=trade-structure>`
3620
3633
  """
3621
3634
  if symbol is None:
3622
3635
  raise ArgumentsRequired(self.id + ' fetchMyTrades() requires a symbol argument')
3623
3636
  await self.load_markets()
3624
3637
  market = self.market(symbol)
3625
- marketType, query = self.handle_market_type_and_params('fetchMyTrades', market, params)
3638
+ marketType: Str = None
3639
+ marketType, params = self.handle_market_type_and_params('fetchMyTrades', market, params)
3626
3640
  request: dict = {
3627
3641
  'symbol': market['id'],
3628
3642
  }
3629
3643
  trades = None
3630
3644
  if marketType == 'spot':
3631
3645
  if since is not None:
3632
- request['start_time'] = since
3646
+ request['startTime'] = since
3633
3647
  if limit is not None:
3634
3648
  request['limit'] = limit
3635
- trades = await self.spotPrivateGetMyTrades(self.extend(request, query))
3649
+ until = self.safe_integer(params, 'until')
3650
+ if until is not None:
3651
+ params = self.omit(params, 'until')
3652
+ request['endTime'] = until
3653
+ trades = await self.spotPrivateGetMyTrades(self.extend(request, params))
3636
3654
  #
3637
3655
  # spot
3638
3656
  #
@@ -3662,7 +3680,7 @@ class mexc(Exchange, ImplicitAPI):
3662
3680
  request['end_time'] = self.sum(since, self.options['maxTimeTillEnd'])
3663
3681
  if limit is not None:
3664
3682
  request['page_size'] = limit
3665
- response = await self.contractPrivateGetOrderListOrderDeals(self.extend(request, query))
3683
+ response = await self.contractPrivateGetOrderListOrderDeals(self.extend(request, params))
3666
3684
  #
3667
3685
  # {
3668
3686
  # "success": True,
ccxt/async_support/okx.py CHANGED
@@ -18,6 +18,7 @@ from ccxt.base.errors import AccountSuspended
18
18
  from ccxt.base.errors import ArgumentsRequired
19
19
  from ccxt.base.errors import BadRequest
20
20
  from ccxt.base.errors import BadSymbol
21
+ from ccxt.base.errors import ManualInteractionNeeded
21
22
  from ccxt.base.errors import InsufficientFunds
22
23
  from ccxt.base.errors import InvalidAddress
23
24
  from ccxt.base.errors import InvalidOrder
@@ -600,6 +601,7 @@ class okx(Exchange, ImplicitAPI):
600
601
  # General Class
601
602
  '1': ExchangeError, # Operation failed
602
603
  '2': ExchangeError, # Bulk operation partially succeeded
604
+ '4088': ManualInteractionNeeded, # {"code":"4088","data":[],"msg":"You can’t trade or deposit until you’ve verified your identity again. Head to Identity Verification to complete it."}
603
605
  '50000': BadRequest, # Body can not be empty
604
606
  '50001': OnMaintenance, # Matching engine upgrading. Please try again later
605
607
  '50002': BadRequest, # Json data format error
@@ -2793,7 +2795,7 @@ class okx(Exchange, ImplicitAPI):
2793
2795
  :param str [params.positionSide]: if position mode is one-way: set to 'net', if position mode is hedge-mode: set to 'long' or 'short'
2794
2796
  :param str [params.trailingPercent]: the percent to trail away from the current market price
2795
2797
  :param str [params.tpOrdKind]: 'condition' or 'limit', the default is 'condition'
2796
- :param str [params.hedged]: True/false, to automatically set exchange-specific params needed when trading in hedge mode
2798
+ :param bool [params.hedged]: *swap and future only* True for hedged mode, False for one way mode
2797
2799
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2798
2800
  """
2799
2801
  await self.load_markets()
@@ -4526,32 +4528,27 @@ class okx(Exchange, ImplicitAPI):
4526
4528
  :see: https://www.okx.com/docs-v5/en/#funding-account-rest-api-get-deposit-address
4527
4529
  :param str code: unified currency code
4528
4530
  :param dict [params]: extra parameters specific to the exchange API endpoint
4531
+ :param str [params.network]: the network name for the deposit address
4529
4532
  :returns dict: an `address structure <https://docs.ccxt.com/#/?id=address-structure>`
4530
4533
  """
4534
+ await self.load_markets()
4531
4535
  rawNetwork = self.safe_string_upper(params, 'network')
4532
- networks = self.safe_value(self.options, 'networks', {})
4533
- network = self.safe_string(networks, rawNetwork, rawNetwork)
4534
4536
  params = self.omit(params, 'network')
4537
+ code = self.safe_currency_code(code)
4538
+ network = self.network_id_to_code(rawNetwork, code)
4535
4539
  response = await self.fetch_deposit_addresses_by_network(code, params)
4536
- result = None
4537
- if network is None:
4538
- result = self.safe_value(response, code)
4540
+ if network is not None:
4541
+ result = self.safe_dict(response, network)
4539
4542
  if result is None:
4540
- alias = self.safe_string(networks, code, code)
4541
- result = self.safe_value(response, alias)
4542
- if result is None:
4543
- defaultNetwork = self.safe_string(self.options, 'defaultNetwork', 'ERC20')
4544
- result = self.safe_value(response, defaultNetwork)
4545
- if result is None:
4546
- values = list(response.values())
4547
- result = self.safe_value(values, 0)
4548
- if result is None:
4549
- raise InvalidAddress(self.id + ' fetchDepositAddress() cannot find deposit address for ' + code)
4543
+ raise InvalidAddress(self.id + ' fetchDepositAddress() cannot find ' + network + ' deposit address for ' + code)
4550
4544
  return result
4551
- result = self.safe_value(response, network)
4552
- if result is None:
4553
- raise InvalidAddress(self.id + ' fetchDepositAddress() cannot find ' + network + ' deposit address for ' + code)
4554
- return result
4545
+ codeNetwork = self.network_id_to_code(code, code)
4546
+ if codeNetwork in response:
4547
+ return response[codeNetwork]
4548
+ # if the network is not specified, return the first address
4549
+ keys = list(response.keys())
4550
+ first = self.safe_string(keys, 0)
4551
+ return self.safe_dict(response, first)
4555
4552
 
4556
4553
  async def withdraw(self, code: str, amount: float, address: str, tag=None, params={}):
4557
4554
  """
@@ -2402,6 +2402,8 @@ class phemex(Exchange, ImplicitAPI):
2402
2402
  :param float [params.takeProfit.triggerPrice]: take profit trigger price
2403
2403
  :param dict [params.stopLoss]: *swap only* *stopLoss object in params* containing the triggerPrice at which the attached stop loss order will be triggered(perpetual swap markets only)
2404
2404
  :param float [params.stopLoss.triggerPrice]: stop loss trigger price
2405
+ :param str [params.posSide]: *swap only* "Merged" for one way mode, "Long" for buy side of hedged mode, "Short" for sell side of hedged mode
2406
+ :param bool [params.hedged]: *swap only* True for hedged mode, False for one way mode, default is False
2405
2407
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
2406
2408
  """
2407
2409
  await self.load_markets()
@@ -2486,13 +2488,18 @@ class phemex(Exchange, ImplicitAPI):
2486
2488
  amountString = self.number_to_string(amount)
2487
2489
  request['baseQtyEv'] = self.to_ev(amountString, market)
2488
2490
  elif market['swap']:
2491
+ hedged = self.safe_bool(params, 'hedged', False)
2492
+ params = self.omit(params, 'hedged')
2489
2493
  posSide = self.safe_string_lower(params, 'posSide')
2490
2494
  if posSide is None:
2491
- posSide = 'Merged'
2495
+ if hedged:
2496
+ if reduceOnly:
2497
+ side = 'sell' if (side == 'buy') else 'buy'
2498
+ posSide = 'Long' if (side == 'buy') else 'Short'
2499
+ else:
2500
+ posSide = 'Merged'
2492
2501
  posSide = self.capitalize(posSide)
2493
2502
  request['posSide'] = posSide
2494
- if reduceOnly is not None:
2495
- request['reduceOnly'] = reduceOnly
2496
2503
  if market['settle'] == 'USDT':
2497
2504
  request['orderQtyRq'] = amount
2498
2505
  else:
ccxt/base/exchange.py CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  # -----------------------------------------------------------------------------
6
6
 
7
- __version__ = '4.4.10'
7
+ __version__ = '4.4.12'
8
8
 
9
9
  # -----------------------------------------------------------------------------
10
10
 
ccxt/binance.py CHANGED
@@ -1115,6 +1115,7 @@ class binance(Exchange, ImplicitAPI):
1115
1115
  'listenKey': 1, # 1
1116
1116
  'asset-collection': 3,
1117
1117
  'margin/repay-debt': 0.4, # Weight(Order): 0.4 =>(1000 / (50 * 0.4)) * 60 = 3000
1118
+ 'um/feeBurn': 1,
1118
1119
  },
1119
1120
  'put': {
1120
1121
  'listenKey': 1, # 1
@@ -5594,6 +5595,8 @@ class binance(Exchange, ImplicitAPI):
5594
5595
  :param float [params.takeProfitPrice]: the price that a take profit order is triggered at
5595
5596
  :param boolean [params.portfolioMargin]: set to True if you would like to create an order in a portfolio margin account
5596
5597
  :param str [params.stopLossOrTakeProfit]: 'stopLoss' or 'takeProfit', required for spot trailing orders
5598
+ :param str [params.positionSide]: *swap and portfolio margin only* "BOTH" for one-way mode, "LONG" for buy side of hedged mode, "SHORT" for sell side of hedged mode
5599
+ :param bool [params.hedged]: *swap and portfolio margin only* True for hedged mode, False for one way mode, default is False
5597
5600
  :returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
5598
5601
  """
5599
5602
  self.load_markets()
@@ -5679,9 +5682,9 @@ class binance(Exchange, ImplicitAPI):
5679
5682
  isPortfolioMargin, params = self.handle_option_and_params_2(params, 'createOrder', 'papi', 'portfolioMargin', False)
5680
5683
  marginMode = None
5681
5684
  marginMode, params = self.handle_margin_mode_and_params('createOrder', params)
5685
+ reduceOnly = self.safe_bool(params, 'reduceOnly', False)
5682
5686
  if (marketType == 'margin') or (marginMode is not None) or market['option']:
5683
5687
  # for swap and future reduceOnly is a string that cant be sent with close position set to True or in hedge mode
5684
- reduceOnly = self.safe_bool(params, 'reduceOnly', False)
5685
5688
  params = self.omit(params, 'reduceOnly')
5686
5689
  if market['option']:
5687
5690
  request['reduceOnly'] = reduceOnly
@@ -5882,7 +5885,13 @@ class binance(Exchange, ImplicitAPI):
5882
5885
  # remove timeInForce from params because PO is only used by self.is_post_only and it's not a valid value for Binance
5883
5886
  if self.safe_string(params, 'timeInForce') == 'PO':
5884
5887
  params = self.omit(params, 'timeInForce')
5885
- requestParams = self.omit(params, ['type', 'newClientOrderId', 'clientOrderId', 'postOnly', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'triggerPrice', 'trailingTriggerPrice', 'trailingPercent', 'quoteOrderQty', 'cost', 'test'])
5888
+ hedged = self.safe_bool(params, 'hedged', False)
5889
+ if not market['spot'] and not market['option'] and hedged:
5890
+ if reduceOnly:
5891
+ params = self.omit(params, 'reduceOnly')
5892
+ side = 'sell' if (side == 'buy') else 'buy'
5893
+ request['positionSide'] = 'LONG' if (side == 'buy') else 'SHORT'
5894
+ requestParams = self.omit(params, ['type', 'newClientOrderId', 'clientOrderId', 'postOnly', 'stopLossPrice', 'takeProfitPrice', 'stopPrice', 'triggerPrice', 'trailingTriggerPrice', 'trailingPercent', 'quoteOrderQty', 'cost', 'test', 'hedged'])
5886
5895
  return self.extend(request, requestParams)
5887
5896
 
5888
5897
  def create_market_order_with_cost(self, symbol: str, side: OrderSide, cost: float, params={}):