add
This commit is contained in:
253
ccxt/test/exchange/async/test_create_order.py
Normal file
253
ccxt/test/exchange/async/test_create_order.py
Normal file
@@ -0,0 +1,253 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.base.decimal_to_precision import TICK_SIZE # noqa E402
|
||||
from ccxt.base.decimal_to_precision import TRUNCATE # noqa E402
|
||||
from ccxt.base.decimal_to_precision import ROUND # noqa E402
|
||||
from ccxt.base.decimal_to_precision import ROUND_UP # noqa E402
|
||||
from ccxt.base.decimal_to_precision import decimal_to_precision # noqa E402
|
||||
from ccxt.base.decimal_to_precision import number_to_string # noqa E402
|
||||
from ccxt.base.precise import Precise # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
from ccxt.test.exchange.base import test_order # noqa E402
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
def tco_debug(exchange, symbol, message):
|
||||
# just for debugging purposes
|
||||
debug_create_order = True
|
||||
if debug_create_order:
|
||||
# for c# fix, extra step to convert them to string
|
||||
print(' >>>>> testCreateOrder [', str((exchange['id'])), ' : ', symbol, '] ', message)
|
||||
return True
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
async def test_create_order(exchange, skipped_properties, symbol):
|
||||
log_prefix = test_shared_methods.log_template(exchange, 'createOrder', [symbol])
|
||||
assert exchange.has['cancelOrder'] or exchange.has['cancelOrders'] or exchange.has['cancelAllOrders'], log_prefix + ' does not have cancelOrder|cancelOrders|canelAllOrders method, which is needed to make tests for `createOrder` method. Skipping the test...'
|
||||
# pre-define some coefficients, which will be used down below
|
||||
limit_price_safety_multiplier_from_median = 1.045 # todo: when this https://github.com/ccxt/ccxt/issues/22442 is implemented, we'll remove hardcoded value. atm 5% is enough
|
||||
market = exchange.market(symbol)
|
||||
is_swap_future = market['swap'] or market['future']
|
||||
assert exchange.has['fetchBalance'], log_prefix + ' does not have fetchBalance() method, which is needed to make tests for `createOrder` method. Skipping the test...'
|
||||
balance = await exchange.fetch_balance()
|
||||
initial_base_balance = balance[market['base']]['free']
|
||||
initial_quote_balance = balance[market['quote']]['free']
|
||||
assert initial_quote_balance is not None, log_prefix + ' - testing account not have balance of' + market['quote'] + ' in fetchBalance() which is required to test'
|
||||
tco_debug(exchange, symbol, 'fetched balance for ' + symbol + ' : ' + str(initial_base_balance) + ' ' + market['base'] + '/' + initial_quote_balance + ' ' + market['quote'])
|
||||
[best_bid, best_ask] = await test_shared_methods.fetch_best_bid_ask(exchange, 'createOrder', symbol)
|
||||
# **************** [Scenario 1 - START] **************** #
|
||||
tco_debug(exchange, symbol, '### SCENARIO 1 ###')
|
||||
# create a "limit order" which IS GUARANTEED not to have a fill (i.e. being far from the real price)
|
||||
await tco_create_unfillable_order(exchange, market, log_prefix, skipped_properties, best_bid, best_ask, limit_price_safety_multiplier_from_median, 'buy', None)
|
||||
if is_swap_future:
|
||||
# for swap markets, we test sell orders too
|
||||
await tco_create_unfillable_order(exchange, market, log_prefix, skipped_properties, best_bid, best_ask, limit_price_safety_multiplier_from_median, 'sell', None)
|
||||
tco_debug(exchange, symbol, '### SCENARIO 1 PASSED ###')
|
||||
# **************** [Scenario 2 - START] **************** #
|
||||
tco_debug(exchange, symbol, '### SCENARIO 2 ###')
|
||||
# create an order which IS GUARANTEED to have a fill (full or partial)
|
||||
await tco_create_fillable_order(exchange, market, log_prefix, skipped_properties, best_bid, best_ask, limit_price_safety_multiplier_from_median, 'buy', None)
|
||||
if is_swap_future:
|
||||
# for swap markets, we test sell orders too
|
||||
await tco_create_fillable_order(exchange, market, log_prefix, skipped_properties, best_bid, best_ask, limit_price_safety_multiplier_from_median, 'sell', None)
|
||||
tco_debug(exchange, symbol, '### SCENARIO 2 PASSED ###')
|
||||
# **************** [Scenario 3 - START] **************** #
|
||||
return True
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
async def tco_create_unfillable_order(exchange, market, log_prefix, skipped_properties, best_bid, best_ask, limit_price_safety_multiplier_from_median, buy_or_sell, predefined_amount=None):
|
||||
try:
|
||||
symbol = market['symbol']
|
||||
minimun_prices = exchange.safe_dict(market['limits'], 'price', {})
|
||||
minimum_price = minimun_prices['min']
|
||||
maximum_price = minimun_prices['max']
|
||||
# below we set limit price, where the order will not be completed.
|
||||
# We do not use the extreme "limits" values for that market, because, even though min purchase amount for BTC/USDT can be 0.01 BTC, it means with 10$ you can buy 1000 BTC, which leads to unrealistic outcome. So, we just use around 5%-10% far price from the current price.
|
||||
limit_buy_price_non_fillable = best_bid / limit_price_safety_multiplier_from_median
|
||||
if minimum_price is not None and limit_buy_price_non_fillable < minimum_price:
|
||||
limit_buy_price_non_fillable = minimum_price
|
||||
limit_sell_price_non_fillable = best_ask * limit_price_safety_multiplier_from_median
|
||||
if maximum_price is not None and limit_sell_price_non_fillable > maximum_price:
|
||||
limit_sell_price_non_fillable = maximum_price
|
||||
created_order = None
|
||||
if buy_or_sell == 'buy':
|
||||
order_amount = tco_get_minimum_amount_for_limit_price(exchange, market, limit_buy_price_non_fillable, predefined_amount)
|
||||
created_order = await tco_create_order_safe(exchange, symbol, 'limit', 'buy', order_amount, limit_buy_price_non_fillable, {}, skipped_properties)
|
||||
else:
|
||||
order_amount = tco_get_minimum_amount_for_limit_price(exchange, market, limit_sell_price_non_fillable, predefined_amount)
|
||||
created_order = await tco_create_order_safe(exchange, symbol, 'limit', 'sell', order_amount, limit_sell_price_non_fillable, {}, skipped_properties)
|
||||
fetched_order = await test_shared_methods.fetch_order(exchange, symbol, created_order['id'], skipped_properties)
|
||||
# test fetched order object
|
||||
if fetched_order is not None:
|
||||
test_order(exchange, skipped_properties, 'createOrder', fetched_order, symbol, exchange.milliseconds())
|
||||
# ensure that order is not filled
|
||||
test_shared_methods.assert_order_state(exchange, skipped_properties, 'createdOrder', created_order, 'open', False)
|
||||
test_shared_methods.assert_order_state(exchange, skipped_properties, 'fetchedOrder', fetched_order, 'open', True)
|
||||
# ensure that order side matches
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, 'createdOrder', created_order, 'side', [None, buy_or_sell])
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, 'fetchedOrder', fetched_order, 'side', [None, buy_or_sell])
|
||||
await tco_cancel_order(exchange, symbol, created_order['id'])
|
||||
except Exception as e:
|
||||
raise Error(log_prefix + ' failed for Scenario 1: ' + str(e))
|
||||
return True
|
||||
|
||||
|
||||
async def tco_create_fillable_order(exchange, market, log_prefix, skipped_properties, best_bid, best_ask, limit_price_safety_multiplier_from_median, buy_or_sell_string, predefined_amount=None):
|
||||
try:
|
||||
is_swap_future = market['swap'] or market['future']
|
||||
is_buy = (buy_or_sell_string == 'buy')
|
||||
entry_side = 'buy' if is_buy else 'sell'
|
||||
exit_side = 'sell' if is_buy else 'buy'
|
||||
entryorder_price = best_ask * limit_price_safety_multiplier_from_median if is_buy else best_bid / limit_price_safety_multiplier_from_median
|
||||
exitorder_price = best_bid / limit_price_safety_multiplier_from_median if is_buy else best_ask * limit_price_safety_multiplier_from_median # todo revise: (tcoMininumCost (exchange, market) / amountToClose) / limitPriceSafetyMultiplierFromMedian;
|
||||
#
|
||||
#
|
||||
symbol = market['symbol']
|
||||
entry_amount = tco_get_minimum_amount_for_limit_price(exchange, market, entryorder_price)
|
||||
entryorder_filled = await tco_create_order_safe(exchange, symbol, 'limit', entry_side, entry_amount, entryorder_price, {}, skipped_properties)
|
||||
# just for case, cancel any possible unfilled amount (though it is not be expected because the order was fillable)
|
||||
await tco_try_cancel_order(exchange, symbol, entryorder_filled, skipped_properties)
|
||||
# now, as order is closed/canceled, we can reliably fetch the order information
|
||||
entryorder_fetched = await test_shared_methods.fetch_order(exchange, symbol, entryorder_filled['id'], skipped_properties)
|
||||
tco_assert_filled_order(exchange, market, log_prefix, skipped_properties, entryorder_filled, entryorder_fetched, entry_side, entry_amount)
|
||||
#
|
||||
# ### close the traded position ###
|
||||
#
|
||||
amount_to_close = exchange.parse_to_numeric(exchange.safe_string(entryorder_fetched, 'filled'))
|
||||
params = {}
|
||||
# as we want to close position, we should use 'reduceOnly' to ensure we don't open a margined position accidentally, because some exchanges might have automatically enabled margin-mode (on spot) or hedge-mode (on contracts)
|
||||
if is_swap_future:
|
||||
params['reduceOnly'] = True
|
||||
exitorder_filled = await tco_create_order_safe(exchange, symbol, 'market', exit_side, amount_to_close, (None if market['spot'] else exitorder_price), params, skipped_properties)
|
||||
exitorder_fetched = await test_shared_methods.fetch_order(exchange, symbol, exitorder_filled['id'], skipped_properties)
|
||||
tco_assert_filled_order(exchange, market, log_prefix, skipped_properties, exitorder_filled, exitorder_fetched, exit_side, amount_to_close)
|
||||
except Exception as e:
|
||||
raise Error('failed for Scenario 2: ' + str(e))
|
||||
return True
|
||||
|
||||
|
||||
def tco_assert_filled_order(exchange, market, log_prefix, skipped_properties, created_order, fetched_order, requested_side, requested_amount):
|
||||
# test filled amount
|
||||
precision_amount = exchange.safe_string(market['precision'], 'amount')
|
||||
entryorder_amount_string = exchange.number_to_string(requested_amount)
|
||||
filled_string = exchange.safe_string(fetched_order, 'filled')
|
||||
assert filled_string is not None, log_prefix + ' order should be filled, but it is not. ' + exchange.json(fetched_order)
|
||||
# filled amount should be whithin the expected range i.e. if you buy 100 DOGECOIN and amount-precision is 1,
|
||||
# and also considering possible roundings in implementation, then filled amount should be between 99 and 101
|
||||
max_expected_filled_amount = Precise.string_add(entryorder_amount_string, precision_amount)
|
||||
min_expected_filled_amount = Precise.string_sub(entryorder_amount_string, precision_amount)
|
||||
assert Precise.string_le(filled_string, max_expected_filled_amount), log_prefix + ' filled amount is more than expected, possibly some implementation issue. ' + exchange.json(fetched_order)
|
||||
assert Precise.string_ge(filled_string, min_expected_filled_amount), log_prefix + ' filled amount is less than expected, possibly some implementation issue. ' + exchange.json(fetched_order)
|
||||
# order state should be "closed"
|
||||
test_shared_methods.assert_order_state(exchange, skipped_properties, 'createdOrder', created_order, 'closed', False)
|
||||
test_shared_methods.assert_order_state(exchange, skipped_properties, 'fetchedOrder', fetched_order, 'closed', True)
|
||||
# ensure that order side matches
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, 'createdOrder', created_order, 'side', [None, requested_side])
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, 'fetchedOrder', fetched_order, 'side', [None, requested_side])
|
||||
return True
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
async def tco_cancel_order(exchange, symbol, order_id=None):
|
||||
log_prefix = test_shared_methods.log_template(exchange, 'createOrder', [symbol])
|
||||
used_method = ''
|
||||
cancel_result = None
|
||||
if exchange.has['cancelOrder'] and order_id is not None:
|
||||
used_method = 'cancelOrder'
|
||||
cancel_result = await exchange.cancel_order(order_id, symbol)
|
||||
elif exchange.has['cancelAllOrders']:
|
||||
used_method = 'cancelAllOrders'
|
||||
cancel_result = await exchange.cancel_all_orders(symbol)
|
||||
elif exchange.has['cancelOrders']:
|
||||
raise Error(log_prefix + ' cancelOrders method is not unified yet, coming soon...')
|
||||
tco_debug(exchange, symbol, 'canceled order using ' + used_method + ':' + cancel_result['id'])
|
||||
# todo:
|
||||
# testSharedMethods.assertOrderState (exchange, skippedProperties, 'cancelOrder', cancelResult, 'canceled', false);
|
||||
# testSharedMethods.assertOrderState (exchange, skippedProperties, 'cancelOrder', cancelResult, 'closed', true);
|
||||
return True
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# ----------------------------------------------------------------------------
|
||||
async def tco_create_order_safe(exchange, symbol, order_type, side, amount, price=None, params={}, skipped_properties={}):
|
||||
tco_debug(exchange, symbol, 'Executing createOrder ' + order_type + ' ' + side + ' ' + amount + ' ' + price + ' ' + exchange.json(params))
|
||||
order = await exchange.create_order(symbol, order_type, side, amount, price, params)
|
||||
try:
|
||||
test_order(exchange, skipped_properties, 'createOrder', order, symbol, int(time.time() * 1000))
|
||||
except Exception as e:
|
||||
if order_type != 'market':
|
||||
# if it was limit order, try to cancel it before exiting the script
|
||||
await tco_try_cancel_order(exchange, symbol, order, skipped_properties)
|
||||
raise e
|
||||
return order
|
||||
|
||||
|
||||
def tco_mininum_amount(exchange, market):
|
||||
amount_values = exchange.safe_dict(market['limits'], 'amount', {})
|
||||
amount_min = exchange.safe_number(amount_values, 'min')
|
||||
assert amount_min is not None, exchange.id + ' ' + market['symbol'] + ' can not determine minimum amount for order'
|
||||
return amount_min
|
||||
|
||||
|
||||
def tco_mininum_cost(exchange, market):
|
||||
cost_values = exchange.safe_dict(market['limits'], 'cost', {})
|
||||
cost_min = exchange.safe_number(cost_values, 'min')
|
||||
assert cost_min is not None, exchange.id + ' ' + market['symbol'] + ' can not determine minimum cost for order'
|
||||
return cost_min
|
||||
|
||||
|
||||
def tco_get_minimum_amount_for_limit_price(exchange, market, price, predefined_amount=None):
|
||||
# this method calculates the minimum realistic order amount:
|
||||
# at first it checks the "minimum hardcap limit" (i.e. 7 DOGE), however, if exchange also has "minimum cost" limits,
|
||||
# then we need to calculate the amount using cost, because of price is volatile, today's 7 DOGE cost could be 1$
|
||||
# but "minimum cost" requirement could be 5$ (which translates to 35 DOGE amount)
|
||||
minimum_amount = tco_mininum_amount(exchange, market)
|
||||
minimum_cost = tco_mininum_cost(exchange, market)
|
||||
final_amount = minimum_amount
|
||||
if minimum_cost is not None:
|
||||
if final_amount * price < minimum_cost:
|
||||
final_amount = minimum_cost / price
|
||||
if predefined_amount is not None:
|
||||
final_amount = max(final_amount, predefined_amount)
|
||||
# because it's possible that calculated value might get truncated down in "createOrder" (i.e. 0.129 -> 0.12), we should ensure that final amount * price would bypass minimum cost requirements, by adding the "minimum precision"
|
||||
amount_precision = exchange.safe_number(market['precision'], 'amount')
|
||||
is_tick_size_precision = exchange.precisionMode == 4
|
||||
if amount_precision is None:
|
||||
amount_precision = 1e-15 # todo: revise this for better way in future
|
||||
else:
|
||||
# todo: remove after TICK_SIZE unification
|
||||
if not is_tick_size_precision:
|
||||
amount_precision = 1 / math.pow(10, amount_precision) # this converts DECIMAL_PRECISION into TICK_SIZE
|
||||
final_amount = final_amount + amount_precision
|
||||
final_amount = final_amount * 1.1 # add around 10% to ensure "cost" is enough
|
||||
final_amount = float(exchange.decimal_to_precision(final_amount, 2, market['precision']['amount'], exchange.precisionMode)) # 2 stands for ROUND_UP constant, 0 stands for TRUNCATE
|
||||
return final_amount
|
||||
|
||||
|
||||
async def tco_try_cancel_order(exchange, symbol, order, skipped_properties):
|
||||
order_fetched = await test_shared_methods.fetch_order(exchange, symbol, order['id'], skipped_properties)
|
||||
needs_cancel = exchange.in_array(order_fetched['status'], ['open', 'pending', None])
|
||||
# if it was not reported as closed/filled, then try to cancel it
|
||||
if needs_cancel:
|
||||
tco_debug(exchange, symbol, 'trying to cancel the remaining amount of partially filled order...')
|
||||
try:
|
||||
await tco_cancel_order(exchange, symbol, order['id'])
|
||||
except Exception as e:
|
||||
# order might have been closed/filled already, before 'cancelOrder' call reaches server, so it is tolerable, we don't throw exception
|
||||
tco_debug(exchange, symbol, ' a moment ago order was reported as pending, but could not be cancelled at this moment. Exception message: ' + str(e))
|
||||
else:
|
||||
tco_debug(exchange, symbol, 'order is already closed/filled, no need to cancel it')
|
||||
return True
|
||||
124
ccxt/test/exchange/async/test_features.py
Normal file
124
ccxt/test/exchange/async/test_features.py
Normal file
@@ -0,0 +1,124 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
async def test_features(exchange, skipped_properties):
|
||||
market_types = ['spot', 'swap', 'future', 'option']
|
||||
sub_types = ['linear', 'inverse']
|
||||
features = exchange.features
|
||||
keys = list(features.keys())
|
||||
for i in range(0, len(keys)):
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, 'features', keys, i, market_types)
|
||||
market_type = keys[i]
|
||||
value = features[market_type]
|
||||
# assert (value !== undefined, 'exchange.features["' + marketType + '"] is undefined, that key should be either absent or have a value');
|
||||
if value is None:
|
||||
continue
|
||||
if market_type == 'spot':
|
||||
test_features_inner(exchange, skipped_properties, value)
|
||||
else:
|
||||
sub_keys = list(value.keys())
|
||||
for j in range(0, len(sub_keys)):
|
||||
sub_key = sub_keys[j]
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, 'features', sub_keys, j, sub_types)
|
||||
sub_value = value[sub_key]
|
||||
# sometimes it might not be available for exchange, eg. future>inverse)
|
||||
if sub_value is not None:
|
||||
test_features_inner(exchange, skipped_properties, sub_value)
|
||||
return True
|
||||
|
||||
|
||||
def test_features_inner(exchange, skipped_properties, feature_obj):
|
||||
format = {
|
||||
'sandbox': False,
|
||||
'createOrder': {
|
||||
'marginMode': False,
|
||||
'triggerPrice': False,
|
||||
'triggerPriceType': {
|
||||
'mark': False,
|
||||
'last': False,
|
||||
'index': False,
|
||||
},
|
||||
'stopLossPrice': False,
|
||||
'takeProfitPrice': False,
|
||||
'attachedStopLossTakeProfit': {
|
||||
'triggerPriceType': {
|
||||
'last': False,
|
||||
'mark': False,
|
||||
'index': False,
|
||||
},
|
||||
'price': False,
|
||||
},
|
||||
'timeInForce': {
|
||||
'GTC': False,
|
||||
'IOC': False,
|
||||
'FOK': False,
|
||||
'PO': False,
|
||||
'GTD': False,
|
||||
},
|
||||
'hedged': False,
|
||||
'trailing': False,
|
||||
},
|
||||
'createOrders': {
|
||||
'max': 5,
|
||||
},
|
||||
'fetchMyTrades': {
|
||||
'marginMode': False,
|
||||
'daysBack': 0,
|
||||
'limit': 0,
|
||||
'untilDays': 0,
|
||||
'symbolRequired': False,
|
||||
},
|
||||
'fetchOrder': {
|
||||
'marginMode': False,
|
||||
'trigger': False,
|
||||
'trailing': False,
|
||||
'symbolRequired': False,
|
||||
},
|
||||
'fetchOpenOrders': {
|
||||
'marginMode': False,
|
||||
'limit': 0,
|
||||
'trigger': False,
|
||||
'trailing': False,
|
||||
'symbolRequired': False,
|
||||
},
|
||||
'fetchOrders': {
|
||||
'marginMode': False,
|
||||
'limit': 0,
|
||||
'daysBack': 0,
|
||||
'untilDays': 0,
|
||||
'trigger': False,
|
||||
'trailing': False,
|
||||
'symbolRequired': False,
|
||||
},
|
||||
'fetchClosedOrders': {
|
||||
'marginMode': False,
|
||||
'limit': 0,
|
||||
'daysBack': 0,
|
||||
'daysBackCanceled': 0,
|
||||
'untilDays': 0,
|
||||
'trigger': False,
|
||||
'trailing': False,
|
||||
'symbolRequired': False,
|
||||
},
|
||||
'fetchOHLCV': {
|
||||
'limit': 0,
|
||||
},
|
||||
}
|
||||
feature_keys = list(feature_obj.keys())
|
||||
all_methods = list(exchange.has.keys())
|
||||
for i in range(0, len(feature_keys)):
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, 'features', feature_keys, i, all_methods)
|
||||
test_shared_methods.assert_structure(exchange, skipped_properties, 'features', feature_obj, format, None, True) # deep structure check
|
||||
24
ccxt/test/exchange/async/test_fetch_accounts.py
Normal file
24
ccxt/test/exchange/async/test_fetch_accounts.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_account # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
async def test_fetch_accounts(exchange, skipped_properties):
|
||||
method = 'fetchAccounts'
|
||||
accounts = await exchange.fetch_accounts()
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, accounts)
|
||||
for i in range(0, len(accounts)):
|
||||
test_account(exchange, skipped_properties, method, accounts[i])
|
||||
return True
|
||||
21
ccxt/test/exchange/async/test_fetch_balance.py
Normal file
21
ccxt/test/exchange/async/test_fetch_balance.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_balance # noqa E402
|
||||
|
||||
async def test_fetch_balance(exchange, skipped_properties):
|
||||
method = 'fetchBalance'
|
||||
response = await exchange.fetch_balance()
|
||||
test_balance(exchange, skipped_properties, method, response)
|
||||
return True
|
||||
24
ccxt/test/exchange/async/test_fetch_borrow_interest.py
Normal file
24
ccxt/test/exchange/async/test_fetch_borrow_interest.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_borrow_interest # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
async def test_fetch_borrow_interest(exchange, skipped_properties, code, symbol):
|
||||
method = 'fetchBorrowInterest'
|
||||
borrow_interest = await exchange.fetch_borrow_interest(code, symbol)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, borrow_interest, code)
|
||||
for i in range(0, len(borrow_interest)):
|
||||
test_borrow_interest(exchange, skipped_properties, method, borrow_interest[i], code, symbol)
|
||||
return True
|
||||
28
ccxt/test/exchange/async/test_fetch_closed_orders.py
Normal file
28
ccxt/test/exchange/async/test_fetch_closed_orders.py
Normal file
@@ -0,0 +1,28 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_order # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
async def test_fetch_closed_orders(exchange, skipped_properties, symbol):
|
||||
method = 'fetchClosedOrders'
|
||||
orders = await exchange.fetch_closed_orders(symbol)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, orders, symbol)
|
||||
now = exchange.milliseconds()
|
||||
for i in range(0, len(orders)):
|
||||
order = orders[i]
|
||||
test_order(exchange, skipped_properties, method, order, symbol, now)
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, order, 'status', ['closed', 'canceled'])
|
||||
test_shared_methods.assert_timestamp_order(exchange, method, symbol, orders)
|
||||
return True
|
||||
73
ccxt/test/exchange/async/test_fetch_currencies.py
Normal file
73
ccxt/test/exchange/async/test_fetch_currencies.py
Normal file
@@ -0,0 +1,73 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_currency # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
async def test_fetch_currencies(exchange, skipped_properties):
|
||||
method = 'fetchCurrencies'
|
||||
currencies = await exchange.fetch_currencies()
|
||||
# todo: try to invent something to avoid undefined undefined, i.e. maybe move into private and force it to have a value
|
||||
num_inactive_currencies = 0
|
||||
max_inactive_currencies_percentage = exchange.safe_integer(skipped_properties, 'maxInactiveCurrenciesPercentage', 50) # no more than X% currencies should be inactive
|
||||
required_active_currencies = ['BTC', 'ETH', 'USDT', 'USDC']
|
||||
features = exchange.features
|
||||
features_spot = exchange.safe_dict(features, 'spot', {})
|
||||
fetch_currencies = exchange.safe_dict(features_spot, 'fetchCurrencies', {})
|
||||
is_fetch_currencies_private = exchange.safe_value(fetch_currencies, 'private', False)
|
||||
if not is_fetch_currencies_private:
|
||||
values = list(currencies.values())
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, values)
|
||||
currencies_length = len(values)
|
||||
# ensure exchange returns enough length of currencies
|
||||
skip_amount = ('amountOfCurrencies' in skipped_properties)
|
||||
assert skip_amount or currencies_length > 5, exchange.id + ' ' + method + ' must return at least several currencies, but it returned ' + str(currencies_length)
|
||||
# allow skipped exchanges
|
||||
skip_active = ('activeCurrenciesQuota' in skipped_properties)
|
||||
skip_major_currency_check = ('activeMajorCurrencies' in skipped_properties)
|
||||
# loop
|
||||
for i in range(0, currencies_length):
|
||||
currency = values[i]
|
||||
test_currency(exchange, skipped_properties, method, currency)
|
||||
# detailed check for deposit/withdraw
|
||||
active = exchange.safe_bool(currency, 'active')
|
||||
if active is False:
|
||||
num_inactive_currencies = num_inactive_currencies + 1
|
||||
# ensure that major currencies are active and enabled for deposit and withdrawal
|
||||
code = exchange.safe_string(currency, 'code', None)
|
||||
withdraw = exchange.safe_bool(currency, 'withdraw')
|
||||
deposit = exchange.safe_bool(currency, 'deposit')
|
||||
if exchange.in_array(code, required_active_currencies):
|
||||
assert skip_major_currency_check or (withdraw and deposit), 'Major currency ' + code + ' should have withdraw and deposit flags enabled'
|
||||
# check at least X% of currencies are active
|
||||
inactive_currencies_percentage = (num_inactive_currencies / currencies_length) * 100
|
||||
assert skip_active or (inactive_currencies_percentage < max_inactive_currencies_percentage), 'Percentage of inactive currencies is too high at ' + str(inactive_currencies_percentage) + '% that is more than the allowed maximum of ' + str(max_inactive_currencies_percentage) + '%'
|
||||
detect_currency_conflicts(exchange, currencies)
|
||||
return True
|
||||
|
||||
|
||||
def detect_currency_conflicts(exchange, currency_values):
|
||||
# detect if there are currencies with different ids for the same code
|
||||
ids = {}
|
||||
keys = list(currency_values.keys())
|
||||
for i in range(0, len(keys)):
|
||||
key = keys[i]
|
||||
currency = currency_values[key]
|
||||
code = currency['code']
|
||||
if not (code in ids):
|
||||
ids[code] = currency['id']
|
||||
else:
|
||||
is_different = ids[code] != currency['id']
|
||||
assert not is_different, exchange.id + ' fetchCurrencies() has different ids for the same code: ' + code + ' ' + ids[code] + ' ' + currency['id']
|
||||
return True
|
||||
26
ccxt/test/exchange/async/test_fetch_deposit_withdrawals.py
Normal file
26
ccxt/test/exchange/async/test_fetch_deposit_withdrawals.py
Normal file
@@ -0,0 +1,26 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_deposit_withdrawal # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
async def test_fetch_deposit_withdrawals(exchange, skipped_properties, code):
|
||||
method = 'fetchTransactions'
|
||||
transactions = await exchange.fetch_transactions(code)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, transactions, code)
|
||||
now = exchange.milliseconds()
|
||||
for i in range(0, len(transactions)):
|
||||
test_deposit_withdrawal(exchange, skipped_properties, method, transactions[i], code, now)
|
||||
test_shared_methods.assert_timestamp_order(exchange, method, code, transactions)
|
||||
return True
|
||||
26
ccxt/test/exchange/async/test_fetch_deposits.py
Normal file
26
ccxt/test/exchange/async/test_fetch_deposits.py
Normal file
@@ -0,0 +1,26 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_deposit_withdrawal # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
async def test_fetch_deposits(exchange, skipped_properties, code):
|
||||
method = 'fetchDeposits'
|
||||
transactions = await exchange.fetch_deposits(code)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, transactions, code)
|
||||
now = exchange.milliseconds()
|
||||
for i in range(0, len(transactions)):
|
||||
test_deposit_withdrawal(exchange, skipped_properties, method, transactions[i], code, now)
|
||||
test_shared_methods.assert_timestamp_order(exchange, method, code, transactions)
|
||||
return True
|
||||
25
ccxt/test/exchange/async/test_fetch_funding_rate_history.py
Normal file
25
ccxt/test/exchange/async/test_fetch_funding_rate_history.py
Normal file
@@ -0,0 +1,25 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_funding_rate_history # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
async def test_fetch_funding_rate_history(exchange, skipped_properties, symbol):
|
||||
method = 'fetchFundingRateHistory'
|
||||
funding_rates_history = await exchange.fetch_funding_rate_history(symbol)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, funding_rates_history, symbol)
|
||||
for i in range(0, len(funding_rates_history)):
|
||||
test_funding_rate_history(exchange, skipped_properties, method, funding_rates_history[i], symbol)
|
||||
test_shared_methods.assert_timestamp_order(exchange, method, symbol, funding_rates_history)
|
||||
return True
|
||||
21
ccxt/test/exchange/async/test_fetch_l2_order_book.py
Normal file
21
ccxt/test/exchange/async/test_fetch_l2_order_book.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_order_book # noqa E402
|
||||
|
||||
async def test_fetch_l2_order_book(exchange, skipped_properties, symbol):
|
||||
method = 'fetchL2OrderBook'
|
||||
order_book = await exchange.fetch_l2_order_book(symbol)
|
||||
test_order_book(exchange, skipped_properties, method, order_book, symbol)
|
||||
return True
|
||||
37
ccxt/test/exchange/async/test_fetch_last_prices.py
Normal file
37
ccxt/test/exchange/async/test_fetch_last_prices.py
Normal file
@@ -0,0 +1,37 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_last_price # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
async def test_fetch_last_prices(exchange, skipped_properties, symbol):
|
||||
method = 'fetchLastprices'
|
||||
# log ('fetching all tickers at once...')
|
||||
response = None
|
||||
checked_symbol = None
|
||||
try:
|
||||
response = await exchange.fetch_last_prices()
|
||||
except Exception as e:
|
||||
response = await exchange.fetch_last_prices([symbol])
|
||||
checked_symbol = symbol
|
||||
assert isinstance(response, dict), exchange.id + ' ' + method + ' ' + checked_symbol + ' must return an object. ' + exchange.json(response)
|
||||
values = list(response.values())
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, values, checked_symbol)
|
||||
at_least_one_passed = False
|
||||
for i in range(0, len(values)):
|
||||
# todo: symbol check here
|
||||
test_last_price(exchange, skipped_properties, method, values[i], checked_symbol)
|
||||
at_least_one_passed = at_least_one_passed or (exchange.safe_number(values[i], 'price') > 0)
|
||||
assert at_least_one_passed, exchange.id + ' ' + method + ' ' + checked_symbol + ' at least one symbol should pass the test'
|
||||
return True
|
||||
26
ccxt/test/exchange/async/test_fetch_ledger.py
Normal file
26
ccxt/test/exchange/async/test_fetch_ledger.py
Normal file
@@ -0,0 +1,26 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_ledger_entry # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
async def test_fetch_ledger(exchange, skipped_properties, code):
|
||||
method = 'fetchLedger'
|
||||
items = await exchange.fetch_ledger(code)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, items, code)
|
||||
now = exchange.milliseconds()
|
||||
for i in range(0, len(items)):
|
||||
test_ledger_entry(exchange, skipped_properties, method, items[i], code, now)
|
||||
test_shared_methods.assert_timestamp_order(exchange, method, code, items)
|
||||
return True
|
||||
29
ccxt/test/exchange/async/test_fetch_ledger_entry.py
Normal file
29
ccxt/test/exchange/async/test_fetch_ledger_entry.py
Normal file
@@ -0,0 +1,29 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_ledger_entry # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
async def test_fetch_ledger_entry(exchange, skipped_properties, code):
|
||||
method = 'fetchLedgerEntry'
|
||||
items = await exchange.fetch_ledger(code)
|
||||
length = len(items)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, items, code)
|
||||
if length > 0:
|
||||
first_item = items[0]
|
||||
id = first_item['id']
|
||||
item = await exchange.fetch_ledger_entry(id)
|
||||
now = exchange.milliseconds()
|
||||
test_ledger_entry(exchange, skipped_properties, method, item, code, now)
|
||||
return True
|
||||
34
ccxt/test/exchange/async/test_fetch_leverage_tiers.py
Normal file
34
ccxt/test/exchange/async/test_fetch_leverage_tiers.py
Normal file
@@ -0,0 +1,34 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_leverage_tier # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
async def test_fetch_leverage_tiers(exchange, skipped_properties, symbol):
|
||||
method = 'fetchLeverageTiers'
|
||||
tiers = await exchange.fetch_leverage_tiers(['symbol'])
|
||||
# const format = {
|
||||
# 'RAY/USDT': [
|
||||
# {},
|
||||
# ],
|
||||
# };
|
||||
assert isinstance(tiers, dict), exchange.id + ' ' + method + ' ' + symbol + ' must return an object. ' + exchange.json(tiers)
|
||||
tier_keys = list(tiers.keys())
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, tier_keys, symbol)
|
||||
for i in range(0, len(tier_keys)):
|
||||
tiers_for_symbol = tiers[tier_keys[i]]
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, tiers_for_symbol, symbol)
|
||||
for j in range(0, len(tiers_for_symbol)):
|
||||
test_leverage_tier(exchange, skipped_properties, method, tiers_for_symbol[j])
|
||||
return True
|
||||
28
ccxt/test/exchange/async/test_fetch_liquidations.py
Normal file
28
ccxt/test/exchange/async/test_fetch_liquidations.py
Normal file
@@ -0,0 +1,28 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
from ccxt.test.exchange.base import test_liquidation # noqa E402
|
||||
|
||||
async def test_fetch_liquidations(exchange, skipped_properties, code):
|
||||
method = 'fetchLiquidations'
|
||||
if not exchange.has['fetchLiquidations']:
|
||||
return True
|
||||
items = await exchange.fetch_liquidations(code)
|
||||
assert isinstance(items, list), exchange.id + ' ' + method + ' ' + code + ' must return an array. ' + exchange.json(items)
|
||||
# const now = exchange.milliseconds ();
|
||||
for i in range(0, len(items)):
|
||||
test_liquidation(exchange, skipped_properties, method, items[i], code)
|
||||
test_shared_methods.assert_timestamp_order(exchange, method, code, items)
|
||||
return True
|
||||
21
ccxt/test/exchange/async/test_fetch_margin_mode.py
Normal file
21
ccxt/test/exchange/async/test_fetch_margin_mode.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_margin_mode # noqa E402
|
||||
|
||||
async def test_fetch_margin_mode(exchange, skipped_properties, symbol):
|
||||
method = 'fetchMarginMode'
|
||||
margin_mode = await exchange.fetch_margin_mode(symbol)
|
||||
test_margin_mode(exchange, skipped_properties, method, margin_mode)
|
||||
return True
|
||||
28
ccxt/test/exchange/async/test_fetch_margin_modes.py
Normal file
28
ccxt/test/exchange/async/test_fetch_margin_modes.py
Normal file
@@ -0,0 +1,28 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_margin_mode # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
async def test_fetch_margin_modes(exchange, skipped_properties, symbol):
|
||||
method = 'fetchMarginModes'
|
||||
margin_modes = await exchange.fetch_margin_modes(['symbol'])
|
||||
assert isinstance(margin_modes, dict), exchange.id + ' ' + method + ' ' + symbol + ' must return an object. ' + exchange.json(margin_modes)
|
||||
margin_mode_keys = list(margin_modes.keys())
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, margin_modes, symbol)
|
||||
for i in range(0, len(margin_mode_keys)):
|
||||
margin_mode = margin_modes[margin_mode_keys[i]]
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, margin_mode, symbol)
|
||||
test_margin_mode(exchange, skipped_properties, method, margin_mode)
|
||||
return True
|
||||
24
ccxt/test/exchange/async/test_fetch_market_leverage_tiers.py
Normal file
24
ccxt/test/exchange/async/test_fetch_market_leverage_tiers.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_leverage_tier # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
async def test_fetch_market_leverage_tiers(exchange, skipped_properties, symbol):
|
||||
method = 'fetchMarketLeverageTiers'
|
||||
tiers = await exchange.fetch_market_leverage_tiers(symbol)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, tiers, symbol)
|
||||
for j in range(0, len(tiers)):
|
||||
test_leverage_tier(exchange, skipped_properties, method, tiers[j])
|
||||
return True
|
||||
41
ccxt/test/exchange/async/test_fetch_markets.py
Normal file
41
ccxt/test/exchange/async/test_fetch_markets.py
Normal file
@@ -0,0 +1,41 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_market # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
async def test_fetch_markets(exchange, skipped_properties):
|
||||
method = 'fetchMarkets'
|
||||
markets = await exchange.fetch_markets()
|
||||
assert isinstance(markets, dict), exchange.id + ' ' + method + ' must return an object. ' + exchange.json(markets)
|
||||
market_values = list(markets.values())
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, market_values)
|
||||
for i in range(0, len(market_values)):
|
||||
test_market(exchange, skipped_properties, method, market_values[i])
|
||||
detect_market_conflicts(exchange, markets)
|
||||
return True
|
||||
|
||||
|
||||
def detect_market_conflicts(exchange, market_values):
|
||||
# detect if there are markets with different ids for the same symbol
|
||||
ids = {}
|
||||
for i in range(0, len(market_values)):
|
||||
market = market_values[i]
|
||||
symbol = market['symbol']
|
||||
if not (symbol in ids):
|
||||
ids[symbol] = market['id']
|
||||
else:
|
||||
is_different = ids[symbol] != market['id']
|
||||
assert not is_different, exchange.id + ' fetchMarkets() has different ids for the same symbol: ' + symbol + ' ' + ids[symbol] + ' ' + market['id']
|
||||
return True
|
||||
28
ccxt/test/exchange/async/test_fetch_my_liquidations.py
Normal file
28
ccxt/test/exchange/async/test_fetch_my_liquidations.py
Normal file
@@ -0,0 +1,28 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
from ccxt.test.exchange.base import test_liquidation # noqa E402
|
||||
|
||||
async def test_fetch_my_liquidations(exchange, skipped_properties, code):
|
||||
method = 'fetchMyLiquidations'
|
||||
if not exchange.has['fetchMyLiquidations']:
|
||||
return True
|
||||
items = await exchange.fetch_my_liquidations(code)
|
||||
assert isinstance(items, list), exchange.id + ' ' + method + ' ' + code + ' must return an array. ' + exchange.json(items)
|
||||
# const now = exchange.milliseconds ();
|
||||
for i in range(0, len(items)):
|
||||
test_liquidation(exchange, skipped_properties, method, items[i], code)
|
||||
test_shared_methods.assert_timestamp_order(exchange, method, code, items)
|
||||
return True
|
||||
26
ccxt/test/exchange/async/test_fetch_my_trades.py
Normal file
26
ccxt/test/exchange/async/test_fetch_my_trades.py
Normal file
@@ -0,0 +1,26 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
from ccxt.test.exchange.base import test_trade # noqa E402
|
||||
|
||||
async def test_fetch_my_trades(exchange, skipped_properties, symbol):
|
||||
method = 'fetchMyTrades'
|
||||
trades = await exchange.fetch_my_trades(symbol)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, trades, symbol)
|
||||
now = exchange.milliseconds()
|
||||
for i in range(0, len(trades)):
|
||||
test_trade(exchange, skipped_properties, method, trades[i], symbol, now)
|
||||
test_shared_methods.assert_timestamp_order(exchange, method, symbol, trades)
|
||||
return True
|
||||
35
ccxt/test/exchange/async/test_fetch_ohlcv.py
Normal file
35
ccxt/test/exchange/async/test_fetch_ohlcv.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_ohlcv # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
async def test_fetch_ohlcv(exchange, skipped_properties, symbol):
|
||||
method = 'fetchOHLCV'
|
||||
timeframe_keys = list(exchange.timeframes.keys())
|
||||
assert len(timeframe_keys), exchange.id + ' ' + method + ' - no timeframes found'
|
||||
# prefer 1m timeframe if available, otherwise return the first one
|
||||
chosen_timeframe_key = '1m'
|
||||
if not exchange.in_array(chosen_timeframe_key, timeframe_keys):
|
||||
chosen_timeframe_key = timeframe_keys[0]
|
||||
limit = 10
|
||||
duration = exchange.parse_timeframe(chosen_timeframe_key)
|
||||
since = exchange.milliseconds() - duration * limit * 1000 - 1000
|
||||
ohlcvs = await exchange.fetch_ohlcv(symbol, chosen_timeframe_key, since, limit)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, ohlcvs, symbol)
|
||||
now = exchange.milliseconds()
|
||||
for i in range(0, len(ohlcvs)):
|
||||
test_ohlcv(exchange, skipped_properties, method, ohlcvs[i], symbol, now)
|
||||
# todo: sorted timestamps check
|
||||
return True
|
||||
24
ccxt/test/exchange/async/test_fetch_open_interest_history.py
Normal file
24
ccxt/test/exchange/async/test_fetch_open_interest_history.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_open_interest # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
async def test_fetch_open_interest_history(exchange, skipped_properties, symbol):
|
||||
method = 'fetchOpenInterestHistory'
|
||||
open_interest_history = await exchange.fetch_open_interest_history(symbol)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, open_interest_history, symbol)
|
||||
for i in range(0, len(open_interest_history)):
|
||||
test_open_interest(exchange, skipped_properties, method, open_interest_history[i])
|
||||
return True
|
||||
28
ccxt/test/exchange/async/test_fetch_open_orders.py
Normal file
28
ccxt/test/exchange/async/test_fetch_open_orders.py
Normal file
@@ -0,0 +1,28 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_order # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
async def test_fetch_open_orders(exchange, skipped_properties, symbol):
|
||||
method = 'fetchOpenOrders'
|
||||
orders = await exchange.fetch_open_orders(symbol)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, orders, symbol)
|
||||
now = exchange.milliseconds()
|
||||
for i in range(0, len(orders)):
|
||||
order = orders[i]
|
||||
test_order(exchange, skipped_properties, method, order, symbol, now)
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, order, 'status', ['open'])
|
||||
test_shared_methods.assert_timestamp_order(exchange, method, symbol, orders)
|
||||
return True
|
||||
21
ccxt/test/exchange/async/test_fetch_order_book.py
Normal file
21
ccxt/test/exchange/async/test_fetch_order_book.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_order_book # noqa E402
|
||||
|
||||
async def test_fetch_order_book(exchange, skipped_properties, symbol):
|
||||
method = 'fetchOrderBook'
|
||||
orderbook = await exchange.fetch_order_book(symbol)
|
||||
test_order_book(exchange, skipped_properties, method, orderbook, symbol)
|
||||
return True
|
||||
27
ccxt/test/exchange/async/test_fetch_order_books.py
Normal file
27
ccxt/test/exchange/async/test_fetch_order_books.py
Normal file
@@ -0,0 +1,27 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_order_book # noqa E402
|
||||
|
||||
async def test_fetch_order_books(exchange, skipped_properties):
|
||||
method = 'fetchOrderBooks'
|
||||
symbol = exchange.symbols[0]
|
||||
order_books = await exchange.fetch_order_books([symbol])
|
||||
assert isinstance(order_books, dict), exchange.id + ' ' + method + ' must return an object. ' + exchange.json(order_books)
|
||||
order_book_keys = list(order_books.keys())
|
||||
assert len(order_book_keys), exchange.id + ' ' + method + ' returned 0 length data'
|
||||
for i in range(0, len(order_book_keys)):
|
||||
symbol_inner = order_book_keys[i]
|
||||
test_order_book(exchange, skipped_properties, method, order_books[symbol_inner], symbol_inner)
|
||||
return True
|
||||
27
ccxt/test/exchange/async/test_fetch_orders.py
Normal file
27
ccxt/test/exchange/async/test_fetch_orders.py
Normal file
@@ -0,0 +1,27 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_order # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
async def test_fetch_orders(exchange, skipped_properties, symbol):
|
||||
method = 'fetchOrders'
|
||||
orders = await exchange.fetch_orders(symbol)
|
||||
assert isinstance(orders, list), exchange.id + ' ' + method + ' must return an array, returned ' + exchange.json(orders)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, orders, symbol)
|
||||
now = exchange.milliseconds()
|
||||
for i in range(0, len(orders)):
|
||||
test_order(exchange, skipped_properties, method, orders[i], symbol, now)
|
||||
test_shared_methods.assert_timestamp_order(exchange, method, symbol, orders)
|
||||
return True
|
||||
35
ccxt/test/exchange/async/test_fetch_positions.py
Normal file
35
ccxt/test/exchange/async/test_fetch_positions.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_position # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
async def test_fetch_positions(exchange, skipped_properties, symbol):
|
||||
method = 'fetchPositions'
|
||||
now = exchange.milliseconds()
|
||||
# without symbol
|
||||
positions = await exchange.fetch_positions()
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, positions, symbol)
|
||||
for i in range(0, len(positions)):
|
||||
test_position(exchange, skipped_properties, method, positions[i], None, now)
|
||||
# testSharedMethods.assertTimestampOrder (exchange, method, undefined, positions); # currently order of positions does not make sense
|
||||
# with symbol
|
||||
positions_for_symbol = await exchange.fetch_positions([symbol])
|
||||
assert isinstance(positions_for_symbol, list), exchange.id + ' ' + method + ' must return an array, returned ' + exchange.json(positions_for_symbol)
|
||||
positions_for_symbol_length = len(positions_for_symbol)
|
||||
assert positions_for_symbol_length <= 4, exchange.id + ' ' + method + ' positions length for particular symbol should be less than 4, returned ' + exchange.json(positions_for_symbol)
|
||||
for i in range(0, len(positions_for_symbol)):
|
||||
test_position(exchange, skipped_properties, method, positions_for_symbol[i], symbol, now)
|
||||
# testSharedMethods.assertTimestampOrder (exchange, method, symbol, positionsForSymbol);
|
||||
return True
|
||||
21
ccxt/test/exchange/async/test_fetch_status.py
Normal file
21
ccxt/test/exchange/async/test_fetch_status.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_status # noqa E402
|
||||
|
||||
async def test_fetch_status(exchange, skipped_properties):
|
||||
method = 'fetchStatus'
|
||||
status = await exchange.fetch_status()
|
||||
test_status(exchange, skipped_properties, method, status, exchange.milliseconds())
|
||||
return True
|
||||
21
ccxt/test/exchange/async/test_fetch_ticker.py
Normal file
21
ccxt/test/exchange/async/test_fetch_ticker.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_ticker # noqa E402
|
||||
|
||||
async def test_fetch_ticker(exchange, skipped_properties, symbol):
|
||||
method = 'fetchTicker'
|
||||
ticker = await exchange.fetch_ticker(symbol)
|
||||
test_ticker(exchange, skipped_properties, method, ticker, symbol)
|
||||
return True
|
||||
59
ccxt/test/exchange/async/test_fetch_tickers.py
Normal file
59
ccxt/test/exchange/async/test_fetch_tickers.py
Normal file
@@ -0,0 +1,59 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import asyncio
|
||||
from ccxt.test.exchange.base import test_ticker # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
async def test_fetch_tickers(exchange, skipped_properties, symbol):
|
||||
without_symbol = test_fetch_tickers_helper(exchange, skipped_properties, None)
|
||||
with_symbol = test_fetch_tickers_helper(exchange, skipped_properties, [symbol])
|
||||
results = await asyncio.gather(*[without_symbol, with_symbol])
|
||||
test_fetch_tickers_amounts(exchange, skipped_properties, results[0])
|
||||
return results
|
||||
|
||||
|
||||
async def test_fetch_tickers_helper(exchange, skipped_properties, arg_symbols, arg_params={}):
|
||||
method = 'fetchTickers'
|
||||
response = await exchange.fetch_tickers(arg_symbols, arg_params)
|
||||
assert isinstance(response, dict), exchange.id + ' ' + method + ' ' + exchange.json(arg_symbols) + ' must return an object. ' + exchange.json(response)
|
||||
values = list(response.values())
|
||||
checked_symbol = None
|
||||
if arg_symbols is not None and len(arg_symbols) == 1:
|
||||
checked_symbol = arg_symbols[0]
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, values, checked_symbol)
|
||||
for i in range(0, len(values)):
|
||||
# todo: symbol check here
|
||||
ticker = values[i]
|
||||
test_ticker(exchange, skipped_properties, method, ticker, checked_symbol)
|
||||
return response
|
||||
|
||||
|
||||
def test_fetch_tickers_amounts(exchange, skipped_properties, tickers):
|
||||
tickers_values = list(tickers.values())
|
||||
if not ('checkActiveSymbols' in skipped_properties):
|
||||
#
|
||||
# ensure all "active" symbols have tickers
|
||||
#
|
||||
non_inactive_markets = test_shared_methods.get_active_markets(exchange)
|
||||
not_inactive_symbols_length = len(non_inactive_markets)
|
||||
obtained_tickers_length = len(tickers_values)
|
||||
min_ratio = 0.99 # 1.0 - 0.01 = 0.99, hardcoded to avoid C# transpiler type casting issues
|
||||
assert obtained_tickers_length >= not_inactive_symbols_length * min_ratio, exchange.id + ' ' + 'fetchTickers' + ' must return tickers for all active markets. but returned: ' + str(obtained_tickers_length) + ' tickers, ' + str(not_inactive_symbols_length) + ' active markets'
|
||||
#
|
||||
# ensure tickers length is less than markets length
|
||||
#
|
||||
all_markets = exchange.markets
|
||||
all_markets_length = len(list(all_markets.keys()))
|
||||
assert obtained_tickers_length <= all_markets_length, exchange.id + ' ' + 'fetchTickers' + ' must return <= than all markets, but returned: ' + str(obtained_tickers_length) + ' tickers, ' + str(all_markets_length) + ' markets'
|
||||
28
ccxt/test/exchange/async/test_fetch_trades.py
Normal file
28
ccxt/test/exchange/async/test_fetch_trades.py
Normal file
@@ -0,0 +1,28 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
from ccxt.test.exchange.base import test_trade # noqa E402
|
||||
|
||||
async def test_fetch_trades(exchange, skipped_properties, symbol):
|
||||
method = 'fetchTrades'
|
||||
trades = await exchange.fetch_trades(symbol)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, trades)
|
||||
now = exchange.milliseconds()
|
||||
for i in range(0, len(trades)):
|
||||
test_trade(exchange, skipped_properties, method, trades[i], symbol, now)
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, trades[i], 'takerOrMaker', ['taker', None])
|
||||
if not ('timestampSort' in skipped_properties):
|
||||
test_shared_methods.assert_timestamp_order(exchange, method, symbol, trades)
|
||||
return True
|
||||
22
ccxt/test/exchange/async/test_fetch_trading_fee.py
Normal file
22
ccxt/test/exchange/async/test_fetch_trading_fee.py
Normal file
@@ -0,0 +1,22 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_trading_fee # noqa E402
|
||||
|
||||
async def test_fetch_trading_fee(exchange, skipped_properties, symbol):
|
||||
method = 'fetchTradingFee'
|
||||
fee = await exchange.fetch_trading_fee(symbol)
|
||||
assert isinstance(fee, dict), exchange.id + ' ' + method + ' ' + symbol + ' must return an object. ' + exchange.json(fee)
|
||||
test_trading_fee(exchange, skipped_properties, method, symbol, fee)
|
||||
return True
|
||||
26
ccxt/test/exchange/async/test_fetch_trading_fees.py
Normal file
26
ccxt/test/exchange/async/test_fetch_trading_fees.py
Normal file
@@ -0,0 +1,26 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_trading_fee # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
async def test_fetch_trading_fees(exchange, skipped_properties):
|
||||
method = 'fetchTradingFees'
|
||||
fees = await exchange.fetch_trading_fees()
|
||||
symbols = list(fees.keys())
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, symbols)
|
||||
for i in range(0, len(symbols)):
|
||||
symbol = symbols[i]
|
||||
test_trading_fee(exchange, skipped_properties, method, symbol, fees[symbol])
|
||||
return True
|
||||
22
ccxt/test/exchange/async/test_fetch_transaction_fees.py
Normal file
22
ccxt/test/exchange/async/test_fetch_transaction_fees.py
Normal file
@@ -0,0 +1,22 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
|
||||
async def test_fetch_transaction_fees(exchange, skipped_properties):
|
||||
# const method = 'fetchTransactionFees';
|
||||
# const fees = await exchange.fetchTransactionFees ();
|
||||
# const withdrawKeys = Object.keys (fees['withdraw']);
|
||||
# todo : assert each entry
|
||||
return None
|
||||
26
ccxt/test/exchange/async/test_fetch_withdrawals.py
Normal file
26
ccxt/test/exchange/async/test_fetch_withdrawals.py
Normal file
@@ -0,0 +1,26 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_deposit_withdrawal # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
async def test_fetch_withdrawals(exchange, skipped_properties, code):
|
||||
method = 'fetchWithdrawals'
|
||||
transactions = await exchange.fetch_withdrawals(code)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, transactions, code)
|
||||
now = exchange.milliseconds()
|
||||
for i in range(0, len(transactions)):
|
||||
test_deposit_withdrawal(exchange, skipped_properties, method, transactions[i], code, now)
|
||||
test_shared_methods.assert_timestamp_order(exchange, method, code, transactions)
|
||||
return True
|
||||
31
ccxt/test/exchange/async/test_load_markets.py
Normal file
31
ccxt/test/exchange/async/test_load_markets.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_market # noqa E402
|
||||
|
||||
async def test_load_markets(exchange, skipped_properties):
|
||||
method = 'loadMarkets'
|
||||
markets = await exchange.load_markets()
|
||||
assert isinstance(exchange.markets, dict), '.markets is not an object'
|
||||
assert isinstance(exchange.symbols, list), '.symbols is not an array'
|
||||
symbols_length = len(exchange.symbols)
|
||||
market_keys = list(exchange.markets.keys())
|
||||
market_keys_length = len(market_keys)
|
||||
assert symbols_length > 0, '.symbols count <= 0 (less than or equal to zero)'
|
||||
assert market_keys_length > 0, '.markets objects keys length <= 0 (less than or equal to zero)'
|
||||
assert symbols_length == market_keys_length, 'number of .symbols is not equal to the number of .markets'
|
||||
market_values = list(markets.values())
|
||||
for i in range(0, len(market_values)):
|
||||
test_market(exchange, skipped_properties, method, market_values[i])
|
||||
return True
|
||||
73
ccxt/test/exchange/async/test_proxies.py
Normal file
73
ccxt/test/exchange/async/test_proxies.py
Normal file
@@ -0,0 +1,73 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
async def test_proxies(exchange, skipped_properties):
|
||||
await test_proxy_url(exchange, skipped_properties)
|
||||
await test_http_proxy(exchange, skipped_properties)
|
||||
# 'httpsProxy', 'socksProxy'
|
||||
await test_proxy_for_exceptions(exchange, skipped_properties)
|
||||
|
||||
|
||||
async def test_proxy_url(exchange, skipped_properties):
|
||||
method = 'proxyUrl'
|
||||
proxy_server_ip = '5.75.153.75'
|
||||
[proxy_url, http_proxy, https_proxy, socks_proxy] = test_shared_methods.remove_proxy_options(exchange, skipped_properties)
|
||||
exchange.proxy_url = 'http://' + proxy_server_ip + ':8090/proxy_url.php?caller=https://ccxt.com&url='
|
||||
encoded_colon = '%3A'
|
||||
encoded_slash = '%2F'
|
||||
ip_check_url = 'https' + encoded_colon + encoded_slash + encoded_slash + 'api.ipify.org'
|
||||
response = await exchange.fetch(ip_check_url)
|
||||
assert response == proxy_server_ip, exchange.id + ' ' + method + ' test failed. Returned response is ' + response + ' while it should be "' + proxy_server_ip + '"'
|
||||
# reset the instance property
|
||||
test_shared_methods.set_proxy_options(exchange, skipped_properties, proxy_url, http_proxy, https_proxy, socks_proxy)
|
||||
return True
|
||||
|
||||
|
||||
async def test_http_proxy(exchange, skipped_properties):
|
||||
method = 'httpProxy'
|
||||
proxy_server_ip = '5.75.153.75'
|
||||
[proxy_url, http_proxy, https_proxy, socks_proxy] = test_shared_methods.remove_proxy_options(exchange, skipped_properties)
|
||||
exchange.http_proxy = 'http://' + proxy_server_ip + ':8911'
|
||||
ip_check_url = 'https://api.ipify.org/'
|
||||
response = await exchange.fetch(ip_check_url)
|
||||
assert response == proxy_server_ip, exchange.id + ' ' + method + ' test failed. Returned response is ' + response + ' while it should be "' + proxy_server_ip + '"'
|
||||
# reset the instance property
|
||||
test_shared_methods.set_proxy_options(exchange, skipped_properties, proxy_url, http_proxy, https_proxy, socks_proxy)
|
||||
|
||||
|
||||
# with the below method we test out all variations of possible proxy options, so at least 2 of them should be set together, and such cases must throw exception
|
||||
async def test_proxy_for_exceptions(exchange, skipped_properties):
|
||||
method = 'testProxyForExceptions'
|
||||
[proxy_url, http_proxy, https_proxy, socks_proxy] = test_shared_methods.remove_proxy_options(exchange, skipped_properties)
|
||||
possible_options_array = ['proxyUrl', 'proxyUrlCallback', 'proxy_url', 'proxy_url_callback', 'httpProxy', 'httpProxyCallback', 'http_proxy', 'http_proxy_callback', 'httpsProxy', 'httpsProxyCallback', 'https_proxy', 'https_proxy_callback', 'socksProxy', 'socksProxyCallback', 'socks_proxy', 'socks_proxy_callback']
|
||||
for i in range(0, len(possible_options_array)):
|
||||
for j in range(0, len(possible_options_array)):
|
||||
if j != i:
|
||||
proxy_first = possible_options_array[i]
|
||||
proxy_second = possible_options_array[j]
|
||||
exchange.set_property(exchange, proxy_first, '0.0.0.0') # actual value does not matter
|
||||
exchange.set_property(exchange, proxy_second, '0.0.0.0') # actual value does not matter
|
||||
exception_caught = False
|
||||
try:
|
||||
await exchange.fetch('http://example.com') # url does not matter, it will not be called
|
||||
except Exception as e:
|
||||
exception_caught = True
|
||||
assert exception_caught, exchange.id + ' ' + method + ' test failed. No exception was thrown, while ' + proxy_first + ' and ' + proxy_second + ' were set together'
|
||||
# reset to undefined
|
||||
exchange.set_property(exchange, proxy_first, None)
|
||||
exchange.set_property(exchange, proxy_second, None)
|
||||
# reset the instance property
|
||||
test_shared_methods.set_proxy_options(exchange, skipped_properties, proxy_url, http_proxy, https_proxy, socks_proxy)
|
||||
21
ccxt/test/exchange/async/test_sign_in.py
Normal file
21
ccxt/test/exchange/async/test_sign_in.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
|
||||
async def test_sign_in(exchange, skipped_properties):
|
||||
method = 'signIn'
|
||||
if exchange.has[method]:
|
||||
await exchange.sign_in()
|
||||
return True
|
||||
29
ccxt/test/exchange/base/__init__.py
Normal file
29
ccxt/test/exchange/base/__init__.py
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
from ccxt.test.exchange.base.test_account import test_account # noqa E402
|
||||
from ccxt.test.exchange.base.test_balance import test_balance # noqa E402
|
||||
from ccxt.test.exchange.base.test_borrow_interest import test_borrow_interest # noqa E402
|
||||
from ccxt.test.exchange.base.test_borrow_rate import test_borrow_rate # noqa E402
|
||||
from ccxt.test.exchange.base.test_currency import test_currency # noqa E402
|
||||
from ccxt.test.exchange.base.test_deposit_withdrawal import test_deposit_withdrawal # noqa E402
|
||||
from ccxt.test.exchange.base.test_funding_rate_history import test_funding_rate_history # noqa E402
|
||||
from ccxt.test.exchange.base.test_last_price import test_last_price # noqa E402
|
||||
from ccxt.test.exchange.base.test_ledger_entry import test_ledger_entry # noqa E402
|
||||
from ccxt.test.exchange.base.test_leverage_tier import test_leverage_tier # noqa E402
|
||||
from ccxt.test.exchange.base.test_liquidation import test_liquidation # noqa E402
|
||||
from ccxt.test.exchange.base.test_margin_mode import test_margin_mode # noqa E402
|
||||
from ccxt.test.exchange.base.test_margin_modification import test_margin_modification # noqa E402
|
||||
from ccxt.test.exchange.base.test_market import test_market # noqa E402
|
||||
from ccxt.test.exchange.base.test_ohlcv import test_ohlcv # noqa E402
|
||||
from ccxt.test.exchange.base.test_open_interest import test_open_interest # noqa E402
|
||||
from ccxt.test.exchange.base.test_order import test_order # noqa E402
|
||||
from ccxt.test.exchange.base.test_order_book import test_order_book # noqa E402
|
||||
from ccxt.test.exchange.base.test_position import test_position # noqa E402
|
||||
from ccxt.test.exchange.base.test_status import test_status # noqa E402
|
||||
from ccxt.test.exchange.base.test_ticker import test_ticker # noqa E402
|
||||
from ccxt.test.exchange.base.test_trade import test_trade # noqa E402
|
||||
from ccxt.test.exchange.base.test_trading_fee import test_trading_fee # noqa E402
|
||||
26
ccxt/test/exchange/base/test_account.py
Normal file
26
ccxt/test/exchange/base/test_account.py
Normal file
@@ -0,0 +1,26 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_account(exchange, skipped_properties, method, entry):
|
||||
format = {
|
||||
'info': {},
|
||||
'code': 'BTC',
|
||||
'type': 'spot',
|
||||
'id': '12345',
|
||||
}
|
||||
empty_allowed_for = ['code', 'id']
|
||||
test_shared_methods.assert_structure(exchange, skipped_properties, method, entry, format, empty_allowed_for)
|
||||
test_shared_methods.assert_currency_code(exchange, skipped_properties, method, entry, entry['code'])
|
||||
56
ccxt/test/exchange/base/test_balance.py
Normal file
56
ccxt/test/exchange/base/test_balance.py
Normal file
@@ -0,0 +1,56 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.base.precise import Precise # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_balance(exchange, skipped_properties, method, entry):
|
||||
format = {
|
||||
'free': {},
|
||||
'used': {},
|
||||
'total': {},
|
||||
'info': {},
|
||||
}
|
||||
test_shared_methods.assert_structure(exchange, skipped_properties, method, entry, format)
|
||||
log_text = test_shared_methods.log_template(exchange, method, entry)
|
||||
#
|
||||
codes_total = list(entry['total'].keys())
|
||||
codes_free = list(entry['free'].keys())
|
||||
codes_used = list(entry['used'].keys())
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, codes_total, 'total')
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, codes_free, 'free')
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, codes_used, 'used')
|
||||
all_codes = exchange.array_concat(codes_total, codes_free)
|
||||
all_codes = exchange.array_concat(all_codes, codes_used)
|
||||
codes_length = len(codes_total)
|
||||
free_length = len(codes_free)
|
||||
used_length = len(codes_used)
|
||||
assert (codes_length == free_length) or (codes_length == used_length), 'free and total and used codes have different lengths' + log_text
|
||||
for i in range(0, len(all_codes)):
|
||||
code = all_codes[i]
|
||||
# testSharedMethods.assertCurrencyCode (exchange, skippedProperties, method, entry, code);
|
||||
assert code in entry['total'], 'code ' + code + ' not in total' + log_text
|
||||
assert code in entry['free'], 'code ' + code + ' not in free' + log_text
|
||||
assert code in entry['used'], 'code ' + code + ' not in used' + log_text
|
||||
total = exchange.safe_string(entry['total'], code)
|
||||
free = exchange.safe_string(entry['free'], code)
|
||||
used = exchange.safe_string(entry['used'], code)
|
||||
assert total is not None, 'total is undefined' + log_text
|
||||
assert free is not None, 'free is undefined' + log_text
|
||||
assert used is not None, 'used is undefined' + log_text
|
||||
assert Precise.string_ge(total, '0'), 'total is not positive' + log_text
|
||||
assert Precise.string_ge(free, '0'), 'free is not positive' + log_text
|
||||
assert Precise.string_ge(used, '0'), 'used is not positive' + log_text
|
||||
sum_free_used = Precise.string_add(free, used)
|
||||
assert Precise.string_eq(total, sum_free_used), 'free and used do not sum to total' + log_text
|
||||
35
ccxt/test/exchange/base/test_borrow_interest.py
Normal file
35
ccxt/test/exchange/base/test_borrow_interest.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_borrow_interest(exchange, skipped_properties, method, entry, requested_code, requested_symbol):
|
||||
format = {
|
||||
'info': {},
|
||||
'account': 'BTC/USDT',
|
||||
'currency': 'USDT',
|
||||
'interest': exchange.parse_number('0.1444'),
|
||||
'interestRate': exchange.parse_number('0.0006'),
|
||||
'amountBorrowed': exchange.parse_number('30.0'),
|
||||
'timestamp': 1638230400000,
|
||||
'datetime': '2021-11-30T00:00:00.000Z',
|
||||
}
|
||||
empty_allowed_for = ['account']
|
||||
test_shared_methods.assert_structure(exchange, skipped_properties, method, entry, format, empty_allowed_for)
|
||||
test_shared_methods.assert_timestamp_and_datetime(exchange, skipped_properties, method, entry)
|
||||
test_shared_methods.assert_currency_code(exchange, skipped_properties, method, entry, entry['currency'], requested_code)
|
||||
test_shared_methods.assert_symbol(exchange, skipped_properties, method, entry, entry['account'], requested_symbol)
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'interest', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'interestRate', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'amountBorrowed', '0')
|
||||
32
ccxt/test/exchange/base/test_borrow_rate.py
Normal file
32
ccxt/test/exchange/base/test_borrow_rate.py
Normal file
@@ -0,0 +1,32 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_borrow_rate(exchange, skipped_properties, method, entry, requested_code):
|
||||
format = {
|
||||
'info': {},
|
||||
'currency': 'USDT',
|
||||
'timestamp': 1638230400000,
|
||||
'datetime': '2021-11-30T00:00:00.000Z',
|
||||
'rate': exchange.parse_number('0.0006'),
|
||||
'period': 86400000,
|
||||
}
|
||||
test_shared_methods.assert_structure(exchange, skipped_properties, method, entry, format)
|
||||
test_shared_methods.assert_timestamp_and_datetime(exchange, skipped_properties, method, entry)
|
||||
test_shared_methods.assert_currency_code(exchange, skipped_properties, method, entry, entry['currency'], requested_code)
|
||||
#
|
||||
# assert (borrowRate['period'] === 86400000 || borrowRate['period'] === 3600000) # Milliseconds in an hour or a day
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'period', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'rate', '0')
|
||||
85
ccxt/test/exchange/base/test_currency.py
Normal file
85
ccxt/test/exchange/base/test_currency.py
Normal file
@@ -0,0 +1,85 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.base.decimal_to_precision import SIGNIFICANT_DIGITS # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_currency(exchange, skipped_properties, method, entry):
|
||||
format = {
|
||||
'id': 'btc',
|
||||
'code': 'BTC',
|
||||
}
|
||||
# todo: remove fee from empty
|
||||
empty_allowed_for = ['name', 'fee']
|
||||
# todo: info key needs to be added in base, when exchange does not have fetchCurrencies
|
||||
is_native = exchange.has['fetchCurrencies'] and exchange.has['fetchCurrencies'] != 'emulated'
|
||||
currency_type = exchange.safe_string(entry, 'type')
|
||||
if is_native:
|
||||
format['info'] = {}
|
||||
# todo: 'name': 'Bitcoin', # uppercase string, base currency, 2 or more letters
|
||||
format['withdraw'] = True # withdraw enabled
|
||||
format['deposit'] = True # deposit enabled
|
||||
format['precision'] = exchange.parse_number('0.0001') # in case of SIGNIFICANT_DIGITS it will be 4 - number of digits "after the dot"
|
||||
format['fee'] = exchange.parse_number('0.001')
|
||||
format['networks'] = {}
|
||||
format['limits'] = {
|
||||
'withdraw': {
|
||||
'min': exchange.parse_number('0.01'),
|
||||
'max': exchange.parse_number('1000'),
|
||||
},
|
||||
'deposit': {
|
||||
'min': exchange.parse_number('0.01'),
|
||||
'max': exchange.parse_number('1000'),
|
||||
},
|
||||
}
|
||||
format['type'] = 'crypto' # crypto, fiat, leverage, other
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, entry, 'type', ['fiat', 'crypto', 'leveraged', 'other', None]) # todo: remove undefined
|
||||
# only require "deposit" & "withdraw" values, when currency is not fiat, or when it's fiat, but not skipped
|
||||
if currency_type != 'crypto' and ('depositForNonCrypto' in skipped_properties):
|
||||
empty_allowed_for.append('deposit')
|
||||
if currency_type != 'crypto' and ('withdrawForNonCrypto' in skipped_properties):
|
||||
empty_allowed_for.append('withdraw')
|
||||
if currency_type == 'leveraged' or currency_type == 'other':
|
||||
empty_allowed_for.append('precision')
|
||||
#
|
||||
test_shared_methods.assert_currency_code(exchange, skipped_properties, method, entry, entry['code'])
|
||||
# check if empty networks should be skipped
|
||||
networks = exchange.safe_dict(entry, 'networks', {})
|
||||
network_keys = list(networks.keys())
|
||||
network_keys_length = len(network_keys)
|
||||
if network_keys_length == 0 and ('skipCurrenciesWithoutNetworks' in skipped_properties):
|
||||
return
|
||||
#
|
||||
test_shared_methods.assert_structure(exchange, skipped_properties, method, entry, format, empty_allowed_for)
|
||||
#
|
||||
test_shared_methods.check_precision_accuracy(exchange, skipped_properties, method, entry, 'precision')
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, entry, 'fee', '0')
|
||||
if not ('limits' in skipped_properties):
|
||||
limits = exchange.safe_value(entry, 'limits', {})
|
||||
withdraw_limits = exchange.safe_value(limits, 'withdraw', {})
|
||||
deposit_limits = exchange.safe_value(limits, 'deposit', {})
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, withdraw_limits, 'min', '0')
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, withdraw_limits, 'max', '0')
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, deposit_limits, 'min', '0')
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, deposit_limits, 'max', '0')
|
||||
# max should be more than min (withdrawal limits)
|
||||
min_string_withdrawal = exchange.safe_string(withdraw_limits, 'min')
|
||||
if min_string_withdrawal is not None:
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, withdraw_limits, 'max', min_string_withdrawal)
|
||||
# max should be more than min (deposit limits)
|
||||
min_string_deposit = exchange.safe_string(deposit_limits, 'min')
|
||||
if min_string_deposit is not None:
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, deposit_limits, 'max', min_string_deposit)
|
||||
# check valid ID & CODE
|
||||
test_shared_methods.assert_valid_currency_id_and_code(exchange, skipped_properties, method, entry, entry['id'], entry['code'])
|
||||
50
ccxt/test/exchange/base/test_deposit_withdrawal.py
Normal file
50
ccxt/test/exchange/base/test_deposit_withdrawal.py
Normal file
@@ -0,0 +1,50 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_deposit_withdrawal(exchange, skipped_properties, method, entry, requested_code, now):
|
||||
format = {
|
||||
'info': {},
|
||||
'id': '1234',
|
||||
'txid': '0x1345FEG45EAEF7',
|
||||
'timestamp': 1502962946216,
|
||||
'datetime': '2017-08-17 12:42:48.000',
|
||||
'network': 'ETH',
|
||||
'address': '0xEFE3487358AEF352345345',
|
||||
'addressTo': '0xEFE3487358AEF352345123',
|
||||
'addressFrom': '0xEFE3487358AEF352345456',
|
||||
'tag': 'smth',
|
||||
'tagTo': 'smth',
|
||||
'tagFrom': 'smth',
|
||||
'type': 'deposit',
|
||||
'amount': exchange.parse_number('1.234'),
|
||||
'currency': 'USDT',
|
||||
'status': 'ok',
|
||||
'updated': 1502962946233,
|
||||
'fee': {},
|
||||
}
|
||||
empty_allowed_for = ['address', 'addressTo', 'addressFrom', 'tag', 'tagTo', 'tagFrom'] # below we still do assertion for to/from
|
||||
test_shared_methods.assert_structure(exchange, skipped_properties, method, entry, format, empty_allowed_for)
|
||||
test_shared_methods.assert_timestamp_and_datetime(exchange, skipped_properties, method, entry, now)
|
||||
test_shared_methods.assert_currency_code(exchange, skipped_properties, method, entry, entry['currency'], requested_code)
|
||||
#
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, entry, 'status', ['ok', 'pending', 'failed', 'rejected', 'canceled'])
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, entry, 'type', ['deposit', 'withdrawal'])
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, entry, 'amount', '0')
|
||||
test_shared_methods.assert_fee_structure(exchange, skipped_properties, method, entry, 'fee')
|
||||
if entry['type'] == 'deposit':
|
||||
test_shared_methods.assert_type(exchange, skipped_properties, entry, 'addressFrom', format)
|
||||
else:
|
||||
test_shared_methods.assert_type(exchange, skipped_properties, entry, 'addressTo', format)
|
||||
29
ccxt/test/exchange/base/test_funding_rate_history.py
Normal file
29
ccxt/test/exchange/base/test_funding_rate_history.py
Normal file
@@ -0,0 +1,29 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_funding_rate_history(exchange, skipped_properties, method, entry, symbol):
|
||||
format = {
|
||||
'info': {},
|
||||
'symbol': 'BTC/USDT:USDT',
|
||||
'timestamp': 1638230400000,
|
||||
'datetime': '2021-11-30T00:00:00.000Z',
|
||||
'fundingRate': exchange.parse_number('0.0006'),
|
||||
}
|
||||
test_shared_methods.assert_structure(exchange, skipped_properties, method, entry, format)
|
||||
test_shared_methods.assert_symbol(exchange, skipped_properties, method, entry, 'symbol', symbol)
|
||||
test_shared_methods.assert_timestamp_and_datetime(exchange, skipped_properties, method, entry)
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'fundingRate', '-100')
|
||||
test_shared_methods.assert_less(exchange, skipped_properties, method, entry, 'fundingRate', '100')
|
||||
31
ccxt/test/exchange/base/test_last_price.py
Normal file
31
ccxt/test/exchange/base/test_last_price.py
Normal file
@@ -0,0 +1,31 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_last_price(exchange, skipped_properties, method, entry, symbol):
|
||||
format = {
|
||||
'info': {},
|
||||
'symbol': 'ETH/BTC',
|
||||
'timestamp': 1502962946216,
|
||||
'datetime': '2017-09-01T00:00:00',
|
||||
'price': exchange.parse_number('1.234'),
|
||||
'side': 'buy',
|
||||
}
|
||||
empty_allowed_for = ['timestamp', 'datetime', 'side', 'price'] # binance sometimes provides empty prices for old pairs
|
||||
test_shared_methods.assert_structure(exchange, skipped_properties, method, entry, format, empty_allowed_for)
|
||||
test_shared_methods.assert_timestamp_and_datetime(exchange, skipped_properties, method, entry)
|
||||
#
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'price', '0')
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, entry, 'side', ['buy', 'sell', None])
|
||||
45
ccxt/test/exchange/base/test_ledger_entry.py
Normal file
45
ccxt/test/exchange/base/test_ledger_entry.py
Normal file
@@ -0,0 +1,45 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_ledger_entry(exchange, skipped_properties, method, entry, requested_code, now):
|
||||
format = {
|
||||
'info': {},
|
||||
'id': 'x1234',
|
||||
'currency': 'BTC',
|
||||
'account': 'spot',
|
||||
'referenceId': 'foo',
|
||||
'referenceAccount': 'bar',
|
||||
'status': 'ok',
|
||||
'amount': exchange.parse_number('22'),
|
||||
'before': exchange.parse_number('111'),
|
||||
'after': exchange.parse_number('133'),
|
||||
'fee': {},
|
||||
'direction': 'in',
|
||||
'timestamp': 1638230400000,
|
||||
'datetime': '2021-11-30T00:00:00.000Z',
|
||||
'type': 'deposit',
|
||||
}
|
||||
empty_allowed_for = ['referenceId', 'referenceAccount', 'id']
|
||||
test_shared_methods.assert_structure(exchange, skipped_properties, method, entry, format, empty_allowed_for)
|
||||
test_shared_methods.assert_timestamp_and_datetime(exchange, skipped_properties, method, entry, now)
|
||||
test_shared_methods.assert_currency_code(exchange, skipped_properties, method, entry, entry['currency'], requested_code)
|
||||
#
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, entry, 'direction', ['in', 'out'])
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, entry, 'type', ['trade', 'transaction', 'margin', 'cashback', 'referral', 'transfer', 'fee'])
|
||||
# testSharedMethods.assertInArray (exchange, skippedProperties, method, entry, 'account', ['spot', 'swap', .. ]); # todo
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, entry, 'amount', '0')
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, entry, 'before', '0')
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, entry, 'after', '0')
|
||||
33
ccxt/test/exchange/base/test_leverage_tier.py
Normal file
33
ccxt/test/exchange/base/test_leverage_tier.py
Normal file
@@ -0,0 +1,33 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_leverage_tier(exchange, skipped_properties, method, entry):
|
||||
format = {
|
||||
'tier': exchange.parse_number('1'),
|
||||
'minNotional': exchange.parse_number('0'),
|
||||
'maxNotional': exchange.parse_number('5000'),
|
||||
'maintenanceMarginRate': exchange.parse_number('0.01'),
|
||||
'maxLeverage': exchange.parse_number('25'),
|
||||
'info': {},
|
||||
}
|
||||
empty_allowed_for = ['maintenanceMarginRate']
|
||||
test_shared_methods.assert_structure(exchange, skipped_properties, method, entry, format, empty_allowed_for)
|
||||
#
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, entry, 'tier', '0')
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, entry, 'minNotional', '0')
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, entry, 'maxNotional', '0')
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, entry, 'maxLeverage', '1')
|
||||
test_shared_methods.assert_less_or_equal(exchange, skipped_properties, method, entry, 'maintenanceMarginRate', '1')
|
||||
50
ccxt/test/exchange/base/test_liquidation.py
Normal file
50
ccxt/test/exchange/base/test_liquidation.py
Normal file
@@ -0,0 +1,50 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.base.precise import Precise # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_liquidation(exchange, skipped_properties, method, entry, symbol):
|
||||
format = {
|
||||
'info': {},
|
||||
'symbol': 'ETH/BTC',
|
||||
'contracts': exchange.parse_number('1.234'),
|
||||
'contractSize': exchange.parse_number('1.234'),
|
||||
'price': exchange.parse_number('1.234'),
|
||||
'baseValue': exchange.parse_number('1.234'),
|
||||
'quoteValue': exchange.parse_number('1.234'),
|
||||
'timestamp': 1502962946216,
|
||||
'datetime': '2017-09-01T00:00:00',
|
||||
}
|
||||
# todo: atm, many exchanges fail, so temporarily decrease stict mode
|
||||
empty_allowed_for = ['timestamp', 'datetime', 'quoteValue', 'baseValue', 'previousClose', 'price', 'contractSize', 'contracts']
|
||||
test_shared_methods.assert_structure(exchange, skipped_properties, method, entry, format, empty_allowed_for)
|
||||
test_shared_methods.assert_timestamp_and_datetime(exchange, skipped_properties, method, entry)
|
||||
log_text = test_shared_methods.log_template(exchange, method, entry)
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'contracts', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'contractSize', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'price', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'baseValue', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'quoteValue', '0')
|
||||
contracts = exchange.safe_string(entry, 'contracts')
|
||||
contract_size = exchange.safe_string(entry, 'contractSize')
|
||||
price = exchange.safe_string(entry, 'price')
|
||||
base_value = exchange.safe_string(entry, 'baseValue')
|
||||
if contracts and contract_size:
|
||||
assert Precise.string_eq(base_value, Precise.string_mul(contracts, contract_size)), 'baseValue == contracts * contractSize' + log_text
|
||||
if price:
|
||||
assert Precise.string_eq(base_value, Precise.string_mul(Precise.string_mul(contracts, contract_size), price)), 'quoteValue == contracts * contractSize * price' + log_text
|
||||
# if singular was called, then symbol needs to be asserted
|
||||
if method == 'watchLiquidations' or method == 'fetchLiquidations':
|
||||
test_shared_methods.assert_symbol(exchange, skipped_properties, method, entry, 'symbol', symbol)
|
||||
24
ccxt/test/exchange/base/test_margin_mode.py
Normal file
24
ccxt/test/exchange/base/test_margin_mode.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_margin_mode(exchange, skipped_properties, method, entry):
|
||||
format = {
|
||||
'info': {},
|
||||
'symbol': 'BTC/USDT:USDT',
|
||||
'marginMode': 'cross',
|
||||
}
|
||||
empty_allowed_for = ['symbol']
|
||||
test_shared_methods.assert_structure(exchange, skipped_properties, method, entry, format, empty_allowed_for)
|
||||
35
ccxt/test/exchange/base/test_margin_modification.py
Normal file
35
ccxt/test/exchange/base/test_margin_modification.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_margin_modification(exchange, skipped_properties, method, entry):
|
||||
format = {
|
||||
'info': {},
|
||||
'type': 'add',
|
||||
'amount': exchange.parse_number('0.1'),
|
||||
'total': exchange.parse_number('0.29934828'),
|
||||
'code': 'USDT',
|
||||
'symbol': 'ADA/USDT:USDT',
|
||||
'status': 'ok',
|
||||
}
|
||||
empty_allowed_for = ['status', 'symbol', 'code', 'total', 'amount']
|
||||
test_shared_methods.assert_structure(exchange, skipped_properties, method, entry, format, empty_allowed_for)
|
||||
test_shared_methods.assert_currency_code(exchange, skipped_properties, method, entry, entry['code'])
|
||||
#
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, entry, 'amount', '0')
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, entry, 'total', '0')
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, entry, 'type', ['add', 'reduce', 'set'])
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, entry, 'status', ['ok', 'pending', 'canceled', 'failed'])
|
||||
test_shared_methods.assert_symbol(exchange, skipped_properties, method, entry, 'symbol')
|
||||
241
ccxt/test/exchange/base/test_market.py
Normal file
241
ccxt/test/exchange/base/test_market.py
Normal file
@@ -0,0 +1,241 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.base.precise import Precise # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_market(exchange, skipped_properties, method, market):
|
||||
format = {
|
||||
'id': 'btcusd',
|
||||
'symbol': 'BTC/USD',
|
||||
'base': 'BTC',
|
||||
'quote': 'USD',
|
||||
'taker': exchange.parse_number('0.0011'),
|
||||
'maker': exchange.parse_number('0.0009'),
|
||||
'baseId': 'btc',
|
||||
'quoteId': 'usd',
|
||||
'active': False,
|
||||
'type': 'spot',
|
||||
'linear': False,
|
||||
'inverse': False,
|
||||
'spot': False,
|
||||
'swap': False,
|
||||
'future': False,
|
||||
'option': False,
|
||||
'margin': False,
|
||||
'contract': False,
|
||||
'contractSize': exchange.parse_number('0.001'),
|
||||
'expiry': 1656057600000,
|
||||
'expiryDatetime': '2022-06-24T08:00:00.000Z',
|
||||
'optionType': 'put',
|
||||
'strike': exchange.parse_number('56000'),
|
||||
'settle': 'XYZ',
|
||||
'settleId': 'Xyz',
|
||||
'precision': {
|
||||
'price': exchange.parse_number('0.001'),
|
||||
'amount': exchange.parse_number('0.001'),
|
||||
'cost': exchange.parse_number('0.001'),
|
||||
},
|
||||
'limits': {
|
||||
'amount': {
|
||||
'min': exchange.parse_number('0.01'),
|
||||
'max': exchange.parse_number('1000'),
|
||||
},
|
||||
'price': {
|
||||
'min': exchange.parse_number('0.01'),
|
||||
'max': exchange.parse_number('1000'),
|
||||
},
|
||||
'cost': {
|
||||
'min': exchange.parse_number('0.01'),
|
||||
'max': exchange.parse_number('1000'),
|
||||
},
|
||||
},
|
||||
'marginModes': {
|
||||
'cross': True,
|
||||
'isolated': False,
|
||||
},
|
||||
'info': {},
|
||||
}
|
||||
# temporary: only test QUANTO markets where that prop exists (todo: add in type later)
|
||||
if 'quanto' in market:
|
||||
format['quanto'] = False # whether the market is QUANTO or not
|
||||
# define locals
|
||||
spot = market['spot']
|
||||
contract = market['contract']
|
||||
swap = market['swap']
|
||||
future = market['future']
|
||||
option = market['option']
|
||||
index = exchange.safe_bool(market, 'index') # todo: unify
|
||||
is_index = (index is not None) and index
|
||||
linear = market['linear']
|
||||
inverse = market['inverse']
|
||||
quanto = exchange.safe_bool(market, 'quanto') # todo: unify
|
||||
is_quanto = (quanto is not None) and quanto
|
||||
#
|
||||
empty_allowed_for = ['margin']
|
||||
if not contract:
|
||||
empty_allowed_for.append('contractSize')
|
||||
empty_allowed_for.append('linear')
|
||||
empty_allowed_for.append('inverse')
|
||||
empty_allowed_for.append('quanto')
|
||||
empty_allowed_for.append('settle')
|
||||
empty_allowed_for.append('settleId')
|
||||
if not future and not option:
|
||||
empty_allowed_for.append('expiry')
|
||||
empty_allowed_for.append('expiryDatetime')
|
||||
if not option:
|
||||
empty_allowed_for.append('optionType')
|
||||
empty_allowed_for.append('strike')
|
||||
test_shared_methods.assert_structure(exchange, skipped_properties, method, market, format, empty_allowed_for)
|
||||
test_shared_methods.assert_symbol(exchange, skipped_properties, method, market, 'symbol')
|
||||
log_text = test_shared_methods.log_template(exchange, method, market)
|
||||
# check taker/maker
|
||||
# todo: check not all to be within 0-1.0
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, market, 'taker', '-100')
|
||||
test_shared_methods.assert_less(exchange, skipped_properties, method, market, 'taker', '100')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, market, 'maker', '-100')
|
||||
test_shared_methods.assert_less(exchange, skipped_properties, method, market, 'maker', '100')
|
||||
# validate type
|
||||
valid_types = ['spot', 'margin', 'swap', 'future', 'option', 'index', 'other']
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, market, 'type', valid_types)
|
||||
# validate subTypes
|
||||
valid_sub_types = ['linear', 'inverse', 'quanto', None]
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, market, 'subType', valid_sub_types)
|
||||
# check if 'type' is consistent
|
||||
checked_types = ['spot', 'swap', 'future', 'option']
|
||||
for i in range(0, len(checked_types)):
|
||||
type = checked_types[i]
|
||||
if market[type]:
|
||||
assert type == market['type'], 'market.type (' + market['type'] + ') not equal to "' + type + '"' + log_text
|
||||
# check if 'subType' is consistent
|
||||
if swap or future:
|
||||
checked_sub_types = ['linear', 'inverse']
|
||||
for i in range(0, len(checked_sub_types)):
|
||||
sub_type = checked_sub_types[i]
|
||||
if market[sub_type]:
|
||||
assert sub_type == market['subType'], 'market.subType (' + market['subType'] + ') not equal to "' + sub_type + '"' + log_text
|
||||
# margin check (todo: add margin as mandatory, instead of undefined)
|
||||
if spot:
|
||||
# for spot market, 'margin' can be either true/false or undefined
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, market, 'margin', [True, False, None])
|
||||
else:
|
||||
# otherwise, it must be false or undefined
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, market, 'margin', [False, None])
|
||||
# check mutually exclusive fields
|
||||
if spot:
|
||||
assert not contract and linear is None and inverse is None and not option and not swap and not future, 'for spot market, none of contract/linear/inverse/option/swap/future should be set' + log_text
|
||||
else:
|
||||
# if not spot, any of the below should be true
|
||||
assert contract and (future or swap or option or is_index), 'for non-spot markets, any of (future/swap/option/index) should be set' + log_text
|
||||
contract_size = exchange.safe_string(market, 'contractSize')
|
||||
# contract fields
|
||||
if contract:
|
||||
if is_quanto:
|
||||
assert linear is False, 'linear must be false when "quanto" is true' + log_text
|
||||
assert inverse is False, 'inverse must be false when "quanto" is true' + log_text
|
||||
else:
|
||||
# if false or undefined
|
||||
assert inverse is not None, 'inverse must be defined when "contract" is true' + log_text
|
||||
assert linear is not None, 'linear must be defined when "contract" is true' + log_text
|
||||
assert linear != inverse, 'linear and inverse must not be the same' + log_text
|
||||
# contract size should be defined
|
||||
assert (('contractSize' in skipped_properties) or contract_size is not None), '"contractSize" must be defined when "contract" is true' + log_text
|
||||
# contract size should be above zero
|
||||
assert ('contractSize' in skipped_properties) or Precise.string_gt(contract_size, '0'), '"contractSize" must be > 0 when "contract" is true' + log_text
|
||||
# settle should be defined
|
||||
assert ('settle' in skipped_properties) or (market['settle'] is not None and market['settleId'] is not None), '"settle" & "settleId" must be defined when "contract" is true' + log_text
|
||||
else:
|
||||
# linear & inverse needs to be undefined
|
||||
assert linear is None and inverse is None and quanto is None, 'market linear and inverse (and quanto) must be undefined when "contract" is false' + log_text
|
||||
# contract size should be undefined
|
||||
assert contract_size is None, '"contractSize" must be undefined when "contract" is false' + log_text
|
||||
# settle should be undefined
|
||||
assert (market['settle'] is None) and (market['settleId'] is None), '"settle" must be undefined when "contract" is false' + log_text
|
||||
# future, swap and option should be mutually exclusive
|
||||
if market['future']:
|
||||
assert not market['swap'] and not market['option'] and not is_index, 'market swap and option must be false when "future" is true' + log_text
|
||||
elif market['swap']:
|
||||
assert not market['future'] and not market['option'], 'market future and option must be false when "swap" is true' + log_text
|
||||
elif market['option']:
|
||||
assert not market['future'] and not market['swap'], 'market future and swap must be false when "option" is true' + log_text
|
||||
# check specific fields for options & futures
|
||||
if option or future:
|
||||
# future or option markets need 'expiry' and 'expiryDatetime'
|
||||
assert market['expiry'] is not None, '"expiry" must be defined when "future" is true' + log_text
|
||||
assert market['expiryDatetime'] is not None, '"expiryDatetime" must be defined when "future" is true' + log_text
|
||||
# expiry datetime should be correct
|
||||
iso_string = exchange.iso8601(market['expiry'])
|
||||
assert market['expiryDatetime'] == iso_string, 'expiryDatetime ("' + market['expiryDatetime'] + '") must be equal to expiry in iso8601 format "' + iso_string + '"' + log_text
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, market, 'expiry', '0')
|
||||
if option:
|
||||
# strike should be defined
|
||||
assert (('strike' in skipped_properties) or market['strike'] is not None), '"strike" must be defined when "option" is true' + log_text
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, market, 'strike', '0')
|
||||
# optionType should be defined
|
||||
assert (('optionType' in skipped_properties) or market['optionType'] is not None), '"optionType" must be defined when "option" is true' + log_text
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, market, 'optionType', ['put', 'call'])
|
||||
else:
|
||||
# if not option, then strike and optionType should be undefined
|
||||
assert market['strike'] is None, '"strike" must be undefined when "option" is false' + log_text
|
||||
assert market['optionType'] is None, '"optionType" must be undefined when "option" is false' + log_text
|
||||
elif spot:
|
||||
# otherwise, expiry needs to be undefined
|
||||
assert (market['expiry'] is None) and (market['expiryDatetime'] is None), '"expiry" and "expiryDatetime" must be undefined when it is not future|option market' + log_text
|
||||
# check precisions
|
||||
precision_keys = list(market['precision'].keys())
|
||||
precision_keys_len = len(precision_keys)
|
||||
assert precision_keys_len >= 2, 'precision should have "amount" and "price" keys at least' + log_text
|
||||
for i in range(0, len(precision_keys)):
|
||||
price_or_amount_key = precision_keys[i]
|
||||
# only allow very high priced markets (wher coin costs around 100k) to have a 5$ price tickSize
|
||||
is_exclusive_pair = market['baseId'] == 'BTC'
|
||||
is_non_spot = not spot # such high precision is only allowed in contract markets
|
||||
is_price = price_or_amount_key == 'price'
|
||||
is_tick_size_5 = Precise.string_eq('5', exchange.safe_string(market['precision'], price_or_amount_key))
|
||||
if is_non_spot and is_price and is_exclusive_pair and is_tick_size_5:
|
||||
continue
|
||||
if not ('precision' in skipped_properties):
|
||||
test_shared_methods.check_precision_accuracy(exchange, skipped_properties, method, market['precision'], price_or_amount_key)
|
||||
is_inactive_market = market['active'] is False
|
||||
# check limits
|
||||
limits_keys = list(market['limits'].keys())
|
||||
limits_keys_length = len(limits_keys)
|
||||
assert limits_keys_length >= 3, 'limits should have "amount", "price" and "cost" keys at least' + log_text
|
||||
for i in range(0, len(limits_keys)):
|
||||
key = limits_keys[i]
|
||||
limit_entry = market['limits'][key]
|
||||
if is_inactive_market:
|
||||
continue # check limits
|
||||
if not ('limits' in skipped_properties):
|
||||
# min >= 0
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, limit_entry, 'min', '0')
|
||||
# max >= 0
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, limit_entry, 'max', '0')
|
||||
# max >= min
|
||||
min_string = exchange.safe_string(limit_entry, 'min')
|
||||
if min_string is not None:
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, limit_entry, 'max', min_string)
|
||||
# check currencies
|
||||
test_shared_methods.assert_valid_currency_id_and_code(exchange, skipped_properties, method, market, market['baseId'], market['base'])
|
||||
test_shared_methods.assert_valid_currency_id_and_code(exchange, skipped_properties, method, market, market['quoteId'], market['quote'])
|
||||
test_shared_methods.assert_valid_currency_id_and_code(exchange, skipped_properties, method, market, market['settleId'], market['settle'])
|
||||
# check ts
|
||||
test_shared_methods.assert_timestamp(exchange, skipped_properties, method, market, None, 'created')
|
||||
# margin modes
|
||||
if not ('marginModes' in skipped_properties):
|
||||
margin_modes = exchange.safe_dict(market, 'marginModes') # in future, remove safeDict
|
||||
assert 'cross' in margin_modes, 'marginModes should have "cross" key' + log_text
|
||||
assert 'isolated' in margin_modes, 'marginModes should have "isolated" key' + log_text
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, margin_modes, 'cross', [True, False, None])
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, margin_modes, 'isolated', [True, False, None])
|
||||
33
ccxt/test/exchange/base/test_ohlcv.py
Normal file
33
ccxt/test/exchange/base/test_ohlcv.py
Normal file
@@ -0,0 +1,33 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_ohlcv(exchange, skipped_properties, method, entry, symbol, now):
|
||||
format = [1638230400000, exchange.parse_number('0.123'), exchange.parse_number('0.125'), exchange.parse_number('0.121'), exchange.parse_number('0.122'), exchange.parse_number('123.456')]
|
||||
empty_not_allowed_for = [0, 1, 2, 3, 4, 5]
|
||||
test_shared_methods.assert_structure(exchange, skipped_properties, method, entry, format, empty_not_allowed_for)
|
||||
test_shared_methods.assert_timestamp_and_datetime(exchange, skipped_properties, method, entry, now, 0)
|
||||
log_text = test_shared_methods.log_template(exchange, method, entry)
|
||||
#
|
||||
assert len(entry) >= 6, 'ohlcv array length should be >= 6;' + log_text
|
||||
if not ('roundTimestamp' in skipped_properties):
|
||||
test_shared_methods.assert_round_minute_timestamp(exchange, skipped_properties, method, entry, 0)
|
||||
high = exchange.safe_string(entry, 2)
|
||||
low = exchange.safe_string(entry, 3)
|
||||
test_shared_methods.assert_less_or_equal(exchange, skipped_properties, method, entry, '1', high)
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, entry, '1', low)
|
||||
test_shared_methods.assert_less_or_equal(exchange, skipped_properties, method, entry, '4', high)
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, entry, '4', low)
|
||||
assert (symbol is None) or (isinstance(symbol, str)), 'symbol ' + symbol + ' is incorrect' + log_text # todo: check with standard symbol check
|
||||
32
ccxt/test/exchange/base/test_open_interest.py
Normal file
32
ccxt/test/exchange/base/test_open_interest.py
Normal file
@@ -0,0 +1,32 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_open_interest(exchange, skipped_properties, method, entry):
|
||||
format = {
|
||||
'symbol': 'BTC/USDT',
|
||||
'openInterestAmount': exchange.parse_number('3544581864.598'),
|
||||
'openInterestValue': exchange.parse_number('3544581864.598'),
|
||||
'timestamp': 1649373600000,
|
||||
'datetime': '2022-04-07T23:20:00.000Z',
|
||||
'info': {},
|
||||
}
|
||||
empty_allowed_for = ['symbol', 'timestamp', 'openInterestAmount', 'openInterestValue', 'datetime']
|
||||
test_shared_methods.assert_structure(exchange, skipped_properties, method, entry, format, empty_allowed_for)
|
||||
test_shared_methods.assert_symbol(exchange, skipped_properties, method, entry, 'symbol')
|
||||
test_shared_methods.assert_timestamp_and_datetime(exchange, skipped_properties, method, entry)
|
||||
#
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'openInterestAmount', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'openInterestValue', '0')
|
||||
69
ccxt/test/exchange/base/test_order.py
Normal file
69
ccxt/test/exchange/base/test_order.py
Normal file
@@ -0,0 +1,69 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
from ccxt.test.exchange.base.test_trade import test_trade # noqa E402
|
||||
|
||||
def test_order(exchange, skipped_properties, method, entry, symbol, now):
|
||||
format = {
|
||||
'info': {},
|
||||
'id': '123',
|
||||
'clientOrderId': '1234',
|
||||
'timestamp': 1649373600000,
|
||||
'datetime': '2022-04-07T23:20:00.000Z',
|
||||
'lastTradeTimestamp': 1649373610000,
|
||||
'symbol': 'XYZ/USDT',
|
||||
'type': 'limit',
|
||||
'timeInForce': 'GTC',
|
||||
'postOnly': True,
|
||||
'side': 'sell',
|
||||
'price': exchange.parse_number('1.23456'),
|
||||
'stopPrice': exchange.parse_number('1.1111'),
|
||||
'amount': exchange.parse_number('1.23'),
|
||||
'cost': exchange.parse_number('2.34'),
|
||||
'average': exchange.parse_number('1.234'),
|
||||
'filled': exchange.parse_number('1.23'),
|
||||
'remaining': exchange.parse_number('0.123'),
|
||||
'status': 'ok',
|
||||
'fee': {},
|
||||
'trades': [],
|
||||
}
|
||||
empty_allowed_for = ['clientOrderId', 'stopPrice', 'trades', 'timestamp', 'datetime', 'lastTradeTimestamp', 'average', 'type', 'timeInForce', 'postOnly', 'side', 'price', 'amount', 'cost', 'filled', 'remaining', 'status', 'fee'] # there are exchanges that return only order id, so we don't need to strictly requite all props to be set.
|
||||
test_shared_methods.assert_structure(exchange, skipped_properties, method, entry, format, empty_allowed_for)
|
||||
test_shared_methods.assert_timestamp_and_datetime(exchange, skipped_properties, method, entry, now)
|
||||
#
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, entry, 'timeInForce', ['GTC', 'GTK', 'IOC', 'FOK', 'PO'])
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, entry, 'status', ['open', 'closed', 'canceled'])
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, entry, 'side', ['buy', 'sell'])
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, entry, 'postOnly', [True, False])
|
||||
test_shared_methods.assert_symbol(exchange, skipped_properties, method, entry, 'symbol', symbol)
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'price', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'stopPrice', '0')
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, entry, 'cost', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'average', '0')
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, entry, 'filled', '0')
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, entry, 'remaining', '0')
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, entry, 'amount', '0')
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, entry, 'amount', exchange.safe_string(entry, 'remaining'))
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, entry, 'amount', exchange.safe_string(entry, 'filled'))
|
||||
if not ('trades' in skipped_properties):
|
||||
skipped_new = exchange.deep_extend(skipped_properties, {
|
||||
'timestamp': True,
|
||||
'datetime': True,
|
||||
'side': True,
|
||||
})
|
||||
if entry['trades'] is not None:
|
||||
for i in range(0, len(entry['trades'])):
|
||||
test_trade(exchange, skipped_new, method, entry['trades'][i], symbol, now)
|
||||
test_shared_methods.assert_fee_structure(exchange, skipped_properties, method, entry, 'fee')
|
||||
66
ccxt/test/exchange/base/test_order_book.py
Normal file
66
ccxt/test/exchange/base/test_order_book.py
Normal file
@@ -0,0 +1,66 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.base.precise import Precise # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_order_book(exchange, skipped_properties, method, orderbook, symbol):
|
||||
format = {
|
||||
'symbol': 'ETH/BTC',
|
||||
'asks': [[exchange.parse_number('1.24'), exchange.parse_number('0.453')], [exchange.parse_number('1.25'), exchange.parse_number('0.157')]],
|
||||
'bids': [[exchange.parse_number('1.23'), exchange.parse_number('0.123')], [exchange.parse_number('1.22'), exchange.parse_number('0.543')]],
|
||||
'timestamp': 1504224000000,
|
||||
'datetime': '2017-09-01T00:00:00',
|
||||
'nonce': 134234234,
|
||||
}
|
||||
empty_allowed_for = ['nonce']
|
||||
# turn into copy: https://discord.com/channels/690203284119617602/921046068555313202/1220626834887282728
|
||||
orderbook = exchange.deep_extend({}, orderbook)
|
||||
test_shared_methods.assert_structure(exchange, skipped_properties, method, orderbook, format, empty_allowed_for)
|
||||
test_shared_methods.assert_timestamp_and_datetime(exchange, skipped_properties, method, orderbook)
|
||||
test_shared_methods.assert_symbol(exchange, skipped_properties, method, orderbook, 'symbol', symbol)
|
||||
log_text = test_shared_methods.log_template(exchange, method, orderbook)
|
||||
# todo: check non-emtpy arrays for bids/asks for toptier exchanges
|
||||
bids = orderbook['bids']
|
||||
bids_length = len(bids)
|
||||
for i in range(0, bids_length):
|
||||
current_bid_string = exchange.safe_string(bids[i], 0)
|
||||
if not ('compareToNextItem' in skipped_properties):
|
||||
next_i = i + 1
|
||||
if bids_length > next_i:
|
||||
next_bid_string = exchange.safe_string(bids[next_i], 0)
|
||||
assert Precise.string_gt(current_bid_string, next_bid_string), 'current bid should be > than the next one: ' + current_bid_string + '>' + next_bid_string + log_text
|
||||
if not ('compareToZero' in skipped_properties):
|
||||
# compare price & volume to zero
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, bids[i], 0, '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, bids[i], 1, '0')
|
||||
asks = orderbook['asks']
|
||||
asks_length = len(asks)
|
||||
for i in range(0, asks_length):
|
||||
current_ask_string = exchange.safe_string(asks[i], 0)
|
||||
if not ('compareToNextItem' in skipped_properties):
|
||||
next_i = i + 1
|
||||
if asks_length > next_i:
|
||||
next_ask_string = exchange.safe_string(asks[next_i], 0)
|
||||
assert Precise.string_lt(current_ask_string, next_ask_string), 'current ask should be < than the next one: ' + current_ask_string + '<' + next_ask_string + log_text
|
||||
if not ('compareToZero' in skipped_properties):
|
||||
# compare price & volume to zero
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, asks[i], 0, '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, asks[i], 1, '0')
|
||||
if not ('spread' in skipped_properties):
|
||||
if bids_length and asks_length:
|
||||
first_bid = exchange.safe_string(bids[0], 0)
|
||||
first_ask = exchange.safe_string(asks[0], 0)
|
||||
# check bid-ask spread
|
||||
assert Precise.string_lt(first_bid, first_ask), 'bids[0][0] (' + first_bid + ') should be < than asks[0][0] (' + first_ask + ')' + log_text
|
||||
60
ccxt/test/exchange/base/test_position.py
Normal file
60
ccxt/test/exchange/base/test_position.py
Normal file
@@ -0,0 +1,60 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_position(exchange, skipped_properties, method, entry, symbol, now):
|
||||
format = {
|
||||
'info': {},
|
||||
'symbol': 'XYZ/USDT',
|
||||
'timestamp': 1504224000000,
|
||||
'datetime': '2017-09-01T00:00:00',
|
||||
'initialMargin': exchange.parse_number('1.234'),
|
||||
'initialMarginPercentage': exchange.parse_number('0.123'),
|
||||
'maintenanceMargin': exchange.parse_number('1.234'),
|
||||
'maintenanceMarginPercentage': exchange.parse_number('0.123'),
|
||||
'entryPrice': exchange.parse_number('1.234'),
|
||||
'notional': exchange.parse_number('1.234'),
|
||||
'leverage': exchange.parse_number('1.234'),
|
||||
'unrealizedPnl': exchange.parse_number('1.234'),
|
||||
'contracts': exchange.parse_number('1'),
|
||||
'contractSize': exchange.parse_number('1.234'),
|
||||
'marginRatio': exchange.parse_number('1.234'),
|
||||
'liquidationPrice': exchange.parse_number('1.234'),
|
||||
'markPrice': exchange.parse_number('1.234'),
|
||||
'collateral': exchange.parse_number('1.234'),
|
||||
'marginMode': 'cross',
|
||||
'side': 'long',
|
||||
'percentage': exchange.parse_number('1.234'),
|
||||
}
|
||||
emptyot_allowed_for = ['liquidationPrice', 'initialMargin', 'initialMarginPercentage', 'maintenanceMargin', 'maintenanceMarginPercentage', 'marginRatio']
|
||||
test_shared_methods.assert_structure(exchange, skipped_properties, method, entry, format, emptyot_allowed_for)
|
||||
test_shared_methods.assert_timestamp_and_datetime(exchange, skipped_properties, method, entry, now)
|
||||
test_shared_methods.assert_symbol(exchange, skipped_properties, method, entry, 'symbol', symbol)
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, entry, 'side', ['long', 'short'])
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, entry, 'marginMode', ['cross', 'isolated'])
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'leverage', '0')
|
||||
test_shared_methods.assert_less_or_equal(exchange, skipped_properties, method, entry, 'leverage', '200')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'initialMargin', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'initialMarginPercentage', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'maintenanceMargin', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'maintenanceMarginPercentage', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'entryPrice', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'notional', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'contracts', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'contractSize', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'marginRatio', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'liquidationPrice', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'markPrice', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'collateral', '0')
|
||||
551
ccxt/test/exchange/base/test_shared_methods.py
Normal file
551
ccxt/test/exchange/base/test_shared_methods.py
Normal file
@@ -0,0 +1,551 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.base.decimal_to_precision import DECIMAL_PLACES # noqa E402
|
||||
from ccxt.base.decimal_to_precision import TICK_SIZE # noqa E402
|
||||
import numbers # noqa E402
|
||||
import json # noqa E402
|
||||
from ccxt.base.precise import Precise # noqa E402
|
||||
from ccxt.base.errors import OnMaintenance # noqa E402
|
||||
from ccxt.base.errors import OperationFailed # noqa E402
|
||||
|
||||
def log_template(exchange, method, entry):
|
||||
# there are cases when exchange is undefined (eg. base tests)
|
||||
id = exchange.id if (exchange is not None) else 'undefined'
|
||||
method_string = method if (method is not None) else 'undefined'
|
||||
entry_string = exchange.json(entry) if (exchange is not None) else ''
|
||||
return ' <<< ' + id + ' ' + method_string + ' ::: ' + entry_string + ' >>> '
|
||||
|
||||
|
||||
def is_temporary_failure(e):
|
||||
return (isinstance(e, OperationFailed)) and (not (isinstance(e, OnMaintenance)))
|
||||
|
||||
|
||||
def string_value(value):
|
||||
string_val = None
|
||||
if isinstance(value, str):
|
||||
string_val = value
|
||||
elif value is None:
|
||||
string_val = 'undefined'
|
||||
else:
|
||||
string_val = str(value)
|
||||
return string_val
|
||||
|
||||
|
||||
def assert_type(exchange, skipped_properties, entry, key, format):
|
||||
if key in skipped_properties:
|
||||
return None
|
||||
# because "typeof" string is not transpilable without === 'name', we list them manually at this moment
|
||||
entry_key_val = exchange.safe_value(entry, key)
|
||||
format_key_val = exchange.safe_value(format, key)
|
||||
same_string = (isinstance(entry_key_val, str)) and (isinstance(format_key_val, str))
|
||||
same_numeric = (isinstance(entry_key_val, numbers.Real)) and (isinstance(format_key_val, numbers.Real))
|
||||
same_boolean = ((entry_key_val) or (entry_key_val is False)) and ((format_key_val) or (format_key_val is False))
|
||||
same_array = isinstance(entry_key_val, list) and isinstance(format_key_val, list)
|
||||
same_object = (isinstance(entry_key_val, dict)) and (isinstance(format_key_val, dict))
|
||||
result = (entry_key_val is None) or same_string or same_numeric or same_boolean or same_array or same_object
|
||||
return result
|
||||
|
||||
|
||||
def assert_structure(exchange, skipped_properties, method, entry, format, empty_allowed_for=None, deep=False):
|
||||
log_text = log_template(exchange, method, entry)
|
||||
assert entry is not None, 'item is null/undefined' + log_text
|
||||
# get all expected & predefined keys for this specific item and ensure thos ekeys exist in parsed structure
|
||||
allow_empty_skips = exchange.safe_list(skipped_properties, 'allowNull', [])
|
||||
if empty_allowed_for is not None:
|
||||
empty_allowed_for = concat(empty_allowed_for, allow_empty_skips)
|
||||
if isinstance(format, list):
|
||||
assert isinstance(entry, list), 'entry is not an array' + log_text
|
||||
real_length = len(entry)
|
||||
expected_length = len(format)
|
||||
assert real_length == expected_length, 'entry length is not equal to expected length of ' + str(expected_length) + log_text
|
||||
for i in range(0, len(format)):
|
||||
empty_allowed_for_this_key = (empty_allowed_for is None) or exchange.in_array(i, empty_allowed_for)
|
||||
value = entry[i]
|
||||
if i in skipped_properties:
|
||||
continue
|
||||
# check when:
|
||||
# - it's not inside "allowe empty values" list
|
||||
# - it's not undefined
|
||||
if empty_allowed_for_this_key and (value is None):
|
||||
continue
|
||||
assert value is not None, str(i) + ' index is expected to have a value' + log_text
|
||||
# because of other langs, this is needed for arrays
|
||||
type_assertion = assert_type(exchange, skipped_properties, entry, i, format)
|
||||
assert type_assertion, str(i) + ' index does not have an expected type ' + log_text
|
||||
else:
|
||||
assert isinstance(entry, dict), 'entry is not an object' + log_text
|
||||
keys = list(format.keys())
|
||||
for i in range(0, len(keys)):
|
||||
key = keys[i]
|
||||
if key in skipped_properties:
|
||||
continue
|
||||
assert key in entry, '"' + string_value(key) + '" key is missing from structure' + log_text
|
||||
if key in skipped_properties:
|
||||
continue
|
||||
empty_allowed_for_this_key = (empty_allowed_for is None) or exchange.in_array(key, empty_allowed_for)
|
||||
value = entry[key]
|
||||
# check when:
|
||||
# - it's not inside "allowe empty values" list
|
||||
# - it's not undefined
|
||||
if empty_allowed_for_this_key and (value is None):
|
||||
continue
|
||||
# if it was in needed keys, then it should have value.
|
||||
assert value is not None, '"' + string_value(key) + '" key is expected to have a value' + log_text
|
||||
# add exclusion for info key, as it can be any type
|
||||
if key != 'info':
|
||||
type_assertion = assert_type(exchange, skipped_properties, entry, key, format)
|
||||
assert type_assertion, '"' + string_value(key) + '" key is neither undefined, neither of expected type' + log_text
|
||||
if deep:
|
||||
if isinstance(value, dict):
|
||||
assert_structure(exchange, skipped_properties, method, value, format[key], empty_allowed_for, deep)
|
||||
|
||||
|
||||
def assert_timestamp(exchange, skipped_properties, method, entry, now_to_check=None, key_name_or_index='timestamp', allow_null=True):
|
||||
log_text = log_template(exchange, method, entry)
|
||||
skip_value = exchange.safe_value(skipped_properties, key_name_or_index)
|
||||
if skip_value is not None:
|
||||
return # skipped
|
||||
is_date_time_object = isinstance(key_name_or_index, str)
|
||||
if is_date_time_object:
|
||||
assert (key_name_or_index in entry), 'timestamp key "' + key_name_or_index + '" is missing from structure' + log_text
|
||||
else:
|
||||
# if index was provided (mostly from fetchOHLCV) then we check if it exists, as mandatory
|
||||
assert not (entry[key_name_or_index] is None), 'timestamp index ' + string_value(key_name_or_index) + ' is undefined' + log_text
|
||||
ts = entry[key_name_or_index]
|
||||
assert ts is not None or allow_null, 'timestamp is null' + log_text
|
||||
if ts is not None:
|
||||
assert isinstance(ts, numbers.Real), 'timestamp is not numeric' + log_text
|
||||
assert isinstance(ts, int), 'timestamp should be an integer' + log_text
|
||||
min_ts = 1230940800000 # 03 Jan 2009 - first block
|
||||
max_ts = 2147483648000 # 19 Jan 2038 - max int
|
||||
assert ts > min_ts, 'timestamp is impossible to be before ' + str(min_ts) + ' (03.01.2009)' + log_text # 03 Jan 2009 - first block
|
||||
assert ts < max_ts, 'timestamp more than ' + str(max_ts) + ' (19.01.2038)' + log_text # 19 Jan 2038 - int32 overflows # 7258118400000 -> Jan 1 2200
|
||||
if now_to_check is not None:
|
||||
max_ms_offset = 60000 # 1 min
|
||||
assert ts < now_to_check + max_ms_offset, 'returned item timestamp (' + exchange.iso8601(ts) + ') is ahead of the current time (' + exchange.iso8601(now_to_check) + ')' + log_text
|
||||
|
||||
|
||||
def assert_timestamp_and_datetime(exchange, skipped_properties, method, entry, now_to_check=None, key_name_or_index='timestamp', allow_null=True):
|
||||
log_text = log_template(exchange, method, entry)
|
||||
skip_value = exchange.safe_value(skipped_properties, key_name_or_index)
|
||||
if skip_value is not None:
|
||||
return
|
||||
assert_timestamp(exchange, skipped_properties, method, entry, now_to_check, key_name_or_index)
|
||||
is_date_time_object = isinstance(key_name_or_index, str)
|
||||
# only in case if the entry is a dictionary, thus it must have 'timestamp' & 'datetime' string keys
|
||||
if is_date_time_object:
|
||||
# we also test 'datetime' here because it's certain sibling of 'timestamp'
|
||||
assert ('datetime' in entry), '"datetime" key is missing from structure' + log_text
|
||||
dt = entry['datetime']
|
||||
assert dt is not None or allow_null, 'timestamp is null' + log_text
|
||||
if dt is not None:
|
||||
assert isinstance(dt, str), '"datetime" key does not have a string value' + log_text
|
||||
# there are exceptional cases, like getting microsecond-targeted string '2022-08-08T22:03:19.014680Z', so parsed unified timestamp, which carries only 13 digits (millisecond precision) can not be stringified back to microsecond accuracy, causing the bellow assertion to fail
|
||||
# assert (dt === exchange.iso8601 (entry['timestamp']))
|
||||
# so, we have to compare with millisecond accururacy
|
||||
dt_parsed = exchange.parse8601(dt)
|
||||
ts_ms = entry['timestamp']
|
||||
diff = abs(dt_parsed - ts_ms)
|
||||
if diff >= 500:
|
||||
dt_parsed_string = exchange.iso8601(dt_parsed)
|
||||
dt_entry_string = exchange.iso8601(ts_ms)
|
||||
assert False, 'datetime is not iso8601 of timestamp:' + dt_parsed_string + '(string) != ' + dt_entry_string + '(from ts)' + log_text
|
||||
|
||||
|
||||
def assert_currency_code(exchange, skipped_properties, method, entry, actual_code, expected_code=None, allow_null=True):
|
||||
if ('currency' in skipped_properties) or ('currencyIdAndCode' in skipped_properties):
|
||||
return
|
||||
log_text = log_template(exchange, method, entry)
|
||||
assert actual_code is not None or allow_null, 'currency code is null' + log_text
|
||||
if actual_code is not None:
|
||||
assert isinstance(actual_code, str), 'currency code should be either undefined or a string' + log_text
|
||||
assert (actual_code in exchange.currencies), 'currency code ("' + actual_code + '") should be present in exchange.currencies' + log_text
|
||||
if expected_code is not None:
|
||||
assert actual_code == expected_code, 'currency code in response ("' + string_value(actual_code) + '") should be equal to expected code ("' + string_value(expected_code) + '")' + log_text
|
||||
|
||||
|
||||
def assert_valid_currency_id_and_code(exchange, skipped_properties, method, entry, currency_id, currency_code, allow_null=True):
|
||||
# this is exclusive exceptional key name to be used in `skip-tests.json`, to skip check for currency id and code
|
||||
if ('currency' in skipped_properties) or ('currencyIdAndCode' in skipped_properties):
|
||||
return
|
||||
log_text = log_template(exchange, method, entry)
|
||||
undefined_values = currency_id is None and currency_code is None
|
||||
defined_values = currency_id is not None and currency_code is not None
|
||||
assert undefined_values or defined_values, 'currencyId and currencyCode should be either both defined or both undefined' + log_text
|
||||
assert defined_values or allow_null, 'currency code and id is not defined' + log_text
|
||||
if defined_values:
|
||||
# check by code
|
||||
currency_by_code = exchange.currency(currency_code)
|
||||
assert currency_by_code['id'] == currency_id, 'currencyId "' + string_value(currency_id) + '" does not match currency id from instance: "' + string_value(currency_by_code['id']) + '"' + log_text
|
||||
# check by id
|
||||
currency_by_id = exchange.safe_currency(currency_id)
|
||||
assert currency_by_id['code'] == currency_code, 'currencyCode ' + string_value(currency_code) + ' does not match currency of id: ' + string_value(currency_id) + log_text
|
||||
|
||||
|
||||
def assert_symbol(exchange, skipped_properties, method, entry, key, expected_symbol=None, allow_null=True):
|
||||
if key in skipped_properties:
|
||||
return
|
||||
log_text = log_template(exchange, method, entry)
|
||||
actual_symbol = exchange.safe_string(entry, key)
|
||||
if actual_symbol is not None:
|
||||
assert isinstance(actual_symbol, str), 'symbol should be either undefined or a string' + log_text
|
||||
if expected_symbol is not None:
|
||||
assert actual_symbol == expected_symbol, 'symbol in response ("' + string_value(actual_symbol) + '") should be equal to expected symbol ("' + string_value(expected_symbol) + '")' + log_text
|
||||
defined_values = actual_symbol is not None and expected_symbol is not None
|
||||
assert defined_values or allow_null, 'symbols are not defined' + log_text
|
||||
|
||||
|
||||
def assert_symbol_in_markets(exchange, skipped_properties, method, symbol):
|
||||
log_text = log_template(exchange, method, {})
|
||||
assert (symbol in exchange.markets), 'symbol should be present in exchange.symbols' + log_text
|
||||
|
||||
|
||||
def assert_greater(exchange, skipped_properties, method, entry, key, compare_to, allow_null=True):
|
||||
if key in skipped_properties:
|
||||
return
|
||||
log_text = log_template(exchange, method, entry)
|
||||
value = exchange.safe_string(entry, key)
|
||||
assert value is not None or allow_null, 'value is null' + log_text
|
||||
if value is not None:
|
||||
assert Precise.string_gt(value, compare_to), string_value(key) + ' key (with a value of ' + string_value(value) + ') was expected to be > ' + string_value(compare_to) + log_text
|
||||
|
||||
|
||||
def assert_greater_or_equal(exchange, skipped_properties, method, entry, key, compare_to, allow_null=True):
|
||||
if key in skipped_properties:
|
||||
return
|
||||
log_text = log_template(exchange, method, entry)
|
||||
value = exchange.safe_string(entry, key)
|
||||
assert value is not None or allow_null, 'value is null' + log_text
|
||||
if value is not None and compare_to is not None:
|
||||
assert Precise.string_ge(value, compare_to), string_value(key) + ' key (with a value of ' + string_value(value) + ') was expected to be >= ' + string_value(compare_to) + log_text
|
||||
|
||||
|
||||
def assert_less(exchange, skipped_properties, method, entry, key, compare_to, allow_null=True):
|
||||
if key in skipped_properties:
|
||||
return
|
||||
log_text = log_template(exchange, method, entry)
|
||||
value = exchange.safe_string(entry, key)
|
||||
assert value is not None or allow_null, 'value is null' + log_text
|
||||
if value is not None and compare_to is not None:
|
||||
assert Precise.string_lt(value, compare_to), string_value(key) + ' key (with a value of ' + string_value(value) + ') was expected to be < ' + string_value(compare_to) + log_text
|
||||
|
||||
|
||||
def assert_less_or_equal(exchange, skipped_properties, method, entry, key, compare_to, allow_null=True):
|
||||
if key in skipped_properties:
|
||||
return
|
||||
log_text = log_template(exchange, method, entry)
|
||||
value = exchange.safe_string(entry, key)
|
||||
assert value is not None or allow_null, 'value is null' + log_text
|
||||
if value is not None and compare_to is not None:
|
||||
assert Precise.string_le(value, compare_to), string_value(key) + ' key (with a value of ' + string_value(value) + ') was expected to be <= ' + string_value(compare_to) + log_text
|
||||
|
||||
|
||||
def assert_equal(exchange, skipped_properties, method, entry, key, compare_to, allow_null=True):
|
||||
if key in skipped_properties:
|
||||
return
|
||||
log_text = log_template(exchange, method, entry)
|
||||
value = exchange.safe_string(entry, key)
|
||||
assert value is not None or allow_null, 'value is null' + log_text
|
||||
if value is not None and compare_to is not None:
|
||||
assert Precise.string_eq(value, compare_to), string_value(key) + ' key (with a value of ' + string_value(value) + ') was expected to be equal to ' + string_value(compare_to) + log_text
|
||||
|
||||
|
||||
def assert_non_equal(exchange, skipped_properties, method, entry, key, compare_to, allow_null=True):
|
||||
if key in skipped_properties:
|
||||
return
|
||||
log_text = log_template(exchange, method, entry)
|
||||
value = exchange.safe_string(entry, key)
|
||||
assert value is not None or allow_null, 'value is null' + log_text
|
||||
if value is not None:
|
||||
assert not Precise.string_eq(value, compare_to), string_value(key) + ' key (with a value of ' + string_value(value) + ') was expected not to be equal to ' + string_value(compare_to) + log_text
|
||||
|
||||
|
||||
def assert_in_array(exchange, skipped_properties, method, entry, key, expected_array, allow_null=True):
|
||||
if key in skipped_properties:
|
||||
return
|
||||
log_text = log_template(exchange, method, entry)
|
||||
value = exchange.safe_value(entry, key)
|
||||
assert value is not None or allow_null, 'value is null' + log_text
|
||||
# todo: remove undefined check
|
||||
if value is not None:
|
||||
stingified_array_value = exchange.json(expected_array) # don't use expectedArray.join (','), as it bugs in other languages, if values are bool, undefined or etc..
|
||||
assert exchange.in_array(value, expected_array), '"' + string_value(key) + '" key (value "' + string_value(value) + '") is not from the expected list : [' + stingified_array_value + ']' + log_text
|
||||
|
||||
|
||||
def assert_fee_structure(exchange, skipped_properties, method, entry, key, allow_null=True):
|
||||
log_text = log_template(exchange, method, entry)
|
||||
key_string = string_value(key)
|
||||
if isinstance(key, int):
|
||||
assert isinstance(entry, list), 'fee container is expected to be an array' + log_text
|
||||
assert key < len(entry), 'fee key ' + key_string + ' was expected to be present in entry' + log_text
|
||||
else:
|
||||
assert isinstance(entry, dict), 'fee container is expected to be an object' + log_text
|
||||
assert key in entry, 'fee key "' + key + '" was expected to be present in entry' + log_text
|
||||
fee_object = exchange.safe_value(entry, key)
|
||||
assert fee_object is not None or allow_null, 'fee object is null' + log_text
|
||||
# todo: remove undefined check to make stricter
|
||||
if fee_object is not None:
|
||||
assert 'cost' in fee_object, key_string + ' fee object should contain "cost" key' + log_text
|
||||
if fee_object['cost'] is None:
|
||||
return # todo: remove undefined check to make stricter
|
||||
assert isinstance(fee_object['cost'], numbers.Real), key_string + ' "cost" must be numeric type' + log_text
|
||||
# assertGreaterOrEqual (exchange, skippedProperties, method, feeObject, 'cost', '0'); # fee might be negative in the case of a rebate or reward
|
||||
assert 'currency' in fee_object, '"' + key_string + '" fee object should contain "currency" key' + log_text
|
||||
assert_currency_code(exchange, skipped_properties, method, entry, fee_object['currency'])
|
||||
|
||||
|
||||
def assert_timestamp_order(exchange, method, code_or_symbol, items, ascending=True):
|
||||
for i in range(0, len(items)):
|
||||
if i > 0:
|
||||
current_ts = items[i - 1]['timestamp']
|
||||
next_ts = items[i]['timestamp']
|
||||
if current_ts is not None and next_ts is not None:
|
||||
ascending_or_descending = 'ascending' if ascending else 'descending'
|
||||
comparison = (current_ts <= next_ts) if ascending else (current_ts >= next_ts)
|
||||
assert comparison, exchange.id + ' ' + method + ' ' + string_value(code_or_symbol) + ' must return a ' + ascending_or_descending + ' sorted array of items by timestamp, but ' + str(current_ts) + ' is opposite with its next ' + str(next_ts) + ' ' + exchange.json(items)
|
||||
|
||||
|
||||
def assert_integer(exchange, skipped_properties, method, entry, key, allow_null=True):
|
||||
if key in skipped_properties:
|
||||
return
|
||||
log_text = log_template(exchange, method, entry)
|
||||
if entry is not None:
|
||||
value = exchange.safe_value(entry, key)
|
||||
assert value is not None or allow_null, 'value is null' + log_text
|
||||
if value is not None:
|
||||
is_integer = isinstance(value, int)
|
||||
assert is_integer, '"' + string_value(key) + '" key (value "' + string_value(value) + '") is not an integer' + log_text
|
||||
|
||||
|
||||
def check_precision_accuracy(exchange, skipped_properties, method, entry, key):
|
||||
if key in skipped_properties:
|
||||
return
|
||||
if exchange.is_tick_precision():
|
||||
# TICK_SIZE should be above zero
|
||||
assert_greater(exchange, skipped_properties, method, entry, key, '0')
|
||||
# the below array of integers are inexistent tick-sizes (theoretically technically possible, but not in real-world cases), so their existence in our case indicates to incorrectly implemented tick-sizes, which might mistakenly be implemented with DECIMAL_PLACES, so we throw error
|
||||
decimal_numbers = ['2', '3', '4', '5', '6', '7', '8', '9', '11', '12', '13', '14', '15', '16']
|
||||
for i in range(0, len(decimal_numbers)):
|
||||
num = decimal_numbers[i]
|
||||
num_str = num
|
||||
assert_non_equal(exchange, skipped_properties, method, entry, key, num_str)
|
||||
else:
|
||||
# todo: significant-digits return doubles from `this.parseNumber`, so for now can't assert against integer atm
|
||||
# assertInteger (exchange, skippedProperties, method, entry, key); # should be integer
|
||||
assert_less_or_equal(exchange, skipped_properties, method, entry, key, '18') # should be under 18 decimals
|
||||
assert_greater_or_equal(exchange, skipped_properties, method, entry, key, '-8') # in real-world cases, there would not be less than that
|
||||
|
||||
|
||||
def fetch_best_bid_ask(exchange, method, symbol):
|
||||
log_text = log_template(exchange, method, {})
|
||||
# find out best bid/ask price
|
||||
best_bid = None
|
||||
best_ask = None
|
||||
used_method = None
|
||||
if exchange.has['fetchOrderBook']:
|
||||
used_method = 'fetchOrderBook'
|
||||
orderbook = exchange.fetch_order_book(symbol)
|
||||
bids = exchange.safe_list(orderbook, 'bids')
|
||||
asks = exchange.safe_list(orderbook, 'asks')
|
||||
best_bid_array = exchange.safe_list(bids, 0)
|
||||
best_ask_array = exchange.safe_list(asks, 0)
|
||||
best_bid = exchange.safe_number(best_bid_array, 0)
|
||||
best_ask = exchange.safe_number(best_ask_array, 0)
|
||||
elif exchange.has['fetchBidsAsks']:
|
||||
used_method = 'fetchBidsAsks'
|
||||
tickers = exchange.fetch_bids_asks([symbol])
|
||||
ticker = exchange.safe_dict(tickers, symbol)
|
||||
best_bid = exchange.safe_number(ticker, 'bid')
|
||||
best_ask = exchange.safe_number(ticker, 'ask')
|
||||
elif exchange.has['fetchTicker']:
|
||||
used_method = 'fetchTicker'
|
||||
ticker = exchange.fetch_ticker(symbol)
|
||||
best_bid = exchange.safe_number(ticker, 'bid')
|
||||
best_ask = exchange.safe_number(ticker, 'ask')
|
||||
elif exchange.has['fetchTickers']:
|
||||
used_method = 'fetchTickers'
|
||||
tickers = exchange.fetch_tickers([symbol])
|
||||
ticker = exchange.safe_dict(tickers, symbol)
|
||||
best_bid = exchange.safe_number(ticker, 'bid')
|
||||
best_ask = exchange.safe_number(ticker, 'ask')
|
||||
#
|
||||
assert best_bid is not None and best_ask is not None, log_text + ' ' + exchange.id + ' could not get best bid/ask for ' + symbol + ' using ' + used_method + ' while testing ' + method
|
||||
return [best_bid, best_ask]
|
||||
|
||||
|
||||
def fetch_order(exchange, symbol, order_id, skipped_properties):
|
||||
fetched_order = None
|
||||
original_id = order_id
|
||||
# set 'since' to 5 minute ago for optimal results
|
||||
since_time = exchange.milliseconds() - 1000 * 60 * 5
|
||||
# iterate
|
||||
methods_singular = ['fetchOrder', 'fetchOpenOrder', 'fetchClosedOrder', 'fetchCanceledOrder']
|
||||
for i in range(0, len(methods_singular)):
|
||||
singular_fetch_name = methods_singular[i]
|
||||
if exchange.has[singular_fetch_name]:
|
||||
current_order = exchange[singular_fetch_name](original_id, symbol)
|
||||
# if there is an id inside the order, it means the order was fetched successfully
|
||||
if current_order['id'] == original_id:
|
||||
fetched_order = current_order
|
||||
break
|
||||
#
|
||||
# search through plural methods
|
||||
if fetched_order is None:
|
||||
methods_plural = ['fetchOrders', 'fetchOpenOrders', 'fetchClosedOrders', 'fetchCanceledOrders']
|
||||
for i in range(0, len(methods_plural)):
|
||||
plural_fetch_name = methods_plural[i]
|
||||
if exchange.has[plural_fetch_name]:
|
||||
orders = exchange[plural_fetch_name](symbol, since_time)
|
||||
found = False
|
||||
for j in range(0, len(orders)):
|
||||
current_order = orders[j]
|
||||
if current_order['id'] == original_id:
|
||||
fetched_order = current_order
|
||||
found = True
|
||||
break
|
||||
if found:
|
||||
break
|
||||
return fetched_order
|
||||
|
||||
|
||||
def assert_order_state(exchange, skipped_properties, method, order, asserted_status, strict_check):
|
||||
# note, `strictCheck` is `true` only from "fetchOrder" cases
|
||||
log_text = log_template(exchange, method, order)
|
||||
msg = 'order should be ' + asserted_status + ', but it was not asserted' + log_text
|
||||
filled = exchange.safe_string(order, 'filled')
|
||||
amount = exchange.safe_string(order, 'amount')
|
||||
# shorthand variables
|
||||
status_undefined = (order['status'] is None)
|
||||
status_open = (order['status'] == 'open')
|
||||
status_closed = (order['status'] == 'closed')
|
||||
status_clanceled = (order['status'] == 'canceled')
|
||||
filled_defined = (filled is not None)
|
||||
amount_defined = (amount is not None)
|
||||
condition = None
|
||||
#
|
||||
# ### OPEN STATUS
|
||||
#
|
||||
# if strict check, then 'status' must be 'open' and filled amount should be less then whole order amount
|
||||
strict_open = status_open and (filled_defined and amount_defined and filled < amount)
|
||||
# if non-strict check, then accept & ignore undefined values
|
||||
nonstrict_open = (status_open or status_undefined) and ((not filled_defined or not amount_defined) or Precise.string_lt(filled, amount))
|
||||
# check
|
||||
if asserted_status == 'open':
|
||||
condition = strict_open if strict_check else nonstrict_open
|
||||
assert condition, msg
|
||||
return
|
||||
#
|
||||
# ### CLOSED STATUS
|
||||
#
|
||||
# if strict check, then 'status' must be 'closed' and filled amount should be equal to the whole order amount
|
||||
closed_strict = status_closed and (filled_defined and amount_defined and Precise.string_eq(filled, amount))
|
||||
# if non-strict check, then accept & ignore undefined values
|
||||
closed_non_strict = (status_closed or status_undefined) and ((not filled_defined or not amount_defined) or Precise.string_eq(filled, amount))
|
||||
# check
|
||||
if asserted_status == 'closed':
|
||||
condition = closed_strict if strict_check else closed_non_strict
|
||||
assert condition, msg
|
||||
return
|
||||
#
|
||||
# ### CANCELED STATUS
|
||||
#
|
||||
# if strict check, then 'status' must be 'canceled' and filled amount should be less then whole order amount
|
||||
canceled_strict = status_clanceled and (filled_defined and amount_defined and Precise.string_lt(filled, amount))
|
||||
# if non-strict check, then accept & ignore undefined values
|
||||
canceled_non_strict = (status_clanceled or status_undefined) and ((not filled_defined or not amount_defined) or Precise.string_lt(filled, amount))
|
||||
# check
|
||||
if asserted_status == 'canceled':
|
||||
condition = canceled_strict if strict_check else canceled_non_strict
|
||||
assert condition, msg
|
||||
return
|
||||
#
|
||||
# ### CLOSED_or_CANCELED STATUS
|
||||
#
|
||||
if asserted_status == 'closed_or_canceled':
|
||||
condition = (closed_strict or canceled_strict) if strict_check else (closed_non_strict or canceled_non_strict)
|
||||
assert condition, msg
|
||||
return
|
||||
|
||||
|
||||
def get_active_markets(exchange, include_unknown=True):
|
||||
filtered_active = exchange.filter_by(exchange.markets, 'active', True)
|
||||
if include_unknown:
|
||||
filtered_undefined = exchange.filter_by(exchange.markets, 'active', None)
|
||||
return exchange.array_concat(filtered_active, filtered_undefined)
|
||||
return filtered_active
|
||||
|
||||
|
||||
def remove_proxy_options(exchange, skipped_properties):
|
||||
proxy_url = exchange.check_proxy_url_settings()
|
||||
[http_proxy, https_proxy, socks_proxy] = exchange.check_proxy_settings()
|
||||
# because of bug in transpiled, about `.proxyUrl` being transpiled into `.proxy_url`, we have to use this workaround
|
||||
exchange.set_property(exchange, 'proxyUrl', None)
|
||||
exchange.set_property(exchange, 'proxy_url', None)
|
||||
exchange.set_property(exchange, 'httpProxy', None)
|
||||
exchange.set_property(exchange, 'http_proxy', None)
|
||||
exchange.set_property(exchange, 'httpsProxy', None)
|
||||
exchange.set_property(exchange, 'https_proxy', None)
|
||||
exchange.set_property(exchange, 'socksProxy', None)
|
||||
exchange.set_property(exchange, 'socks_proxy', None)
|
||||
return [proxy_url, http_proxy, https_proxy, socks_proxy]
|
||||
|
||||
|
||||
def set_proxy_options(exchange, skipped_properties, proxy_url, http_proxy, https_proxy, socks_proxy):
|
||||
exchange.proxy_url = proxy_url
|
||||
exchange.http_proxy = http_proxy
|
||||
exchange.https_proxy = https_proxy
|
||||
exchange.socks_proxy = socks_proxy
|
||||
|
||||
|
||||
def concat(a=None, b=None):
|
||||
# we use this method temporarily, because of ast-transpiler issue across langs
|
||||
if a is None:
|
||||
return b
|
||||
elif b is None:
|
||||
return a
|
||||
else:
|
||||
result = []
|
||||
for i in range(0, len(a)):
|
||||
result.append(a[i])
|
||||
for j in range(0, len(b)):
|
||||
result.append(b[j])
|
||||
return result
|
||||
|
||||
|
||||
def assert_non_emtpy_array(exchange, skipped_properties, method, entry, hint=None):
|
||||
log_text = log_template(exchange, method, entry)
|
||||
if hint is not None:
|
||||
log_text = log_text + ' ' + hint
|
||||
assert isinstance(entry, list), 'response is expected to be an array' + log_text
|
||||
if not ('emptyResponse' in skipped_properties):
|
||||
return
|
||||
assert len(entry) > 0, 'response is expected to be a non-empty array' + log_text + ' (add "emptyResponse" in skip-tests.json to skip this check)'
|
||||
|
||||
|
||||
def assert_round_minute_timestamp(exchange, skipped_properties, method, entry, key):
|
||||
if key in skipped_properties:
|
||||
return
|
||||
log_text = log_template(exchange, method, entry)
|
||||
ts = exchange.safe_string(entry, key)
|
||||
assert Precise.string_mod(ts, '60000') == '0', 'timestamp should be a multiple of 60 seconds (1 minute)' + log_text
|
||||
|
||||
|
||||
def deep_equal(a, b):
|
||||
return json.dumps(a) == json.dumps(b)
|
||||
|
||||
|
||||
def assert_deep_equal(exchange, skipped_properties, method, a, b):
|
||||
log_text = log_template(exchange, method, {})
|
||||
assert deep_equal(a, b), 'two dicts do not match: ' + json.dumps(a) + ' != ' + json.dumps(b) + log_text
|
||||
18
ccxt/test/exchange/base/test_status.py
Normal file
18
ccxt/test/exchange/base/test_status.py
Normal file
@@ -0,0 +1,18 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
|
||||
def test_status(exchange, skipped_properties, method, entry, now):
|
||||
assert True, 'testStatus'
|
||||
177
ccxt/test/exchange/base/test_ticker.py
Normal file
177
ccxt/test/exchange/base/test_ticker.py
Normal file
@@ -0,0 +1,177 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.base.precise import Precise # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_ticker(exchange, skipped_properties, method, entry, symbol):
|
||||
format = {
|
||||
'info': {},
|
||||
'symbol': 'ETH/BTC',
|
||||
'timestamp': 1502962946216,
|
||||
'datetime': '2017-09-01T00:00:00',
|
||||
'high': exchange.parse_number('1.234'),
|
||||
'low': exchange.parse_number('1.234'),
|
||||
'bid': exchange.parse_number('1.234'),
|
||||
'bidVolume': exchange.parse_number('1.234'),
|
||||
'ask': exchange.parse_number('1.234'),
|
||||
'askVolume': exchange.parse_number('1.234'),
|
||||
'vwap': exchange.parse_number('1.234'),
|
||||
'open': exchange.parse_number('1.234'),
|
||||
'close': exchange.parse_number('1.234'),
|
||||
'last': exchange.parse_number('1.234'),
|
||||
'previousClose': exchange.parse_number('1.234'),
|
||||
'change': exchange.parse_number('1.234'),
|
||||
'percentage': exchange.parse_number('1.234'),
|
||||
'average': exchange.parse_number('1.234'),
|
||||
'baseVolume': exchange.parse_number('1.234'),
|
||||
'quoteVolume': exchange.parse_number('1.234'),
|
||||
}
|
||||
# todo: atm, many exchanges fail, so temporarily decrease stict mode
|
||||
empty_allowed_for = ['timestamp', 'datetime', 'open', 'high', 'low', 'close', 'last', 'baseVolume', 'quoteVolume', 'previousClose', 'bidVolume', 'askVolume', 'vwap', 'change', 'percentage', 'average']
|
||||
# trick csharp-transpiler for string
|
||||
if not ('BidsAsks' in str(method)):
|
||||
empty_allowed_for.append('bid')
|
||||
empty_allowed_for.append('ask')
|
||||
test_shared_methods.assert_structure(exchange, skipped_properties, method, entry, format, empty_allowed_for)
|
||||
test_shared_methods.assert_timestamp_and_datetime(exchange, skipped_properties, method, entry)
|
||||
log_text = test_shared_methods.log_template(exchange, method, entry)
|
||||
# check market
|
||||
market = None
|
||||
symbol_for_market = symbol if (symbol is not None) else exchange.safe_string(entry, 'symbol')
|
||||
if symbol_for_market is not None and (symbol_for_market in exchange.markets):
|
||||
market = exchange.market(symbol_for_market)
|
||||
# only check "above zero" values if exchange is not supposed to have exotic index markets
|
||||
is_standard_market = (market is not None and exchange.in_array(market['type'], ['spot', 'swap', 'future', 'option']))
|
||||
values_should_be_positive = is_standard_market # || (market === undefined) atm, no check for index markets
|
||||
if values_should_be_positive and not ('positiveValues' in skipped_properties):
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'open', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'high', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'low', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'close', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'ask', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'bid', '0')
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'average', '0')
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, entry, 'vwap', '0')
|
||||
# volume can not be negative
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, entry, 'askVolume', '0')
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, entry, 'bidVolume', '0')
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, entry, 'baseVolume', '0')
|
||||
test_shared_methods.assert_greater_or_equal(exchange, skipped_properties, method, entry, 'quoteVolume', '0')
|
||||
#
|
||||
# close price
|
||||
#
|
||||
last_string = exchange.safe_string(entry, 'last')
|
||||
close_string = exchange.safe_string(entry, 'close')
|
||||
assert ((close_string is None) and (last_string is None)) or Precise.string_eq(last_string, close_string), '`last` != `close`' + log_text
|
||||
open_price = exchange.safe_string(entry, 'open')
|
||||
#
|
||||
# base & quote volumes
|
||||
#
|
||||
base_volume = exchange.omit_zero(exchange.safe_string(entry, 'baseVolume'))
|
||||
quote_volume = exchange.omit_zero(exchange.safe_string(entry, 'quoteVolume'))
|
||||
high = exchange.omit_zero(exchange.safe_string(entry, 'high'))
|
||||
low = exchange.omit_zero(exchange.safe_string(entry, 'low'))
|
||||
open = exchange.omit_zero(exchange.safe_string(entry, 'open'))
|
||||
close = exchange.omit_zero(exchange.safe_string(entry, 'close'))
|
||||
if not ('compareQuoteVolumeBaseVolume' in skipped_properties):
|
||||
# assert (baseVolumeDefined === quoteVolumeDefined, 'baseVolume or quoteVolume should be either both defined or both undefined' + logText); # No, exchanges might not report both values
|
||||
if (base_volume is not None) and (quote_volume is not None) and (high is not None) and (low is not None):
|
||||
base_low = Precise.string_mul(base_volume, low)
|
||||
base_high = Precise.string_mul(base_volume, high)
|
||||
# to avoid abnormal long precision issues (like https://discord.com/channels/690203284119617602/1338828283902689280/1338846071278927912 )
|
||||
m_precision = exchange.safe_dict(market, 'precision')
|
||||
amount_precision = exchange.safe_string(m_precision, 'amount')
|
||||
tolerance = '1.0001'
|
||||
if amount_precision is not None:
|
||||
base_low = Precise.string_mul(Precise.string_sub(base_volume, amount_precision), low)
|
||||
base_high = Precise.string_mul(Precise.string_add(base_volume, amount_precision), high)
|
||||
else:
|
||||
# if nothing found, as an exclusion, just add 0.001%
|
||||
base_low = Precise.string_mul(Precise.string_div(base_volume, tolerance), low)
|
||||
base_high = Precise.string_mul(Precise.string_mul(base_volume, tolerance), high)
|
||||
# because of exchange engines might not rounding numbers propertly, we add some tolerance of calculated 24hr high/low
|
||||
base_low = Precise.string_div(base_low, tolerance)
|
||||
base_high = Precise.string_mul(base_high, tolerance)
|
||||
assert Precise.string_ge(quote_volume, base_low), 'quoteVolume should be => baseVolume * low' + log_text
|
||||
assert Precise.string_le(quote_volume, base_high), 'quoteVolume should be <= baseVolume * high' + log_text
|
||||
# open and close should be between High & Low
|
||||
if high is not None and low is not None and not ('compareOHLC' in skipped_properties):
|
||||
if open is not None:
|
||||
assert Precise.string_ge(open, low), 'open should be >= low' + log_text
|
||||
assert Precise.string_le(open, high), 'open should be <= high' + log_text
|
||||
if close is not None:
|
||||
assert Precise.string_ge(close, low), 'close should be >= low' + log_text
|
||||
assert Precise.string_le(close, high), 'close should be <= high' + log_text
|
||||
#
|
||||
# vwap
|
||||
#
|
||||
vwap = exchange.safe_string(entry, 'vwap')
|
||||
if vwap is not None:
|
||||
# todo
|
||||
# assert (high !== undefined, 'vwap is defined, but high is not' + logText);
|
||||
# assert (low !== undefined, 'vwap is defined, but low is not' + logText);
|
||||
# assert (vwap >= low && vwap <= high)
|
||||
# todo: calc compare
|
||||
assert not values_should_be_positive or Precise.string_ge(vwap, '0'), 'vwap is not greater than zero' + log_text
|
||||
if base_volume is not None:
|
||||
assert quote_volume is not None, 'baseVolume & vwap is defined, but quoteVolume is not' + log_text
|
||||
if quote_volume is not None:
|
||||
assert base_volume is not None, 'quoteVolume & vwap is defined, but baseVolume is not' + log_text
|
||||
ask_string = exchange.safe_string(entry, 'ask')
|
||||
bid_string = exchange.safe_string(entry, 'bid')
|
||||
if (ask_string is not None) and (bid_string is not None) and not ('spread' in skipped_properties):
|
||||
test_shared_methods.assert_greater(exchange, skipped_properties, method, entry, 'ask', exchange.safe_string(entry, 'bid'))
|
||||
percentage = exchange.safe_string(entry, 'percentage')
|
||||
change = exchange.safe_string(entry, 'change')
|
||||
if not ('maxIncrease' in skipped_properties):
|
||||
#
|
||||
# percentage
|
||||
#
|
||||
max_increase = '100' # for testing purposes, if "increased" value is more than 100x, tests should break as implementation might be wrong. however, if something rarest event happens and some coin really had that huge increase, the tests will shortly recover in few hours, as new 24-hour cycle would stabilize tests)
|
||||
if percentage is not None:
|
||||
# - should be above -100 and below MAX
|
||||
assert Precise.string_ge(percentage, '-100'), 'percentage should be above -100% ' + log_text
|
||||
assert Precise.string_le(percentage, Precise.string_mul('+100', max_increase)), 'percentage should be below ' + max_increase + '00% ' + log_text
|
||||
#
|
||||
# change
|
||||
#
|
||||
approx_value = exchange.safe_string_n(entry, ['open', 'close', 'average', 'bid', 'ask', 'vwap', 'previousClose'])
|
||||
if change is not None:
|
||||
# - should be between -price & +price*100
|
||||
assert Precise.string_ge(change, Precise.string_neg(approx_value)), 'change should be above -price ' + log_text
|
||||
assert Precise.string_le(change, Precise.string_mul(approx_value, max_increase)), 'change should be below ' + max_increase + 'x price ' + log_text
|
||||
#
|
||||
# ensure all expected values are defined
|
||||
#
|
||||
if last_string is not None:
|
||||
if percentage is not None:
|
||||
# if one knows 'last' and 'percentage' values, then 'change', 'open' and 'average' values should be determinable.
|
||||
assert open_price is not None and change is not None, 'open & change should be defined if last & percentage are defined' + log_text # todo : add average price too
|
||||
elif change is not None:
|
||||
# if one knows 'last' and 'change' values, then 'percentage', 'open' and 'average' values should be determinable.
|
||||
assert open_price is not None and percentage is not None, 'open & percentage should be defined if last & change are defined' + log_text # todo : add average price too
|
||||
elif open_price is not None:
|
||||
if percentage is not None:
|
||||
# if one knows 'open' and 'percentage' values, then 'last', 'change' and 'average' values should be determinable.
|
||||
assert last_string is not None and change is not None, 'last & change should be defined if open & percentage are defined' + log_text # todo : add average price too
|
||||
elif change is not None:
|
||||
# if one knows 'open' and 'change' values, then 'last', 'percentage' and 'average' values should be determinable.
|
||||
assert last_string is not None and percentage is not None, 'last & percentage should be defined if open & change are defined' + log_text # todo : add average price too
|
||||
#
|
||||
# todo: rethink about this
|
||||
# else {
|
||||
# assert ((askString === undefined) && (bidString === undefined), 'ask & bid should be both defined or both undefined' + logText);
|
||||
# }
|
||||
test_shared_methods.assert_symbol(exchange, skipped_properties, method, entry, 'symbol', symbol)
|
||||
47
ccxt/test/exchange/base/test_trade.py
Normal file
47
ccxt/test/exchange/base/test_trade.py
Normal file
@@ -0,0 +1,47 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_trade(exchange, skipped_properties, method, entry, symbol, now):
|
||||
format = {
|
||||
'info': {},
|
||||
'id': '12345-67890:09876/54321',
|
||||
'timestamp': 1502962946216,
|
||||
'datetime': '2017-08-17 12:42:48.000',
|
||||
'symbol': 'ETH/BTC',
|
||||
'order': '12345-67890:09876/54321',
|
||||
'side': 'buy',
|
||||
'takerOrMaker': 'taker',
|
||||
'price': exchange.parse_number('0.06917684'),
|
||||
'amount': exchange.parse_number('1.5'),
|
||||
'cost': exchange.parse_number('0.10376526'),
|
||||
'fees': [],
|
||||
'fee': {},
|
||||
}
|
||||
# todo: add takeOrMaker as mandatory (atm, many exchanges fail)
|
||||
# removed side because some public endpoints return trades without side
|
||||
empty_allowed_for = ['fees', 'fee', 'symbol', 'order', 'id', 'takerOrMaker']
|
||||
test_shared_methods.assert_structure(exchange, skipped_properties, method, entry, format, empty_allowed_for)
|
||||
test_shared_methods.assert_timestamp_and_datetime(exchange, skipped_properties, method, entry, now)
|
||||
test_shared_methods.assert_symbol(exchange, skipped_properties, method, entry, 'symbol', symbol)
|
||||
#
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, entry, 'side', ['buy', 'sell'])
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, entry, 'takerOrMaker', ['taker', 'maker'])
|
||||
test_shared_methods.assert_fee_structure(exchange, skipped_properties, method, entry, 'fee')
|
||||
if not ('fees' in skipped_properties):
|
||||
# todo: remove undefined check and probably non-empty array check later
|
||||
if entry['fees'] is not None:
|
||||
for i in range(0, len(entry['fees'])):
|
||||
test_shared_methods.assert_fee_structure(exchange, skipped_properties, method, entry['fees'], i)
|
||||
26
ccxt/test/exchange/base/test_trading_fee.py
Normal file
26
ccxt/test/exchange/base/test_trading_fee.py
Normal file
@@ -0,0 +1,26 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_trading_fee(exchange, skipped_properties, method, symbol, entry):
|
||||
format = {
|
||||
'info': {},
|
||||
'symbol': 'ETH/BTC',
|
||||
'maker': exchange.parse_number('0.002'),
|
||||
'taker': exchange.parse_number('0.003'),
|
||||
}
|
||||
empty_allowed_for = ['tierBased', 'percentage', 'symbol']
|
||||
test_shared_methods.assert_structure(exchange, skipped_properties, method, entry, format, empty_allowed_for)
|
||||
test_shared_methods.assert_symbol(exchange, skipped_properties, method, entry, 'symbol', symbol)
|
||||
253
ccxt/test/exchange/sync/test_create_order.py
Normal file
253
ccxt/test/exchange/sync/test_create_order.py
Normal file
@@ -0,0 +1,253 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.base.decimal_to_precision import TICK_SIZE # noqa E402
|
||||
from ccxt.base.decimal_to_precision import TRUNCATE # noqa E402
|
||||
from ccxt.base.decimal_to_precision import ROUND # noqa E402
|
||||
from ccxt.base.decimal_to_precision import ROUND_UP # noqa E402
|
||||
from ccxt.base.decimal_to_precision import decimal_to_precision # noqa E402
|
||||
from ccxt.base.decimal_to_precision import number_to_string # noqa E402
|
||||
from ccxt.base.precise import Precise # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
from ccxt.test.exchange.base import test_order # noqa E402
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
def tco_debug(exchange, symbol, message):
|
||||
# just for debugging purposes
|
||||
debug_create_order = True
|
||||
if debug_create_order:
|
||||
# for c# fix, extra step to convert them to string
|
||||
print(' >>>>> testCreateOrder [', str((exchange['id'])), ' : ', symbol, '] ', message)
|
||||
return True
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
def test_create_order(exchange, skipped_properties, symbol):
|
||||
log_prefix = test_shared_methods.log_template(exchange, 'createOrder', [symbol])
|
||||
assert exchange.has['cancelOrder'] or exchange.has['cancelOrders'] or exchange.has['cancelAllOrders'], log_prefix + ' does not have cancelOrder|cancelOrders|canelAllOrders method, which is needed to make tests for `createOrder` method. Skipping the test...'
|
||||
# pre-define some coefficients, which will be used down below
|
||||
limit_price_safety_multiplier_from_median = 1.045 # todo: when this https://github.com/ccxt/ccxt/issues/22442 is implemented, we'll remove hardcoded value. atm 5% is enough
|
||||
market = exchange.market(symbol)
|
||||
is_swap_future = market['swap'] or market['future']
|
||||
assert exchange.has['fetchBalance'], log_prefix + ' does not have fetchBalance() method, which is needed to make tests for `createOrder` method. Skipping the test...'
|
||||
balance = exchange.fetch_balance()
|
||||
initial_base_balance = balance[market['base']]['free']
|
||||
initial_quote_balance = balance[market['quote']]['free']
|
||||
assert initial_quote_balance is not None, log_prefix + ' - testing account not have balance of' + market['quote'] + ' in fetchBalance() which is required to test'
|
||||
tco_debug(exchange, symbol, 'fetched balance for ' + symbol + ' : ' + str(initial_base_balance) + ' ' + market['base'] + '/' + initial_quote_balance + ' ' + market['quote'])
|
||||
[best_bid, best_ask] = test_shared_methods.fetch_best_bid_ask(exchange, 'createOrder', symbol)
|
||||
# **************** [Scenario 1 - START] **************** #
|
||||
tco_debug(exchange, symbol, '### SCENARIO 1 ###')
|
||||
# create a "limit order" which IS GUARANTEED not to have a fill (i.e. being far from the real price)
|
||||
tco_create_unfillable_order(exchange, market, log_prefix, skipped_properties, best_bid, best_ask, limit_price_safety_multiplier_from_median, 'buy', None)
|
||||
if is_swap_future:
|
||||
# for swap markets, we test sell orders too
|
||||
tco_create_unfillable_order(exchange, market, log_prefix, skipped_properties, best_bid, best_ask, limit_price_safety_multiplier_from_median, 'sell', None)
|
||||
tco_debug(exchange, symbol, '### SCENARIO 1 PASSED ###')
|
||||
# **************** [Scenario 2 - START] **************** #
|
||||
tco_debug(exchange, symbol, '### SCENARIO 2 ###')
|
||||
# create an order which IS GUARANTEED to have a fill (full or partial)
|
||||
tco_create_fillable_order(exchange, market, log_prefix, skipped_properties, best_bid, best_ask, limit_price_safety_multiplier_from_median, 'buy', None)
|
||||
if is_swap_future:
|
||||
# for swap markets, we test sell orders too
|
||||
tco_create_fillable_order(exchange, market, log_prefix, skipped_properties, best_bid, best_ask, limit_price_safety_multiplier_from_median, 'sell', None)
|
||||
tco_debug(exchange, symbol, '### SCENARIO 2 PASSED ###')
|
||||
# **************** [Scenario 3 - START] **************** #
|
||||
return True
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
def tco_create_unfillable_order(exchange, market, log_prefix, skipped_properties, best_bid, best_ask, limit_price_safety_multiplier_from_median, buy_or_sell, predefined_amount=None):
|
||||
try:
|
||||
symbol = market['symbol']
|
||||
minimun_prices = exchange.safe_dict(market['limits'], 'price', {})
|
||||
minimum_price = minimun_prices['min']
|
||||
maximum_price = minimun_prices['max']
|
||||
# below we set limit price, where the order will not be completed.
|
||||
# We do not use the extreme "limits" values for that market, because, even though min purchase amount for BTC/USDT can be 0.01 BTC, it means with 10$ you can buy 1000 BTC, which leads to unrealistic outcome. So, we just use around 5%-10% far price from the current price.
|
||||
limit_buy_price_non_fillable = best_bid / limit_price_safety_multiplier_from_median
|
||||
if minimum_price is not None and limit_buy_price_non_fillable < minimum_price:
|
||||
limit_buy_price_non_fillable = minimum_price
|
||||
limit_sell_price_non_fillable = best_ask * limit_price_safety_multiplier_from_median
|
||||
if maximum_price is not None and limit_sell_price_non_fillable > maximum_price:
|
||||
limit_sell_price_non_fillable = maximum_price
|
||||
created_order = None
|
||||
if buy_or_sell == 'buy':
|
||||
order_amount = tco_get_minimum_amount_for_limit_price(exchange, market, limit_buy_price_non_fillable, predefined_amount)
|
||||
created_order = tco_create_order_safe(exchange, symbol, 'limit', 'buy', order_amount, limit_buy_price_non_fillable, {}, skipped_properties)
|
||||
else:
|
||||
order_amount = tco_get_minimum_amount_for_limit_price(exchange, market, limit_sell_price_non_fillable, predefined_amount)
|
||||
created_order = tco_create_order_safe(exchange, symbol, 'limit', 'sell', order_amount, limit_sell_price_non_fillable, {}, skipped_properties)
|
||||
fetched_order = test_shared_methods.fetch_order(exchange, symbol, created_order['id'], skipped_properties)
|
||||
# test fetched order object
|
||||
if fetched_order is not None:
|
||||
test_order(exchange, skipped_properties, 'createOrder', fetched_order, symbol, exchange.milliseconds())
|
||||
# ensure that order is not filled
|
||||
test_shared_methods.assert_order_state(exchange, skipped_properties, 'createdOrder', created_order, 'open', False)
|
||||
test_shared_methods.assert_order_state(exchange, skipped_properties, 'fetchedOrder', fetched_order, 'open', True)
|
||||
# ensure that order side matches
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, 'createdOrder', created_order, 'side', [None, buy_or_sell])
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, 'fetchedOrder', fetched_order, 'side', [None, buy_or_sell])
|
||||
tco_cancel_order(exchange, symbol, created_order['id'])
|
||||
except Exception as e:
|
||||
raise Error(log_prefix + ' failed for Scenario 1: ' + str(e))
|
||||
return True
|
||||
|
||||
|
||||
def tco_create_fillable_order(exchange, market, log_prefix, skipped_properties, best_bid, best_ask, limit_price_safety_multiplier_from_median, buy_or_sell_string, predefined_amount=None):
|
||||
try:
|
||||
is_swap_future = market['swap'] or market['future']
|
||||
is_buy = (buy_or_sell_string == 'buy')
|
||||
entry_side = 'buy' if is_buy else 'sell'
|
||||
exit_side = 'sell' if is_buy else 'buy'
|
||||
entryorder_price = best_ask * limit_price_safety_multiplier_from_median if is_buy else best_bid / limit_price_safety_multiplier_from_median
|
||||
exitorder_price = best_bid / limit_price_safety_multiplier_from_median if is_buy else best_ask * limit_price_safety_multiplier_from_median # todo revise: (tcoMininumCost (exchange, market) / amountToClose) / limitPriceSafetyMultiplierFromMedian;
|
||||
#
|
||||
#
|
||||
symbol = market['symbol']
|
||||
entry_amount = tco_get_minimum_amount_for_limit_price(exchange, market, entryorder_price)
|
||||
entryorder_filled = tco_create_order_safe(exchange, symbol, 'limit', entry_side, entry_amount, entryorder_price, {}, skipped_properties)
|
||||
# just for case, cancel any possible unfilled amount (though it is not be expected because the order was fillable)
|
||||
tco_try_cancel_order(exchange, symbol, entryorder_filled, skipped_properties)
|
||||
# now, as order is closed/canceled, we can reliably fetch the order information
|
||||
entryorder_fetched = test_shared_methods.fetch_order(exchange, symbol, entryorder_filled['id'], skipped_properties)
|
||||
tco_assert_filled_order(exchange, market, log_prefix, skipped_properties, entryorder_filled, entryorder_fetched, entry_side, entry_amount)
|
||||
#
|
||||
# ### close the traded position ###
|
||||
#
|
||||
amount_to_close = exchange.parse_to_numeric(exchange.safe_string(entryorder_fetched, 'filled'))
|
||||
params = {}
|
||||
# as we want to close position, we should use 'reduceOnly' to ensure we don't open a margined position accidentally, because some exchanges might have automatically enabled margin-mode (on spot) or hedge-mode (on contracts)
|
||||
if is_swap_future:
|
||||
params['reduceOnly'] = True
|
||||
exitorder_filled = tco_create_order_safe(exchange, symbol, 'market', exit_side, amount_to_close, (None if market['spot'] else exitorder_price), params, skipped_properties)
|
||||
exitorder_fetched = test_shared_methods.fetch_order(exchange, symbol, exitorder_filled['id'], skipped_properties)
|
||||
tco_assert_filled_order(exchange, market, log_prefix, skipped_properties, exitorder_filled, exitorder_fetched, exit_side, amount_to_close)
|
||||
except Exception as e:
|
||||
raise Error('failed for Scenario 2: ' + str(e))
|
||||
return True
|
||||
|
||||
|
||||
def tco_assert_filled_order(exchange, market, log_prefix, skipped_properties, created_order, fetched_order, requested_side, requested_amount):
|
||||
# test filled amount
|
||||
precision_amount = exchange.safe_string(market['precision'], 'amount')
|
||||
entryorder_amount_string = exchange.number_to_string(requested_amount)
|
||||
filled_string = exchange.safe_string(fetched_order, 'filled')
|
||||
assert filled_string is not None, log_prefix + ' order should be filled, but it is not. ' + exchange.json(fetched_order)
|
||||
# filled amount should be whithin the expected range i.e. if you buy 100 DOGECOIN and amount-precision is 1,
|
||||
# and also considering possible roundings in implementation, then filled amount should be between 99 and 101
|
||||
max_expected_filled_amount = Precise.string_add(entryorder_amount_string, precision_amount)
|
||||
min_expected_filled_amount = Precise.string_sub(entryorder_amount_string, precision_amount)
|
||||
assert Precise.string_le(filled_string, max_expected_filled_amount), log_prefix + ' filled amount is more than expected, possibly some implementation issue. ' + exchange.json(fetched_order)
|
||||
assert Precise.string_ge(filled_string, min_expected_filled_amount), log_prefix + ' filled amount is less than expected, possibly some implementation issue. ' + exchange.json(fetched_order)
|
||||
# order state should be "closed"
|
||||
test_shared_methods.assert_order_state(exchange, skipped_properties, 'createdOrder', created_order, 'closed', False)
|
||||
test_shared_methods.assert_order_state(exchange, skipped_properties, 'fetchedOrder', fetched_order, 'closed', True)
|
||||
# ensure that order side matches
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, 'createdOrder', created_order, 'side', [None, requested_side])
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, 'fetchedOrder', fetched_order, 'side', [None, requested_side])
|
||||
return True
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
def tco_cancel_order(exchange, symbol, order_id=None):
|
||||
log_prefix = test_shared_methods.log_template(exchange, 'createOrder', [symbol])
|
||||
used_method = ''
|
||||
cancel_result = None
|
||||
if exchange.has['cancelOrder'] and order_id is not None:
|
||||
used_method = 'cancelOrder'
|
||||
cancel_result = exchange.cancel_order(order_id, symbol)
|
||||
elif exchange.has['cancelAllOrders']:
|
||||
used_method = 'cancelAllOrders'
|
||||
cancel_result = exchange.cancel_all_orders(symbol)
|
||||
elif exchange.has['cancelOrders']:
|
||||
raise Error(log_prefix + ' cancelOrders method is not unified yet, coming soon...')
|
||||
tco_debug(exchange, symbol, 'canceled order using ' + used_method + ':' + cancel_result['id'])
|
||||
# todo:
|
||||
# testSharedMethods.assertOrderState (exchange, skippedProperties, 'cancelOrder', cancelResult, 'canceled', false);
|
||||
# testSharedMethods.assertOrderState (exchange, skippedProperties, 'cancelOrder', cancelResult, 'closed', true);
|
||||
return True
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# ----------------------------------------------------------------------------
|
||||
def tco_create_order_safe(exchange, symbol, order_type, side, amount, price=None, params={}, skipped_properties={}):
|
||||
tco_debug(exchange, symbol, 'Executing createOrder ' + order_type + ' ' + side + ' ' + amount + ' ' + price + ' ' + exchange.json(params))
|
||||
order = exchange.create_order(symbol, order_type, side, amount, price, params)
|
||||
try:
|
||||
test_order(exchange, skipped_properties, 'createOrder', order, symbol, int(time.time() * 1000))
|
||||
except Exception as e:
|
||||
if order_type != 'market':
|
||||
# if it was limit order, try to cancel it before exiting the script
|
||||
tco_try_cancel_order(exchange, symbol, order, skipped_properties)
|
||||
raise e
|
||||
return order
|
||||
|
||||
|
||||
def tco_mininum_amount(exchange, market):
|
||||
amount_values = exchange.safe_dict(market['limits'], 'amount', {})
|
||||
amount_min = exchange.safe_number(amount_values, 'min')
|
||||
assert amount_min is not None, exchange.id + ' ' + market['symbol'] + ' can not determine minimum amount for order'
|
||||
return amount_min
|
||||
|
||||
|
||||
def tco_mininum_cost(exchange, market):
|
||||
cost_values = exchange.safe_dict(market['limits'], 'cost', {})
|
||||
cost_min = exchange.safe_number(cost_values, 'min')
|
||||
assert cost_min is not None, exchange.id + ' ' + market['symbol'] + ' can not determine minimum cost for order'
|
||||
return cost_min
|
||||
|
||||
|
||||
def tco_get_minimum_amount_for_limit_price(exchange, market, price, predefined_amount=None):
|
||||
# this method calculates the minimum realistic order amount:
|
||||
# at first it checks the "minimum hardcap limit" (i.e. 7 DOGE), however, if exchange also has "minimum cost" limits,
|
||||
# then we need to calculate the amount using cost, because of price is volatile, today's 7 DOGE cost could be 1$
|
||||
# but "minimum cost" requirement could be 5$ (which translates to 35 DOGE amount)
|
||||
minimum_amount = tco_mininum_amount(exchange, market)
|
||||
minimum_cost = tco_mininum_cost(exchange, market)
|
||||
final_amount = minimum_amount
|
||||
if minimum_cost is not None:
|
||||
if final_amount * price < minimum_cost:
|
||||
final_amount = minimum_cost / price
|
||||
if predefined_amount is not None:
|
||||
final_amount = max(final_amount, predefined_amount)
|
||||
# because it's possible that calculated value might get truncated down in "createOrder" (i.e. 0.129 -> 0.12), we should ensure that final amount * price would bypass minimum cost requirements, by adding the "minimum precision"
|
||||
amount_precision = exchange.safe_number(market['precision'], 'amount')
|
||||
is_tick_size_precision = exchange.precisionMode == 4
|
||||
if amount_precision is None:
|
||||
amount_precision = 1e-15 # todo: revise this for better way in future
|
||||
else:
|
||||
# todo: remove after TICK_SIZE unification
|
||||
if not is_tick_size_precision:
|
||||
amount_precision = 1 / math.pow(10, amount_precision) # this converts DECIMAL_PRECISION into TICK_SIZE
|
||||
final_amount = final_amount + amount_precision
|
||||
final_amount = final_amount * 1.1 # add around 10% to ensure "cost" is enough
|
||||
final_amount = float(exchange.decimal_to_precision(final_amount, 2, market['precision']['amount'], exchange.precisionMode)) # 2 stands for ROUND_UP constant, 0 stands for TRUNCATE
|
||||
return final_amount
|
||||
|
||||
|
||||
def tco_try_cancel_order(exchange, symbol, order, skipped_properties):
|
||||
order_fetched = test_shared_methods.fetch_order(exchange, symbol, order['id'], skipped_properties)
|
||||
needs_cancel = exchange.in_array(order_fetched['status'], ['open', 'pending', None])
|
||||
# if it was not reported as closed/filled, then try to cancel it
|
||||
if needs_cancel:
|
||||
tco_debug(exchange, symbol, 'trying to cancel the remaining amount of partially filled order...')
|
||||
try:
|
||||
tco_cancel_order(exchange, symbol, order['id'])
|
||||
except Exception as e:
|
||||
# order might have been closed/filled already, before 'cancelOrder' call reaches server, so it is tolerable, we don't throw exception
|
||||
tco_debug(exchange, symbol, ' a moment ago order was reported as pending, but could not be cancelled at this moment. Exception message: ' + str(e))
|
||||
else:
|
||||
tco_debug(exchange, symbol, 'order is already closed/filled, no need to cancel it')
|
||||
return True
|
||||
124
ccxt/test/exchange/sync/test_features.py
Normal file
124
ccxt/test/exchange/sync/test_features.py
Normal file
@@ -0,0 +1,124 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_features(exchange, skipped_properties):
|
||||
market_types = ['spot', 'swap', 'future', 'option']
|
||||
sub_types = ['linear', 'inverse']
|
||||
features = exchange.features
|
||||
keys = list(features.keys())
|
||||
for i in range(0, len(keys)):
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, 'features', keys, i, market_types)
|
||||
market_type = keys[i]
|
||||
value = features[market_type]
|
||||
# assert (value !== undefined, 'exchange.features["' + marketType + '"] is undefined, that key should be either absent or have a value');
|
||||
if value is None:
|
||||
continue
|
||||
if market_type == 'spot':
|
||||
test_features_inner(exchange, skipped_properties, value)
|
||||
else:
|
||||
sub_keys = list(value.keys())
|
||||
for j in range(0, len(sub_keys)):
|
||||
sub_key = sub_keys[j]
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, 'features', sub_keys, j, sub_types)
|
||||
sub_value = value[sub_key]
|
||||
# sometimes it might not be available for exchange, eg. future>inverse)
|
||||
if sub_value is not None:
|
||||
test_features_inner(exchange, skipped_properties, sub_value)
|
||||
return True
|
||||
|
||||
|
||||
def test_features_inner(exchange, skipped_properties, feature_obj):
|
||||
format = {
|
||||
'sandbox': False,
|
||||
'createOrder': {
|
||||
'marginMode': False,
|
||||
'triggerPrice': False,
|
||||
'triggerPriceType': {
|
||||
'mark': False,
|
||||
'last': False,
|
||||
'index': False,
|
||||
},
|
||||
'stopLossPrice': False,
|
||||
'takeProfitPrice': False,
|
||||
'attachedStopLossTakeProfit': {
|
||||
'triggerPriceType': {
|
||||
'last': False,
|
||||
'mark': False,
|
||||
'index': False,
|
||||
},
|
||||
'price': False,
|
||||
},
|
||||
'timeInForce': {
|
||||
'GTC': False,
|
||||
'IOC': False,
|
||||
'FOK': False,
|
||||
'PO': False,
|
||||
'GTD': False,
|
||||
},
|
||||
'hedged': False,
|
||||
'trailing': False,
|
||||
},
|
||||
'createOrders': {
|
||||
'max': 5,
|
||||
},
|
||||
'fetchMyTrades': {
|
||||
'marginMode': False,
|
||||
'daysBack': 0,
|
||||
'limit': 0,
|
||||
'untilDays': 0,
|
||||
'symbolRequired': False,
|
||||
},
|
||||
'fetchOrder': {
|
||||
'marginMode': False,
|
||||
'trigger': False,
|
||||
'trailing': False,
|
||||
'symbolRequired': False,
|
||||
},
|
||||
'fetchOpenOrders': {
|
||||
'marginMode': False,
|
||||
'limit': 0,
|
||||
'trigger': False,
|
||||
'trailing': False,
|
||||
'symbolRequired': False,
|
||||
},
|
||||
'fetchOrders': {
|
||||
'marginMode': False,
|
||||
'limit': 0,
|
||||
'daysBack': 0,
|
||||
'untilDays': 0,
|
||||
'trigger': False,
|
||||
'trailing': False,
|
||||
'symbolRequired': False,
|
||||
},
|
||||
'fetchClosedOrders': {
|
||||
'marginMode': False,
|
||||
'limit': 0,
|
||||
'daysBack': 0,
|
||||
'daysBackCanceled': 0,
|
||||
'untilDays': 0,
|
||||
'trigger': False,
|
||||
'trailing': False,
|
||||
'symbolRequired': False,
|
||||
},
|
||||
'fetchOHLCV': {
|
||||
'limit': 0,
|
||||
},
|
||||
}
|
||||
feature_keys = list(feature_obj.keys())
|
||||
all_methods = list(exchange.has.keys())
|
||||
for i in range(0, len(feature_keys)):
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, 'features', feature_keys, i, all_methods)
|
||||
test_shared_methods.assert_structure(exchange, skipped_properties, 'features', feature_obj, format, None, True) # deep structure check
|
||||
24
ccxt/test/exchange/sync/test_fetch_accounts.py
Normal file
24
ccxt/test/exchange/sync/test_fetch_accounts.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_account # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_fetch_accounts(exchange, skipped_properties):
|
||||
method = 'fetchAccounts'
|
||||
accounts = exchange.fetch_accounts()
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, accounts)
|
||||
for i in range(0, len(accounts)):
|
||||
test_account(exchange, skipped_properties, method, accounts[i])
|
||||
return True
|
||||
21
ccxt/test/exchange/sync/test_fetch_balance.py
Normal file
21
ccxt/test/exchange/sync/test_fetch_balance.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_balance # noqa E402
|
||||
|
||||
def test_fetch_balance(exchange, skipped_properties):
|
||||
method = 'fetchBalance'
|
||||
response = exchange.fetch_balance()
|
||||
test_balance(exchange, skipped_properties, method, response)
|
||||
return True
|
||||
24
ccxt/test/exchange/sync/test_fetch_borrow_interest.py
Normal file
24
ccxt/test/exchange/sync/test_fetch_borrow_interest.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_borrow_interest # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_fetch_borrow_interest(exchange, skipped_properties, code, symbol):
|
||||
method = 'fetchBorrowInterest'
|
||||
borrow_interest = exchange.fetch_borrow_interest(code, symbol)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, borrow_interest, code)
|
||||
for i in range(0, len(borrow_interest)):
|
||||
test_borrow_interest(exchange, skipped_properties, method, borrow_interest[i], code, symbol)
|
||||
return True
|
||||
28
ccxt/test/exchange/sync/test_fetch_closed_orders.py
Normal file
28
ccxt/test/exchange/sync/test_fetch_closed_orders.py
Normal file
@@ -0,0 +1,28 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_order # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_fetch_closed_orders(exchange, skipped_properties, symbol):
|
||||
method = 'fetchClosedOrders'
|
||||
orders = exchange.fetch_closed_orders(symbol)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, orders, symbol)
|
||||
now = exchange.milliseconds()
|
||||
for i in range(0, len(orders)):
|
||||
order = orders[i]
|
||||
test_order(exchange, skipped_properties, method, order, symbol, now)
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, order, 'status', ['closed', 'canceled'])
|
||||
test_shared_methods.assert_timestamp_order(exchange, method, symbol, orders)
|
||||
return True
|
||||
73
ccxt/test/exchange/sync/test_fetch_currencies.py
Normal file
73
ccxt/test/exchange/sync/test_fetch_currencies.py
Normal file
@@ -0,0 +1,73 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_currency # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_fetch_currencies(exchange, skipped_properties):
|
||||
method = 'fetchCurrencies'
|
||||
currencies = exchange.fetch_currencies()
|
||||
# todo: try to invent something to avoid undefined undefined, i.e. maybe move into private and force it to have a value
|
||||
num_inactive_currencies = 0
|
||||
max_inactive_currencies_percentage = exchange.safe_integer(skipped_properties, 'maxInactiveCurrenciesPercentage', 50) # no more than X% currencies should be inactive
|
||||
required_active_currencies = ['BTC', 'ETH', 'USDT', 'USDC']
|
||||
features = exchange.features
|
||||
features_spot = exchange.safe_dict(features, 'spot', {})
|
||||
fetch_currencies = exchange.safe_dict(features_spot, 'fetchCurrencies', {})
|
||||
is_fetch_currencies_private = exchange.safe_value(fetch_currencies, 'private', False)
|
||||
if not is_fetch_currencies_private:
|
||||
values = list(currencies.values())
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, values)
|
||||
currencies_length = len(values)
|
||||
# ensure exchange returns enough length of currencies
|
||||
skip_amount = ('amountOfCurrencies' in skipped_properties)
|
||||
assert skip_amount or currencies_length > 5, exchange.id + ' ' + method + ' must return at least several currencies, but it returned ' + str(currencies_length)
|
||||
# allow skipped exchanges
|
||||
skip_active = ('activeCurrenciesQuota' in skipped_properties)
|
||||
skip_major_currency_check = ('activeMajorCurrencies' in skipped_properties)
|
||||
# loop
|
||||
for i in range(0, currencies_length):
|
||||
currency = values[i]
|
||||
test_currency(exchange, skipped_properties, method, currency)
|
||||
# detailed check for deposit/withdraw
|
||||
active = exchange.safe_bool(currency, 'active')
|
||||
if active is False:
|
||||
num_inactive_currencies = num_inactive_currencies + 1
|
||||
# ensure that major currencies are active and enabled for deposit and withdrawal
|
||||
code = exchange.safe_string(currency, 'code', None)
|
||||
withdraw = exchange.safe_bool(currency, 'withdraw')
|
||||
deposit = exchange.safe_bool(currency, 'deposit')
|
||||
if exchange.in_array(code, required_active_currencies):
|
||||
assert skip_major_currency_check or (withdraw and deposit), 'Major currency ' + code + ' should have withdraw and deposit flags enabled'
|
||||
# check at least X% of currencies are active
|
||||
inactive_currencies_percentage = (num_inactive_currencies / currencies_length) * 100
|
||||
assert skip_active or (inactive_currencies_percentage < max_inactive_currencies_percentage), 'Percentage of inactive currencies is too high at ' + str(inactive_currencies_percentage) + '% that is more than the allowed maximum of ' + str(max_inactive_currencies_percentage) + '%'
|
||||
detect_currency_conflicts(exchange, currencies)
|
||||
return True
|
||||
|
||||
|
||||
def detect_currency_conflicts(exchange, currency_values):
|
||||
# detect if there are currencies with different ids for the same code
|
||||
ids = {}
|
||||
keys = list(currency_values.keys())
|
||||
for i in range(0, len(keys)):
|
||||
key = keys[i]
|
||||
currency = currency_values[key]
|
||||
code = currency['code']
|
||||
if not (code in ids):
|
||||
ids[code] = currency['id']
|
||||
else:
|
||||
is_different = ids[code] != currency['id']
|
||||
assert not is_different, exchange.id + ' fetchCurrencies() has different ids for the same code: ' + code + ' ' + ids[code] + ' ' + currency['id']
|
||||
return True
|
||||
26
ccxt/test/exchange/sync/test_fetch_deposit_withdrawals.py
Normal file
26
ccxt/test/exchange/sync/test_fetch_deposit_withdrawals.py
Normal file
@@ -0,0 +1,26 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_deposit_withdrawal # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_fetch_deposit_withdrawals(exchange, skipped_properties, code):
|
||||
method = 'fetchTransactions'
|
||||
transactions = exchange.fetch_transactions(code)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, transactions, code)
|
||||
now = exchange.milliseconds()
|
||||
for i in range(0, len(transactions)):
|
||||
test_deposit_withdrawal(exchange, skipped_properties, method, transactions[i], code, now)
|
||||
test_shared_methods.assert_timestamp_order(exchange, method, code, transactions)
|
||||
return True
|
||||
26
ccxt/test/exchange/sync/test_fetch_deposits.py
Normal file
26
ccxt/test/exchange/sync/test_fetch_deposits.py
Normal file
@@ -0,0 +1,26 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_deposit_withdrawal # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_fetch_deposits(exchange, skipped_properties, code):
|
||||
method = 'fetchDeposits'
|
||||
transactions = exchange.fetch_deposits(code)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, transactions, code)
|
||||
now = exchange.milliseconds()
|
||||
for i in range(0, len(transactions)):
|
||||
test_deposit_withdrawal(exchange, skipped_properties, method, transactions[i], code, now)
|
||||
test_shared_methods.assert_timestamp_order(exchange, method, code, transactions)
|
||||
return True
|
||||
25
ccxt/test/exchange/sync/test_fetch_funding_rate_history.py
Normal file
25
ccxt/test/exchange/sync/test_fetch_funding_rate_history.py
Normal file
@@ -0,0 +1,25 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_funding_rate_history # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_fetch_funding_rate_history(exchange, skipped_properties, symbol):
|
||||
method = 'fetchFundingRateHistory'
|
||||
funding_rates_history = exchange.fetch_funding_rate_history(symbol)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, funding_rates_history, symbol)
|
||||
for i in range(0, len(funding_rates_history)):
|
||||
test_funding_rate_history(exchange, skipped_properties, method, funding_rates_history[i], symbol)
|
||||
test_shared_methods.assert_timestamp_order(exchange, method, symbol, funding_rates_history)
|
||||
return True
|
||||
21
ccxt/test/exchange/sync/test_fetch_l2_order_book.py
Normal file
21
ccxt/test/exchange/sync/test_fetch_l2_order_book.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_order_book # noqa E402
|
||||
|
||||
def test_fetch_l2_order_book(exchange, skipped_properties, symbol):
|
||||
method = 'fetchL2OrderBook'
|
||||
order_book = exchange.fetch_l2_order_book(symbol)
|
||||
test_order_book(exchange, skipped_properties, method, order_book, symbol)
|
||||
return True
|
||||
37
ccxt/test/exchange/sync/test_fetch_last_prices.py
Normal file
37
ccxt/test/exchange/sync/test_fetch_last_prices.py
Normal file
@@ -0,0 +1,37 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_last_price # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_fetch_last_prices(exchange, skipped_properties, symbol):
|
||||
method = 'fetchLastprices'
|
||||
# log ('fetching all tickers at once...')
|
||||
response = None
|
||||
checked_symbol = None
|
||||
try:
|
||||
response = exchange.fetch_last_prices()
|
||||
except Exception as e:
|
||||
response = exchange.fetch_last_prices([symbol])
|
||||
checked_symbol = symbol
|
||||
assert isinstance(response, dict), exchange.id + ' ' + method + ' ' + checked_symbol + ' must return an object. ' + exchange.json(response)
|
||||
values = list(response.values())
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, values, checked_symbol)
|
||||
at_least_one_passed = False
|
||||
for i in range(0, len(values)):
|
||||
# todo: symbol check here
|
||||
test_last_price(exchange, skipped_properties, method, values[i], checked_symbol)
|
||||
at_least_one_passed = at_least_one_passed or (exchange.safe_number(values[i], 'price') > 0)
|
||||
assert at_least_one_passed, exchange.id + ' ' + method + ' ' + checked_symbol + ' at least one symbol should pass the test'
|
||||
return True
|
||||
26
ccxt/test/exchange/sync/test_fetch_ledger.py
Normal file
26
ccxt/test/exchange/sync/test_fetch_ledger.py
Normal file
@@ -0,0 +1,26 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_ledger_entry # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_fetch_ledger(exchange, skipped_properties, code):
|
||||
method = 'fetchLedger'
|
||||
items = exchange.fetch_ledger(code)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, items, code)
|
||||
now = exchange.milliseconds()
|
||||
for i in range(0, len(items)):
|
||||
test_ledger_entry(exchange, skipped_properties, method, items[i], code, now)
|
||||
test_shared_methods.assert_timestamp_order(exchange, method, code, items)
|
||||
return True
|
||||
29
ccxt/test/exchange/sync/test_fetch_ledger_entry.py
Normal file
29
ccxt/test/exchange/sync/test_fetch_ledger_entry.py
Normal file
@@ -0,0 +1,29 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_ledger_entry # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_fetch_ledger_entry(exchange, skipped_properties, code):
|
||||
method = 'fetchLedgerEntry'
|
||||
items = exchange.fetch_ledger(code)
|
||||
length = len(items)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, items, code)
|
||||
if length > 0:
|
||||
first_item = items[0]
|
||||
id = first_item['id']
|
||||
item = exchange.fetch_ledger_entry(id)
|
||||
now = exchange.milliseconds()
|
||||
test_ledger_entry(exchange, skipped_properties, method, item, code, now)
|
||||
return True
|
||||
34
ccxt/test/exchange/sync/test_fetch_leverage_tiers.py
Normal file
34
ccxt/test/exchange/sync/test_fetch_leverage_tiers.py
Normal file
@@ -0,0 +1,34 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_leverage_tier # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_fetch_leverage_tiers(exchange, skipped_properties, symbol):
|
||||
method = 'fetchLeverageTiers'
|
||||
tiers = exchange.fetch_leverage_tiers(['symbol'])
|
||||
# const format = {
|
||||
# 'RAY/USDT': [
|
||||
# {},
|
||||
# ],
|
||||
# };
|
||||
assert isinstance(tiers, dict), exchange.id + ' ' + method + ' ' + symbol + ' must return an object. ' + exchange.json(tiers)
|
||||
tier_keys = list(tiers.keys())
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, tier_keys, symbol)
|
||||
for i in range(0, len(tier_keys)):
|
||||
tiers_for_symbol = tiers[tier_keys[i]]
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, tiers_for_symbol, symbol)
|
||||
for j in range(0, len(tiers_for_symbol)):
|
||||
test_leverage_tier(exchange, skipped_properties, method, tiers_for_symbol[j])
|
||||
return True
|
||||
28
ccxt/test/exchange/sync/test_fetch_liquidations.py
Normal file
28
ccxt/test/exchange/sync/test_fetch_liquidations.py
Normal file
@@ -0,0 +1,28 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
from ccxt.test.exchange.base import test_liquidation # noqa E402
|
||||
|
||||
def test_fetch_liquidations(exchange, skipped_properties, code):
|
||||
method = 'fetchLiquidations'
|
||||
if not exchange.has['fetchLiquidations']:
|
||||
return True
|
||||
items = exchange.fetch_liquidations(code)
|
||||
assert isinstance(items, list), exchange.id + ' ' + method + ' ' + code + ' must return an array. ' + exchange.json(items)
|
||||
# const now = exchange.milliseconds ();
|
||||
for i in range(0, len(items)):
|
||||
test_liquidation(exchange, skipped_properties, method, items[i], code)
|
||||
test_shared_methods.assert_timestamp_order(exchange, method, code, items)
|
||||
return True
|
||||
21
ccxt/test/exchange/sync/test_fetch_margin_mode.py
Normal file
21
ccxt/test/exchange/sync/test_fetch_margin_mode.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_margin_mode # noqa E402
|
||||
|
||||
def test_fetch_margin_mode(exchange, skipped_properties, symbol):
|
||||
method = 'fetchMarginMode'
|
||||
margin_mode = exchange.fetch_margin_mode(symbol)
|
||||
test_margin_mode(exchange, skipped_properties, method, margin_mode)
|
||||
return True
|
||||
28
ccxt/test/exchange/sync/test_fetch_margin_modes.py
Normal file
28
ccxt/test/exchange/sync/test_fetch_margin_modes.py
Normal file
@@ -0,0 +1,28 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_margin_mode # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_fetch_margin_modes(exchange, skipped_properties, symbol):
|
||||
method = 'fetchMarginModes'
|
||||
margin_modes = exchange.fetch_margin_modes(['symbol'])
|
||||
assert isinstance(margin_modes, dict), exchange.id + ' ' + method + ' ' + symbol + ' must return an object. ' + exchange.json(margin_modes)
|
||||
margin_mode_keys = list(margin_modes.keys())
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, margin_modes, symbol)
|
||||
for i in range(0, len(margin_mode_keys)):
|
||||
margin_mode = margin_modes[margin_mode_keys[i]]
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, margin_mode, symbol)
|
||||
test_margin_mode(exchange, skipped_properties, method, margin_mode)
|
||||
return True
|
||||
24
ccxt/test/exchange/sync/test_fetch_market_leverage_tiers.py
Normal file
24
ccxt/test/exchange/sync/test_fetch_market_leverage_tiers.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_leverage_tier # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_fetch_market_leverage_tiers(exchange, skipped_properties, symbol):
|
||||
method = 'fetchMarketLeverageTiers'
|
||||
tiers = exchange.fetch_market_leverage_tiers(symbol)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, tiers, symbol)
|
||||
for j in range(0, len(tiers)):
|
||||
test_leverage_tier(exchange, skipped_properties, method, tiers[j])
|
||||
return True
|
||||
41
ccxt/test/exchange/sync/test_fetch_markets.py
Normal file
41
ccxt/test/exchange/sync/test_fetch_markets.py
Normal file
@@ -0,0 +1,41 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_market # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_fetch_markets(exchange, skipped_properties):
|
||||
method = 'fetchMarkets'
|
||||
markets = exchange.fetch_markets()
|
||||
assert isinstance(markets, dict), exchange.id + ' ' + method + ' must return an object. ' + exchange.json(markets)
|
||||
market_values = list(markets.values())
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, market_values)
|
||||
for i in range(0, len(market_values)):
|
||||
test_market(exchange, skipped_properties, method, market_values[i])
|
||||
detect_market_conflicts(exchange, markets)
|
||||
return True
|
||||
|
||||
|
||||
def detect_market_conflicts(exchange, market_values):
|
||||
# detect if there are markets with different ids for the same symbol
|
||||
ids = {}
|
||||
for i in range(0, len(market_values)):
|
||||
market = market_values[i]
|
||||
symbol = market['symbol']
|
||||
if not (symbol in ids):
|
||||
ids[symbol] = market['id']
|
||||
else:
|
||||
is_different = ids[symbol] != market['id']
|
||||
assert not is_different, exchange.id + ' fetchMarkets() has different ids for the same symbol: ' + symbol + ' ' + ids[symbol] + ' ' + market['id']
|
||||
return True
|
||||
28
ccxt/test/exchange/sync/test_fetch_my_liquidations.py
Normal file
28
ccxt/test/exchange/sync/test_fetch_my_liquidations.py
Normal file
@@ -0,0 +1,28 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
from ccxt.test.exchange.base import test_liquidation # noqa E402
|
||||
|
||||
def test_fetch_my_liquidations(exchange, skipped_properties, code):
|
||||
method = 'fetchMyLiquidations'
|
||||
if not exchange.has['fetchMyLiquidations']:
|
||||
return True
|
||||
items = exchange.fetch_my_liquidations(code)
|
||||
assert isinstance(items, list), exchange.id + ' ' + method + ' ' + code + ' must return an array. ' + exchange.json(items)
|
||||
# const now = exchange.milliseconds ();
|
||||
for i in range(0, len(items)):
|
||||
test_liquidation(exchange, skipped_properties, method, items[i], code)
|
||||
test_shared_methods.assert_timestamp_order(exchange, method, code, items)
|
||||
return True
|
||||
26
ccxt/test/exchange/sync/test_fetch_my_trades.py
Normal file
26
ccxt/test/exchange/sync/test_fetch_my_trades.py
Normal file
@@ -0,0 +1,26 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
from ccxt.test.exchange.base import test_trade # noqa E402
|
||||
|
||||
def test_fetch_my_trades(exchange, skipped_properties, symbol):
|
||||
method = 'fetchMyTrades'
|
||||
trades = exchange.fetch_my_trades(symbol)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, trades, symbol)
|
||||
now = exchange.milliseconds()
|
||||
for i in range(0, len(trades)):
|
||||
test_trade(exchange, skipped_properties, method, trades[i], symbol, now)
|
||||
test_shared_methods.assert_timestamp_order(exchange, method, symbol, trades)
|
||||
return True
|
||||
35
ccxt/test/exchange/sync/test_fetch_ohlcv.py
Normal file
35
ccxt/test/exchange/sync/test_fetch_ohlcv.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_ohlcv # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_fetch_ohlcv(exchange, skipped_properties, symbol):
|
||||
method = 'fetchOHLCV'
|
||||
timeframe_keys = list(exchange.timeframes.keys())
|
||||
assert len(timeframe_keys), exchange.id + ' ' + method + ' - no timeframes found'
|
||||
# prefer 1m timeframe if available, otherwise return the first one
|
||||
chosen_timeframe_key = '1m'
|
||||
if not exchange.in_array(chosen_timeframe_key, timeframe_keys):
|
||||
chosen_timeframe_key = timeframe_keys[0]
|
||||
limit = 10
|
||||
duration = exchange.parse_timeframe(chosen_timeframe_key)
|
||||
since = exchange.milliseconds() - duration * limit * 1000 - 1000
|
||||
ohlcvs = exchange.fetch_ohlcv(symbol, chosen_timeframe_key, since, limit)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, ohlcvs, symbol)
|
||||
now = exchange.milliseconds()
|
||||
for i in range(0, len(ohlcvs)):
|
||||
test_ohlcv(exchange, skipped_properties, method, ohlcvs[i], symbol, now)
|
||||
# todo: sorted timestamps check
|
||||
return True
|
||||
24
ccxt/test/exchange/sync/test_fetch_open_interest_history.py
Normal file
24
ccxt/test/exchange/sync/test_fetch_open_interest_history.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_open_interest # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_fetch_open_interest_history(exchange, skipped_properties, symbol):
|
||||
method = 'fetchOpenInterestHistory'
|
||||
open_interest_history = exchange.fetch_open_interest_history(symbol)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, open_interest_history, symbol)
|
||||
for i in range(0, len(open_interest_history)):
|
||||
test_open_interest(exchange, skipped_properties, method, open_interest_history[i])
|
||||
return True
|
||||
28
ccxt/test/exchange/sync/test_fetch_open_orders.py
Normal file
28
ccxt/test/exchange/sync/test_fetch_open_orders.py
Normal file
@@ -0,0 +1,28 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_order # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_fetch_open_orders(exchange, skipped_properties, symbol):
|
||||
method = 'fetchOpenOrders'
|
||||
orders = exchange.fetch_open_orders(symbol)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, orders, symbol)
|
||||
now = exchange.milliseconds()
|
||||
for i in range(0, len(orders)):
|
||||
order = orders[i]
|
||||
test_order(exchange, skipped_properties, method, order, symbol, now)
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, order, 'status', ['open'])
|
||||
test_shared_methods.assert_timestamp_order(exchange, method, symbol, orders)
|
||||
return True
|
||||
21
ccxt/test/exchange/sync/test_fetch_order_book.py
Normal file
21
ccxt/test/exchange/sync/test_fetch_order_book.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_order_book # noqa E402
|
||||
|
||||
def test_fetch_order_book(exchange, skipped_properties, symbol):
|
||||
method = 'fetchOrderBook'
|
||||
orderbook = exchange.fetch_order_book(symbol)
|
||||
test_order_book(exchange, skipped_properties, method, orderbook, symbol)
|
||||
return True
|
||||
27
ccxt/test/exchange/sync/test_fetch_order_books.py
Normal file
27
ccxt/test/exchange/sync/test_fetch_order_books.py
Normal file
@@ -0,0 +1,27 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_order_book # noqa E402
|
||||
|
||||
def test_fetch_order_books(exchange, skipped_properties):
|
||||
method = 'fetchOrderBooks'
|
||||
symbol = exchange.symbols[0]
|
||||
order_books = exchange.fetch_order_books([symbol])
|
||||
assert isinstance(order_books, dict), exchange.id + ' ' + method + ' must return an object. ' + exchange.json(order_books)
|
||||
order_book_keys = list(order_books.keys())
|
||||
assert len(order_book_keys), exchange.id + ' ' + method + ' returned 0 length data'
|
||||
for i in range(0, len(order_book_keys)):
|
||||
symbol_inner = order_book_keys[i]
|
||||
test_order_book(exchange, skipped_properties, method, order_books[symbol_inner], symbol_inner)
|
||||
return True
|
||||
27
ccxt/test/exchange/sync/test_fetch_orders.py
Normal file
27
ccxt/test/exchange/sync/test_fetch_orders.py
Normal file
@@ -0,0 +1,27 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_order # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_fetch_orders(exchange, skipped_properties, symbol):
|
||||
method = 'fetchOrders'
|
||||
orders = exchange.fetch_orders(symbol)
|
||||
assert isinstance(orders, list), exchange.id + ' ' + method + ' must return an array, returned ' + exchange.json(orders)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, orders, symbol)
|
||||
now = exchange.milliseconds()
|
||||
for i in range(0, len(orders)):
|
||||
test_order(exchange, skipped_properties, method, orders[i], symbol, now)
|
||||
test_shared_methods.assert_timestamp_order(exchange, method, symbol, orders)
|
||||
return True
|
||||
35
ccxt/test/exchange/sync/test_fetch_positions.py
Normal file
35
ccxt/test/exchange/sync/test_fetch_positions.py
Normal file
@@ -0,0 +1,35 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_position # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_fetch_positions(exchange, skipped_properties, symbol):
|
||||
method = 'fetchPositions'
|
||||
now = exchange.milliseconds()
|
||||
# without symbol
|
||||
positions = exchange.fetch_positions()
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, positions, symbol)
|
||||
for i in range(0, len(positions)):
|
||||
test_position(exchange, skipped_properties, method, positions[i], None, now)
|
||||
# testSharedMethods.assertTimestampOrder (exchange, method, undefined, positions); # currently order of positions does not make sense
|
||||
# with symbol
|
||||
positions_for_symbol = exchange.fetch_positions([symbol])
|
||||
assert isinstance(positions_for_symbol, list), exchange.id + ' ' + method + ' must return an array, returned ' + exchange.json(positions_for_symbol)
|
||||
positions_for_symbol_length = len(positions_for_symbol)
|
||||
assert positions_for_symbol_length <= 4, exchange.id + ' ' + method + ' positions length for particular symbol should be less than 4, returned ' + exchange.json(positions_for_symbol)
|
||||
for i in range(0, len(positions_for_symbol)):
|
||||
test_position(exchange, skipped_properties, method, positions_for_symbol[i], symbol, now)
|
||||
# testSharedMethods.assertTimestampOrder (exchange, method, symbol, positionsForSymbol);
|
||||
return True
|
||||
21
ccxt/test/exchange/sync/test_fetch_status.py
Normal file
21
ccxt/test/exchange/sync/test_fetch_status.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_status # noqa E402
|
||||
|
||||
def test_fetch_status(exchange, skipped_properties):
|
||||
method = 'fetchStatus'
|
||||
status = exchange.fetch_status()
|
||||
test_status(exchange, skipped_properties, method, status, exchange.milliseconds())
|
||||
return True
|
||||
21
ccxt/test/exchange/sync/test_fetch_ticker.py
Normal file
21
ccxt/test/exchange/sync/test_fetch_ticker.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_ticker # noqa E402
|
||||
|
||||
def test_fetch_ticker(exchange, skipped_properties, symbol):
|
||||
method = 'fetchTicker'
|
||||
ticker = exchange.fetch_ticker(symbol)
|
||||
test_ticker(exchange, skipped_properties, method, ticker, symbol)
|
||||
return True
|
||||
58
ccxt/test/exchange/sync/test_fetch_tickers.py
Normal file
58
ccxt/test/exchange/sync/test_fetch_tickers.py
Normal file
@@ -0,0 +1,58 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_ticker # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_fetch_tickers(exchange, skipped_properties, symbol):
|
||||
without_symbol = test_fetch_tickers_helper(exchange, skipped_properties, None)
|
||||
with_symbol = test_fetch_tickers_helper(exchange, skipped_properties, [symbol])
|
||||
results = asyncio.gather(*[without_symbol, with_symbol])
|
||||
test_fetch_tickers_amounts(exchange, skipped_properties, results[0])
|
||||
return results
|
||||
|
||||
|
||||
def test_fetch_tickers_helper(exchange, skipped_properties, arg_symbols, arg_params={}):
|
||||
method = 'fetchTickers'
|
||||
response = exchange.fetch_tickers(arg_symbols, arg_params)
|
||||
assert isinstance(response, dict), exchange.id + ' ' + method + ' ' + exchange.json(arg_symbols) + ' must return an object. ' + exchange.json(response)
|
||||
values = list(response.values())
|
||||
checked_symbol = None
|
||||
if arg_symbols is not None and len(arg_symbols) == 1:
|
||||
checked_symbol = arg_symbols[0]
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, values, checked_symbol)
|
||||
for i in range(0, len(values)):
|
||||
# todo: symbol check here
|
||||
ticker = values[i]
|
||||
test_ticker(exchange, skipped_properties, method, ticker, checked_symbol)
|
||||
return response
|
||||
|
||||
|
||||
def test_fetch_tickers_amounts(exchange, skipped_properties, tickers):
|
||||
tickers_values = list(tickers.values())
|
||||
if not ('checkActiveSymbols' in skipped_properties):
|
||||
#
|
||||
# ensure all "active" symbols have tickers
|
||||
#
|
||||
non_inactive_markets = test_shared_methods.get_active_markets(exchange)
|
||||
not_inactive_symbols_length = len(non_inactive_markets)
|
||||
obtained_tickers_length = len(tickers_values)
|
||||
min_ratio = 0.99 # 1.0 - 0.01 = 0.99, hardcoded to avoid C# transpiler type casting issues
|
||||
assert obtained_tickers_length >= not_inactive_symbols_length * min_ratio, exchange.id + ' ' + 'fetchTickers' + ' must return tickers for all active markets. but returned: ' + str(obtained_tickers_length) + ' tickers, ' + str(not_inactive_symbols_length) + ' active markets'
|
||||
#
|
||||
# ensure tickers length is less than markets length
|
||||
#
|
||||
all_markets = exchange.markets
|
||||
all_markets_length = len(list(all_markets.keys()))
|
||||
assert obtained_tickers_length <= all_markets_length, exchange.id + ' ' + 'fetchTickers' + ' must return <= than all markets, but returned: ' + str(obtained_tickers_length) + ' tickers, ' + str(all_markets_length) + ' markets'
|
||||
28
ccxt/test/exchange/sync/test_fetch_trades.py
Normal file
28
ccxt/test/exchange/sync/test_fetch_trades.py
Normal file
@@ -0,0 +1,28 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
from ccxt.test.exchange.base import test_trade # noqa E402
|
||||
|
||||
def test_fetch_trades(exchange, skipped_properties, symbol):
|
||||
method = 'fetchTrades'
|
||||
trades = exchange.fetch_trades(symbol)
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, trades)
|
||||
now = exchange.milliseconds()
|
||||
for i in range(0, len(trades)):
|
||||
test_trade(exchange, skipped_properties, method, trades[i], symbol, now)
|
||||
test_shared_methods.assert_in_array(exchange, skipped_properties, method, trades[i], 'takerOrMaker', ['taker', None])
|
||||
if not ('timestampSort' in skipped_properties):
|
||||
test_shared_methods.assert_timestamp_order(exchange, method, symbol, trades)
|
||||
return True
|
||||
22
ccxt/test/exchange/sync/test_fetch_trading_fee.py
Normal file
22
ccxt/test/exchange/sync/test_fetch_trading_fee.py
Normal file
@@ -0,0 +1,22 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_trading_fee # noqa E402
|
||||
|
||||
def test_fetch_trading_fee(exchange, skipped_properties, symbol):
|
||||
method = 'fetchTradingFee'
|
||||
fee = exchange.fetch_trading_fee(symbol)
|
||||
assert isinstance(fee, dict), exchange.id + ' ' + method + ' ' + symbol + ' must return an object. ' + exchange.json(fee)
|
||||
test_trading_fee(exchange, skipped_properties, method, symbol, fee)
|
||||
return True
|
||||
26
ccxt/test/exchange/sync/test_fetch_trading_fees.py
Normal file
26
ccxt/test/exchange/sync/test_fetch_trading_fees.py
Normal file
@@ -0,0 +1,26 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
||||
sys.path.append(root)
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
||||
# PLEASE DO NOT EDIT THIS FILE, IT IS GENERATED AND WILL BE OVERWRITTEN:
|
||||
# https://github.com/ccxt/ccxt/blob/master/CONTRIBUTING.md#how-to-contribute-code
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ccxt.test.exchange.base import test_trading_fee # noqa E402
|
||||
from ccxt.test.exchange.base import test_shared_methods # noqa E402
|
||||
|
||||
def test_fetch_trading_fees(exchange, skipped_properties):
|
||||
method = 'fetchTradingFees'
|
||||
fees = exchange.fetch_trading_fees()
|
||||
symbols = list(fees.keys())
|
||||
test_shared_methods.assert_non_emtpy_array(exchange, skipped_properties, method, symbols)
|
||||
for i in range(0, len(symbols)):
|
||||
symbol = symbols[i]
|
||||
test_trading_fee(exchange, skipped_properties, method, symbol, fees[symbol])
|
||||
return True
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user