ccxt 4.1.54__py2.py3-none-any.whl → 4.1.56__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.
Potentially problematic release.
This version of ccxt might be problematic. Click here for more details.
- ccxt/__init__.py +2 -2
- ccxt/abstract/binance.py +1 -0
- ccxt/abstract/binancecoinm.py +1 -0
- ccxt/abstract/binanceus.py +1 -0
- ccxt/abstract/binanceusdm.py +1 -0
- ccxt/abstract/bitbank.py +1 -0
- ccxt/abstract/coinbase.py +2 -0
- ccxt/abstract/htx.py +3 -0
- ccxt/abstract/huobi.py +3 -0
- ccxt/abstract/huobipro.py +3 -0
- ccxt/abstract/okex.py +3 -1
- ccxt/abstract/okex5.py +3 -1
- ccxt/abstract/okx.py +3 -1
- ccxt/ace.py +23 -23
- ccxt/alpaca.py +8 -8
- ccxt/ascendex.py +26 -26
- ccxt/async_support/__init__.py +2 -2
- ccxt/async_support/ace.py +23 -23
- ccxt/async_support/alpaca.py +8 -8
- ccxt/async_support/ascendex.py +26 -26
- ccxt/async_support/base/exchange.py +4 -2216
- ccxt/async_support/bigone.py +21 -24
- ccxt/async_support/binance.py +61 -54
- ccxt/async_support/bingx.py +28 -28
- ccxt/async_support/bit2c.py +9 -9
- ccxt/async_support/bitbank.py +11 -10
- ccxt/async_support/bitbns.py +11 -11
- ccxt/async_support/bitfinex.py +15 -15
- ccxt/async_support/bitfinex2.py +22 -22
- ccxt/async_support/bitflyer.py +13 -13
- ccxt/async_support/bitforex.py +10 -10
- ccxt/async_support/bitget.py +44 -44
- ccxt/async_support/bithumb.py +9 -9
- ccxt/async_support/bitmart.py +85 -104
- ccxt/async_support/bitmex.py +27 -27
- ccxt/async_support/bitopro.py +18 -18
- ccxt/async_support/bitpanda.py +18 -18
- ccxt/async_support/bitrue.py +14 -14
- ccxt/async_support/bitso.py +17 -17
- ccxt/async_support/bitstamp.py +17 -17
- ccxt/async_support/bittrex.py +22 -24
- ccxt/async_support/bitvavo.py +15 -15
- ccxt/async_support/bl3p.py +4 -4
- ccxt/async_support/blockchaincom.py +17 -17
- ccxt/async_support/btcalpha.py +14 -14
- ccxt/async_support/btcbox.py +9 -9
- ccxt/async_support/btcmarkets.py +17 -17
- ccxt/async_support/btcturk.py +9 -9
- ccxt/async_support/bybit.py +46 -46
- ccxt/async_support/cex.py +10 -10
- ccxt/async_support/coinbase.py +69 -25
- ccxt/async_support/coinbasepro.py +19 -19
- ccxt/async_support/coincheck.py +10 -10
- ccxt/async_support/coinex.py +57 -66
- ccxt/async_support/coinlist.py +22 -22
- ccxt/async_support/coinmate.py +10 -10
- ccxt/async_support/coinone.py +10 -10
- ccxt/async_support/coinsph.py +17 -17
- ccxt/async_support/coinspot.py +5 -5
- ccxt/async_support/cryptocom.py +27 -27
- ccxt/async_support/currencycom.py +18 -18
- ccxt/async_support/delta.py +21 -21
- ccxt/async_support/deribit.py +24 -24
- ccxt/async_support/digifinex.py +35 -35
- ccxt/async_support/exmo.py +19 -19
- ccxt/async_support/gate.py +38 -38
- ccxt/async_support/gemini.py +11 -11
- ccxt/async_support/hitbtc.py +27 -27
- ccxt/async_support/hollaex.py +19 -19
- ccxt/async_support/htx.py +47 -44
- ccxt/async_support/huobijp.py +22 -22
- ccxt/async_support/idex.py +20 -20
- ccxt/async_support/independentreserve.py +9 -9
- ccxt/async_support/indodax.py +10 -10
- ccxt/async_support/kraken.py +25 -25
- ccxt/async_support/krakenfutures.py +17 -17
- ccxt/async_support/kucoin.py +27 -27
- ccxt/async_support/kucoinfutures.py +20 -20
- ccxt/async_support/kuna.py +19 -19
- ccxt/async_support/latoken.py +14 -14
- ccxt/async_support/lbank.py +18 -18
- ccxt/async_support/luno.py +14 -14
- ccxt/async_support/lykke.py +12 -12
- ccxt/async_support/mercado.py +11 -11
- ccxt/async_support/mexc.py +36 -36
- ccxt/async_support/ndax.py +18 -18
- ccxt/async_support/novadax.py +17 -17
- ccxt/async_support/oceanex.py +12 -12
- ccxt/async_support/okcoin.py +19 -19
- ccxt/async_support/okx.py +48 -45
- ccxt/async_support/p2b.py +6 -6
- ccxt/async_support/paymium.py +6 -6
- ccxt/async_support/phemex.py +57 -57
- ccxt/async_support/poloniex.py +31 -30
- ccxt/async_support/poloniexfutures.py +16 -16
- ccxt/async_support/probit.py +22 -22
- ccxt/async_support/tidex.py +15 -15
- ccxt/async_support/timex.py +20 -20
- ccxt/async_support/tokocrypto.py +16 -16
- ccxt/async_support/upbit.py +15 -15
- ccxt/async_support/wavesexchange.py +12 -12
- ccxt/async_support/wazirx.py +13 -13
- ccxt/async_support/whitebit.py +26 -26
- ccxt/async_support/woo.py +47 -47
- ccxt/async_support/yobit.py +8 -8
- ccxt/async_support/zaif.py +10 -10
- ccxt/async_support/zonda.py +16 -16
- ccxt/base/errors.py +17 -16
- ccxt/base/exchange.py +57 -97
- ccxt/base/types.py +138 -139
- ccxt/bigone.py +21 -24
- ccxt/binance.py +61 -54
- ccxt/bingx.py +28 -28
- ccxt/bit2c.py +9 -9
- ccxt/bitbank.py +11 -10
- ccxt/bitbns.py +11 -11
- ccxt/bitfinex.py +15 -15
- ccxt/bitfinex2.py +22 -22
- ccxt/bitflyer.py +13 -13
- ccxt/bitforex.py +10 -10
- ccxt/bitget.py +44 -44
- ccxt/bithumb.py +9 -9
- ccxt/bitmart.py +85 -104
- ccxt/bitmex.py +27 -27
- ccxt/bitopro.py +18 -18
- ccxt/bitpanda.py +18 -18
- ccxt/bitrue.py +14 -14
- ccxt/bitso.py +17 -17
- ccxt/bitstamp.py +17 -17
- ccxt/bittrex.py +22 -24
- ccxt/bitvavo.py +15 -15
- ccxt/bl3p.py +4 -4
- ccxt/blockchaincom.py +17 -17
- ccxt/btcalpha.py +14 -14
- ccxt/btcbox.py +9 -9
- ccxt/btcmarkets.py +17 -17
- ccxt/btcturk.py +9 -9
- ccxt/bybit.py +46 -46
- ccxt/cex.py +10 -10
- ccxt/coinbase.py +69 -25
- ccxt/coinbasepro.py +19 -19
- ccxt/coincheck.py +10 -10
- ccxt/coinex.py +57 -66
- ccxt/coinlist.py +22 -22
- ccxt/coinmate.py +10 -10
- ccxt/coinone.py +10 -10
- ccxt/coinsph.py +17 -17
- ccxt/coinspot.py +5 -5
- ccxt/cryptocom.py +27 -27
- ccxt/currencycom.py +18 -18
- ccxt/delta.py +21 -21
- ccxt/deribit.py +24 -24
- ccxt/digifinex.py +35 -35
- ccxt/exmo.py +19 -19
- ccxt/gate.py +38 -38
- ccxt/gemini.py +11 -11
- ccxt/hitbtc.py +27 -27
- ccxt/hollaex.py +19 -19
- ccxt/htx.py +47 -44
- ccxt/huobijp.py +22 -22
- ccxt/idex.py +20 -20
- ccxt/independentreserve.py +9 -9
- ccxt/indodax.py +10 -10
- ccxt/kraken.py +25 -25
- ccxt/krakenfutures.py +17 -17
- ccxt/kucoin.py +27 -27
- ccxt/kucoinfutures.py +20 -20
- ccxt/kuna.py +19 -19
- ccxt/latoken.py +14 -14
- ccxt/lbank.py +18 -18
- ccxt/luno.py +14 -14
- ccxt/lykke.py +12 -12
- ccxt/mercado.py +11 -11
- ccxt/mexc.py +36 -36
- ccxt/ndax.py +18 -18
- ccxt/novadax.py +17 -17
- ccxt/oceanex.py +12 -12
- ccxt/okcoin.py +19 -19
- ccxt/okx.py +48 -45
- ccxt/p2b.py +6 -6
- ccxt/paymium.py +6 -6
- ccxt/phemex.py +57 -57
- ccxt/poloniex.py +31 -30
- ccxt/poloniexfutures.py +16 -16
- ccxt/pro/__init__.py +1 -1
- ccxt/pro/alpaca.py +3 -3
- ccxt/pro/ascendex.py +2 -2
- ccxt/pro/binance.py +9 -9
- ccxt/pro/bingx.py +3 -3
- ccxt/pro/bitfinex.py +3 -3
- ccxt/pro/bitfinex2.py +3 -3
- ccxt/pro/bitget.py +3 -3
- ccxt/pro/bitmart.py +2 -2
- ccxt/pro/bitmex.py +3 -3
- ccxt/pro/bitpanda.py +3 -3
- ccxt/pro/bitrue.py +2 -2
- ccxt/pro/bitstamp.py +2 -2
- ccxt/pro/bittrex.py +3 -3
- ccxt/pro/bitvavo.py +3 -3
- ccxt/pro/blockchaincom.py +2 -2
- ccxt/pro/bybit.py +4 -4
- ccxt/pro/cex.py +3 -3
- ccxt/pro/coinbasepro.py +3 -3
- ccxt/pro/coinex.py +2 -2
- ccxt/pro/cryptocom.py +5 -5
- ccxt/pro/deribit.py +3 -3
- ccxt/pro/exmo.py +2 -2
- ccxt/pro/gate.py +3 -3
- ccxt/pro/gemini.py +2 -2
- ccxt/pro/hitbtc.py +4 -4
- ccxt/pro/hollaex.py +3 -3
- ccxt/pro/htx.py +3 -3
- ccxt/pro/idex.py +3 -3
- ccxt/pro/kraken.py +7 -7
- ccxt/pro/krakenfutures.py +4 -4
- ccxt/pro/kucoin.py +3 -3
- ccxt/pro/kucoinfutures.py +3 -3
- ccxt/pro/mexc.py +3 -3
- ccxt/pro/okcoin.py +2 -2
- ccxt/pro/okx.py +6 -6
- ccxt/pro/phemex.py +3 -3
- ccxt/pro/poloniex.py +3 -3
- ccxt/pro/poloniexfutures.py +3 -3
- ccxt/pro/probit.py +3 -3
- ccxt/pro/wazirx.py +3 -3
- ccxt/pro/whitebit.py +3 -3
- ccxt/pro/woo.py +2 -2
- ccxt/probit.py +22 -22
- ccxt/test/base/test_shared_methods.py +3 -3
- ccxt/test/test_async.py +543 -535
- ccxt/test/test_sync.py +542 -534
- ccxt/tidex.py +15 -15
- ccxt/timex.py +20 -20
- ccxt/tokocrypto.py +16 -16
- ccxt/upbit.py +15 -15
- ccxt/wavesexchange.py +12 -12
- ccxt/wazirx.py +13 -13
- ccxt/whitebit.py +26 -26
- ccxt/woo.py +47 -47
- ccxt/yobit.py +8 -8
- ccxt/zaif.py +10 -10
- ccxt/zonda.py +16 -16
- {ccxt-4.1.54.dist-info → ccxt-4.1.56.dist-info}/METADATA +10 -8
- ccxt-4.1.56.dist-info/RECORD +449 -0
- ccxt/async_support/bitstamp1.py +0 -402
- ccxt/async_support/lbank2.py +0 -2620
- ccxt/bitstamp1.py +0 -402
- ccxt/lbank2.py +0 -2619
- ccxt-4.1.54.dist-info/RECORD +0 -453
- {ccxt-4.1.54.dist-info → ccxt-4.1.56.dist-info}/WHEEL +0 -0
- {ccxt-4.1.54.dist-info → ccxt-4.1.56.dist-info}/top_level.txt +0 -0
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
# -----------------------------------------------------------------------------
|
4
4
|
|
5
|
-
__version__ = '4.1.
|
5
|
+
__version__ = '4.1.56'
|
6
6
|
|
7
7
|
# -----------------------------------------------------------------------------
|
8
8
|
|
@@ -16,7 +16,7 @@ import sys
|
|
16
16
|
import yarl
|
17
17
|
import math
|
18
18
|
from typing import Any, List
|
19
|
-
from ccxt.base.types import Int
|
19
|
+
from ccxt.base.types import Int
|
20
20
|
|
21
21
|
# -----------------------------------------------------------------------------
|
22
22
|
|
@@ -24,14 +24,12 @@ from ccxt.async_support.base.throttler import Throttler
|
|
24
24
|
|
25
25
|
# -----------------------------------------------------------------------------
|
26
26
|
|
27
|
-
from ccxt.base.errors import BaseError, BadSymbol, BadRequest, BadResponse,
|
28
|
-
from ccxt.base.
|
29
|
-
from ccxt.base.types import OrderType, OrderSide, IndexType, Balance, Trade, OrderRequest
|
27
|
+
from ccxt.base.errors import BaseError, BadSymbol, BadRequest, BadResponse, ExchangeError, ExchangeNotAvailable, RequestTimeout, NotSupported, NullResponse, InvalidAddress, RateLimitExceeded
|
28
|
+
from ccxt.base.types import OrderType, OrderSide, OrderRequest
|
30
29
|
|
31
30
|
# -----------------------------------------------------------------------------
|
32
31
|
|
33
32
|
from ccxt.base.exchange import Exchange as BaseExchange, ArgumentsRequired
|
34
|
-
from ccxt.base.precise import Precise
|
35
33
|
|
36
34
|
# -----------------------------------------------------------------------------
|
37
35
|
|
@@ -502,151 +500,6 @@ class Exchange(BaseExchange):
|
|
502
500
|
|
503
501
|
# METHODS BELOW THIS LINE ARE TRANSPILED FROM JAVASCRIPT TO PYTHON AND PHP
|
504
502
|
|
505
|
-
def handle_deltas(self, orderbook, deltas):
|
506
|
-
for i in range(0, len(deltas)):
|
507
|
-
self.handle_delta(orderbook, deltas[i])
|
508
|
-
|
509
|
-
def handle_delta(self, bookside, delta):
|
510
|
-
raise NotSupported(self.id + ' handleDelta not supported yet')
|
511
|
-
|
512
|
-
def get_cache_index(self, orderbook, deltas):
|
513
|
-
# return the first index of the cache that can be applied to the orderbook or -1 if not possible
|
514
|
-
return -1
|
515
|
-
|
516
|
-
def find_timeframe(self, timeframe, timeframes=None):
|
517
|
-
if timeframes is None:
|
518
|
-
timeframes = self.timeframes
|
519
|
-
keys = list(timeframes.keys())
|
520
|
-
for i in range(0, len(keys)):
|
521
|
-
key = keys[i]
|
522
|
-
if timeframes[key] == timeframe:
|
523
|
-
return key
|
524
|
-
return None
|
525
|
-
|
526
|
-
def check_proxy_settings(self, url, method, headers, body):
|
527
|
-
proxyUrl = self.proxyUrl if (self.proxyUrl is not None) else self.proxy_url
|
528
|
-
proxyUrlCallback = self.proxyUrlCallback if (self.proxyUrlCallback is not None) else self.proxy_url_callback
|
529
|
-
if proxyUrlCallback is not None:
|
530
|
-
proxyUrl = proxyUrlCallback(url, method, headers, body)
|
531
|
-
# backwards-compatibility
|
532
|
-
if self.proxy is not None:
|
533
|
-
if callable(self.proxy):
|
534
|
-
proxyUrl = self.proxy(url, method, headers, body)
|
535
|
-
else:
|
536
|
-
proxyUrl = self.proxy
|
537
|
-
httpProxy = self.httpProxy if (self.httpProxy is not None) else self.http_proxy
|
538
|
-
httpProxyCallback = self.httpProxyCallback if (self.httpProxyCallback is not None) else self.http_proxy_callback
|
539
|
-
if httpProxyCallback is not None:
|
540
|
-
httpProxy = httpProxyCallback(url, method, headers, body)
|
541
|
-
httpsProxy = self.httpsProxy if (self.httpsProxy is not None) else self.https_proxy
|
542
|
-
httpsProxyCallback = self.httpsProxyCallback if (self.httpsProxyCallback is not None) else self.https_proxy_callback
|
543
|
-
if httpsProxyCallback is not None:
|
544
|
-
httpsProxy = httpsProxyCallback(url, method, headers, body)
|
545
|
-
socksProxy = self.socksProxy if (self.socksProxy is not None) else self.socks_proxy
|
546
|
-
socksProxyCallback = self.socksProxyCallback if (self.socksProxyCallback is not None) else self.socks_proxy_callback
|
547
|
-
if socksProxyCallback is not None:
|
548
|
-
socksProxy = socksProxyCallback(url, method, headers, body)
|
549
|
-
val = 0
|
550
|
-
if proxyUrl is not None:
|
551
|
-
val = val + 1
|
552
|
-
if proxyUrlCallback is not None:
|
553
|
-
val = val + 1
|
554
|
-
if httpProxy is not None:
|
555
|
-
val = val + 1
|
556
|
-
if httpProxyCallback is not None:
|
557
|
-
val = val + 1
|
558
|
-
if httpsProxy is not None:
|
559
|
-
val = val + 1
|
560
|
-
if httpsProxyCallback is not None:
|
561
|
-
val = val + 1
|
562
|
-
if socksProxy is not None:
|
563
|
-
val = val + 1
|
564
|
-
if socksProxyCallback is not None:
|
565
|
-
val = val + 1
|
566
|
-
if val > 1:
|
567
|
-
raise ExchangeError(self.id + ' you have multiple conflicting proxy settings, please use only one from : proxyUrl, httpProxy, httpsProxy, socksProxy, userAgent')
|
568
|
-
return [proxyUrl, httpProxy, httpsProxy, socksProxy]
|
569
|
-
|
570
|
-
def find_message_hashes(self, client, element: str):
|
571
|
-
result = []
|
572
|
-
messageHashes = list(client.futures.keys())
|
573
|
-
for i in range(0, len(messageHashes)):
|
574
|
-
messageHash = messageHashes[i]
|
575
|
-
if messageHash.find(element) >= 0:
|
576
|
-
result.append(messageHash)
|
577
|
-
return result
|
578
|
-
|
579
|
-
def filter_by_limit(self, array: List[object], limit: Int = None, key: IndexType = 'timestamp'):
|
580
|
-
if self.valueIsDefined(limit):
|
581
|
-
arrayLength = len(array)
|
582
|
-
if arrayLength > 0:
|
583
|
-
ascending = True
|
584
|
-
if (key in array[0]):
|
585
|
-
first = array[0][key]
|
586
|
-
last = array[arrayLength - 1][key]
|
587
|
-
if first is not None and last is not None:
|
588
|
-
ascending = first <= last # True if array is sorted in ascending order based on 'timestamp'
|
589
|
-
array = self.arraySlice(array, -limit) if ascending else self.arraySlice(array, 0, limit)
|
590
|
-
return array
|
591
|
-
|
592
|
-
def filter_by_since_limit(self, array: List[object], since: Int = None, limit: Int = None, key: IndexType = 'timestamp', tail=False):
|
593
|
-
sinceIsDefined = self.valueIsDefined(since)
|
594
|
-
parsedArray = self.to_array(array)
|
595
|
-
result = parsedArray
|
596
|
-
if sinceIsDefined:
|
597
|
-
result = []
|
598
|
-
for i in range(0, len(parsedArray)):
|
599
|
-
entry = parsedArray[i]
|
600
|
-
value = self.safe_value(entry, key)
|
601
|
-
if value and (value >= since):
|
602
|
-
result.append(entry)
|
603
|
-
if tail and limit is not None:
|
604
|
-
return self.arraySlice(result, -limit)
|
605
|
-
return self.filter_by_limit(result, limit, key)
|
606
|
-
|
607
|
-
def filter_by_value_since_limit(self, array: List[object], field: IndexType, value=None, since: Int = None, limit: Int = None, key='timestamp', tail=False):
|
608
|
-
valueIsDefined = self.valueIsDefined(value)
|
609
|
-
sinceIsDefined = self.valueIsDefined(since)
|
610
|
-
parsedArray = self.to_array(array)
|
611
|
-
result = parsedArray
|
612
|
-
# single-pass filter for both symbol and since
|
613
|
-
if valueIsDefined or sinceIsDefined:
|
614
|
-
result = []
|
615
|
-
for i in range(0, len(parsedArray)):
|
616
|
-
entry = parsedArray[i]
|
617
|
-
entryFiledEqualValue = entry[field] == value
|
618
|
-
firstCondition = entryFiledEqualValue if valueIsDefined else True
|
619
|
-
entryKeyValue = self.safe_value(entry, key)
|
620
|
-
entryKeyGESince = (entryKeyValue) and since and (entryKeyValue >= since)
|
621
|
-
secondCondition = entryKeyGESince if sinceIsDefined else True
|
622
|
-
if firstCondition and secondCondition:
|
623
|
-
result.append(entry)
|
624
|
-
if tail and limit is not None:
|
625
|
-
return self.arraySlice(result, -limit)
|
626
|
-
return self.filter_by_limit(result, limit, key)
|
627
|
-
|
628
|
-
def set_sandbox_mode(self, enabled):
|
629
|
-
if enabled:
|
630
|
-
if 'test' in self.urls:
|
631
|
-
if isinstance(self.urls['api'], str):
|
632
|
-
self.urls['apiBackup'] = self.urls['api']
|
633
|
-
self.urls['api'] = self.urls['test']
|
634
|
-
else:
|
635
|
-
self.urls['apiBackup'] = self.clone(self.urls['api'])
|
636
|
-
self.urls['api'] = self.clone(self.urls['test'])
|
637
|
-
else:
|
638
|
-
raise NotSupported(self.id + ' does not have a sandbox URL')
|
639
|
-
elif 'apiBackup' in self.urls:
|
640
|
-
if isinstance(self.urls['api'], str):
|
641
|
-
self.urls['api'] = self.urls['apiBackup']
|
642
|
-
else:
|
643
|
-
self.urls['api'] = self.clone(self.urls['apiBackup'])
|
644
|
-
newUrls = self.omit(self.urls, 'apiBackup')
|
645
|
-
self.urls = newUrls
|
646
|
-
|
647
|
-
def sign(self, path, api: Any = 'public', method='GET', params={}, headers: Any = None, body: Any = None):
|
648
|
-
return {}
|
649
|
-
|
650
503
|
async def fetch_accounts(self, params={}):
|
651
504
|
raise NotSupported(self.id + ' fetchAccounts() is not supported yet')
|
652
505
|
|
@@ -703,69 +556,12 @@ class Exchange(BaseExchange):
|
|
703
556
|
async def fetch_trading_limits(self, symbols: List[str] = None, params={}):
|
704
557
|
raise NotSupported(self.id + ' fetchTradingLimits() is not supported yet')
|
705
558
|
|
706
|
-
def parse_market(self, market):
|
707
|
-
raise NotSupported(self.id + ' parseMarket() is not supported yet')
|
708
|
-
|
709
|
-
def parse_markets(self, markets):
|
710
|
-
result = []
|
711
|
-
for i in range(0, len(markets)):
|
712
|
-
result.append(self.parseMarket(markets[i]))
|
713
|
-
return result
|
714
|
-
|
715
|
-
def parse_ticker(self, ticker: object, market=None):
|
716
|
-
raise NotSupported(self.id + ' parseTicker() is not supported yet')
|
717
|
-
|
718
|
-
def parse_deposit_address(self, depositAddress, currency=None):
|
719
|
-
raise NotSupported(self.id + ' parseDepositAddress() is not supported yet')
|
720
|
-
|
721
|
-
def parse_trade(self, trade: object, market=None):
|
722
|
-
raise NotSupported(self.id + ' parseTrade() is not supported yet')
|
723
|
-
|
724
|
-
def parse_transaction(self, transaction, currency=None):
|
725
|
-
raise NotSupported(self.id + ' parseTransaction() is not supported yet')
|
726
|
-
|
727
|
-
def parse_transfer(self, transfer, currency=None):
|
728
|
-
raise NotSupported(self.id + ' parseTransfer() is not supported yet')
|
729
|
-
|
730
|
-
def parse_account(self, account):
|
731
|
-
raise NotSupported(self.id + ' parseAccount() is not supported yet')
|
732
|
-
|
733
|
-
def parse_ledger_entry(self, item, currency=None):
|
734
|
-
raise NotSupported(self.id + ' parseLedgerEntry() is not supported yet')
|
735
|
-
|
736
|
-
def parse_order(self, order, market=None):
|
737
|
-
raise NotSupported(self.id + ' parseOrder() is not supported yet')
|
738
|
-
|
739
559
|
async def fetch_borrow_rates(self, params={}):
|
740
560
|
raise NotSupported(self.id + ' fetchBorrowRates() is not supported yet')
|
741
561
|
|
742
|
-
def parse_market_leverage_tiers(self, info, market=None):
|
743
|
-
raise NotSupported(self.id + ' parseMarketLeverageTiers() is not supported yet')
|
744
|
-
|
745
562
|
async def fetch_leverage_tiers(self, symbols: List[str] = None, params={}):
|
746
563
|
raise NotSupported(self.id + ' fetchLeverageTiers() is not supported yet')
|
747
564
|
|
748
|
-
def parse_position(self, position, market=None):
|
749
|
-
raise NotSupported(self.id + ' parsePosition() is not supported yet')
|
750
|
-
|
751
|
-
def parse_funding_rate_history(self, info, market=None):
|
752
|
-
raise NotSupported(self.id + ' parseFundingRateHistory() is not supported yet')
|
753
|
-
|
754
|
-
def parse_borrow_interest(self, info, market=None):
|
755
|
-
raise NotSupported(self.id + ' parseBorrowInterest() is not supported yet')
|
756
|
-
|
757
|
-
def parse_ws_trade(self, trade, market=None):
|
758
|
-
raise NotSupported(self.id + ' parseWsTrade() is not supported yet')
|
759
|
-
|
760
|
-
def parse_ws_order(self, order, market=None):
|
761
|
-
raise NotSupported(self.id + ' parseWsOrder() is not supported yet')
|
762
|
-
|
763
|
-
def parse_ws_order_trade(self, trade, market=None):
|
764
|
-
raise NotSupported(self.id + ' parseWsOrderTrade() is not supported yet')
|
765
|
-
|
766
|
-
def parse_ws_ohlcv(self, ohlcv, market=None):
|
767
|
-
return self.parse_ohlcv(ohlcv, market)
|
768
|
-
|
769
565
|
async def fetch_funding_rates(self, symbols: List[str] = None, params={}):
|
770
566
|
raise NotSupported(self.id + ' fetchFundingRates() is not supported yet')
|
771
567
|
|
@@ -781,771 +577,6 @@ class Exchange(BaseExchange):
|
|
781
577
|
async def set_leverage(self, leverage, symbol: str = None, params={}):
|
782
578
|
raise NotSupported(self.id + ' setLeverage() is not supported yet')
|
783
579
|
|
784
|
-
def parse_to_int(self, number):
|
785
|
-
# Solve Common intmisuse ex: int((since / str(1000)))
|
786
|
-
# using a number which is not valid in ts
|
787
|
-
stringifiedNumber = str(number)
|
788
|
-
convertedNumber = float(stringifiedNumber)
|
789
|
-
return int(convertedNumber)
|
790
|
-
|
791
|
-
def parse_to_numeric(self, number):
|
792
|
-
stringVersion = self.number_to_string(number) # self will convert 1.0 and 1 to "1" and 1.1 to "1.1"
|
793
|
-
# keep self in mind:
|
794
|
-
# in JS: 1 == 1.0 is True
|
795
|
-
# in Python: 1 == 1.0 is True
|
796
|
-
# in PHP 1 == 1.0 is False
|
797
|
-
if stringVersion.find('.') > 0:
|
798
|
-
return float(stringVersion)
|
799
|
-
return int(stringVersion)
|
800
|
-
|
801
|
-
def after_construct(self):
|
802
|
-
self.create_networks_by_id_object()
|
803
|
-
|
804
|
-
def create_networks_by_id_object(self):
|
805
|
-
# automatically generate network-id-to-code mappings
|
806
|
-
networkIdsToCodesGenerated = self.invert_flat_string_dictionary(self.safe_value(self.options, 'networks', {})) # invert defined networks dictionary
|
807
|
-
self.options['networksById'] = self.extend(networkIdsToCodesGenerated, self.safe_value(self.options, 'networksById', {})) # support manually overriden "networksById" dictionary too
|
808
|
-
|
809
|
-
def get_default_options(self):
|
810
|
-
return {
|
811
|
-
'defaultNetworkCodeReplacements': {
|
812
|
-
'ETH': {'ERC20': 'ETH'},
|
813
|
-
'TRX': {'TRC20': 'TRX'},
|
814
|
-
'CRO': {'CRC20': 'CRONOS'},
|
815
|
-
},
|
816
|
-
}
|
817
|
-
|
818
|
-
def safe_ledger_entry(self, entry: object, currency: Currency = None):
|
819
|
-
currency = self.safe_currency(None, currency)
|
820
|
-
direction = self.safe_string(entry, 'direction')
|
821
|
-
before = self.safe_string(entry, 'before')
|
822
|
-
after = self.safe_string(entry, 'after')
|
823
|
-
amount = self.safe_string(entry, 'amount')
|
824
|
-
if amount is not None:
|
825
|
-
if before is None and after is not None:
|
826
|
-
before = Precise.string_sub(after, amount)
|
827
|
-
elif before is not None and after is None:
|
828
|
-
after = Precise.string_add(before, amount)
|
829
|
-
if before is not None and after is not None:
|
830
|
-
if direction is None:
|
831
|
-
if Precise.string_gt(before, after):
|
832
|
-
direction = 'out'
|
833
|
-
if Precise.string_gt(after, before):
|
834
|
-
direction = 'in'
|
835
|
-
fee = self.safe_value(entry, 'fee')
|
836
|
-
if fee is not None:
|
837
|
-
fee['cost'] = self.safe_number(fee, 'cost')
|
838
|
-
timestamp = self.safe_integer(entry, 'timestamp')
|
839
|
-
return {
|
840
|
-
'id': self.safe_string(entry, 'id'),
|
841
|
-
'timestamp': timestamp,
|
842
|
-
'datetime': self.iso8601(timestamp),
|
843
|
-
'direction': direction,
|
844
|
-
'account': self.safe_string(entry, 'account'),
|
845
|
-
'referenceId': self.safe_string(entry, 'referenceId'),
|
846
|
-
'referenceAccount': self.safe_string(entry, 'referenceAccount'),
|
847
|
-
'type': self.safe_string(entry, 'type'),
|
848
|
-
'currency': currency['code'],
|
849
|
-
'amount': self.parse_number(amount),
|
850
|
-
'before': self.parse_number(before),
|
851
|
-
'after': self.parse_number(after),
|
852
|
-
'status': self.safe_string(entry, 'status'),
|
853
|
-
'fee': fee,
|
854
|
-
'info': entry,
|
855
|
-
}
|
856
|
-
|
857
|
-
def safe_currency_structure(self, currency: object):
|
858
|
-
return self.extend({
|
859
|
-
'info': None,
|
860
|
-
'id': None,
|
861
|
-
'numericId': None,
|
862
|
-
'code': None,
|
863
|
-
'precision': None,
|
864
|
-
'type': None,
|
865
|
-
'name': None,
|
866
|
-
'active': None,
|
867
|
-
'deposit': None,
|
868
|
-
'withdraw': None,
|
869
|
-
'fee': None,
|
870
|
-
'fees': {},
|
871
|
-
'networks': {},
|
872
|
-
'limits': {
|
873
|
-
'deposit': {
|
874
|
-
'min': None,
|
875
|
-
'max': None,
|
876
|
-
},
|
877
|
-
'withdraw': {
|
878
|
-
'min': None,
|
879
|
-
'max': None,
|
880
|
-
},
|
881
|
-
},
|
882
|
-
}, currency)
|
883
|
-
|
884
|
-
def safe_market_structure(self, market: object = None):
|
885
|
-
cleanStructure = {
|
886
|
-
'id': None,
|
887
|
-
'lowercaseId': None,
|
888
|
-
'symbol': None,
|
889
|
-
'base': None,
|
890
|
-
'quote': None,
|
891
|
-
'settle': None,
|
892
|
-
'baseId': None,
|
893
|
-
'quoteId': None,
|
894
|
-
'settleId': None,
|
895
|
-
'type': None,
|
896
|
-
'spot': None,
|
897
|
-
'margin': None,
|
898
|
-
'swap': None,
|
899
|
-
'future': None,
|
900
|
-
'option': None,
|
901
|
-
'index': None,
|
902
|
-
'active': None,
|
903
|
-
'contract': None,
|
904
|
-
'linear': None,
|
905
|
-
'inverse': None,
|
906
|
-
'taker': None,
|
907
|
-
'maker': None,
|
908
|
-
'contractSize': None,
|
909
|
-
'expiry': None,
|
910
|
-
'expiryDatetime': None,
|
911
|
-
'strike': None,
|
912
|
-
'optionType': None,
|
913
|
-
'precision': {
|
914
|
-
'amount': None,
|
915
|
-
'price': None,
|
916
|
-
'cost': None,
|
917
|
-
'base': None,
|
918
|
-
'quote': None,
|
919
|
-
},
|
920
|
-
'limits': {
|
921
|
-
'leverage': {
|
922
|
-
'min': None,
|
923
|
-
'max': None,
|
924
|
-
},
|
925
|
-
'amount': {
|
926
|
-
'min': None,
|
927
|
-
'max': None,
|
928
|
-
},
|
929
|
-
'price': {
|
930
|
-
'min': None,
|
931
|
-
'max': None,
|
932
|
-
},
|
933
|
-
'cost': {
|
934
|
-
'min': None,
|
935
|
-
'max': None,
|
936
|
-
},
|
937
|
-
},
|
938
|
-
'created': None,
|
939
|
-
'info': None,
|
940
|
-
}
|
941
|
-
if market is not None:
|
942
|
-
result = self.extend(cleanStructure, market)
|
943
|
-
# set None swap/future/etc
|
944
|
-
if result['spot']:
|
945
|
-
if result['contract'] is None:
|
946
|
-
result['contract'] = False
|
947
|
-
if result['swap'] is None:
|
948
|
-
result['swap'] = False
|
949
|
-
if result['future'] is None:
|
950
|
-
result['future'] = False
|
951
|
-
if result['option'] is None:
|
952
|
-
result['option'] = False
|
953
|
-
if result['index'] is None:
|
954
|
-
result['index'] = False
|
955
|
-
return result
|
956
|
-
return cleanStructure
|
957
|
-
|
958
|
-
def set_markets(self, markets, currencies=None):
|
959
|
-
values = []
|
960
|
-
self.markets_by_id = {}
|
961
|
-
# handle marketId conflicts
|
962
|
-
# we insert spot markets first
|
963
|
-
marketValues = self.sort_by(self.to_array(markets), 'spot', True, True)
|
964
|
-
for i in range(0, len(marketValues)):
|
965
|
-
value = marketValues[i]
|
966
|
-
if value['id'] in self.markets_by_id:
|
967
|
-
(self.markets_by_id[value['id']]).append(value)
|
968
|
-
else:
|
969
|
-
self.markets_by_id[value['id']] = [value]
|
970
|
-
market = self.deep_extend(self.safe_market_structure(), {
|
971
|
-
'precision': self.precision,
|
972
|
-
'limits': self.limits,
|
973
|
-
}, self.fees['trading'], value)
|
974
|
-
values.append(market)
|
975
|
-
self.markets = self.index_by(values, 'symbol')
|
976
|
-
marketsSortedBySymbol = self.keysort(self.markets)
|
977
|
-
marketsSortedById = self.keysort(self.markets_by_id)
|
978
|
-
self.symbols = list(marketsSortedBySymbol.keys())
|
979
|
-
self.ids = list(marketsSortedById.keys())
|
980
|
-
if currencies is not None:
|
981
|
-
# currencies is always None when called in constructor but not when called from loadMarkets
|
982
|
-
self.currencies = self.deep_extend(self.currencies, currencies)
|
983
|
-
else:
|
984
|
-
baseCurrencies = []
|
985
|
-
quoteCurrencies = []
|
986
|
-
for i in range(0, len(values)):
|
987
|
-
market = values[i]
|
988
|
-
defaultCurrencyPrecision = 8 if (self.precisionMode == DECIMAL_PLACES) else self.parse_number('1e-8')
|
989
|
-
marketPrecision = self.safe_value(market, 'precision', {})
|
990
|
-
if 'base' in market:
|
991
|
-
currency = self.safe_currency_structure({
|
992
|
-
'id': self.safe_string_2(market, 'baseId', 'base'),
|
993
|
-
'numericId': self.safe_integer(market, 'baseNumericId'),
|
994
|
-
'code': self.safe_string(market, 'base'),
|
995
|
-
'precision': self.safe_value_2(marketPrecision, 'base', 'amount', defaultCurrencyPrecision),
|
996
|
-
})
|
997
|
-
baseCurrencies.append(currency)
|
998
|
-
if 'quote' in market:
|
999
|
-
currency = self.safe_currency_structure({
|
1000
|
-
'id': self.safe_string_2(market, 'quoteId', 'quote'),
|
1001
|
-
'numericId': self.safe_integer(market, 'quoteNumericId'),
|
1002
|
-
'code': self.safe_string(market, 'quote'),
|
1003
|
-
'precision': self.safe_value_2(marketPrecision, 'quote', 'price', defaultCurrencyPrecision),
|
1004
|
-
})
|
1005
|
-
quoteCurrencies.append(currency)
|
1006
|
-
baseCurrencies = self.sort_by(baseCurrencies, 'code', False, '')
|
1007
|
-
quoteCurrencies = self.sort_by(quoteCurrencies, 'code', False, '')
|
1008
|
-
self.baseCurrencies = self.index_by(baseCurrencies, 'code')
|
1009
|
-
self.quoteCurrencies = self.index_by(quoteCurrencies, 'code')
|
1010
|
-
allCurrencies = self.array_concat(baseCurrencies, quoteCurrencies)
|
1011
|
-
groupedCurrencies = self.group_by(allCurrencies, 'code')
|
1012
|
-
codes = list(groupedCurrencies.keys())
|
1013
|
-
resultingCurrencies = []
|
1014
|
-
for i in range(0, len(codes)):
|
1015
|
-
code = codes[i]
|
1016
|
-
groupedCurrenciesCode = self.safe_value(groupedCurrencies, code, [])
|
1017
|
-
highestPrecisionCurrency = self.safe_value(groupedCurrenciesCode, 0)
|
1018
|
-
for j in range(1, len(groupedCurrenciesCode)):
|
1019
|
-
currentCurrency = groupedCurrenciesCode[j]
|
1020
|
-
if self.precisionMode == TICK_SIZE:
|
1021
|
-
highestPrecisionCurrency = currentCurrency if (currentCurrency['precision'] < highestPrecisionCurrency['precision']) else highestPrecisionCurrency
|
1022
|
-
else:
|
1023
|
-
highestPrecisionCurrency = currentCurrency if (currentCurrency['precision'] > highestPrecisionCurrency['precision']) else highestPrecisionCurrency
|
1024
|
-
resultingCurrencies.append(highestPrecisionCurrency)
|
1025
|
-
sortedCurrencies = self.sort_by(resultingCurrencies, 'code')
|
1026
|
-
self.currencies = self.deep_extend(self.currencies, self.index_by(sortedCurrencies, 'code'))
|
1027
|
-
self.currencies_by_id = self.index_by(self.currencies, 'id')
|
1028
|
-
currenciesSortedByCode = self.keysort(self.currencies)
|
1029
|
-
self.codes = list(currenciesSortedByCode.keys())
|
1030
|
-
return self.markets
|
1031
|
-
|
1032
|
-
def safe_balance(self, balance: object):
|
1033
|
-
balances = self.omit(balance, ['info', 'timestamp', 'datetime', 'free', 'used', 'total'])
|
1034
|
-
codes = list(balances.keys())
|
1035
|
-
balance['free'] = {}
|
1036
|
-
balance['used'] = {}
|
1037
|
-
balance['total'] = {}
|
1038
|
-
debtBalance = {}
|
1039
|
-
for i in range(0, len(codes)):
|
1040
|
-
code = codes[i]
|
1041
|
-
total = self.safe_string(balance[code], 'total')
|
1042
|
-
free = self.safe_string(balance[code], 'free')
|
1043
|
-
used = self.safe_string(balance[code], 'used')
|
1044
|
-
debt = self.safe_string(balance[code], 'debt')
|
1045
|
-
if (total is None) and (free is not None) and (used is not None):
|
1046
|
-
total = Precise.string_add(free, used)
|
1047
|
-
if (free is None) and (total is not None) and (used is not None):
|
1048
|
-
free = Precise.string_sub(total, used)
|
1049
|
-
if (used is None) and (total is not None) and (free is not None):
|
1050
|
-
used = Precise.string_sub(total, free)
|
1051
|
-
balance[code]['free'] = self.parse_number(free)
|
1052
|
-
balance[code]['used'] = self.parse_number(used)
|
1053
|
-
balance[code]['total'] = self.parse_number(total)
|
1054
|
-
balance['free'][code] = balance[code]['free']
|
1055
|
-
balance['used'][code] = balance[code]['used']
|
1056
|
-
balance['total'][code] = balance[code]['total']
|
1057
|
-
if debt is not None:
|
1058
|
-
balance[code]['debt'] = self.parse_number(debt)
|
1059
|
-
debtBalance[code] = balance[code]['debt']
|
1060
|
-
debtBalanceArray = list(debtBalance.keys())
|
1061
|
-
length = len(debtBalanceArray)
|
1062
|
-
if length:
|
1063
|
-
balance['debt'] = debtBalance
|
1064
|
-
return balance
|
1065
|
-
|
1066
|
-
def safe_order(self, order: object, market: object = None):
|
1067
|
-
# parses numbers
|
1068
|
-
# * it is important pass the trades rawTrades
|
1069
|
-
amount = self.omit_zero(self.safe_string(order, 'amount'))
|
1070
|
-
remaining = self.safe_string(order, 'remaining')
|
1071
|
-
filled = self.safe_string(order, 'filled')
|
1072
|
-
cost = self.safe_string(order, 'cost')
|
1073
|
-
average = self.omit_zero(self.safe_string(order, 'average'))
|
1074
|
-
price = self.omit_zero(self.safe_string(order, 'price'))
|
1075
|
-
lastTradeTimeTimestamp = self.safe_integer(order, 'lastTradeTimestamp')
|
1076
|
-
symbol = self.safe_string(order, 'symbol')
|
1077
|
-
side = self.safe_string(order, 'side')
|
1078
|
-
status = self.safe_string(order, 'status')
|
1079
|
-
parseFilled = (filled is None)
|
1080
|
-
parseCost = (cost is None)
|
1081
|
-
parseLastTradeTimeTimestamp = (lastTradeTimeTimestamp is None)
|
1082
|
-
fee = self.safe_value(order, 'fee')
|
1083
|
-
parseFee = (fee is None)
|
1084
|
-
parseFees = self.safe_value(order, 'fees') is None
|
1085
|
-
parseSymbol = symbol is None
|
1086
|
-
parseSide = side is None
|
1087
|
-
shouldParseFees = parseFee or parseFees
|
1088
|
-
fees = self.safe_value(order, 'fees', [])
|
1089
|
-
trades = []
|
1090
|
-
if parseFilled or parseCost or shouldParseFees:
|
1091
|
-
rawTrades = self.safe_value(order, 'trades', trades)
|
1092
|
-
oldNumber = self.number
|
1093
|
-
# we parse trades here!
|
1094
|
-
self.number = str
|
1095
|
-
firstTrade = self.safe_value(rawTrades, 0)
|
1096
|
-
# parse trades if they haven't already been parsed
|
1097
|
-
tradesAreParsed = ((firstTrade is not None) and ('info' in firstTrade) and ('id' in firstTrade))
|
1098
|
-
if not tradesAreParsed:
|
1099
|
-
trades = self.parse_trades(rawTrades, market)
|
1100
|
-
else:
|
1101
|
-
trades = rawTrades
|
1102
|
-
self.number = oldNumber
|
1103
|
-
tradesLength = 0
|
1104
|
-
isArray = isinstance(trades, list)
|
1105
|
-
if isArray:
|
1106
|
-
tradesLength = len(trades)
|
1107
|
-
if isArray and (tradesLength > 0):
|
1108
|
-
# move properties that are defined in trades up into the order
|
1109
|
-
if order['symbol'] is None:
|
1110
|
-
order['symbol'] = trades[0]['symbol']
|
1111
|
-
if order['side'] is None:
|
1112
|
-
order['side'] = trades[0]['side']
|
1113
|
-
if order['type'] is None:
|
1114
|
-
order['type'] = trades[0]['type']
|
1115
|
-
if order['id'] is None:
|
1116
|
-
order['id'] = trades[0]['order']
|
1117
|
-
if parseFilled:
|
1118
|
-
filled = '0'
|
1119
|
-
if parseCost:
|
1120
|
-
cost = '0'
|
1121
|
-
for i in range(0, len(trades)):
|
1122
|
-
trade = trades[i]
|
1123
|
-
tradeAmount = self.safe_string(trade, 'amount')
|
1124
|
-
if parseFilled and (tradeAmount is not None):
|
1125
|
-
filled = Precise.string_add(filled, tradeAmount)
|
1126
|
-
tradeCost = self.safe_string(trade, 'cost')
|
1127
|
-
if parseCost and (tradeCost is not None):
|
1128
|
-
cost = Precise.string_add(cost, tradeCost)
|
1129
|
-
if parseSymbol:
|
1130
|
-
symbol = self.safe_string(trade, 'symbol')
|
1131
|
-
if parseSide:
|
1132
|
-
side = self.safe_string(trade, 'side')
|
1133
|
-
tradeTimestamp = self.safe_value(trade, 'timestamp')
|
1134
|
-
if parseLastTradeTimeTimestamp and (tradeTimestamp is not None):
|
1135
|
-
if lastTradeTimeTimestamp is None:
|
1136
|
-
lastTradeTimeTimestamp = tradeTimestamp
|
1137
|
-
else:
|
1138
|
-
lastTradeTimeTimestamp = max(lastTradeTimeTimestamp, tradeTimestamp)
|
1139
|
-
if shouldParseFees:
|
1140
|
-
tradeFees = self.safe_value(trade, 'fees')
|
1141
|
-
if tradeFees is not None:
|
1142
|
-
for j in range(0, len(tradeFees)):
|
1143
|
-
tradeFee = tradeFees[j]
|
1144
|
-
fees.append(self.extend({}, tradeFee))
|
1145
|
-
else:
|
1146
|
-
tradeFee = self.safe_value(trade, 'fee')
|
1147
|
-
if tradeFee is not None:
|
1148
|
-
fees.append(self.extend({}, tradeFee))
|
1149
|
-
if shouldParseFees:
|
1150
|
-
reducedFees = self.reduce_fees_by_currency(fees) if self.reduceFees else fees
|
1151
|
-
reducedLength = len(reducedFees)
|
1152
|
-
for i in range(0, reducedLength):
|
1153
|
-
reducedFees[i]['cost'] = self.safe_number(reducedFees[i], 'cost')
|
1154
|
-
if 'rate' in reducedFees[i]:
|
1155
|
-
reducedFees[i]['rate'] = self.safe_number(reducedFees[i], 'rate')
|
1156
|
-
if not parseFee and (reducedLength == 0):
|
1157
|
-
fee['cost'] = self.safe_number(fee, 'cost')
|
1158
|
-
if 'rate' in fee:
|
1159
|
-
fee['rate'] = self.safe_number(fee, 'rate')
|
1160
|
-
reducedFees.append(fee)
|
1161
|
-
order['fees'] = reducedFees
|
1162
|
-
if parseFee and (reducedLength == 1):
|
1163
|
-
order['fee'] = reducedFees[0]
|
1164
|
-
if amount is None:
|
1165
|
-
# ensure amount = filled + remaining
|
1166
|
-
if filled is not None and remaining is not None:
|
1167
|
-
amount = Precise.string_add(filled, remaining)
|
1168
|
-
elif status == 'closed':
|
1169
|
-
amount = filled
|
1170
|
-
if filled is None:
|
1171
|
-
if amount is not None and remaining is not None:
|
1172
|
-
filled = Precise.string_sub(amount, remaining)
|
1173
|
-
elif status == 'closed' and amount is not None:
|
1174
|
-
filled = amount
|
1175
|
-
if remaining is None:
|
1176
|
-
if amount is not None and filled is not None:
|
1177
|
-
remaining = Precise.string_sub(amount, filled)
|
1178
|
-
elif status == 'closed':
|
1179
|
-
remaining = '0'
|
1180
|
-
# ensure that the average field is calculated correctly
|
1181
|
-
inverse = self.safe_value(market, 'inverse', False)
|
1182
|
-
contractSize = self.number_to_string(self.safe_value(market, 'contractSize', 1))
|
1183
|
-
# inverse
|
1184
|
-
# price = filled * contract size / cost
|
1185
|
-
#
|
1186
|
-
# linear
|
1187
|
-
# price = cost / (filled * contract size)
|
1188
|
-
if average is None:
|
1189
|
-
if (filled is not None) and (cost is not None) and Precise.string_gt(filled, '0'):
|
1190
|
-
filledTimesContractSize = Precise.string_mul(filled, contractSize)
|
1191
|
-
if inverse:
|
1192
|
-
average = Precise.string_div(filledTimesContractSize, cost)
|
1193
|
-
else:
|
1194
|
-
average = Precise.string_div(cost, filledTimesContractSize)
|
1195
|
-
# similarly
|
1196
|
-
# inverse
|
1197
|
-
# cost = filled * contract size / price
|
1198
|
-
#
|
1199
|
-
# linear
|
1200
|
-
# cost = filled * contract size * price
|
1201
|
-
costPriceExists = (average is not None) or (price is not None)
|
1202
|
-
if parseCost and (filled is not None) and costPriceExists:
|
1203
|
-
multiplyPrice = None
|
1204
|
-
if average is None:
|
1205
|
-
multiplyPrice = price
|
1206
|
-
else:
|
1207
|
-
multiplyPrice = average
|
1208
|
-
# contract trading
|
1209
|
-
filledTimesContractSize = Precise.string_mul(filled, contractSize)
|
1210
|
-
if inverse:
|
1211
|
-
cost = Precise.string_div(filledTimesContractSize, multiplyPrice)
|
1212
|
-
else:
|
1213
|
-
cost = Precise.string_mul(filledTimesContractSize, multiplyPrice)
|
1214
|
-
# support for market orders
|
1215
|
-
orderType = self.safe_value(order, 'type')
|
1216
|
-
emptyPrice = (price is None) or Precise.string_equals(price, '0')
|
1217
|
-
if emptyPrice and (orderType == 'market'):
|
1218
|
-
price = average
|
1219
|
-
# we have trades with string values at self point so we will mutate them
|
1220
|
-
for i in range(0, len(trades)):
|
1221
|
-
entry = trades[i]
|
1222
|
-
entry['amount'] = self.safe_number(entry, 'amount')
|
1223
|
-
entry['price'] = self.safe_number(entry, 'price')
|
1224
|
-
entry['cost'] = self.safe_number(entry, 'cost')
|
1225
|
-
tradeFee = self.safe_value(entry, 'fee', {})
|
1226
|
-
tradeFee['cost'] = self.safe_number(tradeFee, 'cost')
|
1227
|
-
if 'rate' in tradeFee:
|
1228
|
-
tradeFee['rate'] = self.safe_number(tradeFee, 'rate')
|
1229
|
-
entry['fee'] = tradeFee
|
1230
|
-
timeInForce = self.safe_string(order, 'timeInForce')
|
1231
|
-
postOnly = self.safe_value(order, 'postOnly')
|
1232
|
-
# timeInForceHandling
|
1233
|
-
if timeInForce is None:
|
1234
|
-
if self.safe_string(order, 'type') == 'market':
|
1235
|
-
timeInForce = 'IOC'
|
1236
|
-
# allow postOnly override
|
1237
|
-
if postOnly:
|
1238
|
-
timeInForce = 'PO'
|
1239
|
-
elif postOnly is None:
|
1240
|
-
# timeInForce is not None here
|
1241
|
-
postOnly = timeInForce == 'PO'
|
1242
|
-
timestamp = self.safe_integer(order, 'timestamp')
|
1243
|
-
lastUpdateTimestamp = self.safe_integer(order, 'lastUpdateTimestamp')
|
1244
|
-
datetime = self.safe_string(order, 'datetime')
|
1245
|
-
if datetime is None:
|
1246
|
-
datetime = self.iso8601(timestamp)
|
1247
|
-
triggerPrice = self.parse_number(self.safe_string_2(order, 'triggerPrice', 'stopPrice'))
|
1248
|
-
takeProfitPrice = self.parse_number(self.safe_string(order, 'takeProfitPrice'))
|
1249
|
-
stopLossPrice = self.parse_number(self.safe_string(order, 'stopLossPrice'))
|
1250
|
-
return self.extend(order, {
|
1251
|
-
'id': self.safe_string(order, 'id'),
|
1252
|
-
'clientOrderId': self.safe_string(order, 'clientOrderId'),
|
1253
|
-
'timestamp': timestamp,
|
1254
|
-
'datetime': datetime,
|
1255
|
-
'symbol': symbol,
|
1256
|
-
'type': self.safe_string(order, 'type'),
|
1257
|
-
'side': side,
|
1258
|
-
'lastTradeTimestamp': lastTradeTimeTimestamp,
|
1259
|
-
'lastUpdateTimestamp': lastUpdateTimestamp,
|
1260
|
-
'price': self.parse_number(price),
|
1261
|
-
'amount': self.parse_number(amount),
|
1262
|
-
'cost': self.parse_number(cost),
|
1263
|
-
'average': self.parse_number(average),
|
1264
|
-
'filled': self.parse_number(filled),
|
1265
|
-
'remaining': self.parse_number(remaining),
|
1266
|
-
'timeInForce': timeInForce,
|
1267
|
-
'postOnly': postOnly,
|
1268
|
-
'trades': trades,
|
1269
|
-
'reduceOnly': self.safe_value(order, 'reduceOnly'),
|
1270
|
-
'stopPrice': triggerPrice, # ! deprecated, use triggerPrice instead
|
1271
|
-
'triggerPrice': triggerPrice,
|
1272
|
-
'takeProfitPrice': takeProfitPrice,
|
1273
|
-
'stopLossPrice': stopLossPrice,
|
1274
|
-
'status': status,
|
1275
|
-
'fee': self.safe_value(order, 'fee'),
|
1276
|
-
})
|
1277
|
-
|
1278
|
-
def parse_orders(self, orders: object, market: object = None, since: Int = None, limit: Int = None, params={}):
|
1279
|
-
#
|
1280
|
-
# the value of orders is either a dict or a list
|
1281
|
-
#
|
1282
|
-
# dict
|
1283
|
-
#
|
1284
|
-
# {
|
1285
|
-
# 'id1': {...},
|
1286
|
-
# 'id2': {...},
|
1287
|
-
# 'id3': {...},
|
1288
|
-
# ...
|
1289
|
-
# }
|
1290
|
-
#
|
1291
|
-
# list
|
1292
|
-
#
|
1293
|
-
# [
|
1294
|
-
# {'id': 'id1', ...},
|
1295
|
-
# {'id': 'id2', ...},
|
1296
|
-
# {'id': 'id3', ...},
|
1297
|
-
# ...
|
1298
|
-
# ]
|
1299
|
-
#
|
1300
|
-
results = []
|
1301
|
-
if isinstance(orders, list):
|
1302
|
-
for i in range(0, len(orders)):
|
1303
|
-
order = self.extend(self.parse_order(orders[i], market), params)
|
1304
|
-
results.append(order)
|
1305
|
-
else:
|
1306
|
-
ids = list(orders.keys())
|
1307
|
-
for i in range(0, len(ids)):
|
1308
|
-
id = ids[i]
|
1309
|
-
order = self.extend(self.parse_order(self.extend({'id': id}, orders[id]), market), params)
|
1310
|
-
results.append(order)
|
1311
|
-
results = self.sort_by(results, 'timestamp')
|
1312
|
-
symbol = market['symbol'] if (market is not None) else None
|
1313
|
-
return self.filter_by_symbol_since_limit(results, symbol, since, limit)
|
1314
|
-
|
1315
|
-
def calculate_fee(self, symbol: str, type: str, side: str, amount: float, price: float, takerOrMaker='taker', params={}):
|
1316
|
-
if type == 'market' and takerOrMaker == 'maker':
|
1317
|
-
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.')
|
1318
|
-
market = self.markets[symbol]
|
1319
|
-
feeSide = self.safe_string(market, 'feeSide', 'quote')
|
1320
|
-
useQuote = None
|
1321
|
-
if feeSide == 'get':
|
1322
|
-
# the fee is always in the currency you get
|
1323
|
-
useQuote = side == 'sell'
|
1324
|
-
elif feeSide == 'give':
|
1325
|
-
# the fee is always in the currency you give
|
1326
|
-
useQuote = side == 'buy'
|
1327
|
-
else:
|
1328
|
-
# the fee is always in feeSide currency
|
1329
|
-
useQuote = feeSide == 'quote'
|
1330
|
-
cost = self.number_to_string(amount)
|
1331
|
-
key = None
|
1332
|
-
if useQuote:
|
1333
|
-
priceString = self.number_to_string(price)
|
1334
|
-
cost = Precise.string_mul(cost, priceString)
|
1335
|
-
key = 'quote'
|
1336
|
-
else:
|
1337
|
-
key = 'base'
|
1338
|
-
# for derivatives, the fee is in 'settle' currency
|
1339
|
-
if not market['spot']:
|
1340
|
-
key = 'settle'
|
1341
|
-
# even if `takerOrMaker` argument was set to 'maker', for 'market' orders we should forcefully override it to 'taker'
|
1342
|
-
if type == 'market':
|
1343
|
-
takerOrMaker = 'taker'
|
1344
|
-
rate = self.safe_string(market, takerOrMaker)
|
1345
|
-
cost = Precise.string_mul(cost, rate)
|
1346
|
-
return {
|
1347
|
-
'type': takerOrMaker,
|
1348
|
-
'currency': market[key],
|
1349
|
-
'rate': self.parse_number(rate),
|
1350
|
-
'cost': self.parse_number(cost),
|
1351
|
-
}
|
1352
|
-
|
1353
|
-
def safe_liquidation(self, liquidation: object, market: object = None):
|
1354
|
-
contracts = self.safe_string(liquidation, 'contracts')
|
1355
|
-
contractSize = self.safe_string(market, 'contractSize')
|
1356
|
-
price = self.safe_string(liquidation, 'price')
|
1357
|
-
baseValue = self.safe_string(liquidation, 'baseValue')
|
1358
|
-
quoteValue = self.safe_string(liquidation, 'quoteValue')
|
1359
|
-
if (baseValue is None) and (contracts is not None) and (contractSize is not None) and (price is not None):
|
1360
|
-
baseValue = Precise.string_mul(contracts, contractSize)
|
1361
|
-
if (quoteValue is None) and (baseValue is not None) and (price is not None):
|
1362
|
-
quoteValue = Precise.string_mul(baseValue, price)
|
1363
|
-
liquidation['contracts'] = self.parse_number(contracts)
|
1364
|
-
liquidation['contractSize'] = self.parse_number(contractSize)
|
1365
|
-
liquidation['price'] = self.parse_number(price)
|
1366
|
-
liquidation['baseValue'] = self.parse_number(baseValue)
|
1367
|
-
liquidation['quoteValue'] = self.parse_number(quoteValue)
|
1368
|
-
return liquidation
|
1369
|
-
|
1370
|
-
def safe_trade(self, trade: object, market: object = None):
|
1371
|
-
amount = self.safe_string(trade, 'amount')
|
1372
|
-
price = self.safe_string(trade, 'price')
|
1373
|
-
cost = self.safe_string(trade, 'cost')
|
1374
|
-
if cost is None:
|
1375
|
-
# contract trading
|
1376
|
-
contractSize = self.safe_string(market, 'contractSize')
|
1377
|
-
multiplyPrice = price
|
1378
|
-
if contractSize is not None:
|
1379
|
-
inverse = self.safe_value(market, 'inverse', False)
|
1380
|
-
if inverse:
|
1381
|
-
multiplyPrice = Precise.string_div('1', price)
|
1382
|
-
multiplyPrice = Precise.string_mul(multiplyPrice, contractSize)
|
1383
|
-
cost = Precise.string_mul(multiplyPrice, amount)
|
1384
|
-
parseFee = self.safe_value(trade, 'fee') is None
|
1385
|
-
parseFees = self.safe_value(trade, 'fees') is None
|
1386
|
-
shouldParseFees = parseFee or parseFees
|
1387
|
-
fees = []
|
1388
|
-
fee = self.safe_value(trade, 'fee')
|
1389
|
-
if shouldParseFees:
|
1390
|
-
reducedFees = self.reduce_fees_by_currency(fees) if self.reduceFees else fees
|
1391
|
-
reducedLength = len(reducedFees)
|
1392
|
-
for i in range(0, reducedLength):
|
1393
|
-
reducedFees[i]['cost'] = self.safe_number(reducedFees[i], 'cost')
|
1394
|
-
if 'rate' in reducedFees[i]:
|
1395
|
-
reducedFees[i]['rate'] = self.safe_number(reducedFees[i], 'rate')
|
1396
|
-
if not parseFee and (reducedLength == 0):
|
1397
|
-
fee['cost'] = self.safe_number(fee, 'cost')
|
1398
|
-
if 'rate' in fee:
|
1399
|
-
fee['rate'] = self.safe_number(fee, 'rate')
|
1400
|
-
reducedFees.append(fee)
|
1401
|
-
if parseFees:
|
1402
|
-
trade['fees'] = reducedFees
|
1403
|
-
if parseFee and (reducedLength == 1):
|
1404
|
-
trade['fee'] = reducedFees[0]
|
1405
|
-
tradeFee = self.safe_value(trade, 'fee')
|
1406
|
-
if tradeFee is not None:
|
1407
|
-
tradeFee['cost'] = self.safe_number(tradeFee, 'cost')
|
1408
|
-
if 'rate' in tradeFee:
|
1409
|
-
tradeFee['rate'] = self.safe_number(tradeFee, 'rate')
|
1410
|
-
trade['fee'] = tradeFee
|
1411
|
-
trade['amount'] = self.parse_number(amount)
|
1412
|
-
trade['price'] = self.parse_number(price)
|
1413
|
-
trade['cost'] = self.parse_number(cost)
|
1414
|
-
return trade
|
1415
|
-
|
1416
|
-
def invert_flat_string_dictionary(self, dict):
|
1417
|
-
reversed = {}
|
1418
|
-
keys = list(dict.keys())
|
1419
|
-
for i in range(0, len(keys)):
|
1420
|
-
key = keys[i]
|
1421
|
-
value = dict[key]
|
1422
|
-
if isinstance(value, str):
|
1423
|
-
reversed[value] = key
|
1424
|
-
return reversed
|
1425
|
-
|
1426
|
-
def reduce_fees_by_currency(self, fees):
|
1427
|
-
#
|
1428
|
-
# self function takes a list of fee structures having the following format
|
1429
|
-
#
|
1430
|
-
# string = True
|
1431
|
-
#
|
1432
|
-
# [
|
1433
|
-
# {'currency': 'BTC', 'cost': '0.1'},
|
1434
|
-
# {'currency': 'BTC', 'cost': '0.2' },
|
1435
|
-
# {'currency': 'BTC', 'cost': '0.2', 'rate': '0.00123'},
|
1436
|
-
# {'currency': 'BTC', 'cost': '0.4', 'rate': '0.00123'},
|
1437
|
-
# {'currency': 'BTC', 'cost': '0.5', 'rate': '0.00456'},
|
1438
|
-
# {'currency': 'USDT', 'cost': '12.3456'},
|
1439
|
-
# ]
|
1440
|
-
#
|
1441
|
-
# string = False
|
1442
|
-
#
|
1443
|
-
# [
|
1444
|
-
# {'currency': 'BTC', 'cost': 0.1},
|
1445
|
-
# {'currency': 'BTC', 'cost': 0.2},
|
1446
|
-
# {'currency': 'BTC', 'cost': 0.2, 'rate': 0.00123},
|
1447
|
-
# {'currency': 'BTC', 'cost': 0.4, 'rate': 0.00123},
|
1448
|
-
# {'currency': 'BTC', 'cost': 0.5, 'rate': 0.00456},
|
1449
|
-
# {'currency': 'USDT', 'cost': 12.3456},
|
1450
|
-
# ]
|
1451
|
-
#
|
1452
|
-
# and returns a reduced fee list, where fees are summed per currency and rate(if any)
|
1453
|
-
#
|
1454
|
-
# string = True
|
1455
|
-
#
|
1456
|
-
# [
|
1457
|
-
# {'currency': 'BTC', 'cost': '0.4' },
|
1458
|
-
# {'currency': 'BTC', 'cost': '0.6', 'rate': '0.00123'},
|
1459
|
-
# {'currency': 'BTC', 'cost': '0.5', 'rate': '0.00456'},
|
1460
|
-
# {'currency': 'USDT', 'cost': '12.3456'},
|
1461
|
-
# ]
|
1462
|
-
#
|
1463
|
-
# string = False
|
1464
|
-
#
|
1465
|
-
# [
|
1466
|
-
# {'currency': 'BTC', 'cost': 0.3 },
|
1467
|
-
# {'currency': 'BTC', 'cost': 0.6, 'rate': 0.00123},
|
1468
|
-
# {'currency': 'BTC', 'cost': 0.5, 'rate': 0.00456},
|
1469
|
-
# {'currency': 'USDT', 'cost': 12.3456},
|
1470
|
-
# ]
|
1471
|
-
#
|
1472
|
-
reduced = {}
|
1473
|
-
for i in range(0, len(fees)):
|
1474
|
-
fee = fees[i]
|
1475
|
-
feeCurrencyCode = self.safe_string(fee, 'currency')
|
1476
|
-
if feeCurrencyCode is not None:
|
1477
|
-
rate = self.safe_string(fee, 'rate')
|
1478
|
-
cost = self.safe_value(fee, 'cost')
|
1479
|
-
if Precise.string_eq(cost, '0'):
|
1480
|
-
# omit zero cost fees
|
1481
|
-
continue
|
1482
|
-
if not (feeCurrencyCode in reduced):
|
1483
|
-
reduced[feeCurrencyCode] = {}
|
1484
|
-
rateKey = '' if (rate is None) else rate
|
1485
|
-
if rateKey in reduced[feeCurrencyCode]:
|
1486
|
-
reduced[feeCurrencyCode][rateKey]['cost'] = Precise.string_add(reduced[feeCurrencyCode][rateKey]['cost'], cost)
|
1487
|
-
else:
|
1488
|
-
reduced[feeCurrencyCode][rateKey] = {
|
1489
|
-
'currency': feeCurrencyCode,
|
1490
|
-
'cost': cost,
|
1491
|
-
}
|
1492
|
-
if rate is not None:
|
1493
|
-
reduced[feeCurrencyCode][rateKey]['rate'] = rate
|
1494
|
-
result = []
|
1495
|
-
feeValues = list(reduced.values())
|
1496
|
-
for i in range(0, len(feeValues)):
|
1497
|
-
reducedFeeValues = list(feeValues[i].values())
|
1498
|
-
result = self.array_concat(result, reducedFeeValues)
|
1499
|
-
return result
|
1500
|
-
|
1501
|
-
def safe_ticker(self, ticker: object, market=None):
|
1502
|
-
open = self.safe_value(ticker, 'open')
|
1503
|
-
close = self.safe_value(ticker, 'close')
|
1504
|
-
last = self.safe_value(ticker, 'last')
|
1505
|
-
change = self.safe_value(ticker, 'change')
|
1506
|
-
percentage = self.safe_value(ticker, 'percentage')
|
1507
|
-
average = self.safe_value(ticker, 'average')
|
1508
|
-
vwap = self.safe_value(ticker, 'vwap')
|
1509
|
-
baseVolume = self.safe_string(ticker, 'baseVolume')
|
1510
|
-
quoteVolume = self.safe_string(ticker, 'quoteVolume')
|
1511
|
-
if vwap is None:
|
1512
|
-
vwap = Precise.string_div(quoteVolume, baseVolume)
|
1513
|
-
if (last is not None) and (close is None):
|
1514
|
-
close = last
|
1515
|
-
elif (last is None) and (close is not None):
|
1516
|
-
last = close
|
1517
|
-
if (last is not None) and (open is not None):
|
1518
|
-
if change is None:
|
1519
|
-
change = Precise.string_sub(last, open)
|
1520
|
-
if average is None:
|
1521
|
-
average = Precise.string_div(Precise.string_add(last, open), '2')
|
1522
|
-
if (percentage is None) and (change is not None) and (open is not None) and Precise.string_gt(open, '0'):
|
1523
|
-
percentage = Precise.string_mul(Precise.string_div(change, open), '100')
|
1524
|
-
if (change is None) and (percentage is not None) and (open is not None):
|
1525
|
-
change = Precise.string_div(Precise.string_mul(percentage, open), '100')
|
1526
|
-
if (open is None) and (last is not None) and (change is not None):
|
1527
|
-
open = Precise.string_sub(last, change)
|
1528
|
-
# timestamp and symbol operations don't belong in safeTicker
|
1529
|
-
# they should be done in the derived classes
|
1530
|
-
return self.extend(ticker, {
|
1531
|
-
'bid': self.omit_zero(self.safe_number(ticker, 'bid')),
|
1532
|
-
'bidVolume': self.safe_number(ticker, 'bidVolume'),
|
1533
|
-
'ask': self.omit_zero(self.safe_number(ticker, 'ask')),
|
1534
|
-
'askVolume': self.safe_number(ticker, 'askVolume'),
|
1535
|
-
'high': self.omit_zero(self.safe_number(ticker, 'high')),
|
1536
|
-
'low': self.omit_zero(self.safe_number(ticker, 'low')),
|
1537
|
-
'open': self.omit_zero(self.parse_number(open)),
|
1538
|
-
'close': self.omit_zero(self.parse_number(close)),
|
1539
|
-
'last': self.omit_zero(self.parse_number(last)),
|
1540
|
-
'change': self.parse_number(change),
|
1541
|
-
'percentage': self.parse_number(percentage),
|
1542
|
-
'average': self.omit_zero(self.parse_number(average)),
|
1543
|
-
'vwap': self.omit_zero(self.parse_number(vwap)),
|
1544
|
-
'baseVolume': self.parse_number(baseVolume),
|
1545
|
-
'quoteVolume': self.parse_number(quoteVolume),
|
1546
|
-
'previousClose': self.safe_number(ticker, 'previousClose'),
|
1547
|
-
})
|
1548
|
-
|
1549
580
|
async def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}):
|
1550
581
|
message = ''
|
1551
582
|
if self.has['fetchTrades']:
|
@@ -1555,43 +586,6 @@ class Exchange(BaseExchange):
|
|
1555
586
|
async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}):
|
1556
587
|
raise NotSupported(self.id + ' watchOHLCV() is not supported yet')
|
1557
588
|
|
1558
|
-
def convert_trading_view_to_ohlcv(self, ohlcvs, timestamp='t', open='o', high='h', low='l', close='c', volume='v', ms=False):
|
1559
|
-
result = []
|
1560
|
-
timestamps = self.safe_value(ohlcvs, timestamp, [])
|
1561
|
-
opens = self.safe_value(ohlcvs, open, [])
|
1562
|
-
highs = self.safe_value(ohlcvs, high, [])
|
1563
|
-
lows = self.safe_value(ohlcvs, low, [])
|
1564
|
-
closes = self.safe_value(ohlcvs, close, [])
|
1565
|
-
volumes = self.safe_value(ohlcvs, volume, [])
|
1566
|
-
for i in range(0, len(timestamps)):
|
1567
|
-
result.append([
|
1568
|
-
self.safe_integer(timestamps, i) if ms else self.safe_timestamp(timestamps, i),
|
1569
|
-
self.safe_value(opens, i),
|
1570
|
-
self.safe_value(highs, i),
|
1571
|
-
self.safe_value(lows, i),
|
1572
|
-
self.safe_value(closes, i),
|
1573
|
-
self.safe_value(volumes, i),
|
1574
|
-
])
|
1575
|
-
return result
|
1576
|
-
|
1577
|
-
def convert_ohlcv_to_trading_view(self, ohlcvs, timestamp='t', open='o', high='h', low='l', close='c', volume='v', ms=False):
|
1578
|
-
result = {}
|
1579
|
-
result[timestamp] = []
|
1580
|
-
result[open] = []
|
1581
|
-
result[high] = []
|
1582
|
-
result[low] = []
|
1583
|
-
result[close] = []
|
1584
|
-
result[volume] = []
|
1585
|
-
for i in range(0, len(ohlcvs)):
|
1586
|
-
ts = ohlcvs[i][0] if ms else self.parseToInt(ohlcvs[i][0] / 1000)
|
1587
|
-
result[timestamp].append(ts)
|
1588
|
-
result[open].append(ohlcvs[i][1])
|
1589
|
-
result[high].append(ohlcvs[i][2])
|
1590
|
-
result[low].append(ohlcvs[i][3])
|
1591
|
-
result[close].append(ohlcvs[i][4])
|
1592
|
-
result[volume].append(ohlcvs[i][5])
|
1593
|
-
return result
|
1594
|
-
|
1595
589
|
async def fetch_web_endpoint(self, method, endpointMethod, returnAsJson, startRegex=None, endRegex=None):
|
1596
590
|
errorMessage = ''
|
1597
591
|
options = self.safe_value(self.options, method, {})
|
@@ -1633,59 +627,6 @@ class Exchange(BaseExchange):
|
|
1633
627
|
else:
|
1634
628
|
raise BadResponse(errorMessage)
|
1635
629
|
|
1636
|
-
def market_ids(self, symbols):
|
1637
|
-
if symbols is None:
|
1638
|
-
return symbols
|
1639
|
-
result = []
|
1640
|
-
for i in range(0, len(symbols)):
|
1641
|
-
result.append(self.market_id(symbols[i]))
|
1642
|
-
return result
|
1643
|
-
|
1644
|
-
def market_symbols(self, symbols, type: str = None, allowEmpty=True, sameTypeOnly=False, sameSubTypeOnly=False):
|
1645
|
-
if symbols is None:
|
1646
|
-
if not allowEmpty:
|
1647
|
-
raise ArgumentsRequired(self.id + ' empty list of symbols is not supported')
|
1648
|
-
return symbols
|
1649
|
-
symbolsLength = len(symbols)
|
1650
|
-
if symbolsLength == 0:
|
1651
|
-
if not allowEmpty:
|
1652
|
-
raise ArgumentsRequired(self.id + ' empty list of symbols is not supported')
|
1653
|
-
return symbols
|
1654
|
-
result = []
|
1655
|
-
marketType = None
|
1656
|
-
isLinearSubType = None
|
1657
|
-
for i in range(0, len(symbols)):
|
1658
|
-
market = self.market(symbols[i])
|
1659
|
-
if sameTypeOnly and (marketType is not None):
|
1660
|
-
if market['type'] != marketType:
|
1661
|
-
raise BadRequest(self.id + ' symbols must be of the same type, either ' + marketType + ' or ' + market['type'] + '.')
|
1662
|
-
if sameSubTypeOnly and (isLinearSubType is not None):
|
1663
|
-
if market['linear'] != isLinearSubType:
|
1664
|
-
raise BadRequest(self.id + ' symbols must be of the same subType, either linear or inverse.')
|
1665
|
-
if type is not None and market['type'] != type:
|
1666
|
-
raise BadRequest(self.id + ' symbols must be of the same type ' + type + '. If the type is incorrect you can change it in options or the params of the request')
|
1667
|
-
marketType = market['type']
|
1668
|
-
if not market['spot']:
|
1669
|
-
isLinearSubType = market['linear']
|
1670
|
-
symbol = self.safe_string(market, 'symbol', symbols[i])
|
1671
|
-
result.append(symbol)
|
1672
|
-
return result
|
1673
|
-
|
1674
|
-
def market_codes(self, codes):
|
1675
|
-
if codes is None:
|
1676
|
-
return codes
|
1677
|
-
result = []
|
1678
|
-
for i in range(0, len(codes)):
|
1679
|
-
result.append(self.common_currency_code(codes[i]))
|
1680
|
-
return result
|
1681
|
-
|
1682
|
-
def parse_bids_asks(self, bidasks, priceKey: IndexType = 0, amountKey: IndexType = 1):
|
1683
|
-
bidasks = self.to_array(bidasks)
|
1684
|
-
result = []
|
1685
|
-
for i in range(0, len(bidasks)):
|
1686
|
-
result.append(self.parse_bid_ask(bidasks[i], priceKey, amountKey))
|
1687
|
-
return result
|
1688
|
-
|
1689
630
|
async def fetch_l2_order_book(self, symbol: str, limit: Int = None, params={}):
|
1690
631
|
orderbook = await self.fetch_order_book(symbol, limit, params)
|
1691
632
|
return self.extend(orderbook, {
|
@@ -1693,168 +634,6 @@ class Exchange(BaseExchange):
|
|
1693
634
|
'bids': self.sort_by(self.aggregate(orderbook['bids']), 0, True),
|
1694
635
|
})
|
1695
636
|
|
1696
|
-
def filter_by_symbol(self, objects, symbol: str = None):
|
1697
|
-
if symbol is None:
|
1698
|
-
return objects
|
1699
|
-
result = []
|
1700
|
-
for i in range(0, len(objects)):
|
1701
|
-
objectSymbol = self.safe_string(objects[i], 'symbol')
|
1702
|
-
if objectSymbol == symbol:
|
1703
|
-
result.append(objects[i])
|
1704
|
-
return result
|
1705
|
-
|
1706
|
-
def parse_ohlcv(self, ohlcv, market=None) -> list:
|
1707
|
-
if isinstance(ohlcv, list):
|
1708
|
-
return [
|
1709
|
-
self.safe_integer(ohlcv, 0), # timestamp
|
1710
|
-
self.safe_number(ohlcv, 1), # open
|
1711
|
-
self.safe_number(ohlcv, 2), # high
|
1712
|
-
self.safe_number(ohlcv, 3), # low
|
1713
|
-
self.safe_number(ohlcv, 4), # close
|
1714
|
-
self.safe_number(ohlcv, 5), # volume
|
1715
|
-
]
|
1716
|
-
return ohlcv
|
1717
|
-
|
1718
|
-
def network_code_to_id(self, networkCode, currencyCode=None):
|
1719
|
-
"""
|
1720
|
-
* @ignore
|
1721
|
-
tries to convert the provided networkCode(which is expected to be an unified network code) to a network id. In order to achieve self, derived class needs to have 'options->networks' defined.
|
1722
|
-
:param str networkCode: unified network code
|
1723
|
-
:param str currencyCode: unified currency code, but self argument is not required by default, unless there is an exchange(like huobi) that needs an override of the method to be able to pass currencyCode argument additionally
|
1724
|
-
:returns str|None: exchange-specific network id
|
1725
|
-
"""
|
1726
|
-
networkIdsByCodes = self.safe_value(self.options, 'networks', {})
|
1727
|
-
networkId = self.safe_string(networkIdsByCodes, networkCode)
|
1728
|
-
# for example, if 'ETH' is passed for networkCode, but 'ETH' key not defined in `options->networks` object
|
1729
|
-
if networkId is None:
|
1730
|
-
if currencyCode is None:
|
1731
|
-
# if currencyCode was not provided, then we just set passed value to networkId
|
1732
|
-
networkId = networkCode
|
1733
|
-
else:
|
1734
|
-
# if currencyCode was provided, then we try to find if that currencyCode has a replacement(i.e. ERC20 for ETH)
|
1735
|
-
defaultNetworkCodeReplacements = self.safe_value(self.options, 'defaultNetworkCodeReplacements', {})
|
1736
|
-
if currencyCode in defaultNetworkCodeReplacements:
|
1737
|
-
# if there is a replacement for the passed networkCode, then we use it to find network-id in `options->networks` object
|
1738
|
-
replacementObject = defaultNetworkCodeReplacements[currencyCode] # i.e. {'ERC20': 'ETH'}
|
1739
|
-
keys = list(replacementObject.keys())
|
1740
|
-
for i in range(0, len(keys)):
|
1741
|
-
key = keys[i]
|
1742
|
-
value = replacementObject[key]
|
1743
|
-
# if value matches to provided unified networkCode, then we use it's key to find network-id in `options->networks` object
|
1744
|
-
if value == networkCode:
|
1745
|
-
networkId = self.safe_string(networkIdsByCodes, key)
|
1746
|
-
break
|
1747
|
-
# if it wasn't found, we just set the provided value to network-id
|
1748
|
-
if networkId is None:
|
1749
|
-
networkId = networkCode
|
1750
|
-
return networkId
|
1751
|
-
|
1752
|
-
def network_id_to_code(self, networkId, currencyCode=None):
|
1753
|
-
"""
|
1754
|
-
* @ignore
|
1755
|
-
tries to convert the provided exchange-specific networkId to an unified network Code. In order to achieve self, derived class needs to have "options['networksById']" defined.
|
1756
|
-
:param str networkId: exchange specific network id/title, like: TRON, Trc-20, usdt-erc20, etc
|
1757
|
-
:param str|None currencyCode: unified currency code, but self argument is not required by default, unless there is an exchange(like huobi) that needs an override of the method to be able to pass currencyCode argument additionally
|
1758
|
-
:returns str|None: unified network code
|
1759
|
-
"""
|
1760
|
-
networkCodesByIds = self.safe_value(self.options, 'networksById', {})
|
1761
|
-
networkCode = self.safe_string(networkCodesByIds, networkId, networkId)
|
1762
|
-
# replace mainnet network-codes(i.e. ERC20->ETH)
|
1763
|
-
if currencyCode is not None:
|
1764
|
-
defaultNetworkCodeReplacements = self.safe_value(self.options, 'defaultNetworkCodeReplacements', {})
|
1765
|
-
if currencyCode in defaultNetworkCodeReplacements:
|
1766
|
-
replacementObject = self.safe_value(defaultNetworkCodeReplacements, currencyCode, {})
|
1767
|
-
networkCode = self.safe_string(replacementObject, networkCode, networkCode)
|
1768
|
-
return networkCode
|
1769
|
-
|
1770
|
-
def handle_network_code_and_params(self, params):
|
1771
|
-
networkCodeInParams = self.safe_string_2(params, 'networkCode', 'network')
|
1772
|
-
if networkCodeInParams is not None:
|
1773
|
-
params = self.omit(params, ['networkCode', 'network'])
|
1774
|
-
# if it was not defined by user, we should not set it from 'defaultNetworks', because handleNetworkCodeAndParams is for only request-side and thus we do not fill it with anything. We can only use 'defaultNetworks' after parsing response-side
|
1775
|
-
return [networkCodeInParams, params]
|
1776
|
-
|
1777
|
-
def default_network_code(self, currencyCode):
|
1778
|
-
defaultNetworkCode = None
|
1779
|
-
defaultNetworks = self.safe_value(self.options, 'defaultNetworks', {})
|
1780
|
-
if currencyCode in defaultNetworks:
|
1781
|
-
# if currency had set its network in "defaultNetworks", use it
|
1782
|
-
defaultNetworkCode = defaultNetworks[currencyCode]
|
1783
|
-
else:
|
1784
|
-
# otherwise, try to use the global-scope 'defaultNetwork' value(even if that network is not supported by currency, it doesn't make any problem, self will be just used "at first" if currency supports self network at all)
|
1785
|
-
defaultNetwork = self.safe_value(self.options, 'defaultNetwork')
|
1786
|
-
if defaultNetwork is not None:
|
1787
|
-
defaultNetworkCode = defaultNetwork
|
1788
|
-
return defaultNetworkCode
|
1789
|
-
|
1790
|
-
def select_network_code_from_unified_networks(self, currencyCode, networkCode, indexedNetworkEntries):
|
1791
|
-
return self.select_network_key_from_networks(currencyCode, networkCode, indexedNetworkEntries, True)
|
1792
|
-
|
1793
|
-
def select_network_id_from_raw_networks(self, currencyCode, networkCode, indexedNetworkEntries):
|
1794
|
-
return self.select_network_key_from_networks(currencyCode, networkCode, indexedNetworkEntries, False)
|
1795
|
-
|
1796
|
-
def select_network_key_from_networks(self, currencyCode, networkCode, indexedNetworkEntries, isIndexedByUnifiedNetworkCode=False):
|
1797
|
-
# self method is used against raw & unparse network entries, which are just indexed by network id
|
1798
|
-
chosenNetworkId = None
|
1799
|
-
availableNetworkIds = list(indexedNetworkEntries.keys())
|
1800
|
-
responseNetworksLength = len(availableNetworkIds)
|
1801
|
-
if networkCode is not None:
|
1802
|
-
if responseNetworksLength == 0:
|
1803
|
-
raise NotSupported(self.id + ' - ' + networkCode + ' network did not return any result for ' + currencyCode)
|
1804
|
-
else:
|
1805
|
-
# if networkCode was provided by user, we should check it after response, referenced exchange doesn't support network-code during request
|
1806
|
-
networkId = networkCode if isIndexedByUnifiedNetworkCode else self.network_code_to_id(networkCode, currencyCode)
|
1807
|
-
if networkId in indexedNetworkEntries:
|
1808
|
-
chosenNetworkId = networkId
|
1809
|
-
else:
|
1810
|
-
raise NotSupported(self.id + ' - ' + networkId + ' network was not found for ' + currencyCode + ', use one of ' + ', '.join(availableNetworkIds))
|
1811
|
-
else:
|
1812
|
-
if responseNetworksLength == 0:
|
1813
|
-
raise NotSupported(self.id + ' - no networks were returned for ' + currencyCode)
|
1814
|
-
else:
|
1815
|
-
# if networkCode was not provided by user, then we try to use the default network(if it was defined in "defaultNetworks"), otherwise, we just return the first network entry
|
1816
|
-
defaultNetworkCode = self.default_network_code(currencyCode)
|
1817
|
-
defaultNetworkId = defaultNetworkCode if isIndexedByUnifiedNetworkCode else self.network_code_to_id(defaultNetworkCode, currencyCode)
|
1818
|
-
chosenNetworkId = defaultNetworkId if (defaultNetworkId in indexedNetworkEntries) else availableNetworkIds[0]
|
1819
|
-
return chosenNetworkId
|
1820
|
-
|
1821
|
-
def safe_number_2(self, dictionary, key1, key2, d=None):
|
1822
|
-
value = self.safe_string_2(dictionary, key1, key2)
|
1823
|
-
return self.parse_number(value, d)
|
1824
|
-
|
1825
|
-
def parse_order_book(self, orderbook: object, symbol: str, timestamp: Int = None, bidsKey='bids', asksKey='asks', priceKey: IndexType = 0, amountKey: IndexType = 1):
|
1826
|
-
bids = self.parse_bids_asks(self.safe_value(orderbook, bidsKey, []), priceKey, amountKey)
|
1827
|
-
asks = self.parse_bids_asks(self.safe_value(orderbook, asksKey, []), priceKey, amountKey)
|
1828
|
-
return {
|
1829
|
-
'symbol': symbol,
|
1830
|
-
'bids': self.sort_by(bids, 0, True),
|
1831
|
-
'asks': self.sort_by(asks, 0),
|
1832
|
-
'timestamp': timestamp,
|
1833
|
-
'datetime': self.iso8601(timestamp),
|
1834
|
-
'nonce': None,
|
1835
|
-
}
|
1836
|
-
|
1837
|
-
def parse_ohlcvs(self, ohlcvs: List[object], market: Any = None, timeframe: str = '1m', since: Int = None, limit: Int = None):
|
1838
|
-
results = []
|
1839
|
-
for i in range(0, len(ohlcvs)):
|
1840
|
-
results.append(self.parse_ohlcv(ohlcvs[i], market))
|
1841
|
-
sorted = self.sort_by(results, 0)
|
1842
|
-
return self.filter_by_since_limit(sorted, since, limit, 0)
|
1843
|
-
|
1844
|
-
def parse_leverage_tiers(self, response, symbols: List[str] = None, marketIdKey=None):
|
1845
|
-
# marketIdKey should only be None when response is a dictionary
|
1846
|
-
symbols = self.market_symbols(symbols)
|
1847
|
-
tiers = {}
|
1848
|
-
for i in range(0, len(response)):
|
1849
|
-
item = response[i]
|
1850
|
-
id = self.safe_string(item, marketIdKey)
|
1851
|
-
market = self.safe_market(id, None, None, self.safe_string(self.options, 'defaultType'))
|
1852
|
-
symbol = market['symbol']
|
1853
|
-
contract = self.safe_value(market, 'contract', False)
|
1854
|
-
if contract and ((symbols is None) or self.in_array(symbol, symbols)):
|
1855
|
-
tiers[symbol] = self.parse_market_leverage_tiers(item, market)
|
1856
|
-
return tiers
|
1857
|
-
|
1858
637
|
async def load_trading_limits(self, symbols: List[str] = None, reload=False, params={}):
|
1859
638
|
if self.has['fetchTradingLimits']:
|
1860
639
|
if reload or not ('limitsLoaded' in self.options):
|
@@ -1865,123 +644,6 @@ class Exchange(BaseExchange):
|
|
1865
644
|
self.options['limitsLoaded'] = self.milliseconds()
|
1866
645
|
return self.markets
|
1867
646
|
|
1868
|
-
def safe_position(self, position):
|
1869
|
-
# simplified version of: /pull/12765/
|
1870
|
-
unrealizedPnlString = self.safe_string(position, 'unrealisedPnl')
|
1871
|
-
initialMarginString = self.safe_string(position, 'initialMargin')
|
1872
|
-
#
|
1873
|
-
# PERCENTAGE
|
1874
|
-
#
|
1875
|
-
percentage = self.safe_value(position, 'percentage')
|
1876
|
-
if (percentage is None) and (unrealizedPnlString is not None) and (initialMarginString is not None):
|
1877
|
-
# was done in all implementations( aax, btcex, bybit, deribit, ftx, gate, kucoinfutures, phemex )
|
1878
|
-
percentageString = Precise.string_mul(Precise.string_div(unrealizedPnlString, initialMarginString, 4), '100')
|
1879
|
-
position['percentage'] = self.parse_number(percentageString)
|
1880
|
-
# if contractSize is None get from market
|
1881
|
-
contractSize = self.safe_number(position, 'contractSize')
|
1882
|
-
symbol = self.safe_string(position, 'symbol')
|
1883
|
-
market = None
|
1884
|
-
if symbol is not None:
|
1885
|
-
market = self.safe_value(self.markets, symbol)
|
1886
|
-
if contractSize is None and market is not None:
|
1887
|
-
contractSize = self.safe_number(market, 'contractSize')
|
1888
|
-
position['contractSize'] = contractSize
|
1889
|
-
return position
|
1890
|
-
|
1891
|
-
def parse_positions(self, positions, symbols: List[str] = None, params={}):
|
1892
|
-
symbols = self.market_symbols(symbols)
|
1893
|
-
positions = self.to_array(positions)
|
1894
|
-
result = []
|
1895
|
-
for i in range(0, len(positions)):
|
1896
|
-
position = self.extend(self.parse_position(positions[i], None), params)
|
1897
|
-
result.append(position)
|
1898
|
-
return self.filter_by_array_positions(result, 'symbol', symbols, False)
|
1899
|
-
|
1900
|
-
def parse_accounts(self, accounts, params={}):
|
1901
|
-
accounts = self.to_array(accounts)
|
1902
|
-
result = []
|
1903
|
-
for i in range(0, len(accounts)):
|
1904
|
-
account = self.extend(self.parse_account(accounts[i]), params)
|
1905
|
-
result.append(account)
|
1906
|
-
return result
|
1907
|
-
|
1908
|
-
def parse_trades(self, trades, market: object = None, since: Int = None, limit: Int = None, params={}):
|
1909
|
-
trades = self.to_array(trades)
|
1910
|
-
result = []
|
1911
|
-
for i in range(0, len(trades)):
|
1912
|
-
trade = self.extend(self.parse_trade(trades[i], market), params)
|
1913
|
-
result.append(trade)
|
1914
|
-
result = self.sort_by_2(result, 'timestamp', 'id')
|
1915
|
-
symbol = market['symbol'] if (market is not None) else None
|
1916
|
-
return self.filter_by_symbol_since_limit(result, symbol, since, limit)
|
1917
|
-
|
1918
|
-
def parse_transactions(self, transactions, currency: object = None, since: Int = None, limit: Int = None, params={}):
|
1919
|
-
transactions = self.to_array(transactions)
|
1920
|
-
result = []
|
1921
|
-
for i in range(0, len(transactions)):
|
1922
|
-
transaction = self.extend(self.parse_transaction(transactions[i], currency), params)
|
1923
|
-
result.append(transaction)
|
1924
|
-
result = self.sort_by(result, 'timestamp')
|
1925
|
-
code = currency['code'] if (currency is not None) else None
|
1926
|
-
return self.filter_by_currency_since_limit(result, code, since, limit)
|
1927
|
-
|
1928
|
-
def parse_transfers(self, transfers, currency: object = None, since: Int = None, limit: Int = None, params={}):
|
1929
|
-
transfers = self.to_array(transfers)
|
1930
|
-
result = []
|
1931
|
-
for i in range(0, len(transfers)):
|
1932
|
-
transfer = self.extend(self.parse_transfer(transfers[i], currency), params)
|
1933
|
-
result.append(transfer)
|
1934
|
-
result = self.sort_by(result, 'timestamp')
|
1935
|
-
code = currency['code'] if (currency is not None) else None
|
1936
|
-
return self.filter_by_currency_since_limit(result, code, since, limit)
|
1937
|
-
|
1938
|
-
def parse_ledger(self, data, currency: object = None, since: Int = None, limit: Int = None, params={}):
|
1939
|
-
result = []
|
1940
|
-
arrayData = self.to_array(data)
|
1941
|
-
for i in range(0, len(arrayData)):
|
1942
|
-
itemOrItems = self.parse_ledger_entry(arrayData[i], currency)
|
1943
|
-
if isinstance(itemOrItems, list):
|
1944
|
-
for j in range(0, len(itemOrItems)):
|
1945
|
-
result.append(self.extend(itemOrItems[j], params))
|
1946
|
-
else:
|
1947
|
-
result.append(self.extend(itemOrItems, params))
|
1948
|
-
result = self.sort_by(result, 'timestamp')
|
1949
|
-
code = currency['code'] if (currency is not None) else None
|
1950
|
-
return self.filter_by_currency_since_limit(result, code, since, limit)
|
1951
|
-
|
1952
|
-
def nonce(self):
|
1953
|
-
return self.seconds()
|
1954
|
-
|
1955
|
-
def set_headers(self, headers):
|
1956
|
-
return headers
|
1957
|
-
|
1958
|
-
def market_id(self, symbol: str):
|
1959
|
-
market = self.market(symbol)
|
1960
|
-
if market is not None:
|
1961
|
-
return market['id']
|
1962
|
-
return symbol
|
1963
|
-
|
1964
|
-
def symbol(self, symbol: str):
|
1965
|
-
market = self.market(symbol)
|
1966
|
-
return self.safe_string(market, 'symbol', symbol)
|
1967
|
-
|
1968
|
-
def resolve_path(self, path, params):
|
1969
|
-
return [
|
1970
|
-
self.implode_params(path, params),
|
1971
|
-
self.omit(params, self.extract_params(path)),
|
1972
|
-
]
|
1973
|
-
|
1974
|
-
def filter_by_array(self, objects, key: IndexType, values=None, indexed=True):
|
1975
|
-
objects = self.to_array(objects)
|
1976
|
-
# return all of them if no values were passed
|
1977
|
-
if values is None or not values:
|
1978
|
-
return self.index_by(objects, key) if indexed else objects
|
1979
|
-
results = []
|
1980
|
-
for i in range(0, len(objects)):
|
1981
|
-
if self.in_array(objects[i][key], values):
|
1982
|
-
results.append(objects[i])
|
1983
|
-
return self.index_by(results, key) if indexed else results
|
1984
|
-
|
1985
647
|
async def fetch2(self, path, api: Any = 'public', method='GET', params={}, headers: Any = None, body: Any = None, config={}):
|
1986
648
|
if self.enableRateLimit:
|
1987
649
|
cost = self.calculate_rate_limiter_cost(api, method, path, params, config)
|
@@ -2007,54 +669,6 @@ class Exchange(BaseExchange):
|
|
2007
669
|
self.accountsById = self.index_by(self.accounts, 'id')
|
2008
670
|
return self.accounts
|
2009
671
|
|
2010
|
-
def build_ohlcvc(self, trades: List[Trade], timeframe: str = '1m', since: float = 0, limit: float = 2147483647):
|
2011
|
-
# given a sorted arrays of trades(recent last) and a timeframe builds an array of OHLCV candles
|
2012
|
-
# note, default limit value(2147483647) is max int32 value
|
2013
|
-
ms = self.parse_timeframe(timeframe) * 1000
|
2014
|
-
ohlcvs = []
|
2015
|
-
i_timestamp = 0
|
2016
|
-
# open = 1
|
2017
|
-
i_high = 2
|
2018
|
-
i_low = 3
|
2019
|
-
i_close = 4
|
2020
|
-
i_volume = 5
|
2021
|
-
i_count = 6
|
2022
|
-
tradesLength = len(trades)
|
2023
|
-
oldest = min(tradesLength, limit)
|
2024
|
-
for i in range(0, oldest):
|
2025
|
-
trade = trades[i]
|
2026
|
-
ts = trade['timestamp']
|
2027
|
-
if ts < since:
|
2028
|
-
continue
|
2029
|
-
openingTime = int(math.floor(ts / ms)) * ms # shift to the edge of m/h/d(but not M)
|
2030
|
-
if openingTime < since: # we don't need bars, that have opening time earlier than requested
|
2031
|
-
continue
|
2032
|
-
ohlcv_length = len(ohlcvs)
|
2033
|
-
candle = ohlcv_length - 1
|
2034
|
-
if (candle == -1) or (openingTime >= self.sum(ohlcvs[candle][i_timestamp], ms)):
|
2035
|
-
# moved to a new timeframe -> create a new candle from opening trade
|
2036
|
-
ohlcvs.append([
|
2037
|
-
openingTime, # timestamp
|
2038
|
-
trade['price'], # O
|
2039
|
-
trade['price'], # H
|
2040
|
-
trade['price'], # L
|
2041
|
-
trade['price'], # C
|
2042
|
-
trade['amount'], # V
|
2043
|
-
1, # count
|
2044
|
-
])
|
2045
|
-
else:
|
2046
|
-
# still processing the same timeframe -> update opening trade
|
2047
|
-
ohlcvs[candle][i_high] = max(ohlcvs[candle][i_high], trade['price'])
|
2048
|
-
ohlcvs[candle][i_low] = min(ohlcvs[candle][i_low], trade['price'])
|
2049
|
-
ohlcvs[candle][i_close] = trade['price']
|
2050
|
-
ohlcvs[candle][i_volume] = self.sum(ohlcvs[candle][i_volume], trade['amount'])
|
2051
|
-
ohlcvs[candle][i_count] = self.sum(ohlcvs[candle][i_count], 1)
|
2052
|
-
return ohlcvs
|
2053
|
-
|
2054
|
-
def parse_trading_view_ohlcv(self, ohlcvs, market=None, timeframe='1m', since: Int = None, limit: Int = None):
|
2055
|
-
result = self.convert_trading_view_to_ohlcv(ohlcvs)
|
2056
|
-
return self.parse_ohlcvs(result, market, timeframe, since, limit)
|
2057
|
-
|
2058
672
|
async def edit_limit_buy_order(self, id, symbol, amount, price=None, params={}):
|
2059
673
|
return await self.edit_limit_order(id, symbol, 'buy', amount, price, params)
|
2060
674
|
|
@@ -2105,127 +719,12 @@ class Exchange(BaseExchange):
|
|
2105
719
|
async def fetch_bids_asks(self, symbols: List[str] = None, params={}):
|
2106
720
|
raise NotSupported(self.id + ' fetchBidsAsks() is not supported yet')
|
2107
721
|
|
2108
|
-
def parse_bid_ask(self, bidask, priceKey: IndexType = 0, amountKey: IndexType = 1):
|
2109
|
-
price = self.safe_number(bidask, priceKey)
|
2110
|
-
amount = self.safe_number(bidask, amountKey)
|
2111
|
-
return [price, amount]
|
2112
|
-
|
2113
|
-
def safe_currency(self, currencyId: String, currency: Currency = None):
|
2114
|
-
if (currencyId is None) and (currency is not None):
|
2115
|
-
return currency
|
2116
|
-
if (self.currencies_by_id is not None) and (currencyId in self.currencies_by_id) and (self.currencies_by_id[currencyId] is not None):
|
2117
|
-
return self.currencies_by_id[currencyId]
|
2118
|
-
code = currencyId
|
2119
|
-
if currencyId is not None:
|
2120
|
-
code = self.common_currency_code(currencyId.upper())
|
2121
|
-
return {
|
2122
|
-
'id': currencyId,
|
2123
|
-
'code': code,
|
2124
|
-
}
|
2125
|
-
|
2126
|
-
def safe_market(self, marketId: String, market: Market = None, delimiter: String = None, marketType: String = None):
|
2127
|
-
result = {
|
2128
|
-
'id': marketId,
|
2129
|
-
'symbol': marketId,
|
2130
|
-
'base': None,
|
2131
|
-
'quote': None,
|
2132
|
-
'baseId': None,
|
2133
|
-
'quoteId': None,
|
2134
|
-
'active': None,
|
2135
|
-
'type': None,
|
2136
|
-
'linear': None,
|
2137
|
-
'inverse': None,
|
2138
|
-
'spot': False,
|
2139
|
-
'swap': False,
|
2140
|
-
'future': False,
|
2141
|
-
'option': False,
|
2142
|
-
'margin': False,
|
2143
|
-
'contract': False,
|
2144
|
-
'contractSize': None,
|
2145
|
-
'expiry': None,
|
2146
|
-
'expiryDatetime': None,
|
2147
|
-
'optionType': None,
|
2148
|
-
'strike': None,
|
2149
|
-
'settle': None,
|
2150
|
-
'settleId': None,
|
2151
|
-
'precision': {
|
2152
|
-
'amount': None,
|
2153
|
-
'price': None,
|
2154
|
-
},
|
2155
|
-
'limits': {
|
2156
|
-
'amount': {
|
2157
|
-
'min': None,
|
2158
|
-
'max': None,
|
2159
|
-
},
|
2160
|
-
'price': {
|
2161
|
-
'min': None,
|
2162
|
-
'max': None,
|
2163
|
-
},
|
2164
|
-
'cost': {
|
2165
|
-
'min': None,
|
2166
|
-
'max': None,
|
2167
|
-
},
|
2168
|
-
},
|
2169
|
-
'info': None,
|
2170
|
-
}
|
2171
|
-
if marketId is not None:
|
2172
|
-
if (self.markets_by_id is not None) and (marketId in self.markets_by_id):
|
2173
|
-
markets = self.markets_by_id[marketId]
|
2174
|
-
numMarkets = len(markets)
|
2175
|
-
if numMarkets == 1:
|
2176
|
-
return markets[0]
|
2177
|
-
else:
|
2178
|
-
if marketType is None:
|
2179
|
-
if market is None:
|
2180
|
-
raise ArgumentsRequired(self.id + ' safeMarket() requires a fourth argument for ' + marketId + ' to disambiguate between different markets with the same market id')
|
2181
|
-
else:
|
2182
|
-
marketType = market['type']
|
2183
|
-
for i in range(0, len(markets)):
|
2184
|
-
currentMarket = markets[i]
|
2185
|
-
if currentMarket[marketType]:
|
2186
|
-
return currentMarket
|
2187
|
-
elif delimiter is not None:
|
2188
|
-
parts = marketId.split(delimiter)
|
2189
|
-
partsLength = len(parts)
|
2190
|
-
if partsLength == 2:
|
2191
|
-
result['baseId'] = self.safe_string(parts, 0)
|
2192
|
-
result['quoteId'] = self.safe_string(parts, 1)
|
2193
|
-
result['base'] = self.safe_currency_code(result['baseId'])
|
2194
|
-
result['quote'] = self.safe_currency_code(result['quoteId'])
|
2195
|
-
result['symbol'] = result['base'] + '/' + result['quote']
|
2196
|
-
return result
|
2197
|
-
else:
|
2198
|
-
return result
|
2199
|
-
if market is not None:
|
2200
|
-
return market
|
2201
|
-
return result
|
2202
|
-
|
2203
|
-
def check_required_credentials(self, error=True):
|
2204
|
-
keys = list(self.requiredCredentials.keys())
|
2205
|
-
for i in range(0, len(keys)):
|
2206
|
-
key = keys[i]
|
2207
|
-
if self.requiredCredentials[key] and not getattr(self, key):
|
2208
|
-
if error:
|
2209
|
-
raise AuthenticationError(self.id + ' requires "' + key + '" credential')
|
2210
|
-
else:
|
2211
|
-
return False
|
2212
|
-
return True
|
2213
|
-
|
2214
|
-
def oath(self):
|
2215
|
-
if self.twofa is not None:
|
2216
|
-
return self.totp(self.twofa)
|
2217
|
-
else:
|
2218
|
-
raise ExchangeError(self.id + ' exchange.twofa has not been set for 2FA Two-Factor Authentication')
|
2219
|
-
|
2220
722
|
async def fetch_balance(self, params={}):
|
2221
723
|
raise NotSupported(self.id + ' fetchBalance() is not supported yet')
|
2222
724
|
|
2223
725
|
async def fetch_balance_ws(self, params={}):
|
2224
726
|
raise NotSupported(self.id + ' fetchBalanceWs() is not supported yet')
|
2225
727
|
|
2226
|
-
def parse_balance(self, response):
|
2227
|
-
raise NotSupported(self.id + ' parseBalance() is not supported yet')
|
2228
|
-
|
2229
728
|
async def watch_balance(self, params={}):
|
2230
729
|
raise NotSupported(self.id + ' watchBalance() is not supported yet')
|
2231
730
|
|
@@ -2274,12 +773,6 @@ class Exchange(BaseExchange):
|
|
2274
773
|
fees = await self.fetchDepositWithdrawFees([code], params)
|
2275
774
|
return self.safe_value(fees, code)
|
2276
775
|
|
2277
|
-
def get_supported_mapping(self, key, mapping={}):
|
2278
|
-
if key in mapping:
|
2279
|
-
return mapping[key]
|
2280
|
-
else:
|
2281
|
-
raise NotSupported(self.id + ' ' + key + ' does not have a value in mapping')
|
2282
|
-
|
2283
776
|
async def fetch_borrow_rate(self, code: str, params={}):
|
2284
777
|
await self.load_markets()
|
2285
778
|
if not self.has['fetchBorrowRates']:
|
@@ -2290,101 +783,6 @@ class Exchange(BaseExchange):
|
|
2290
783
|
raise ExchangeError(self.id + ' fetchBorrowRate() could not find the borrow rate for currency code ' + code)
|
2291
784
|
return rate
|
2292
785
|
|
2293
|
-
def handle_option_and_params(self, params, methodName, optionName, defaultValue=None):
|
2294
|
-
# This method can be used to obtain method specific properties, i.e: self.handle_option_and_params(params, 'fetchPosition', 'marginMode', 'isolated')
|
2295
|
-
defaultOptionName = 'default' + self.capitalize(optionName) # we also need to check the 'defaultXyzWhatever'
|
2296
|
-
# check if params contain the key
|
2297
|
-
value = self.safe_value_2(params, optionName, defaultOptionName)
|
2298
|
-
if value is not None:
|
2299
|
-
params = self.omit(params, [optionName, defaultOptionName])
|
2300
|
-
else:
|
2301
|
-
# check if exchange has properties for self method
|
2302
|
-
exchangeWideMethodOptions = self.safe_value(self.options, methodName)
|
2303
|
-
if exchangeWideMethodOptions is not None:
|
2304
|
-
# check if the option is defined inside self method's props
|
2305
|
-
value = self.safe_value_2(exchangeWideMethodOptions, optionName, defaultOptionName)
|
2306
|
-
if value is None:
|
2307
|
-
# if it's still None, check if global exchange-wide option exists
|
2308
|
-
value = self.safe_value_2(self.options, optionName, defaultOptionName)
|
2309
|
-
# if it's still None, use the default value
|
2310
|
-
value = value if (value is not None) else defaultValue
|
2311
|
-
return [value, params]
|
2312
|
-
|
2313
|
-
def handle_option(self, methodName, optionName, defaultValue=None):
|
2314
|
-
# eslint-disable-next-line no-unused-vars
|
2315
|
-
result, empty = self.handle_option_and_params({}, methodName, optionName, defaultValue)
|
2316
|
-
return result
|
2317
|
-
|
2318
|
-
def handle_market_type_and_params(self, methodName, market=None, params={}):
|
2319
|
-
defaultType = self.safe_string_2(self.options, 'defaultType', 'type', 'spot')
|
2320
|
-
methodOptions = self.safe_value(self.options, methodName)
|
2321
|
-
methodType = defaultType
|
2322
|
-
if methodOptions is not None:
|
2323
|
-
if isinstance(methodOptions, str):
|
2324
|
-
methodType = methodOptions
|
2325
|
-
else:
|
2326
|
-
methodType = self.safe_string_2(methodOptions, 'defaultType', 'type', methodType)
|
2327
|
-
marketType = methodType if (market is None) else market['type']
|
2328
|
-
type = self.safe_string_2(params, 'defaultType', 'type', marketType)
|
2329
|
-
params = self.omit(params, ['defaultType', 'type'])
|
2330
|
-
return [type, params]
|
2331
|
-
|
2332
|
-
def handle_sub_type_and_params(self, methodName, market=None, params={}, defaultValue=None):
|
2333
|
-
subType = None
|
2334
|
-
# if set in params, it takes precedence
|
2335
|
-
subTypeInParams = self.safe_string_2(params, 'subType', 'defaultSubType')
|
2336
|
-
# avoid omitting if it's not present
|
2337
|
-
if subTypeInParams is not None:
|
2338
|
-
subType = subTypeInParams
|
2339
|
-
params = self.omit(params, ['subType', 'defaultSubType'])
|
2340
|
-
else:
|
2341
|
-
# at first, check from market object
|
2342
|
-
if market is not None:
|
2343
|
-
if market['linear']:
|
2344
|
-
subType = 'linear'
|
2345
|
-
elif market['inverse']:
|
2346
|
-
subType = 'inverse'
|
2347
|
-
# if it was not defined in market object
|
2348
|
-
if subType is None:
|
2349
|
-
values = self.handle_option_and_params(None, methodName, 'subType', defaultValue) # no need to re-test params here
|
2350
|
-
subType = values[0]
|
2351
|
-
return [subType, params]
|
2352
|
-
|
2353
|
-
def handle_margin_mode_and_params(self, methodName, params={}, defaultValue=None):
|
2354
|
-
"""
|
2355
|
-
* @ignore
|
2356
|
-
:param dict [params]: extra parameters specific to the exchange api endpoint
|
2357
|
-
:returns Array: the marginMode in lowercase by params["marginMode"], params["defaultMarginMode"] self.options["marginMode"] or self.options["defaultMarginMode"]
|
2358
|
-
"""
|
2359
|
-
return self.handle_option_and_params(params, methodName, 'marginMode', defaultValue)
|
2360
|
-
|
2361
|
-
def throw_exactly_matched_exception(self, exact, string, message):
|
2362
|
-
if string in exact:
|
2363
|
-
raise exact[string](message)
|
2364
|
-
|
2365
|
-
def throw_broadly_matched_exception(self, broad, string, message):
|
2366
|
-
broadKey = self.find_broadly_matched_key(broad, string)
|
2367
|
-
if broadKey is not None:
|
2368
|
-
raise broad[broadKey](message)
|
2369
|
-
|
2370
|
-
def find_broadly_matched_key(self, broad, string):
|
2371
|
-
# a helper for matching error strings exactly vs broadly
|
2372
|
-
keys = list(broad.keys())
|
2373
|
-
for i in range(0, len(keys)):
|
2374
|
-
key = keys[i]
|
2375
|
-
if string is not None: # #issues/12698
|
2376
|
-
if string.find(key) >= 0:
|
2377
|
-
return key
|
2378
|
-
return None
|
2379
|
-
|
2380
|
-
def handle_errors(self, statusCode, statusText, url, method, responseHeaders, responseBody, response, requestHeaders, requestBody):
|
2381
|
-
# it is a stub method that must be overrided in the derived exchange classes
|
2382
|
-
# raise NotSupported(self.id + ' handleErrors() not implemented yet')
|
2383
|
-
return None
|
2384
|
-
|
2385
|
-
def calculate_rate_limiter_cost(self, api, method, path, params, config={}):
|
2386
|
-
return self.safe_value(config, 'cost', 1)
|
2387
|
-
|
2388
786
|
async def fetch_ticker(self, symbol: str, params={}):
|
2389
787
|
if self.has['fetchTickers']:
|
2390
788
|
await self.load_markets()
|
@@ -2518,9 +916,6 @@ class Exchange(BaseExchange):
|
|
2518
916
|
async def fetch_funding_history(self, symbol: str = None, since: Int = None, limit: Int = None, params={}):
|
2519
917
|
raise NotSupported(self.id + ' fetchFundingHistory() is not supported yet')
|
2520
918
|
|
2521
|
-
def parse_last_price(self, price, market=None):
|
2522
|
-
raise NotSupported(self.id + ' parseLastPrice() is not supported yet')
|
2523
|
-
|
2524
919
|
async def fetch_deposit_address(self, code: str, params={}):
|
2525
920
|
if self.has['fetchDepositAddresses']:
|
2526
921
|
depositAddresses = await self.fetchDepositAddresses([code], params)
|
@@ -2532,54 +927,6 @@ class Exchange(BaseExchange):
|
|
2532
927
|
else:
|
2533
928
|
raise NotSupported(self.id + ' fetchDepositAddress() is not supported yet')
|
2534
929
|
|
2535
|
-
def account(self) -> Balance:
|
2536
|
-
return {
|
2537
|
-
'free': None,
|
2538
|
-
'used': None,
|
2539
|
-
'total': None,
|
2540
|
-
}
|
2541
|
-
|
2542
|
-
def common_currency_code(self, currency: str):
|
2543
|
-
if not self.substituteCommonCurrencyCodes:
|
2544
|
-
return currency
|
2545
|
-
return self.safe_string(self.commonCurrencies, currency, currency)
|
2546
|
-
|
2547
|
-
def currency(self, code):
|
2548
|
-
if self.currencies is None:
|
2549
|
-
raise ExchangeError(self.id + ' currencies not loaded')
|
2550
|
-
if isinstance(code, str):
|
2551
|
-
if code in self.currencies:
|
2552
|
-
return self.currencies[code]
|
2553
|
-
elif code in self.currencies_by_id:
|
2554
|
-
return self.currencies_by_id[code]
|
2555
|
-
raise ExchangeError(self.id + ' does not have currency code ' + code)
|
2556
|
-
|
2557
|
-
def market(self, symbol: str):
|
2558
|
-
if self.markets is None:
|
2559
|
-
raise ExchangeError(self.id + ' markets not loaded')
|
2560
|
-
if isinstance(symbol, str):
|
2561
|
-
if symbol in self.markets:
|
2562
|
-
return self.markets[symbol]
|
2563
|
-
elif symbol in self.markets_by_id:
|
2564
|
-
markets = self.markets_by_id[symbol]
|
2565
|
-
defaultType = self.safe_string_2(self.options, 'defaultType', 'defaultSubType', 'spot')
|
2566
|
-
for i in range(0, len(markets)):
|
2567
|
-
market = markets[i]
|
2568
|
-
if market[defaultType]:
|
2569
|
-
return market
|
2570
|
-
return markets[0]
|
2571
|
-
raise BadSymbol(self.id + ' does not have market symbol ' + symbol)
|
2572
|
-
|
2573
|
-
def handle_withdraw_tag_and_params(self, tag, params):
|
2574
|
-
if isinstance(tag, dict):
|
2575
|
-
params = self.extend(tag, params)
|
2576
|
-
tag = None
|
2577
|
-
if tag is None:
|
2578
|
-
tag = self.safe_string(params, 'tag')
|
2579
|
-
if tag is not None:
|
2580
|
-
params = self.omit(params, 'tag')
|
2581
|
-
return [tag, params]
|
2582
|
-
|
2583
930
|
async def create_limit_order(self, symbol: str, side: OrderSide, amount, price, params={}):
|
2584
931
|
return await self.create_order(symbol, 'limit', side, amount, price, params)
|
2585
932
|
|
@@ -2598,87 +945,12 @@ class Exchange(BaseExchange):
|
|
2598
945
|
async def create_market_sell_order(self, symbol: str, amount, params={}):
|
2599
946
|
return await self.create_order(symbol, 'market', 'sell', amount, None, params)
|
2600
947
|
|
2601
|
-
def cost_to_precision(self, symbol: str, cost):
|
2602
|
-
market = self.market(symbol)
|
2603
|
-
return self.decimal_to_precision(cost, TRUNCATE, market['precision']['price'], self.precisionMode, self.paddingMode)
|
2604
|
-
|
2605
|
-
def price_to_precision(self, symbol: str, price):
|
2606
|
-
market = self.market(symbol)
|
2607
|
-
result = self.decimal_to_precision(price, ROUND, market['precision']['price'], self.precisionMode, self.paddingMode)
|
2608
|
-
if result == '0':
|
2609
|
-
raise InvalidOrder(self.id + ' price of ' + market['symbol'] + ' must be greater than minimum price precision of ' + self.number_to_string(market['precision']['price']))
|
2610
|
-
return result
|
2611
|
-
|
2612
|
-
def amount_to_precision(self, symbol: str, amount):
|
2613
|
-
market = self.market(symbol)
|
2614
|
-
result = self.decimal_to_precision(amount, TRUNCATE, market['precision']['amount'], self.precisionMode, self.paddingMode)
|
2615
|
-
if result == '0':
|
2616
|
-
raise InvalidOrder(self.id + ' amount of ' + market['symbol'] + ' must be greater than minimum amount precision of ' + self.number_to_string(market['precision']['amount']))
|
2617
|
-
return result
|
2618
|
-
|
2619
|
-
def fee_to_precision(self, symbol: str, fee):
|
2620
|
-
market = self.market(symbol)
|
2621
|
-
return self.decimal_to_precision(fee, ROUND, market['precision']['price'], self.precisionMode, self.paddingMode)
|
2622
|
-
|
2623
|
-
def currency_to_precision(self, code: str, fee, networkCode=None):
|
2624
|
-
currency = self.currencies[code]
|
2625
|
-
precision = self.safe_value(currency, 'precision')
|
2626
|
-
if networkCode is not None:
|
2627
|
-
networks = self.safe_value(currency, 'networks', {})
|
2628
|
-
networkItem = self.safe_value(networks, networkCode, {})
|
2629
|
-
precision = self.safe_value(networkItem, 'precision', precision)
|
2630
|
-
if precision is None:
|
2631
|
-
return self.forceString(fee)
|
2632
|
-
else:
|
2633
|
-
return self.decimal_to_precision(fee, ROUND, precision, self.precisionMode, self.paddingMode)
|
2634
|
-
|
2635
|
-
def force_string(self, value):
|
2636
|
-
if not isinstance(value, str):
|
2637
|
-
return self.number_to_string(value)
|
2638
|
-
return value
|
2639
|
-
|
2640
|
-
def is_tick_precision(self):
|
2641
|
-
return self.precisionMode == TICK_SIZE
|
2642
|
-
|
2643
|
-
def is_decimal_precision(self):
|
2644
|
-
return self.precisionMode == DECIMAL_PLACES
|
2645
|
-
|
2646
|
-
def is_significant_precision(self):
|
2647
|
-
return self.precisionMode == SIGNIFICANT_DIGITS
|
2648
|
-
|
2649
|
-
def safe_number(self, obj: object, key: IndexType, defaultNumber: float = None):
|
2650
|
-
value = self.safe_string(obj, key)
|
2651
|
-
return self.parse_number(value, defaultNumber)
|
2652
|
-
|
2653
|
-
def safe_number_n(self, obj: object, arr: List[IndexType], defaultNumber: float = None):
|
2654
|
-
value = self.safe_string_n(obj, arr)
|
2655
|
-
return self.parse_number(value, defaultNumber)
|
2656
|
-
|
2657
|
-
def parse_precision(self, precision: str):
|
2658
|
-
"""
|
2659
|
-
* @ignore
|
2660
|
-
:param str precision: The number of digits to the right of the decimal
|
2661
|
-
:returns str: a string number equal to 1e-precision
|
2662
|
-
"""
|
2663
|
-
if precision is None:
|
2664
|
-
return None
|
2665
|
-
precisionNumber = int(precision)
|
2666
|
-
if precisionNumber == 0:
|
2667
|
-
return '1'
|
2668
|
-
parsedPrecision = '0.'
|
2669
|
-
for i in range(0, precisionNumber - 1):
|
2670
|
-
parsedPrecision = parsedPrecision + '0'
|
2671
|
-
return parsedPrecision + '1'
|
2672
|
-
|
2673
948
|
async def load_time_difference(self, params={}):
|
2674
949
|
serverTime = await self.fetch_time(params)
|
2675
950
|
after = self.milliseconds()
|
2676
951
|
self.options['timeDifference'] = after - serverTime
|
2677
952
|
return self.options['timeDifference']
|
2678
953
|
|
2679
|
-
def implode_hostname(self, url: str):
|
2680
|
-
return self.implode_params(url, {'hostname': self.hostname})
|
2681
|
-
|
2682
954
|
async def fetch_market_leverage_tiers(self, symbol: str, params={}):
|
2683
955
|
if self.has['fetchLeverageTiers']:
|
2684
956
|
market = self.market(symbol)
|
@@ -2721,190 +993,6 @@ class Exchange(BaseExchange):
|
|
2721
993
|
query = self.extend(params, {'stopPrice': stopPrice})
|
2722
994
|
return await self.create_order(symbol, 'market', side, amount, None, query)
|
2723
995
|
|
2724
|
-
def safe_currency_code(self, currencyId: str, currency: Any = None):
|
2725
|
-
currency = self.safe_currency(currencyId, currency)
|
2726
|
-
return currency['code']
|
2727
|
-
|
2728
|
-
def filter_by_symbol_since_limit(self, array, symbol: str = None, since: Int = None, limit: Int = None, tail=False):
|
2729
|
-
return self.filter_by_value_since_limit(array, 'symbol', symbol, since, limit, 'timestamp', tail)
|
2730
|
-
|
2731
|
-
def filter_by_currency_since_limit(self, array, code=None, since: Int = None, limit: Int = None, tail=False):
|
2732
|
-
return self.filter_by_value_since_limit(array, 'currency', code, since, limit, 'timestamp', tail)
|
2733
|
-
|
2734
|
-
def filter_by_symbols_since_limit(self, array, symbols: List[str] = None, since: Int = None, limit: Int = None, tail=False):
|
2735
|
-
result = self.filter_by_array(array, 'symbol', symbols, False)
|
2736
|
-
return self.filter_by_since_limit(result, since, limit, 'timestamp', tail)
|
2737
|
-
|
2738
|
-
def parse_last_prices(self, pricesData, symbols: List[str] = None, params={}):
|
2739
|
-
#
|
2740
|
-
# the value of tickers is either a dict or a list
|
2741
|
-
#
|
2742
|
-
# dict
|
2743
|
-
#
|
2744
|
-
# {
|
2745
|
-
# 'marketId1': {...},
|
2746
|
-
# 'marketId2': {...},
|
2747
|
-
# ...
|
2748
|
-
# }
|
2749
|
-
#
|
2750
|
-
# list
|
2751
|
-
#
|
2752
|
-
# [
|
2753
|
-
# {'market': 'marketId1', ...},
|
2754
|
-
# {'market': 'marketId2', ...},
|
2755
|
-
# ...
|
2756
|
-
# ]
|
2757
|
-
#
|
2758
|
-
results = []
|
2759
|
-
if isinstance(pricesData, list):
|
2760
|
-
for i in range(0, len(pricesData)):
|
2761
|
-
priceData = self.extend(self.parseLastPrice(pricesData[i]), params)
|
2762
|
-
results.append(priceData)
|
2763
|
-
else:
|
2764
|
-
marketIds = list(pricesData.keys())
|
2765
|
-
for i in range(0, len(marketIds)):
|
2766
|
-
marketId = marketIds[i]
|
2767
|
-
market = self.safe_market(marketId)
|
2768
|
-
priceData = self.extend(self.parseLastPrice(pricesData[marketId], market), params)
|
2769
|
-
results.append(priceData)
|
2770
|
-
symbols = self.market_symbols(symbols)
|
2771
|
-
return self.filter_by_array(results, 'symbol', symbols)
|
2772
|
-
|
2773
|
-
def parse_tickers(self, tickers, symbols: List[str] = None, params={}):
|
2774
|
-
#
|
2775
|
-
# the value of tickers is either a dict or a list
|
2776
|
-
#
|
2777
|
-
# dict
|
2778
|
-
#
|
2779
|
-
# {
|
2780
|
-
# 'marketId1': {...},
|
2781
|
-
# 'marketId2': {...},
|
2782
|
-
# 'marketId3': {...},
|
2783
|
-
# ...
|
2784
|
-
# }
|
2785
|
-
#
|
2786
|
-
# list
|
2787
|
-
#
|
2788
|
-
# [
|
2789
|
-
# {'market': 'marketId1', ...},
|
2790
|
-
# {'market': 'marketId2', ...},
|
2791
|
-
# {'market': 'marketId3', ...},
|
2792
|
-
# ...
|
2793
|
-
# ]
|
2794
|
-
#
|
2795
|
-
results = []
|
2796
|
-
if isinstance(tickers, list):
|
2797
|
-
for i in range(0, len(tickers)):
|
2798
|
-
ticker = self.extend(self.parse_ticker(tickers[i]), params)
|
2799
|
-
results.append(ticker)
|
2800
|
-
else:
|
2801
|
-
marketIds = list(tickers.keys())
|
2802
|
-
for i in range(0, len(marketIds)):
|
2803
|
-
marketId = marketIds[i]
|
2804
|
-
market = self.safe_market(marketId)
|
2805
|
-
ticker = self.extend(self.parse_ticker(tickers[marketId], market), params)
|
2806
|
-
results.append(ticker)
|
2807
|
-
symbols = self.market_symbols(symbols)
|
2808
|
-
return self.filter_by_array(results, 'symbol', symbols)
|
2809
|
-
|
2810
|
-
def parse_deposit_addresses(self, addresses, codes: List[str] = None, indexed=True, params={}):
|
2811
|
-
result = []
|
2812
|
-
for i in range(0, len(addresses)):
|
2813
|
-
address = self.extend(self.parse_deposit_address(addresses[i]), params)
|
2814
|
-
result.append(address)
|
2815
|
-
if codes is not None:
|
2816
|
-
result = self.filter_by_array(result, 'currency', codes, False)
|
2817
|
-
if indexed:
|
2818
|
-
return self.index_by(result, 'currency')
|
2819
|
-
return result
|
2820
|
-
|
2821
|
-
def parse_borrow_interests(self, response, market=None):
|
2822
|
-
interests = []
|
2823
|
-
for i in range(0, len(response)):
|
2824
|
-
row = response[i]
|
2825
|
-
interests.append(self.parse_borrow_interest(row, market))
|
2826
|
-
return interests
|
2827
|
-
|
2828
|
-
def parse_funding_rate_histories(self, response, market=None, since: Int = None, limit: Int = None):
|
2829
|
-
rates = []
|
2830
|
-
for i in range(0, len(response)):
|
2831
|
-
entry = response[i]
|
2832
|
-
rates.append(self.parse_funding_rate_history(entry, market))
|
2833
|
-
sorted = self.sort_by(rates, 'timestamp')
|
2834
|
-
symbol = None if (market is None) else market['symbol']
|
2835
|
-
return self.filter_by_symbol_since_limit(sorted, symbol, since, limit)
|
2836
|
-
|
2837
|
-
def safe_symbol(self, marketId, market=None, delimiter=None, marketType=None):
|
2838
|
-
market = self.safe_market(marketId, market, delimiter, marketType)
|
2839
|
-
return market['symbol']
|
2840
|
-
|
2841
|
-
def parse_funding_rate(self, contract: str, market=None):
|
2842
|
-
raise NotSupported(self.id + ' parseFundingRate() is not supported yet')
|
2843
|
-
|
2844
|
-
def parse_funding_rates(self, response, market=None):
|
2845
|
-
result = {}
|
2846
|
-
for i in range(0, len(response)):
|
2847
|
-
parsed = self.parse_funding_rate(response[i], market)
|
2848
|
-
result[parsed['symbol']] = parsed
|
2849
|
-
return result
|
2850
|
-
|
2851
|
-
def is_trigger_order(self, params):
|
2852
|
-
isTrigger = self.safe_value_2(params, 'trigger', 'stop')
|
2853
|
-
if isTrigger:
|
2854
|
-
params = self.omit(params, ['trigger', 'stop'])
|
2855
|
-
return [isTrigger, params]
|
2856
|
-
|
2857
|
-
def is_post_only(self, isMarketOrder: bool, exchangeSpecificParam, params={}):
|
2858
|
-
"""
|
2859
|
-
* @ignore
|
2860
|
-
:param str type: Order type
|
2861
|
-
:param boolean exchangeSpecificParam: exchange specific postOnly
|
2862
|
-
:param dict [params]: exchange specific params
|
2863
|
-
:returns boolean: True if a post only order, False otherwise
|
2864
|
-
"""
|
2865
|
-
timeInForce = self.safe_string_upper(params, 'timeInForce')
|
2866
|
-
postOnly = self.safe_value_2(params, 'postOnly', 'post_only', False)
|
2867
|
-
# we assume timeInForce is uppercase from safeStringUpper(params, 'timeInForce')
|
2868
|
-
ioc = timeInForce == 'IOC'
|
2869
|
-
fok = timeInForce == 'FOK'
|
2870
|
-
timeInForcePostOnly = timeInForce == 'PO'
|
2871
|
-
postOnly = postOnly or timeInForcePostOnly or exchangeSpecificParam
|
2872
|
-
if postOnly:
|
2873
|
-
if ioc or fok:
|
2874
|
-
raise InvalidOrder(self.id + ' postOnly orders cannot have timeInForce equal to ' + timeInForce)
|
2875
|
-
elif isMarketOrder:
|
2876
|
-
raise InvalidOrder(self.id + ' market orders cannot be postOnly')
|
2877
|
-
else:
|
2878
|
-
return True
|
2879
|
-
else:
|
2880
|
-
return False
|
2881
|
-
|
2882
|
-
def handle_post_only(self, isMarketOrder: bool, exchangeSpecificPostOnlyOption: bool, params: Any = {}):
|
2883
|
-
"""
|
2884
|
-
* @ignore
|
2885
|
-
:param str type: Order type
|
2886
|
-
:param boolean exchangeSpecificBoolean: exchange specific postOnly
|
2887
|
-
:param dict [params]: exchange specific params
|
2888
|
-
:returns Array:
|
2889
|
-
"""
|
2890
|
-
timeInForce = self.safe_string_upper(params, 'timeInForce')
|
2891
|
-
postOnly = self.safe_value(params, 'postOnly', False)
|
2892
|
-
ioc = timeInForce == 'IOC'
|
2893
|
-
fok = timeInForce == 'FOK'
|
2894
|
-
po = timeInForce == 'PO'
|
2895
|
-
postOnly = postOnly or po or exchangeSpecificPostOnlyOption
|
2896
|
-
if postOnly:
|
2897
|
-
if ioc or fok:
|
2898
|
-
raise InvalidOrder(self.id + ' postOnly orders cannot have timeInForce equal to ' + timeInForce)
|
2899
|
-
elif isMarketOrder:
|
2900
|
-
raise InvalidOrder(self.id + ' market orders cannot be postOnly')
|
2901
|
-
else:
|
2902
|
-
if po:
|
2903
|
-
params = self.omit(params, 'timeInForce')
|
2904
|
-
params = self.omit(params, 'postOnly')
|
2905
|
-
return [True, params]
|
2906
|
-
return [False, params]
|
2907
|
-
|
2908
996
|
async def fetch_last_prices(self, symbols: List[str] = None, params={}):
|
2909
997
|
raise NotSupported(self.id + ' fetchLastPrices() is not supported yet')
|
2910
998
|
|
@@ -2916,19 +1004,6 @@ class Exchange(BaseExchange):
|
|
2916
1004
|
raise NotSupported(self.id + ' fetchTradingFee() is not supported yet')
|
2917
1005
|
return await self.fetch_trading_fees(params)
|
2918
1006
|
|
2919
|
-
def parse_open_interest(self, interest, market=None):
|
2920
|
-
raise NotSupported(self.id + ' parseOpenInterest() is not supported yet')
|
2921
|
-
|
2922
|
-
def parse_open_interests(self, response, market=None, since: Int = None, limit: Int = None):
|
2923
|
-
interests = []
|
2924
|
-
for i in range(0, len(response)):
|
2925
|
-
entry = response[i]
|
2926
|
-
interest = self.parse_open_interest(entry, market)
|
2927
|
-
interests.append(interest)
|
2928
|
-
sorted = self.sort_by(interests, 'timestamp')
|
2929
|
-
symbol = self.safe_string(market, 'symbol')
|
2930
|
-
return self.filter_by_symbol_since_limit(sorted, symbol, since, limit)
|
2931
|
-
|
2932
1007
|
async def fetch_funding_rate(self, symbol: str, params={}):
|
2933
1008
|
if self.has['fetchFundingRates']:
|
2934
1009
|
await self.load_markets()
|
@@ -2999,171 +1074,6 @@ class Exchange(BaseExchange):
|
|
2999
1074
|
else:
|
3000
1075
|
raise NotSupported(self.id + ' fetchPremiumIndexOHLCV() is not supported yet')
|
3001
1076
|
|
3002
|
-
def handle_time_in_force(self, params={}):
|
3003
|
-
"""
|
3004
|
-
* @ignore
|
3005
|
-
* * Must add timeInForce to self.options to use self method
|
3006
|
-
:return string returns: the exchange specific value for timeInForce
|
3007
|
-
"""
|
3008
|
-
timeInForce = self.safe_string_upper(params, 'timeInForce') # supported values GTC, IOC, PO
|
3009
|
-
if timeInForce is not None:
|
3010
|
-
exchangeValue = self.safe_string(self.options['timeInForce'], timeInForce)
|
3011
|
-
if exchangeValue is None:
|
3012
|
-
raise ExchangeError(self.id + ' does not support timeInForce "' + timeInForce + '"')
|
3013
|
-
return exchangeValue
|
3014
|
-
return None
|
3015
|
-
|
3016
|
-
def convert_type_to_account(self, account):
|
3017
|
-
"""
|
3018
|
-
* @ignore
|
3019
|
-
* * Must add accountsByType to self.options to use self method
|
3020
|
-
:param str account: key for account name in self.options['accountsByType']
|
3021
|
-
:returns: the exchange specific account name or the isolated margin id for transfers
|
3022
|
-
"""
|
3023
|
-
accountsByType = self.safe_value(self.options, 'accountsByType', {})
|
3024
|
-
lowercaseAccount = account.lower()
|
3025
|
-
if lowercaseAccount in accountsByType:
|
3026
|
-
return accountsByType[lowercaseAccount]
|
3027
|
-
elif (account in self.markets) or (account in self.markets_by_id):
|
3028
|
-
market = self.market(account)
|
3029
|
-
return market['id']
|
3030
|
-
else:
|
3031
|
-
return account
|
3032
|
-
|
3033
|
-
def check_required_argument(self, methodName, argument, argumentName, options=[]):
|
3034
|
-
"""
|
3035
|
-
* @ignore
|
3036
|
-
:param str methodName: the name of the method that the argument is being checked for
|
3037
|
-
:param str argument: the argument's actual value provided
|
3038
|
-
:param str argumentName: the name of the argument being checked(for logging purposes)
|
3039
|
-
:param str[] options: a list of options that the argument can be
|
3040
|
-
:returns None:
|
3041
|
-
"""
|
3042
|
-
optionsLength = len(options)
|
3043
|
-
if (argument is None) or ((optionsLength > 0) and (not(self.in_array(argument, options)))):
|
3044
|
-
messageOptions = ', '.join(options)
|
3045
|
-
message = self.id + ' ' + methodName + '() requires a ' + argumentName + ' argument'
|
3046
|
-
if messageOptions != '':
|
3047
|
-
message += ', one of ' + '(' + messageOptions + ')'
|
3048
|
-
raise ArgumentsRequired(message)
|
3049
|
-
|
3050
|
-
def check_required_margin_argument(self, methodName: str, symbol: str, marginMode: str):
|
3051
|
-
"""
|
3052
|
-
* @ignore
|
3053
|
-
:param str symbol: unified symbol of the market
|
3054
|
-
:param str methodName: name of the method that requires a symbol
|
3055
|
-
:param str marginMode: is either 'isolated' or 'cross'
|
3056
|
-
"""
|
3057
|
-
if (marginMode == 'isolated') and (symbol is None):
|
3058
|
-
raise ArgumentsRequired(self.id + ' ' + methodName + '() requires a symbol argument for isolated margin')
|
3059
|
-
elif (marginMode == 'cross') and (symbol is not None):
|
3060
|
-
raise ArgumentsRequired(self.id + ' ' + methodName + '() cannot have a symbol argument for cross margin')
|
3061
|
-
|
3062
|
-
def check_required_symbol(self, methodName: str, symbol: str):
|
3063
|
-
"""
|
3064
|
-
* @ignore
|
3065
|
-
:param str symbol: unified symbol of the market
|
3066
|
-
:param str methodName: name of the method that requires a symbol
|
3067
|
-
"""
|
3068
|
-
self.check_required_argument(methodName, symbol, 'symbol')
|
3069
|
-
|
3070
|
-
def parse_deposit_withdraw_fees(self, response, codes: List[str] = None, currencyIdKey=None):
|
3071
|
-
"""
|
3072
|
-
* @ignore
|
3073
|
-
:param object[]|dict response: unparsed response from the exchange
|
3074
|
-
:param str[]|None codes: the unified currency codes to fetch transactions fees for, returns all currencies when None
|
3075
|
-
:param str currencyIdKey: *should only be None when response is a dictionary* the object key that corresponds to the currency id
|
3076
|
-
:returns dict: objects with withdraw and deposit fees, indexed by currency codes
|
3077
|
-
"""
|
3078
|
-
depositWithdrawFees = {}
|
3079
|
-
codes = self.marketCodes(codes)
|
3080
|
-
isArray = isinstance(response, list)
|
3081
|
-
responseKeys = response
|
3082
|
-
if not isArray:
|
3083
|
-
responseKeys = list(response.keys())
|
3084
|
-
for i in range(0, len(responseKeys)):
|
3085
|
-
entry = responseKeys[i]
|
3086
|
-
dictionary = entry if isArray else response[entry]
|
3087
|
-
currencyId = self.safe_string(dictionary, currencyIdKey) if isArray else entry
|
3088
|
-
currency = self.safe_value(self.currencies_by_id, currencyId)
|
3089
|
-
code = self.safe_string(currency, 'code', currencyId)
|
3090
|
-
if (codes is None) or (self.in_array(code, codes)):
|
3091
|
-
depositWithdrawFees[code] = self.parseDepositWithdrawFee(dictionary, currency)
|
3092
|
-
return depositWithdrawFees
|
3093
|
-
|
3094
|
-
def parse_deposit_withdraw_fee(self, fee, currency=None):
|
3095
|
-
raise NotSupported(self.id + ' parseDepositWithdrawFee() is not supported yet')
|
3096
|
-
|
3097
|
-
def deposit_withdraw_fee(self, info):
|
3098
|
-
return {
|
3099
|
-
'info': info,
|
3100
|
-
'withdraw': {
|
3101
|
-
'fee': None,
|
3102
|
-
'percentage': None,
|
3103
|
-
},
|
3104
|
-
'deposit': {
|
3105
|
-
'fee': None,
|
3106
|
-
'percentage': None,
|
3107
|
-
},
|
3108
|
-
'networks': {},
|
3109
|
-
}
|
3110
|
-
|
3111
|
-
def assign_default_deposit_withdraw_fees(self, fee, currency=None):
|
3112
|
-
"""
|
3113
|
-
* @ignore
|
3114
|
-
Takes a depositWithdrawFee structure and assigns the default values for withdraw and deposit
|
3115
|
-
:param dict fee: A deposit withdraw fee structure
|
3116
|
-
:param dict currency: A currency structure, the response from self.currency()
|
3117
|
-
:returns dict: A deposit withdraw fee structure
|
3118
|
-
"""
|
3119
|
-
networkKeys = list(fee['networks'].keys())
|
3120
|
-
numNetworks = len(networkKeys)
|
3121
|
-
if numNetworks == 1:
|
3122
|
-
fee['withdraw'] = fee['networks'][networkKeys[0]]['withdraw']
|
3123
|
-
fee['deposit'] = fee['networks'][networkKeys[0]]['deposit']
|
3124
|
-
return fee
|
3125
|
-
currencyCode = self.safe_string(currency, 'code')
|
3126
|
-
for i in range(0, numNetworks):
|
3127
|
-
network = networkKeys[i]
|
3128
|
-
if network == currencyCode:
|
3129
|
-
fee['withdraw'] = fee['networks'][networkKeys[i]]['withdraw']
|
3130
|
-
fee['deposit'] = fee['networks'][networkKeys[i]]['deposit']
|
3131
|
-
return fee
|
3132
|
-
|
3133
|
-
def parse_income(self, info, market=None):
|
3134
|
-
raise NotSupported(self.id + ' parseIncome() is not supported yet')
|
3135
|
-
|
3136
|
-
def parse_incomes(self, incomes, market=None, since: Int = None, limit: Int = None):
|
3137
|
-
"""
|
3138
|
-
* @ignore
|
3139
|
-
parses funding fee info from exchange response
|
3140
|
-
:param dict[] incomes: each item describes once instance of currency being received or paid
|
3141
|
-
:param dict market: ccxt market
|
3142
|
-
:param int [since]: when defined, the response items are filtered to only include items after self timestamp
|
3143
|
-
:param int [limit]: limits the number of items in the response
|
3144
|
-
:returns dict[]: an array of `funding history structures <https://github.com/ccxt/ccxt/wiki/Manual#funding-history-structure>`
|
3145
|
-
"""
|
3146
|
-
result = []
|
3147
|
-
for i in range(0, len(incomes)):
|
3148
|
-
entry = incomes[i]
|
3149
|
-
parsed = self.parse_income(entry, market)
|
3150
|
-
result.append(parsed)
|
3151
|
-
sorted = self.sort_by(result, 'timestamp')
|
3152
|
-
return self.filter_by_since_limit(sorted, since, limit)
|
3153
|
-
|
3154
|
-
def get_market_from_symbols(self, symbols: List[str] = None):
|
3155
|
-
if symbols is None:
|
3156
|
-
return None
|
3157
|
-
firstMarket = self.safe_string(symbols, 0)
|
3158
|
-
market = self.market(firstMarket)
|
3159
|
-
return market
|
3160
|
-
|
3161
|
-
def parse_ws_ohlcvs(self, ohlcvs: List[object], market: Any = None, timeframe: str = '1m', since: Int = None, limit: Int = None):
|
3162
|
-
results = []
|
3163
|
-
for i in range(0, len(ohlcvs)):
|
3164
|
-
results.append(self.parse_ws_ohlcv(ohlcvs[i], market))
|
3165
|
-
return results
|
3166
|
-
|
3167
1077
|
async def fetch_transactions(self, code: str = None, since: Int = None, limit: Int = None, params={}):
|
3168
1078
|
"""
|
3169
1079
|
* @deprecated
|
@@ -3179,56 +1089,6 @@ class Exchange(BaseExchange):
|
|
3179
1089
|
else:
|
3180
1090
|
raise NotSupported(self.id + ' fetchTransactions() is not supported yet')
|
3181
1091
|
|
3182
|
-
def filter_by_array_positions(self, objects, key: IndexType, values=None, indexed=True):
|
3183
|
-
"""
|
3184
|
-
* @ignore
|
3185
|
-
Typed wrapper for filterByArray that returns a list of positions
|
3186
|
-
"""
|
3187
|
-
return self.filter_by_array(objects, key, values, indexed)
|
3188
|
-
|
3189
|
-
def filter_by_array_tickers(self, objects, key: IndexType, values=None, indexed=True):
|
3190
|
-
"""
|
3191
|
-
* @ignore
|
3192
|
-
Typed wrapper for filterByArray that returns a dictionary of tickers
|
3193
|
-
"""
|
3194
|
-
return self.filter_by_array(objects, key, values, indexed)
|
3195
|
-
|
3196
|
-
def resolve_promise_if_messagehash_matches(self, client, prefix: str, symbol: str, data):
|
3197
|
-
messageHashes = self.findMessageHashes(client, prefix)
|
3198
|
-
for i in range(0, len(messageHashes)):
|
3199
|
-
messageHash = messageHashes[i]
|
3200
|
-
parts = messageHash.split('::')
|
3201
|
-
symbolsString = parts[1]
|
3202
|
-
symbols = symbolsString.split(',')
|
3203
|
-
if self.in_array(symbol, symbols):
|
3204
|
-
client.resolve(data, messageHash)
|
3205
|
-
|
3206
|
-
def resolve_multiple_ohlcv(self, client, prefix: str, symbol: str, timeframe: str, data):
|
3207
|
-
messageHashes = self.findMessageHashes(client, 'multipleOHLCV::')
|
3208
|
-
for i in range(0, len(messageHashes)):
|
3209
|
-
messageHash = messageHashes[i]
|
3210
|
-
parts = messageHash.split('::')
|
3211
|
-
symbolsAndTimeframes = parts[1]
|
3212
|
-
splitted = symbolsAndTimeframes.split(',')
|
3213
|
-
id = symbol + '#' + timeframe
|
3214
|
-
if self.in_array(id, splitted):
|
3215
|
-
client.resolve([symbol, timeframe, data], messageHash)
|
3216
|
-
|
3217
|
-
def create_ohlcv_object(self, symbol: str, timeframe: str, data):
|
3218
|
-
res = {}
|
3219
|
-
res[symbol] = {}
|
3220
|
-
res[symbol][timeframe] = data
|
3221
|
-
return res
|
3222
|
-
|
3223
|
-
def handle_max_entries_per_request_and_params(self, method: str, maxEntriesPerRequest: Int = None, params={}):
|
3224
|
-
newMaxEntriesPerRequest = None
|
3225
|
-
newMaxEntriesPerRequest, params = self.handle_option_and_params(params, method, 'maxEntriesPerRequest')
|
3226
|
-
if (newMaxEntriesPerRequest is not None) and (newMaxEntriesPerRequest != maxEntriesPerRequest):
|
3227
|
-
maxEntriesPerRequest = newMaxEntriesPerRequest
|
3228
|
-
if maxEntriesPerRequest is None:
|
3229
|
-
maxEntriesPerRequest = 1000 # default to 1000
|
3230
|
-
return [maxEntriesPerRequest, params]
|
3231
|
-
|
3232
1092
|
async def fetch_paginated_call_dynamic(self, method: str, symbol: str = None, since: Int = None, limit: Int = None, params={}, maxEntriesPerRequest: Int = None):
|
3233
1093
|
maxCalls = None
|
3234
1094
|
maxCalls, params = self.handle_option_and_params(params, method, 'paginationCalls', 10)
|
@@ -3402,75 +1262,3 @@ class Exchange(BaseExchange):
|
|
3402
1262
|
sorted = self.sortCursorPaginatedResult(result)
|
3403
1263
|
key = 0 if (method == 'fetchOHLCV') else 'timestamp'
|
3404
1264
|
return self.filter_by_since_limit(sorted, since, limit, key)
|
3405
|
-
|
3406
|
-
def sort_cursor_paginated_result(self, result):
|
3407
|
-
first = self.safe_value(result, 0)
|
3408
|
-
if first is not None:
|
3409
|
-
if 'timestamp' in first:
|
3410
|
-
return self.sort_by(result, 'timestamp')
|
3411
|
-
if 'id' in first:
|
3412
|
-
return self.sort_by(result, 'id')
|
3413
|
-
return result
|
3414
|
-
|
3415
|
-
def remove_repeated_elements_from_array(self, input):
|
3416
|
-
uniqueResult = {}
|
3417
|
-
for i in range(0, len(input)):
|
3418
|
-
entry = input[i]
|
3419
|
-
id = self.safe_string(entry, 'id')
|
3420
|
-
if id is not None:
|
3421
|
-
if self.safe_string(uniqueResult, id) is None:
|
3422
|
-
uniqueResult[id] = entry
|
3423
|
-
else:
|
3424
|
-
timestamp = self.safe_integer_2(entry, 'timestamp', 0)
|
3425
|
-
if timestamp is not None:
|
3426
|
-
if self.safe_string(uniqueResult, timestamp) is None:
|
3427
|
-
uniqueResult[timestamp] = entry
|
3428
|
-
values = list(uniqueResult.values())
|
3429
|
-
valuesLength = len(values)
|
3430
|
-
if valuesLength > 0:
|
3431
|
-
return values
|
3432
|
-
return input
|
3433
|
-
|
3434
|
-
def handle_until_option(self, key, request, params, multiplier=1):
|
3435
|
-
until = self.safe_value_2(params, 'until', 'till')
|
3436
|
-
if until is not None:
|
3437
|
-
request[key] = self.parseToInt(until * multiplier)
|
3438
|
-
params = self.omit(params, ['until', 'till'])
|
3439
|
-
return [request, params]
|
3440
|
-
|
3441
|
-
def safe_open_interest(self, interest, market=None):
|
3442
|
-
return self.extend(interest, {
|
3443
|
-
'symbol': self.safe_string(market, 'symbol'),
|
3444
|
-
'baseVolume': self.safe_number(interest, 'baseVolume'), # deprecated
|
3445
|
-
'quoteVolume': self.safe_number(interest, 'quoteVolume'), # deprecated
|
3446
|
-
'openInterestAmount': self.safe_number(interest, 'openInterestAmount'),
|
3447
|
-
'openInterestValue': self.safe_number(interest, 'openInterestValue'),
|
3448
|
-
'timestamp': self.safe_integer(interest, 'timestamp'),
|
3449
|
-
'datetime': self.safe_string(interest, 'datetime'),
|
3450
|
-
'info': self.safe_value(interest, 'info'),
|
3451
|
-
})
|
3452
|
-
|
3453
|
-
def parse_liquidation(self, liquidation, market=None):
|
3454
|
-
raise NotSupported(self.id + ' parseLiquidation() is not supported yet')
|
3455
|
-
|
3456
|
-
def parse_liquidations(self, liquidations, market=None, since: Int = None, limit: Int = None):
|
3457
|
-
"""
|
3458
|
-
* @ignore
|
3459
|
-
parses liquidation info from the exchange response
|
3460
|
-
:param dict[] liquidations: each item describes an instance of a liquidation event
|
3461
|
-
:param dict market: ccxt market
|
3462
|
-
:param int [since]: when defined, the response items are filtered to only include items after self timestamp
|
3463
|
-
:param int [limit]: limits the number of items in the response
|
3464
|
-
:returns dict[]: an array of `liquidation structures <https://github.com/ccxt/ccxt/wiki/Manual#liquidation-structure>`
|
3465
|
-
"""
|
3466
|
-
result = []
|
3467
|
-
for i in range(0, len(liquidations)):
|
3468
|
-
entry = liquidations[i]
|
3469
|
-
parsed = self.parseLiquidation(entry, market)
|
3470
|
-
result.append(parsed)
|
3471
|
-
sorted = self.sort_by(result, 'timestamp')
|
3472
|
-
symbol = self.safe_string(market, 'symbol')
|
3473
|
-
return self.filter_by_symbol_since_limit(sorted, symbol, since, limit)
|
3474
|
-
|
3475
|
-
def parse_greeks(self, greeks, market=None):
|
3476
|
-
raise NotSupported(self.id + ' parseGreeks() is not supported yet')
|