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
# ----------------------------------------------------------------------------
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

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 -*-
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
def test_fetch_withdrawals(exchange, skipped_properties, code):
method = 'fetchWithdrawals'
transactions = 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
def test_load_markets(exchange, skipped_properties):
method = 'loadMarkets'
markets = 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
def test_proxies(exchange, skipped_properties):
test_proxy_url(exchange, skipped_properties)
test_http_proxy(exchange, skipped_properties)
# 'httpsProxy', 'socksProxy'
test_proxy_for_exceptions(exchange, skipped_properties)
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 = 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
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 = 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
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:
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 -*-
def test_sign_in(exchange, skipped_properties):
method = 'signIn'
if exchange.has[method]:
exchange.sign_in()
return True