ccxt 4.2.35__py2.py3-none-any.whl → 4.2.37__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/bitfinex2.py +122 -122
- ccxt/async_support/__init__.py +1 -1
- ccxt/async_support/base/exchange.py +1 -1
- ccxt/async_support/binance.py +347 -107
- ccxt/async_support/bitfinex.py +21 -0
- ccxt/async_support/bitfinex2.py +122 -122
- ccxt/async_support/bitget.py +23 -32
- ccxt/async_support/bithumb.py +14 -0
- ccxt/async_support/bitmex.py +22 -3
- ccxt/async_support/bybit.py +11 -4
- ccxt/async_support/woo.py +60 -35
- ccxt/base/exchange.py +1 -1
- ccxt/binance.py +347 -107
- ccxt/bitfinex.py +21 -0
- ccxt/bitfinex2.py +122 -122
- ccxt/bitget.py +23 -32
- ccxt/bithumb.py +14 -0
- ccxt/bitmex.py +22 -3
- ccxt/bybit.py +11 -4
- ccxt/pro/__init__.py +1 -1
- ccxt/pro/binance.py +2 -2
- ccxt/pro/gemini.py +165 -3
- ccxt/test/test_async.py +8 -6
- ccxt/test/test_sync.py +8 -6
- ccxt/woo.py +60 -35
- {ccxt-4.2.35.dist-info → ccxt-4.2.37.dist-info}/METADATA +6 -6
- {ccxt-4.2.35.dist-info → ccxt-4.2.37.dist-info}/RECORD +30 -30
- {ccxt-4.2.35.dist-info → ccxt-4.2.37.dist-info}/WHEEL +0 -0
- {ccxt-4.2.35.dist-info → ccxt-4.2.37.dist-info}/top_level.txt +0 -0
ccxt/bitmex.py
CHANGED
@@ -292,6 +292,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
292
292
|
def fetch_currencies(self, params={}):
|
293
293
|
"""
|
294
294
|
fetches all available currencies on an exchange
|
295
|
+
:see: https://www.bitmex.com/api/explorer/#not /Wallet/Wallet_getAssetsConfig
|
295
296
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
296
297
|
:returns dict: an associative dictionary of currencies
|
297
298
|
"""
|
@@ -752,6 +753,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
752
753
|
def fetch_balance(self, params={}) -> Balances:
|
753
754
|
"""
|
754
755
|
query for balance and get the amount of funds available for trading or funds locked in orders
|
756
|
+
:see: https://www.bitmex.com/api/explorer/#not /User/User_getMargin
|
755
757
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
756
758
|
:returns dict: a `balance structure <https://docs.ccxt.com/#/?id=balance-structure>`
|
757
759
|
"""
|
@@ -812,6 +814,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
812
814
|
def fetch_order_book(self, symbol: str, limit: Int = None, params={}) -> OrderBook:
|
813
815
|
"""
|
814
816
|
fetches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
817
|
+
:see: https://www.bitmex.com/api/explorer/#not /OrderBook/OrderBook_getL2
|
815
818
|
:param str symbol: unified symbol of the market to fetch the order book for
|
816
819
|
:param int [limit]: the maximum amount of order book entries to return
|
817
820
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
@@ -850,6 +853,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
850
853
|
def fetch_order(self, id: str, symbol: Str = None, params={}):
|
851
854
|
"""
|
852
855
|
fetches information on an order made by the user
|
856
|
+
:see: https://www.bitmex.com/api/explorer/#not /Order/Order_getOrders
|
853
857
|
:param str symbol: unified symbol of the market the order was made in
|
854
858
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
855
859
|
:returns dict: An `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
@@ -907,6 +911,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
907
911
|
def fetch_open_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
908
912
|
"""
|
909
913
|
fetch all unfilled currently open orders
|
914
|
+
:see: https://www.bitmex.com/api/explorer/#not /Order/Order_getOrders
|
910
915
|
:param str symbol: unified market symbol
|
911
916
|
:param int [since]: the earliest time in ms to fetch open orders for
|
912
917
|
:param int [limit]: the maximum number of open orders structures to retrieve
|
@@ -923,6 +928,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
923
928
|
def fetch_closed_orders(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Order]:
|
924
929
|
"""
|
925
930
|
fetches information on multiple closed orders made by the user
|
931
|
+
:see: https://www.bitmex.com/api/explorer/#not /Order/Order_getOrders
|
926
932
|
:param str symbol: unified market symbol of the market orders were made in
|
927
933
|
:param int [since]: the earliest time in ms to fetch orders for
|
928
934
|
:param int [limit]: the maximum number of order structures to retrieve
|
@@ -935,8 +941,8 @@ class bitmex(Exchange, ImplicitAPI):
|
|
935
941
|
|
936
942
|
def fetch_my_trades(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
937
943
|
"""
|
938
|
-
:see: https://www.bitmex.com/api/explorer/#not /Execution/Execution_getTradeHistory
|
939
944
|
fetch all trades made by the user
|
945
|
+
:see: https://www.bitmex.com/api/explorer/#not /Execution/Execution_getTradeHistory
|
940
946
|
:param str symbol: unified market symbol
|
941
947
|
:param int [since]: the earliest time in ms to fetch trades for
|
942
948
|
:param int [limit]: the maximum number of trades structures to retrieve
|
@@ -1132,6 +1138,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1132
1138
|
def fetch_ledger(self, code: Str = None, since: Int = None, limit: Int = None, params={}):
|
1133
1139
|
"""
|
1134
1140
|
fetch the history of changes, actions done by the user or operations that altered balance of the user
|
1141
|
+
:see: https://www.bitmex.com/api/explorer/#not /User/User_getWalletHistory
|
1135
1142
|
:param str code: unified currency code, default is None
|
1136
1143
|
:param int [since]: timestamp in ms of the earliest ledger entry, default is None
|
1137
1144
|
:param int [limit]: max number of ledger entrys to return, default is None
|
@@ -1179,6 +1186,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1179
1186
|
def fetch_deposits_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
|
1180
1187
|
"""
|
1181
1188
|
fetch history of deposits and withdrawals
|
1189
|
+
:see: https://www.bitmex.com/api/explorer/#not /User/User_getWalletHistory
|
1182
1190
|
:param str [code]: unified currency code for the currency of the deposit/withdrawals, default is None
|
1183
1191
|
:param int [since]: timestamp in ms of the earliest deposit/withdrawal, default is None
|
1184
1192
|
:param int [limit]: max number of deposit/withdrawals to return, default is None
|
@@ -1290,6 +1298,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1290
1298
|
def fetch_ticker(self, symbol: str, params={}) -> Ticker:
|
1291
1299
|
"""
|
1292
1300
|
fetches a price ticker, a statistical calculation with the information calculated over the past 24 hours for a specific market
|
1301
|
+
:see: https://www.bitmex.com/api/explorer/#not /Instrument/Instrument_get
|
1293
1302
|
:param str symbol: unified symbol of the market to fetch the ticker for
|
1294
1303
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
1295
1304
|
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
@@ -1308,6 +1317,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1308
1317
|
def fetch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
|
1309
1318
|
"""
|
1310
1319
|
fetches price tickers for multiple markets, statistical information calculated over the past 24 hours for each market
|
1320
|
+
:see: https://www.bitmex.com/api/explorer/#not /Instrument/Instrument_getActiveAndIndices
|
1311
1321
|
:param str[]|None symbols: unified symbols of the markets to fetch the ticker for, all market tickers are returned if not assigned
|
1312
1322
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
1313
1323
|
:returns dict: a dictionary of `ticker structures <https://docs.ccxt.com/#/?id=ticker-structure>`
|
@@ -1386,8 +1396,8 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1386
1396
|
|
1387
1397
|
def fetch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
1388
1398
|
"""
|
1389
|
-
:see: https://www.bitmex.com/api/explorer/#not /Trade/Trade_getBucketed
|
1390
1399
|
fetches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
1400
|
+
:see: https://www.bitmex.com/api/explorer/#not /Trade/Trade_getBucketed
|
1391
1401
|
:param str symbol: unified symbol of the market to fetch OHLCV data for
|
1392
1402
|
:param str timeframe: the length of time each candle represents
|
1393
1403
|
:param int [since]: timestamp in ms of the earliest candle to fetch
|
@@ -1683,8 +1693,8 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1683
1693
|
|
1684
1694
|
def fetch_trades(self, symbol: str, since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
1685
1695
|
"""
|
1686
|
-
:see: https://www.bitmex.com/api/explorer/#not /Trade/Trade_get
|
1687
1696
|
get the list of most recent trades for a particular symbol
|
1697
|
+
:see: https://www.bitmex.com/api/explorer/#not /Trade/Trade_get
|
1688
1698
|
:param str symbol: unified symbol of the market to fetch trades for
|
1689
1699
|
:param int [since]: timestamp in ms of the earliest trade to fetch
|
1690
1700
|
:param int [limit]: the maximum amount of trades to fetch
|
@@ -1866,6 +1876,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1866
1876
|
def cancel_order(self, id: str, symbol: Str = None, params={}):
|
1867
1877
|
"""
|
1868
1878
|
cancels an open order
|
1879
|
+
:see: https://www.bitmex.com/api/explorer/#not /Order/Order_cancel
|
1869
1880
|
:param str id: order id
|
1870
1881
|
:param str symbol: not used by bitmex cancelOrder()
|
1871
1882
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
@@ -1891,6 +1902,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1891
1902
|
def cancel_orders(self, ids, symbol: Str = None, params={}):
|
1892
1903
|
"""
|
1893
1904
|
cancel multiple orders
|
1905
|
+
:see: https://www.bitmex.com/api/explorer/#not /Order/Order_cancel
|
1894
1906
|
:param str[] ids: order ids
|
1895
1907
|
:param str symbol: not used by bitmex cancelOrders()
|
1896
1908
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
@@ -1912,6 +1924,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1912
1924
|
def cancel_all_orders(self, symbol: Str = None, params={}):
|
1913
1925
|
"""
|
1914
1926
|
cancel all open orders
|
1927
|
+
:see: https://www.bitmex.com/api/explorer/#not /Order/Order_cancelAll
|
1915
1928
|
:param str symbol: unified market symbol, only orders in the market of self symbol are cancelled when symbol is not None
|
1916
1929
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
1917
1930
|
:returns dict[]: a list of `order structures <https://docs.ccxt.com/#/?id=order-structure>`
|
@@ -1967,6 +1980,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
1967
1980
|
def fetch_positions(self, symbols: Strings = None, params={}):
|
1968
1981
|
"""
|
1969
1982
|
fetch all open positions
|
1983
|
+
:see: https://www.bitmex.com/api/explorer/#not /Position/Position_get
|
1970
1984
|
:param str[]|None symbols: list of unified market symbols
|
1971
1985
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
1972
1986
|
:returns dict[]: a list of `position structure <https://docs.ccxt.com/#/?id=position-structure>`
|
@@ -2220,6 +2234,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
2220
2234
|
def withdraw(self, code: str, amount: float, address, tag=None, params={}):
|
2221
2235
|
"""
|
2222
2236
|
make a withdrawal
|
2237
|
+
:see: https://www.bitmex.com/api/explorer/#not /User/User_requestWithdrawal
|
2223
2238
|
:param str code: unified currency code
|
2224
2239
|
:param float amount: the amount to withdraw
|
2225
2240
|
:param str address: the address to withdraw to
|
@@ -2265,6 +2280,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
2265
2280
|
def fetch_funding_rates(self, symbols: Strings = None, params={}):
|
2266
2281
|
"""
|
2267
2282
|
fetch the funding rate for multiple markets
|
2283
|
+
:see: https://www.bitmex.com/api/explorer/#not /Instrument/Instrument_getActiveAndIndices
|
2268
2284
|
:param str[]|None symbols: list of unified market symbols
|
2269
2285
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
2270
2286
|
:returns dict: a dictionary of `funding rates structures <https://docs.ccxt.com/#/?id=funding-rates-structure>`, indexe by market symbols
|
@@ -2312,6 +2328,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
2312
2328
|
def fetch_funding_rate_history(self, symbol: Str = None, since: Int = None, limit: Int = None, params={}):
|
2313
2329
|
"""
|
2314
2330
|
Fetches the history of funding rates
|
2331
|
+
:see: https://www.bitmex.com/api/explorer/#not /Funding/Funding_get
|
2315
2332
|
:param str symbol: unified symbol of the market to fetch the funding rate history for
|
2316
2333
|
:param int [since]: timestamp in ms of the earliest funding rate to fetch
|
2317
2334
|
:param int [limit]: the maximum amount of `funding rate structures <https://docs.ccxt.com/#/?id=funding-rate-history-structure>` to fetch
|
@@ -2386,6 +2403,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
2386
2403
|
def set_leverage(self, leverage: Int, symbol: Str = None, params={}):
|
2387
2404
|
"""
|
2388
2405
|
set the level of leverage for a market
|
2406
|
+
:see: https://www.bitmex.com/api/explorer/#not /Position/Position_updateLeverage
|
2389
2407
|
:param float leverage: the rate of leverage
|
2390
2408
|
:param str symbol: unified market symbol
|
2391
2409
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
@@ -2408,6 +2426,7 @@ class bitmex(Exchange, ImplicitAPI):
|
|
2408
2426
|
def set_margin_mode(self, marginMode, symbol: Str = None, params={}):
|
2409
2427
|
"""
|
2410
2428
|
set margin mode to 'cross' or 'isolated'
|
2429
|
+
:see: https://www.bitmex.com/api/explorer/#not /Position/Position_isolateMargin
|
2411
2430
|
:param str marginMode: 'cross' or 'isolated'
|
2412
2431
|
:param str symbol: unified market symbol
|
2413
2432
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
ccxt/bybit.py
CHANGED
@@ -3525,9 +3525,19 @@ class bybit(Exchange, ImplicitAPI):
|
|
3525
3525
|
if isStopLoss:
|
3526
3526
|
slTriggerPrice = self.safe_value_2(stopLoss, 'triggerPrice', 'stopPrice', stopLoss)
|
3527
3527
|
request['stopLoss'] = self.price_to_precision(symbol, slTriggerPrice)
|
3528
|
+
slLimitPrice = self.safe_value(stopLoss, 'price')
|
3529
|
+
if slLimitPrice is not None:
|
3530
|
+
request['tpslMode'] = 'Partial'
|
3531
|
+
request['slOrderType'] = 'Limit'
|
3532
|
+
request['slLimitPrice'] = self.price_to_precision(symbol, slLimitPrice)
|
3528
3533
|
if isTakeProfit:
|
3529
3534
|
tpTriggerPrice = self.safe_value_2(takeProfit, 'triggerPrice', 'stopPrice', takeProfit)
|
3530
3535
|
request['takeProfit'] = self.price_to_precision(symbol, tpTriggerPrice)
|
3536
|
+
tpLimitPrice = self.safe_value(takeProfit, 'price')
|
3537
|
+
if tpLimitPrice is not None:
|
3538
|
+
request['tpslMode'] = 'Partial'
|
3539
|
+
request['tpOrderType'] = 'Limit'
|
3540
|
+
request['tpLimitPrice'] = self.price_to_precision(symbol, tpLimitPrice)
|
3531
3541
|
if market['spot']:
|
3532
3542
|
# only works for spot market
|
3533
3543
|
if triggerPrice is not None:
|
@@ -5621,9 +5631,6 @@ class bybit(Exchange, ImplicitAPI):
|
|
5621
5631
|
timestamp = self.parse8601(self.safe_string(position, 'updated_at'))
|
5622
5632
|
if timestamp is None:
|
5623
5633
|
timestamp = self.safe_integer_n(position, ['updatedTime', 'updatedAt'])
|
5624
|
-
# default to cross of USDC margined positions
|
5625
|
-
tradeMode = self.safe_integer(position, 'tradeMode', 0)
|
5626
|
-
marginMode = 'isolated' if tradeMode else 'cross'
|
5627
5634
|
collateralString = self.safe_string(position, 'positionBalance')
|
5628
5635
|
entryPrice = self.omit_zero(self.safe_string_2(position, 'entryPrice', 'avgPrice'))
|
5629
5636
|
liquidationPrice = self.omit_zero(self.safe_string(position, 'liqPrice'))
|
@@ -5680,7 +5687,7 @@ class bybit(Exchange, ImplicitAPI):
|
|
5680
5687
|
'markPrice': self.safe_number(position, 'markPrice'),
|
5681
5688
|
'lastPrice': None,
|
5682
5689
|
'collateral': self.parse_number(collateralString),
|
5683
|
-
'marginMode':
|
5690
|
+
'marginMode': None,
|
5684
5691
|
'side': side,
|
5685
5692
|
'percentage': None,
|
5686
5693
|
'stopLossPrice': self.safe_number_2(position, 'stop_loss', 'stopLoss'),
|
ccxt/pro/__init__.py
CHANGED
ccxt/pro/binance.py
CHANGED
@@ -56,8 +56,8 @@ class binance(ccxt.async_support.binance):
|
|
56
56
|
},
|
57
57
|
'api': {
|
58
58
|
'ws': {
|
59
|
-
'spot': 'wss://stream.binance.com/ws',
|
60
|
-
'margin': 'wss://stream.binance.com/ws',
|
59
|
+
'spot': 'wss://stream.binance.com:9443/ws',
|
60
|
+
'margin': 'wss://stream.binance.com:9443/ws',
|
61
61
|
'future': 'wss://fstream.binance.com/ws',
|
62
62
|
'delivery': 'wss://dstream.binance.com/ws',
|
63
63
|
'ws': 'wss://ws-api.binance.com:443/ws-api/v3',
|
ccxt/pro/gemini.py
CHANGED
@@ -10,6 +10,7 @@ from ccxt.base.types import Int, Order, OrderBook, Str, 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 ExchangeError
|
13
|
+
from ccxt.base.errors import NotSupported
|
13
14
|
|
14
15
|
|
15
16
|
class gemini(ccxt.async_support.gemini):
|
@@ -22,9 +23,11 @@ class gemini(ccxt.async_support.gemini):
|
|
22
23
|
'watchTicker': False,
|
23
24
|
'watchTickers': False,
|
24
25
|
'watchTrades': True,
|
26
|
+
'watchTradesForSymbols': True,
|
25
27
|
'watchMyTrades': False,
|
26
28
|
'watchOrders': True,
|
27
29
|
'watchOrderBook': True,
|
30
|
+
'watchOrderBookForSymbols': True,
|
28
31
|
'watchOHLCV': True,
|
29
32
|
},
|
30
33
|
'hostname': 'api.gemini.com',
|
@@ -70,7 +73,26 @@ class gemini(ccxt.async_support.gemini):
|
|
70
73
|
limit = trades.getLimit(market['symbol'], limit)
|
71
74
|
return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
|
72
75
|
|
73
|
-
def
|
76
|
+
async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
77
|
+
"""
|
78
|
+
:see: https://docs.gemini.com/websocket-api/#multi-market-data
|
79
|
+
get the list of most recent trades for a list of symbols
|
80
|
+
:param str[] symbols: unified symbol of the market to fetch trades for
|
81
|
+
:param int [since]: timestamp in ms of the earliest trade to fetch
|
82
|
+
:param int [limit]: the maximum amount of trades to fetch
|
83
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
84
|
+
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
85
|
+
"""
|
86
|
+
trades = await self.helper_for_watch_multiple_construct('trades', symbols, params)
|
87
|
+
if self.newUpdates:
|
88
|
+
first = self.safe_list(trades, 0)
|
89
|
+
tradeSymbol = self.safe_string(first, 'symbol')
|
90
|
+
limit = trades.getLimit(tradeSymbol, limit)
|
91
|
+
return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
|
92
|
+
|
93
|
+
def parse_ws_trade(self, trade, market=None) -> Trade:
|
94
|
+
#
|
95
|
+
# regular v2 trade
|
74
96
|
#
|
75
97
|
# {
|
76
98
|
# "type": "trade",
|
@@ -82,11 +104,28 @@ class gemini(ccxt.async_support.gemini):
|
|
82
104
|
# "side": "buy"
|
83
105
|
# }
|
84
106
|
#
|
107
|
+
# multi data trade
|
108
|
+
#
|
109
|
+
# {
|
110
|
+
# "type": "trade",
|
111
|
+
# "symbol": "ETHUSD",
|
112
|
+
# "tid": "1683002242170204", # self is not TS, but somewhat ID
|
113
|
+
# "price": "2299.24",
|
114
|
+
# "amount": "0.002662",
|
115
|
+
# "makerSide": "bid"
|
116
|
+
# }
|
117
|
+
#
|
85
118
|
timestamp = self.safe_integer(trade, 'timestamp')
|
86
|
-
id = self.
|
119
|
+
id = self.safe_string_2(trade, 'event_id', 'tid')
|
87
120
|
priceString = self.safe_string(trade, 'price')
|
88
|
-
amountString = self.
|
121
|
+
amountString = self.safe_string_2(trade, 'quantity', 'amount')
|
89
122
|
side = self.safe_string_lower(trade, 'side')
|
123
|
+
if side is None:
|
124
|
+
marketSide = self.safe_string_lower(trade, 'makerSide')
|
125
|
+
if marketSide == 'bid':
|
126
|
+
side = 'sell'
|
127
|
+
elif marketSide == 'ask':
|
128
|
+
side = 'buy'
|
90
129
|
marketId = self.safe_string_lower(trade, 'symbol')
|
91
130
|
symbol = self.safe_symbol(marketId, market)
|
92
131
|
return self.safe_trade({
|
@@ -182,6 +221,30 @@ class gemini(ccxt.async_support.gemini):
|
|
182
221
|
messageHash = 'trades:' + symbol
|
183
222
|
client.resolve(stored, messageHash)
|
184
223
|
|
224
|
+
def handle_trades_for_multidata(self, client: Client, trades, timestamp: Int):
|
225
|
+
if trades is not None:
|
226
|
+
tradesLimit = self.safe_integer(self.options, 'tradesLimit', 1000)
|
227
|
+
storesForSymbols = {}
|
228
|
+
for i in range(0, len(trades)):
|
229
|
+
marketId = trades[i]['symbol']
|
230
|
+
market = self.safe_market(marketId.lower())
|
231
|
+
symbol = market['symbol']
|
232
|
+
trade = self.parse_ws_trade(trades[i], market)
|
233
|
+
trade['timestamp'] = timestamp
|
234
|
+
trade['datetime'] = self.iso8601(timestamp)
|
235
|
+
stored = self.safe_value(self.trades, symbol)
|
236
|
+
if stored is None:
|
237
|
+
stored = ArrayCache(tradesLimit)
|
238
|
+
self.trades[symbol] = stored
|
239
|
+
stored.append(trade)
|
240
|
+
storesForSymbols[symbol] = stored
|
241
|
+
symbols = list(storesForSymbols.keys())
|
242
|
+
for i in range(0, len(symbols)):
|
243
|
+
symbol = symbols[i]
|
244
|
+
stored = storesForSymbols[symbol]
|
245
|
+
messageHash = 'trades:' + symbol
|
246
|
+
client.resolve(stored, messageHash)
|
247
|
+
|
185
248
|
async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
186
249
|
"""
|
187
250
|
watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
@@ -317,6 +380,83 @@ class gemini(ccxt.async_support.gemini):
|
|
317
380
|
self.orderbooks[symbol] = orderbook
|
318
381
|
client.resolve(orderbook, messageHash)
|
319
382
|
|
383
|
+
async def watch_order_book_for_symbols(self, symbols: List[str], limit: Int = None, params={}) -> OrderBook:
|
384
|
+
"""
|
385
|
+
watches information on open orders with bid(buy) and ask(sell) prices, volumes and other data
|
386
|
+
:see: https://docs.gemini.com/websocket-api/#multi-market-data
|
387
|
+
:param str[] symbols: unified array of symbols
|
388
|
+
:param int [limit]: the maximum amount of order book entries to return
|
389
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
390
|
+
:returns dict: A dictionary of `order book structures <https://docs.ccxt.com/#/?id=order-book-structure>` indexed by market symbols
|
391
|
+
"""
|
392
|
+
orderbook = await self.helper_for_watch_multiple_construct('orderbook', symbols, params)
|
393
|
+
return orderbook.limit()
|
394
|
+
|
395
|
+
async def helper_for_watch_multiple_construct(self, itemHashName: str, symbols: List[str], params={}):
|
396
|
+
await self.load_markets()
|
397
|
+
symbols = self.market_symbols(symbols, None, False, True, True)
|
398
|
+
firstMarket = self.market(symbols[0])
|
399
|
+
if not firstMarket['spot'] and not firstMarket['linear']:
|
400
|
+
raise NotSupported(self.id + ' watchMultiple supports only spot or linear-swap symbols')
|
401
|
+
messageHashes = []
|
402
|
+
marketIds = []
|
403
|
+
for i in range(0, len(symbols)):
|
404
|
+
symbol = symbols[i]
|
405
|
+
messageHash = itemHashName + ':' + symbol
|
406
|
+
messageHashes.append(messageHash)
|
407
|
+
market = self.market(symbol)
|
408
|
+
marketIds.append(market['id'])
|
409
|
+
queryStr = ','.join(marketIds)
|
410
|
+
url = self.urls['api']['ws'] + '/v1/multimarketdata?symbols=' + queryStr + '&heartbeat=true&'
|
411
|
+
if itemHashName == 'orderbook':
|
412
|
+
url += 'trades=false&bids=true&offers=true'
|
413
|
+
elif itemHashName == 'trades':
|
414
|
+
url += 'trades=true&bids=false&offers=false'
|
415
|
+
return await self.watch_multiple(url, messageHashes, None)
|
416
|
+
|
417
|
+
def handle_order_book_for_multidata(self, client: Client, rawOrderBookChanges, timestamp: Int, nonce: Int):
|
418
|
+
#
|
419
|
+
# rawOrderBookChanges
|
420
|
+
#
|
421
|
+
# [
|
422
|
+
# {
|
423
|
+
# delta: "4105123935484.817624",
|
424
|
+
# price: "0.000000001",
|
425
|
+
# reason: "initial", # initial|cancel|place
|
426
|
+
# remaining: "4105123935484.817624",
|
427
|
+
# side: "bid", # bid|ask
|
428
|
+
# symbol: "SHIBUSD",
|
429
|
+
# type: "change", # seems always change
|
430
|
+
# },
|
431
|
+
# ...
|
432
|
+
#
|
433
|
+
marketId = rawOrderBookChanges[0]['symbol']
|
434
|
+
market = self.safe_market(marketId.lower())
|
435
|
+
symbol = market['symbol']
|
436
|
+
messageHash = 'orderbook:' + symbol
|
437
|
+
orderbook = self.safe_dict(self.orderbooks, symbol)
|
438
|
+
if orderbook is None:
|
439
|
+
orderbook = self.order_book()
|
440
|
+
bids = orderbook['bids']
|
441
|
+
asks = orderbook['asks']
|
442
|
+
for i in range(0, len(rawOrderBookChanges)):
|
443
|
+
entry = rawOrderBookChanges[i]
|
444
|
+
price = self.safe_number(entry, 'price')
|
445
|
+
size = self.safe_number(entry, 'remaining')
|
446
|
+
rawSide = self.safe_string(entry, 'side')
|
447
|
+
if rawSide == 'bid':
|
448
|
+
bids.store(price, size)
|
449
|
+
else:
|
450
|
+
asks.store(price, size)
|
451
|
+
orderbook['bids'] = bids
|
452
|
+
orderbook['asks'] = asks
|
453
|
+
orderbook['symbol'] = symbol
|
454
|
+
orderbook['nonce'] = nonce
|
455
|
+
orderbook['timestamp'] = timestamp
|
456
|
+
orderbook['datetime'] = self.iso8601(timestamp)
|
457
|
+
self.orderbooks[symbol] = orderbook
|
458
|
+
client.resolve(orderbook, messageHash)
|
459
|
+
|
320
460
|
def handle_l2_updates(self, client: Client, message):
|
321
461
|
#
|
322
462
|
# {
|
@@ -393,6 +533,7 @@ class gemini(ccxt.async_support.gemini):
|
|
393
533
|
# "socket_sequence": 7
|
394
534
|
# }
|
395
535
|
#
|
536
|
+
client.lastPong = self.milliseconds()
|
396
537
|
return message
|
397
538
|
|
398
539
|
def handle_subscription(self, client: Client, message):
|
@@ -586,6 +727,27 @@ class gemini(ccxt.async_support.gemini):
|
|
586
727
|
method = self.safe_value(methods, type)
|
587
728
|
if method is not None:
|
588
729
|
method(client, message)
|
730
|
+
# handle multimarketdata
|
731
|
+
if type == 'update':
|
732
|
+
ts = self.safe_integer(message, 'timestampms', self.milliseconds())
|
733
|
+
eventId = self.safe_integer(message, 'eventId')
|
734
|
+
events = self.safe_list(message, 'events')
|
735
|
+
orderBookItems = []
|
736
|
+
collectedEventsOfTrades = []
|
737
|
+
for i in range(0, len(events)):
|
738
|
+
event = events[i]
|
739
|
+
eventType = self.safe_string(event, 'type')
|
740
|
+
isOrderBook = (eventType == 'change') and ('side' in event) and self.in_array(event['side'], ['ask', 'bid'])
|
741
|
+
if isOrderBook:
|
742
|
+
orderBookItems.append(event)
|
743
|
+
elif eventType == 'trade':
|
744
|
+
collectedEventsOfTrades.append(events[i])
|
745
|
+
lengthOb = len(orderBookItems)
|
746
|
+
if lengthOb > 0:
|
747
|
+
self.handle_order_book_for_multidata(client, orderBookItems, ts, eventId)
|
748
|
+
lengthTrades = len(collectedEventsOfTrades)
|
749
|
+
if lengthTrades > 0:
|
750
|
+
self.handle_trades_for_multidata(client, collectedEventsOfTrades, ts)
|
589
751
|
|
590
752
|
async def authenticate(self, params={}):
|
591
753
|
url = self.safe_string(params, 'url')
|
ccxt/test/test_async.py
CHANGED
@@ -816,10 +816,10 @@ class testMainClass(baseMainTestClass):
|
|
816
816
|
# --- Init of static tests functions------------------------------------------
|
817
817
|
# -----------------------------------------------------------------------------
|
818
818
|
calculated_string = json_stringify(calculated_output)
|
819
|
-
|
820
|
-
error_message = message + '
|
819
|
+
stored_string = json_stringify(stored_output)
|
820
|
+
error_message = message + ' computed ' + stored_string + ' stored: ' + calculated_string
|
821
821
|
if key is not None:
|
822
|
-
error_message = ' | ' + key + ' | ' + 'computed value: ' +
|
822
|
+
error_message = ' | ' + key + ' | ' + 'computed value: ' + stored_string + ' stored value: ' + calculated_string
|
823
823
|
assert cond, error_message
|
824
824
|
|
825
825
|
def load_markets_from_file(self, id):
|
@@ -1141,7 +1141,9 @@ class testMainClass(baseMainTestClass):
|
|
1141
1141
|
await close(exchange)
|
1142
1142
|
return True # in c# methods that will be used with promiseAll need to return something
|
1143
1143
|
|
1144
|
-
def get_number_of_tests_from_exchange(self, exchange, exchange_data):
|
1144
|
+
def get_number_of_tests_from_exchange(self, exchange, exchange_data, test_name=None):
|
1145
|
+
if test_name is not None:
|
1146
|
+
return 1
|
1145
1147
|
sum = 0
|
1146
1148
|
methods = exchange_data['methods']
|
1147
1149
|
methods_names = list(methods.keys())
|
@@ -1171,7 +1173,7 @@ class testMainClass(baseMainTestClass):
|
|
1171
1173
|
for i in range(0, len(exchanges)):
|
1172
1174
|
exchange_name = exchanges[i]
|
1173
1175
|
exchange_data = static_data[exchange_name]
|
1174
|
-
number_of_tests = self.get_number_of_tests_from_exchange(exchange, exchange_data)
|
1176
|
+
number_of_tests = self.get_number_of_tests_from_exchange(exchange, exchange_data, test_name)
|
1175
1177
|
sum = exchange.sum(sum, number_of_tests)
|
1176
1178
|
if type == 'request':
|
1177
1179
|
promises.append(self.test_exchange_request_statically(exchange_name, exchange_data, test_name))
|
@@ -1444,5 +1446,5 @@ class testMainClass(baseMainTestClass):
|
|
1444
1446
|
|
1445
1447
|
|
1446
1448
|
if __name__ == '__main__':
|
1447
|
-
symbol = argv.symbol if argv.symbol
|
1449
|
+
symbol = argv.symbol if argv.symbol else None
|
1448
1450
|
asyncio.run(testMainClass().init(argv.exchange, symbol))
|
ccxt/test/test_sync.py
CHANGED
@@ -815,10 +815,10 @@ class testMainClass(baseMainTestClass):
|
|
815
815
|
# --- Init of static tests functions------------------------------------------
|
816
816
|
# -----------------------------------------------------------------------------
|
817
817
|
calculated_string = json_stringify(calculated_output)
|
818
|
-
|
819
|
-
error_message = message + '
|
818
|
+
stored_string = json_stringify(stored_output)
|
819
|
+
error_message = message + ' computed ' + stored_string + ' stored: ' + calculated_string
|
820
820
|
if key is not None:
|
821
|
-
error_message = ' | ' + key + ' | ' + 'computed value: ' +
|
821
|
+
error_message = ' | ' + key + ' | ' + 'computed value: ' + stored_string + ' stored value: ' + calculated_string
|
822
822
|
assert cond, error_message
|
823
823
|
|
824
824
|
def load_markets_from_file(self, id):
|
@@ -1140,7 +1140,9 @@ class testMainClass(baseMainTestClass):
|
|
1140
1140
|
close(exchange)
|
1141
1141
|
return True # in c# methods that will be used with promiseAll need to return something
|
1142
1142
|
|
1143
|
-
def get_number_of_tests_from_exchange(self, exchange, exchange_data):
|
1143
|
+
def get_number_of_tests_from_exchange(self, exchange, exchange_data, test_name=None):
|
1144
|
+
if test_name is not None:
|
1145
|
+
return 1
|
1144
1146
|
sum = 0
|
1145
1147
|
methods = exchange_data['methods']
|
1146
1148
|
methods_names = list(methods.keys())
|
@@ -1170,7 +1172,7 @@ class testMainClass(baseMainTestClass):
|
|
1170
1172
|
for i in range(0, len(exchanges)):
|
1171
1173
|
exchange_name = exchanges[i]
|
1172
1174
|
exchange_data = static_data[exchange_name]
|
1173
|
-
number_of_tests = self.get_number_of_tests_from_exchange(exchange, exchange_data)
|
1175
|
+
number_of_tests = self.get_number_of_tests_from_exchange(exchange, exchange_data, test_name)
|
1174
1176
|
sum = exchange.sum(sum, number_of_tests)
|
1175
1177
|
if type == 'request':
|
1176
1178
|
promises.append(self.test_exchange_request_statically(exchange_name, exchange_data, test_name))
|
@@ -1443,5 +1445,5 @@ class testMainClass(baseMainTestClass):
|
|
1443
1445
|
|
1444
1446
|
|
1445
1447
|
if __name__ == '__main__':
|
1446
|
-
symbol = argv.symbol if argv.symbol
|
1448
|
+
symbol = argv.symbol if argv.symbol else None
|
1447
1449
|
(testMainClass().init(argv.exchange, symbol))
|