ccxt 4.0.100__py2.py3-none-any.whl → 4.0.102__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ccxt/__init__.py +1 -3
- ccxt/abstract/binance.py +8 -0
- ccxt/abstract/binancecoinm.py +8 -0
- ccxt/abstract/binanceus.py +8 -0
- ccxt/abstract/binanceusdm.py +8 -0
- ccxt/abstract/bingx.py +16 -1
- ccxt/async_support/__init__.py +1 -3
- ccxt/async_support/base/exchange.py +1 -1
- ccxt/async_support/binance.py +36 -1
- ccxt/async_support/bingx.py +41 -4
- ccxt/async_support/bitbank.py +11 -0
- ccxt/async_support/bitfinex.py +12 -8
- ccxt/async_support/bitflyer.py +39 -10
- ccxt/async_support/bitforex.py +0 -8
- ccxt/async_support/bitget.py +15 -5
- ccxt/async_support/bitmart.py +66 -0
- ccxt/async_support/bitstamp1.py +22 -0
- ccxt/async_support/bl3p.py +32 -0
- ccxt/async_support/bybit.py +120 -48
- ccxt/async_support/coinbasepro.py +11 -0
- ccxt/async_support/currencycom.py +1 -1
- ccxt/async_support/gemini.py +1 -0
- ccxt/async_support/huobi.py +1 -1
- ccxt/async_support/huobijp.py +1 -1
- ccxt/async_support/idex.py +1 -1
- ccxt/async_support/kucoinfutures.py +46 -51
- ccxt/async_support/lbank.py +1 -1
- ccxt/async_support/lbank2.py +1 -1
- ccxt/base/exchange.py +1 -1
- ccxt/binance.py +36 -1
- ccxt/bingx.py +41 -4
- ccxt/bitbank.py +11 -0
- ccxt/bitfinex.py +12 -8
- ccxt/bitflyer.py +39 -10
- ccxt/bitforex.py +0 -8
- ccxt/bitget.py +15 -5
- ccxt/bitmart.py +66 -0
- ccxt/bitstamp1.py +22 -0
- ccxt/bl3p.py +32 -0
- ccxt/bybit.py +120 -48
- ccxt/coinbasepro.py +11 -0
- ccxt/currencycom.py +1 -1
- ccxt/gemini.py +1 -0
- ccxt/huobi.py +1 -1
- ccxt/huobijp.py +1 -1
- ccxt/idex.py +1 -1
- ccxt/kucoinfutures.py +46 -51
- ccxt/lbank.py +1 -1
- ccxt/lbank2.py +1 -1
- ccxt/pro/__init__.py +1 -1
- ccxt/pro/binance.py +7 -7
- ccxt/pro/bybit.py +16 -16
- ccxt/pro/coinbasepro.py +10 -10
- ccxt/pro/huobijp.py +1 -2
- ccxt/pro/krakenfutures.py +7 -7
- ccxt/pro/kucoin.py +42 -2
- ccxt/pro/kucoinfutures.py +3 -3
- ccxt/pro/phemex.py +2 -2
- ccxt/test/test_async.py +1 -1
- ccxt/test/test_sync.py +1 -1
- {ccxt-4.0.100.dist-info → ccxt-4.0.102.dist-info}/METADATA +6 -7
- {ccxt-4.0.100.dist-info → ccxt-4.0.102.dist-info}/RECORD +64 -65
- ccxt/abstract/bkex.py +0 -58
- {ccxt-4.0.100.dist-info → ccxt-4.0.102.dist-info}/WHEEL +0 -0
- {ccxt-4.0.100.dist-info → ccxt-4.0.102.dist-info}/top_level.txt +0 -0
ccxt/pro/bybit.py
CHANGED
@@ -353,16 +353,16 @@ class bybit(ccxt.async_support.bybit):
|
|
353
353
|
firstSymbol = None
|
354
354
|
for i in range(0, len(symbolsAndTimeframes)):
|
355
355
|
data = symbolsAndTimeframes[i]
|
356
|
-
|
357
|
-
|
358
|
-
market = self.market(
|
359
|
-
|
356
|
+
symbolString = self.safe_string(data, 0)
|
357
|
+
timeframeString = self.safe_string(data, 1)
|
358
|
+
market = self.market(symbolString)
|
359
|
+
symbolString = market['symbol']
|
360
360
|
if i == 0:
|
361
361
|
firstSymbol = market['symbol']
|
362
|
-
timeframeId = self.safe_string(self.timeframes,
|
362
|
+
timeframeId = self.safe_string(self.timeframes, timeframeString, timeframeString)
|
363
363
|
topic = 'kline.' + timeframeId + '.' + market['id']
|
364
364
|
topics.append(topic)
|
365
|
-
hashes.append(
|
365
|
+
hashes.append(symbolString + '#' + timeframeString)
|
366
366
|
messageHash = 'multipleOHLCV::' + ','.join(hashes)
|
367
367
|
url = self.get_url_by_market_type(firstSymbol, False, params)
|
368
368
|
symbol, timeframe, stored = await self.watch_topics(url, messageHash, topics, params)
|
@@ -861,8 +861,8 @@ class bybit(ccxt.async_support.bybit):
|
|
861
861
|
trades.append(parsed)
|
862
862
|
keys = list(symbols.keys())
|
863
863
|
for i in range(0, len(keys)):
|
864
|
-
|
865
|
-
client.resolve(trades,
|
864
|
+
currentMessageHash = 'myTrades:' + keys[i]
|
865
|
+
client.resolve(trades, currentMessageHash)
|
866
866
|
# non-symbol specific
|
867
867
|
messageHash = 'myTrades'
|
868
868
|
client.resolve(trades, messageHash)
|
@@ -988,22 +988,22 @@ class bybit(ccxt.async_support.bybit):
|
|
988
988
|
first = self.safe_value(rawOrders, 0, {})
|
989
989
|
category = self.safe_string(first, 'category')
|
990
990
|
isSpot = category == 'spot'
|
991
|
-
|
992
|
-
if isSpot:
|
993
|
-
parser = 'parseWsSpotOrder'
|
994
|
-
else:
|
995
|
-
parser = 'parseContractOrder'
|
991
|
+
if not isSpot:
|
996
992
|
rawOrders = self.safe_value(rawOrders, 'result', rawOrders)
|
997
993
|
symbols = {}
|
998
994
|
for i in range(0, len(rawOrders)):
|
999
|
-
parsed =
|
995
|
+
parsed = None
|
996
|
+
if isSpot:
|
997
|
+
parsed = self.parse_ws_spot_order(rawOrders[i])
|
998
|
+
else:
|
999
|
+
parsed = self.parse_order(rawOrders[i])
|
1000
1000
|
symbol = parsed['symbol']
|
1001
1001
|
symbols[symbol] = True
|
1002
1002
|
orders.append(parsed)
|
1003
1003
|
symbolsArray = list(symbols.keys())
|
1004
1004
|
for i in range(0, len(symbolsArray)):
|
1005
|
-
|
1006
|
-
client.resolve(orders,
|
1005
|
+
currentMessageHash = 'orders:' + symbolsArray[i]
|
1006
|
+
client.resolve(orders, currentMessageHash)
|
1007
1007
|
messageHash = 'orders'
|
1008
1008
|
client.resolve(orders, messageHash)
|
1009
1009
|
|
ccxt/pro/coinbasepro.py
CHANGED
@@ -496,11 +496,11 @@ class coinbasepro(ccxt.async_support.coinbasepro):
|
|
496
496
|
# reason: 'filled'
|
497
497
|
# }
|
498
498
|
#
|
499
|
-
|
500
|
-
if
|
499
|
+
currentOrders = self.orders
|
500
|
+
if currentOrders is None:
|
501
501
|
limit = self.safe_integer(self.options, 'ordersLimit', 1000)
|
502
|
-
|
503
|
-
self.orders =
|
502
|
+
currentOrders = ArrayCacheBySymbolById(limit)
|
503
|
+
self.orders = currentOrders
|
504
504
|
type = self.safe_string(message, 'type')
|
505
505
|
marketId = self.safe_string(message, 'product_id')
|
506
506
|
if marketId is not None:
|
@@ -533,9 +533,9 @@ class coinbasepro(ccxt.async_support.coinbasepro):
|
|
533
533
|
totalAmount = 0
|
534
534
|
trades = previousOrder['trades']
|
535
535
|
for i in range(0, len(trades)):
|
536
|
-
|
537
|
-
totalCost = self.sum(totalCost,
|
538
|
-
totalAmount = self.sum(totalAmount,
|
536
|
+
tradeEntry = trades[i]
|
537
|
+
totalCost = self.sum(totalCost, tradeEntry['cost'])
|
538
|
+
totalAmount = self.sum(totalAmount, tradeEntry['amount'])
|
539
539
|
if totalAmount > 0:
|
540
540
|
previousOrder['average'] = totalCost / totalAmount
|
541
541
|
previousOrder['cost'] = totalCost
|
@@ -646,12 +646,12 @@ class coinbasepro(ccxt.async_support.coinbasepro):
|
|
646
646
|
client.resolve(ticker, messageHash)
|
647
647
|
messageHashes = self.find_message_hashes(client, 'tickers::')
|
648
648
|
for i in range(0, len(messageHashes)):
|
649
|
-
|
650
|
-
parts =
|
649
|
+
currentMessageHash = messageHashes[i]
|
650
|
+
parts = currentMessageHash.split('::')
|
651
651
|
symbolsString = parts[1]
|
652
652
|
symbols = symbolsString.split(',')
|
653
653
|
if self.in_array(symbol, symbols):
|
654
|
-
client.resolve(ticker,
|
654
|
+
client.resolve(ticker, currentMessageHash)
|
655
655
|
return message
|
656
656
|
|
657
657
|
def parse_ticker(self, ticker, market=None):
|
ccxt/pro/huobijp.py
CHANGED
@@ -316,8 +316,7 @@ class huobijp(ccxt.async_support.huobijp):
|
|
316
316
|
# unroll the accumulated deltas
|
317
317
|
messages = orderbook.cache
|
318
318
|
for i in range(0, len(messages)):
|
319
|
-
|
320
|
-
self.handle_order_book_message(client, message, orderbook)
|
319
|
+
self.handle_order_book_message(client, messages[i], orderbook)
|
321
320
|
self.orderbooks[symbol] = orderbook
|
322
321
|
client.resolve(orderbook, messageHash)
|
323
322
|
|
ccxt/pro/krakenfutures.py
CHANGED
@@ -482,9 +482,9 @@ class krakenfutures(ccxt.async_support.krakenfutures):
|
|
482
482
|
totalAmount = '0'
|
483
483
|
trades = previousOrder['trades']
|
484
484
|
for i in range(0, len(trades)):
|
485
|
-
|
486
|
-
totalCost = Precise.string_add(totalCost, self.number_to_string(
|
487
|
-
totalAmount = Precise.string_add(totalAmount, self.number_to_string(
|
485
|
+
currentTrade = trades[i]
|
486
|
+
totalCost = Precise.string_add(totalCost, self.number_to_string(currentTrade['cost']))
|
487
|
+
totalAmount = Precise.string_add(totalAmount, self.number_to_string(currentTrade['amount']))
|
488
488
|
if Precise.string_gt(totalAmount, '0'):
|
489
489
|
previousOrder['average'] = Precise.string_div(totalCost, totalAmount)
|
490
490
|
previousOrder['cost'] = totalCost
|
@@ -511,13 +511,13 @@ class krakenfutures(ccxt.async_support.krakenfutures):
|
|
511
511
|
if isCancel:
|
512
512
|
# get order without symbol
|
513
513
|
for i in range(0, len(orders)):
|
514
|
-
|
515
|
-
if
|
516
|
-
orders[i] = self.extend(
|
514
|
+
currentOrder = orders[i]
|
515
|
+
if currentOrder['id'] == message['order_id']:
|
516
|
+
orders[i] = self.extend(currentOrder, {
|
517
517
|
'status': 'canceled',
|
518
518
|
})
|
519
519
|
client.resolve(orders, 'orders')
|
520
|
-
client.resolve(orders, 'orders:' +
|
520
|
+
client.resolve(orders, 'orders:' + currentOrder['symbol'])
|
521
521
|
break
|
522
522
|
return message
|
523
523
|
|
ccxt/pro/kucoin.py
CHANGED
@@ -21,7 +21,7 @@ class kucoin(ccxt.async_support.kucoin):
|
|
21
21
|
'watchOrderBook': True,
|
22
22
|
'watchOrders': True,
|
23
23
|
'watchMyTrades': True,
|
24
|
-
'watchTickers':
|
24
|
+
'watchTickers': True,
|
25
25
|
'watchTicker': True,
|
26
26
|
'watchTrades': True,
|
27
27
|
'watchTradesForSymbols': True,
|
@@ -133,6 +133,25 @@ class kucoin(ccxt.async_support.kucoin):
|
|
133
133
|
messageHash = 'ticker:' + symbol
|
134
134
|
return await self.subscribe(url, messageHash, topic, query)
|
135
135
|
|
136
|
+
async def watch_tickers(self, symbols: Optional[List[str]] = None, params={}):
|
137
|
+
"""
|
138
|
+
watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
|
139
|
+
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
140
|
+
:param dict [params]: extra parameters specific to the kucoin api endpoint
|
141
|
+
:returns dict: a `ticker structure <https://github.com/ccxt/ccxt/wiki/Manual#ticker-structure>`
|
142
|
+
"""
|
143
|
+
await self.load_markets()
|
144
|
+
symbols = self.market_symbols(symbols)
|
145
|
+
messageHash = 'tickers'
|
146
|
+
if symbols is not None:
|
147
|
+
messageHash = 'tickers::' + ','.join(symbols)
|
148
|
+
url = await self.negotiate(False)
|
149
|
+
topic = '/market/ticker:all'
|
150
|
+
tickers = await self.subscribe(url, messageHash, topic, params)
|
151
|
+
if self.newUpdates:
|
152
|
+
return tickers
|
153
|
+
return self.filter_by_array(self.tickers, 'symbol', symbols)
|
154
|
+
|
136
155
|
def handle_ticker(self, client: Client, message):
|
137
156
|
#
|
138
157
|
# market/snapshot
|
@@ -192,7 +211,12 @@ class kucoin(ccxt.async_support.kucoin):
|
|
192
211
|
market = None
|
193
212
|
if topic is not None:
|
194
213
|
parts = topic.split(':')
|
195
|
-
|
214
|
+
first = self.safe_string(parts, 1)
|
215
|
+
marketId = None
|
216
|
+
if first == 'all':
|
217
|
+
marketId = self.safe_string(message, 'subject')
|
218
|
+
else:
|
219
|
+
marketId = first
|
196
220
|
market = self.safe_market(marketId, market, '-')
|
197
221
|
data = self.safe_value(message, 'data', {})
|
198
222
|
rawTicker = self.safe_value(data, 'data', data)
|
@@ -201,6 +225,19 @@ class kucoin(ccxt.async_support.kucoin):
|
|
201
225
|
self.tickers[symbol] = ticker
|
202
226
|
messageHash = 'ticker:' + symbol
|
203
227
|
client.resolve(ticker, messageHash)
|
228
|
+
# watchTickers
|
229
|
+
client.resolve(ticker, 'tickers')
|
230
|
+
messageHashes = self.find_message_hashes(client, 'tickers::')
|
231
|
+
for i in range(0, len(messageHashes)):
|
232
|
+
currentMessageHash = messageHashes[i]
|
233
|
+
parts = currentMessageHash.split('::')
|
234
|
+
symbolsString = parts[1]
|
235
|
+
symbols = symbolsString.split(',')
|
236
|
+
tickers = self.filter_by_array(self.tickers, 'symbol', symbols)
|
237
|
+
tickersSymbols = list(tickers.keys())
|
238
|
+
numTickers = len(tickersSymbols)
|
239
|
+
if numTickers > 0:
|
240
|
+
client.resolve(tickers, currentMessageHash)
|
204
241
|
|
205
242
|
async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Optional[int] = None, limit: Optional[int] = None, params={}):
|
206
243
|
"""
|
@@ -828,6 +865,9 @@ class kucoin(ccxt.async_support.kucoin):
|
|
828
865
|
# }
|
829
866
|
# }
|
830
867
|
#
|
868
|
+
topic = self.safe_string(message, 'topic')
|
869
|
+
if topic == '/market/ticker:all':
|
870
|
+
return self.handle_ticker(client, message)
|
831
871
|
subject = self.safe_string(message, 'subject')
|
832
872
|
methods = {
|
833
873
|
'trade.l2update': self.handle_order_book,
|
ccxt/pro/kucoinfutures.py
CHANGED
@@ -369,9 +369,9 @@ class kucoinfutures(ccxt.async_support.kucoinfutures):
|
|
369
369
|
deltaEnd = self.safe_integer(data, 'sequence')
|
370
370
|
if nonce is None:
|
371
371
|
cacheLength = len(storedOrderBook.cache)
|
372
|
-
|
373
|
-
topicSymbol = self.safe_string(
|
374
|
-
topicChannel = self.safe_string(
|
372
|
+
topicPartsNew = topic.split(':')
|
373
|
+
topicSymbol = self.safe_string(topicPartsNew, 1)
|
374
|
+
topicChannel = self.safe_string(topicPartsNew, 0)
|
375
375
|
subscriptions = list(client.subscriptions.keys())
|
376
376
|
subscription = None
|
377
377
|
for i in range(0, len(subscriptions)):
|
ccxt/pro/phemex.py
CHANGED
@@ -1343,8 +1343,8 @@ class phemex(ccxt.async_support.phemex):
|
|
1343
1343
|
del client.subscriptions[id]
|
1344
1344
|
if method is not True:
|
1345
1345
|
return method(client, message)
|
1346
|
-
|
1347
|
-
if ('market24h' in message) or ('spot_market24h' in message) or (
|
1346
|
+
methodName = self.safe_string(message, 'method', '')
|
1347
|
+
if ('market24h' in message) or ('spot_market24h' in message) or (methodName.find('perp_market24h_pack_p') >= 0):
|
1348
1348
|
return self.handle_ticker(client, message)
|
1349
1349
|
elif ('trades' in message) or ('trades_p' in message):
|
1350
1350
|
return self.handle_trades(client, message)
|
ccxt/test/test_async.py
CHANGED
@@ -695,7 +695,7 @@ class testMainClass(baseMainTestClass):
|
|
695
695
|
dump(self.add_padding('[INFO:PRIVATE_TESTS_DONE]', 25), exchange.id)
|
696
696
|
|
697
697
|
async def start_test(self, exchange, symbol):
|
698
|
-
# we
|
698
|
+
# we do not need to test aliases
|
699
699
|
if exchange.alias:
|
700
700
|
return
|
701
701
|
if self.sandbox or get_exchange_prop(exchange, 'sandbox'):
|
ccxt/test/test_sync.py
CHANGED
@@ -694,7 +694,7 @@ class testMainClass(baseMainTestClass):
|
|
694
694
|
dump(self.add_padding('[INFO:PRIVATE_TESTS_DONE]', 25), exchange.id)
|
695
695
|
|
696
696
|
def start_test(self, exchange, symbol):
|
697
|
-
# we
|
697
|
+
# we do not need to test aliases
|
698
698
|
if exchange.alias:
|
699
699
|
return
|
700
700
|
if self.sandbox or get_exchange_prop(exchange, 'sandbox'):
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: ccxt
|
3
|
-
Version: 4.0.
|
3
|
+
Version: 4.0.102
|
4
4
|
Summary: A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 130+ exchanges
|
5
5
|
Home-page: https://ccxt.com
|
6
6
|
Author: Igor Kroitor
|
@@ -44,7 +44,7 @@ Requires-Dist: flake8 (==3.7.9) ; extra == 'qa'
|
|
44
44
|
|
45
45
|
# CCXT – CryptoCurrency eXchange Trading Library
|
46
46
|
|
47
|
-
[](https://travis-ci.com/ccxt/ccxt) [](https://npmjs.com/package/ccxt) [](https://pypi.python.org/pypi/ccxt) [](https://www.npmjs.com/package/ccxt) [](https://discord.gg/ccxt) [](https://travis-ci.com/ccxt/ccxt) [](https://npmjs.com/package/ccxt) [](https://pypi.python.org/pypi/ccxt) [](https://www.npmjs.com/package/ccxt) [](https://discord.gg/ccxt) [](https://github.com/ccxt/ccxt/wiki/Exchange-Markets) [](https://twitter.com/ccxt_official)
|
48
48
|
|
49
49
|
A JavaScript / Python / PHP / C# library for cryptocurrency trading and e-commerce with support for many bitcoin/ether/altcoin exchange markets and merchant APIs.
|
50
50
|
|
@@ -100,7 +100,7 @@ Current feature list:
|
|
100
100
|
|
101
101
|
## Supported Cryptocurrency Exchange Markets
|
102
102
|
|
103
|
-
The CCXT library currently supports the following
|
103
|
+
The CCXT library currently supports the following 97 cryptocurrency exchange markets and trading APIs:
|
104
104
|
|
105
105
|
| logo | id | name | ver | certified | pro |
|
106
106
|
|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------|---------------------------------------------------------------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------:|-----------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------|
|
@@ -133,7 +133,6 @@ The CCXT library currently supports the following 98 cryptocurrency exchange mar
|
|
133
133
|
| [](https://www.bitstamp.net) | bitstamp1 | [Bitstamp](https://www.bitstamp.net) | [](https://www.bitstamp.net/api) | | |
|
134
134
|
| [](https://bittrex.com/Account/Register?referralCode=1ZE-G0G-M3B) | bittrex | [Bittrex](https://bittrex.com/Account/Register?referralCode=1ZE-G0G-M3B) | [](https://bittrex.github.io/api/v3) | | [](https://ccxt.pro) |
|
135
135
|
| [](https://bitvavo.com/?a=24F34952F7) | bitvavo | [Bitvavo](https://bitvavo.com/?a=24F34952F7) | [](https://docs.bitvavo.com/) | [](https://github.com/ccxt/ccxt/wiki/Certification) | [](https://ccxt.pro) |
|
136
|
-
| [](https://www.bkex.com/) | bkex | [BKEX](https://www.bkex.com/) | [](https://bkexapi.github.io/docs/api_en.htm) | | |
|
137
136
|
| [](https://bl3p.eu) | bl3p | [BL3P](https://bl3p.eu) | [](https://github.com/BitonicNL/bl3p-api/tree/master/docs) | | |
|
138
137
|
| [](https://blockchain.com) | blockchaincom | [Blockchain.com](https://blockchain.com) | [](https://api.blockchain.com/v3) | | [](https://ccxt.pro) |
|
139
138
|
| [](https://btc-alpha.com/?r=123788) | btcalpha | [BTC-Alpha](https://btc-alpha.com/?r=123788) | [](https://btc-alpha.github.io/api-docs) | | |
|
@@ -259,13 +258,13 @@ console.log(version, Object.keys(exchanges));
|
|
259
258
|
|
260
259
|
All-in-one browser bundle (dependencies included), served from a CDN of your choice:
|
261
260
|
|
262
|
-
* jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.0.
|
263
|
-
* unpkg: https://unpkg.com/ccxt@4.0.
|
261
|
+
* jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.0.102/dist/ccxt.browser.js
|
262
|
+
* unpkg: https://unpkg.com/ccxt@4.0.102/dist/ccxt.browser.js
|
264
263
|
|
265
264
|
CDNs are not updated in real-time and may have delays. Defaulting to the most recent version without specifying the version number is not recommended. Please, keep in mind that we are not responsible for the correct operation of those CDN servers.
|
266
265
|
|
267
266
|
```HTML
|
268
|
-
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.0.
|
267
|
+
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.0.102/dist/ccxt.browser.js"></script>
|
269
268
|
```
|
270
269
|
|
271
270
|
Creates a global `ccxt` object:
|