This commit is contained in:
lz_db
2025-11-16 12:31:03 +08:00
commit 0fab423a18
1451 changed files with 743213 additions and 0 deletions

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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'

View 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

View 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

View 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

View 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

View 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

View 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

View 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)

View 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

View 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

View 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'])

View 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

View 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')

View 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')

View 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'])

View 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)

View 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')

View 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])

View 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')

View 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')

View 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)

View 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)

View 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')

View 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])

View 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

View 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')

View 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')

View 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

View 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')

View 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

View 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'

View 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)

View 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)

View 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)

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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'

View 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

View 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

View 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