ccxt 4.4.2__py2.py3-none-any.whl → 4.4.3__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 -1
- ccxt/abstract/bitmart.py +1 -0
- ccxt/async_support/__init__.py +1 -1
- ccxt/async_support/base/exchange.py +1 -1
- ccxt/async_support/binance.py +10 -10
- ccxt/async_support/bitmart.py +3 -1
- ccxt/async_support/bitstamp.py +24 -36
- ccxt/async_support/bybit.py +2 -0
- ccxt/async_support/cryptocom.py +2 -1
- ccxt/async_support/mexc.py +15 -0
- ccxt/async_support/xt.py +5 -1
- ccxt/base/exchange.py +1 -1
- ccxt/binance.py +10 -10
- ccxt/bitmart.py +3 -1
- ccxt/bitstamp.py +24 -36
- ccxt/bybit.py +2 -0
- ccxt/cryptocom.py +2 -1
- ccxt/mexc.py +15 -0
- ccxt/pro/__init__.py +1 -1
- ccxt/pro/cryptocom.py +181 -22
- ccxt/pro/mexc.py +76 -4
- ccxt/pro/okx.py +5 -3
- ccxt/pro/oxfun.py +70 -0
- ccxt/pro/phemex.py +41 -2
- ccxt/pro/woofipro.py +64 -0
- ccxt/xt.py +5 -1
- {ccxt-4.4.2.dist-info → ccxt-4.4.3.dist-info}/METADATA +4 -4
- {ccxt-4.4.2.dist-info → ccxt-4.4.3.dist-info}/RECORD +31 -31
- {ccxt-4.4.2.dist-info → ccxt-4.4.3.dist-info}/LICENSE.txt +0 -0
- {ccxt-4.4.2.dist-info → ccxt-4.4.3.dist-info}/WHEEL +0 -0
- {ccxt-4.4.2.dist-info → ccxt-4.4.3.dist-info}/top_level.txt +0 -0
ccxt/pro/cryptocom.py
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
import ccxt.async_support
|
7
7
|
from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheBySymbolBySide, ArrayCacheByTimestamp
|
8
8
|
import hashlib
|
9
|
-
from ccxt.base.types import Balances, Int, Num, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, Trade
|
9
|
+
from ccxt.base.types import Balances, Int, Market, Num, Order, OrderBook, OrderSide, OrderType, Position, Str, Strings, Ticker, Tickers, Trade
|
10
10
|
from ccxt.async_support.base.ws.client import Client
|
11
11
|
from typing import List
|
12
12
|
from typing import Any
|
@@ -24,7 +24,8 @@ class cryptocom(ccxt.async_support.cryptocom):
|
|
24
24
|
'ws': True,
|
25
25
|
'watchBalance': True,
|
26
26
|
'watchTicker': True,
|
27
|
-
'watchTickers':
|
27
|
+
'watchTickers': True,
|
28
|
+
'watchBidsAsks': True,
|
28
29
|
'watchMyTrades': True,
|
29
30
|
'watchTrades': True,
|
30
31
|
'watchTradesForSymbols': True,
|
@@ -443,40 +444,198 @@ class cryptocom(ccxt.async_support.cryptocom):
|
|
443
444
|
messageHash = 'unsubscribe:ticker:' + market['symbol']
|
444
445
|
return await self.un_watch_public_multiple('ticker', [market['symbol']], [messageHash], [subMessageHash], [subMessageHash], params)
|
445
446
|
|
447
|
+
async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
|
448
|
+
"""
|
449
|
+
watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
|
450
|
+
:see: https://exchange-docs.crypto.com/exchange/v1/rest-ws/index.html#ticker-instrument_name
|
451
|
+
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
452
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
453
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
454
|
+
"""
|
455
|
+
await self.load_markets()
|
456
|
+
symbols = self.market_symbols(symbols, None, False)
|
457
|
+
messageHashes = []
|
458
|
+
marketIds = self.market_ids(symbols)
|
459
|
+
for i in range(0, len(marketIds)):
|
460
|
+
marketId = marketIds[i]
|
461
|
+
messageHashes.append('ticker.' + marketId)
|
462
|
+
url = self.urls['api']['ws']['public']
|
463
|
+
id = self.nonce()
|
464
|
+
request: dict = {
|
465
|
+
'method': 'subscribe',
|
466
|
+
'params': {
|
467
|
+
'channels': messageHashes,
|
468
|
+
},
|
469
|
+
'nonce': id,
|
470
|
+
}
|
471
|
+
ticker = await self.watch_multiple(url, messageHashes, self.extend(request, params), messageHashes)
|
472
|
+
if self.newUpdates:
|
473
|
+
result: dict = {}
|
474
|
+
result[ticker['symbol']] = ticker
|
475
|
+
return result
|
476
|
+
return self.filter_by_array(self.tickers, 'symbol', symbols)
|
477
|
+
|
478
|
+
async def un_watch_tickers(self, symbols: Strings = None, params={}) -> Any:
|
479
|
+
"""
|
480
|
+
unWatches a price ticker
|
481
|
+
:see: https://exchange-docs.crypto.com/exchange/v1/rest-ws/index.html#ticker-instrument_name
|
482
|
+
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
483
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
484
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
485
|
+
"""
|
486
|
+
await self.load_markets()
|
487
|
+
symbols = self.market_symbols(symbols, None, False)
|
488
|
+
messageHashes = []
|
489
|
+
subMessageHashes = []
|
490
|
+
marketIds = self.market_ids(symbols)
|
491
|
+
for i in range(0, len(marketIds)):
|
492
|
+
marketId = marketIds[i]
|
493
|
+
symbol = symbols[i]
|
494
|
+
subMessageHashes.append('ticker.' + marketId)
|
495
|
+
messageHashes.append('unsubscribe:ticker:' + symbol)
|
496
|
+
return await self.un_watch_public_multiple('ticker', symbols, messageHashes, subMessageHashes, subMessageHashes, params)
|
497
|
+
|
446
498
|
def handle_ticker(self, client: Client, message):
|
447
499
|
#
|
448
|
-
#
|
449
|
-
#
|
450
|
-
#
|
451
|
-
#
|
452
|
-
#
|
453
|
-
#
|
454
|
-
#
|
455
|
-
#
|
456
|
-
#
|
457
|
-
#
|
458
|
-
#
|
459
|
-
#
|
460
|
-
#
|
461
|
-
#
|
462
|
-
#
|
463
|
-
#
|
464
|
-
#
|
465
|
-
#
|
500
|
+
# {
|
501
|
+
# "instrument_name": "ETHUSD-PERP",
|
502
|
+
# "subscription": "ticker.ETHUSD-PERP",
|
503
|
+
# "channel": "ticker",
|
504
|
+
# "data": [
|
505
|
+
# {
|
506
|
+
# "h": "2400.20",
|
507
|
+
# "l": "2277.10",
|
508
|
+
# "a": "2335.25",
|
509
|
+
# "c": "-0.0022",
|
510
|
+
# "b": "2335.10",
|
511
|
+
# "bs": "5.4000",
|
512
|
+
# "k": "2335.16",
|
513
|
+
# "ks": "1.9970",
|
514
|
+
# "i": "ETHUSD-PERP",
|
515
|
+
# "v": "1305697.6462",
|
516
|
+
# "vv": "3058704939.17",
|
517
|
+
# "oi": "161646.3614",
|
518
|
+
# "t": 1726069647560
|
519
|
+
# }
|
520
|
+
# ]
|
466
521
|
# }
|
467
|
-
# }
|
468
522
|
#
|
523
|
+
self.handle_bid_ask(client, message)
|
469
524
|
messageHash = self.safe_string(message, 'subscription')
|
470
525
|
marketId = self.safe_string(message, 'instrument_name')
|
471
526
|
market = self.safe_market(marketId)
|
472
527
|
data = self.safe_value(message, 'data', [])
|
473
528
|
for i in range(0, len(data)):
|
474
529
|
ticker = data[i]
|
475
|
-
parsed = self.
|
530
|
+
parsed = self.parse_ws_ticker(ticker, market)
|
476
531
|
symbol = parsed['symbol']
|
477
532
|
self.tickers[symbol] = parsed
|
478
533
|
client.resolve(parsed, messageHash)
|
479
534
|
|
535
|
+
def parse_ws_ticker(self, ticker: dict, market: Market = None) -> Ticker:
|
536
|
+
#
|
537
|
+
# {
|
538
|
+
# "h": "2400.20",
|
539
|
+
# "l": "2277.10",
|
540
|
+
# "a": "2335.25",
|
541
|
+
# "c": "-0.0022",
|
542
|
+
# "b": "2335.10",
|
543
|
+
# "bs": "5.4000",
|
544
|
+
# "k": "2335.16",
|
545
|
+
# "ks": "1.9970",
|
546
|
+
# "i": "ETHUSD-PERP",
|
547
|
+
# "v": "1305697.6462",
|
548
|
+
# "vv": "3058704939.17",
|
549
|
+
# "oi": "161646.3614",
|
550
|
+
# "t": 1726069647560
|
551
|
+
# }
|
552
|
+
#
|
553
|
+
timestamp = self.safe_integer(ticker, 't')
|
554
|
+
marketId = self.safe_string(ticker, 'i')
|
555
|
+
market = self.safe_market(marketId, market, '_')
|
556
|
+
quote = self.safe_string(market, 'quote')
|
557
|
+
last = self.safe_string(ticker, 'a')
|
558
|
+
return self.safe_ticker({
|
559
|
+
'symbol': market['symbol'],
|
560
|
+
'timestamp': timestamp,
|
561
|
+
'datetime': self.iso8601(timestamp),
|
562
|
+
'high': self.safe_number(ticker, 'h'),
|
563
|
+
'low': self.safe_number(ticker, 'l'),
|
564
|
+
'bid': self.safe_number(ticker, 'b'),
|
565
|
+
'bidVolume': self.safe_number(ticker, 'bs'),
|
566
|
+
'ask': self.safe_number(ticker, 'k'),
|
567
|
+
'askVolume': self.safe_number(ticker, 'ks'),
|
568
|
+
'vwap': None,
|
569
|
+
'open': None,
|
570
|
+
'close': last,
|
571
|
+
'last': last,
|
572
|
+
'previousClose': None,
|
573
|
+
'change': None,
|
574
|
+
'percentage': self.safe_string(ticker, 'c'),
|
575
|
+
'average': None,
|
576
|
+
'baseVolume': self.safe_string(ticker, 'v'),
|
577
|
+
'quoteVolume': self.safe_string(ticker, 'vv') if (quote == 'USD') else None,
|
578
|
+
'info': ticker,
|
579
|
+
}, market)
|
580
|
+
|
581
|
+
async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
|
582
|
+
"""
|
583
|
+
:see: https://exchange-docs.crypto.com/exchange/v1/rest-ws/index.html#ticker-instrument_name
|
584
|
+
watches best bid & ask for symbols
|
585
|
+
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
586
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
587
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
588
|
+
"""
|
589
|
+
await self.load_markets()
|
590
|
+
symbols = self.market_symbols(symbols, None, False)
|
591
|
+
messageHashes = []
|
592
|
+
topics = []
|
593
|
+
marketIds = self.market_ids(symbols)
|
594
|
+
for i in range(0, len(marketIds)):
|
595
|
+
marketId = marketIds[i]
|
596
|
+
messageHashes.append('bidask.' + symbols[i])
|
597
|
+
topics.append('ticker.' + marketId)
|
598
|
+
url = self.urls['api']['ws']['public']
|
599
|
+
id = self.nonce()
|
600
|
+
request: dict = {
|
601
|
+
'method': 'subscribe',
|
602
|
+
'params': {
|
603
|
+
'channels': topics,
|
604
|
+
},
|
605
|
+
'nonce': id,
|
606
|
+
}
|
607
|
+
newTickers = await self.watch_multiple(url, messageHashes, self.extend(request, params), messageHashes)
|
608
|
+
if self.newUpdates:
|
609
|
+
tickers: dict = {}
|
610
|
+
tickers[newTickers['symbol']] = newTickers
|
611
|
+
return tickers
|
612
|
+
return self.filter_by_array(self.bidsasks, 'symbol', symbols)
|
613
|
+
|
614
|
+
def handle_bid_ask(self, client: Client, message):
|
615
|
+
data = self.safe_list(message, 'data', [])
|
616
|
+
ticker = self.safe_dict(data, 0, {})
|
617
|
+
parsedTicker = self.parse_ws_bid_ask(ticker)
|
618
|
+
symbol = parsedTicker['symbol']
|
619
|
+
self.bidsasks[symbol] = parsedTicker
|
620
|
+
messageHash = 'bidask.' + symbol
|
621
|
+
client.resolve(parsedTicker, messageHash)
|
622
|
+
|
623
|
+
def parse_ws_bid_ask(self, ticker, market=None):
|
624
|
+
marketId = self.safe_string(ticker, 'i')
|
625
|
+
market = self.safe_market(marketId, market)
|
626
|
+
symbol = self.safe_string(market, 'symbol')
|
627
|
+
timestamp = self.safe_integer(ticker, 't')
|
628
|
+
return self.safe_ticker({
|
629
|
+
'symbol': symbol,
|
630
|
+
'timestamp': timestamp,
|
631
|
+
'datetime': self.iso8601(timestamp),
|
632
|
+
'ask': self.safe_string(ticker, 'k'),
|
633
|
+
'askVolume': self.safe_string(ticker, 'ks'),
|
634
|
+
'bid': self.safe_string(ticker, 'b'),
|
635
|
+
'bidVolume': self.safe_string(ticker, 'bs'),
|
636
|
+
'info': ticker,
|
637
|
+
}, market)
|
638
|
+
|
480
639
|
async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
481
640
|
"""
|
482
641
|
watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
ccxt/pro/mexc.py
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
import ccxt.async_support
|
7
7
|
from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheByTimestamp
|
8
8
|
import hashlib
|
9
|
-
from ccxt.base.types import Balances, Int, Order, OrderBook, Str, Ticker, Trade
|
9
|
+
from ccxt.base.types import Balances, Int, Order, OrderBook, Str, Strings, Ticker, Tickers, Trade
|
10
10
|
from ccxt.async_support.base.ws.client import Client
|
11
11
|
from typing import List
|
12
12
|
from ccxt.base.errors import AuthenticationError
|
@@ -33,7 +33,7 @@ class mexc(ccxt.async_support.mexc):
|
|
33
33
|
'watchOrderBook': True,
|
34
34
|
'watchOrders': True,
|
35
35
|
'watchTicker': True,
|
36
|
-
'watchTickers':
|
36
|
+
'watchTickers': True,
|
37
37
|
'watchTrades': True,
|
38
38
|
'watchTradesForSymbols': False,
|
39
39
|
},
|
@@ -126,6 +126,77 @@ class mexc(ccxt.async_support.mexc):
|
|
126
126
|
messageHash = 'ticker:' + symbol
|
127
127
|
client.resolve(ticker, messageHash)
|
128
128
|
|
129
|
+
async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
|
130
|
+
"""
|
131
|
+
watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
|
132
|
+
:see: https://mexcdevelop.github.io/apidocs/spot_v3_en/#individual-symbol-book-ticker-streams
|
133
|
+
:see: https://mexcdevelop.github.io/apidocs/contract_v1_en/#public-channels
|
134
|
+
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
135
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
136
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
137
|
+
"""
|
138
|
+
await self.load_markets()
|
139
|
+
symbols = self.market_symbols(symbols, None, False)
|
140
|
+
messageHashes = []
|
141
|
+
marketIds = self.market_ids(symbols)
|
142
|
+
firstMarket = self.market(symbols[0])
|
143
|
+
isSpot = firstMarket['spot']
|
144
|
+
url = self.urls['api']['ws']['spot'] if (isSpot) else self.urls['api']['ws']['swap']
|
145
|
+
request: dict = {}
|
146
|
+
if isSpot:
|
147
|
+
topics = []
|
148
|
+
for i in range(0, len(marketIds)):
|
149
|
+
marketId = marketIds[i]
|
150
|
+
messageHashes.append('ticker:' + symbols[i])
|
151
|
+
topics.append('spot@public.bookTicker.v3.api@' + marketId)
|
152
|
+
request['method'] = 'SUBSCRIPTION'
|
153
|
+
request['params'] = topics
|
154
|
+
else:
|
155
|
+
request['method'] = 'sub.tickers'
|
156
|
+
request['params'] = {}
|
157
|
+
messageHashes.append('ticker')
|
158
|
+
ticker = await self.watch_multiple(url, messageHashes, self.extend(request, params), messageHashes)
|
159
|
+
if isSpot and self.newUpdates:
|
160
|
+
result: dict = {}
|
161
|
+
result[ticker['symbol']] = ticker
|
162
|
+
return result
|
163
|
+
return self.filter_by_array(self.tickers, 'symbol', symbols)
|
164
|
+
|
165
|
+
def handle_tickers(self, client: Client, message):
|
166
|
+
#
|
167
|
+
# {
|
168
|
+
# "channel": "push.tickers",
|
169
|
+
# "data": [
|
170
|
+
# {
|
171
|
+
# "symbol": "ETH_USDT",
|
172
|
+
# "lastPrice": 2324.5,
|
173
|
+
# "riseFallRate": 0.0356,
|
174
|
+
# "fairPrice": 2324.32,
|
175
|
+
# "indexPrice": 2325.44,
|
176
|
+
# "volume24": 25868309,
|
177
|
+
# "amount24": 591752573.9792,
|
178
|
+
# "maxBidPrice": 2557.98,
|
179
|
+
# "minAskPrice": 2092.89,
|
180
|
+
# "lower24Price": 2239.39,
|
181
|
+
# "high24Price": 2332.59,
|
182
|
+
# "timestamp": 1725872514111
|
183
|
+
# }
|
184
|
+
# ],
|
185
|
+
# "ts": 1725872514111
|
186
|
+
# }
|
187
|
+
#
|
188
|
+
data = self.safe_list(message, 'data')
|
189
|
+
topic = 'ticker'
|
190
|
+
result = []
|
191
|
+
for i in range(0, len(data)):
|
192
|
+
ticker = self.parse_ticker(data[i])
|
193
|
+
symbol = ticker['symbol']
|
194
|
+
self.tickers[symbol] = ticker
|
195
|
+
result.append(ticker)
|
196
|
+
messageHash = topic + ':' + symbol
|
197
|
+
client.resolve(ticker, messageHash)
|
198
|
+
client.resolve(result, topic)
|
199
|
+
|
129
200
|
def parse_ws_ticker(self, ticker, market=None):
|
130
201
|
#
|
131
202
|
# spot
|
@@ -1073,8 +1144,8 @@ class mexc(ccxt.async_support.mexc):
|
|
1073
1144
|
# "code": 0,
|
1074
1145
|
# "msg": "spot@public.increase.depth.v3.api@BTCUSDT"
|
1075
1146
|
# }
|
1076
|
-
#
|
1077
|
-
msg = self.safe_string(message, 'msg')
|
1147
|
+
# Set the default to an empty string if the message is empty during the test.
|
1148
|
+
msg = self.safe_string(message, 'msg', '')
|
1078
1149
|
if msg == 'PONG':
|
1079
1150
|
self.handle_pong(client, message)
|
1080
1151
|
elif msg.find('@') > -1:
|
@@ -1110,6 +1181,7 @@ class mexc(ccxt.async_support.mexc):
|
|
1110
1181
|
'push.kline': self.handle_ohlcv,
|
1111
1182
|
'public.bookTicker.v3.api': self.handle_ticker,
|
1112
1183
|
'push.ticker': self.handle_ticker,
|
1184
|
+
'push.tickers': self.handle_tickers,
|
1113
1185
|
'public.increase.depth.v3.api': self.handle_order_book,
|
1114
1186
|
'push.depth': self.handle_order_book,
|
1115
1187
|
'private.orders.v3.api': self.handle_order,
|
ccxt/pro/okx.py
CHANGED
@@ -1340,8 +1340,10 @@ class okx(ccxt.async_support.okx):
|
|
1340
1340
|
},
|
1341
1341
|
],
|
1342
1342
|
}
|
1343
|
-
|
1344
|
-
|
1343
|
+
# Only add params['access'] to prevent sending custom parameters, such.
|
1344
|
+
if 'access' in params:
|
1345
|
+
request['access'] = params['access']
|
1346
|
+
self.watch(url, messageHash, request, messageHash)
|
1345
1347
|
return await future
|
1346
1348
|
|
1347
1349
|
async def watch_balance(self, params={}) -> Balances:
|
@@ -1499,7 +1501,7 @@ class okx(ccxt.async_support.okx):
|
|
1499
1501
|
'channel': 'positions',
|
1500
1502
|
'instType': 'ANY',
|
1501
1503
|
}
|
1502
|
-
args = [arg]
|
1504
|
+
args = [self.extend(arg, params)]
|
1503
1505
|
nonSymbolRequest: dict = {
|
1504
1506
|
'op': 'subscribe',
|
1505
1507
|
'args': args,
|
ccxt/pro/oxfun.py
CHANGED
@@ -30,6 +30,7 @@ class oxfun(ccxt.async_support.oxfun):
|
|
30
30
|
'watchMyTrades': False,
|
31
31
|
'watchTicker': True,
|
32
32
|
'watchTickers': True,
|
33
|
+
'watchBidsAsks': True,
|
33
34
|
'watchBalance': True,
|
34
35
|
'createOrderWs': True,
|
35
36
|
'editOrderWs': True,
|
@@ -466,6 +467,73 @@ class oxfun(ccxt.async_support.oxfun):
|
|
466
467
|
self.tickers[symbol] = ticker
|
467
468
|
client.resolve(ticker, messageHash)
|
468
469
|
|
470
|
+
async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
|
471
|
+
"""
|
472
|
+
:see: https://docs.ox.fun/?json#best-bid-ask
|
473
|
+
watches best bid & ask for symbols
|
474
|
+
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
475
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
476
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
477
|
+
"""
|
478
|
+
await self.load_markets()
|
479
|
+
symbols = self.market_symbols(symbols, None, False)
|
480
|
+
messageHashes = []
|
481
|
+
args = []
|
482
|
+
for i in range(0, len(symbols)):
|
483
|
+
market = self.market(symbols[i])
|
484
|
+
args.append('bestBidAsk:' + market['id'])
|
485
|
+
messageHashes.append('bidask:' + market['symbol'])
|
486
|
+
newTickers = await self.subscribe_multiple(messageHashes, args, params)
|
487
|
+
if self.newUpdates:
|
488
|
+
tickers: dict = {}
|
489
|
+
tickers[newTickers['symbol']] = newTickers
|
490
|
+
return tickers
|
491
|
+
return self.filter_by_array(self.bidsasks, 'symbol', symbols)
|
492
|
+
|
493
|
+
def handle_bid_ask(self, client: Client, message):
|
494
|
+
#
|
495
|
+
# {
|
496
|
+
# "table": "bestBidAsk",
|
497
|
+
# "data": {
|
498
|
+
# "ask": [
|
499
|
+
# 19045.0,
|
500
|
+
# 1.0
|
501
|
+
# ],
|
502
|
+
# "checksum": 3790706311,
|
503
|
+
# "marketCode": "BTC-USD-SWAP-LIN",
|
504
|
+
# "bid": [
|
505
|
+
# 19015.0,
|
506
|
+
# 1.0
|
507
|
+
# ],
|
508
|
+
# "timestamp": "1665456882928"
|
509
|
+
# }
|
510
|
+
# }
|
511
|
+
#
|
512
|
+
data = self.safe_dict(message, 'data', {})
|
513
|
+
parsedTicker = self.parse_ws_bid_ask(data)
|
514
|
+
symbol = parsedTicker['symbol']
|
515
|
+
self.bidsasks[symbol] = parsedTicker
|
516
|
+
messageHash = 'bidask:' + symbol
|
517
|
+
client.resolve(parsedTicker, messageHash)
|
518
|
+
|
519
|
+
def parse_ws_bid_ask(self, ticker, market=None):
|
520
|
+
marketId = self.safe_string(ticker, 'marketCode')
|
521
|
+
market = self.safe_market(marketId, market)
|
522
|
+
symbol = self.safe_string(market, 'symbol')
|
523
|
+
timestamp = self.safe_integer(ticker, 'timestamp')
|
524
|
+
ask = self.safe_list(ticker, 'ask', [])
|
525
|
+
bid = self.safe_list(ticker, 'bid', [])
|
526
|
+
return self.safe_ticker({
|
527
|
+
'symbol': symbol,
|
528
|
+
'timestamp': timestamp,
|
529
|
+
'datetime': self.iso8601(timestamp),
|
530
|
+
'ask': self.safe_number(ask, 0),
|
531
|
+
'askVolume': self.safe_number(ask, 1),
|
532
|
+
'bid': self.safe_number(bid, 0),
|
533
|
+
'bidVolume': self.safe_number(bid, 1),
|
534
|
+
'info': ticker,
|
535
|
+
}, market)
|
536
|
+
|
469
537
|
async def watch_balance(self, params={}) -> Balances:
|
470
538
|
"""
|
471
539
|
:see: https://docs.ox.fun/?json#balance-channel
|
@@ -943,6 +1011,8 @@ class oxfun(ccxt.async_support.oxfun):
|
|
943
1011
|
self.handle_positions(client, message)
|
944
1012
|
if table.find('order') > -1:
|
945
1013
|
self.handle_orders(client, message)
|
1014
|
+
if table == 'bestBidAsk':
|
1015
|
+
self.handle_bid_ask(client, message)
|
946
1016
|
else:
|
947
1017
|
if event == 'login':
|
948
1018
|
self.handle_authentication_message(client, message)
|
ccxt/pro/phemex.py
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
import ccxt.async_support
|
7
7
|
from ccxt.async_support.base.ws.cache import ArrayCache, ArrayCacheBySymbolById, ArrayCacheByTimestamp
|
8
8
|
import hashlib
|
9
|
-
from ccxt.base.types import Balances, Int, Order, OrderBook, Str, Ticker, Trade
|
9
|
+
from ccxt.base.types import Balances, Int, Order, OrderBook, Str, Strings, Ticker, Tickers, Trade
|
10
10
|
from ccxt.async_support.base.ws.client import Client
|
11
11
|
from typing import List
|
12
12
|
from ccxt.base.errors import AuthenticationError
|
@@ -20,7 +20,7 @@ class phemex(ccxt.async_support.phemex):
|
|
20
20
|
'has': {
|
21
21
|
'ws': True,
|
22
22
|
'watchTicker': True,
|
23
|
-
'watchTickers':
|
23
|
+
'watchTickers': True,
|
24
24
|
'watchTrades': True,
|
25
25
|
'watchMyTrades': True,
|
26
26
|
'watchOrders': True,
|
@@ -504,6 +504,45 @@ class phemex(ccxt.async_support.phemex):
|
|
504
504
|
request = self.deep_extend(subscribe, params)
|
505
505
|
return await self.watch(url, messageHash, request, subscriptionHash)
|
506
506
|
|
507
|
+
async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
|
508
|
+
"""
|
509
|
+
:see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#subscribe-24-hours-ticker
|
510
|
+
:see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Contract-API-en.md#subscribe-24-hours-ticker
|
511
|
+
:see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Spot-API-en.md#subscribe-24-hours-ticker
|
512
|
+
watches a price ticker, a statistical calculation with the information calculated over the past 24 hours for all markets of a specific list
|
513
|
+
:param str[] [symbols]: unified symbol of the market to fetch the ticker for
|
514
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
515
|
+
:param str [params.channel]: the channel to subscribe to, tickers by default. Can be tickers, sprd-tickers, index-tickers, block-tickers
|
516
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
517
|
+
"""
|
518
|
+
await self.load_markets()
|
519
|
+
symbols = self.market_symbols(symbols, None, False)
|
520
|
+
first = symbols[0]
|
521
|
+
market = self.market(first)
|
522
|
+
isSwap = market['swap']
|
523
|
+
settleIsUSDT = market['settle'] == 'USDT'
|
524
|
+
name = 'spot_market24h'
|
525
|
+
if isSwap:
|
526
|
+
name = 'perp_market24h_pack_p' if settleIsUSDT else 'market24h'
|
527
|
+
url = self.urls['api']['ws']
|
528
|
+
requestId = self.request_id()
|
529
|
+
subscriptionHash = name + '.subscribe'
|
530
|
+
messageHashes = []
|
531
|
+
for i in range(0, len(symbols)):
|
532
|
+
messageHashes.append('ticker:' + symbols[i])
|
533
|
+
subscribe: dict = {
|
534
|
+
'method': subscriptionHash,
|
535
|
+
'id': requestId,
|
536
|
+
'params': [],
|
537
|
+
}
|
538
|
+
request = self.deep_extend(subscribe, params)
|
539
|
+
ticker = await self.watch_multiple(url, messageHashes, request, messageHashes)
|
540
|
+
if self.newUpdates:
|
541
|
+
result: dict = {}
|
542
|
+
result[ticker['symbol']] = ticker
|
543
|
+
return result
|
544
|
+
return self.filter_by_array(self.tickers, 'symbol', symbols)
|
545
|
+
|
507
546
|
async def watch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
508
547
|
"""
|
509
548
|
:see: https://github.com/phemex/phemex-api-docs/blob/master/Public-Hedged-Perpetual-API.md#subscribe-trade
|
ccxt/pro/woofipro.py
CHANGED
@@ -26,6 +26,7 @@ class woofipro(ccxt.async_support.woofipro):
|
|
26
26
|
'watchOrders': True,
|
27
27
|
'watchTicker': True,
|
28
28
|
'watchTickers': True,
|
29
|
+
'watchBidsAsks': True,
|
29
30
|
'watchTrades': True,
|
30
31
|
'watchTradesForSymbols': False,
|
31
32
|
'watchPositions': True,
|
@@ -284,6 +285,68 @@ class woofipro(ccxt.async_support.woofipro):
|
|
284
285
|
result.append(ticker)
|
285
286
|
client.resolve(result, topic)
|
286
287
|
|
288
|
+
async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
|
289
|
+
"""
|
290
|
+
:see: https://orderly.network/docs/build-on-evm/evm-api/websocket-api/public/bbos
|
291
|
+
watches best bid & ask for symbols
|
292
|
+
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
293
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
294
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
295
|
+
"""
|
296
|
+
await self.load_markets()
|
297
|
+
symbols = self.market_symbols(symbols)
|
298
|
+
name = 'bbos'
|
299
|
+
topic = name
|
300
|
+
request: dict = {
|
301
|
+
'event': 'subscribe',
|
302
|
+
'topic': topic,
|
303
|
+
}
|
304
|
+
message = self.extend(request, params)
|
305
|
+
tickers = await self.watch_public(topic, message)
|
306
|
+
return self.filter_by_array(tickers, 'symbol', symbols)
|
307
|
+
|
308
|
+
def handle_bid_ask(self, client: Client, message):
|
309
|
+
#
|
310
|
+
# {
|
311
|
+
# "topic": "bbos",
|
312
|
+
# "ts": 1726212495000,
|
313
|
+
# "data": [
|
314
|
+
# {
|
315
|
+
# "symbol": "PERP_WOO_USDC",
|
316
|
+
# "ask": 0.16570,
|
317
|
+
# "askSize": 4224,
|
318
|
+
# "bid": 0.16553,
|
319
|
+
# "bidSize": 6645
|
320
|
+
# }
|
321
|
+
# ]
|
322
|
+
# }
|
323
|
+
#
|
324
|
+
topic = self.safe_string(message, 'topic')
|
325
|
+
data = self.safe_list(message, 'data', [])
|
326
|
+
timestamp = self.safe_integer(message, 'ts')
|
327
|
+
result = []
|
328
|
+
for i in range(0, len(data)):
|
329
|
+
ticker = self.parse_ws_bid_ask(self.extend(data[i], {'ts': timestamp}))
|
330
|
+
self.tickers[ticker['symbol']] = ticker
|
331
|
+
result.append(ticker)
|
332
|
+
client.resolve(result, topic)
|
333
|
+
|
334
|
+
def parse_ws_bid_ask(self, ticker, market=None):
|
335
|
+
marketId = self.safe_string(ticker, 'symbol')
|
336
|
+
market = self.safe_market(marketId, market)
|
337
|
+
symbol = self.safe_string(market, 'symbol')
|
338
|
+
timestamp = self.safe_integer(ticker, 'ts')
|
339
|
+
return self.safe_ticker({
|
340
|
+
'symbol': symbol,
|
341
|
+
'timestamp': timestamp,
|
342
|
+
'datetime': self.iso8601(timestamp),
|
343
|
+
'ask': self.safe_string(ticker, 'ask'),
|
344
|
+
'askVolume': self.safe_string(ticker, 'askSize'),
|
345
|
+
'bid': self.safe_string(ticker, 'bid'),
|
346
|
+
'bidVolume': self.safe_string(ticker, 'bidSize'),
|
347
|
+
'info': ticker,
|
348
|
+
}, market)
|
349
|
+
|
287
350
|
async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
288
351
|
"""
|
289
352
|
watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
@@ -1133,6 +1196,7 @@ class woofipro(ccxt.async_support.woofipro):
|
|
1133
1196
|
'algoexecutionreport': self.handle_order_update,
|
1134
1197
|
'position': self.handle_positions,
|
1135
1198
|
'balance': self.handle_balance,
|
1199
|
+
'bbos': self.handle_bid_ask,
|
1136
1200
|
}
|
1137
1201
|
event = self.safe_string(message, 'event')
|
1138
1202
|
method = self.safe_value(methods, event)
|
ccxt/xt.py
CHANGED
@@ -1137,17 +1137,21 @@ class xt(Exchange, ImplicitAPI):
|
|
1137
1137
|
maxCost = None
|
1138
1138
|
minPrice = None
|
1139
1139
|
maxPrice = None
|
1140
|
+
amountPrecision = None
|
1140
1141
|
for i in range(0, len(filters)):
|
1141
1142
|
entry = filters[i]
|
1142
1143
|
filter = self.safe_string(entry, 'filter')
|
1143
1144
|
if filter == 'QUANTITY':
|
1144
1145
|
minAmount = self.safe_number(entry, 'min')
|
1145
1146
|
maxAmount = self.safe_number(entry, 'max')
|
1147
|
+
amountPrecision = self.safe_number(entry, 'tickSize')
|
1146
1148
|
if filter == 'QUOTE_QTY':
|
1147
1149
|
minCost = self.safe_number(entry, 'min')
|
1148
1150
|
if filter == 'PRICE':
|
1149
1151
|
minPrice = self.safe_number(entry, 'min')
|
1150
1152
|
maxPrice = self.safe_number(entry, 'max')
|
1153
|
+
if amountPrecision is None:
|
1154
|
+
amountPrecision = self.parse_number(self.parse_precision(self.safe_string(market, 'quantityPrecision')))
|
1151
1155
|
underlyingType = self.safe_string(market, 'underlyingType')
|
1152
1156
|
linear = None
|
1153
1157
|
inverse = None
|
@@ -1222,7 +1226,7 @@ class xt(Exchange, ImplicitAPI):
|
|
1222
1226
|
'optionType': None,
|
1223
1227
|
'precision': {
|
1224
1228
|
'price': self.parse_number(self.parse_precision(self.safe_string(market, 'pricePrecision'))),
|
1225
|
-
'amount':
|
1229
|
+
'amount': amountPrecision,
|
1226
1230
|
'base': self.parse_number(self.parse_precision(self.safe_string(market, 'baseCoinPrecision'))),
|
1227
1231
|
'quote': self.parse_number(self.parse_precision(self.safe_string(market, 'quoteCoinPrecision'))),
|
1228
1232
|
},
|