ccxt 4.4.75__py2.py3-none-any.whl → 4.4.77__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 -1
- ccxt/abstract/myokx.py +4 -0
- ccxt/abstract/okx.py +4 -0
- ccxt/abstract/upbit.py +51 -37
- ccxt/abstract/xt.py +3 -0
- ccxt/async_support/__init__.py +1 -1
- ccxt/async_support/base/exchange.py +2 -2
- ccxt/async_support/binance.py +36 -214
- ccxt/async_support/bitget.py +1 -1
- ccxt/async_support/bitrue.py +48 -0
- ccxt/async_support/coinex.py +2 -0
- ccxt/async_support/coinlist.py +85 -2
- ccxt/async_support/okx.py +20 -8
- ccxt/async_support/paradex.py +3 -8
- ccxt/async_support/upbit.py +64 -46
- ccxt/async_support/xt.py +106 -3
- ccxt/base/errors.py +0 -6
- ccxt/base/exchange.py +8 -2
- ccxt/binance.py +36 -214
- ccxt/bitget.py +1 -1
- ccxt/bitrue.py +48 -0
- ccxt/coinex.py +2 -0
- ccxt/coinlist.py +85 -2
- ccxt/okx.py +20 -8
- ccxt/paradex.py +3 -8
- ccxt/pro/__init__.py +1 -1
- ccxt/pro/hyperliquid.py +1 -1
- ccxt/test/tests_async.py +23 -0
- ccxt/test/tests_sync.py +23 -0
- ccxt/upbit.py +64 -46
- ccxt/xt.py +106 -3
- {ccxt-4.4.75.dist-info → ccxt-4.4.77.dist-info}/METADATA +4 -4
- {ccxt-4.4.75.dist-info → ccxt-4.4.77.dist-info}/RECORD +36 -36
- {ccxt-4.4.75.dist-info → ccxt-4.4.77.dist-info}/LICENSE.txt +0 -0
- {ccxt-4.4.75.dist-info → ccxt-4.4.77.dist-info}/WHEEL +0 -0
- {ccxt-4.4.75.dist-info → ccxt-4.4.77.dist-info}/top_level.txt +0 -0
ccxt/async_support/coinlist.py
CHANGED
@@ -7,7 +7,7 @@ from ccxt.async_support.base.exchange import Exchange
|
|
7
7
|
from ccxt.abstract.coinlist import ImplicitAPI
|
8
8
|
import hashlib
|
9
9
|
import math
|
10
|
-
from ccxt.base.types import Account, Any, Balances, Currencies, Currency, Int, LedgerEntry, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, Trade, TradingFees, Transaction, TransferEntry
|
10
|
+
from ccxt.base.types import Account, Any, Balances, Currencies, Currency, Int, LedgerEntry, Market, Num, Order, OrderBook, OrderSide, OrderType, Str, Strings, Ticker, Tickers, FundingRate, Trade, TradingFees, Transaction, TransferEntry
|
11
11
|
from typing import List
|
12
12
|
from ccxt.base.errors import ExchangeError
|
13
13
|
from ccxt.base.errors import AuthenticationError
|
@@ -79,7 +79,7 @@ class coinlist(Exchange, ImplicitAPI):
|
|
79
79
|
'fetchDepositWithdrawFee': False,
|
80
80
|
'fetchDepositWithdrawFees': False,
|
81
81
|
'fetchFundingHistory': False,
|
82
|
-
'fetchFundingRate':
|
82
|
+
'fetchFundingRate': True,
|
83
83
|
'fetchFundingRateHistory': False,
|
84
84
|
'fetchFundingRates': False,
|
85
85
|
'fetchIndexOHLCV': False,
|
@@ -2405,6 +2405,89 @@ class coinlist(Exchange, ImplicitAPI):
|
|
2405
2405
|
}
|
2406
2406
|
return self.safe_string(types, type, type)
|
2407
2407
|
|
2408
|
+
async def fetch_funding_rate(self, symbol: str, params={}) -> FundingRate:
|
2409
|
+
"""
|
2410
|
+
fetch the current funding rate
|
2411
|
+
|
2412
|
+
https://trade-docs.coinlist.co/#coinlist-pro-api-Funding-Rates
|
2413
|
+
|
2414
|
+
:param str symbol: unified market symbol
|
2415
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
2416
|
+
:returns dict: a `funding rate structure <https://docs.ccxt.com/#/?id=funding-rate-structure>`
|
2417
|
+
"""
|
2418
|
+
await self.load_markets()
|
2419
|
+
market = self.market(symbol)
|
2420
|
+
if not market['swap']:
|
2421
|
+
raise BadSymbol(self.id + ' fetchFundingRate() supports swap contracts only')
|
2422
|
+
request: dict = {
|
2423
|
+
'symbol': market['id'],
|
2424
|
+
}
|
2425
|
+
response = await self.publicGetV1SymbolsSymbolFunding(self.extend(request, params))
|
2426
|
+
#
|
2427
|
+
# {
|
2428
|
+
# "last": {
|
2429
|
+
# "funding_rate": "-0.00043841",
|
2430
|
+
# "funding_time": "2025-04-15T04:00:00.000Z"
|
2431
|
+
# },
|
2432
|
+
# "next": {
|
2433
|
+
# "funding_rate": "-0.00046952",
|
2434
|
+
# "funding_time": "2025-04-15T12:00:00.000Z"
|
2435
|
+
# },
|
2436
|
+
# "indicative": {
|
2437
|
+
# "funding_rate": "-0.00042517",
|
2438
|
+
# "funding_time": "2025-04-15T20:00:00.000Z"
|
2439
|
+
# },
|
2440
|
+
# "timestamp": "2025-04-15T07:01:15.219Z"
|
2441
|
+
# }
|
2442
|
+
#
|
2443
|
+
return self.parse_funding_rate(response, market)
|
2444
|
+
|
2445
|
+
def parse_funding_rate(self, contract, market: Market = None) -> FundingRate:
|
2446
|
+
#
|
2447
|
+
# {
|
2448
|
+
# "last": {
|
2449
|
+
# "funding_rate": "-0.00043841",
|
2450
|
+
# "funding_time": "2025-04-15T04:00:00.000Z"
|
2451
|
+
# },
|
2452
|
+
# "next": {
|
2453
|
+
# "funding_rate": "-0.00046952",
|
2454
|
+
# "funding_time": "2025-04-15T12:00:00.000Z"
|
2455
|
+
# },
|
2456
|
+
# "indicative": {
|
2457
|
+
# "funding_rate": "-0.00042517",
|
2458
|
+
# "funding_time": "2025-04-15T20:00:00.000Z"
|
2459
|
+
# },
|
2460
|
+
# "timestamp": "2025-04-15T07:01:15.219Z"
|
2461
|
+
# }
|
2462
|
+
#
|
2463
|
+
previous = self.safe_dict(contract, 'last', {})
|
2464
|
+
current = self.safe_dict(contract, 'next', {})
|
2465
|
+
next = self.safe_dict(contract, 'indicative', {})
|
2466
|
+
previousDatetime = self.safe_string(previous, 'funding_time')
|
2467
|
+
currentDatetime = self.safe_string(current, 'funding_time')
|
2468
|
+
nextDatetime = self.safe_string(next, 'funding_time')
|
2469
|
+
datetime = self.safe_string(contract, 'timestamp')
|
2470
|
+
return {
|
2471
|
+
'info': contract,
|
2472
|
+
'symbol': self.safe_symbol(None, market),
|
2473
|
+
'markPrice': None,
|
2474
|
+
'indexPrice': None,
|
2475
|
+
'interestRate': None,
|
2476
|
+
'estimatedSettlePrice': None,
|
2477
|
+
'timestamp': self.parse8601(datetime),
|
2478
|
+
'datetime': datetime,
|
2479
|
+
'fundingRate': self.safe_number(current, 'funding_rate'),
|
2480
|
+
'fundingTimestamp': self.parse8601(currentDatetime),
|
2481
|
+
'fundingDatetime': currentDatetime,
|
2482
|
+
'nextFundingRate': self.safe_number(next, 'funding_rate'),
|
2483
|
+
'nextFundingTimestamp': self.parse8601(nextDatetime),
|
2484
|
+
'nextFundingDatetime': nextDatetime,
|
2485
|
+
'previousFundingRate': self.safe_number(previous, 'funding_rate'),
|
2486
|
+
'previousFundingTimestamp': self.parse8601(previousDatetime),
|
2487
|
+
'previousFundingDatetime': previousDatetime,
|
2488
|
+
'interval': '8h',
|
2489
|
+
}
|
2490
|
+
|
2408
2491
|
def sign(self, path, api='public', method='GET', params={}, headers=None, body=None):
|
2409
2492
|
request = self.omit(params, self.extract_params(path))
|
2410
2493
|
endpoint = '/' + self.implode_params(path, params)
|
ccxt/async_support/okx.py
CHANGED
@@ -398,6 +398,7 @@ class okx(Exchange, ImplicitAPI):
|
|
398
398
|
'asset/subaccount/managed-subaccount-bills': 5 / 3,
|
399
399
|
'users/entrust-subaccount-list': 10,
|
400
400
|
'account/subaccount/interest-limits': 4,
|
401
|
+
'users/subaccount/apikey': 10,
|
401
402
|
# grid trading
|
402
403
|
'tradingBot/grid/orders-algo-pending': 1,
|
403
404
|
'tradingBot/grid/orders-algo-history': 1,
|
@@ -530,6 +531,9 @@ class okx(Exchange, ImplicitAPI):
|
|
530
531
|
'asset/subaccount/transfer': 10,
|
531
532
|
'users/subaccount/set-transfer-out': 10,
|
532
533
|
'account/subaccount/set-loan-allocation': 4,
|
534
|
+
'users/subaccount/create-subaccount': 10,
|
535
|
+
'users/subaccount/subaccount-apikey': 10,
|
536
|
+
'users/subaccount/delete-apikey': 10,
|
533
537
|
# grid trading
|
534
538
|
'tradingBot/grid/order-algo': 1,
|
535
539
|
'tradingBot/grid/amend-order-algo': 1,
|
@@ -940,6 +944,11 @@ class okx(Exchange, ImplicitAPI):
|
|
940
944
|
'59506': ExchangeError, # APIKey does not exist
|
941
945
|
'59507': ExchangeError, # The two accounts involved in a transfer must be two different sub accounts under the same parent account
|
942
946
|
'59508': AccountSuspended, # The sub account of {0} is suspended
|
947
|
+
'59515': ExchangeError, # You are currently not on the custody whitelist. Please contact customer service for assistance.
|
948
|
+
'59516': ExchangeError, # Please create the Copper custody funding account first.
|
949
|
+
'59517': ExchangeError, # Please create the Komainu custody funding account first.
|
950
|
+
'59518': ExchangeError, # You can’t create a sub-account using the API; please use the app or web.
|
951
|
+
'59519': ExchangeError, # You can’t use self function/feature while it's frozen, due to: {freezereason}
|
943
952
|
'59642': BadRequest, # Lead and copy traders can only use margin-free or single-currency margin account modes
|
944
953
|
'59643': ExchangeError, # Couldn’t switch account modes’re currently copying spot trades
|
945
954
|
# WebSocket error Codes from 60000-63999
|
@@ -1608,8 +1617,8 @@ class okx(Exchange, ImplicitAPI):
|
|
1608
1617
|
swap = (type == 'swap')
|
1609
1618
|
option = (type == 'option')
|
1610
1619
|
contract = swap or future or option
|
1611
|
-
baseId = self.safe_string(market, 'baseCcy')
|
1612
|
-
quoteId = self.safe_string(market, 'quoteCcy')
|
1620
|
+
baseId = self.safe_string(market, 'baseCcy', '') # defaulting to '' because some weird preopen markets have empty baseId
|
1621
|
+
quoteId = self.safe_string(market, 'quoteCcy', '')
|
1613
1622
|
settleId = self.safe_string(market, 'settleCcy')
|
1614
1623
|
settle = self.safe_currency_code(settleId)
|
1615
1624
|
underlying = self.safe_string(market, 'uly')
|
@@ -1624,18 +1633,21 @@ class okx(Exchange, ImplicitAPI):
|
|
1624
1633
|
strikePrice = None
|
1625
1634
|
optionType = None
|
1626
1635
|
if contract:
|
1627
|
-
|
1636
|
+
if settle is not None:
|
1637
|
+
symbol = symbol + ':' + settle
|
1628
1638
|
if future:
|
1629
1639
|
expiry = self.safe_integer(market, 'expTime')
|
1630
|
-
|
1631
|
-
|
1640
|
+
if expiry is not None:
|
1641
|
+
ymd = self.yymmdd(expiry)
|
1642
|
+
symbol = symbol + '-' + ymd
|
1632
1643
|
elif option:
|
1633
1644
|
expiry = self.safe_integer(market, 'expTime')
|
1634
1645
|
strikePrice = self.safe_string(market, 'stk')
|
1635
1646
|
optionType = self.safe_string(market, 'optType')
|
1636
|
-
|
1637
|
-
|
1638
|
-
|
1647
|
+
if expiry is not None:
|
1648
|
+
ymd = self.yymmdd(expiry)
|
1649
|
+
symbol = symbol + '-' + ymd + '-' + strikePrice + '-' + optionType
|
1650
|
+
optionType = 'put' if (optionType == 'P') else 'call'
|
1639
1651
|
tickSize = self.safe_string(market, 'tickSz')
|
1640
1652
|
fees = self.safe_dict_2(self.fees, type, 'trading', {})
|
1641
1653
|
maxLeverage = self.safe_string(market, 'lever', '1')
|
ccxt/async_support/paradex.py
CHANGED
@@ -703,14 +703,9 @@ class paradex(Exchange, ImplicitAPI):
|
|
703
703
|
"""
|
704
704
|
await self.load_markets()
|
705
705
|
symbols = self.market_symbols(symbols)
|
706
|
-
request: dict = {
|
707
|
-
|
708
|
-
|
709
|
-
request['market'] = self.market_id(symbols[0])
|
710
|
-
else:
|
711
|
-
request['market'] = self.market_id(symbols)
|
712
|
-
else:
|
713
|
-
request['market'] = 'ALL'
|
706
|
+
request: dict = {
|
707
|
+
'market': 'ALL',
|
708
|
+
}
|
714
709
|
response = await self.publicGetMarketsSummary(self.extend(request, params))
|
715
710
|
#
|
716
711
|
# {
|
ccxt/async_support/upbit.py
CHANGED
@@ -28,7 +28,7 @@ class upbit(Exchange, ImplicitAPI):
|
|
28
28
|
'name': 'Upbit',
|
29
29
|
'countries': ['KR'],
|
30
30
|
'version': 'v1',
|
31
|
-
'rateLimit':
|
31
|
+
'rateLimit': 50,
|
32
32
|
'pro': True,
|
33
33
|
# new metainfo interface
|
34
34
|
'has': {
|
@@ -83,6 +83,7 @@ class upbit(Exchange, ImplicitAPI):
|
|
83
83
|
'withdraw': True,
|
84
84
|
},
|
85
85
|
'timeframes': {
|
86
|
+
'1s': 'seconds',
|
86
87
|
'1m': 'minutes',
|
87
88
|
'3m': 'minutes',
|
88
89
|
'5m': 'minutes',
|
@@ -94,6 +95,7 @@ class upbit(Exchange, ImplicitAPI):
|
|
94
95
|
'1d': 'days',
|
95
96
|
'1w': 'weeks',
|
96
97
|
'1M': 'months',
|
98
|
+
'1y': 'years',
|
97
99
|
},
|
98
100
|
'hostname': 'api.upbit.com',
|
99
101
|
'urls': {
|
@@ -107,54 +109,70 @@ class upbit(Exchange, ImplicitAPI):
|
|
107
109
|
'fees': 'https://upbit.com/service_center/guide',
|
108
110
|
},
|
109
111
|
'api': {
|
112
|
+
# 'endpoint','API Cost'
|
113
|
+
# cost = 1000 / (rateLimit * RPS)
|
110
114
|
'public': {
|
111
|
-
'get':
|
112
|
-
'market/all',
|
113
|
-
'candles/{timeframe}',
|
114
|
-
'candles/{timeframe}/{unit}',
|
115
|
-
'candles/
|
116
|
-
'candles/minutes/
|
117
|
-
'candles/minutes/
|
118
|
-
'candles/minutes/
|
119
|
-
'candles/minutes/
|
120
|
-
'candles/minutes/
|
121
|
-
'candles/minutes/
|
122
|
-
'candles/minutes/
|
123
|
-
'candles/minutes/
|
124
|
-
'candles/
|
125
|
-
'candles/
|
126
|
-
'candles/
|
127
|
-
'
|
128
|
-
'
|
129
|
-
'
|
130
|
-
|
115
|
+
'get': {
|
116
|
+
'market/all': 2, # RPS: 10
|
117
|
+
'candles/{timeframe}': 2,
|
118
|
+
'candles/{timeframe}/{unit}': 2,
|
119
|
+
'candles/seconds': 2,
|
120
|
+
'candles/minutes/{unit}': 2,
|
121
|
+
'candles/minutes/1': 2,
|
122
|
+
'candles/minutes/3': 2,
|
123
|
+
'candles/minutes/5': 2,
|
124
|
+
'candles/minutes/10': 2,
|
125
|
+
'candles/minutes/15': 2,
|
126
|
+
'candles/minutes/30': 2,
|
127
|
+
'candles/minutes/60': 2,
|
128
|
+
'candles/minutes/240': 2,
|
129
|
+
'candles/days': 2,
|
130
|
+
'candles/weeks': 2,
|
131
|
+
'candles/months': 2,
|
132
|
+
'candles/years': 2,
|
133
|
+
'trades/ticks': 2,
|
134
|
+
'ticker': 2,
|
135
|
+
'ticker/all': 2,
|
136
|
+
'orderbook': 2,
|
137
|
+
'orderbook/supported_levels': 2, # Upbit KR only
|
138
|
+
},
|
131
139
|
},
|
132
140
|
'private': {
|
133
|
-
'get':
|
134
|
-
'accounts',
|
135
|
-
'orders/chance',
|
136
|
-
'order',
|
137
|
-
'orders',
|
138
|
-
'orders/
|
139
|
-
'orders/
|
140
|
-
'
|
141
|
-
'
|
142
|
-
'
|
143
|
-
'withdraws/
|
144
|
-
'deposits',
|
145
|
-
'
|
146
|
-
'
|
147
|
-
'deposits/
|
148
|
-
|
149
|
-
|
150
|
-
'
|
151
|
-
'
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
'
|
157
|
-
|
141
|
+
'get': {
|
142
|
+
'accounts': 0.67, # RPS: 30
|
143
|
+
'orders/chance': 0.67,
|
144
|
+
'order': 0.67,
|
145
|
+
'orders/closed': 0.67,
|
146
|
+
'orders/open': 0.67,
|
147
|
+
'orders/uuids': 0.67,
|
148
|
+
'withdraws': 0.67,
|
149
|
+
'withdraw': 0.67,
|
150
|
+
'withdraws/chance': 0.67,
|
151
|
+
'withdraws/coin_addresses': 0.67,
|
152
|
+
'deposits': 0.67,
|
153
|
+
'deposits/chance/coin': 0.67,
|
154
|
+
'deposit': 0.67,
|
155
|
+
'deposits/coin_addresses': 0.67,
|
156
|
+
'deposits/coin_address': 0.67,
|
157
|
+
'travel_rule/vasps': 0.67,
|
158
|
+
'status/wallet': 0.67, # Upbit KR only
|
159
|
+
'api_keys': 0.67, # Upbit KR only
|
160
|
+
},
|
161
|
+
'post': {
|
162
|
+
'orders': 2.5, # RPS: 8
|
163
|
+
'orders/cancel_and_new': 2.5, # RPS: 8
|
164
|
+
'withdraws/coin': 0.67,
|
165
|
+
'withdraws/krw': 0.67, # Upbit KR only.
|
166
|
+
'deposits/krw': 0.67, # Upbit KR only.
|
167
|
+
'deposits/generate_coin_address': 0.67,
|
168
|
+
'travel_rule/deposit/uuid': 0.67, # RPS: 30, but each deposit can only be queried once every 10 minutes
|
169
|
+
'travel_rule/deposit/txid': 0.67, # RPS: 30, but each deposit can only be queried once every 10 minutes
|
170
|
+
},
|
171
|
+
'delete': {
|
172
|
+
'order': 0.67,
|
173
|
+
'orders/open': 40, # RPS: 0.5
|
174
|
+
'orders/uuids': 0.67,
|
175
|
+
},
|
158
176
|
},
|
159
177
|
},
|
160
178
|
'fees': {
|
ccxt/async_support/xt.py
CHANGED
@@ -59,7 +59,7 @@ class xt(Exchange, ImplicitAPI):
|
|
59
59
|
'createOrder': True,
|
60
60
|
'createPostOnlyOrder': False,
|
61
61
|
'createReduceOnlyOrder': True,
|
62
|
-
'editOrder':
|
62
|
+
'editOrder': True,
|
63
63
|
'fetchAccounts': False,
|
64
64
|
'fetchBalance': True,
|
65
65
|
'fetchBidsAsks': True,
|
@@ -246,6 +246,9 @@ class xt(Exchange, ImplicitAPI):
|
|
246
246
|
'open-order': 1,
|
247
247
|
'order/{orderId}': 1,
|
248
248
|
},
|
249
|
+
'put': {
|
250
|
+
'order/{orderId}': 1,
|
251
|
+
},
|
249
252
|
},
|
250
253
|
'linear': {
|
251
254
|
'get': {
|
@@ -280,6 +283,7 @@ class xt(Exchange, ImplicitAPI):
|
|
280
283
|
'future/trade/v1/order/cancel-all': 1,
|
281
284
|
'future/trade/v1/order/create': 1,
|
282
285
|
'future/trade/v1/order/create-batch': 1,
|
286
|
+
'future/trade/v1/order/update': 1,
|
283
287
|
'future/user/v1/account/open': 1,
|
284
288
|
'future/user/v1/position/adjust-leverage': 1,
|
285
289
|
'future/user/v1/position/auto-margin': 1,
|
@@ -323,6 +327,7 @@ class xt(Exchange, ImplicitAPI):
|
|
323
327
|
'future/trade/v1/order/cancel-all': 1,
|
324
328
|
'future/trade/v1/order/create': 1,
|
325
329
|
'future/trade/v1/order/create-batch': 1,
|
330
|
+
'future/trade/v1/order/update': 1,
|
326
331
|
'future/user/v1/account/open': 1,
|
327
332
|
'future/user/v1/position/adjust-leverage': 1,
|
328
333
|
'future/user/v1/position/auto-margin': 1,
|
@@ -3338,7 +3343,7 @@ class xt(Exchange, ImplicitAPI):
|
|
3338
3343
|
# "cancelId": "208322474307982720"
|
3339
3344
|
# }
|
3340
3345
|
#
|
3341
|
-
# swap and future: createOrder, cancelOrder
|
3346
|
+
# swap and future: createOrder, cancelOrder, editOrder
|
3342
3347
|
#
|
3343
3348
|
# {
|
3344
3349
|
# "returnCode": 0,
|
@@ -3443,6 +3448,14 @@ class xt(Exchange, ImplicitAPI):
|
|
3443
3448
|
# "createdTime": 1681273420039
|
3444
3449
|
# }
|
3445
3450
|
#
|
3451
|
+
# spot editOrder
|
3452
|
+
#
|
3453
|
+
# {
|
3454
|
+
# "orderId": "484203027161892224",
|
3455
|
+
# "modifyId": "484203544105344000",
|
3456
|
+
# "clientModifyId": null
|
3457
|
+
# }
|
3458
|
+
#
|
3446
3459
|
marketId = self.safe_string(order, 'symbol')
|
3447
3460
|
marketType = ('result' in order) or 'contract' if ('positionSide' in order) else 'spot'
|
3448
3461
|
market = self.safe_market(marketId, market, None, marketType)
|
@@ -3456,7 +3469,7 @@ class xt(Exchange, ImplicitAPI):
|
|
3456
3469
|
return self.safe_order({
|
3457
3470
|
'info': order,
|
3458
3471
|
'id': self.safe_string_n(order, ['orderId', 'result', 'cancelId', 'entrustId', 'profitId']),
|
3459
|
-
'clientOrderId': self.
|
3472
|
+
'clientOrderId': self.safe_string_2(order, 'clientOrderId', 'clientModifyId'),
|
3460
3473
|
'timestamp': timestamp,
|
3461
3474
|
'datetime': self.iso8601(timestamp),
|
3462
3475
|
'lastTradeTimestamp': lastUpdatedTimestamp,
|
@@ -4679,6 +4692,94 @@ class xt(Exchange, ImplicitAPI):
|
|
4679
4692
|
#
|
4680
4693
|
return response # unify return type
|
4681
4694
|
|
4695
|
+
async def edit_order(self, id: str, symbol: str, type: OrderType, side: OrderSide, amount: Num = None, price: Num = None, params={}) -> Order:
|
4696
|
+
"""
|
4697
|
+
cancels an order and places a new order
|
4698
|
+
|
4699
|
+
https://doc.xt.com/#orderorderUpdate
|
4700
|
+
https://doc.xt.com/#futures_orderupdate
|
4701
|
+
https://doc.xt.com/#futures_entrustupdateProfit
|
4702
|
+
|
4703
|
+
:param str id: order id
|
4704
|
+
:param str symbol: unified symbol of the market to create an order in
|
4705
|
+
:param str type: 'market' or 'limit'
|
4706
|
+
:param str side: 'buy' or 'sell'
|
4707
|
+
:param float amount: how much of the currency you want to trade in units of the base currency
|
4708
|
+
:param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
|
4709
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
4710
|
+
:param float [params.stopLoss]: price to set a stop-loss on an open position
|
4711
|
+
:param float [params.takeProfit]: price to set a take-profit on an open position
|
4712
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
4713
|
+
"""
|
4714
|
+
if amount is None:
|
4715
|
+
raise ArgumentsRequired(self.id + ' editOrder() requires an amount argument')
|
4716
|
+
await self.load_markets()
|
4717
|
+
market = self.market(symbol)
|
4718
|
+
request = {}
|
4719
|
+
stopLoss = self.safe_number_2(params, 'stopLoss', 'triggerStopPrice')
|
4720
|
+
takeProfit = self.safe_number_2(params, 'takeProfit', 'triggerProfitPrice')
|
4721
|
+
params = self.omit(params, ['stopLoss', 'takeProfit'])
|
4722
|
+
isStopLoss = (stopLoss is not None)
|
4723
|
+
isTakeProfit = (takeProfit is not None)
|
4724
|
+
if isStopLoss or isTakeProfit:
|
4725
|
+
request['profitId'] = id
|
4726
|
+
else:
|
4727
|
+
request['orderId'] = id
|
4728
|
+
request['price'] = self.price_to_precision(symbol, price)
|
4729
|
+
response = None
|
4730
|
+
if market['swap']:
|
4731
|
+
if isStopLoss:
|
4732
|
+
request['triggerStopPrice'] = self.price_to_precision(symbol, stopLoss)
|
4733
|
+
elif takeProfit is not None:
|
4734
|
+
request['triggerProfitPrice'] = self.price_to_precision(symbol, takeProfit)
|
4735
|
+
else:
|
4736
|
+
request['origQty'] = self.amount_to_precision(symbol, amount)
|
4737
|
+
subType = None
|
4738
|
+
subType, params = self.handle_sub_type_and_params('editOrder', market, params)
|
4739
|
+
if subType == 'inverse':
|
4740
|
+
if isStopLoss or isTakeProfit:
|
4741
|
+
response = await self.privateInversePostFutureTradeV1EntrustUpdateProfitStop(self.extend(request, params))
|
4742
|
+
else:
|
4743
|
+
response = await self.privateInversePostFutureTradeV1OrderUpdate(self.extend(request, params))
|
4744
|
+
#
|
4745
|
+
# {
|
4746
|
+
# "returnCode": 0,
|
4747
|
+
# "msgInfo": "success",
|
4748
|
+
# "error": null,
|
4749
|
+
# "result": "483869474947826752"
|
4750
|
+
# }
|
4751
|
+
#
|
4752
|
+
else:
|
4753
|
+
if isStopLoss or isTakeProfit:
|
4754
|
+
response = await self.privateLinearPostFutureTradeV1EntrustUpdateProfitStop(self.extend(request, params))
|
4755
|
+
else:
|
4756
|
+
response = await self.privateLinearPostFutureTradeV1OrderUpdate(self.extend(request, params))
|
4757
|
+
#
|
4758
|
+
# {
|
4759
|
+
# "returnCode": 0,
|
4760
|
+
# "msgInfo": "success",
|
4761
|
+
# "error": null,
|
4762
|
+
# "result": "483869474947826752"
|
4763
|
+
# }
|
4764
|
+
#
|
4765
|
+
else:
|
4766
|
+
request['quantity'] = self.amount_to_precision(symbol, amount)
|
4767
|
+
response = await self.privateSpotPutOrderOrderId(self.extend(request, params))
|
4768
|
+
#
|
4769
|
+
# {
|
4770
|
+
# "rc": 0,
|
4771
|
+
# "mc": "SUCCESS",
|
4772
|
+
# "ma": [],
|
4773
|
+
# "result": {
|
4774
|
+
# "orderId": "484203027161892224",
|
4775
|
+
# "modifyId": "484203544105344000",
|
4776
|
+
# "clientModifyId": null
|
4777
|
+
# }
|
4778
|
+
# }
|
4779
|
+
#
|
4780
|
+
result = response if (market['swap']) else self.safe_dict(response, 'result', {})
|
4781
|
+
return self.parse_order(result, market)
|
4782
|
+
|
4682
4783
|
def handle_errors(self, code, reason, url, method, headers, body, response, requestHeaders, requestBody):
|
4683
4784
|
#
|
4684
4785
|
# spot: error
|
@@ -4776,6 +4877,8 @@ class xt(Exchange, ImplicitAPI):
|
|
4776
4877
|
else:
|
4777
4878
|
body['media'] = id
|
4778
4879
|
isUndefinedBody = ((method == 'GET') or (path == 'order/{orderId}') or (path == 'ws-token'))
|
4880
|
+
if (method == 'PUT') and (endpoint == 'spot'):
|
4881
|
+
isUndefinedBody = False
|
4779
4882
|
body = None if isUndefinedBody else self.json(body)
|
4780
4883
|
payloadString = None
|
4781
4884
|
if (endpoint == 'spot') or (endpoint == 'user'):
|
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.77'
|
8
8
|
|
9
9
|
# -----------------------------------------------------------------------------
|
10
10
|
|
@@ -509,7 +509,7 @@ class Exchange(object):
|
|
509
509
|
proxyUrl = self.check_proxy_url_settings(url, method, headers, body)
|
510
510
|
if proxyUrl is not None:
|
511
511
|
request_headers.update({'Origin': self.origin})
|
512
|
-
url = proxyUrl + url
|
512
|
+
url = proxyUrl + self.url_encoder_for_proxy_url(url)
|
513
513
|
# proxy agents
|
514
514
|
proxies = None # set default
|
515
515
|
httpProxy, httpsProxy, socksProxy = self.check_proxy_settings(url, method, headers, body)
|
@@ -2254,6 +2254,12 @@ class Exchange(object):
|
|
2254
2254
|
raise InvalidProxySettings(self.id + ' you have multiple conflicting proxy settings(' + joinedProxyNames + '), please use only one from : proxyUrl, proxy_url, proxyUrlCallback, proxy_url_callback')
|
2255
2255
|
return proxyUrl
|
2256
2256
|
|
2257
|
+
def url_encoder_for_proxy_url(self, targetUrl: str):
|
2258
|
+
# to be overriden
|
2259
|
+
includesQuery = targetUrl.find('?') >= 0
|
2260
|
+
finalUrl = self.encode_uri_component(targetUrl) if includesQuery else targetUrl
|
2261
|
+
return finalUrl
|
2262
|
+
|
2257
2263
|
def check_proxy_settings(self, url: Str = None, method: Str = None, headers=None, body=None):
|
2258
2264
|
usedProxies = []
|
2259
2265
|
httpProxy = None
|