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.

Files changed (251) hide show
  1. ccxt/__init__.py +2 -2
  2. ccxt/abstract/binance.py +1 -0
  3. ccxt/abstract/binancecoinm.py +1 -0
  4. ccxt/abstract/binanceus.py +1 -0
  5. ccxt/abstract/binanceusdm.py +1 -0
  6. ccxt/abstract/bitbank.py +1 -0
  7. ccxt/abstract/coinbase.py +2 -0
  8. ccxt/abstract/htx.py +3 -0
  9. ccxt/abstract/huobi.py +3 -0
  10. ccxt/abstract/huobipro.py +3 -0
  11. ccxt/abstract/okex.py +3 -1
  12. ccxt/abstract/okex5.py +3 -1
  13. ccxt/abstract/okx.py +3 -1
  14. ccxt/ace.py +23 -23
  15. ccxt/alpaca.py +8 -8
  16. ccxt/ascendex.py +26 -26
  17. ccxt/async_support/__init__.py +2 -2
  18. ccxt/async_support/ace.py +23 -23
  19. ccxt/async_support/alpaca.py +8 -8
  20. ccxt/async_support/ascendex.py +26 -26
  21. ccxt/async_support/base/exchange.py +4 -2216
  22. ccxt/async_support/bigone.py +21 -24
  23. ccxt/async_support/binance.py +61 -54
  24. ccxt/async_support/bingx.py +28 -28
  25. ccxt/async_support/bit2c.py +9 -9
  26. ccxt/async_support/bitbank.py +11 -10
  27. ccxt/async_support/bitbns.py +11 -11
  28. ccxt/async_support/bitfinex.py +15 -15
  29. ccxt/async_support/bitfinex2.py +22 -22
  30. ccxt/async_support/bitflyer.py +13 -13
  31. ccxt/async_support/bitforex.py +10 -10
  32. ccxt/async_support/bitget.py +44 -44
  33. ccxt/async_support/bithumb.py +9 -9
  34. ccxt/async_support/bitmart.py +85 -104
  35. ccxt/async_support/bitmex.py +27 -27
  36. ccxt/async_support/bitopro.py +18 -18
  37. ccxt/async_support/bitpanda.py +18 -18
  38. ccxt/async_support/bitrue.py +14 -14
  39. ccxt/async_support/bitso.py +17 -17
  40. ccxt/async_support/bitstamp.py +17 -17
  41. ccxt/async_support/bittrex.py +22 -24
  42. ccxt/async_support/bitvavo.py +15 -15
  43. ccxt/async_support/bl3p.py +4 -4
  44. ccxt/async_support/blockchaincom.py +17 -17
  45. ccxt/async_support/btcalpha.py +14 -14
  46. ccxt/async_support/btcbox.py +9 -9
  47. ccxt/async_support/btcmarkets.py +17 -17
  48. ccxt/async_support/btcturk.py +9 -9
  49. ccxt/async_support/bybit.py +46 -46
  50. ccxt/async_support/cex.py +10 -10
  51. ccxt/async_support/coinbase.py +69 -25
  52. ccxt/async_support/coinbasepro.py +19 -19
  53. ccxt/async_support/coincheck.py +10 -10
  54. ccxt/async_support/coinex.py +57 -66
  55. ccxt/async_support/coinlist.py +22 -22
  56. ccxt/async_support/coinmate.py +10 -10
  57. ccxt/async_support/coinone.py +10 -10
  58. ccxt/async_support/coinsph.py +17 -17
  59. ccxt/async_support/coinspot.py +5 -5
  60. ccxt/async_support/cryptocom.py +27 -27
  61. ccxt/async_support/currencycom.py +18 -18
  62. ccxt/async_support/delta.py +21 -21
  63. ccxt/async_support/deribit.py +24 -24
  64. ccxt/async_support/digifinex.py +35 -35
  65. ccxt/async_support/exmo.py +19 -19
  66. ccxt/async_support/gate.py +38 -38
  67. ccxt/async_support/gemini.py +11 -11
  68. ccxt/async_support/hitbtc.py +27 -27
  69. ccxt/async_support/hollaex.py +19 -19
  70. ccxt/async_support/htx.py +47 -44
  71. ccxt/async_support/huobijp.py +22 -22
  72. ccxt/async_support/idex.py +20 -20
  73. ccxt/async_support/independentreserve.py +9 -9
  74. ccxt/async_support/indodax.py +10 -10
  75. ccxt/async_support/kraken.py +25 -25
  76. ccxt/async_support/krakenfutures.py +17 -17
  77. ccxt/async_support/kucoin.py +27 -27
  78. ccxt/async_support/kucoinfutures.py +20 -20
  79. ccxt/async_support/kuna.py +19 -19
  80. ccxt/async_support/latoken.py +14 -14
  81. ccxt/async_support/lbank.py +18 -18
  82. ccxt/async_support/luno.py +14 -14
  83. ccxt/async_support/lykke.py +12 -12
  84. ccxt/async_support/mercado.py +11 -11
  85. ccxt/async_support/mexc.py +36 -36
  86. ccxt/async_support/ndax.py +18 -18
  87. ccxt/async_support/novadax.py +17 -17
  88. ccxt/async_support/oceanex.py +12 -12
  89. ccxt/async_support/okcoin.py +19 -19
  90. ccxt/async_support/okx.py +48 -45
  91. ccxt/async_support/p2b.py +6 -6
  92. ccxt/async_support/paymium.py +6 -6
  93. ccxt/async_support/phemex.py +57 -57
  94. ccxt/async_support/poloniex.py +31 -30
  95. ccxt/async_support/poloniexfutures.py +16 -16
  96. ccxt/async_support/probit.py +22 -22
  97. ccxt/async_support/tidex.py +15 -15
  98. ccxt/async_support/timex.py +20 -20
  99. ccxt/async_support/tokocrypto.py +16 -16
  100. ccxt/async_support/upbit.py +15 -15
  101. ccxt/async_support/wavesexchange.py +12 -12
  102. ccxt/async_support/wazirx.py +13 -13
  103. ccxt/async_support/whitebit.py +26 -26
  104. ccxt/async_support/woo.py +47 -47
  105. ccxt/async_support/yobit.py +8 -8
  106. ccxt/async_support/zaif.py +10 -10
  107. ccxt/async_support/zonda.py +16 -16
  108. ccxt/base/errors.py +17 -16
  109. ccxt/base/exchange.py +57 -97
  110. ccxt/base/types.py +138 -139
  111. ccxt/bigone.py +21 -24
  112. ccxt/binance.py +61 -54
  113. ccxt/bingx.py +28 -28
  114. ccxt/bit2c.py +9 -9
  115. ccxt/bitbank.py +11 -10
  116. ccxt/bitbns.py +11 -11
  117. ccxt/bitfinex.py +15 -15
  118. ccxt/bitfinex2.py +22 -22
  119. ccxt/bitflyer.py +13 -13
  120. ccxt/bitforex.py +10 -10
  121. ccxt/bitget.py +44 -44
  122. ccxt/bithumb.py +9 -9
  123. ccxt/bitmart.py +85 -104
  124. ccxt/bitmex.py +27 -27
  125. ccxt/bitopro.py +18 -18
  126. ccxt/bitpanda.py +18 -18
  127. ccxt/bitrue.py +14 -14
  128. ccxt/bitso.py +17 -17
  129. ccxt/bitstamp.py +17 -17
  130. ccxt/bittrex.py +22 -24
  131. ccxt/bitvavo.py +15 -15
  132. ccxt/bl3p.py +4 -4
  133. ccxt/blockchaincom.py +17 -17
  134. ccxt/btcalpha.py +14 -14
  135. ccxt/btcbox.py +9 -9
  136. ccxt/btcmarkets.py +17 -17
  137. ccxt/btcturk.py +9 -9
  138. ccxt/bybit.py +46 -46
  139. ccxt/cex.py +10 -10
  140. ccxt/coinbase.py +69 -25
  141. ccxt/coinbasepro.py +19 -19
  142. ccxt/coincheck.py +10 -10
  143. ccxt/coinex.py +57 -66
  144. ccxt/coinlist.py +22 -22
  145. ccxt/coinmate.py +10 -10
  146. ccxt/coinone.py +10 -10
  147. ccxt/coinsph.py +17 -17
  148. ccxt/coinspot.py +5 -5
  149. ccxt/cryptocom.py +27 -27
  150. ccxt/currencycom.py +18 -18
  151. ccxt/delta.py +21 -21
  152. ccxt/deribit.py +24 -24
  153. ccxt/digifinex.py +35 -35
  154. ccxt/exmo.py +19 -19
  155. ccxt/gate.py +38 -38
  156. ccxt/gemini.py +11 -11
  157. ccxt/hitbtc.py +27 -27
  158. ccxt/hollaex.py +19 -19
  159. ccxt/htx.py +47 -44
  160. ccxt/huobijp.py +22 -22
  161. ccxt/idex.py +20 -20
  162. ccxt/independentreserve.py +9 -9
  163. ccxt/indodax.py +10 -10
  164. ccxt/kraken.py +25 -25
  165. ccxt/krakenfutures.py +17 -17
  166. ccxt/kucoin.py +27 -27
  167. ccxt/kucoinfutures.py +20 -20
  168. ccxt/kuna.py +19 -19
  169. ccxt/latoken.py +14 -14
  170. ccxt/lbank.py +18 -18
  171. ccxt/luno.py +14 -14
  172. ccxt/lykke.py +12 -12
  173. ccxt/mercado.py +11 -11
  174. ccxt/mexc.py +36 -36
  175. ccxt/ndax.py +18 -18
  176. ccxt/novadax.py +17 -17
  177. ccxt/oceanex.py +12 -12
  178. ccxt/okcoin.py +19 -19
  179. ccxt/okx.py +48 -45
  180. ccxt/p2b.py +6 -6
  181. ccxt/paymium.py +6 -6
  182. ccxt/phemex.py +57 -57
  183. ccxt/poloniex.py +31 -30
  184. ccxt/poloniexfutures.py +16 -16
  185. ccxt/pro/__init__.py +1 -1
  186. ccxt/pro/alpaca.py +3 -3
  187. ccxt/pro/ascendex.py +2 -2
  188. ccxt/pro/binance.py +9 -9
  189. ccxt/pro/bingx.py +3 -3
  190. ccxt/pro/bitfinex.py +3 -3
  191. ccxt/pro/bitfinex2.py +3 -3
  192. ccxt/pro/bitget.py +3 -3
  193. ccxt/pro/bitmart.py +2 -2
  194. ccxt/pro/bitmex.py +3 -3
  195. ccxt/pro/bitpanda.py +3 -3
  196. ccxt/pro/bitrue.py +2 -2
  197. ccxt/pro/bitstamp.py +2 -2
  198. ccxt/pro/bittrex.py +3 -3
  199. ccxt/pro/bitvavo.py +3 -3
  200. ccxt/pro/blockchaincom.py +2 -2
  201. ccxt/pro/bybit.py +4 -4
  202. ccxt/pro/cex.py +3 -3
  203. ccxt/pro/coinbasepro.py +3 -3
  204. ccxt/pro/coinex.py +2 -2
  205. ccxt/pro/cryptocom.py +5 -5
  206. ccxt/pro/deribit.py +3 -3
  207. ccxt/pro/exmo.py +2 -2
  208. ccxt/pro/gate.py +3 -3
  209. ccxt/pro/gemini.py +2 -2
  210. ccxt/pro/hitbtc.py +4 -4
  211. ccxt/pro/hollaex.py +3 -3
  212. ccxt/pro/htx.py +3 -3
  213. ccxt/pro/idex.py +3 -3
  214. ccxt/pro/kraken.py +7 -7
  215. ccxt/pro/krakenfutures.py +4 -4
  216. ccxt/pro/kucoin.py +3 -3
  217. ccxt/pro/kucoinfutures.py +3 -3
  218. ccxt/pro/mexc.py +3 -3
  219. ccxt/pro/okcoin.py +2 -2
  220. ccxt/pro/okx.py +6 -6
  221. ccxt/pro/phemex.py +3 -3
  222. ccxt/pro/poloniex.py +3 -3
  223. ccxt/pro/poloniexfutures.py +3 -3
  224. ccxt/pro/probit.py +3 -3
  225. ccxt/pro/wazirx.py +3 -3
  226. ccxt/pro/whitebit.py +3 -3
  227. ccxt/pro/woo.py +2 -2
  228. ccxt/probit.py +22 -22
  229. ccxt/test/base/test_shared_methods.py +3 -3
  230. ccxt/test/test_async.py +543 -535
  231. ccxt/test/test_sync.py +542 -534
  232. ccxt/tidex.py +15 -15
  233. ccxt/timex.py +20 -20
  234. ccxt/tokocrypto.py +16 -16
  235. ccxt/upbit.py +15 -15
  236. ccxt/wavesexchange.py +12 -12
  237. ccxt/wazirx.py +13 -13
  238. ccxt/whitebit.py +26 -26
  239. ccxt/woo.py +47 -47
  240. ccxt/yobit.py +8 -8
  241. ccxt/zaif.py +10 -10
  242. ccxt/zonda.py +16 -16
  243. {ccxt-4.1.54.dist-info → ccxt-4.1.56.dist-info}/METADATA +10 -8
  244. ccxt-4.1.56.dist-info/RECORD +449 -0
  245. ccxt/async_support/bitstamp1.py +0 -402
  246. ccxt/async_support/lbank2.py +0 -2620
  247. ccxt/bitstamp1.py +0 -402
  248. ccxt/lbank2.py +0 -2619
  249. ccxt-4.1.54.dist-info/RECORD +0 -453
  250. {ccxt-4.1.54.dist-info → ccxt-4.1.56.dist-info}/WHEEL +0 -0
  251. {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.54'
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, Currency, String, Market
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, AuthenticationError, ExchangeError, ExchangeNotAvailable, RequestTimeout, NotSupported, NullResponse, InvalidOrder, InvalidAddress, RateLimitExceeded
28
- from ccxt.base.decimal_to_precision import TRUNCATE, ROUND, TICK_SIZE, DECIMAL_PLACES, SIGNIFICANT_DIGITS
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')