ccxt 4.2.89__py2.py3-none-any.whl → 4.2.91__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/bingx.py +2 -0
- ccxt/abstract/bybit.py +2 -0
- ccxt/ascendex.py +1 -0
- ccxt/async_support/__init__.py +1 -1
- ccxt/async_support/ascendex.py +1 -0
- ccxt/async_support/base/exchange.py +13 -1
- ccxt/async_support/binance.py +81 -9
- ccxt/async_support/bingx.py +94 -1
- ccxt/async_support/bitfinex2.py +1 -0
- ccxt/async_support/bitget.py +2 -0
- ccxt/async_support/bitmex.py +1 -0
- ccxt/async_support/bitrue.py +1 -0
- ccxt/async_support/bybit.py +50 -0
- ccxt/async_support/coinbase.py +43 -21
- ccxt/async_support/coinbaseinternational.py +1 -0
- ccxt/async_support/coinex.py +96 -8
- ccxt/async_support/cryptocom.py +1 -0
- ccxt/async_support/delta.py +1 -0
- ccxt/async_support/digifinex.py +1 -0
- ccxt/async_support/exmo.py +1 -0
- ccxt/async_support/gate.py +2 -0
- ccxt/async_support/gemini.py +11 -9
- ccxt/async_support/hitbtc.py +1 -0
- ccxt/async_support/htx.py +1 -0
- ccxt/async_support/hyperliquid.py +1 -0
- ccxt/async_support/kraken.py +11 -8
- ccxt/async_support/kucoin.py +1 -0
- ccxt/async_support/kucoinfutures.py +32 -4
- ccxt/async_support/mexc.py +1 -0
- ccxt/async_support/okx.py +173 -38
- ccxt/async_support/phemex.py +1 -0
- ccxt/async_support/woo.py +1 -0
- ccxt/base/exchange.py +53 -14
- ccxt/base/types.py +1 -0
- ccxt/binance.py +81 -9
- ccxt/bingx.py +94 -1
- ccxt/bitfinex2.py +1 -0
- ccxt/bitget.py +2 -0
- ccxt/bitmex.py +1 -0
- ccxt/bitrue.py +1 -0
- ccxt/bybit.py +50 -0
- ccxt/coinbase.py +43 -21
- ccxt/coinbaseinternational.py +1 -0
- ccxt/coinex.py +96 -8
- ccxt/cryptocom.py +1 -0
- ccxt/delta.py +1 -0
- ccxt/digifinex.py +1 -0
- ccxt/exmo.py +1 -0
- ccxt/gate.py +2 -0
- ccxt/gemini.py +11 -9
- ccxt/hitbtc.py +1 -0
- ccxt/htx.py +1 -0
- ccxt/hyperliquid.py +1 -0
- ccxt/kraken.py +11 -8
- ccxt/kucoin.py +1 -0
- ccxt/kucoinfutures.py +32 -4
- ccxt/mexc.py +1 -0
- ccxt/okx.py +173 -38
- ccxt/phemex.py +1 -0
- ccxt/pro/__init__.py +1 -1
- ccxt/pro/bitmex.py +35 -17
- ccxt/pro/kucoin.py +85 -0
- ccxt/pro/kucoinfutures.py +141 -76
- ccxt/test/test_async.py +15 -1
- ccxt/test/test_sync.py +15 -1
- ccxt/woo.py +1 -0
- {ccxt-4.2.89.dist-info → ccxt-4.2.91.dist-info}/METADATA +4 -4
- {ccxt-4.2.89.dist-info → ccxt-4.2.91.dist-info}/RECORD +71 -71
- {ccxt-4.2.89.dist-info → ccxt-4.2.91.dist-info}/WHEEL +0 -0
- {ccxt-4.2.89.dist-info → ccxt-4.2.91.dist-info}/top_level.txt +0 -0
ccxt/okx.py
CHANGED
@@ -106,6 +106,7 @@ class okx(Exchange, ImplicitAPI):
|
|
106
106
|
'fetchLedgerEntry': None,
|
107
107
|
'fetchLeverage': True,
|
108
108
|
'fetchLeverageTiers': False,
|
109
|
+
'fetchMarginAdjustmentHistory': True,
|
109
110
|
'fetchMarketLeverageTiers': True,
|
110
111
|
'fetchMarkets': True,
|
111
112
|
'fetchMarkOHLCV': True,
|
@@ -1234,7 +1235,7 @@ class okx(Exchange, ImplicitAPI):
|
|
1234
1235
|
# ]
|
1235
1236
|
# }
|
1236
1237
|
#
|
1237
|
-
data = self.
|
1238
|
+
data = self.safe_list(response, 'data', [])
|
1238
1239
|
dataLength = len(data)
|
1239
1240
|
update = {
|
1240
1241
|
'updated': None,
|
@@ -1275,8 +1276,8 @@ class okx(Exchange, ImplicitAPI):
|
|
1275
1276
|
# "msg": ""
|
1276
1277
|
# }
|
1277
1278
|
#
|
1278
|
-
data = self.
|
1279
|
-
first = self.
|
1279
|
+
data = self.safe_list(response, 'data', [])
|
1280
|
+
first = self.safe_dict(data, 0, {})
|
1280
1281
|
return self.safe_integer(first, 'ts')
|
1281
1282
|
|
1282
1283
|
def fetch_accounts(self, params={}) -> List[Account]:
|
@@ -1306,7 +1307,7 @@ class okx(Exchange, ImplicitAPI):
|
|
1306
1307
|
# "msg": ""
|
1307
1308
|
# }
|
1308
1309
|
#
|
1309
|
-
data = self.
|
1310
|
+
data = self.safe_list(response, 'data', [])
|
1310
1311
|
result = []
|
1311
1312
|
for i in range(0, len(data)):
|
1312
1313
|
account = data[i]
|
@@ -1328,7 +1329,7 @@ class okx(Exchange, ImplicitAPI):
|
|
1328
1329
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
1329
1330
|
:returns dict[]: an array of objects representing market data
|
1330
1331
|
"""
|
1331
|
-
types = self.
|
1332
|
+
types = self.safe_list(self.options, 'fetchMarkets', [])
|
1332
1333
|
promises = []
|
1333
1334
|
result = []
|
1334
1335
|
for i in range(0, len(types)):
|
@@ -1425,7 +1426,7 @@ class okx(Exchange, ImplicitAPI):
|
|
1425
1426
|
symbol = symbol + '-' + ymd + '-' + strikePrice + '-' + optionType
|
1426
1427
|
optionType = 'put' if (optionType == 'P') else 'call'
|
1427
1428
|
tickSize = self.safe_string(market, 'tickSz')
|
1428
|
-
fees = self.
|
1429
|
+
fees = self.safe_dict_2(self.fees, type, 'trading', {})
|
1429
1430
|
maxLeverage = self.safe_string(market, 'lever', '1')
|
1430
1431
|
maxLeverage = Precise.string_max(maxLeverage, '1')
|
1431
1432
|
maxSpotCost = self.safe_number(market, 'maxMktSz')
|
@@ -1484,7 +1485,7 @@ class okx(Exchange, ImplicitAPI):
|
|
1484
1485
|
'instType': self.convert_to_instrument_type(type),
|
1485
1486
|
}
|
1486
1487
|
if type == 'option':
|
1487
|
-
optionsUnderlying = self.
|
1488
|
+
optionsUnderlying = self.safe_list(self.options, 'defaultUnderlying', ['BTC-USD', 'ETH-USD'])
|
1488
1489
|
promises = []
|
1489
1490
|
for i in range(0, len(optionsUnderlying)):
|
1490
1491
|
underlying = optionsUnderlying[i]
|
@@ -1493,8 +1494,8 @@ class okx(Exchange, ImplicitAPI):
|
|
1493
1494
|
promisesResult = promises
|
1494
1495
|
markets = []
|
1495
1496
|
for i in range(0, len(promisesResult)):
|
1496
|
-
res = self.
|
1497
|
-
options = self.
|
1497
|
+
res = self.safe_dict(promisesResult, i, {})
|
1498
|
+
options = self.safe_list(res, 'data', [])
|
1498
1499
|
markets = self.array_concat(markets, options)
|
1499
1500
|
return self.parse_markets(markets)
|
1500
1501
|
response = self.publicGetPublicInstruments(self.extend(request, params))
|
@@ -1531,7 +1532,7 @@ class okx(Exchange, ImplicitAPI):
|
|
1531
1532
|
# "msg": ""
|
1532
1533
|
# }
|
1533
1534
|
#
|
1534
|
-
dataResponse = self.
|
1535
|
+
dataResponse = self.safe_list(response, 'data', [])
|
1535
1536
|
return self.parse_markets(dataResponse)
|
1536
1537
|
|
1537
1538
|
def safe_network(self, networkId):
|
@@ -1605,7 +1606,7 @@ class okx(Exchange, ImplicitAPI):
|
|
1605
1606
|
# "msg": ""
|
1606
1607
|
# }
|
1607
1608
|
#
|
1608
|
-
data = self.
|
1609
|
+
data = self.safe_list(response, 'data', [])
|
1609
1610
|
result = {}
|
1610
1611
|
dataByCurrencyId = self.group_by(data, 'ccy')
|
1611
1612
|
currencyIds = list(dataByCurrencyId.keys())
|
@@ -1621,11 +1622,11 @@ class okx(Exchange, ImplicitAPI):
|
|
1621
1622
|
maxPrecision = None
|
1622
1623
|
for j in range(0, len(chains)):
|
1623
1624
|
chain = chains[j]
|
1624
|
-
canDeposit = self.
|
1625
|
+
canDeposit = self.safe_bool(chain, 'canDep')
|
1625
1626
|
depositEnabled = canDeposit if (canDeposit) else depositEnabled
|
1626
|
-
canWithdraw = self.
|
1627
|
+
canWithdraw = self.safe_bool(chain, 'canWd')
|
1627
1628
|
withdrawEnabled = canWithdraw if (canWithdraw) else withdrawEnabled
|
1628
|
-
canInternal = self.
|
1629
|
+
canInternal = self.safe_bool(chain, 'canInternal')
|
1629
1630
|
active = True if (canDeposit and canWithdraw and canInternal) else False
|
1630
1631
|
currencyActive = active if (active) else currencyActive
|
1631
1632
|
networkId = self.safe_string(chain, 'chain')
|
@@ -1654,7 +1655,7 @@ class okx(Exchange, ImplicitAPI):
|
|
1654
1655
|
},
|
1655
1656
|
'info': chain,
|
1656
1657
|
}
|
1657
|
-
firstChain = self.
|
1658
|
+
firstChain = self.safe_dict(chains, 0, {})
|
1658
1659
|
result[code] = {
|
1659
1660
|
'info': None,
|
1660
1661
|
'code': code,
|
@@ -1723,8 +1724,8 @@ class okx(Exchange, ImplicitAPI):
|
|
1723
1724
|
# ]
|
1724
1725
|
# }
|
1725
1726
|
#
|
1726
|
-
data = self.
|
1727
|
-
first = self.
|
1727
|
+
data = self.safe_list(response, 'data', [])
|
1728
|
+
first = self.safe_dict(data, 0, {})
|
1728
1729
|
timestamp = self.safe_integer(first, 'ts')
|
1729
1730
|
return self.parse_order_book(first, symbol, timestamp)
|
1730
1731
|
|
@@ -1823,7 +1824,7 @@ class okx(Exchange, ImplicitAPI):
|
|
1823
1824
|
# ]
|
1824
1825
|
# }
|
1825
1826
|
#
|
1826
|
-
data = self.
|
1827
|
+
data = self.safe_list(response, 'data', [])
|
1827
1828
|
first = self.safe_dict(data, 0, {})
|
1828
1829
|
return self.parse_ticker(first, market)
|
1829
1830
|
|
@@ -1844,7 +1845,7 @@ class okx(Exchange, ImplicitAPI):
|
|
1844
1845
|
'instType': self.convert_to_instrument_type(marketType),
|
1845
1846
|
}
|
1846
1847
|
if marketType == 'option':
|
1847
|
-
defaultUnderlying = self.
|
1848
|
+
defaultUnderlying = self.safe_string(self.options, 'defaultUnderlying', 'BTC-USD')
|
1848
1849
|
currencyId = self.safe_string_2(params, 'uly', 'marketId', defaultUnderlying)
|
1849
1850
|
if currencyId is None:
|
1850
1851
|
raise ArgumentsRequired(self.id + ' fetchTickers() requires an underlying uly or marketId parameter for options markets')
|
@@ -2093,7 +2094,7 @@ class okx(Exchange, ImplicitAPI):
|
|
2093
2094
|
return self.fetch_paginated_call_deterministic('fetchOHLCV', symbol, since, limit, timeframe, params, 200)
|
2094
2095
|
price = self.safe_string(params, 'price')
|
2095
2096
|
params = self.omit(params, 'price')
|
2096
|
-
options = self.
|
2097
|
+
options = self.safe_dict(self.options, 'fetchOHLCV', {})
|
2097
2098
|
timezone = self.safe_string(options, 'timezone', 'UTC')
|
2098
2099
|
if limit is None:
|
2099
2100
|
limit = 100 # default 100, max 100
|
@@ -2206,7 +2207,7 @@ class okx(Exchange, ImplicitAPI):
|
|
2206
2207
|
# }
|
2207
2208
|
#
|
2208
2209
|
rates = []
|
2209
|
-
data = self.
|
2210
|
+
data = self.safe_list(response, 'data', [])
|
2210
2211
|
for i in range(0, len(data)):
|
2211
2212
|
rate = data[i]
|
2212
2213
|
timestamp = self.safe_integer(rate, 'fundingTime')
|
@@ -2228,10 +2229,10 @@ class okx(Exchange, ImplicitAPI):
|
|
2228
2229
|
|
2229
2230
|
def parse_trading_balance(self, response):
|
2230
2231
|
result = {'info': response}
|
2231
|
-
data = self.
|
2232
|
-
first = self.
|
2232
|
+
data = self.safe_list(response, 'data', [])
|
2233
|
+
first = self.safe_dict(data, 0, {})
|
2233
2234
|
timestamp = self.safe_integer(first, 'uTime')
|
2234
|
-
details = self.
|
2235
|
+
details = self.safe_list(first, 'details', [])
|
2235
2236
|
for i in range(0, len(details)):
|
2236
2237
|
balance = details[i]
|
2237
2238
|
currencyId = self.safe_string(balance, 'ccy')
|
@@ -2253,7 +2254,7 @@ class okx(Exchange, ImplicitAPI):
|
|
2253
2254
|
|
2254
2255
|
def parse_funding_balance(self, response):
|
2255
2256
|
result = {'info': response}
|
2256
|
-
data = self.
|
2257
|
+
data = self.safe_list(response, 'data', [])
|
2257
2258
|
for i in range(0, len(data)):
|
2258
2259
|
balance = data[i]
|
2259
2260
|
currencyId = self.safe_string(balance, 'ccy')
|
@@ -2331,8 +2332,8 @@ class okx(Exchange, ImplicitAPI):
|
|
2331
2332
|
# "msg": ""
|
2332
2333
|
# }
|
2333
2334
|
#
|
2334
|
-
data = self.
|
2335
|
-
first = self.
|
2335
|
+
data = self.safe_list(response, 'data', [])
|
2336
|
+
first = self.safe_dict(data, 0, {})
|
2336
2337
|
return self.parse_trading_fee(first, market)
|
2337
2338
|
|
2338
2339
|
def fetch_balance(self, params={}) -> Balances:
|
@@ -2746,8 +2747,8 @@ class okx(Exchange, ImplicitAPI):
|
|
2746
2747
|
response = self.privatePostTradeOrderAlgo(request)
|
2747
2748
|
else:
|
2748
2749
|
response = self.privatePostTradeBatchOrders(request)
|
2749
|
-
data = self.
|
2750
|
-
first = self.
|
2750
|
+
data = self.safe_list(response, 'data', [])
|
2751
|
+
first = self.safe_dict(data, 0, {})
|
2751
2752
|
order = self.parse_order(first, market)
|
2752
2753
|
order['type'] = type
|
2753
2754
|
order['side'] = side
|
@@ -4126,7 +4127,7 @@ class okx(Exchange, ImplicitAPI):
|
|
4126
4127
|
# ]
|
4127
4128
|
# }
|
4128
4129
|
#
|
4129
|
-
data = self.
|
4130
|
+
data = self.safe_list(response, 'data', [])
|
4130
4131
|
return self.parse_ledger(data, currency, since, limit)
|
4131
4132
|
|
4132
4133
|
def parse_ledger_entry_type(self, type):
|
@@ -6035,9 +6036,9 @@ class okx(Exchange, ImplicitAPI):
|
|
6035
6036
|
# }
|
6036
6037
|
#
|
6037
6038
|
data = self.safe_list(response, 'data', [])
|
6039
|
+
entry = self.safe_dict(data, 0, {})
|
6038
6040
|
errorCode = self.safe_string(response, 'code')
|
6039
|
-
|
6040
|
-
return self.extend(self.parse_margin_modification(item, market), {
|
6041
|
+
return self.extend(self.parse_margin_modification(entry, market), {
|
6041
6042
|
'status': 'ok' if (errorCode == '0') else 'failed',
|
6042
6043
|
})
|
6043
6044
|
|
@@ -6052,22 +6053,66 @@ class okx(Exchange, ImplicitAPI):
|
|
6052
6053
|
# "type": "reduce"
|
6053
6054
|
# }
|
6054
6055
|
#
|
6055
|
-
|
6056
|
+
# fetchMarginAdjustmentHistory
|
6057
|
+
#
|
6058
|
+
# {
|
6059
|
+
# bal: '67621.4325135010619812',
|
6060
|
+
# balChg: '-10.0000000000000000',
|
6061
|
+
# billId: '691293628710342659',
|
6062
|
+
# ccy: 'USDT',
|
6063
|
+
# clOrdId: '',
|
6064
|
+
# execType: '',
|
6065
|
+
# fee: '0',
|
6066
|
+
# fillFwdPx: '',
|
6067
|
+
# fillIdxPx: '',
|
6068
|
+
# fillMarkPx: '',
|
6069
|
+
# fillMarkVol: '',
|
6070
|
+
# fillPxUsd: '',
|
6071
|
+
# fillPxVol: '',
|
6072
|
+
# fillTime: '1711089244850',
|
6073
|
+
# from: '',
|
6074
|
+
# instId: 'XRP-USDT-SWAP',
|
6075
|
+
# instType: 'SWAP',
|
6076
|
+
# interest: '0',
|
6077
|
+
# mgnMode: 'isolated',
|
6078
|
+
# notes: '',
|
6079
|
+
# ordId: '',
|
6080
|
+
# pnl: '0',
|
6081
|
+
# posBal: '73.12',
|
6082
|
+
# posBalChg: '10.00',
|
6083
|
+
# px: '',
|
6084
|
+
# subType: '160',
|
6085
|
+
# sz: '10',
|
6086
|
+
# tag: '',
|
6087
|
+
# to: '',
|
6088
|
+
# tradeId: '0',
|
6089
|
+
# ts: '1711089244699',
|
6090
|
+
# type: '6'
|
6091
|
+
# }
|
6092
|
+
#
|
6093
|
+
amountRaw = self.safe_string_2(data, 'amt', 'posBalChg')
|
6056
6094
|
typeRaw = self.safe_string(data, 'type')
|
6057
|
-
type =
|
6095
|
+
type = None
|
6096
|
+
if typeRaw == '6':
|
6097
|
+
type = 'add' if Precise.string_gt(amountRaw, '0') else 'reduce'
|
6098
|
+
else:
|
6099
|
+
type = typeRaw
|
6100
|
+
amount = Precise.string_abs(amountRaw)
|
6058
6101
|
marketId = self.safe_string(data, 'instId')
|
6059
6102
|
responseMarket = self.safe_market(marketId, market)
|
6060
6103
|
code = responseMarket['base'] if responseMarket['inverse'] else responseMarket['quote']
|
6104
|
+
timestamp = self.safe_integer(data, 'ts')
|
6061
6105
|
return {
|
6062
6106
|
'info': data,
|
6063
6107
|
'symbol': responseMarket['symbol'],
|
6064
6108
|
'type': type,
|
6065
|
-
'
|
6066
|
-
'
|
6109
|
+
'marginMode': 'isolated',
|
6110
|
+
'amount': self.parse_number(amount),
|
6067
6111
|
'code': code,
|
6112
|
+
'total': None,
|
6068
6113
|
'status': None,
|
6069
|
-
'timestamp':
|
6070
|
-
'datetime':
|
6114
|
+
'timestamp': timestamp,
|
6115
|
+
'datetime': self.iso8601(timestamp),
|
6071
6116
|
}
|
6072
6117
|
|
6073
6118
|
def reduce_margin(self, symbol: str, amount, params={}) -> MarginModification:
|
@@ -7088,3 +7133,93 @@ class okx(Exchange, ImplicitAPI):
|
|
7088
7133
|
self.throw_exactly_matched_exception(self.exceptions['exact'], code, feedback)
|
7089
7134
|
raise ExchangeError(feedback) # unknown message
|
7090
7135
|
return None
|
7136
|
+
|
7137
|
+
def fetch_margin_adjustment_history(self, symbol: Str = None, type: Str = None, since: Num = None, limit: Num = None, params={}) -> List[MarginModification]:
|
7138
|
+
"""
|
7139
|
+
fetches the history of margin added or reduced from contract isolated positions
|
7140
|
+
:see: https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-bills-details-last-7-days
|
7141
|
+
:see: https://www.okx.com/docs-v5/en/#trading-account-rest-api-get-bills-details-last-3-months
|
7142
|
+
:param str [symbol]: not used by okx fetchMarginAdjustmentHistory
|
7143
|
+
:param str [type]: "add" or "reduce"
|
7144
|
+
:param dict params: extra parameters specific to the exchange api endpoint
|
7145
|
+
:param boolean [params.auto]: True if fetching auto margin increases
|
7146
|
+
:returns dict[]: a list of `margin structures <https://docs.ccxt.com/#/?id=margin-loan-structure>`
|
7147
|
+
"""
|
7148
|
+
self.load_markets()
|
7149
|
+
auto = self.safe_bool(params, 'auto')
|
7150
|
+
if type is None:
|
7151
|
+
raise ArgumentsRequired(self.id + ' fetchMarginAdjustmentHistory() requires a type argument')
|
7152
|
+
isAdd = type == 'add'
|
7153
|
+
subType = '160' if isAdd else '161'
|
7154
|
+
if auto:
|
7155
|
+
if isAdd:
|
7156
|
+
subType = '162'
|
7157
|
+
else:
|
7158
|
+
raise BadRequest(self.id + ' cannot fetch margin adjustments for type ' + type)
|
7159
|
+
request = {
|
7160
|
+
'subType': subType,
|
7161
|
+
'mgnMode': 'isolated',
|
7162
|
+
}
|
7163
|
+
until = self.safe_integer(params, 'until')
|
7164
|
+
params = self.omit(params, 'until')
|
7165
|
+
if since is not None:
|
7166
|
+
request['startTime'] = since
|
7167
|
+
if limit is not None:
|
7168
|
+
request['limit'] = limit
|
7169
|
+
if until is not None:
|
7170
|
+
request['endTime'] = until
|
7171
|
+
response = None
|
7172
|
+
now = self.milliseconds()
|
7173
|
+
oneWeekAgo = now - 604800000
|
7174
|
+
threeMonthsAgo = now - 7776000000
|
7175
|
+
if (since is None) or (since > oneWeekAgo):
|
7176
|
+
response = self.privateGetAccountBills(self.extend(request, params))
|
7177
|
+
elif since > threeMonthsAgo:
|
7178
|
+
response = self.privateGetAccountBillsArchive(self.extend(request, params))
|
7179
|
+
else:
|
7180
|
+
raise BadRequest(self.id + ' fetchMarginAdjustmentHistory() cannot fetch margin adjustments older than 3 months')
|
7181
|
+
#
|
7182
|
+
# {
|
7183
|
+
# code: '0',
|
7184
|
+
# data: [
|
7185
|
+
# {
|
7186
|
+
# bal: '67621.4325135010619812',
|
7187
|
+
# balChg: '-10.0000000000000000',
|
7188
|
+
# billId: '691293628710342659',
|
7189
|
+
# ccy: 'USDT',
|
7190
|
+
# clOrdId: '',
|
7191
|
+
# execType: '',
|
7192
|
+
# fee: '0',
|
7193
|
+
# fillFwdPx: '',
|
7194
|
+
# fillIdxPx: '',
|
7195
|
+
# fillMarkPx: '',
|
7196
|
+
# fillMarkVol: '',
|
7197
|
+
# fillPxUsd: '',
|
7198
|
+
# fillPxVol: '',
|
7199
|
+
# fillTime: '1711089244850',
|
7200
|
+
# from: '',
|
7201
|
+
# instId: 'XRP-USDT-SWAP',
|
7202
|
+
# instType: 'SWAP',
|
7203
|
+
# interest: '0',
|
7204
|
+
# mgnMode: 'isolated',
|
7205
|
+
# notes: '',
|
7206
|
+
# ordId: '',
|
7207
|
+
# pnl: '0',
|
7208
|
+
# posBal: '73.12',
|
7209
|
+
# posBalChg: '10.00',
|
7210
|
+
# px: '',
|
7211
|
+
# subType: '160',
|
7212
|
+
# sz: '10',
|
7213
|
+
# tag: '',
|
7214
|
+
# to: '',
|
7215
|
+
# tradeId: '0',
|
7216
|
+
# ts: '1711089244699',
|
7217
|
+
# type: '6'
|
7218
|
+
# }
|
7219
|
+
# ],
|
7220
|
+
# msg: ''
|
7221
|
+
# }
|
7222
|
+
#
|
7223
|
+
data = self.safe_list(response, 'data')
|
7224
|
+
modifications = self.parse_margin_modifications(data)
|
7225
|
+
return self.filter_by_symbol_since_limit(modifications, symbol, since, limit)
|
ccxt/phemex.py
CHANGED
ccxt/pro/__init__.py
CHANGED
ccxt/pro/bitmex.py
CHANGED
@@ -540,8 +540,8 @@ class bitmex(ccxt.async_support.bitmex):
|
|
540
540
|
for i in range(0, len(marketIds)):
|
541
541
|
marketId = marketIds[i]
|
542
542
|
market = self.safe_market(marketId)
|
543
|
-
messageHash = table + ':' + marketId
|
544
543
|
symbol = market['symbol']
|
544
|
+
messageHash = table + ':' + symbol
|
545
545
|
trades = self.parse_trades(dataByMarketIds[marketId], market)
|
546
546
|
stored = self.safe_value(self.trades, symbol)
|
547
547
|
if stored is None:
|
@@ -561,22 +561,7 @@ class bitmex(ccxt.async_support.bitmex):
|
|
561
561
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
562
562
|
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
563
563
|
"""
|
564
|
-
await self.
|
565
|
-
market = self.market(symbol)
|
566
|
-
symbol = market['symbol']
|
567
|
-
table = 'trade'
|
568
|
-
messageHash = table + ':' + market['id']
|
569
|
-
url = self.urls['api']['ws']
|
570
|
-
request = {
|
571
|
-
'op': 'subscribe',
|
572
|
-
'args': [
|
573
|
-
messageHash,
|
574
|
-
],
|
575
|
-
}
|
576
|
-
trades = await self.watch(url, messageHash, self.extend(request, params), messageHash)
|
577
|
-
if self.newUpdates:
|
578
|
-
limit = trades.getLimit(symbol, limit)
|
579
|
-
return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
|
564
|
+
return await self.watch_trades_for_symbols([symbol], since, limit, params)
|
580
565
|
|
581
566
|
async def authenticate(self, params={}):
|
582
567
|
url = self.urls['api']['ws']
|
@@ -1171,6 +1156,39 @@ class bitmex(ccxt.async_support.bitmex):
|
|
1171
1156
|
orderbook = await self.watch_multiple(url, messageHashes, self.deep_extend(request, params), topics)
|
1172
1157
|
return orderbook.limit()
|
1173
1158
|
|
1159
|
+
async def watch_trades_for_symbols(self, symbols: List[str], since: Int = None, limit: Int = None, params={}) -> List[Trade]:
|
1160
|
+
"""
|
1161
|
+
get the list of most recent trades for a list of symbols
|
1162
|
+
:param str[] symbols: unified symbol of the market to fetch trades for
|
1163
|
+
:param int [since]: timestamp in ms of the earliest trade to fetch
|
1164
|
+
:param int [limit]: the maximum amount of trades to fetch
|
1165
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
1166
|
+
:returns dict[]: a list of `trade structures <https://docs.ccxt.com/#/?id=public-trades>`
|
1167
|
+
"""
|
1168
|
+
await self.load_markets()
|
1169
|
+
symbols = self.market_symbols(symbols, None, False)
|
1170
|
+
table = 'trade'
|
1171
|
+
topics = []
|
1172
|
+
messageHashes = []
|
1173
|
+
for i in range(0, len(symbols)):
|
1174
|
+
symbol = symbols[i]
|
1175
|
+
market = self.market(symbol)
|
1176
|
+
topic = table + ':' + market['id']
|
1177
|
+
topics.append(topic)
|
1178
|
+
messageHash = table + ':' + symbol
|
1179
|
+
messageHashes.append(messageHash)
|
1180
|
+
url = self.urls['api']['ws']
|
1181
|
+
request = {
|
1182
|
+
'op': 'subscribe',
|
1183
|
+
'args': topics,
|
1184
|
+
}
|
1185
|
+
trades = await self.watch_multiple(url, messageHashes, self.deep_extend(request, params), topics)
|
1186
|
+
if self.newUpdates:
|
1187
|
+
first = self.safe_value(trades, 0)
|
1188
|
+
tradeSymbol = self.safe_string(first, 'symbol')
|
1189
|
+
limit = trades.getLimit(tradeSymbol, limit)
|
1190
|
+
return self.filter_by_since_limit(trades, since, limit, 'timestamp', True)
|
1191
|
+
|
1174
1192
|
async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
1175
1193
|
"""
|
1176
1194
|
watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
ccxt/pro/kucoin.py
CHANGED
@@ -25,6 +25,7 @@ class kucoin(ccxt.async_support.kucoin):
|
|
25
25
|
'cancelOrderWs': False,
|
26
26
|
'cancelOrdersWs': False,
|
27
27
|
'cancelAllOrdersWs': False,
|
28
|
+
'watchBidsAsks': True,
|
28
29
|
'watchOrderBook': True,
|
29
30
|
'watchOrders': True,
|
30
31
|
'watchMyTrades': True,
|
@@ -273,6 +274,87 @@ class kucoin(ccxt.async_support.kucoin):
|
|
273
274
|
if numTickers > 0:
|
274
275
|
client.resolve(tickers, currentMessageHash)
|
275
276
|
|
277
|
+
async def watch_bids_asks(self, symbols: Strings = None, params={}) -> Tickers:
|
278
|
+
"""
|
279
|
+
:see: https://www.kucoin.com/docs/websocket/spot-trading/public-channels/level1-bbo-market-data
|
280
|
+
watches best bid & ask for symbols
|
281
|
+
:param str[] symbols: unified symbol of the market to fetch the ticker for
|
282
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
283
|
+
:returns dict: a `ticker structure <https://docs.ccxt.com/#/?id=ticker-structure>`
|
284
|
+
"""
|
285
|
+
ticker = await self.watch_multi_helper('watchBidsAsks', '/spotMarket/level1:', symbols, params)
|
286
|
+
if self.newUpdates:
|
287
|
+
tickers = {}
|
288
|
+
tickers[ticker['symbol']] = ticker
|
289
|
+
return tickers
|
290
|
+
return self.filter_by_array(self.bidsasks, 'symbol', symbols)
|
291
|
+
|
292
|
+
async def watch_multi_helper(self, methodName, channelName: str, symbols: Strings = None, params={}):
|
293
|
+
await self.load_markets()
|
294
|
+
symbols = self.market_symbols(symbols, None, False, True, False)
|
295
|
+
length = len(symbols)
|
296
|
+
if length > 100:
|
297
|
+
raise ArgumentsRequired(self.id + ' ' + methodName + '() accepts a maximum of 100 symbols')
|
298
|
+
messageHashes = []
|
299
|
+
for i in range(0, len(symbols)):
|
300
|
+
symbol = symbols[i]
|
301
|
+
market = self.market(symbol)
|
302
|
+
messageHashes.append('bidask@' + market['symbol'])
|
303
|
+
url = await self.negotiate(False)
|
304
|
+
marketIds = self.market_ids(symbols)
|
305
|
+
joined = ','.join(marketIds)
|
306
|
+
requestId = str(self.request_id())
|
307
|
+
request = {
|
308
|
+
'id': requestId,
|
309
|
+
'type': 'subscribe',
|
310
|
+
'topic': channelName + joined,
|
311
|
+
'response': True,
|
312
|
+
}
|
313
|
+
message = self.extend(request, params)
|
314
|
+
return await self.watch_multiple(url, messageHashes, message, messageHashes)
|
315
|
+
|
316
|
+
def handle_bid_ask(self, client: Client, message):
|
317
|
+
#
|
318
|
+
# arrives one symbol dict
|
319
|
+
#
|
320
|
+
# {
|
321
|
+
# topic: '/spotMarket/level1:ETH-USDT',
|
322
|
+
# type: 'message',
|
323
|
+
# data: {
|
324
|
+
# asks: ['3347.42', '2.0778387'],
|
325
|
+
# bids: ['3347.41', '6.0411697'],
|
326
|
+
# timestamp: 1712231142085
|
327
|
+
# },
|
328
|
+
# subject: 'level1'
|
329
|
+
# }
|
330
|
+
#
|
331
|
+
parsedTicker = self.parse_ws_bid_ask(message)
|
332
|
+
symbol = parsedTicker['symbol']
|
333
|
+
self.bidsasks[symbol] = parsedTicker
|
334
|
+
messageHash = 'bidask@' + symbol
|
335
|
+
client.resolve(parsedTicker, messageHash)
|
336
|
+
|
337
|
+
def parse_ws_bid_ask(self, ticker, market=None):
|
338
|
+
topic = self.safe_string(ticker, 'topic')
|
339
|
+
parts = topic.split(':')
|
340
|
+
marketId = parts[1]
|
341
|
+
market = self.safe_market(marketId, market)
|
342
|
+
symbol = self.safe_string(market, 'symbol')
|
343
|
+
data = self.safe_dict(ticker, 'data', {})
|
344
|
+
ask = self.safe_list(data, 'asks', [])
|
345
|
+
bid = self.safe_list(data, 'bids', [])
|
346
|
+
timestamp = self.safe_integer(data, 'timestamp')
|
347
|
+
return self.safe_ticker({
|
348
|
+
'symbol': symbol,
|
349
|
+
'timestamp': timestamp,
|
350
|
+
'datetime': self.iso8601(timestamp),
|
351
|
+
'ask': self.safe_number(ask, 0),
|
352
|
+
'askVolume': self.safe_number(ask, 1),
|
353
|
+
'bid': self.safe_number(bid, 0),
|
354
|
+
'bidVolume': self.safe_number(bid, 1),
|
355
|
+
'info': ticker,
|
356
|
+
}, market)
|
357
|
+
|
276
358
|
async def watch_ohlcv(self, symbol: str, timeframe='1m', since: Int = None, limit: Int = None, params={}) -> List[list]:
|
277
359
|
"""
|
278
360
|
watches historical candlestick data containing the open, high, low, and close price, and the volume of a market
|
@@ -625,6 +707,8 @@ class kucoin(ccxt.async_support.kucoin):
|
|
625
707
|
# }
|
626
708
|
#
|
627
709
|
id = self.safe_string(message, 'id')
|
710
|
+
if not (id in client.subscriptions):
|
711
|
+
return
|
628
712
|
subscriptionHash = self.safe_string(client.subscriptions, id)
|
629
713
|
subscription = self.safe_value(client.subscriptions, subscriptionHash)
|
630
714
|
del client.subscriptions[id]
|
@@ -978,6 +1062,7 @@ class kucoin(ccxt.async_support.kucoin):
|
|
978
1062
|
return
|
979
1063
|
subject = self.safe_string(message, 'subject')
|
980
1064
|
methods = {
|
1065
|
+
'level1': self.handle_bid_ask,
|
981
1066
|
'level2': self.handle_order_book,
|
982
1067
|
'trade.l2update': self.handle_order_book,
|
983
1068
|
'trade.ticker': self.handle_ticker,
|