ccxt 4.4.34__py2.py3-none-any.whl → 4.4.36__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 +3 -1
- ccxt/abstract/bingx.py +1 -0
- ccxt/abstract/bitopro.py +1 -0
- ccxt/abstract/bitpanda.py +0 -12
- ccxt/abstract/bitrue.py +3 -3
- ccxt/abstract/bybit.py +15 -0
- ccxt/abstract/defx.py +69 -0
- ccxt/abstract/deribit.py +1 -0
- ccxt/abstract/gate.py +14 -0
- ccxt/abstract/gateio.py +14 -0
- ccxt/abstract/okx.py +1 -0
- ccxt/abstract/onetrading.py +0 -12
- ccxt/abstract/xt.py +5 -5
- ccxt/async_support/__init__.py +3 -1
- ccxt/async_support/base/exchange.py +1 -1
- ccxt/async_support/bingx.py +324 -138
- ccxt/async_support/bitfinex2.py +18 -13
- ccxt/async_support/bitmex.py +104 -2
- ccxt/async_support/bitopro.py +21 -4
- ccxt/async_support/bitrue.py +2 -2
- ccxt/async_support/bitso.py +2 -1
- ccxt/async_support/btcmarkets.py +3 -3
- ccxt/async_support/btcturk.py +19 -19
- ccxt/async_support/bybit.py +21 -1
- ccxt/async_support/defx.py +1981 -0
- ccxt/async_support/deribit.py +27 -12
- ccxt/async_support/gate.py +156 -39
- ccxt/async_support/htx.py +11 -2
- ccxt/async_support/hyperliquid.py +68 -11
- ccxt/async_support/idex.py +3 -4
- ccxt/async_support/kraken.py +97 -90
- ccxt/async_support/kucoin.py +1 -1
- ccxt/async_support/okx.py +1 -0
- ccxt/async_support/onetrading.py +47 -369
- ccxt/async_support/xt.py +10 -10
- ccxt/base/exchange.py +2 -1
- ccxt/bingx.py +324 -138
- ccxt/bitfinex2.py +18 -13
- ccxt/bitmex.py +104 -2
- ccxt/bitopro.py +21 -4
- ccxt/bitrue.py +2 -2
- ccxt/bitso.py +2 -1
- ccxt/btcmarkets.py +3 -3
- ccxt/btcturk.py +19 -19
- ccxt/bybit.py +21 -1
- ccxt/defx.py +1980 -0
- ccxt/deribit.py +27 -12
- ccxt/gate.py +156 -39
- ccxt/htx.py +11 -2
- ccxt/hyperliquid.py +68 -11
- ccxt/idex.py +3 -4
- ccxt/kraken.py +97 -90
- ccxt/kucoin.py +1 -1
- ccxt/okx.py +1 -0
- ccxt/onetrading.py +47 -369
- ccxt/pro/__init__.py +3 -1
- ccxt/pro/bitrue.py +13 -11
- ccxt/pro/defx.py +832 -0
- ccxt/pro/probit.py +54 -66
- ccxt/test/tests_async.py +44 -3
- ccxt/test/tests_sync.py +44 -3
- ccxt/xt.py +10 -10
- {ccxt-4.4.34.dist-info → ccxt-4.4.36.dist-info}/METADATA +7 -6
- {ccxt-4.4.34.dist-info → ccxt-4.4.36.dist-info}/RECORD +67 -63
- {ccxt-4.4.34.dist-info → ccxt-4.4.36.dist-info}/LICENSE.txt +0 -0
- {ccxt-4.4.34.dist-info → ccxt-4.4.36.dist-info}/WHEEL +0 -0
- {ccxt-4.4.34.dist-info → ccxt-4.4.36.dist-info}/top_level.txt +0 -0
@@ -12,12 +12,14 @@ from typing import List
|
|
12
12
|
from ccxt.base.errors import ExchangeError
|
13
13
|
from ccxt.base.errors import ArgumentsRequired
|
14
14
|
from ccxt.base.errors import BadRequest
|
15
|
+
from ccxt.base.errors import InsufficientFunds
|
15
16
|
from ccxt.base.errors import InvalidOrder
|
16
17
|
from ccxt.base.errors import OrderNotFound
|
17
18
|
from ccxt.base.errors import NotSupported
|
18
19
|
from ccxt.base.decimal_to_precision import ROUND
|
19
20
|
from ccxt.base.decimal_to_precision import DECIMAL_PLACES
|
20
21
|
from ccxt.base.decimal_to_precision import SIGNIFICANT_DIGITS
|
22
|
+
from ccxt.base.decimal_to_precision import TICK_SIZE
|
21
23
|
from ccxt.base.precise import Precise
|
22
24
|
|
23
25
|
|
@@ -211,9 +213,11 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
211
213
|
'User or API Wallet ': InvalidOrder,
|
212
214
|
'Order has invalid size': InvalidOrder,
|
213
215
|
'Order price cannot be more than 80% away from the reference price': InvalidOrder,
|
216
|
+
'Order has zero size.': InvalidOrder,
|
217
|
+
'Insufficient spot balance asset': InsufficientFunds,
|
214
218
|
},
|
215
219
|
},
|
216
|
-
'precisionMode':
|
220
|
+
'precisionMode': TICK_SIZE,
|
217
221
|
'commonCurrencies': {
|
218
222
|
},
|
219
223
|
'options': {
|
@@ -362,6 +366,48 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
362
366
|
result.append(data)
|
363
367
|
return self.parse_markets(result)
|
364
368
|
|
369
|
+
def calculate_price_precision(self, price: float, amountPrecision: float, maxDecimals: float):
|
370
|
+
"""
|
371
|
+
Helper function to calculate the Hyperliquid DECIMAL_PLACES price precision
|
372
|
+
:param float price: the price to use in the calculation
|
373
|
+
:param int amountPrecision: the amountPrecision to use in the calculation
|
374
|
+
:param int maxDecimals: the maxDecimals to use in the calculation
|
375
|
+
:returns int: The calculated price precision
|
376
|
+
"""
|
377
|
+
pricePrecision = 0
|
378
|
+
priceStr = self.number_to_string(price)
|
379
|
+
if priceStr is None:
|
380
|
+
return 0
|
381
|
+
priceSplitted = priceStr.split('.')
|
382
|
+
if Precise.string_eq(priceStr, '0'):
|
383
|
+
# Significant digits is always hasattr(self, 5) case
|
384
|
+
significantDigits = 5
|
385
|
+
# Integer digits is always hasattr(self, 0) case(0 doesn't count)
|
386
|
+
integerDigits = 0
|
387
|
+
# Calculate the price precision
|
388
|
+
pricePrecision = min(maxDecimals - amountPrecision, significantDigits - integerDigits)
|
389
|
+
elif Precise.string_gt(priceStr, '0') and Precise.string_lt(priceStr, '1'):
|
390
|
+
# Significant digits, always hasattr(self, 5) case
|
391
|
+
significantDigits = 5
|
392
|
+
# Get the part after the decimal separator
|
393
|
+
decimalPart = self.safe_string(priceSplitted, 1, '')
|
394
|
+
# Count the number of leading zeros in the decimal part
|
395
|
+
leadingZeros = 0
|
396
|
+
while((leadingZeros <= len(decimalPart)) and (decimalPart[leadingZeros] == '0')):
|
397
|
+
leadingZeros = leadingZeros + 1
|
398
|
+
# Calculate price precision based on leading zeros and significant digits
|
399
|
+
pricePrecision = leadingZeros + significantDigits
|
400
|
+
# Calculate the price precision based on maxDecimals - szDecimals and the calculated price precision from the previous step
|
401
|
+
pricePrecision = min(maxDecimals - amountPrecision, pricePrecision)
|
402
|
+
else:
|
403
|
+
# Count the numbers before the decimal separator
|
404
|
+
integerPart = self.safe_string(priceSplitted, 0, '')
|
405
|
+
# Get significant digits, take the max() of 5 and the integer digits count
|
406
|
+
significantDigits = max(5, len(integerPart))
|
407
|
+
# Calculate price precision based on maxDecimals - szDecimals and significantDigits - len(integerPart)
|
408
|
+
pricePrecision = min(maxDecimals - amountPrecision, significantDigits - len(integerPart))
|
409
|
+
return self.parse_to_int(pricePrecision)
|
410
|
+
|
365
411
|
async def fetch_spot_markets(self, params={}) -> List[Market]:
|
366
412
|
"""
|
367
413
|
retrieves data on all spot markets for hyperliquid
|
@@ -451,7 +497,11 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
451
497
|
symbol = base + '/' + quote
|
452
498
|
innerBaseTokenInfo = self.safe_dict(baseTokenInfo, 'spec', baseTokenInfo)
|
453
499
|
# innerQuoteTokenInfo = self.safe_dict(quoteTokenInfo, 'spec', quoteTokenInfo)
|
454
|
-
|
500
|
+
amountPrecisionStr = self.safe_string(innerBaseTokenInfo, 'szDecimals')
|
501
|
+
amountPrecision = int(amountPrecisionStr)
|
502
|
+
price = self.safe_number(extraData, 'midPx')
|
503
|
+
pricePrecision = self.calculate_price_precision(price, amountPrecision, 8)
|
504
|
+
pricePrecisionStr = self.number_to_string(pricePrecision)
|
455
505
|
# quotePrecision = self.parse_number(self.parse_precision(self.safe_string(innerQuoteTokenInfo, 'szDecimals')))
|
456
506
|
baseId = self.number_to_string(i + 10000)
|
457
507
|
markets.append(self.safe_market_structure({
|
@@ -482,8 +532,8 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
482
532
|
'strike': None,
|
483
533
|
'optionType': None,
|
484
534
|
'precision': {
|
485
|
-
'amount':
|
486
|
-
'price':
|
535
|
+
'amount': self.parse_number(self.parse_precision(amountPrecisionStr)),
|
536
|
+
'price': self.parse_number(self.parse_precision(pricePrecisionStr)),
|
487
537
|
},
|
488
538
|
'limits': {
|
489
539
|
'leverage': {
|
@@ -544,7 +594,11 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
544
594
|
fees = self.safe_dict(self.fees, 'swap', {})
|
545
595
|
taker = self.safe_number(fees, 'taker')
|
546
596
|
maker = self.safe_number(fees, 'maker')
|
547
|
-
|
597
|
+
amountPrecisionStr = self.safe_string(market, 'szDecimals')
|
598
|
+
amountPrecision = int(amountPrecisionStr)
|
599
|
+
price = self.safe_number(market, 'markPx', 0)
|
600
|
+
pricePrecision = self.calculate_price_precision(price, amountPrecision, 6)
|
601
|
+
pricePrecisionStr = self.number_to_string(pricePrecision)
|
548
602
|
return self.safe_market_structure({
|
549
603
|
'id': baseId,
|
550
604
|
'symbol': symbol,
|
@@ -572,8 +626,8 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
572
626
|
'strike': None,
|
573
627
|
'optionType': None,
|
574
628
|
'precision': {
|
575
|
-
'amount':
|
576
|
-
'price':
|
629
|
+
'amount': self.parse_number(self.parse_precision(amountPrecisionStr)),
|
630
|
+
'price': self.parse_number(self.parse_precision(pricePrecisionStr)),
|
577
631
|
},
|
578
632
|
'limits': {
|
579
633
|
'leverage': {
|
@@ -1040,10 +1094,13 @@ class hyperliquid(Exchange, ImplicitAPI):
|
|
1040
1094
|
|
1041
1095
|
def price_to_precision(self, symbol: str, price) -> str:
|
1042
1096
|
market = self.market(symbol)
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1097
|
+
priceStr = self.number_to_string(price)
|
1098
|
+
integerPart = priceStr.split('.')[0]
|
1099
|
+
significantDigits = max(5, len(integerPart))
|
1100
|
+
result = self.decimal_to_precision(price, ROUND, significantDigits, SIGNIFICANT_DIGITS, self.paddingMode)
|
1101
|
+
maxDecimals = 8 if market['spot'] else 6
|
1102
|
+
subtractedValue = maxDecimals - self.precision_from_string(self.safe_string(market['precision'], 'amount'))
|
1103
|
+
return self.decimal_to_precision(result, ROUND, subtractedValue, DECIMAL_PLACES, self.paddingMode)
|
1047
1104
|
|
1048
1105
|
def hash_message(self, message):
|
1049
1106
|
return '0x' + self.hash(message, 'keccak', 'hex')
|
ccxt/async_support/idex.py
CHANGED
@@ -19,7 +19,6 @@ from ccxt.base.errors import DDoSProtection
|
|
19
19
|
from ccxt.base.errors import ExchangeNotAvailable
|
20
20
|
from ccxt.base.decimal_to_precision import ROUND
|
21
21
|
from ccxt.base.decimal_to_precision import TRUNCATE
|
22
|
-
from ccxt.base.decimal_to_precision import DECIMAL_PLACES
|
23
22
|
from ccxt.base.decimal_to_precision import TICK_SIZE
|
24
23
|
from ccxt.base.decimal_to_precision import PAD_WITH_ZERO
|
25
24
|
from ccxt.base.precise import Precise
|
@@ -206,10 +205,8 @@ class idex(Exchange, ImplicitAPI):
|
|
206
205
|
# {"code":"INVALID_PARAMETER","message":"invalid value provided for request parameter \"price\": all quantities and prices must be below 100 billion, above 0, need to be provided, and always require 4 decimals ending with 4 zeroes"}
|
207
206
|
#
|
208
207
|
market = self.market(symbol)
|
209
|
-
info = self.safe_value(market, 'info', {})
|
210
|
-
quoteAssetPrecision = self.safe_integer(info, 'quoteAssetPrecision')
|
211
208
|
price = self.decimal_to_precision(price, ROUND, market['precision']['price'], self.precisionMode)
|
212
|
-
return self.decimal_to_precision(price, TRUNCATE,
|
209
|
+
return self.decimal_to_precision(price, TRUNCATE, market['precision']['quote'], TICK_SIZE, PAD_WITH_ZERO)
|
213
210
|
|
214
211
|
async def fetch_markets(self, params={}) -> List[Market]:
|
215
212
|
"""
|
@@ -316,6 +313,8 @@ class idex(Exchange, ImplicitAPI):
|
|
316
313
|
'precision': {
|
317
314
|
'amount': basePrecision,
|
318
315
|
'price': self.safe_number(entry, 'tickSize'),
|
316
|
+
'base': basePrecision,
|
317
|
+
'quote': quotePrecision,
|
319
318
|
},
|
320
319
|
'limits': {
|
321
320
|
'leverage': {
|
ccxt/async_support/kraken.py
CHANGED
@@ -447,31 +447,43 @@ class kraken(Exchange, ImplicitAPI):
|
|
447
447
|
},
|
448
448
|
'precisionMode': TICK_SIZE,
|
449
449
|
'exceptions': {
|
450
|
-
'
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
450
|
+
'exact': {
|
451
|
+
'EQuery:Invalid asset pair': BadSymbol, # {"error":["EQuery:Invalid asset pair"]}
|
452
|
+
'EAPI:Invalid key': AuthenticationError,
|
453
|
+
'EFunding:Unknown withdraw key': InvalidAddress, # {"error":["EFunding:Unknown withdraw key"]}
|
454
|
+
'EFunding:Invalid amount': InsufficientFunds,
|
455
|
+
'EService:Unavailable': ExchangeNotAvailable,
|
456
|
+
'EDatabase:Internal error': ExchangeNotAvailable,
|
457
|
+
'EService:Busy': ExchangeNotAvailable,
|
458
|
+
'EQuery:Unknown asset': BadSymbol, # {"error":["EQuery:Unknown asset"]}
|
459
|
+
'EAPI:Rate limit exceeded': DDoSProtection,
|
460
|
+
'EOrder:Rate limit exceeded': DDoSProtection,
|
461
|
+
'EGeneral:Internal error': ExchangeNotAvailable,
|
462
|
+
'EGeneral:Temporary lockout': DDoSProtection,
|
463
|
+
'EGeneral:Permission denied': PermissionDenied,
|
464
|
+
'EGeneral:Invalid arguments:price': InvalidOrder,
|
465
|
+
'EOrder:Unknown order': InvalidOrder,
|
466
|
+
'EOrder:Invalid price:Invalid price argument': InvalidOrder,
|
467
|
+
'EOrder:Order minimum not met': InvalidOrder,
|
468
|
+
'EOrder:Insufficient funds': InsufficientFunds,
|
469
|
+
'EGeneral:Invalid arguments': BadRequest,
|
470
|
+
'ESession:Invalid session': AuthenticationError,
|
471
|
+
'EAPI:Invalid nonce': InvalidNonce,
|
472
|
+
'EFunding:No funding method': BadRequest, # {"error":"EFunding:No funding method"}
|
473
|
+
'EFunding:Unknown asset': BadSymbol, # {"error":["EFunding:Unknown asset"]}
|
474
|
+
'EService:Market in post_only mode': OnMaintenance, # {"error":["EService:Market in post_only mode"]}
|
475
|
+
'EGeneral:Too many requests': DDoSProtection, # {"error":["EGeneral:Too many requests"]}
|
476
|
+
'ETrade:User Locked': AccountSuspended, # {"error":["ETrade:User Locked"]}
|
477
|
+
},
|
478
|
+
'broad': {
|
479
|
+
':Invalid order': InvalidOrder,
|
480
|
+
':Invalid arguments:volume': InvalidOrder,
|
481
|
+
':Invalid arguments:viqc': InvalidOrder,
|
482
|
+
':Invalid nonce': InvalidNonce,
|
483
|
+
':IInsufficient funds': InsufficientFunds,
|
484
|
+
':Cancel pending': CancelPending,
|
485
|
+
':Rate limit exceeded': RateLimitExceeded,
|
486
|
+
},
|
475
487
|
},
|
476
488
|
})
|
477
489
|
|
@@ -1553,18 +1565,9 @@ class kraken(Exchange, ImplicitAPI):
|
|
1553
1565
|
# editOrder
|
1554
1566
|
#
|
1555
1567
|
# {
|
1556
|
-
# "
|
1557
|
-
# "txid": "OAW2BO-7RWEK-PZY5UO",
|
1558
|
-
# "originaltxid": "OXL6SS-UPNMC-26WBE7",
|
1559
|
-
# "newuserref": 1234,
|
1560
|
-
# "olduserref": 123,
|
1561
|
-
# "volume": "0.00075000",
|
1562
|
-
# "price": "13500.0",
|
1563
|
-
# "orders_cancelled": 1,
|
1564
|
-
# "descr": {
|
1565
|
-
# "order": "buy 0.00075000 XBTUSDT @ limit 13500.0"
|
1566
|
-
# }
|
1568
|
+
# "amend_id": "TJSMEH-AA67V-YUSQ6O"
|
1567
1569
|
# }
|
1570
|
+
#
|
1568
1571
|
# ws - createOrder
|
1569
1572
|
# {
|
1570
1573
|
# "descr": 'sell 0.00010000 XBTUSDT @ market',
|
@@ -1687,11 +1690,11 @@ class kraken(Exchange, ImplicitAPI):
|
|
1687
1690
|
elif flags.find('fcib') >= 0:
|
1688
1691
|
fee['currency'] = market['base']
|
1689
1692
|
status = self.parse_order_status(self.safe_string(order, 'status'))
|
1690
|
-
id = self.
|
1693
|
+
id = self.safe_string_n(order, ['id', 'txid', 'amend_id'])
|
1691
1694
|
if (id is None) or (id.startswith('[')):
|
1692
1695
|
txid = self.safe_list(order, 'txid')
|
1693
1696
|
id = self.safe_string(txid, 0)
|
1694
|
-
clientOrderId = self.
|
1697
|
+
clientOrderId = self.safe_string(order, 'userref')
|
1695
1698
|
rawTrades = self.safe_value(order, 'trades', [])
|
1696
1699
|
trades = []
|
1697
1700
|
for i in range(0, len(rawTrades)):
|
@@ -1706,22 +1709,26 @@ class kraken(Exchange, ImplicitAPI):
|
|
1706
1709
|
takeProfitPrice = None
|
1707
1710
|
# the dashed strings are not provided from fields(eg. fetch order)
|
1708
1711
|
# while spaced strings from "order" sentence(when other fields not available)
|
1709
|
-
if rawType
|
1710
|
-
|
1711
|
-
|
1712
|
-
|
1713
|
-
|
1714
|
-
|
1715
|
-
|
1716
|
-
|
1717
|
-
|
1718
|
-
|
1712
|
+
if rawType is not None:
|
1713
|
+
if rawType.startswith('take-profit'):
|
1714
|
+
takeProfitPrice = self.safe_string(description, 'price')
|
1715
|
+
price = self.omit_zero(self.safe_string(description, 'price2'))
|
1716
|
+
elif rawType.startswith('stop-loss'):
|
1717
|
+
stopLossPrice = self.safe_string(description, 'price')
|
1718
|
+
price = self.omit_zero(self.safe_string(description, 'price2'))
|
1719
|
+
elif rawType == 'take profit':
|
1720
|
+
takeProfitPrice = triggerPrice
|
1721
|
+
elif rawType == 'stop loss':
|
1722
|
+
stopLossPrice = triggerPrice
|
1719
1723
|
finalType = self.parse_order_type(rawType)
|
1720
1724
|
# unlike from endpoints which provide eg: "take-profit-limit"
|
1721
1725
|
# for "space-delimited" orders we dont have market/limit suffixes, their format is
|
1722
1726
|
# eg: `stop loss > limit 123`, so we need to parse them manually
|
1723
1727
|
if self.in_array(finalType, ['stop loss', 'take profit']):
|
1724
1728
|
finalType = 'market' if (price is None) else 'limit'
|
1729
|
+
amendId = self.safe_string(order, 'amend_id')
|
1730
|
+
if amendId is not None:
|
1731
|
+
isPostOnly = None
|
1725
1732
|
return self.safe_order({
|
1726
1733
|
'id': id,
|
1727
1734
|
'clientOrderId': clientOrderId,
|
@@ -1751,10 +1758,10 @@ class kraken(Exchange, ImplicitAPI):
|
|
1751
1758
|
}, market)
|
1752
1759
|
|
1753
1760
|
def order_request(self, method: str, symbol: str, type: str, request: dict, amount: Num, price: Num = None, params={}):
|
1754
|
-
clientOrderId = self.
|
1755
|
-
params = self.omit(params, ['
|
1761
|
+
clientOrderId = self.safe_string(params, 'clientOrderId')
|
1762
|
+
params = self.omit(params, ['clientOrderId'])
|
1756
1763
|
if clientOrderId is not None:
|
1757
|
-
request['
|
1764
|
+
request['cl_ord_id'] = clientOrderId
|
1758
1765
|
stopLossTriggerPrice = self.safe_string(params, 'stopLossPrice')
|
1759
1766
|
takeProfitTriggerPrice = self.safe_string(params, 'takeProfitPrice')
|
1760
1767
|
isStopLossTriggerOrder = stopLossTriggerPrice is not None
|
@@ -1854,21 +1861,24 @@ class kraken(Exchange, ImplicitAPI):
|
|
1854
1861
|
"""
|
1855
1862
|
edit a trade order
|
1856
1863
|
|
1857
|
-
https://docs.kraken.com/rest
|
1864
|
+
https://docs.kraken.com/api/docs/rest-api/amend-order
|
1858
1865
|
|
1859
1866
|
:param str id: order id
|
1860
1867
|
:param str symbol: unified symbol of the market to create an order in
|
1861
1868
|
:param str type: 'market' or 'limit'
|
1862
1869
|
:param str side: 'buy' or 'sell'
|
1863
|
-
:param float amount: how much of the currency you want to trade in units of the base currency
|
1870
|
+
:param float [amount]: how much of the currency you want to trade in units of the base currency
|
1864
1871
|
:param float [price]: the price at which the order is to be fulfilled, in units of the quote currency, ignored in market orders
|
1865
1872
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
1866
|
-
:param float [params.stopLossPrice]:
|
1867
|
-
:param float [params.takeProfitPrice]:
|
1868
|
-
:param str [params.trailingAmount]:
|
1869
|
-
:param str [params.
|
1870
|
-
:param str [params.
|
1871
|
-
:param str [params.
|
1873
|
+
:param float [params.stopLossPrice]: the price that a stop loss order is triggered at
|
1874
|
+
:param float [params.takeProfitPrice]: the price that a take profit order is triggered at
|
1875
|
+
:param str [params.trailingAmount]: the quote amount to trail away from the current market price
|
1876
|
+
:param str [params.trailingPercent]: the percent to trail away from the current market price
|
1877
|
+
:param str [params.trailingLimitAmount]: the quote amount away from the trailingAmount
|
1878
|
+
:param str [params.trailingLimitPercent]: the percent away from the trailingAmount
|
1879
|
+
:param str [params.offset]: '+' or '-' whether you want the trailingLimitAmount value to be positive or negative
|
1880
|
+
:param boolean [params.postOnly]: if True, the order will only be posted to the order book and not executed immediately
|
1881
|
+
:param str [params.clientOrderId]: the orders client order id
|
1872
1882
|
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
1873
1883
|
"""
|
1874
1884
|
await self.load_markets()
|
@@ -1877,30 +1887,41 @@ class kraken(Exchange, ImplicitAPI):
|
|
1877
1887
|
raise NotSupported(self.id + ' editOrder() does not support ' + market['type'] + ' orders, only spot orders are accepted')
|
1878
1888
|
request: dict = {
|
1879
1889
|
'txid': id,
|
1880
|
-
'pair': market['id'],
|
1881
1890
|
}
|
1891
|
+
clientOrderId = self.safe_string(params, 'clientOrderId')
|
1892
|
+
if clientOrderId is not None:
|
1893
|
+
request['cl_ord_id'] = clientOrderId
|
1894
|
+
params = self.omit(params, 'clientOrderId')
|
1895
|
+
request = self.omit(request, 'txid')
|
1896
|
+
isMarket = (type == 'market')
|
1897
|
+
postOnly = None
|
1898
|
+
postOnly, params = self.handle_post_only(isMarket, False, params)
|
1899
|
+
if postOnly:
|
1900
|
+
request['post_only'] = 'true' # not using hasattr(self, boolean) case, because the urlencodedNested transforms it into 'True' string
|
1882
1901
|
if amount is not None:
|
1883
|
-
request['
|
1884
|
-
|
1885
|
-
|
1902
|
+
request['order_qty'] = self.amount_to_precision(symbol, amount)
|
1903
|
+
if price is not None:
|
1904
|
+
request['limit_price'] = self.price_to_precision(symbol, price)
|
1905
|
+
allTriggerPrices = self.safe_string_n(params, ['stopLossPrice', 'takeProfitPrice', 'trailingAmount', 'trailingPercent', 'trailingLimitAmount', 'trailingLimitPercent'])
|
1906
|
+
if allTriggerPrices is not None:
|
1907
|
+
offset = self.safe_string(params, 'offset')
|
1908
|
+
params = self.omit(params, ['stopLossPrice', 'takeProfitPrice', 'trailingAmount', 'trailingPercent', 'trailingLimitAmount', 'trailingLimitPercent', 'offset'])
|
1909
|
+
if offset is not None:
|
1910
|
+
allTriggerPrices = offset + allTriggerPrices
|
1911
|
+
request['trigger_price'] = allTriggerPrices
|
1912
|
+
else:
|
1913
|
+
request['trigger_price'] = self.price_to_precision(symbol, allTriggerPrices)
|
1914
|
+
response = await self.privatePostAmendOrder(self.extend(request, params))
|
1886
1915
|
#
|
1887
1916
|
# {
|
1888
1917
|
# "error": [],
|
1889
1918
|
# "result": {
|
1890
|
-
# "
|
1891
|
-
# "txid": "OAW2BO-7RWEK-PZY5UO",
|
1892
|
-
# "originaltxid": "OXL6SS-UPNMC-26WBE7",
|
1893
|
-
# "volume": "0.00075000",
|
1894
|
-
# "price": "13500.0",
|
1895
|
-
# "orders_cancelled": 1,
|
1896
|
-
# "descr": {
|
1897
|
-
# "order": "buy 0.00075000 XBTUSDT @ limit 13500.0"
|
1898
|
-
# }
|
1919
|
+
# "amend_id": "TJSMEH-AA67V-YUSQ6O"
|
1899
1920
|
# }
|
1900
1921
|
# }
|
1901
1922
|
#
|
1902
|
-
|
1903
|
-
return self.parse_order(
|
1923
|
+
result = self.safe_dict(response, 'result', {})
|
1924
|
+
return self.parse_order(result, market)
|
1904
1925
|
|
1905
1926
|
async def fetch_order(self, id: str, symbol: Str = None, params={}):
|
1906
1927
|
"""
|
@@ -3055,21 +3076,6 @@ class kraken(Exchange, ImplicitAPI):
|
|
3055
3076
|
def handle_errors(self, code: int, reason: str, url: str, method: str, headers: dict, body: str, response, requestHeaders, requestBody):
|
3056
3077
|
if code == 520:
|
3057
3078
|
raise ExchangeNotAvailable(self.id + ' ' + str(code) + ' ' + reason)
|
3058
|
-
# todo: rewrite self for "broad" exceptions matching
|
3059
|
-
if body.find('Invalid order') >= 0:
|
3060
|
-
raise InvalidOrder(self.id + ' ' + body)
|
3061
|
-
if body.find('Invalid nonce') >= 0:
|
3062
|
-
raise InvalidNonce(self.id + ' ' + body)
|
3063
|
-
if body.find('Insufficient funds') >= 0:
|
3064
|
-
raise InsufficientFunds(self.id + ' ' + body)
|
3065
|
-
if body.find('Cancel pending') >= 0:
|
3066
|
-
raise CancelPending(self.id + ' ' + body)
|
3067
|
-
if body.find('Invalid arguments:volume') >= 0:
|
3068
|
-
raise InvalidOrder(self.id + ' ' + body)
|
3069
|
-
if body.find('Invalid arguments:viqc') >= 0:
|
3070
|
-
raise InvalidOrder(self.id + ' ' + body)
|
3071
|
-
if body.find('Rate limit exceeded') >= 0:
|
3072
|
-
raise RateLimitExceeded(self.id + ' ' + body)
|
3073
3079
|
if response is None:
|
3074
3080
|
return None
|
3075
3081
|
if body[0] == '{':
|
@@ -3080,6 +3086,7 @@ class kraken(Exchange, ImplicitAPI):
|
|
3080
3086
|
message = self.id + ' ' + body
|
3081
3087
|
for i in range(0, len(response['error'])):
|
3082
3088
|
error = response['error'][i]
|
3083
|
-
self.throw_exactly_matched_exception(self.exceptions, error, message)
|
3089
|
+
self.throw_exactly_matched_exception(self.exceptions['exact'], error, message)
|
3090
|
+
self.throw_exactly_matched_exception(self.exceptions['broad'], error, message)
|
3084
3091
|
raise ExchangeError(message)
|
3085
3092
|
return None
|
ccxt/async_support/kucoin.py
CHANGED
ccxt/async_support/okx.py
CHANGED