ccxt 4.4.53__py2.py3-none-any.whl → 4.4.58__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 +1 -3
- ccxt/abstract/xt.py +1 -0
- ccxt/ascendex.py +2 -0
- ccxt/async_support/__init__.py +1 -3
- ccxt/async_support/ascendex.py +2 -0
- ccxt/async_support/base/exchange.py +5 -5
- ccxt/async_support/binance.py +39 -9
- ccxt/async_support/bitget.py +6 -1
- ccxt/async_support/bitmart.py +13 -3
- ccxt/async_support/blofin.py +1 -2
- ccxt/async_support/bybit.py +16 -3
- ccxt/async_support/coinbase.py +9 -2
- ccxt/async_support/coinbaseinternational.py +2 -2
- ccxt/async_support/coinex.py +1 -1
- ccxt/async_support/deribit.py +8 -25
- ccxt/async_support/exmo.py +1 -1
- ccxt/async_support/hyperliquid.py +11 -6
- ccxt/async_support/kraken.py +1 -1
- ccxt/async_support/timex.py +12 -2
- ccxt/async_support/vertex.py +1 -1
- ccxt/async_support/whitebit.py +2 -1
- ccxt/async_support/woofipro.py +2 -2
- ccxt/async_support/xt.py +54 -1
- ccxt/base/errors.py +0 -6
- ccxt/base/exchange.py +6 -6
- ccxt/binance.py +39 -9
- ccxt/bitget.py +6 -1
- ccxt/bitmart.py +13 -3
- ccxt/blofin.py +1 -2
- ccxt/bybit.py +16 -3
- ccxt/coinbase.py +9 -2
- ccxt/coinbaseinternational.py +2 -2
- ccxt/coinex.py +1 -1
- ccxt/deribit.py +8 -25
- ccxt/exmo.py +1 -1
- ccxt/hyperliquid.py +11 -6
- ccxt/kraken.py +1 -1
- ccxt/pro/__init__.py +1 -1
- ccxt/pro/binance.py +2 -2
- ccxt/pro/bitget.py +3 -3
- ccxt/pro/bybit.py +11 -3
- ccxt/pro/cex.py +1 -1
- ccxt/pro/coincatch.py +3 -3
- ccxt/pro/mexc.py +6 -4
- ccxt/pro/okx.py +1 -1
- ccxt/static_dependencies/ethereum/abi/py.typed +0 -0
- ccxt/static_dependencies/ethereum/account/py.typed +0 -0
- ccxt/static_dependencies/ethereum/hexbytes/py.typed +0 -0
- ccxt/static_dependencies/ethereum/typing/py.typed +0 -0
- ccxt/static_dependencies/ethereum/utils/py.typed +0 -0
- ccxt/static_dependencies/lark/py.typed +0 -0
- ccxt/static_dependencies/marshmallow/py.typed +0 -0
- ccxt/static_dependencies/marshmallow_dataclass/py.typed +0 -0
- ccxt/static_dependencies/marshmallow_oneofschema/py.typed +0 -0
- ccxt/test/tests_init.py +2 -2
- ccxt/timex.py +12 -2
- ccxt/vertex.py +1 -1
- ccxt/whitebit.py +2 -1
- ccxt/woofipro.py +2 -2
- ccxt/xt.py +54 -1
- {ccxt-4.4.53.dist-info → ccxt-4.4.58.dist-info}/METADATA +9 -12
- {ccxt-4.4.53.dist-info → ccxt-4.4.58.dist-info}/RECORD +65 -59
- ccxt/abstract/lykke.py +0 -29
- ccxt/async_support/lykke.py +0 -1374
- ccxt/lykke.py +0 -1374
- {ccxt-4.4.53.dist-info → ccxt-4.4.58.dist-info}/LICENSE.txt +0 -0
- {ccxt-4.4.53.dist-info → ccxt-4.4.58.dist-info}/WHEEL +0 -0
- {ccxt-4.4.53.dist-info → ccxt-4.4.58.dist-info}/top_level.txt +0 -0
ccxt/async_support/timex.py
CHANGED
@@ -729,6 +729,7 @@ class timex(Exchange, ImplicitAPI):
|
|
729
729
|
:param int [since]: timestamp in ms of the earliest candle to fetch
|
730
730
|
:param int [limit]: the maximum amount of candles to fetch
|
731
731
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
732
|
+
:param int [params.until]: timestamp in ms of the latest candle to fetch
|
732
733
|
:returns int[][]: A list of candles ordered, open, high, low, close, volume
|
733
734
|
"""
|
734
735
|
await self.load_markets()
|
@@ -739,15 +740,24 @@ class timex(Exchange, ImplicitAPI):
|
|
739
740
|
}
|
740
741
|
# if since and limit are not specified
|
741
742
|
duration = self.parse_timeframe(timeframe)
|
743
|
+
until = self.safe_integer(params, 'until')
|
742
744
|
if limit is None:
|
743
745
|
limit = 1000 # exchange provides tens of thousands of data, but we set generous default value
|
744
746
|
if since is not None:
|
745
747
|
request['from'] = self.iso8601(since)
|
746
|
-
|
748
|
+
if until is None:
|
749
|
+
request['till'] = self.iso8601(self.sum(since, self.sum(limit, 1) * duration * 1000))
|
750
|
+
else:
|
751
|
+
request['till'] = self.iso8601(until)
|
752
|
+
elif until is not None:
|
753
|
+
request['till'] = self.iso8601(until)
|
754
|
+
fromTimestamp = until - self.sum(limit, 1) * duration * 1000
|
755
|
+
request['from'] = self.iso8601(fromTimestamp)
|
747
756
|
else:
|
748
757
|
now = self.milliseconds()
|
749
758
|
request['till'] = self.iso8601(now)
|
750
|
-
request['from'] = self.iso8601(now - limit * duration * 1000 - 1)
|
759
|
+
request['from'] = self.iso8601(now - self.sum(limit, 1) * duration * 1000 - 1)
|
760
|
+
params = self.omit(params, 'until')
|
751
761
|
response = await self.publicGetCandles(self.extend(request, params))
|
752
762
|
#
|
753
763
|
# [
|
ccxt/async_support/vertex.py
CHANGED
@@ -1523,7 +1523,7 @@ class vertex(Exchange, ImplicitAPI):
|
|
1523
1523
|
marketId = base + '/' + quote
|
1524
1524
|
if base.find('PERP') > 0:
|
1525
1525
|
marketId = marketId.replace('-PERP', '') + ':USDC'
|
1526
|
-
market = self.
|
1526
|
+
market = self.safe_market(marketId, market)
|
1527
1527
|
last = self.safe_string(ticker, 'last_price')
|
1528
1528
|
return self.safe_ticker({
|
1529
1529
|
'symbol': market['symbol'],
|
ccxt/async_support/whitebit.py
CHANGED
@@ -2626,12 +2626,13 @@ class whitebit(Exchange, ImplicitAPI):
|
|
2626
2626
|
# For cases where we have a meaningful status
|
2627
2627
|
# {"response":null,"status":422,"errors":{"orderId":["Finished order id 435453454535 not found on your account"]},"notification":null,"warning":"Finished order id 435453454535 not found on your account","_token":null}
|
2628
2628
|
status = self.safe_string(response, 'status')
|
2629
|
+
errors = self.safe_value(response, 'errors')
|
2629
2630
|
# {"code":10,"message":"Unauthorized request."}
|
2630
2631
|
message = self.safe_string(response, 'message')
|
2631
2632
|
# For these cases where we have a generic code variable error key
|
2632
2633
|
# {"code":0,"message":"Validation failed","errors":{"amount":["Amount must be greater than 0"]}}
|
2633
2634
|
codeNew = self.safe_integer(response, 'code')
|
2634
|
-
hasErrorStatus = status is not None and status != '200'
|
2635
|
+
hasErrorStatus = status is not None and status != '200' and errors is not None
|
2635
2636
|
if hasErrorStatus or codeNew is not None:
|
2636
2637
|
feedback = self.id + ' ' + body
|
2637
2638
|
errorInfo = message
|
ccxt/async_support/woofipro.py
CHANGED
@@ -1507,7 +1507,7 @@ class woofipro(Exchange, ImplicitAPI):
|
|
1507
1507
|
takeProfit = self.safe_value(orderParams, 'takeProfit')
|
1508
1508
|
isConditional = triggerPrice is not None or stopLoss is not None or takeProfit is not None or (self.safe_value(orderParams, 'childOrders') is not None)
|
1509
1509
|
if isConditional:
|
1510
|
-
raise NotSupported(self.id + 'createOrders() only support non-stop order')
|
1510
|
+
raise NotSupported(self.id + ' createOrders() only support non-stop order')
|
1511
1511
|
orderRequest = self.create_order_request(marketId, type, side, amount, price, orderParams)
|
1512
1512
|
ordersRequests.append(orderRequest)
|
1513
1513
|
request: dict = {
|
@@ -2355,7 +2355,7 @@ class woofipro(Exchange, ImplicitAPI):
|
|
2355
2355
|
if code is not None:
|
2356
2356
|
code = code.upper()
|
2357
2357
|
if code != 'USDC':
|
2358
|
-
raise NotSupported(self.id + 'withdraw() only support USDC')
|
2358
|
+
raise NotSupported(self.id + ' withdraw() only support USDC')
|
2359
2359
|
currency = self.currency(code)
|
2360
2360
|
verifyingContractAddress = self.safe_string(self.options, 'verifyingContractAddress')
|
2361
2361
|
chainId = self.safe_string(params, 'chainId')
|
ccxt/async_support/xt.py
CHANGED
@@ -129,7 +129,7 @@ class xt(Exchange, ImplicitAPI):
|
|
129
129
|
'repayMargin': False,
|
130
130
|
'setLeverage': True,
|
131
131
|
'setMargin': False,
|
132
|
-
'setMarginMode':
|
132
|
+
'setMarginMode': True,
|
133
133
|
'setPositionMode': False,
|
134
134
|
'signIn': False,
|
135
135
|
'transfer': True,
|
@@ -287,6 +287,7 @@ class xt(Exchange, ImplicitAPI):
|
|
287
287
|
'future/user/v1/position/margin': 1,
|
288
288
|
'future/user/v1/user/collection/add': 1,
|
289
289
|
'future/user/v1/user/collection/cancel': 1,
|
290
|
+
'future/user/v1/position/change-type': 1,
|
290
291
|
},
|
291
292
|
},
|
292
293
|
'inverse': {
|
@@ -532,10 +533,12 @@ class xt(Exchange, ImplicitAPI):
|
|
532
533
|
'TRANSFER_012': PermissionDenied, # Currency transfer prohibited
|
533
534
|
'symbol_not_support_trading_via_api': BadSymbol, # {"returnCode":1,"msgInfo":"failure","error":{"code":"symbol_not_support_trading_via_api","msg":"The symbol does not support trading via API"},"result":null}
|
534
535
|
'open_order_min_nominal_value_limit': InvalidOrder, # {"returnCode":1,"msgInfo":"failure","error":{"code":"open_order_min_nominal_value_limit","msg":"Exceeds the minimum notional value of a single order"},"result":null}
|
536
|
+
'insufficient_balance': InsufficientFunds,
|
535
537
|
},
|
536
538
|
'broad': {
|
537
539
|
'The symbol does not support trading via API': BadSymbol, # {"returnCode":1,"msgInfo":"failure","error":{"code":"symbol_not_support_trading_via_api","msg":"The symbol does not support trading via API"},"result":null}
|
538
540
|
'Exceeds the minimum notional value of a single order': InvalidOrder, # {"returnCode":1,"msgInfo":"failure","error":{"code":"open_order_min_nominal_value_limit","msg":"Exceeds the minimum notional value of a single order"},"result":null}
|
541
|
+
'insufficient balance': InsufficientFunds,
|
539
542
|
},
|
540
543
|
},
|
541
544
|
'timeframes': {
|
@@ -4617,6 +4620,53 @@ class xt(Exchange, ImplicitAPI):
|
|
4617
4620
|
'status': None,
|
4618
4621
|
}
|
4619
4622
|
|
4623
|
+
async def set_margin_mode(self, marginMode: str, symbol: Str = None, params={}):
|
4624
|
+
"""
|
4625
|
+
set margin mode to 'cross' or 'isolated'
|
4626
|
+
|
4627
|
+
https://doc.xt.com/#futures_userchangePositionType
|
4628
|
+
|
4629
|
+
:param str marginMode: 'cross' or 'isolated'
|
4630
|
+
:param str [symbol]: required
|
4631
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
4632
|
+
:param str [params.positionSide]: *required* "long" or "short"
|
4633
|
+
:returns dict: response from the exchange
|
4634
|
+
"""
|
4635
|
+
if symbol is None:
|
4636
|
+
raise ArgumentsRequired(self.id + ' setMarginMode() requires a symbol argument')
|
4637
|
+
await self.load_markets()
|
4638
|
+
market = self.market(symbol)
|
4639
|
+
if market['spot']:
|
4640
|
+
raise BadSymbol(self.id + ' setMarginMode() supports contract markets only')
|
4641
|
+
marginMode = marginMode.lower()
|
4642
|
+
if marginMode != 'isolated' and marginMode != 'cross':
|
4643
|
+
raise BadRequest(self.id + ' setMarginMode() marginMode argument should be isolated or cross')
|
4644
|
+
if marginMode == 'cross':
|
4645
|
+
marginMode = 'CROSSED'
|
4646
|
+
else:
|
4647
|
+
marginMode = 'ISOLATED'
|
4648
|
+
posSide = self.safe_string_upper(params, 'positionSide')
|
4649
|
+
if posSide is None:
|
4650
|
+
raise ArgumentsRequired(self.id + ' setMarginMode() requires a positionSide parameter, either "LONG" or "SHORT"')
|
4651
|
+
request: dict = {
|
4652
|
+
'positionType': marginMode,
|
4653
|
+
'positionSide': posSide,
|
4654
|
+
'symbol': market['id'],
|
4655
|
+
}
|
4656
|
+
response = await self.privateLinearPostFutureUserV1PositionChangeType(self.extend(request, params))
|
4657
|
+
#
|
4658
|
+
# {
|
4659
|
+
# "error": {
|
4660
|
+
# "code": "",
|
4661
|
+
# "msg": ""
|
4662
|
+
# },
|
4663
|
+
# "msgInfo": "",
|
4664
|
+
# "result": {},
|
4665
|
+
# "returnCode": 0
|
4666
|
+
# }
|
4667
|
+
#
|
4668
|
+
return response # unify return type
|
4669
|
+
|
4620
4670
|
def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
|
4621
4671
|
#
|
4622
4672
|
# spot: error
|
@@ -4667,6 +4717,9 @@ class xt(Exchange, ImplicitAPI):
|
|
4667
4717
|
# "result": {}
|
4668
4718
|
# }
|
4669
4719
|
#
|
4720
|
+
# {"returnCode":1,"msgInfo":"failure","error":{"code":"insufficient_balance","msg":"insufficient balance","args":[]},"result":null}
|
4721
|
+
#
|
4722
|
+
#
|
4670
4723
|
status = self.safe_string_upper_2(response, 'msgInfo', 'mc')
|
4671
4724
|
if status is not None and status != 'SUCCESS':
|
4672
4725
|
feedback = self.id + ' ' + body
|
ccxt/base/errors.py
CHANGED
@@ -1,9 +1,3 @@
|
|
1
|
-
# ----------------------------------------------------------------------------
|
2
|
-
|
3
|
-
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
4
|
-
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
5
|
-
# EDIT THE CORRESPONDENT .ts FILE INSTEAD
|
6
|
-
|
7
1
|
error_hierarchy = {
|
8
2
|
'BaseError': {
|
9
3
|
'ExchangeError': {
|
ccxt/base/exchange.py
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
|
5
5
|
# -----------------------------------------------------------------------------
|
6
6
|
|
7
|
-
__version__ = '4.4.
|
7
|
+
__version__ = '4.4.58'
|
8
8
|
|
9
9
|
# -----------------------------------------------------------------------------
|
10
10
|
|
@@ -3657,7 +3657,7 @@ class Exchange(object):
|
|
3657
3657
|
change = self.omit_zero(self.safe_string(ticker, 'change'))
|
3658
3658
|
percentage = self.omit_zero(self.safe_string(ticker, 'percentage'))
|
3659
3659
|
average = self.omit_zero(self.safe_string(ticker, 'average'))
|
3660
|
-
vwap = self.
|
3660
|
+
vwap = self.safe_string(ticker, 'vwap')
|
3661
3661
|
baseVolume = self.safe_string(ticker, 'baseVolume')
|
3662
3662
|
quoteVolume = self.safe_string(ticker, 'quoteVolume')
|
3663
3663
|
if vwap is None:
|
@@ -5544,25 +5544,25 @@ class Exchange(object):
|
|
5544
5544
|
|
5545
5545
|
def create_post_only_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
|
5546
5546
|
if not self.has['createPostOnlyOrder']:
|
5547
|
-
raise NotSupported(self.id + 'createPostOnlyOrder() is not supported yet')
|
5547
|
+
raise NotSupported(self.id + ' createPostOnlyOrder() is not supported yet')
|
5548
5548
|
query = self.extend(params, {'postOnly': True})
|
5549
5549
|
return self.create_order(symbol, type, side, amount, price, query)
|
5550
5550
|
|
5551
5551
|
def create_post_only_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
|
5552
5552
|
if not self.has['createPostOnlyOrderWs']:
|
5553
|
-
raise NotSupported(self.id + 'createPostOnlyOrderWs() is not supported yet')
|
5553
|
+
raise NotSupported(self.id + ' createPostOnlyOrderWs() is not supported yet')
|
5554
5554
|
query = self.extend(params, {'postOnly': True})
|
5555
5555
|
return self.create_order_ws(symbol, type, side, amount, price, query)
|
5556
5556
|
|
5557
5557
|
def create_reduce_only_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
|
5558
5558
|
if not self.has['createReduceOnlyOrder']:
|
5559
|
-
raise NotSupported(self.id + 'createReduceOnlyOrder() is not supported yet')
|
5559
|
+
raise NotSupported(self.id + ' createReduceOnlyOrder() is not supported yet')
|
5560
5560
|
query = self.extend(params, {'reduceOnly': True})
|
5561
5561
|
return self.create_order(symbol, type, side, amount, price, query)
|
5562
5562
|
|
5563
5563
|
def create_reduce_only_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, params={}):
|
5564
5564
|
if not self.has['createReduceOnlyOrderWs']:
|
5565
|
-
raise NotSupported(self.id + 'createReduceOnlyOrderWs() is not supported yet')
|
5565
|
+
raise NotSupported(self.id + ' createReduceOnlyOrderWs() is not supported yet')
|
5566
5566
|
query = self.extend(params, {'reduceOnly': True})
|
5567
5567
|
return self.create_order_ws(symbol, type, side, amount, price, query)
|
5568
5568
|
|
ccxt/binance.py
CHANGED
@@ -1584,6 +1584,7 @@ class binance(Exchange, ImplicitAPI):
|
|
1584
1584
|
'legalMoneyCurrenciesById': {
|
1585
1585
|
'BUSD': 'USD',
|
1586
1586
|
},
|
1587
|
+
'defaultWithdrawPrecision': 0.00000001,
|
1587
1588
|
},
|
1588
1589
|
'features': {
|
1589
1590
|
'spot': {
|
@@ -1634,6 +1635,7 @@ class binance(Exchange, ImplicitAPI):
|
|
1634
1635
|
'limit': None,
|
1635
1636
|
'trigger': False,
|
1636
1637
|
'trailing': False,
|
1638
|
+
'symbolRequired': False,
|
1637
1639
|
},
|
1638
1640
|
'fetchOrders': {
|
1639
1641
|
'marginMode': True,
|
@@ -3096,6 +3098,7 @@ class binance(Exchange, ImplicitAPI):
|
|
3096
3098
|
id = self.safe_string(entry, 'coin')
|
3097
3099
|
name = self.safe_string(entry, 'name')
|
3098
3100
|
code = self.safe_currency_code(id)
|
3101
|
+
isFiat = self.safe_bool(entry, 'isLegalMoney')
|
3099
3102
|
minPrecision = None
|
3100
3103
|
isWithdrawEnabled = True
|
3101
3104
|
isDepositEnabled = True
|
@@ -3107,6 +3110,7 @@ class binance(Exchange, ImplicitAPI):
|
|
3107
3110
|
networkItem = networkList[j]
|
3108
3111
|
network = self.safe_string(networkItem, 'network')
|
3109
3112
|
networkCode = self.network_id_to_code(network)
|
3113
|
+
isETF = (network == 'ETF') # e.g. BTCUP, ETHDOWN
|
3110
3114
|
# name = self.safe_string(networkItem, 'name')
|
3111
3115
|
withdrawFee = self.safe_number(networkItem, 'withdrawFee')
|
3112
3116
|
depositEnable = self.safe_bool(networkItem, 'depositEnable')
|
@@ -3117,11 +3121,22 @@ class binance(Exchange, ImplicitAPI):
|
|
3117
3121
|
isDefault = self.safe_bool(networkItem, 'isDefault')
|
3118
3122
|
if isDefault or (fee is None):
|
3119
3123
|
fee = withdrawFee
|
3124
|
+
# todo: default networks in "setMarkets" overload
|
3125
|
+
# if isDefault:
|
3126
|
+
# self.options['defaultNetworkCodesForCurrencies'][code] = networkCode
|
3127
|
+
# }
|
3120
3128
|
precisionTick = self.safe_string(networkItem, 'withdrawIntegerMultiple')
|
3121
|
-
|
3122
|
-
#
|
3129
|
+
withdrawPrecision = precisionTick
|
3130
|
+
# avoid zero values, which are mostly from fiat or leveraged tokens or some abandoned coins : https://github.com/ccxt/ccxt/pull/14902#issuecomment-1271636731
|
3123
3131
|
if not Precise.string_eq(precisionTick, '0'):
|
3124
3132
|
minPrecision = precisionTick if (minPrecision is None) else Precise.string_min(minPrecision, precisionTick)
|
3133
|
+
else:
|
3134
|
+
if not isFiat and not isETF:
|
3135
|
+
# non-fiat and non-ETF currency, there are many cases when precision is set to zero(probably bug, we've reported to binance already)
|
3136
|
+
# in such cases, we can set default precision of 8(which is in UI for such coins)
|
3137
|
+
withdrawPrecision = self.omit_zero(self.safe_string(networkItem, 'withdrawInternalMin'))
|
3138
|
+
if withdrawPrecision is None:
|
3139
|
+
withdrawPrecision = self.safe_string(self.options, 'defaultWithdrawPrecision')
|
3125
3140
|
networks[networkCode] = {
|
3126
3141
|
'info': networkItem,
|
3127
3142
|
'id': network,
|
@@ -3130,7 +3145,7 @@ class binance(Exchange, ImplicitAPI):
|
|
3130
3145
|
'deposit': depositEnable,
|
3131
3146
|
'withdraw': withdrawEnable,
|
3132
3147
|
'fee': withdrawFee,
|
3133
|
-
'precision': self.parse_number(
|
3148
|
+
'precision': self.parse_number(withdrawPrecision),
|
3134
3149
|
'limits': {
|
3135
3150
|
'withdraw': {
|
3136
3151
|
'min': self.safe_number(networkItem, 'withdrawMin'),
|
@@ -3159,6 +3174,7 @@ class binance(Exchange, ImplicitAPI):
|
|
3159
3174
|
'id': id,
|
3160
3175
|
'name': name,
|
3161
3176
|
'code': code,
|
3177
|
+
'type': 'fiat' if isFiat else 'crypto',
|
3162
3178
|
'precision': self.parse_number(minPrecision),
|
3163
3179
|
'info': entry,
|
3164
3180
|
'active': active,
|
@@ -5272,10 +5288,10 @@ class binance(Exchange, ImplicitAPI):
|
|
5272
5288
|
request: dict = {
|
5273
5289
|
'symbol': market['id'],
|
5274
5290
|
'side': side.upper(),
|
5291
|
+
'orderId': id,
|
5292
|
+
'quantity': self.amount_to_precision(symbol, amount),
|
5275
5293
|
}
|
5276
5294
|
clientOrderId = self.safe_string_n(params, ['newClientOrderId', 'clientOrderId', 'origClientOrderId'])
|
5277
|
-
request['orderId'] = id
|
5278
|
-
request['quantity'] = self.amount_to_precision(symbol, amount)
|
5279
5295
|
if price is not None:
|
5280
5296
|
request['price'] = self.price_to_precision(symbol, price)
|
5281
5297
|
if clientOrderId is not None:
|
@@ -5289,6 +5305,8 @@ class binance(Exchange, ImplicitAPI):
|
|
5289
5305
|
|
5290
5306
|
https://developers.binance.com/docs/derivatives/usds-margined-futures/trade/rest-api/Modify-Order
|
5291
5307
|
https://developers.binance.com/docs/derivatives/coin-margined-futures/trade/Modify-Order
|
5308
|
+
https://developers.binance.com/docs/derivatives/portfolio-margin/trade/Modify-UM-Order
|
5309
|
+
https://developers.binance.com/docs/derivatives/portfolio-margin/trade/Modify-CM-Order
|
5292
5310
|
|
5293
5311
|
:param str id: cancel order id
|
5294
5312
|
:param str symbol: unified symbol of the market to create an order in
|
@@ -5297,16 +5315,28 @@ class binance(Exchange, ImplicitAPI):
|
|
5297
5315
|
:param float amount: how much of currency you want to trade in units of base currency
|
5298
5316
|
:param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
|
5299
5317
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
5318
|
+
:param boolean [params.portfolioMargin]: set to True if you would like to edit an order in a portfolio margin account
|
5300
5319
|
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
5301
5320
|
"""
|
5302
5321
|
self.load_markets()
|
5303
5322
|
market = self.market(symbol)
|
5323
|
+
isPortfolioMargin = None
|
5324
|
+
isPortfolioMargin, params = self.handle_option_and_params_2(params, 'editContractOrder', 'papi', 'portfolioMargin', False)
|
5325
|
+
if market['linear'] or isPortfolioMargin:
|
5326
|
+
if (price is None) and not ('priceMatch' in params):
|
5327
|
+
raise ArgumentsRequired(self.id + ' editOrder() requires a price argument for portfolio margin and linear orders')
|
5304
5328
|
request = self.edit_contract_order_request(id, symbol, type, side, amount, price, params)
|
5305
5329
|
response = None
|
5306
5330
|
if market['linear']:
|
5307
|
-
|
5331
|
+
if isPortfolioMargin:
|
5332
|
+
response = self.papiPutUmOrder(self.extend(request, params))
|
5333
|
+
else:
|
5334
|
+
response = self.fapiPrivatePutOrder(self.extend(request, params))
|
5308
5335
|
elif market['inverse']:
|
5309
|
-
|
5336
|
+
if isPortfolioMargin:
|
5337
|
+
response = self.papiPutCmOrder(self.extend(request, params))
|
5338
|
+
else:
|
5339
|
+
response = self.dapiPrivatePutOrder(self.extend(request, params))
|
5310
5340
|
#
|
5311
5341
|
# swap and future
|
5312
5342
|
#
|
@@ -12059,7 +12089,7 @@ class binance(Exchange, ImplicitAPI):
|
|
12059
12089
|
:returns dict: an array of `open interest structure <https://docs.ccxt.com/#/?id=open-interest-structure>`
|
12060
12090
|
"""
|
12061
12091
|
if timeframe == '1m':
|
12062
|
-
raise BadRequest(self.id + 'fetchOpenInterestHistory cannot use the 1m timeframe')
|
12092
|
+
raise BadRequest(self.id + ' fetchOpenInterestHistory cannot use the 1m timeframe')
|
12063
12093
|
self.load_markets()
|
12064
12094
|
paginate = False
|
12065
12095
|
paginate, params = self.handle_option_and_params(params, 'fetchOpenInterestHistory', 'paginate', False)
|
@@ -12818,7 +12848,7 @@ class binance(Exchange, ImplicitAPI):
|
|
12818
12848
|
elif market['inverse']:
|
12819
12849
|
response = self.dapiPrivateGetPositionMarginHistory(self.extend(request, params))
|
12820
12850
|
else:
|
12821
|
-
raise BadRequest(self.id + 'fetchMarginAdjustmentHistory() is not supported for markets of type ' + market['type'])
|
12851
|
+
raise BadRequest(self.id + ' fetchMarginAdjustmentHistory() is not supported for markets of type ' + market['type'])
|
12822
12852
|
#
|
12823
12853
|
# [
|
12824
12854
|
# {
|
ccxt/bitget.py
CHANGED
@@ -4632,7 +4632,7 @@ class bitget(Exchange, ImplicitAPI):
|
|
4632
4632
|
response = None
|
4633
4633
|
if market['spot']:
|
4634
4634
|
if triggerPrice is None:
|
4635
|
-
raise NotSupported(self.id + 'editOrder() only supports plan/trigger spot orders')
|
4635
|
+
raise NotSupported(self.id + ' editOrder() only supports plan/trigger spot orders')
|
4636
4636
|
editMarketBuyOrderRequiresPrice = self.safe_bool(self.options, 'editMarketBuyOrderRequiresPrice', True)
|
4637
4637
|
if editMarketBuyOrderRequiresPrice and isMarketOrder and (side == 'buy'):
|
4638
4638
|
if price is None:
|
@@ -8854,4 +8854,9 @@ class bitget(Exchange, ImplicitAPI):
|
|
8854
8854
|
}
|
8855
8855
|
if method == 'POST':
|
8856
8856
|
headers['Content-Type'] = 'application/json'
|
8857
|
+
sandboxMode = self.safe_bool(self.options, 'sandboxMode', False)
|
8858
|
+
if sandboxMode:
|
8859
|
+
if headers is None:
|
8860
|
+
headers = {}
|
8861
|
+
headers['PAPTRADING'] = 1
|
8857
8862
|
return {'url': url, 'method': method, 'body': body, 'headers': headers}
|
ccxt/bitmart.py
CHANGED
@@ -528,7 +528,10 @@ class bitmart(Exchange, ImplicitAPI):
|
|
528
528
|
'40049': InvalidOrder, # 403, The maximum length of clientOrderId cannot exceed 32
|
529
529
|
'40050': InvalidOrder, # 403, Client OrderId duplicated with existing orders
|
530
530
|
},
|
531
|
-
'broad': {
|
531
|
+
'broad': {
|
532
|
+
'You contract account available balance not enough': InsufficientFunds,
|
533
|
+
'you contract account available balance not enough': InsufficientFunds,
|
534
|
+
},
|
532
535
|
},
|
533
536
|
'commonCurrencies': {
|
534
537
|
'$GM': 'GOLDMINER',
|
@@ -968,6 +971,7 @@ class bitmart(Exchange, ImplicitAPI):
|
|
968
971
|
data = self.safe_dict(response, 'data', {})
|
969
972
|
symbols = self.safe_list(data, 'symbols', [])
|
970
973
|
result = []
|
974
|
+
fees = self.fees['trading']
|
971
975
|
for i in range(0, len(symbols)):
|
972
976
|
market = symbols[i]
|
973
977
|
id = self.safe_string(market, 'symbol')
|
@@ -1006,6 +1010,8 @@ class bitmart(Exchange, ImplicitAPI):
|
|
1006
1010
|
'expiryDatetime': None,
|
1007
1011
|
'strike': None,
|
1008
1012
|
'optionType': None,
|
1013
|
+
'maker': fees['maker'],
|
1014
|
+
'taker': fees['taker'],
|
1009
1015
|
'precision': {
|
1010
1016
|
'amount': baseMinSize,
|
1011
1017
|
'price': self.parse_number(self.parse_precision(self.safe_string(market, 'price_max_precision'))),
|
@@ -1077,6 +1083,7 @@ class bitmart(Exchange, ImplicitAPI):
|
|
1077
1083
|
data = self.safe_dict(response, 'data', {})
|
1078
1084
|
symbols = self.safe_list(data, 'symbols', [])
|
1079
1085
|
result = []
|
1086
|
+
fees = self.fees['trading']
|
1080
1087
|
for i in range(0, len(symbols)):
|
1081
1088
|
market = symbols[i]
|
1082
1089
|
id = self.safe_string(market, 'symbol')
|
@@ -1118,6 +1125,8 @@ class bitmart(Exchange, ImplicitAPI):
|
|
1118
1125
|
'expiryDatetime': self.iso8601(expiry),
|
1119
1126
|
'strike': None,
|
1120
1127
|
'optionType': None,
|
1128
|
+
'maker': fees['maker'],
|
1129
|
+
'taker': fees['taker'],
|
1121
1130
|
'precision': {
|
1122
1131
|
'amount': self.safe_number(market, 'vol_precision'),
|
1123
1132
|
'price': self.safe_number(market, 'price_precision'),
|
@@ -5085,6 +5094,7 @@ class bitmart(Exchange, ImplicitAPI):
|
|
5085
5094
|
# {"message":"Bad Request [from is empty]","code":50000,"trace":"579986f7-c93a-4559-926b-06ba9fa79d76","data":{}}
|
5086
5095
|
# {"message":"Kline size over 500","code":50004,"trace":"d625caa8-e8ca-4bd2-b77c-958776965819","data":{}}
|
5087
5096
|
# {"message":"Balance not enough","code":50020,"trace":"7c709d6a-3292-462c-98c5-32362540aeef","data":{}}
|
5097
|
+
# {"code":40012,"message":"You contract account available balance not enough.","trace":"..."}
|
5088
5098
|
#
|
5089
5099
|
# contract
|
5090
5100
|
#
|
@@ -5096,9 +5106,9 @@ class bitmart(Exchange, ImplicitAPI):
|
|
5096
5106
|
isErrorCode = (errorCode is not None) and (errorCode != '1000')
|
5097
5107
|
if isErrorCode or isErrorMessage:
|
5098
5108
|
feedback = self.id + ' ' + body
|
5099
|
-
self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
|
5100
|
-
self.throw_broadly_matched_exception(self.exceptions['broad'], errorCode, feedback)
|
5101
5109
|
self.throw_exactly_matched_exception(self.exceptions['exact'], message, feedback)
|
5102
5110
|
self.throw_broadly_matched_exception(self.exceptions['broad'], message, feedback)
|
5111
|
+
self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
|
5112
|
+
self.throw_broadly_matched_exception(self.exceptions['broad'], errorCode, feedback)
|
5103
5113
|
raise ExchangeError(feedback) # unknown message
|
5104
5114
|
return None
|
ccxt/blofin.py
CHANGED
ccxt/bybit.py
CHANGED
@@ -1420,8 +1420,8 @@ class bybit(Exchange, ImplicitAPI):
|
|
1420
1420
|
|
1421
1421
|
def create_expired_option_market(self, symbol: str):
|
1422
1422
|
# support expired option contracts
|
1423
|
-
quote =
|
1424
|
-
settle =
|
1423
|
+
quote = None
|
1424
|
+
settle = None
|
1425
1425
|
optionParts = symbol.split('-')
|
1426
1426
|
symbolBase = symbol.split('/')
|
1427
1427
|
base = None
|
@@ -1429,9 +1429,20 @@ class bybit(Exchange, ImplicitAPI):
|
|
1429
1429
|
if symbol.find('/') > -1:
|
1430
1430
|
base = self.safe_string(symbolBase, 0)
|
1431
1431
|
expiry = self.safe_string(optionParts, 1)
|
1432
|
+
symbolQuoteAndSettle = self.safe_string(symbolBase, 1)
|
1433
|
+
splitQuote = symbolQuoteAndSettle.split(':')
|
1434
|
+
quoteAndSettle = self.safe_string(splitQuote, 0)
|
1435
|
+
quote = quoteAndSettle
|
1436
|
+
settle = quoteAndSettle
|
1432
1437
|
else:
|
1433
1438
|
base = self.safe_string(optionParts, 0)
|
1434
1439
|
expiry = self.convert_market_id_expire_date(self.safe_string(optionParts, 1))
|
1440
|
+
if symbol.endswith('-USDT'):
|
1441
|
+
quote = 'USDT'
|
1442
|
+
settle = 'USDT'
|
1443
|
+
else:
|
1444
|
+
quote = 'USDC'
|
1445
|
+
settle = 'USDC'
|
1435
1446
|
strike = self.safe_string(optionParts, 2)
|
1436
1447
|
optionType = self.safe_string(optionParts, 3)
|
1437
1448
|
datetime = self.convert_expire_date(expiry)
|
@@ -6488,7 +6499,7 @@ classic accounts only/ spot not supported* fetches information on an order made
|
|
6488
6499
|
:returns: An array of open interest structures
|
6489
6500
|
"""
|
6490
6501
|
if timeframe == '1m':
|
6491
|
-
raise BadRequest(self.id + 'fetchOpenInterestHistory cannot use the 1m timeframe')
|
6502
|
+
raise BadRequest(self.id + ' fetchOpenInterestHistory cannot use the 1m timeframe')
|
6492
6503
|
self.load_markets()
|
6493
6504
|
paginate = self.safe_bool(params, 'paginate')
|
6494
6505
|
if paginate:
|
@@ -8704,6 +8715,8 @@ classic accounts only/ spot not supported* fetches information on an order made
|
|
8704
8715
|
feedback = self.id + ' private api uses /user/v3/private/query-api to check if you have a unified account. The API key of user id must own one of permissions: "Account Transfer", "Subaccount Transfer", "Withdrawal" ' + body
|
8705
8716
|
else:
|
8706
8717
|
feedback = self.id + ' ' + body
|
8718
|
+
if body.find('Withdraw address chain or destination tag are not equal'):
|
8719
|
+
feedback = feedback + '; You might also need to ensure the address is whitelisted'
|
8707
8720
|
self.throw_broadly_matched_exception(self.exceptions['broad'], body, feedback)
|
8708
8721
|
self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
|
8709
8722
|
raise ExchangeError(feedback) # unknown message
|
ccxt/coinbase.py
CHANGED
@@ -452,7 +452,7 @@ class coinbase(Exchange, ImplicitAPI):
|
|
452
452
|
'symbolRequired': False,
|
453
453
|
},
|
454
454
|
'fetchOHLCV': {
|
455
|
-
'limit':
|
455
|
+
'limit': 300,
|
456
456
|
},
|
457
457
|
},
|
458
458
|
'spot': {
|
@@ -4795,10 +4795,17 @@ class coinbase(Exchange, ImplicitAPI):
|
|
4795
4795
|
# }
|
4796
4796
|
# ]
|
4797
4797
|
# }
|
4798
|
+
# or
|
4799
|
+
# {
|
4800
|
+
# "error": "UNKNOWN_FAILURE_REASON",
|
4801
|
+
# "message": "",
|
4802
|
+
# "error_details": "",
|
4803
|
+
# "preview_failure_reason": "PREVIEW_STOP_PRICE_BELOW_LAST_TRADE_PRICE"
|
4804
|
+
# }
|
4798
4805
|
#
|
4799
4806
|
errorCode = self.safe_string(response, 'error')
|
4800
4807
|
if errorCode is not None:
|
4801
|
-
errorMessage = self.
|
4808
|
+
errorMessage = self.safe_string_2(response, 'error_description', 'preview_failure_reason')
|
4802
4809
|
self.throw_exactly_matched_exception(self.exceptions['exact'], errorCode, feedback)
|
4803
4810
|
self.throw_broadly_matched_exception(self.exceptions['broad'], errorMessage, feedback)
|
4804
4811
|
raise ExchangeError(feedback)
|
ccxt/coinbaseinternational.py
CHANGED
@@ -1684,7 +1684,7 @@ class coinbaseinternational(Exchange, ImplicitAPI):
|
|
1684
1684
|
request['type'] = typeId
|
1685
1685
|
if type == 'limit':
|
1686
1686
|
if price is None:
|
1687
|
-
raise InvalidOrder(self.id + 'createOrder() requires a price parameter for a limit order types')
|
1687
|
+
raise InvalidOrder(self.id + ' createOrder() requires a price parameter for a limit order types')
|
1688
1688
|
request['price'] = price
|
1689
1689
|
portfolio = None
|
1690
1690
|
portfolio, params = self.handle_portfolio_and_params('createOrder', params)
|
@@ -1695,7 +1695,7 @@ class coinbaseinternational(Exchange, ImplicitAPI):
|
|
1695
1695
|
# market orders must be IOC
|
1696
1696
|
if typeId == 'MARKET':
|
1697
1697
|
if tif is not None and tif != 'IOC':
|
1698
|
-
raise InvalidOrder(self.id + 'createOrder() market orders must have tif set to "IOC"')
|
1698
|
+
raise InvalidOrder(self.id + ' createOrder() market orders must have tif set to "IOC"')
|
1699
1699
|
tif = 'IOC'
|
1700
1700
|
else:
|
1701
1701
|
tif = 'GTC' if (tif is None) else tif
|
ccxt/coinex.py
CHANGED
@@ -4615,7 +4615,7 @@ class coinex(Exchange, ImplicitAPI):
|
|
4615
4615
|
request: dict = {
|
4616
4616
|
'ccy': currency['id'],
|
4617
4617
|
'to_address': address, # must be authorized, inter-user transfer by a registered mobile phone number or an email address is supported
|
4618
|
-
'amount': self.
|
4618
|
+
'amount': self.currency_to_precision(code, amount), # the actual amount without fees, https://www.coinex.com/fees
|
4619
4619
|
}
|
4620
4620
|
if tag is not None:
|
4621
4621
|
request['memo'] = tag
|
ccxt/deribit.py
CHANGED
@@ -498,9 +498,6 @@ class deribit(Exchange, ImplicitAPI):
|
|
498
498
|
'fetchBalance': {
|
499
499
|
'code': 'BTC',
|
500
500
|
},
|
501
|
-
'fetchPositions': {
|
502
|
-
'code': 'BTC',
|
503
|
-
},
|
504
501
|
'transfer': {
|
505
502
|
'method': 'privateGetSubmitTransferToSubaccount', # or 'privateGetSubmitTransferToUser'
|
506
503
|
},
|
@@ -2663,32 +2660,18 @@ class deribit(Exchange, ImplicitAPI):
|
|
2663
2660
|
|
2664
2661
|
:param str[]|None symbols: list of unified market symbols
|
2665
2662
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
2663
|
+
:param str [params.currency]: currency code filter for positions
|
2666
2664
|
:param str [params.kind]: market type filter for positions 'future', 'option', 'spot', 'future_combo' or 'option_combo'
|
2665
|
+
:param int [params.subaccount_id]: the user id for the subaccount
|
2667
2666
|
:returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
|
2668
2667
|
"""
|
2669
2668
|
self.load_markets()
|
2670
|
-
|
2671
|
-
|
2672
|
-
if
|
2673
|
-
|
2674
|
-
|
2675
|
-
|
2676
|
-
symbols = None # fix https://github.com/ccxt/ccxt/issues/13961
|
2677
|
-
else:
|
2678
|
-
if isinstance(symbols, list):
|
2679
|
-
length = len(symbols)
|
2680
|
-
if length != 1:
|
2681
|
-
raise BadRequest(self.id + ' fetchPositions() symbols argument cannot contain more than 1 symbol')
|
2682
|
-
market = self.market(symbols[0])
|
2683
|
-
settle = market['settle']
|
2684
|
-
code = settle if (settle is not None) else market['base']
|
2685
|
-
kind = market['info']['kind']
|
2686
|
-
currency = self.currency(code)
|
2687
|
-
request: dict = {
|
2688
|
-
'currency': currency['id'],
|
2689
|
-
}
|
2690
|
-
if kind is not None:
|
2691
|
-
request['kind'] = kind
|
2669
|
+
code = self.safe_string(params, 'currency')
|
2670
|
+
request: dict = {}
|
2671
|
+
if code is not None:
|
2672
|
+
params = self.omit(params, 'currency')
|
2673
|
+
currency = self.currency(code)
|
2674
|
+
request['currency'] = currency['id']
|
2692
2675
|
response = self.privateGetGetPositions(self.extend(request, params))
|
2693
2676
|
#
|
2694
2677
|
# {
|
ccxt/exmo.py
CHANGED
@@ -1351,7 +1351,7 @@ class exmo(Exchange, ImplicitAPI):
|
|
1351
1351
|
marginMode = None
|
1352
1352
|
marginMode, params = self.handle_margin_mode_and_params('fetchMyTrades', params)
|
1353
1353
|
if marginMode == 'cross':
|
1354
|
-
raise BadRequest(self.id + 'only isolated margin is supported')
|
1354
|
+
raise BadRequest(self.id + ' only isolated margin is supported')
|
1355
1355
|
self.load_markets()
|
1356
1356
|
market = self.market(symbol)
|
1357
1357
|
pair = market['id']
|