ccxt 4.2.47__py2.py3-none-any.whl → 4.2.49__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/bitstamp.py +8 -0
- ccxt/abstract/indodax.py +9 -8
- ccxt/async_support/__init__.py +1 -1
- ccxt/async_support/base/exchange.py +1 -1
- ccxt/async_support/binance.py +9 -4
- ccxt/async_support/bitmart.py +24 -2
- ccxt/async_support/bitstamp.py +8 -0
- ccxt/async_support/btcalpha.py +4 -0
- ccxt/async_support/btcmarkets.py +4 -0
- ccxt/async_support/btcturk.py +4 -0
- ccxt/async_support/bybit.py +132 -6
- ccxt/async_support/idex.py +48 -1
- ccxt/async_support/independentreserve.py +47 -1
- ccxt/async_support/indodax.py +115 -19
- ccxt/async_support/latoken.py +16 -0
- ccxt/async_support/luno.py +18 -0
- ccxt/async_support/lykke.py +19 -0
- ccxt/async_support/ndax.py +18 -0
- ccxt/async_support/okx.py +32 -5
- ccxt/async_support/upbit.py +92 -17
- ccxt/base/exchange.py +2 -2
- ccxt/binance.py +9 -4
- ccxt/bitmart.py +24 -2
- ccxt/bitstamp.py +8 -0
- ccxt/btcalpha.py +4 -0
- ccxt/btcmarkets.py +4 -0
- ccxt/btcturk.py +4 -0
- ccxt/bybit.py +132 -6
- ccxt/idex.py +48 -1
- ccxt/independentreserve.py +47 -1
- ccxt/indodax.py +115 -19
- ccxt/latoken.py +16 -0
- ccxt/luno.py +18 -0
- ccxt/lykke.py +19 -0
- ccxt/ndax.py +18 -0
- ccxt/okx.py +32 -5
- ccxt/pro/__init__.py +1 -1
- ccxt/pro/ascendex.py +19 -7
- ccxt/pro/bitget.py +24 -7
- ccxt/pro/bitstamp.py +1 -1
- ccxt/pro/hitbtc.py +6 -11
- ccxt/pro/mexc.py +2 -1
- ccxt/test/test_async.py +10 -10
- ccxt/test/test_sync.py +10 -10
- ccxt/upbit.py +92 -17
- {ccxt-4.2.47.dist-info → ccxt-4.2.49.dist-info}/METADATA +4 -4
- {ccxt-4.2.47.dist-info → ccxt-4.2.49.dist-info}/RECORD +50 -50
- {ccxt-4.2.47.dist-info → ccxt-4.2.49.dist-info}/WHEEL +0 -0
- {ccxt-4.2.47.dist-info → ccxt-4.2.49.dist-info}/top_level.txt +0 -0
ccxt/pro/ascendex.py
CHANGED
@@ -202,7 +202,7 @@ class ascendex(ccxt.async_support.ascendex):
|
|
202
202
|
"""
|
203
203
|
await self.load_markets()
|
204
204
|
market = self.market(symbol)
|
205
|
-
channel = 'depth
|
205
|
+
channel = 'depth' + ':' + market['id']
|
206
206
|
params = self.extend(params, {
|
207
207
|
'ch': channel,
|
208
208
|
})
|
@@ -212,7 +212,7 @@ class ascendex(ccxt.async_support.ascendex):
|
|
212
212
|
async def watch_order_book_snapshot(self, symbol: str, limit: Int = None, params={}):
|
213
213
|
await self.load_markets()
|
214
214
|
market = self.market(symbol)
|
215
|
-
action = 'depth-snapshot
|
215
|
+
action = 'depth-snapshot'
|
216
216
|
channel = action + ':' + market['id']
|
217
217
|
params = self.extend(params, {
|
218
218
|
'action': action,
|
@@ -224,6 +224,14 @@ class ascendex(ccxt.async_support.ascendex):
|
|
224
224
|
orderbook = await self.watch_public(channel, params)
|
225
225
|
return orderbook.limit()
|
226
226
|
|
227
|
+
async def fetch_order_book_snapshot(self, symbol: str, limit: Int = None, params={}):
|
228
|
+
restOrderBook = await self.fetch_rest_order_book_safe(symbol, limit, params)
|
229
|
+
if not (symbol in self.orderbooks):
|
230
|
+
self.orderbooks[symbol] = self.order_book()
|
231
|
+
orderbook = self.orderbooks[symbol]
|
232
|
+
orderbook.reset(restOrderBook)
|
233
|
+
return orderbook
|
234
|
+
|
227
235
|
def handle_order_book_snapshot(self, client: Client, message):
|
228
236
|
#
|
229
237
|
# {
|
@@ -826,8 +834,8 @@ class ascendex(ccxt.async_support.ascendex):
|
|
826
834
|
'ping': self.handle_ping,
|
827
835
|
'auth': self.handle_authenticate,
|
828
836
|
'sub': self.handle_subscription_status,
|
829
|
-
'depth
|
830
|
-
'depth-snapshot
|
837
|
+
'depth': self.handle_order_book,
|
838
|
+
'depth-snapshot': self.handle_order_book_snapshot,
|
831
839
|
'trades': self.handle_trades,
|
832
840
|
'bar': self.handle_ohlcv,
|
833
841
|
'balance': self.handle_balance,
|
@@ -851,7 +859,7 @@ class ascendex(ccxt.async_support.ascendex):
|
|
851
859
|
# {m: 'sub', id: "1647515701", ch: "depth:BTC/USDT", code: 0}
|
852
860
|
#
|
853
861
|
channel = self.safe_string(message, 'ch', '')
|
854
|
-
if channel.find('depth-
|
862
|
+
if channel.find('depth') > -1 and not (channel.find('depth-snapshot') > -1):
|
855
863
|
self.handle_order_book_subscription(client, message)
|
856
864
|
return message
|
857
865
|
|
@@ -859,11 +867,15 @@ class ascendex(ccxt.async_support.ascendex):
|
|
859
867
|
channel = self.safe_string(message, 'ch')
|
860
868
|
parts = channel.split(':')
|
861
869
|
marketId = parts[1]
|
862
|
-
|
870
|
+
market = self.safe_market(marketId)
|
871
|
+
symbol = market['symbol']
|
863
872
|
if symbol in self.orderbooks:
|
864
873
|
del self.orderbooks[symbol]
|
865
874
|
self.orderbooks[symbol] = self.order_book({})
|
866
|
-
self.
|
875
|
+
if self.options['defaultType'] == 'swap' or market['contract']:
|
876
|
+
self.spawn(self.fetch_order_book_snapshot, symbol)
|
877
|
+
else:
|
878
|
+
self.spawn(self.watch_order_book_snapshot, symbol)
|
867
879
|
|
868
880
|
async def pong(self, client, message):
|
869
881
|
#
|
ccxt/pro/bitget.py
CHANGED
@@ -908,6 +908,7 @@ class bitget(ccxt.async_support.bitget):
|
|
908
908
|
# "clientOid": "798d1425-d31d-4ada-a51b-ec701e00a1d9",
|
909
909
|
# "price": "35000.00",
|
910
910
|
# "size": "7.0000",
|
911
|
+
# "newSize": "500.0000",
|
911
912
|
# "notional": "7.000000",
|
912
913
|
# "orderType": "limit",
|
913
914
|
# "force": "gtc",
|
@@ -1069,6 +1070,7 @@ class bitget(ccxt.async_support.bitget):
|
|
1069
1070
|
# "clientOid": "798d1425-d31d-4ada-a51b-ec701e00a1d9",
|
1070
1071
|
# "price": "35000.00",
|
1071
1072
|
# "size": "7.0000",
|
1073
|
+
# "newSize": "500.0000",
|
1072
1074
|
# "notional": "7.000000",
|
1073
1075
|
# "orderType": "limit",
|
1074
1076
|
# "force": "gtc",
|
@@ -1175,6 +1177,21 @@ class bitget(ccxt.async_support.bitget):
|
|
1175
1177
|
'currency': self.safe_currency_code(feeCurrency),
|
1176
1178
|
}
|
1177
1179
|
triggerPrice = self.safe_number(order, 'triggerPrice')
|
1180
|
+
price = self.safe_string(order, 'price')
|
1181
|
+
avgPrice = self.omit_zero(self.safe_string_2(order, 'priceAvg', 'fillPrice'))
|
1182
|
+
cost = self.safe_string_n(order, ['notional', 'notionalUsd', 'quoteSize'])
|
1183
|
+
side = self.safe_string(order, 'side')
|
1184
|
+
type = self.safe_string(order, 'orderType')
|
1185
|
+
if side == 'buy' and market['spot'] and (type == 'market'):
|
1186
|
+
cost = self.safe_string(order, 'newSize', cost)
|
1187
|
+
filled = self.safe_string_2(order, 'accBaseVolume', 'baseVolume')
|
1188
|
+
if market['spot'] and (rawStatus != 'live'):
|
1189
|
+
filled = Precise.string_div(cost, avgPrice)
|
1190
|
+
amount = self.safe_string(order, 'baseVolume')
|
1191
|
+
if not market['spot'] or not (side == 'buy' and type == 'market'):
|
1192
|
+
amount = self.safe_string(order, 'newSize', amount)
|
1193
|
+
if market['swap'] and (amount is None):
|
1194
|
+
amount = self.safe_string(order, 'size')
|
1178
1195
|
return self.safe_order({
|
1179
1196
|
'info': order,
|
1180
1197
|
'symbol': symbol,
|
@@ -1183,17 +1200,17 @@ class bitget(ccxt.async_support.bitget):
|
|
1183
1200
|
'timestamp': timestamp,
|
1184
1201
|
'datetime': self.iso8601(timestamp),
|
1185
1202
|
'lastTradeTimestamp': self.safe_integer(order, 'uTime'),
|
1186
|
-
'type':
|
1203
|
+
'type': type,
|
1187
1204
|
'timeInForce': self.safe_string_upper(order, 'force'),
|
1188
1205
|
'postOnly': None,
|
1189
|
-
'side':
|
1190
|
-
'price':
|
1206
|
+
'side': side,
|
1207
|
+
'price': price,
|
1191
1208
|
'stopPrice': triggerPrice,
|
1192
1209
|
'triggerPrice': triggerPrice,
|
1193
|
-
'amount':
|
1194
|
-
'cost':
|
1195
|
-
'average':
|
1196
|
-
'filled':
|
1210
|
+
'amount': amount,
|
1211
|
+
'cost': cost,
|
1212
|
+
'average': avgPrice,
|
1213
|
+
'filled': filled,
|
1197
1214
|
'remaining': None,
|
1198
1215
|
'status': self.parse_ws_order_status(rawStatus),
|
1199
1216
|
'fee': feeObject,
|
ccxt/pro/bitstamp.py
CHANGED
@@ -111,7 +111,7 @@ class bitstamp(ccxt.async_support.bitstamp):
|
|
111
111
|
# usually it takes at least 4-5 deltas to resolve
|
112
112
|
snapshotDelay = self.handle_option('watchOrderBook', 'snapshotDelay', 6)
|
113
113
|
if cacheLength == snapshotDelay:
|
114
|
-
self.spawn(self.load_order_book, client, messageHash, symbol)
|
114
|
+
self.spawn(self.load_order_book, client, messageHash, symbol, None, {})
|
115
115
|
storedOrderBook.cache.append(delta)
|
116
116
|
return
|
117
117
|
elif nonce >= deltaNonce:
|
ccxt/pro/hitbtc.py
CHANGED
@@ -215,7 +215,7 @@ class hitbtc(ccxt.async_support.hitbtc):
|
|
215
215
|
'symbols': [market['id']],
|
216
216
|
},
|
217
217
|
}
|
218
|
-
orderbook = await self.subscribe_public(name,
|
218
|
+
orderbook = await self.subscribe_public(name, 'orderbooks', [symbol], self.deep_extend(request, params))
|
219
219
|
return orderbook.limit()
|
220
220
|
|
221
221
|
def handle_order_book(self, client: Client, message):
|
@@ -244,13 +244,12 @@ class hitbtc(ccxt.async_support.hitbtc):
|
|
244
244
|
#
|
245
245
|
data = self.safe_value_2(message, 'snapshot', 'update', {})
|
246
246
|
marketIds = list(data.keys())
|
247
|
-
channel = self.safe_string(message, 'ch')
|
248
247
|
for i in range(0, len(marketIds)):
|
249
248
|
marketId = marketIds[i]
|
250
249
|
market = self.safe_market(marketId)
|
251
250
|
symbol = market['symbol']
|
252
251
|
item = data[marketId]
|
253
|
-
messageHash =
|
252
|
+
messageHash = 'orderbooks::' + symbol
|
254
253
|
if not (symbol in self.orderbooks):
|
255
254
|
subscription = self.safe_value(client.subscriptions, messageHash, {})
|
256
255
|
limit = self.safe_integer(subscription, 'limit')
|
@@ -303,7 +302,7 @@ class hitbtc(ccxt.async_support.hitbtc):
|
|
303
302
|
'symbols': [market['id']],
|
304
303
|
},
|
305
304
|
}
|
306
|
-
result = await self.subscribe_public(name, '
|
305
|
+
result = await self.subscribe_public(name, 'tickers', [symbol], self.deep_extend(request, params))
|
307
306
|
return self.safe_value(result, symbol)
|
308
307
|
|
309
308
|
async def watch_tickers(self, symbols: Strings = None, params={}) -> Tickers:
|
@@ -380,7 +379,6 @@ class hitbtc(ccxt.async_support.hitbtc):
|
|
380
379
|
#
|
381
380
|
data = self.safe_value(message, 'data', {})
|
382
381
|
marketIds = list(data.keys())
|
383
|
-
channel = self.safe_string(message, 'ch')
|
384
382
|
newTickers = {}
|
385
383
|
for i in range(0, len(marketIds)):
|
386
384
|
marketId = marketIds[i]
|
@@ -389,8 +387,6 @@ class hitbtc(ccxt.async_support.hitbtc):
|
|
389
387
|
ticker = self.parse_ws_ticker(data[marketId], market)
|
390
388
|
self.tickers[symbol] = ticker
|
391
389
|
newTickers[symbol] = ticker
|
392
|
-
messageHash = channel + '::' + symbol
|
393
|
-
client.resolve(newTickers, messageHash)
|
394
390
|
client.resolve(newTickers, 'tickers')
|
395
391
|
messageHashes = self.find_message_hashes(client, 'tickers::')
|
396
392
|
for i in range(0, len(messageHashes)):
|
@@ -403,7 +399,6 @@ class hitbtc(ccxt.async_support.hitbtc):
|
|
403
399
|
numTickers = len(tickersSymbols)
|
404
400
|
if numTickers > 0:
|
405
401
|
client.resolve(tickers, messageHash)
|
406
|
-
client.resolve(self.tickers, channel)
|
407
402
|
return message
|
408
403
|
|
409
404
|
def parse_ws_ticker(self, ticker, market=None):
|
@@ -481,7 +476,7 @@ class hitbtc(ccxt.async_support.hitbtc):
|
|
481
476
|
if limit is not None:
|
482
477
|
request['limit'] = limit
|
483
478
|
name = 'trades'
|
484
|
-
trades = await self.subscribe_public(name,
|
479
|
+
trades = await self.subscribe_public(name, 'trades', [symbol], self.deep_extend(request, params))
|
485
480
|
if self.newUpdates:
|
486
481
|
limit = trades.getLimit(symbol, limit)
|
487
482
|
return self.filter_by_since_limit(trades, since, limit, 'timestamp')
|
@@ -602,7 +597,7 @@ class hitbtc(ccxt.async_support.hitbtc):
|
|
602
597
|
}
|
603
598
|
if limit is not None:
|
604
599
|
request['params']['limit'] = limit
|
605
|
-
ohlcv = await self.subscribe_public(name,
|
600
|
+
ohlcv = await self.subscribe_public(name, 'candles', [symbol], self.deep_extend(request, params))
|
606
601
|
if self.newUpdates:
|
607
602
|
limit = ohlcv.getLimit(symbol, limit)
|
608
603
|
return self.filter_by_since_limit(ohlcv, since, limit, 0)
|
@@ -660,7 +655,7 @@ class hitbtc(ccxt.async_support.hitbtc):
|
|
660
655
|
ohlcvs = self.parse_ws_ohlcvs(data[marketId], market)
|
661
656
|
for j in range(0, len(ohlcvs)):
|
662
657
|
stored.append(ohlcvs[j])
|
663
|
-
messageHash =
|
658
|
+
messageHash = 'candles::' + symbol
|
664
659
|
client.resolve(stored, messageHash)
|
665
660
|
return message
|
666
661
|
|
ccxt/pro/mexc.py
CHANGED
@@ -439,6 +439,7 @@ class mexc(ccxt.async_support.mexc):
|
|
439
439
|
symbol = self.safe_symbol(marketId)
|
440
440
|
messageHash = 'orderbook:' + symbol
|
441
441
|
subscription = self.safe_value(client.subscriptions, messageHash)
|
442
|
+
limit = self.safe_integer(subscription, 'limit')
|
442
443
|
if subscription is True:
|
443
444
|
# we set client.subscriptions[messageHash] to 1
|
444
445
|
# once we have received the first delta and initialized the orderbook
|
@@ -450,7 +451,7 @@ class mexc(ccxt.async_support.mexc):
|
|
450
451
|
cacheLength = len(storedOrderBook.cache)
|
451
452
|
snapshotDelay = self.handle_option('watchOrderBook', 'snapshotDelay', 25)
|
452
453
|
if cacheLength == snapshotDelay:
|
453
|
-
self.spawn(self.load_order_book, client, messageHash, symbol)
|
454
|
+
self.spawn(self.load_order_book, client, messageHash, symbol, limit, {})
|
454
455
|
storedOrderBook.cache.append(data)
|
455
456
|
return
|
456
457
|
try:
|
ccxt/test/test_async.py
CHANGED
@@ -158,8 +158,9 @@ def json_stringify(elem):
|
|
158
158
|
return json.dumps(elem)
|
159
159
|
|
160
160
|
|
161
|
-
def convert_to_snake_case(
|
162
|
-
|
161
|
+
def convert_to_snake_case(content):
|
162
|
+
res = re.sub(r'(?<!^)(?=[A-Z])', '_', content).lower()
|
163
|
+
return res.replace('o_h_l_c_v', 'ohlcv')
|
163
164
|
|
164
165
|
|
165
166
|
def get_test_name(methodName):
|
@@ -185,8 +186,7 @@ def io_dir_read(path):
|
|
185
186
|
|
186
187
|
|
187
188
|
async def call_method(test_files, methodName, exchange, skippedProperties, args):
|
188
|
-
methodNameToCall = convert_to_snake_case(methodName)
|
189
|
-
methodNameToCall = 'test_' + methodNameToCall.replace('o_h_l_c_v', 'ohlcv')
|
189
|
+
methodNameToCall = 'test_' + convert_to_snake_case(methodName)
|
190
190
|
return await getattr(test_files[methodName], methodNameToCall)(exchange, skippedProperties, *args)
|
191
191
|
|
192
192
|
|
@@ -583,7 +583,7 @@ class testMainClass(baseMainTestClass):
|
|
583
583
|
result = await self.test_safe('loadMarkets', exchange, [], True)
|
584
584
|
if not result:
|
585
585
|
return False
|
586
|
-
symbols = ['BTC/
|
586
|
+
symbols = ['BTC/USDT', 'BTC/USDC', 'BTC/CNY', 'BTC/USD', 'BTC/EUR', 'BTC/ETH', 'ETH/BTC', 'BTC/JPY', 'ETH/EUR', 'ETH/JPY', 'ETH/CNY', 'ETH/USD', 'LTC/CNY', 'DASH/BTC', 'DOGE/BTC', 'BTC/AUD', 'BTC/PLN', 'USD/SLL', 'BTC/RUB', 'BTC/UAH', 'LTC/BTC', 'EUR/USD']
|
587
587
|
result_symbols = []
|
588
588
|
exchange_specific_symbols = exchange.symbols
|
589
589
|
for i in range(0, len(exchange_specific_symbols)):
|
@@ -638,8 +638,8 @@ class testMainClass(baseMainTestClass):
|
|
638
638
|
def get_valid_symbol(self, exchange, spot=True):
|
639
639
|
current_type_markets = self.get_markets_from_exchange(exchange, spot)
|
640
640
|
codes = ['BTC', 'ETH', 'XRP', 'LTC', 'BCH', 'EOS', 'BNB', 'BSV', 'USDT', 'ATOM', 'BAT', 'BTG', 'DASH', 'DOGE', 'ETC', 'IOTA', 'LSK', 'MKR', 'NEO', 'PAX', 'QTUM', 'TRX', 'TUSD', 'USD', 'USDC', 'WAVES', 'XEM', 'XMR', 'ZEC', 'ZRX']
|
641
|
-
spot_symbols = ['BTC/
|
642
|
-
swap_symbols = ['BTC/USDT:USDT', 'BTC/USD:USD', 'ETH/USDT:USDT', 'ETH/USD:USD', 'LTC/USDT:USDT', 'DOGE/USDT:USDT', 'ADA/USDT:USDT', 'BTC/USD:BTC', 'ETH/USD:ETH']
|
641
|
+
spot_symbols = ['BTC/USDT', 'BTC/USDC', 'BTC/USD', 'BTC/CNY', 'BTC/EUR', 'BTC/ETH', 'ETH/BTC', 'ETH/USD', 'ETH/USDT', 'BTC/JPY', 'LTC/BTC', 'ZRX/WETH', 'EUR/USD']
|
642
|
+
swap_symbols = ['BTC/USDT:USDT', 'BTC/USDC:USDC', 'BTC/USD:USD', 'ETH/USDT:USDT', 'ETH/USD:USD', 'LTC/USDT:USDT', 'DOGE/USDT:USDT', 'ADA/USDT:USDT', 'BTC/USD:BTC', 'ETH/USD:ETH']
|
643
643
|
target_symbols = spot_symbols if spot else swap_symbols
|
644
644
|
symbol = self.get_test_symbol(exchange, spot, target_symbols)
|
645
645
|
# if symbols wasn't found from above hardcoded list, then try to locate any symbol which has our target hardcoded 'base' code
|
@@ -688,16 +688,16 @@ class testMainClass(baseMainTestClass):
|
|
688
688
|
if swap_symbol is not None:
|
689
689
|
dump('[INFO:MAIN] Selected SWAP SYMBOL:', swap_symbol)
|
690
690
|
if not self.private_test_only:
|
691
|
-
# note, spot & swap tests should run sequentially, because of conflicting `exchange.options['
|
691
|
+
# note, spot & swap tests should run sequentially, because of conflicting `exchange.options['defaultType']` setting
|
692
692
|
if exchange.has['spot'] and spot_symbol is not None:
|
693
693
|
if self.info:
|
694
694
|
dump('[INFO] ### SPOT TESTS ###')
|
695
|
-
exchange.options['
|
695
|
+
exchange.options['defaultType'] = 'spot'
|
696
696
|
await self.run_public_tests(exchange, spot_symbol)
|
697
697
|
if exchange.has['swap'] and swap_symbol is not None:
|
698
698
|
if self.info:
|
699
699
|
dump('[INFO] ### SWAP TESTS ###')
|
700
|
-
exchange.options['
|
700
|
+
exchange.options['defaultType'] = 'swap'
|
701
701
|
await self.run_public_tests(exchange, swap_symbol)
|
702
702
|
if self.private_test or self.private_test_only:
|
703
703
|
if exchange.has['spot'] and spot_symbol is not None:
|
ccxt/test/test_sync.py
CHANGED
@@ -157,8 +157,9 @@ def json_stringify(elem):
|
|
157
157
|
return json.dumps(elem)
|
158
158
|
|
159
159
|
|
160
|
-
def convert_to_snake_case(
|
161
|
-
|
160
|
+
def convert_to_snake_case(content):
|
161
|
+
res = re.sub(r'(?<!^)(?=[A-Z])', '_', content).lower()
|
162
|
+
return res.replace('o_h_l_c_v', 'ohlcv')
|
162
163
|
|
163
164
|
|
164
165
|
def get_test_name(methodName):
|
@@ -184,8 +185,7 @@ def io_dir_read(path):
|
|
184
185
|
|
185
186
|
|
186
187
|
def call_method(test_files, methodName, exchange, skippedProperties, args):
|
187
|
-
methodNameToCall = convert_to_snake_case(methodName)
|
188
|
-
methodNameToCall = 'test_' + methodNameToCall.replace('o_h_l_c_v', 'ohlcv')
|
188
|
+
methodNameToCall = 'test_' + convert_to_snake_case(methodName)
|
189
189
|
return getattr(test_files[methodName], methodNameToCall)(exchange, skippedProperties, *args)
|
190
190
|
|
191
191
|
|
@@ -582,7 +582,7 @@ class testMainClass(baseMainTestClass):
|
|
582
582
|
result = self.test_safe('loadMarkets', exchange, [], True)
|
583
583
|
if not result:
|
584
584
|
return False
|
585
|
-
symbols = ['BTC/
|
585
|
+
symbols = ['BTC/USDT', 'BTC/USDC', 'BTC/CNY', 'BTC/USD', 'BTC/EUR', 'BTC/ETH', 'ETH/BTC', 'BTC/JPY', 'ETH/EUR', 'ETH/JPY', 'ETH/CNY', 'ETH/USD', 'LTC/CNY', 'DASH/BTC', 'DOGE/BTC', 'BTC/AUD', 'BTC/PLN', 'USD/SLL', 'BTC/RUB', 'BTC/UAH', 'LTC/BTC', 'EUR/USD']
|
586
586
|
result_symbols = []
|
587
587
|
exchange_specific_symbols = exchange.symbols
|
588
588
|
for i in range(0, len(exchange_specific_symbols)):
|
@@ -637,8 +637,8 @@ class testMainClass(baseMainTestClass):
|
|
637
637
|
def get_valid_symbol(self, exchange, spot=True):
|
638
638
|
current_type_markets = self.get_markets_from_exchange(exchange, spot)
|
639
639
|
codes = ['BTC', 'ETH', 'XRP', 'LTC', 'BCH', 'EOS', 'BNB', 'BSV', 'USDT', 'ATOM', 'BAT', 'BTG', 'DASH', 'DOGE', 'ETC', 'IOTA', 'LSK', 'MKR', 'NEO', 'PAX', 'QTUM', 'TRX', 'TUSD', 'USD', 'USDC', 'WAVES', 'XEM', 'XMR', 'ZEC', 'ZRX']
|
640
|
-
spot_symbols = ['BTC/
|
641
|
-
swap_symbols = ['BTC/USDT:USDT', 'BTC/USD:USD', 'ETH/USDT:USDT', 'ETH/USD:USD', 'LTC/USDT:USDT', 'DOGE/USDT:USDT', 'ADA/USDT:USDT', 'BTC/USD:BTC', 'ETH/USD:ETH']
|
640
|
+
spot_symbols = ['BTC/USDT', 'BTC/USDC', 'BTC/USD', 'BTC/CNY', 'BTC/EUR', 'BTC/ETH', 'ETH/BTC', 'ETH/USD', 'ETH/USDT', 'BTC/JPY', 'LTC/BTC', 'ZRX/WETH', 'EUR/USD']
|
641
|
+
swap_symbols = ['BTC/USDT:USDT', 'BTC/USDC:USDC', 'BTC/USD:USD', 'ETH/USDT:USDT', 'ETH/USD:USD', 'LTC/USDT:USDT', 'DOGE/USDT:USDT', 'ADA/USDT:USDT', 'BTC/USD:BTC', 'ETH/USD:ETH']
|
642
642
|
target_symbols = spot_symbols if spot else swap_symbols
|
643
643
|
symbol = self.get_test_symbol(exchange, spot, target_symbols)
|
644
644
|
# if symbols wasn't found from above hardcoded list, then try to locate any symbol which has our target hardcoded 'base' code
|
@@ -687,16 +687,16 @@ class testMainClass(baseMainTestClass):
|
|
687
687
|
if swap_symbol is not None:
|
688
688
|
dump('[INFO:MAIN] Selected SWAP SYMBOL:', swap_symbol)
|
689
689
|
if not self.private_test_only:
|
690
|
-
# note, spot & swap tests should run sequentially, because of conflicting `exchange.options['
|
690
|
+
# note, spot & swap tests should run sequentially, because of conflicting `exchange.options['defaultType']` setting
|
691
691
|
if exchange.has['spot'] and spot_symbol is not None:
|
692
692
|
if self.info:
|
693
693
|
dump('[INFO] ### SPOT TESTS ###')
|
694
|
-
exchange.options['
|
694
|
+
exchange.options['defaultType'] = 'spot'
|
695
695
|
self.run_public_tests(exchange, spot_symbol)
|
696
696
|
if exchange.has['swap'] and swap_symbol is not None:
|
697
697
|
if self.info:
|
698
698
|
dump('[INFO] ### SWAP TESTS ###')
|
699
|
-
exchange.options['
|
699
|
+
exchange.options['defaultType'] = 'swap'
|
700
700
|
self.run_public_tests(exchange, swap_symbol)
|
701
701
|
if self.private_test or self.private_test_only:
|
702
702
|
if exchange.has['spot'] and spot_symbol is not None:
|
ccxt/upbit.py
CHANGED
@@ -48,6 +48,7 @@ class upbit(Exchange, ImplicitAPI):
|
|
48
48
|
'fetchBalance': True,
|
49
49
|
'fetchCanceledOrders': True,
|
50
50
|
'fetchClosedOrders': True,
|
51
|
+
'fetchDeposit': True,
|
51
52
|
'fetchDepositAddress': True,
|
52
53
|
'fetchDepositAddresses': True,
|
53
54
|
'fetchDeposits': True,
|
@@ -75,6 +76,7 @@ class upbit(Exchange, ImplicitAPI):
|
|
75
76
|
'fetchTradingFee': True,
|
76
77
|
'fetchTradingFees': False,
|
77
78
|
'fetchTransactions': False,
|
79
|
+
'fetchWithdrawal': True,
|
78
80
|
'fetchWithdrawals': True,
|
79
81
|
'transfer': False,
|
80
82
|
'withdraw': True,
|
@@ -988,6 +990,7 @@ class upbit(Exchange, ImplicitAPI):
|
|
988
990
|
"""
|
989
991
|
create a trade order
|
990
992
|
:see: https://docs.upbit.com/reference/%EC%A3%BC%EB%AC%B8%ED%95%98%EA%B8%B0
|
993
|
+
:see: https://global-docs.upbit.com/reference/order
|
991
994
|
:param str symbol: unified symbol of the market to create an order in
|
992
995
|
:param str type: 'market' or 'limit'
|
993
996
|
:param str side: 'buy' or 'sell'
|
@@ -995,6 +998,7 @@ class upbit(Exchange, ImplicitAPI):
|
|
995
998
|
:param float [price]: the price at which the order is to be fullfilled, in units of the quote currency, ignored in market orders
|
996
999
|
:param dict [params]: extra parameters specific to the exchange API endpoint
|
997
1000
|
:param float [params.cost]: for market buy orders, the quote quantity that can be used alternative for the amount
|
1001
|
+
:param str [params.timeInForce]: 'IOC' or 'FOK'
|
998
1002
|
:returns dict: an `order structure <https://docs.ccxt.com/#/?id=order-structure>`
|
999
1003
|
"""
|
1000
1004
|
self.load_markets()
|
@@ -1039,6 +1043,11 @@ class upbit(Exchange, ImplicitAPI):
|
|
1039
1043
|
clientOrderId = self.safe_string_2(params, 'clientOrderId', 'identifier')
|
1040
1044
|
if clientOrderId is not None:
|
1041
1045
|
request['identifier'] = clientOrderId
|
1046
|
+
if type != 'market':
|
1047
|
+
timeInForce = self.safe_string_lower_2(params, 'timeInForce', 'time_in_force')
|
1048
|
+
params = self.omit(params, 'timeInForce')
|
1049
|
+
if timeInForce is not None:
|
1050
|
+
request['time_in_force'] = timeInForce
|
1042
1051
|
params = self.omit(params, ['clientOrderId', 'identifier'])
|
1043
1052
|
response = self.privatePostOrders(self.extend(request, params))
|
1044
1053
|
#
|
@@ -1138,6 +1147,42 @@ class upbit(Exchange, ImplicitAPI):
|
|
1138
1147
|
#
|
1139
1148
|
return self.parse_transactions(response, currency, since, limit)
|
1140
1149
|
|
1150
|
+
def fetch_deposit(self, id: str, code: Str = None, params={}):
|
1151
|
+
"""
|
1152
|
+
fetch information on a deposit
|
1153
|
+
:see: https://global-docs.upbit.com/reference/individual-deposit-inquiry
|
1154
|
+
:param str id: the unique id for the deposit
|
1155
|
+
:param str [code]: unified currency code of the currency deposited
|
1156
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
1157
|
+
:param str [params.txid]: withdrawal transaction id, the id argument is reserved for uuid
|
1158
|
+
:returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
|
1159
|
+
"""
|
1160
|
+
self.load_markets()
|
1161
|
+
request = {
|
1162
|
+
'uuid': id,
|
1163
|
+
}
|
1164
|
+
currency = None
|
1165
|
+
if code is not None:
|
1166
|
+
currency = self.currency(code)
|
1167
|
+
request['currency'] = currency['id']
|
1168
|
+
response = self.privateGetDeposit(self.extend(request, params))
|
1169
|
+
#
|
1170
|
+
# {
|
1171
|
+
# "type": "deposit",
|
1172
|
+
# "uuid": "7f54527e-2eee-4268-860e-fd8b9d7fe3c7",
|
1173
|
+
# "currency": "ADA",
|
1174
|
+
# "net_type": "ADA",
|
1175
|
+
# "txid": "99795bbfeca91eaa071068bb659b33eeb65d8aaff2551fdf7c78f345d188952b",
|
1176
|
+
# "state": "ACCEPTED",
|
1177
|
+
# "created_at": "2023-12-12T04:58:41Z",
|
1178
|
+
# "done_at": "2023-12-12T05:31:50Z",
|
1179
|
+
# "amount": "35.72344",
|
1180
|
+
# "fee": "0.0",
|
1181
|
+
# "transaction_type": "default"
|
1182
|
+
# }
|
1183
|
+
#
|
1184
|
+
return self.parse_transaction(response, currency)
|
1185
|
+
|
1141
1186
|
def fetch_withdrawals(self, code: Str = None, since: Int = None, limit: Int = None, params={}) -> List[Transaction]:
|
1142
1187
|
"""
|
1143
1188
|
:see: https://docs.upbit.com/reference/%EC%A0%84%EC%B2%B4-%EC%B6%9C%EA%B8%88-%EC%A1%B0%ED%9A%8C
|
@@ -1178,13 +1223,49 @@ class upbit(Exchange, ImplicitAPI):
|
|
1178
1223
|
#
|
1179
1224
|
return self.parse_transactions(response, currency, since, limit)
|
1180
1225
|
|
1226
|
+
def fetch_withdrawal(self, id: str, code: Str = None, params={}):
|
1227
|
+
"""
|
1228
|
+
fetch data on a currency withdrawal via the withdrawal id
|
1229
|
+
:see: https://global-docs.upbit.com/reference/individual-withdrawal-inquiry
|
1230
|
+
:param str id: the unique id for the withdrawal
|
1231
|
+
:param str [code]: unified currency code of the currency withdrawn
|
1232
|
+
:param dict [params]: extra parameters specific to the exchange API endpoint
|
1233
|
+
:param str [params.txid]: withdrawal transaction id, the id argument is reserved for uuid
|
1234
|
+
:returns dict: a `transaction structure <https://docs.ccxt.com/#/?id=transaction-structure>`
|
1235
|
+
"""
|
1236
|
+
self.load_markets()
|
1237
|
+
request = {
|
1238
|
+
'uuid': id,
|
1239
|
+
}
|
1240
|
+
currency = None
|
1241
|
+
if code is not None:
|
1242
|
+
currency = self.currency(code)
|
1243
|
+
request['currency'] = currency['id']
|
1244
|
+
response = self.privateGetWithdraw(self.extend(request, params))
|
1245
|
+
#
|
1246
|
+
# {
|
1247
|
+
# "type": "withdraw",
|
1248
|
+
# "uuid": "95ef274b-23a6-4de4-95b0-5cbef4ca658f",
|
1249
|
+
# "currency": "ADA",
|
1250
|
+
# "net_type": "ADA",
|
1251
|
+
# "txid": "b1528f149297a71671b86636f731f8fdb0ff53da0f1d8c19093d59df96f34583",
|
1252
|
+
# "state": "DONE",
|
1253
|
+
# "created_at": "2023-12-14T02:46:52Z",
|
1254
|
+
# "done_at": "2023-12-14T03:10:11Z",
|
1255
|
+
# "amount": "35.22344",
|
1256
|
+
# "fee": "0.5",
|
1257
|
+
# "transaction_type": "default"
|
1258
|
+
# }
|
1259
|
+
#
|
1260
|
+
return self.parse_transaction(response, currency)
|
1261
|
+
|
1181
1262
|
def parse_transaction_status(self, status):
|
1182
1263
|
statuses = {
|
1183
1264
|
'submitting': 'pending', # 처리 중
|
1184
1265
|
'submitted': 'pending', # 처리 완료
|
1185
1266
|
'almost_accepted': 'pending', # 출금대기중
|
1186
1267
|
'rejected': 'failed', # 거부
|
1187
|
-
'accepted': '
|
1268
|
+
'accepted': 'ok', # 승인됨
|
1188
1269
|
'processing': 'pending', # 처리 중
|
1189
1270
|
'done': 'ok', # 완료
|
1190
1271
|
'canceled': 'canceled', # 취소됨
|
@@ -1193,7 +1274,7 @@ class upbit(Exchange, ImplicitAPI):
|
|
1193
1274
|
|
1194
1275
|
def parse_transaction(self, transaction, currency: Currency = None) -> Transaction:
|
1195
1276
|
#
|
1196
|
-
# fetchDeposits
|
1277
|
+
# fetchDeposits, fetchDeposit
|
1197
1278
|
#
|
1198
1279
|
# {
|
1199
1280
|
# "type": "deposit",
|
@@ -1207,7 +1288,7 @@ class upbit(Exchange, ImplicitAPI):
|
|
1207
1288
|
# "fee": "0.0"
|
1208
1289
|
# }
|
1209
1290
|
#
|
1210
|
-
# fetchWithdrawals
|
1291
|
+
# fetchWithdrawals, fetchWithdrawal
|
1211
1292
|
#
|
1212
1293
|
# {
|
1213
1294
|
# "type": "withdraw",
|
@@ -1222,26 +1303,20 @@ class upbit(Exchange, ImplicitAPI):
|
|
1222
1303
|
# "krw_amount": "80420.0"
|
1223
1304
|
# }
|
1224
1305
|
#
|
1225
|
-
id = self.safe_string(transaction, 'uuid')
|
1226
|
-
amount = self.safe_number(transaction, 'amount')
|
1227
1306
|
address = None # not present in the data structure received from the exchange
|
1228
1307
|
tag = None # not present in the data structure received from the exchange
|
1229
|
-
txid = self.safe_string(transaction, 'txid')
|
1230
1308
|
updatedRaw = self.safe_string(transaction, 'done_at')
|
1231
|
-
updated = self.parse8601(updatedRaw)
|
1232
1309
|
timestamp = self.parse8601(self.safe_string(transaction, 'created_at', updatedRaw))
|
1233
1310
|
type = self.safe_string(transaction, 'type')
|
1234
1311
|
if type == 'withdraw':
|
1235
1312
|
type = 'withdrawal'
|
1236
1313
|
currencyId = self.safe_string(transaction, 'currency')
|
1237
|
-
code = self.safe_currency_code(currencyId)
|
1238
|
-
status = self.parse_transaction_status(self.safe_string_lower(transaction, 'state'))
|
1239
|
-
feeCost = self.safe_number(transaction, 'fee')
|
1314
|
+
code = self.safe_currency_code(currencyId, currency)
|
1240
1315
|
return {
|
1241
1316
|
'info': transaction,
|
1242
|
-
'id':
|
1317
|
+
'id': self.safe_string(transaction, 'uuid'),
|
1243
1318
|
'currency': code,
|
1244
|
-
'amount': amount,
|
1319
|
+
'amount': self.safe_number(transaction, 'amount'),
|
1245
1320
|
'network': None,
|
1246
1321
|
'address': address,
|
1247
1322
|
'addressTo': None,
|
@@ -1249,17 +1324,17 @@ class upbit(Exchange, ImplicitAPI):
|
|
1249
1324
|
'tag': tag,
|
1250
1325
|
'tagTo': None,
|
1251
1326
|
'tagFrom': None,
|
1252
|
-
'status':
|
1327
|
+
'status': self.parse_transaction_status(self.safe_string_lower(transaction, 'state')),
|
1253
1328
|
'type': type,
|
1254
|
-
'updated':
|
1255
|
-
'txid': txid,
|
1329
|
+
'updated': self.parse8601(updatedRaw),
|
1330
|
+
'txid': self.safe_string(transaction, 'txid'),
|
1256
1331
|
'timestamp': timestamp,
|
1257
1332
|
'datetime': self.iso8601(timestamp),
|
1258
1333
|
'internal': None,
|
1259
1334
|
'comment': None,
|
1260
1335
|
'fee': {
|
1261
1336
|
'currency': code,
|
1262
|
-
'cost':
|
1337
|
+
'cost': self.safe_number(transaction, 'fee'),
|
1263
1338
|
},
|
1264
1339
|
}
|
1265
1340
|
|
@@ -1705,7 +1780,7 @@ class upbit(Exchange, ImplicitAPI):
|
|
1705
1780
|
url += '?' + self.urlencode(query)
|
1706
1781
|
if api == 'private':
|
1707
1782
|
self.check_required_credentials()
|
1708
|
-
nonce = self.
|
1783
|
+
nonce = self.uuid()
|
1709
1784
|
request = {
|
1710
1785
|
'access_key': self.apiKey,
|
1711
1786
|
'nonce': nonce,
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: ccxt
|
3
|
-
Version: 4.2.
|
3
|
+
Version: 4.2.49
|
4
4
|
Summary: A JavaScript / TypeScript / Python / C# / PHP cryptocurrency trading library with support for 100+ exchanges
|
5
5
|
Home-page: https://ccxt.com
|
6
6
|
Author: Igor Kroitor
|
@@ -259,13 +259,13 @@ console.log(version, Object.keys(exchanges));
|
|
259
259
|
|
260
260
|
All-in-one browser bundle (dependencies included), served from a CDN of your choice:
|
261
261
|
|
262
|
-
* jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.2.
|
263
|
-
* unpkg: https://unpkg.com/ccxt@4.2.
|
262
|
+
* jsDelivr: https://cdn.jsdelivr.net/npm/ccxt@4.2.49/dist/ccxt.browser.js
|
263
|
+
* unpkg: https://unpkg.com/ccxt@4.2.49/dist/ccxt.browser.js
|
264
264
|
|
265
265
|
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
266
|
|
267
267
|
```HTML
|
268
|
-
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.2.
|
268
|
+
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/ccxt@4.2.49/dist/ccxt.browser.js"></script>
|
269
269
|
```
|
270
270
|
|
271
271
|
Creates a global `ccxt` object:
|