gate-io-api 0.0.74__py3-none-any.whl → 0.0.100__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.
Potentially problematic release.
This version of gate-io-api might be problematic. Click here for more details.
- gate/ccxt/__init__.py +2 -1
- gate/ccxt/abstract/gate.py +62 -18
- gate/ccxt/async_support/__init__.py +2 -1
- gate/ccxt/async_support/base/exchange.py +150 -21
- gate/ccxt/async_support/base/throttler.py +1 -1
- gate/ccxt/async_support/base/ws/client.py +20 -2
- gate/ccxt/async_support/base/ws/future.py +5 -3
- gate/ccxt/async_support/gate.py +339 -241
- gate/ccxt/base/decimal_to_precision.py +14 -10
- gate/ccxt/base/errors.py +12 -0
- gate/ccxt/base/exchange.py +466 -56
- gate/ccxt/base/types.py +3 -0
- gate/ccxt/gate.py +339 -241
- gate/ccxt/pro/__init__.py +2 -1
- gate/ccxt/pro/gate.py +14 -7
- {gate_io_api-0.0.74.dist-info → gate_io_api-0.0.100.dist-info}/METADATA +70 -25
- {gate_io_api-0.0.74.dist-info → gate_io_api-0.0.100.dist-info}/RECORD +18 -18
- {gate_io_api-0.0.74.dist-info → gate_io_api-0.0.100.dist-info}/WHEEL +0 -0
gate/ccxt/base/exchange.py
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
# -----------------------------------------------------------------------------
|
|
6
6
|
|
|
7
|
-
__version__ = '4.
|
|
7
|
+
__version__ = '4.5.15'
|
|
8
8
|
|
|
9
9
|
# -----------------------------------------------------------------------------
|
|
10
10
|
|
|
@@ -33,7 +33,7 @@ from ccxt.base.decimal_to_precision import decimal_to_precision
|
|
|
33
33
|
from ccxt.base.decimal_to_precision import DECIMAL_PLACES, TICK_SIZE, NO_PADDING, TRUNCATE, ROUND, ROUND_UP, ROUND_DOWN, SIGNIFICANT_DIGITS
|
|
34
34
|
from ccxt.base.decimal_to_precision import number_to_string
|
|
35
35
|
from ccxt.base.precise import Precise
|
|
36
|
-
from ccxt.base.types import ConstructorArgs, BalanceAccount, Currency, IndexType, OrderSide, OrderType, Trade, OrderRequest, Market, MarketType, Str, Num, Strings, CancellationRequest, Bool
|
|
36
|
+
from ccxt.base.types import ConstructorArgs, BalanceAccount, Currency, IndexType, OrderSide, OrderType, Trade, OrderRequest, Market, MarketType, Str, Num, Strings, CancellationRequest, Bool, Order
|
|
37
37
|
|
|
38
38
|
# -----------------------------------------------------------------------------
|
|
39
39
|
|
|
@@ -50,6 +50,11 @@ from cryptography.hazmat.primitives.serialization import load_pem_private_key
|
|
|
50
50
|
from ccxt.static_dependencies import ecdsa
|
|
51
51
|
from ccxt.static_dependencies import keccak
|
|
52
52
|
|
|
53
|
+
try:
|
|
54
|
+
import coincurve
|
|
55
|
+
except ImportError:
|
|
56
|
+
coincurve = None
|
|
57
|
+
|
|
53
58
|
# eddsa signing
|
|
54
59
|
try:
|
|
55
60
|
import axolotl_curve25519 as eddsa
|
|
@@ -229,6 +234,7 @@ class Exchange(object):
|
|
|
229
234
|
'chrome100': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/100.0.4896.75 Safari/537.36',
|
|
230
235
|
}
|
|
231
236
|
headers = None
|
|
237
|
+
returnResponseHeaders = False
|
|
232
238
|
origin = '*' # CORS origin
|
|
233
239
|
MAX_VALUE = float('inf')
|
|
234
240
|
#
|
|
@@ -310,8 +316,7 @@ class Exchange(object):
|
|
|
310
316
|
bidsasks = None
|
|
311
317
|
base_currencies = None
|
|
312
318
|
quote_currencies = None
|
|
313
|
-
currencies =
|
|
314
|
-
|
|
319
|
+
currencies = {}
|
|
315
320
|
options = None # Python does not allow to define properties in run-time with setattr
|
|
316
321
|
isSandboxModeEnabled = False
|
|
317
322
|
accounts = None
|
|
@@ -579,6 +584,8 @@ class Exchange(object):
|
|
|
579
584
|
if self.verbose:
|
|
580
585
|
self.log("\nfetch Response:", self.id, method, url, http_status_code, "ResponseHeaders:", headers, "ResponseBody:", http_response)
|
|
581
586
|
self.logger.debug("%s %s, Response: %s %s %s", method, url, http_status_code, headers, http_response)
|
|
587
|
+
if json_response and not isinstance(json_response, list) and self.returnResponseHeaders:
|
|
588
|
+
json_response['responseHeaders'] = headers
|
|
582
589
|
response.raise_for_status()
|
|
583
590
|
|
|
584
591
|
except Timeout as e:
|
|
@@ -1306,6 +1313,10 @@ class Exchange(object):
|
|
|
1306
1313
|
elif algoType == 'ES':
|
|
1307
1314
|
rawSignature = Exchange.ecdsa(token, secret, 'p256', algorithm)
|
|
1308
1315
|
signature = Exchange.base16_to_binary(rawSignature['r'].rjust(64, "0") + rawSignature['s'].rjust(64, "0"))
|
|
1316
|
+
elif algoType == 'Ed':
|
|
1317
|
+
signature = Exchange.eddsa(token.encode('utf-8'), secret, 'ed25519', True)
|
|
1318
|
+
# here the signature is already a urlencoded base64-encoded string
|
|
1319
|
+
return token + '.' + signature
|
|
1309
1320
|
else:
|
|
1310
1321
|
signature = Exchange.hmac(Exchange.encode(token), secret, algos[algorithm], 'binary')
|
|
1311
1322
|
return token + '.' + Exchange.urlencode_base64(signature)
|
|
@@ -1376,9 +1387,9 @@ class Exchange(object):
|
|
|
1376
1387
|
return msgHash
|
|
1377
1388
|
|
|
1378
1389
|
@staticmethod
|
|
1379
|
-
def starknet_sign (
|
|
1390
|
+
def starknet_sign (msg_hash, pri):
|
|
1380
1391
|
# // TODO: unify to ecdsa
|
|
1381
|
-
r, s = message_signature(
|
|
1392
|
+
r, s = message_signature(msg_hash, pri)
|
|
1382
1393
|
return Exchange.json([hex(r), hex(s)])
|
|
1383
1394
|
|
|
1384
1395
|
@staticmethod
|
|
@@ -1395,6 +1406,21 @@ class Exchange(object):
|
|
|
1395
1406
|
|
|
1396
1407
|
@staticmethod
|
|
1397
1408
|
def ecdsa(request, secret, algorithm='p256', hash=None, fixed_length=False):
|
|
1409
|
+
"""
|
|
1410
|
+
ECDSA signing with support for multiple algorithms and coincurve for SECP256K1.
|
|
1411
|
+
Args:
|
|
1412
|
+
request: The message to sign
|
|
1413
|
+
secret: The private key (hex string or PEM format)
|
|
1414
|
+
algorithm: The elliptic curve algorithm ('p192', 'p224', 'p256', 'p384', 'p521', 'secp256k1')
|
|
1415
|
+
hash: The hash function to use (defaults to algorithm-specific hash)
|
|
1416
|
+
fixed_length: Whether to ensure fixed-length signatures (for deterministic signing)
|
|
1417
|
+
Note: coincurve produces non-deterministic signatures
|
|
1418
|
+
Returns:
|
|
1419
|
+
dict: {'r': r_value, 's': s_value, 'v': v_value}
|
|
1420
|
+
Note:
|
|
1421
|
+
If coincurve is not available or fails for SECP256K1, the method automatically
|
|
1422
|
+
falls back to the standard ecdsa implementation.
|
|
1423
|
+
"""
|
|
1398
1424
|
# your welcome - frosty00
|
|
1399
1425
|
algorithms = {
|
|
1400
1426
|
'p192': [ecdsa.NIST192p, 'sha256'],
|
|
@@ -1406,6 +1432,14 @@ class Exchange(object):
|
|
|
1406
1432
|
}
|
|
1407
1433
|
if algorithm not in algorithms:
|
|
1408
1434
|
raise ArgumentsRequired(algorithm + ' is not a supported algorithm')
|
|
1435
|
+
# Use coincurve for SECP256K1 if available
|
|
1436
|
+
if algorithm == 'secp256k1' and coincurve is not None:
|
|
1437
|
+
try:
|
|
1438
|
+
return Exchange._ecdsa_secp256k1_coincurve(request, secret, hash, fixed_length)
|
|
1439
|
+
except Exception:
|
|
1440
|
+
# If coincurve fails, fall back to ecdsa implementation
|
|
1441
|
+
pass
|
|
1442
|
+
# Fall back to original ecdsa implementation for other algorithms or when deterministic signing is needed
|
|
1409
1443
|
curve_info = algorithms[algorithm]
|
|
1410
1444
|
hash_function = getattr(hashlib, curve_info[1])
|
|
1411
1445
|
encoded_request = Exchange.encode(request)
|
|
@@ -1439,12 +1473,69 @@ class Exchange(object):
|
|
|
1439
1473
|
'v': v,
|
|
1440
1474
|
}
|
|
1441
1475
|
|
|
1476
|
+
|
|
1442
1477
|
@staticmethod
|
|
1443
|
-
def
|
|
1478
|
+
def _ecdsa_secp256k1_coincurve(request, secret, hash=None, fixed_length=False):
|
|
1479
|
+
"""
|
|
1480
|
+
Use coincurve library for SECP256K1 ECDSA signing.
|
|
1481
|
+
This method provides faster SECP256K1 signing using the coincurve library,
|
|
1482
|
+
which is a Python binding to libsecp256k1. This implementation produces
|
|
1483
|
+
deterministic signatures (RFC 6979) using coincurve's sign_recoverable method.
|
|
1484
|
+
Args:
|
|
1485
|
+
request: The message to sign
|
|
1486
|
+
secret: The private key (hex string or PEM format)
|
|
1487
|
+
hash: The hash function to use
|
|
1488
|
+
fixed_length: Not used in coincurve implementation (signatures are always fixed length)
|
|
1489
|
+
Returns:
|
|
1490
|
+
dict: {'r': r_value, 's': s_value, 'v': v_value}
|
|
1491
|
+
Raises:
|
|
1492
|
+
ArgumentsRequired: If coincurve library is not available
|
|
1493
|
+
"""
|
|
1494
|
+
encoded_request = Exchange.encode(request)
|
|
1495
|
+
if hash is not None:
|
|
1496
|
+
digest = Exchange.hash(encoded_request, hash, 'binary')
|
|
1497
|
+
else:
|
|
1498
|
+
digest = base64.b16decode(encoded_request, casefold=True)
|
|
1499
|
+
if isinstance(secret, str):
|
|
1500
|
+
secret = Exchange.encode(secret)
|
|
1501
|
+
# Handle PEM format
|
|
1502
|
+
if secret.find(b'-----BEGIN EC PRIVATE KEY-----') > -1:
|
|
1503
|
+
secret = base64.b16decode(secret.replace(b'-----BEGIN EC PRIVATE KEY-----', b'').replace(b'-----END EC PRIVATE KEY-----', b'').replace(b'\n', b'').replace(b'\r', b''), casefold=True)
|
|
1504
|
+
else:
|
|
1505
|
+
# Assume hex format
|
|
1506
|
+
secret = base64.b16decode(secret, casefold=True)
|
|
1507
|
+
# Create coincurve PrivateKey
|
|
1508
|
+
private_key = coincurve.PrivateKey(secret)
|
|
1509
|
+
# Sign the digest using sign_recoverable which produces deterministic signatures (RFC 6979)
|
|
1510
|
+
# The signature format is: 32 bytes r + 32 bytes s + 1 byte recovery_id (v)
|
|
1511
|
+
signature = private_key.sign_recoverable(digest, hasher=None)
|
|
1512
|
+
# Extract r, s, and v from the recoverable signature (65 bytes total)
|
|
1513
|
+
r_binary = signature[:32]
|
|
1514
|
+
s_binary = signature[32:64]
|
|
1515
|
+
v = signature[64]
|
|
1516
|
+
# Convert to hex strings
|
|
1517
|
+
r = Exchange.decode(base64.b16encode(r_binary)).lower()
|
|
1518
|
+
s = Exchange.decode(base64.b16encode(s_binary)).lower()
|
|
1519
|
+
return {
|
|
1520
|
+
'r': r,
|
|
1521
|
+
's': s,
|
|
1522
|
+
'v': v,
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
def binary_to_urlencoded_base64(data: bytes) -> str:
|
|
1526
|
+
encoded = base64.urlsafe_b64encode(data).decode("utf-8")
|
|
1527
|
+
return encoded.rstrip("=")
|
|
1528
|
+
|
|
1529
|
+
@staticmethod
|
|
1530
|
+
def eddsa(request, secret, curve='ed25519', url_encode=False):
|
|
1444
1531
|
if isinstance(secret, str):
|
|
1445
1532
|
secret = Exchange.encode(secret)
|
|
1446
1533
|
private_key = ed25519.Ed25519PrivateKey.from_private_bytes(secret) if len(secret) == 32 else load_pem_private_key(secret, None)
|
|
1447
|
-
|
|
1534
|
+
signature = private_key.sign(request)
|
|
1535
|
+
if url_encode:
|
|
1536
|
+
return Exchange.binary_to_urlencoded_base64(signature)
|
|
1537
|
+
|
|
1538
|
+
return Exchange.binary_to_base64(signature)
|
|
1448
1539
|
|
|
1449
1540
|
@staticmethod
|
|
1450
1541
|
def axolotl(request, secret, curve='ed25519'):
|
|
@@ -1859,6 +1950,8 @@ class Exchange(object):
|
|
|
1859
1950
|
signature = auth_data.signature
|
|
1860
1951
|
return signature
|
|
1861
1952
|
|
|
1953
|
+
def is_binary_message(self, message):
|
|
1954
|
+
return isinstance(message, bytes) or isinstance(message, bytearray)
|
|
1862
1955
|
|
|
1863
1956
|
# ########################################################################
|
|
1864
1957
|
# ########################################################################
|
|
@@ -1897,7 +1990,7 @@ class Exchange(object):
|
|
|
1897
1990
|
# ########################################################################
|
|
1898
1991
|
# ########################################################################
|
|
1899
1992
|
|
|
1900
|
-
# METHODS BELOW THIS LINE ARE TRANSPILED FROM
|
|
1993
|
+
# METHODS BELOW THIS LINE ARE TRANSPILED FROM TYPESCRIPT
|
|
1901
1994
|
|
|
1902
1995
|
def describe(self) -> Any:
|
|
1903
1996
|
return {
|
|
@@ -2130,6 +2223,17 @@ class Exchange(object):
|
|
|
2130
2223
|
'watchLiquidations': None,
|
|
2131
2224
|
'watchLiquidationsForSymbols': None,
|
|
2132
2225
|
'watchMyLiquidations': None,
|
|
2226
|
+
'unWatchOrders': None,
|
|
2227
|
+
'unWatchTrades': None,
|
|
2228
|
+
'unWatchTradesForSymbols': None,
|
|
2229
|
+
'unWatchOHLCVForSymbols': None,
|
|
2230
|
+
'unWatchOrderBookForSymbols': None,
|
|
2231
|
+
'unWatchPositions': None,
|
|
2232
|
+
'unWatchOrderBook': None,
|
|
2233
|
+
'unWatchTickers': None,
|
|
2234
|
+
'unWatchMyTrades': None,
|
|
2235
|
+
'unWatchTicker': None,
|
|
2236
|
+
'unWatchOHLCV': None,
|
|
2133
2237
|
'watchMyLiquidationsForSymbols': None,
|
|
2134
2238
|
'withdraw': None,
|
|
2135
2239
|
'ws': None,
|
|
@@ -2321,6 +2425,12 @@ class Exchange(object):
|
|
|
2321
2425
|
# return the first index of the cache that can be applied to the orderbook or -1 if not possible
|
|
2322
2426
|
return -1
|
|
2323
2427
|
|
|
2428
|
+
def arrays_concat(self, arraysOfArrays: List[Any]):
|
|
2429
|
+
result = []
|
|
2430
|
+
for i in range(0, len(arraysOfArrays)):
|
|
2431
|
+
result = self.array_concat(result, arraysOfArrays[i])
|
|
2432
|
+
return result
|
|
2433
|
+
|
|
2324
2434
|
def find_timeframe(self, timeframe, timeframes=None):
|
|
2325
2435
|
if timeframes is None:
|
|
2326
2436
|
timeframes = self.timeframes
|
|
@@ -2555,6 +2665,22 @@ class Exchange(object):
|
|
|
2555
2665
|
# set flag
|
|
2556
2666
|
self.isSandboxModeEnabled = False
|
|
2557
2667
|
|
|
2668
|
+
def enable_demo_trading(self, enable: bool):
|
|
2669
|
+
"""
|
|
2670
|
+
enables or disables demo trading mode
|
|
2671
|
+
:param boolean [enable]: True if demo trading should be enabled, False otherwise
|
|
2672
|
+
"""
|
|
2673
|
+
if self.isSandboxModeEnabled:
|
|
2674
|
+
raise NotSupported(self.id + ' demo trading does not support in sandbox environment. Please check https://www.binance.com/en/support/faq/detail/9be58f73e5e14338809e3b705b9687dd to see the differences')
|
|
2675
|
+
if enable:
|
|
2676
|
+
self.urls['apiBackupDemoTrading'] = self.urls['api']
|
|
2677
|
+
self.urls['api'] = self.urls['demo']
|
|
2678
|
+
elif 'apiBackupDemoTrading' in self.urls:
|
|
2679
|
+
self.urls['api'] = self.urls['apiBackupDemoTrading']
|
|
2680
|
+
newUrls = self.omit(self.urls, 'apiBackupDemoTrading')
|
|
2681
|
+
self.urls = newUrls
|
|
2682
|
+
self.options['enableDemoTrading'] = enable
|
|
2683
|
+
|
|
2558
2684
|
def sign(self, path, api: Any = 'public', method='GET', params={}, headers: Any = None, body: Any = None):
|
|
2559
2685
|
return {}
|
|
2560
2686
|
|
|
@@ -2616,6 +2742,18 @@ class Exchange(object):
|
|
|
2616
2742
|
def un_watch_order_book_for_symbols(self, symbols: List[str], params={}):
|
|
2617
2743
|
raise NotSupported(self.id + ' unWatchOrderBookForSymbols() is not supported yet')
|
|
2618
2744
|
|
|
2745
|
+
def un_watch_positions(self, symbols: Strings = None, params={}):
|
|
2746
|
+
raise NotSupported(self.id + ' unWatchPositions() is not supported yet')
|
|
2747
|
+
|
|
2748
|
+
def un_watch_ticker(self, symbol: str, params={}):
|
|
2749
|
+
raise NotSupported(self.id + ' unWatchTicker() is not supported yet')
|
|
2750
|
+
|
|
2751
|
+
def un_watch_mark_price(self, symbol: str, params={}):
|
|
2752
|
+
raise NotSupported(self.id + ' unWatchMarkPrice() is not supported yet')
|
|
2753
|
+
|
|
2754
|
+
def un_watch_mark_prices(self, symbols: Strings = None, params={}):
|
|
2755
|
+
raise NotSupported(self.id + ' unWatchMarkPrices() is not supported yet')
|
|
2756
|
+
|
|
2619
2757
|
def fetch_deposit_addresses(self, codes: Strings = None, params={}):
|
|
2620
2758
|
raise NotSupported(self.id + ' fetchDepositAddresses() is not supported yet')
|
|
2621
2759
|
|
|
@@ -2757,13 +2895,13 @@ class Exchange(object):
|
|
|
2757
2895
|
def transfer(self, code: str, amount: float, fromAccount: str, toAccount: str, params={}):
|
|
2758
2896
|
raise NotSupported(self.id + ' transfer() is not supported yet')
|
|
2759
2897
|
|
|
2760
|
-
def withdraw(self, code: str, amount: float, address: str, tag=None, params={}):
|
|
2898
|
+
def withdraw(self, code: str, amount: float, address: str, tag: Str = None, params={}):
|
|
2761
2899
|
raise NotSupported(self.id + ' withdraw() is not supported yet')
|
|
2762
2900
|
|
|
2763
2901
|
def create_deposit_address(self, code: str, params={}):
|
|
2764
2902
|
raise NotSupported(self.id + ' createDepositAddress() is not supported yet')
|
|
2765
2903
|
|
|
2766
|
-
def set_leverage(self, leverage:
|
|
2904
|
+
def set_leverage(self, leverage: int, symbol: Str = None, params={}):
|
|
2767
2905
|
raise NotSupported(self.id + ' setLeverage() is not supported yet')
|
|
2768
2906
|
|
|
2769
2907
|
def fetch_leverage(self, symbol: str, params={}):
|
|
@@ -2812,7 +2950,7 @@ class Exchange(object):
|
|
|
2812
2950
|
def fetch_deposit_addresses_by_network(self, code: str, params={}):
|
|
2813
2951
|
raise NotSupported(self.id + ' fetchDepositAddressesByNetwork() is not supported yet')
|
|
2814
2952
|
|
|
2815
|
-
def fetch_open_interest_history(self, symbol: str, timeframe='1h', since: Int = None, limit: Int = None, params={}):
|
|
2953
|
+
def fetch_open_interest_history(self, symbol: str, timeframe: str = '1h', since: Int = None, limit: Int = None, params={}):
|
|
2816
2954
|
raise NotSupported(self.id + ' fetchOpenInterestHistory() is not supported yet')
|
|
2817
2955
|
|
|
2818
2956
|
def fetch_open_interest(self, symbol: str, params={}):
|
|
@@ -2837,9 +2975,9 @@ class Exchange(object):
|
|
|
2837
2975
|
def parse_to_numeric(self, number):
|
|
2838
2976
|
stringVersion = self.number_to_string(number) # self will convert 1.0 and 1 to "1" and 1.1 to "1.1"
|
|
2839
2977
|
# keep self in mind:
|
|
2840
|
-
# in JS:
|
|
2978
|
+
# in JS: 1 == 1.0 is True
|
|
2841
2979
|
# in Python: 1 == 1.0 is True
|
|
2842
|
-
# in PHP
|
|
2980
|
+
# in PHP: 1 == 1.0 is True, but 1 == 1.0 is False.
|
|
2843
2981
|
if stringVersion.find('.') >= 0:
|
|
2844
2982
|
return float(stringVersion)
|
|
2845
2983
|
return int(stringVersion)
|
|
@@ -2885,7 +3023,7 @@ class Exchange(object):
|
|
|
2885
3023
|
'delay': 0.001,
|
|
2886
3024
|
'capacity': 1,
|
|
2887
3025
|
'cost': 1,
|
|
2888
|
-
'maxCapacity': 1000,
|
|
3026
|
+
'maxCapacity': self.safe_integer(self.options, 'maxRequestsQueue', 1000),
|
|
2889
3027
|
'refillRate': refillRate,
|
|
2890
3028
|
}
|
|
2891
3029
|
existingBucket = {} if (self.tokenBucket is None) else self.tokenBucket
|
|
@@ -2967,6 +3105,79 @@ class Exchange(object):
|
|
|
2967
3105
|
featureBlock['symbolRequired'] = self.in_array(key, ['createOrder', 'createOrders', 'fetchOHLCV'])
|
|
2968
3106
|
return featuresObj
|
|
2969
3107
|
|
|
3108
|
+
def feature_value(self, symbol: str, methodName: Str = None, paramName: Str = None, defaultValue: Any = None):
|
|
3109
|
+
"""
|
|
3110
|
+
self method is a very deterministic to help users to know what feature is supported by the exchange
|
|
3111
|
+
:param str [symbol]: unified symbol
|
|
3112
|
+
:param str [methodName]: view currently supported methods: https://docs.ccxt.com/#/README?id=features
|
|
3113
|
+
:param str [paramName]: unified param value, like: `triggerPrice`, `stopLoss.triggerPrice`(check docs for supported param names)
|
|
3114
|
+
:param dict [defaultValue]: return default value if no result found
|
|
3115
|
+
:returns dict: returns feature value
|
|
3116
|
+
"""
|
|
3117
|
+
market = self.market(symbol)
|
|
3118
|
+
return self.feature_value_by_type(market['type'], market['subType'], methodName, paramName, defaultValue)
|
|
3119
|
+
|
|
3120
|
+
def feature_value_by_type(self, marketType: str, subType: Str, methodName: Str = None, paramName: Str = None, defaultValue: Any = None):
|
|
3121
|
+
"""
|
|
3122
|
+
self method is a very deterministic to help users to know what feature is supported by the exchange
|
|
3123
|
+
:param str [marketType]: supported only: "spot", "swap", "future"
|
|
3124
|
+
:param str [subType]: supported only: "linear", "inverse"
|
|
3125
|
+
:param str [methodName]: view currently supported methods: https://docs.ccxt.com/#/README?id=features
|
|
3126
|
+
:param str [paramName]: unified param value(check docs for supported param names)
|
|
3127
|
+
:param dict [defaultValue]: return default value if no result found
|
|
3128
|
+
:returns dict: returns feature value
|
|
3129
|
+
"""
|
|
3130
|
+
# if exchange does not yet have features manually implemented
|
|
3131
|
+
if self.features is None:
|
|
3132
|
+
return defaultValue
|
|
3133
|
+
if marketType is None:
|
|
3134
|
+
return defaultValue # marketType is required
|
|
3135
|
+
# if marketType(e.g. 'option') does not exist in features
|
|
3136
|
+
if not (marketType in self.features):
|
|
3137
|
+
return defaultValue # unsupported marketType, check "exchange.features" for details
|
|
3138
|
+
# if marketType dict None
|
|
3139
|
+
if self.features[marketType] is None:
|
|
3140
|
+
return defaultValue
|
|
3141
|
+
methodsContainer = self.features[marketType]
|
|
3142
|
+
if subType is None:
|
|
3143
|
+
if marketType != 'spot':
|
|
3144
|
+
return defaultValue # subType is required for non-spot markets
|
|
3145
|
+
else:
|
|
3146
|
+
if not (subType in self.features[marketType]):
|
|
3147
|
+
return defaultValue # unsupported subType, check "exchange.features" for details
|
|
3148
|
+
# if subType dict None
|
|
3149
|
+
if self.features[marketType][subType] is None:
|
|
3150
|
+
return defaultValue
|
|
3151
|
+
methodsContainer = self.features[marketType][subType]
|
|
3152
|
+
# if user wanted only marketType and didn't provide methodName, eg: featureIsSupported('spot')
|
|
3153
|
+
if methodName is None:
|
|
3154
|
+
return defaultValue if (defaultValue is not None) else methodsContainer
|
|
3155
|
+
if not (methodName in methodsContainer):
|
|
3156
|
+
return defaultValue # unsupported method, check "exchange.features" for details')
|
|
3157
|
+
methodDict = methodsContainer[methodName]
|
|
3158
|
+
if methodDict is None:
|
|
3159
|
+
return defaultValue
|
|
3160
|
+
# if user wanted only method and didn't provide `paramName`, eg: featureIsSupported('swap', 'linear', 'createOrder')
|
|
3161
|
+
if paramName is None:
|
|
3162
|
+
return defaultValue if (defaultValue is not None) else methodDict
|
|
3163
|
+
splited = paramName.split('.') # can be only parent key(`stopLoss`) or with child(`stopLoss.triggerPrice`)
|
|
3164
|
+
parentKey = splited[0]
|
|
3165
|
+
subKey = self.safe_string(splited, 1)
|
|
3166
|
+
if not (parentKey in methodDict):
|
|
3167
|
+
return defaultValue # unsupported paramName, check "exchange.features" for details')
|
|
3168
|
+
dictionary = self.safe_dict(methodDict, parentKey)
|
|
3169
|
+
if dictionary is None:
|
|
3170
|
+
# if the value is not dictionary but a scalar value(or None), return
|
|
3171
|
+
return methodDict[parentKey]
|
|
3172
|
+
else:
|
|
3173
|
+
# return, when calling without subKey eg: featureValueByType('spot', None, 'createOrder', 'stopLoss')
|
|
3174
|
+
if subKey is None:
|
|
3175
|
+
return methodDict[parentKey]
|
|
3176
|
+
# raise an exception for unsupported subKey
|
|
3177
|
+
if not (subKey in methodDict[parentKey]):
|
|
3178
|
+
return defaultValue # unsupported subKey, check "exchange.features" for details
|
|
3179
|
+
return methodDict[parentKey][subKey]
|
|
3180
|
+
|
|
2970
3181
|
def orderbook_checksum_message(self, symbol: Str):
|
|
2971
3182
|
return symbol + ' = False'
|
|
2972
3183
|
|
|
@@ -3233,7 +3444,11 @@ class Exchange(object):
|
|
|
3233
3444
|
marketsSortedById = self.keysort(self.markets_by_id)
|
|
3234
3445
|
self.symbols = list(marketsSortedBySymbol.keys())
|
|
3235
3446
|
self.ids = list(marketsSortedById.keys())
|
|
3447
|
+
numCurrencies = 0
|
|
3236
3448
|
if currencies is not None:
|
|
3449
|
+
keys = list(currencies.keys())
|
|
3450
|
+
numCurrencies = len(keys)
|
|
3451
|
+
if numCurrencies > 0:
|
|
3237
3452
|
# currencies is always None when called in constructor but not when called from loadMarkets
|
|
3238
3453
|
self.currencies = self.map_to_safe_map(self.deep_extend(self.currencies, currencies))
|
|
3239
3454
|
else:
|
|
@@ -3285,6 +3500,30 @@ class Exchange(object):
|
|
|
3285
3500
|
self.codes = list(currenciesSortedByCode.keys())
|
|
3286
3501
|
return self.markets
|
|
3287
3502
|
|
|
3503
|
+
def set_markets_from_exchange(self, sourceExchange):
|
|
3504
|
+
# Validate that both exchanges are of the same type
|
|
3505
|
+
if self.id != sourceExchange.id:
|
|
3506
|
+
raise ArgumentsRequired(self.id + ' shareMarkets() can only share markets with exchanges of the same type(got ' + sourceExchange['id'] + ')')
|
|
3507
|
+
# Validate that source exchange has loaded markets
|
|
3508
|
+
if not sourceExchange.markets:
|
|
3509
|
+
raise ExchangeError('setMarketsFromExchange() source exchange must have loaded markets first. Can call by using loadMarkets function')
|
|
3510
|
+
# Set all market-related data
|
|
3511
|
+
self.markets = sourceExchange.markets
|
|
3512
|
+
self.markets_by_id = sourceExchange.markets_by_id
|
|
3513
|
+
self.symbols = sourceExchange.symbols
|
|
3514
|
+
self.ids = sourceExchange.ids
|
|
3515
|
+
self.currencies = sourceExchange.currencies
|
|
3516
|
+
self.baseCurrencies = sourceExchange.baseCurrencies
|
|
3517
|
+
self.quoteCurrencies = sourceExchange.quoteCurrencies
|
|
3518
|
+
self.codes = sourceExchange.codes
|
|
3519
|
+
# check marketHelperProps
|
|
3520
|
+
sourceExchangeHelpers = self.safe_list(sourceExchange.options, 'marketHelperProps', [])
|
|
3521
|
+
for i in range(0, len(sourceExchangeHelpers)):
|
|
3522
|
+
helper = sourceExchangeHelpers[i]
|
|
3523
|
+
if sourceExchange.options[helper] is not None:
|
|
3524
|
+
self.options[helper] = sourceExchange.options[helper]
|
|
3525
|
+
return self
|
|
3526
|
+
|
|
3288
3527
|
def get_describe_for_extended_ws_exchange(self, currentRestInstance: Any, parentRestInstance: Any, wsBaseDescribe: dict):
|
|
3289
3528
|
extendedRestDescribe = self.deep_extend(parentRestInstance.describe(), currentRestInstance.describe())
|
|
3290
3529
|
superWithRestDescribe = self.deep_extend(extendedRestDescribe, wsBaseDescribe)
|
|
@@ -3584,18 +3823,7 @@ class Exchange(object):
|
|
|
3584
3823
|
symbol = market['symbol'] if (market is not None) else None
|
|
3585
3824
|
return self.filter_by_symbol_since_limit(results, symbol, since, limit)
|
|
3586
3825
|
|
|
3587
|
-
def
|
|
3588
|
-
"""
|
|
3589
|
-
calculates the presumptive fee that would be charged for an order
|
|
3590
|
-
:param str symbol: unified market symbol
|
|
3591
|
-
:param str type: 'market' or 'limit'
|
|
3592
|
-
:param str side: 'buy' or 'sell'
|
|
3593
|
-
:param float amount: how much you want to trade, in units of the base currency on most exchanges, or number of contracts
|
|
3594
|
-
:param float price: the price for the order to be filled at, in units of the quote currency
|
|
3595
|
-
:param str takerOrMaker: 'taker' or 'maker'
|
|
3596
|
-
:param dict params:
|
|
3597
|
-
:returns dict: contains the rate, the percentage multiplied to the order amount to obtain the fee amount, and cost, the total value of the fee in units of the quote currency, for the order
|
|
3598
|
-
"""
|
|
3826
|
+
def calculate_fee_with_rate(self, symbol: str, type: str, side: str, amount: float, price: float, takerOrMaker='taker', feeRate: Num = None, params={}):
|
|
3599
3827
|
if type == 'market' and takerOrMaker == 'maker':
|
|
3600
3828
|
raise ArgumentsRequired(self.id + ' calculateFee() - you have provided incompatible arguments - "market" type order can not be "maker". Change either the "type" or the "takerOrMaker" argument to calculate the fee.')
|
|
3601
3829
|
market = self.markets[symbol]
|
|
@@ -3624,7 +3852,7 @@ class Exchange(object):
|
|
|
3624
3852
|
# even if `takerOrMaker` argument was set to 'maker', for 'market' orders we should forcefully override it to 'taker'
|
|
3625
3853
|
if type == 'market':
|
|
3626
3854
|
takerOrMaker = 'taker'
|
|
3627
|
-
rate = self.safe_string(market, takerOrMaker)
|
|
3855
|
+
rate = self.number_to_string(feeRate) if (feeRate is not None) else self.safe_string(market, takerOrMaker)
|
|
3628
3856
|
cost = Precise.string_mul(cost, rate)
|
|
3629
3857
|
return {
|
|
3630
3858
|
'type': takerOrMaker,
|
|
@@ -3633,6 +3861,20 @@ class Exchange(object):
|
|
|
3633
3861
|
'cost': self.parse_number(cost),
|
|
3634
3862
|
}
|
|
3635
3863
|
|
|
3864
|
+
def calculate_fee(self, symbol: str, type: str, side: str, amount: float, price: float, takerOrMaker='taker', params={}):
|
|
3865
|
+
"""
|
|
3866
|
+
calculates the presumptive fee that would be charged for an order
|
|
3867
|
+
:param str symbol: unified market symbol
|
|
3868
|
+
:param str type: 'market' or 'limit'
|
|
3869
|
+
:param str side: 'buy' or 'sell'
|
|
3870
|
+
:param float amount: how much you want to trade, in units of the base currency on most exchanges, or number of contracts
|
|
3871
|
+
:param float price: the price for the order to be filled at, in units of the quote currency
|
|
3872
|
+
:param str takerOrMaker: 'taker' or 'maker'
|
|
3873
|
+
:param dict params:
|
|
3874
|
+
:returns dict: contains the rate, the percentage multiplied to the order amount to obtain the fee amount, and cost, the total value of the fee in units of the quote currency, for the order
|
|
3875
|
+
"""
|
|
3876
|
+
return self.calculate_fee_with_rate(symbol, type, side, amount, price, takerOrMaker, None, params)
|
|
3877
|
+
|
|
3636
3878
|
def safe_liquidation(self, liquidation: dict, market: Market = None):
|
|
3637
3879
|
contracts = self.safe_string(liquidation, 'contracts')
|
|
3638
3880
|
contractSize = self.safe_string(market, 'contractSize')
|
|
@@ -3672,6 +3914,21 @@ class Exchange(object):
|
|
|
3672
3914
|
trade['cost'] = self.parse_number(cost)
|
|
3673
3915
|
return trade
|
|
3674
3916
|
|
|
3917
|
+
def create_ccxt_trade_id(self, timestamp=None, side=None, amount=None, price=None, takerOrMaker=None):
|
|
3918
|
+
# self approach is being used by multiple exchanges(mexc, woo, coinsbit, dydx, ...)
|
|
3919
|
+
id = None
|
|
3920
|
+
if timestamp is not None:
|
|
3921
|
+
id = self.number_to_string(timestamp)
|
|
3922
|
+
if side is not None:
|
|
3923
|
+
id += '-' + side
|
|
3924
|
+
if amount is not None:
|
|
3925
|
+
id += '-' + self.number_to_string(amount)
|
|
3926
|
+
if price is not None:
|
|
3927
|
+
id += '-' + self.number_to_string(price)
|
|
3928
|
+
if takerOrMaker is not None:
|
|
3929
|
+
id += '-' + takerOrMaker
|
|
3930
|
+
return id
|
|
3931
|
+
|
|
3675
3932
|
def parsed_fee_and_fees(self, container: Any):
|
|
3676
3933
|
fee = self.safe_dict(container, 'fee')
|
|
3677
3934
|
fees = self.safe_list(container, 'fees')
|
|
@@ -3905,19 +4162,19 @@ class Exchange(object):
|
|
|
3905
4162
|
def repay_margin(self, code: str, amount: float, symbol: Str = None, params={}):
|
|
3906
4163
|
raise NotSupported(self.id + ' repayMargin is deprecated, please use repayCrossMargin or repayIsolatedMargin instead')
|
|
3907
4164
|
|
|
3908
|
-
def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}):
|
|
4165
|
+
def fetch_ohlcv(self, symbol: str, timeframe: str = '1m', since: Int = None, limit: Int = None, params={}):
|
|
3909
4166
|
message = ''
|
|
3910
4167
|
if self.has['fetchTrades']:
|
|
3911
4168
|
message = '. If you want to build OHLCV candles from trade executions data, visit https://github.com/ccxt/ccxt/tree/master/examples/ and see "build-ohlcv-bars" file'
|
|
3912
4169
|
raise NotSupported(self.id + ' fetchOHLCV() is not supported yet' + message)
|
|
3913
4170
|
|
|
3914
|
-
def fetch_ohlcv_ws(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}):
|
|
4171
|
+
def fetch_ohlcv_ws(self, symbol: str, timeframe: str = '1m', since: Int = None, limit: Int = None, params={}):
|
|
3915
4172
|
message = ''
|
|
3916
4173
|
if self.has['fetchTradesWs']:
|
|
3917
4174
|
message = '. If you want to build OHLCV candles from trade executions data, visit https://github.com/ccxt/ccxt/tree/master/examples/ and see "build-ohlcv-bars" file'
|
|
3918
4175
|
raise NotSupported(self.id + ' fetchOHLCVWs() is not supported yet. Try using fetchOHLCV instead.' + message)
|
|
3919
4176
|
|
|
3920
|
-
def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}):
|
|
4177
|
+
def watch_ohlcv(self, symbol: str, timeframe: str = '1m', since: Int = None, limit: Int = None, params={}):
|
|
3921
4178
|
raise NotSupported(self.id + ' watchOHLCV() is not supported yet')
|
|
3922
4179
|
|
|
3923
4180
|
def convert_trading_view_to_ohlcv(self, ohlcvs: List[List[float]], timestamp='t', open='o', high='h', low='l', close='c', volume='v', ms=False):
|
|
@@ -4329,16 +4586,27 @@ class Exchange(object):
|
|
|
4329
4586
|
result.append(account)
|
|
4330
4587
|
return result
|
|
4331
4588
|
|
|
4332
|
-
def
|
|
4589
|
+
def parse_trades_helper(self, isWs: bool, trades: List[Any], market: Market = None, since: Int = None, limit: Int = None, params={}):
|
|
4333
4590
|
trades = self.to_array(trades)
|
|
4334
4591
|
result = []
|
|
4335
4592
|
for i in range(0, len(trades)):
|
|
4336
|
-
|
|
4593
|
+
parsed = None
|
|
4594
|
+
if isWs:
|
|
4595
|
+
parsed = self.parse_ws_trade(trades[i], market)
|
|
4596
|
+
else:
|
|
4597
|
+
parsed = self.parse_trade(trades[i], market)
|
|
4598
|
+
trade = self.extend(parsed, params)
|
|
4337
4599
|
result.append(trade)
|
|
4338
4600
|
result = self.sort_by_2(result, 'timestamp', 'id')
|
|
4339
4601
|
symbol = market['symbol'] if (market is not None) else None
|
|
4340
4602
|
return self.filter_by_symbol_since_limit(result, symbol, since, limit)
|
|
4341
4603
|
|
|
4604
|
+
def parse_trades(self, trades: List[Any], market: Market = None, since: Int = None, limit: Int = None, params={}):
|
|
4605
|
+
return self.parse_trades_helper(False, trades, market, since, limit, params)
|
|
4606
|
+
|
|
4607
|
+
def parse_ws_trades(self, trades: List[Any], market: Market = None, since: Int = None, limit: Int = None, params={}):
|
|
4608
|
+
return self.parse_trades_helper(True, trades, market, since, limit, params)
|
|
4609
|
+
|
|
4342
4610
|
def parse_transactions(self, transactions: List[Any], currency: Currency = None, since: Int = None, limit: Int = None, params={}):
|
|
4343
4611
|
transactions = self.to_array(transactions)
|
|
4344
4612
|
result = []
|
|
@@ -4555,9 +4823,12 @@ class Exchange(object):
|
|
|
4555
4823
|
i_count = 6
|
|
4556
4824
|
tradesLength = len(trades)
|
|
4557
4825
|
oldest = min(tradesLength, limit)
|
|
4826
|
+
options = self.safe_dict(self.options, 'buildOHLCVC', {})
|
|
4827
|
+
skipZeroPrices = self.safe_bool(options, 'skipZeroPrices', True)
|
|
4558
4828
|
for i in range(0, oldest):
|
|
4559
4829
|
trade = trades[i]
|
|
4560
4830
|
ts = trade['timestamp']
|
|
4831
|
+
price = trade['price']
|
|
4561
4832
|
if ts < since:
|
|
4562
4833
|
continue
|
|
4563
4834
|
openingTime = int(math.floor(ts / ms)) * ms # shift to the edge of m/h/d(but not M)
|
|
@@ -4565,22 +4836,25 @@ class Exchange(object):
|
|
|
4565
4836
|
continue
|
|
4566
4837
|
ohlcv_length = len(ohlcvs)
|
|
4567
4838
|
candle = ohlcv_length - 1
|
|
4568
|
-
if (
|
|
4839
|
+
if skipZeroPrices and not (price > 0) and not (price < 0):
|
|
4840
|
+
continue
|
|
4841
|
+
isFirstCandle = candle == -1
|
|
4842
|
+
if isFirstCandle or openingTime >= self.sum(ohlcvs[candle][i_timestamp], ms):
|
|
4569
4843
|
# moved to a new timeframe -> create a new candle from opening trade
|
|
4570
4844
|
ohlcvs.append([
|
|
4571
4845
|
openingTime, # timestamp
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4846
|
+
price, # O
|
|
4847
|
+
price, # H
|
|
4848
|
+
price, # L
|
|
4849
|
+
price, # C
|
|
4576
4850
|
trade['amount'], # V
|
|
4577
4851
|
1, # count
|
|
4578
4852
|
])
|
|
4579
4853
|
else:
|
|
4580
4854
|
# still processing the same timeframe -> update opening trade
|
|
4581
|
-
ohlcvs[candle][i_high] = max(ohlcvs[candle][i_high],
|
|
4582
|
-
ohlcvs[candle][i_low] = min(ohlcvs[candle][i_low],
|
|
4583
|
-
ohlcvs[candle][i_close] =
|
|
4855
|
+
ohlcvs[candle][i_high] = max(ohlcvs[candle][i_high], price)
|
|
4856
|
+
ohlcvs[candle][i_low] = min(ohlcvs[candle][i_low], price)
|
|
4857
|
+
ohlcvs[candle][i_close] = price
|
|
4584
4858
|
ohlcvs[candle][i_volume] = self.sum(ohlcvs[candle][i_volume], trade['amount'])
|
|
4585
4859
|
ohlcvs[candle][i_count] = self.sum(ohlcvs[candle][i_count], 1)
|
|
4586
4860
|
return ohlcvs
|
|
@@ -4720,6 +4994,11 @@ class Exchange(object):
|
|
|
4720
4994
|
return market
|
|
4721
4995
|
return result
|
|
4722
4996
|
|
|
4997
|
+
def market_or_null(self, symbol: str):
|
|
4998
|
+
if symbol is None:
|
|
4999
|
+
return None
|
|
5000
|
+
return self.market(symbol)
|
|
5001
|
+
|
|
4723
5002
|
def check_required_credentials(self, error=True):
|
|
4724
5003
|
"""
|
|
4725
5004
|
@ignore
|
|
@@ -5038,7 +5317,7 @@ class Exchange(object):
|
|
|
5038
5317
|
def fetch_position_mode(self, symbol: Str = None, params={}):
|
|
5039
5318
|
raise NotSupported(self.id + ' fetchPositionMode() is not supported yet')
|
|
5040
5319
|
|
|
5041
|
-
def create_trailing_amount_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, trailingAmount=None, trailingTriggerPrice=None, params={}):
|
|
5320
|
+
def create_trailing_amount_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, trailingAmount: Num = None, trailingTriggerPrice: Num = None, params={}):
|
|
5042
5321
|
"""
|
|
5043
5322
|
create a trailing order by providing the symbol, type, side, amount, price and trailingAmount
|
|
5044
5323
|
:param str symbol: unified symbol of the market to create an order in
|
|
@@ -5060,7 +5339,7 @@ class Exchange(object):
|
|
|
5060
5339
|
return self.create_order(symbol, type, side, amount, price, params)
|
|
5061
5340
|
raise NotSupported(self.id + ' createTrailingAmountOrder() is not supported yet')
|
|
5062
5341
|
|
|
5063
|
-
def create_trailing_amount_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, trailingAmount=None, trailingTriggerPrice=None, params={}):
|
|
5342
|
+
def create_trailing_amount_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, trailingAmount: Num = None, trailingTriggerPrice: Num = None, params={}):
|
|
5064
5343
|
"""
|
|
5065
5344
|
create a trailing order by providing the symbol, type, side, amount, price and trailingAmount
|
|
5066
5345
|
:param str symbol: unified symbol of the market to create an order in
|
|
@@ -5082,7 +5361,7 @@ class Exchange(object):
|
|
|
5082
5361
|
return self.create_order_ws(symbol, type, side, amount, price, params)
|
|
5083
5362
|
raise NotSupported(self.id + ' createTrailingAmountOrderWs() is not supported yet')
|
|
5084
5363
|
|
|
5085
|
-
def create_trailing_percent_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, trailingPercent=None, trailingTriggerPrice=None, params={}):
|
|
5364
|
+
def create_trailing_percent_order(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, trailingPercent: Num = None, trailingTriggerPrice: Num = None, params={}):
|
|
5086
5365
|
"""
|
|
5087
5366
|
create a trailing order by providing the symbol, type, side, amount, price and trailingPercent
|
|
5088
5367
|
:param str symbol: unified symbol of the market to create an order in
|
|
@@ -5104,7 +5383,7 @@ class Exchange(object):
|
|
|
5104
5383
|
return self.create_order(symbol, type, side, amount, price, params)
|
|
5105
5384
|
raise NotSupported(self.id + ' createTrailingPercentOrder() is not supported yet')
|
|
5106
5385
|
|
|
5107
|
-
def create_trailing_percent_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, trailingPercent=None, trailingTriggerPrice=None, params={}):
|
|
5386
|
+
def create_trailing_percent_order_ws(self, symbol: str, type: OrderType, side: OrderSide, amount: float, price: Num = None, trailingPercent: Num = None, trailingTriggerPrice: Num = None, params={}):
|
|
5108
5387
|
"""
|
|
5109
5388
|
create a trailing order by providing the symbol, type, side, amount, price and trailingPercent
|
|
5110
5389
|
:param str symbol: unified symbol of the market to create an order in
|
|
@@ -5395,6 +5674,9 @@ class Exchange(object):
|
|
|
5395
5674
|
def cancel_order_ws(self, id: str, symbol: Str = None, params={}):
|
|
5396
5675
|
raise NotSupported(self.id + ' cancelOrderWs() is not supported yet')
|
|
5397
5676
|
|
|
5677
|
+
def cancel_orders(self, ids: List[str], symbol: Str = None, params={}):
|
|
5678
|
+
raise NotSupported(self.id + ' cancelOrders() is not supported yet')
|
|
5679
|
+
|
|
5398
5680
|
def cancel_orders_ws(self, ids: List[str], symbol: Str = None, params={}):
|
|
5399
5681
|
raise NotSupported(self.id + ' cancelOrdersWs() is not supported yet')
|
|
5400
5682
|
|
|
@@ -5410,7 +5692,7 @@ class Exchange(object):
|
|
|
5410
5692
|
def cancel_all_orders_ws(self, symbol: Str = None, params={}):
|
|
5411
5693
|
raise NotSupported(self.id + ' cancelAllOrdersWs() is not supported yet')
|
|
5412
5694
|
|
|
5413
|
-
def cancel_unified_order(self, order, params={}):
|
|
5695
|
+
def cancel_unified_order(self, order: Order, params={}):
|
|
5414
5696
|
return self.cancel_order(self.safe_string(order, 'id'), self.safe_string(order, 'symbol'), params)
|
|
5415
5697
|
|
|
5416
5698
|
def fetch_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
@@ -5495,10 +5777,10 @@ class Exchange(object):
|
|
|
5495
5777
|
"""
|
|
5496
5778
|
raise NotSupported(self.id + ' fetchDepositsWithdrawals() is not supported yet')
|
|
5497
5779
|
|
|
5498
|
-
def fetch_deposits(self,
|
|
5780
|
+
def fetch_deposits(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
5499
5781
|
raise NotSupported(self.id + ' fetchDeposits() is not supported yet')
|
|
5500
5782
|
|
|
5501
|
-
def fetch_withdrawals(self,
|
|
5783
|
+
def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
5502
5784
|
raise NotSupported(self.id + ' fetchWithdrawals() is not supported yet')
|
|
5503
5785
|
|
|
5504
5786
|
def fetch_deposits_ws(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
@@ -5559,7 +5841,9 @@ class Exchange(object):
|
|
|
5559
5841
|
return self.safe_string(self.commonCurrencies, code, code)
|
|
5560
5842
|
|
|
5561
5843
|
def currency(self, code: str):
|
|
5562
|
-
|
|
5844
|
+
keys = list(self.currencies.keys())
|
|
5845
|
+
numCurrencies = len(keys)
|
|
5846
|
+
if numCurrencies == 0:
|
|
5563
5847
|
raise ExchangeError(self.id + ' currencies not loaded')
|
|
5564
5848
|
if isinstance(code, str):
|
|
5565
5849
|
if code in self.currencies:
|
|
@@ -6005,6 +6289,29 @@ class Exchange(object):
|
|
|
6005
6289
|
symbol = None if (market is None) else market['symbol']
|
|
6006
6290
|
return self.filter_by_symbol_since_limit(sorted, symbol, since, limit)
|
|
6007
6291
|
|
|
6292
|
+
def handle_trigger_prices_and_params(self, symbol, params, omitParams=True):
|
|
6293
|
+
#
|
|
6294
|
+
triggerPrice = self.safe_string_2(params, 'triggerPrice', 'stopPrice')
|
|
6295
|
+
triggerPriceStr: Str = None
|
|
6296
|
+
stopLossPrice = self.safe_string(params, 'stopLossPrice')
|
|
6297
|
+
stopLossPriceStr: Str = None
|
|
6298
|
+
takeProfitPrice = self.safe_string(params, 'takeProfitPrice')
|
|
6299
|
+
takeProfitPriceStr: Str = None
|
|
6300
|
+
#
|
|
6301
|
+
if triggerPrice is not None:
|
|
6302
|
+
if omitParams:
|
|
6303
|
+
params = self.omit(params, ['triggerPrice', 'stopPrice'])
|
|
6304
|
+
triggerPriceStr = self.price_to_precision(symbol, float(triggerPrice))
|
|
6305
|
+
if stopLossPrice is not None:
|
|
6306
|
+
if omitParams:
|
|
6307
|
+
params = self.omit(params, 'stopLossPrice')
|
|
6308
|
+
stopLossPriceStr = self.price_to_precision(symbol, float(stopLossPrice))
|
|
6309
|
+
if takeProfitPrice is not None:
|
|
6310
|
+
if omitParams:
|
|
6311
|
+
params = self.omit(params, 'takeProfitPrice')
|
|
6312
|
+
takeProfitPriceStr = self.price_to_precision(symbol, float(takeProfitPrice))
|
|
6313
|
+
return [triggerPriceStr, stopLossPriceStr, takeProfitPriceStr, params]
|
|
6314
|
+
|
|
6008
6315
|
def handle_trigger_direction_and_params(self, params, exchangeSpecificKey: Str = None, allowEmpty: Bool = False):
|
|
6009
6316
|
"""
|
|
6010
6317
|
@ignore
|
|
@@ -6158,7 +6465,7 @@ class Exchange(object):
|
|
|
6158
6465
|
else:
|
|
6159
6466
|
raise NotSupported(self.id + ' fetchFundingInterval() is not supported yet')
|
|
6160
6467
|
|
|
6161
|
-
def fetch_mark_ohlcv(self, symbol, timeframe='1m', since: Int = None, limit: Int = None, params={}):
|
|
6468
|
+
def fetch_mark_ohlcv(self, symbol: str, timeframe: str = '1m', since: Int = None, limit: Int = None, params={}):
|
|
6162
6469
|
"""
|
|
6163
6470
|
fetches historical mark price candlestick data containing the open, high, low, and close price of a market
|
|
6164
6471
|
:param str symbol: unified symbol of the market to fetch OHLCV data for
|
|
@@ -6176,7 +6483,7 @@ class Exchange(object):
|
|
|
6176
6483
|
else:
|
|
6177
6484
|
raise NotSupported(self.id + ' fetchMarkOHLCV() is not supported yet')
|
|
6178
6485
|
|
|
6179
|
-
def fetch_index_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}):
|
|
6486
|
+
def fetch_index_ohlcv(self, symbol: str, timeframe: str = '1m', since: Int = None, limit: Int = None, params={}):
|
|
6180
6487
|
"""
|
|
6181
6488
|
fetches historical index price candlestick data containing the open, high, low, and close price of a market
|
|
6182
6489
|
:param str symbol: unified symbol of the market to fetch OHLCV data for
|
|
@@ -6194,7 +6501,7 @@ class Exchange(object):
|
|
|
6194
6501
|
else:
|
|
6195
6502
|
raise NotSupported(self.id + ' fetchIndexOHLCV() is not supported yet')
|
|
6196
6503
|
|
|
6197
|
-
def fetch_premium_index_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}):
|
|
6504
|
+
def fetch_premium_index_ohlcv(self, symbol: str, timeframe: str = '1m', since: Int = None, limit: Int = None, params={}):
|
|
6198
6505
|
"""
|
|
6199
6506
|
fetches historical premium index price candlestick data containing the open, high, low, and close price of a market
|
|
6200
6507
|
:param str symbol: unified symbol of the market to fetch OHLCV data for
|
|
@@ -6426,7 +6733,7 @@ class Exchange(object):
|
|
|
6426
6733
|
calls = 0
|
|
6427
6734
|
result = []
|
|
6428
6735
|
errors = 0
|
|
6429
|
-
until = self.
|
|
6736
|
+
until = self.safe_integer_n(params, ['until', 'untill', 'till']) # do not omit it from params here
|
|
6430
6737
|
maxEntriesPerRequest, params = self.handle_max_entries_per_request_and_params(method, maxEntriesPerRequest, params)
|
|
6431
6738
|
if (paginationDirection == 'forward'):
|
|
6432
6739
|
if since is None:
|
|
@@ -6666,6 +6973,15 @@ class Exchange(object):
|
|
|
6666
6973
|
values = list(uniqueResult.values())
|
|
6667
6974
|
return values
|
|
6668
6975
|
|
|
6976
|
+
def remove_keys_from_dict(self, dict: dict, removeKeys: List[str]):
|
|
6977
|
+
keys = list(dict.keys())
|
|
6978
|
+
newDict = {}
|
|
6979
|
+
for i in range(0, len(keys)):
|
|
6980
|
+
key = keys[i]
|
|
6981
|
+
if not self.in_array(key, removeKeys):
|
|
6982
|
+
newDict[key] = dict[key]
|
|
6983
|
+
return newDict
|
|
6984
|
+
|
|
6669
6985
|
def handle_until_option(self, key: str, request, params, multiplier=1):
|
|
6670
6986
|
until = self.safe_integer_2(params, 'until', 'till')
|
|
6671
6987
|
if until is not None:
|
|
@@ -6935,6 +7251,83 @@ class Exchange(object):
|
|
|
6935
7251
|
"""
|
|
6936
7252
|
raise NotSupported(self.id + ' fetchTransfers() is not supported yet')
|
|
6937
7253
|
|
|
7254
|
+
def un_watch_ohlcv(self, symbol: str, timeframe: str = '1m', params={}):
|
|
7255
|
+
"""
|
|
7256
|
+
watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
|
7257
|
+
:param str symbol: unified symbol of the market to fetch OHLCV data for
|
|
7258
|
+
:param str timeframe: the length of time each candle represents
|
|
7259
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
7260
|
+
:returns int[][]: A list of candles ordered, open, high, low, close, volume
|
|
7261
|
+
"""
|
|
7262
|
+
raise NotSupported(self.id + ' unWatchOHLCV() is not supported yet')
|
|
7263
|
+
|
|
7264
|
+
def watch_mark_price(self, symbol: str, params={}):
|
|
7265
|
+
"""
|
|
7266
|
+
watches a mark price for a specific market
|
|
7267
|
+
:param str symbol: unified symbol of the market to fetch the ticker for
|
|
7268
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
7269
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
7270
|
+
"""
|
|
7271
|
+
raise NotSupported(self.id + ' watchMarkPrice() is not supported yet')
|
|
7272
|
+
|
|
7273
|
+
def watch_mark_prices(self, symbols: Strings = None, params={}):
|
|
7274
|
+
"""
|
|
7275
|
+
watches the mark price for all markets
|
|
7276
|
+
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
|
7277
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
7278
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
7279
|
+
"""
|
|
7280
|
+
raise NotSupported(self.id + ' watchMarkPrices() is not supported yet')
|
|
7281
|
+
|
|
7282
|
+
def withdraw_ws(self, code: str, amount: float, address: str, tag: Str = None, params={}):
|
|
7283
|
+
"""
|
|
7284
|
+
make a withdrawal
|
|
7285
|
+
:param str code: unified currency code
|
|
7286
|
+
:param float amount: the amount to withdraw
|
|
7287
|
+
:param str address: the address to withdraw to
|
|
7288
|
+
:param str tag:
|
|
7289
|
+
:param dict [params]: extra parameters specific to the bitvavo api endpoint
|
|
7290
|
+
:returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
|
|
7291
|
+
"""
|
|
7292
|
+
raise NotSupported(self.id + ' withdrawWs() is not supported yet')
|
|
7293
|
+
|
|
7294
|
+
def un_watch_my_trades(self, symbol: Str = None, params={}):
|
|
7295
|
+
"""
|
|
7296
|
+
unWatches information on multiple trades made by the user
|
|
7297
|
+
:param str symbol: unified market symbol of the market orders were made in
|
|
7298
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
7299
|
+
:returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
|
7300
|
+
"""
|
|
7301
|
+
raise NotSupported(self.id + ' unWatchMyTrades() is not supported yet')
|
|
7302
|
+
|
|
7303
|
+
def create_orders_ws(self, orders: List[OrderRequest], params={}):
|
|
7304
|
+
"""
|
|
7305
|
+
create a list of trade orders
|
|
7306
|
+
:param Array orders: list of orders to create, each object should contain the parameters required by createOrder, namely symbol, type, side, amount, price and params
|
|
7307
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
7308
|
+
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
|
7309
|
+
"""
|
|
7310
|
+
raise NotSupported(self.id + ' createOrdersWs() is not supported yet')
|
|
7311
|
+
|
|
7312
|
+
def fetch_orders_by_status_ws(self, status: str, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
|
7313
|
+
"""
|
|
7314
|
+
watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
|
7315
|
+
:param str symbol: unified symbol of the market to fetch the order book for
|
|
7316
|
+
:param int [limit]: the maximum amount of order book entries to return
|
|
7317
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
7318
|
+
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
|
|
7319
|
+
"""
|
|
7320
|
+
raise NotSupported(self.id + ' fetchOrdersByStatusWs() is not supported yet')
|
|
7321
|
+
|
|
7322
|
+
def un_watch_bids_asks(self, symbols: Strings = None, params={}):
|
|
7323
|
+
"""
|
|
7324
|
+
unWatches best bid & ask for symbols
|
|
7325
|
+
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
|
7326
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
|
7327
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
|
7328
|
+
"""
|
|
7329
|
+
raise NotSupported(self.id + ' unWatchBidsAsks() is not supported yet')
|
|
7330
|
+
|
|
6938
7331
|
def clean_unsubscription(self, client, subHash: str, unsubHash: str, subHashIsPrefix=False):
|
|
6939
7332
|
if unsubHash in client.subscriptions:
|
|
6940
7333
|
del client.subscriptions[unsubHash]
|
|
@@ -6963,9 +7356,9 @@ class Exchange(object):
|
|
|
6963
7356
|
symbols = self.safe_list(subscription, 'symbols', [])
|
|
6964
7357
|
symbolsLength = len(symbols)
|
|
6965
7358
|
if topic == 'ohlcv':
|
|
6966
|
-
|
|
6967
|
-
for i in range(0, len(
|
|
6968
|
-
symbolAndTimeFrame =
|
|
7359
|
+
symbolsAndTimeframes = self.safe_list(subscription, 'symbolsAndTimeframes', [])
|
|
7360
|
+
for i in range(0, len(symbolsAndTimeframes)):
|
|
7361
|
+
symbolAndTimeFrame = symbolsAndTimeframes[i]
|
|
6969
7362
|
symbol = self.safe_string(symbolAndTimeFrame, 0)
|
|
6970
7363
|
timeframe = self.safe_string(symbolAndTimeFrame, 1)
|
|
6971
7364
|
if (self.ohlcvs is not None) and (symbol in self.ohlcvs):
|
|
@@ -6983,14 +7376,31 @@ class Exchange(object):
|
|
|
6983
7376
|
elif topic == 'ticker':
|
|
6984
7377
|
if symbol in self.tickers:
|
|
6985
7378
|
del self.tickers[symbol]
|
|
7379
|
+
elif topic == 'bidsasks':
|
|
7380
|
+
if symbol in self.bidsasks:
|
|
7381
|
+
del self.bidsasks[symbol]
|
|
6986
7382
|
else:
|
|
6987
7383
|
if topic == 'myTrades' and (self.myTrades is not None):
|
|
6988
7384
|
self.myTrades = None
|
|
6989
7385
|
elif topic == 'orders' and (self.orders is not None):
|
|
6990
7386
|
self.orders = None
|
|
7387
|
+
elif topic == 'positions' and (self.positions is not None):
|
|
7388
|
+
self.positions = None
|
|
7389
|
+
clients = list(self.clients.values())
|
|
7390
|
+
for i in range(0, len(clients)):
|
|
7391
|
+
client = clients[i]
|
|
7392
|
+
futures = client.futures
|
|
7393
|
+
if (futures is not None) and ('fetchPositionsSnapshot' in futures):
|
|
7394
|
+
del futures['fetchPositionsSnapshot']
|
|
6991
7395
|
elif topic == 'ticker' and (self.tickers is not None):
|
|
6992
7396
|
tickerSymbols = list(self.tickers.keys())
|
|
6993
7397
|
for i in range(0, len(tickerSymbols)):
|
|
6994
7398
|
tickerSymbol = tickerSymbols[i]
|
|
6995
7399
|
if tickerSymbol in self.tickers:
|
|
6996
7400
|
del self.tickers[tickerSymbol]
|
|
7401
|
+
elif topic == 'bidsasks' and (self.bidsasks is not None):
|
|
7402
|
+
bidsaskSymbols = list(self.bidsasks.keys())
|
|
7403
|
+
for i in range(0, len(bidsaskSymbols)):
|
|
7404
|
+
bidsaskSymbol = bidsaskSymbols[i]
|
|
7405
|
+
if bidsaskSymbol in self.bidsasks:
|
|
7406
|
+
del self.bidsasks[bidsaskSymbol]
|