Files
ccxt_with_mt5/ccxt/test/exchange/base/test_ticker.py
lz_db 0fab423a18 add
2025-11-16 12:31:03 +08:00

178 lines
12 KiB
Python

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)