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

3
ccxt/test/__init__.py Normal file
View File

@@ -0,0 +1,3 @@
# from ccxt.test.test_ohlcv import test_ohlcv # noqa: F401
# from . import ccxt
# __all__ = [ ccxt.test.test_shared_methods ]

View File

@@ -0,0 +1,19 @@
import os
import sys
root = 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.base.test_deep_extend import test_deep_extend # noqa E402
def test_language_specific():
pass

View File

@@ -0,0 +1,114 @@
import os
import sys
root = 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 ccxt # noqa: F402
from ccxt.test.exchange.base import test_shared_methods # noqa E402
def helper_test_init_throttler():
exchange = ccxt.Exchange({
'id': 'sampleexchange',
'rateLimit': 10.8,
})
# todo: assert (exchange.MAX_VALUE !== undefined);
token_bucket = exchange.get_property(exchange, 'tokenBucket') # trick for uncamelcase transpilation
if token_bucket is None:
token_bucket = exchange.get_property(exchange, 'TokenBucket')
assert token_bucket is not None
assert 'GO_SKIP_START'
rate_limit = exchange.get_property(exchange, 'rateLimit')
assert rate_limit == 10.8
assert token_bucket['delay'] == 0.001
assert token_bucket['refillRate'] == 1 / rate_limit
assert 'GO_SKIP_END'
# fix decimal/integer issues across langs
assert exchange.in_array(token_bucket['capacity'], [1, 1])
cost = exchange.parse_to_numeric(exchange.safe_string_2(token_bucket, 'cost', 'defaultCost')) # python sync, todo fix
assert exchange.in_array(cost, [1, 1])
assert not ('maxCapacity' in token_bucket) or exchange.in_array(token_bucket['maxCapacity'], [1000, 1000])
def helper_test_sandbox_state(exchange, should_be_enabled=True):
assert exchange.urls is not None
assert 'test' in exchange.urls
assert 'GO_SKIP_START'
is_sandbox_mode_enabled = exchange.get_property(exchange, 'isSandboxModeEnabled')
if should_be_enabled:
assert is_sandbox_mode_enabled
assert exchange.urls['api']['public'] == 'https://example.org'
assert exchange.urls['apiBackup']['public'] == 'https://example.com'
else:
assert not is_sandbox_mode_enabled
assert exchange.urls['api']['public'] == 'https://example.com'
assert exchange.urls['test']['public'] == 'https://example.org'
assert 'GO_SKIP_END'
def helper_test_init_sandbox():
# todo: sandbox for real exchanges
opts = {
'id': 'sampleexchange',
'options': {
'sandbox': False,
},
'urls': {
'api': {
'public': 'https://example.com',
},
'test': {
'public': 'https://example.org',
},
},
}
#
# CASE A: when sandbox is not enabled
#
exchange3 = ccxt.Exchange(opts)
helper_test_sandbox_state(exchange3, False)
exchange3.set_sandbox_mode(True)
helper_test_sandbox_state(exchange3, True)
#
# CASE B: when sandbox is enabled
#
opts['options']['sandbox'] = True
exchange4 = ccxt.Exchange(opts)
helper_test_sandbox_state(exchange4, True)
exchange4.set_sandbox_mode(False)
helper_test_sandbox_state(exchange4, False)
def helper_test_init_market():
# ############# markets ############# #
sample_market = {
'id': 'BtcUsd',
'symbol': 'BTC/USD',
'base': 'BTC',
'quote': 'USD',
'baseId': 'Btc',
'quoteId': 'Usd',
'type': 'spot',
'spot': True,
}
exchange2 = ccxt.Exchange({
'id': 'sampleexchange',
'markets': {
'BTC/USD': sample_market,
},
})
assert exchange2.markets['BTC/USD'] is not None
def test_after_constructor():
helper_test_init_throttler()
helper_test_init_sandbox()
helper_test_init_market()

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.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 ccxt # noqa: F402
from ccxt.test.exchange.base import test_shared_methods # noqa E402
def test_arrays_concat():
exchange = ccxt.Exchange({
'id': 'sampleexchange',
})
test_shared_methods.assert_deep_equal(exchange, None, 'testArraysConcat', exchange.arrays_concat([['b'], ['a', 'c']]), ['b', 'a', 'c'])

View File

@@ -0,0 +1,136 @@
import os
import sys
root = 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
# ----------------------------------------------------------------------------
import ccxt # noqa: F402
import hashlib # noqa: F402
Exchange = ccxt.Exchange
hash = Exchange.hash
hmac = Exchange.hmac
ecdsa = Exchange.ecdsa
eddsa = Exchange.eddsa
safe_string = Exchange.safe_string
safe_integer = Exchange.safe_integer
in_array = Exchange.in_array
jwt = Exchange.jwt
crc32 = Exchange.crc32
rsa = Exchange.rsa
encode = Exchange.encode
def equals(a, b):
return a == b
# even though no AUTO_TRANSP flag here, self file is manually transpiled
def test_cryptography():
# exchange = Exchange()
# ---------------------------------------------------------------------------------------------------------------------
assert hash(encode(''), 'sha256', 'hex') == 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'
assert hash(encode('cheese'), 'sha256', 'hex') == '873ac9ffea4dd04fa719e8920cd6938f0c23cd678af330939cff53c3d2855f34'
assert hash(encode(''), 'md5', 'hex') == 'd41d8cd98f00b204e9800998ecf8427e'
assert hash(encode('sexyfish'), 'md5', 'hex') == 'c8a35464aa9d5683585786f44d5889f8'
assert hash(encode(''), 'sha1', 'hex') == 'da39a3ee5e6b4b0d3255bfef95601890afd80709'
assert hash(encode('nutella'), 'sha1', 'hex') == 'b3d60a34b744159793c483b067c56d8affc5111a'
assert hmac(encode('hello'), encode('there'), hashlib.sha256, 'hex') == '551e1c1ecbce0fe9b643745a376584a6289f5f43a46861b315fac9edc8d52a26'
assert hmac(encode('a message'), encode('a secret'), hashlib.md5, 'hex') == '0bfa503bdbc7358185fcd49b4869e23d'
# ---------------------------------------------------------------------------------------------------------------------
privateKey = '1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a'
assert(equals(ecdsa('1a', privateKey, 'secp256k1', 'sha256'), {
'r': '23dcb2a2a3728a35eb1a35cc01743c4609550d9cceaf2083550f13a9eb135f9f',
's': '317963fcac18e4ec9f7921b97d7ea0c82a873dd6299cbfb6af016e08ef5ed667',
'v': 0,
}))
assert(equals(ecdsa(privateKey, privateKey, 'secp256k1', None), {
'r': 'b84a36a6fbabd5277ede578448b93d48e70b38efb5b15b1d4e2a298accf938b1',
's': '66ebfb8221cda925526e699a59cd221bb4cc84bdc563024b1802c4d9e1d8bbe9',
'v': 1,
}))
# ---------------------------------------------------------------------------------------------------------------------
#
# assert exchange.hashMessage(privateKey) == '0x59ea5d98c3500c3729f95cf98aa91663f498518cc401360df2912742c232207f'
#
# assert(equals(exchange.signHash('0x59ea5d98c3500c3729f95cf98aa91663f498518cc401360df2912742c232207f', privateKey), {
# 'r': '0x6f684aa41c02da83dac3039d8805ddbe79a03b1297e247c7742cab8dfc19d341',
# 's': '0x62473881674550563cb028ff40a7846fd53620ddf40a20cc1003b8484a109a4a',
# 'v': 27
# }))
#
# assert(equals(exchange.signMessage(privateKey, privateKey), {
# 'r': '0x6f684aa41c02da83dac3039d8805ddbe79a03b1297e247c7742cab8dfc19d341',
# 's': '0x62473881674550563cb028ff40a7846fd53620ddf40a20cc1003b8484a109a4a',
# 'v': 27
# }))
#
# ---------------------------------------------------------------------------------------------------------------------
pemKeyArray = [
'-----BEGIN RSA PRIVATE KEY-----',
'MIIEpAIBAAKCAQEAqUtXQXv2uSm9zPvdJTRpu5/65rBjAoHmIiowAs+u7fY0QP9O',
'+T8CZRQjvZrfPomBiccjCxDo8mm7GkmL67rs9s7VOMQFvpTTtMBeglNSEbXJ3wTt',
'7WM5gD3ZAbhfGtwWdGpcOMX0hV5/d/fiw1zQk0+AooayTryZ7HV+DQcD1sGTYYir',
'LePUGkKV2NCvKtGOQfRAtuo0ccigMxMvEhWuExCc9Fhd077OpXMc0n7OiFqA2JWN',
'jlocM9S71Srvw/lDos8a7lGaFUV8gP1CsQY/4qTju6hhsRd4lFujVr5J9FqmDbnv',
'wQ79SSu6+lT0+ToFdDHiYOorBK2ESFR7EzlyLwIDAQABAoIBAEobQMbZjNbg/sSM',
'O/HdT6tiDGKPM8gVNLgf34RbhSeFbrpFCDzy6Al3F24YLUEi0CGPmjdt34q93blU',
'GHvIB5LCV3PR2vHiFAo7ayOBdZtrCEMn1T7lAHaynBu0qW0IiovLQzNW9AKtqv7I',
'8+qw5lyVoKmEbOkqhfaMN/Fb8MJAo3yEVyhyp4EjtFhqDQ9DuHEjp1jGthnMgm+4',
'qFyELf0DXZSAN+R9IGDqWPyo78lOcPW4pgeLuoLQ6Nn/2JAEGHFt1a7zMEw5yYbR',
'XB89Bh0dheSmopBN6Heay4YuhnNKua37OlL1/nhKpLGUNE3z/UOXeiUiMeE1C2i+',
'GjK+xgECgYEA4XH63rJ3VYDHHWUGlWffFWkEpgR4BDEkZ8MyVYQoUjQA2TpCvQ2+',
'bR7aAIGXhBnRTrIBNu9m4+am0aUfi1hVmVHqt1b2vFgEb9uKuO4U62tCFpeji+Rz',
'8C8QJyu5v5OUWdQZ4EA0d7ljeoTl50g8tpcGsDhnImLt+/jvJuFt8dECgYEAwD0n',
'rhlkEjKVHxu1xwKeczxYCqqcUV9Quq8HnPh4VJQ77ljfZ57V7sAKrFDi5XfVD9jS',
'oJPwxjw6za134VobhdvCM6WNs6AJmbR8E/b5kDMbGaZn27vt+/8JfnGaWBqpDi6W',
'a5xoJOqmcMBQBK1YleZDoY4PLbk+onVKLMfGI/8CgYEAkyUIv8euGdGWpHnm5SdJ',
'tLi5vv4Vs267uzntJWG/y3+DukTLgIdy7dgAI+pxkVgkg/+syUVSW5eU9CqZPyLl',
'o8+Sqh2Jp36vTq71iSRj5RA5r3ND3K+8eFzPZzGj6AWUA1lrljFxzV7kLfiF8gH1',
'FpvWUrhNoGT/vcFJno/uabECgYAecRC5hxfLserfVDoC261PvjyK492BHUDhbxob',
'h1U2v4qGAdjOxd5Gwm5uPxjPEZzRt5oTB5pXKe5953xWWTiGh/hGyW6ZBTy/9E65',
'sqBub0lZVHqZ1zamcwqD1WWFkiM3NbVoMQpk3iuhKzMAqpqekiofiSlqKi16+GvY',
'j4IW7QKBgQCrIUckPZ6IY3ERIN1IL4TIcK2gOJcznp7fLWpC+sv35ya3OhtDXKFt',
'GjIHmwLuiUNc0iPzA9Rw89W0zIkKWmWcxM88/ithdxh3MEeNDUGSnd4hQ9SECwxB',
'Wem3eBT7I4VtFYoaTE3/bX1SKfgBdTzIRqWKSDpgBNZg/P2Tc+s11g==',
'-----END RSA PRIVATE KEY-----',
]
pemKey = "\n".join(pemKeyArray)
assert rsa('hello', pemKey, 'sha256') == 'PqHotvSEBvM/AejnMOWBXUcOf3uHtcGu2zAYdlYdnlNSSQ80Uq4lcyAEstnZ2AnQJ9l5TCC53uoRZ26GQ47zlACgqtYglmPhQKLvQ5fldRzeBauYhGgM2C0mUuUGxh074fNGbK+bgmwEmDMIrnSPtXwiCqTAHh+8VEnC7us3t09D61y298dPBJYEBNN3dFZT0w0pCIQg3j3DSiFJOCfywmOKyXqS1pvmk6A38DVclQZORQ5WZXp2yvSKRLjxpzjxDl76h1GfbBl7sMLEFMyzk0wyIhIz8ZELMibYn036G4X1IcSlDcimthEkIbn2QjM0ntyYDZIS4QnsMBjvkV2UHw=='
assert rsa('poopy', pemKey, 'sha256') == 'or069qHwRDyl162T1s5G5+LfLnvDxlgk9kEsJvwI3vM02KB1LHW4+8gWqsV4TENZpeqed2Tb4na6ex+L/UR8JxJnnZtpVp33nUBgcp3miqp/YhcGN4++qolP4YN/21/AyfLFZW+VYggc+Mhh6PJSm+0dSEWMVsP35uH+35abXVxgB8GVOn7YTOSPaL8aw7hn4wlZWf2ieikKAi7AwAjkxnd7/Bu5+cW8D+ZdPHQfSKj+XHuPXlJNuQX0MDIqhdD2yuYJOQL56eKYs6nHPlClATkndSaAemQSGKet3X3Iz1awG4MGgz2Ei6bOanlNugc0f6Rng6rdwmqiMU3G4it6cw=='
assert jwt({'chicken': 'salad'}, encode(pemKey), 'sha256', True) == 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJjaGlja2VuIjoic2FsYWQifQ.FSKD5Y6RNzkHTuHdvG3753U7QNZ-u-GUSPfP1FMjEaK0Rr_iyQTSSmHhkdYSFFnmBvrrN_l-UwKwir52WlsgmQm9HYm0kidxbj7fWwrK2E1oe0P7OjupFjv1BZxc5W69WeaHtOPWe28tiHiON1LCnax6HgfI5lcIBsESGIIBZMVeaioQn9gDVwea7JxJvAlrhDIWZowIHTIdCQocXip7g5jREWHeEIuJNug67mwnfAFxCjvTRiTd0Bw6oBwjM3FLya-RyEyWrejQOWSuC8CNWVUHISaSmEyZ7uM6wTi2m_58TaE9mQwlef32OPErPvvBpgL5pZIyQ4ymwrCIFQLBQQ'
assert jwt({'lil': 'xan'}, encode('betrayed'), 'sha256', False) == 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJsaWwiOiJ4YW4ifQ.md-oFvZagA-NXmZoRNyJOQ7zwK-PWUMmMQ_LI9ZOKaM'
assert crc32('hello', True) == 907060870
assert crc32('tasty chicken breast :)', True) == 825820175
assert crc32('21101:0.00123125:21102:-0.001:21100:0.710705:21103:-0.001:21096:0.71076:21104:-0.001:21094:1.0746:21105:-0.001:21093:0.710854:21106:-0.419:21092:0.01368102:21107:-0.001:21090:0.710975:21109:-0.001:21089:0.63586344:21110:-1.186213:21087:0.299:21111:-0.48751202:21086:0.9493:21112:-0.03702409:21082:0.03537667:21113:-0.712385:21081:0.00101366:21114:-0.2903:21079:0.710713:21115:-0.001:21078:0.997048:21116:-0.60089827:21077:0.23770225:21117:-0.83201:21076:0.03619135:21118:-0.09996142:21075:0.1272433:21119:-1.09681107:21074:0.7447885:21120:-0.04771792:21073:0.0011:21121:-0.91495684:21072:0.73311632:21122:-0.07940416:21071:0.09817:21123:-0.39376843:21070:0.19101052:21124:-1.51692599:21069:0.2757:21125:-0.11107322:21068:0.12480303:21126:-0.12704666:21067:0.4201:21128:-0.12804666', True) == -51055998
# assert eddsa('1b1b', privateKey, 'ed25519') == '3DBaaz8z4Pq9n6ncNCjB4pFLWaWTXbjaCUqKQmBgS3w7AP6opeDqANBhPssbV3jyfJB4LfK8kGR6pu6GU8fbjMuy'

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.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 ROUND # noqa E402
from ccxt.base.decimal_to_precision import ROUND_UP # noqa E402
from ccxt.base.decimal_to_precision import ROUND_DOWN # noqa E402
import ccxt # noqa: F402
def test_datetime():
exchange = ccxt.Exchange({
'id': 'regirock',
})
assert exchange.iso8601(514862627000) == '1986-04-26T01:23:47.000Z'
assert exchange.iso8601(514862627559) == '1986-04-26T01:23:47.559Z'
assert exchange.iso8601(514862627062) == '1986-04-26T01:23:47.062Z'
assert exchange.iso8601(1) == '1970-01-01T00:00:00.001Z'
assert exchange.iso8601(-1) is None
# assert (exchange.iso8601 () === undefined);
# todo: assert (exchange.iso8601 () === undefined);
assert exchange.iso8601(None) is None
assert exchange.iso8601('') is None
assert exchange.iso8601('a') is None
assert exchange.iso8601({}) is None
# ----------------------------------------------------------------------------
assert exchange.parse8601('1986-04-26T01:23:47.000Z') == 514862627000
assert exchange.parse8601('1986-04-26T01:23:47.559Z') == 514862627559
assert exchange.parse8601('1986-04-26T01:23:47.062Z') == 514862627062
assert exchange.parse8601('1986-04-26T01:23:47.06Z') == 514862627060
assert exchange.parse8601('1986-04-26T01:23:47.6Z') == 514862627600
assert exchange.parse8601('1977-13-13T00:00:00.000Z') is None
assert exchange.parse8601('1986-04-26T25:71:47.000Z') is None
assert exchange.parse8601('3333') is None
assert exchange.parse8601('Sr90') is None
assert exchange.parse8601('') is None
# assert (exchange.parse8601 () === undefined);
# todo: assert (exchange.parse8601 () === undefined);
assert exchange.parse8601(None) is None
assert exchange.parse8601({}) is None
assert exchange.parse8601(33) is None
# ----------------------------------------------------------------------------
assert exchange.parse_date('1986-04-26 00:00:00') == 514857600000
assert exchange.parse_date('1986-04-26T01:23:47.000Z') == 514862627000
assert exchange.parse_date('1986-13-13 00:00:00') is None
# GMT formats (todo: bugs in php)
# assert (exchange.parseDate ('Mon, 29 Apr 2024 14:00:17 GMT') === 1714399217000);
# assert (exchange.parseDate ('Mon, 29 Apr 2024 14:09:17 GMT') === 1714399757000);
# assert (exchange.parseDate ('Sun, 29 Dec 2024 01:01:10 GMT') === 1735434070000);
# assert (exchange.parseDate ('Sun, 29 Dec 2024 02:11:10 GMT') === 1735438270000);
# assert (exchange.parseDate ('Sun, 08 Dec 2024 02:03:04 GMT') === 1733623384000);
assert exchange.round_timeframe('5m', exchange.parse8601('2019-08-12 13:22:08'), ROUND_DOWN) == exchange.parse8601('2019-08-12 13:20:00')
assert exchange.round_timeframe('10m', exchange.parse8601('2019-08-12 13:22:08'), ROUND_DOWN) == exchange.parse8601('2019-08-12 13:20:00')
assert exchange.round_timeframe('30m', exchange.parse8601('2019-08-12 13:22:08'), ROUND_DOWN) == exchange.parse8601('2019-08-12 13:00:00')
assert exchange.round_timeframe('1d', exchange.parse8601('2019-08-12 13:22:08'), ROUND_DOWN) == exchange.parse8601('2019-08-12 00:00:00')
assert exchange.round_timeframe('5m', exchange.parse8601('2019-08-12 13:22:08'), ROUND_UP) == exchange.parse8601('2019-08-12 13:25:00')
assert exchange.round_timeframe('10m', exchange.parse8601('2019-08-12 13:22:08'), ROUND_UP) == exchange.parse8601('2019-08-12 13:30:00')
assert exchange.round_timeframe('30m', exchange.parse8601('2019-08-12 13:22:08'), ROUND_UP) == exchange.parse8601('2019-08-12 13:30:00')
assert exchange.round_timeframe('1h', exchange.parse8601('2019-08-12 13:22:08'), ROUND_UP) == exchange.parse8601('2019-08-12 14:00:00')
assert exchange.round_timeframe('1d', exchange.parse8601('2019-08-12 13:22:08'), ROUND_UP) == exchange.parse8601('2019-08-13 00:00:00')

View File

@@ -0,0 +1,325 @@
import os
import sys
root = 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
from ccxt.base.decimal_to_precision import NO_PADDING # 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 SIGNIFICANT_DIGITS # noqa E402
from ccxt.base.decimal_to_precision import PAD_WITH_ZERO # noqa E402
from ccxt.base.decimal_to_precision import decimal_to_precision # noqa E402
import ccxt # noqa: F402
def test_decimal_to_precision():
exchange = ccxt.Exchange({
'id': 'regirock',
})
# ----------------------------------------------------------------------------
# Truncate To N Digits After Dot
assert exchange.decimal_to_precision('12.3456000', TRUNCATE, 100, DECIMAL_PLACES) == '12.3456'
assert exchange.decimal_to_precision('12.3456', TRUNCATE, 100, DECIMAL_PLACES) == '12.3456'
assert exchange.decimal_to_precision('12.3456', TRUNCATE, 4, DECIMAL_PLACES) == '12.3456'
assert exchange.decimal_to_precision('12.3456', TRUNCATE, 3, DECIMAL_PLACES) == '12.345'
assert exchange.decimal_to_precision('12.3456', TRUNCATE, 2, DECIMAL_PLACES) == '12.34'
assert exchange.decimal_to_precision('12.3456', TRUNCATE, 1, DECIMAL_PLACES) == '12.3'
assert exchange.decimal_to_precision('12.3456', TRUNCATE, 0, DECIMAL_PLACES) == '12'
# ['12.3456', TRUNCATE, -1, DECIMAL_PLACES, '10'], # not yet supported
# ['123.456', TRUNCATE, -2, DECIMAL_PLACES, '120'], # not yet supported
# ['123.456', TRUNCATE, -3, DECIMAL_PLACES, '100'], # not yet supported
assert exchange.decimal_to_precision('0.0000001', TRUNCATE, 8, DECIMAL_PLACES) == '0.0000001'
assert exchange.decimal_to_precision('0.00000001', TRUNCATE, 8, DECIMAL_PLACES) == '0.00000001'
assert exchange.decimal_to_precision('0.000000000', TRUNCATE, 9, DECIMAL_PLACES, PAD_WITH_ZERO) == '0.000000000'
assert exchange.decimal_to_precision('0.000000001', TRUNCATE, 9, DECIMAL_PLACES, PAD_WITH_ZERO) == '0.000000001'
assert exchange.decimal_to_precision('12.3456', TRUNCATE, -1, DECIMAL_PLACES) == '10'
assert exchange.decimal_to_precision('123.456', TRUNCATE, -1, DECIMAL_PLACES) == '120'
assert exchange.decimal_to_precision('123.456', TRUNCATE, -2, DECIMAL_PLACES) == '100'
assert exchange.decimal_to_precision('9.99999', TRUNCATE, -1, DECIMAL_PLACES) == '0'
assert exchange.decimal_to_precision('99.9999', TRUNCATE, -1, DECIMAL_PLACES) == '90'
assert exchange.decimal_to_precision('99.9999', TRUNCATE, -2, DECIMAL_PLACES) == '0'
assert exchange.decimal_to_precision('0', TRUNCATE, 0, DECIMAL_PLACES) == '0'
assert exchange.decimal_to_precision('-0.9', TRUNCATE, 0, DECIMAL_PLACES) == '0'
# ----------------------------------------------------------------------------
# Truncate To N Significant Digits
assert exchange.decimal_to_precision('0.000123456700', TRUNCATE, 100, SIGNIFICANT_DIGITS) == '0.0001234567'
assert exchange.decimal_to_precision('0.0001234567', TRUNCATE, 100, SIGNIFICANT_DIGITS) == '0.0001234567'
assert exchange.decimal_to_precision('0.0001234567', TRUNCATE, 7, SIGNIFICANT_DIGITS) == '0.0001234567'
assert exchange.decimal_to_precision('0.000123456', TRUNCATE, 6, SIGNIFICANT_DIGITS) == '0.000123456'
assert exchange.decimal_to_precision('0.000123456', TRUNCATE, 5, SIGNIFICANT_DIGITS) == '0.00012345'
assert exchange.decimal_to_precision('0.000123456', TRUNCATE, 2, SIGNIFICANT_DIGITS) == '0.00012'
assert exchange.decimal_to_precision('0.000123456', TRUNCATE, 1, SIGNIFICANT_DIGITS) == '0.0001'
assert exchange.decimal_to_precision('123.0000987654', TRUNCATE, 10, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '123.0000987'
assert exchange.decimal_to_precision('123.0000987654', TRUNCATE, 8, SIGNIFICANT_DIGITS) == '123.00009'
assert exchange.decimal_to_precision('123.0000987654', TRUNCATE, 7, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '123.0000'
assert exchange.decimal_to_precision('123.0000987654', TRUNCATE, 6, SIGNIFICANT_DIGITS) == '123'
assert exchange.decimal_to_precision('123.0000987654', TRUNCATE, 5, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '123.00'
assert exchange.decimal_to_precision('123.0000987654', TRUNCATE, 4, SIGNIFICANT_DIGITS) == '123'
assert exchange.decimal_to_precision('123.0000987654', TRUNCATE, 4, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '123.0'
assert exchange.decimal_to_precision('123.0000987654', TRUNCATE, 3, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '123'
assert exchange.decimal_to_precision('123.0000987654', TRUNCATE, 2, SIGNIFICANT_DIGITS) == '120'
assert exchange.decimal_to_precision('123.0000987654', TRUNCATE, 1, SIGNIFICANT_DIGITS) == '100'
assert exchange.decimal_to_precision('123.0000987654', TRUNCATE, 1, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '100'
assert exchange.decimal_to_precision('1234', TRUNCATE, 5, SIGNIFICANT_DIGITS) == '1234'
assert exchange.decimal_to_precision('1234', TRUNCATE, 5, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '1234.0'
assert exchange.decimal_to_precision('1234', TRUNCATE, 4, SIGNIFICANT_DIGITS) == '1234'
assert exchange.decimal_to_precision('1234', TRUNCATE, 4, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '1234'
assert exchange.decimal_to_precision('1234.69', TRUNCATE, 0, SIGNIFICANT_DIGITS) == '0'
assert exchange.decimal_to_precision('1234.69', TRUNCATE, 0, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '0'
# ----------------------------------------------------------------------------
# Round To N Digits After Dot
assert exchange.decimal_to_precision('12.3456000', ROUND, 100, DECIMAL_PLACES) == '12.3456'
assert exchange.decimal_to_precision('12.3456', ROUND, 100, DECIMAL_PLACES) == '12.3456'
assert exchange.decimal_to_precision('12.3456', ROUND, 4, DECIMAL_PLACES) == '12.3456'
assert exchange.decimal_to_precision('12.3456', ROUND, 3, DECIMAL_PLACES) == '12.346'
assert exchange.decimal_to_precision('12.3456', ROUND, 2, DECIMAL_PLACES) == '12.35'
assert exchange.decimal_to_precision('12.3456', ROUND, 1, DECIMAL_PLACES) == '12.3'
assert exchange.decimal_to_precision('12.3456', ROUND, 0, DECIMAL_PLACES) == '12'
# todo:
# ['9.999', ROUND, 3, DECIMAL_PLACES, NO_PADDING, '9.999'],
# ['9.999', ROUND, 2, DECIMAL_PLACES, NO_PADDING, '10'],
# ['9.999', ROUND, 2, DECIMAL_PLACES, PAD_WITH_ZERO, '10.00'],
# ['99.999', ROUND, 2, DECIMAL_PLACES, PAD_WITH_ZERO, '100.00'],
# ['-99.999', ROUND, 2, DECIMAL_PLACES, PAD_WITH_ZERO, '-100.00'],
# ['12.3456', ROUND, -1, DECIMAL_PLACES, NO_PADDING, '10'], # not yet supported
# ['123.456', ROUND, -1, DECIMAL_PLACES, NO_PADDING, '120'], # not yet supported
# ['123.456', ROUND, -2, DECIMAL_PLACES, NO_PADDING, '100'], # not yet supported
# a problematic case in PHP
assert exchange.decimal_to_precision('10000', ROUND, 6, DECIMAL_PLACES) == '10000'
assert exchange.decimal_to_precision('0.00003186', ROUND, 8, DECIMAL_PLACES) == '0.00003186'
assert exchange.decimal_to_precision('12.3456', ROUND, -1, DECIMAL_PLACES) == '10'
assert exchange.decimal_to_precision('123.456', ROUND, -1, DECIMAL_PLACES) == '120'
assert exchange.decimal_to_precision('123.456', ROUND, -2, DECIMAL_PLACES) == '100'
assert exchange.decimal_to_precision('9.99999', ROUND, -1, DECIMAL_PLACES) == '10'
assert exchange.decimal_to_precision('99.9999', ROUND, -1, DECIMAL_PLACES) == '100'
assert exchange.decimal_to_precision('99.9999', ROUND, -2, DECIMAL_PLACES) == '100'
assert exchange.decimal_to_precision('9.999', ROUND, 3, DECIMAL_PLACES) == '9.999'
assert exchange.decimal_to_precision('9.999', ROUND, 2, DECIMAL_PLACES) == '10'
assert exchange.decimal_to_precision('9.999', ROUND, 2, DECIMAL_PLACES, PAD_WITH_ZERO) == '10.00'
assert exchange.decimal_to_precision('99.999', ROUND, 2, DECIMAL_PLACES, PAD_WITH_ZERO) == '100.00'
assert exchange.decimal_to_precision('-99.999', ROUND, 2, DECIMAL_PLACES, PAD_WITH_ZERO) == '-100.00'
# ----------------------------------------------------------------------------
# Round To N Significant Digits
assert exchange.decimal_to_precision('0.000123456700', ROUND, 100, SIGNIFICANT_DIGITS) == '0.0001234567'
assert exchange.decimal_to_precision('0.0001234567', ROUND, 100, SIGNIFICANT_DIGITS) == '0.0001234567'
assert exchange.decimal_to_precision('0.0001234567', ROUND, 7, SIGNIFICANT_DIGITS) == '0.0001234567'
assert exchange.decimal_to_precision('0.000123456', ROUND, 6, SIGNIFICANT_DIGITS) == '0.000123456'
assert exchange.decimal_to_precision('0.000123456', ROUND, 5, SIGNIFICANT_DIGITS) == '0.00012346'
assert exchange.decimal_to_precision('0.000123456', ROUND, 4, SIGNIFICANT_DIGITS) == '0.0001235'
assert exchange.decimal_to_precision('0.00012', ROUND, 2, SIGNIFICANT_DIGITS) == '0.00012'
assert exchange.decimal_to_precision('0.0001', ROUND, 1, SIGNIFICANT_DIGITS) == '0.0001'
assert exchange.decimal_to_precision('123.0000987654', ROUND, 7, SIGNIFICANT_DIGITS) == '123.0001'
assert exchange.decimal_to_precision('123.0000987654', ROUND, 6, SIGNIFICANT_DIGITS) == '123'
assert exchange.decimal_to_precision('0.00098765', ROUND, 2, SIGNIFICANT_DIGITS) == '0.00099'
assert exchange.decimal_to_precision('0.00098765', ROUND, 2, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '0.00099'
assert exchange.decimal_to_precision('0.00098765', ROUND, 1, SIGNIFICANT_DIGITS) == '0.001'
assert exchange.decimal_to_precision('0.00098765', ROUND, 10, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '0.0009876500000'
assert exchange.decimal_to_precision('0.098765', ROUND, 1, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '0.1'
assert exchange.decimal_to_precision('0', ROUND, 0, SIGNIFICANT_DIGITS) == '0'
assert exchange.decimal_to_precision('-0.123', ROUND, 0, SIGNIFICANT_DIGITS) == '0'
assert exchange.decimal_to_precision('0.00000044', ROUND, 5, SIGNIFICANT_DIGITS) == '0.00000044'
assert exchange.decimal_to_precision('0.123456', ROUND, 5, SIGNIFICANT_DIGITS) == '0.12346'
assert exchange.decimal_to_precision('0.123456', ROUND, 6, SIGNIFICANT_DIGITS) == '0.123456'
assert exchange.decimal_to_precision('0.123456', ROUND, 7, SIGNIFICANT_DIGITS) == '0.123456'
assert exchange.decimal_to_precision('1.234567', ROUND, 5, SIGNIFICANT_DIGITS) == '1.2346'
assert exchange.decimal_to_precision('1.234567', ROUND, 6, SIGNIFICANT_DIGITS) == '1.23457'
assert exchange.decimal_to_precision('1.234567', ROUND, 7, SIGNIFICANT_DIGITS) == '1.234567'
assert exchange.decimal_to_precision('12.34567', ROUND, 5, SIGNIFICANT_DIGITS) == '12.346'
assert exchange.decimal_to_precision('12.34567', ROUND, 6, SIGNIFICANT_DIGITS) == '12.3457'
assert exchange.decimal_to_precision('12.34567', ROUND, 7, SIGNIFICANT_DIGITS) == '12.34567'
# above 1.0
assert exchange.decimal_to_precision('1114.5', ROUND, 3, SIGNIFICANT_DIGITS) == '1110'
assert exchange.decimal_to_precision('1115.5', ROUND, 3, SIGNIFICANT_DIGITS) == '1120'
assert exchange.decimal_to_precision('1114.5', ROUND, 4, SIGNIFICANT_DIGITS) == '1115'
assert exchange.decimal_to_precision('1114.5', ROUND, 5, SIGNIFICANT_DIGITS) == '1114.5'
assert exchange.decimal_to_precision('1115.5', ROUND, 5, SIGNIFICANT_DIGITS) == '1115.5'
# ----------------------------------------------------------------------------
# Round To Tick Size
assert exchange.decimal_to_precision('0.000123456700', ROUND, 0.00012, TICK_SIZE) == '0.00012'
assert exchange.decimal_to_precision('0.0001234567', ROUND, 0.00013, TICK_SIZE) == '0.00013'
assert exchange.decimal_to_precision('0.0001234567', TRUNCATE, 0.00013, TICK_SIZE) == '0'
assert exchange.decimal_to_precision('101.000123456700', ROUND, 100, TICK_SIZE) == '100'
assert exchange.decimal_to_precision('0.000123456700', ROUND, 100, TICK_SIZE) == '0'
assert exchange.decimal_to_precision('165', TRUNCATE, 110, TICK_SIZE) == '110'
assert exchange.decimal_to_precision('3210', TRUNCATE, 1110, TICK_SIZE) == '2220'
assert exchange.decimal_to_precision('165', ROUND, 110, TICK_SIZE) == '220'
assert exchange.decimal_to_precision('0.000123456789', ROUND, 1.2e-7, TICK_SIZE) == '0.00012348'
assert exchange.decimal_to_precision('0.000123456789', TRUNCATE, 1.2e-7, TICK_SIZE) == '0.00012336'
assert exchange.decimal_to_precision('0.000273398', ROUND, 1e-7, TICK_SIZE) == '0.0002734'
assert exchange.decimal_to_precision('0.00005714', TRUNCATE, 1e-8, TICK_SIZE) == '0.00005714'
# this line causes problems in JS, fix with Precise
# assert (exchange.decimalToPrecision ('0.0000571495257361', TRUNCATE, 0.00000001, TICK_SIZE) === '0.00005714');
assert exchange.decimal_to_precision('0.01', ROUND, 0.0001, TICK_SIZE, PAD_WITH_ZERO) == '0.0100'
assert exchange.decimal_to_precision('0.01', TRUNCATE, 0.0001, TICK_SIZE, PAD_WITH_ZERO) == '0.0100'
assert exchange.decimal_to_precision('-0.000123456789', ROUND, 1.2e-7, TICK_SIZE) == '-0.00012348'
assert exchange.decimal_to_precision('-0.000123456789', TRUNCATE, 1.2e-7, TICK_SIZE) == '-0.00012336'
assert exchange.decimal_to_precision('-165', TRUNCATE, 110, TICK_SIZE) == '-110'
assert exchange.decimal_to_precision('-165', ROUND, 110, TICK_SIZE) == '-220'
assert exchange.decimal_to_precision('-1650', TRUNCATE, 1100, TICK_SIZE) == '-1100'
assert exchange.decimal_to_precision('-1650', ROUND, 1100, TICK_SIZE) == '-2200'
assert exchange.decimal_to_precision('0.0006', TRUNCATE, 0.0001, TICK_SIZE) == '0.0006'
assert exchange.decimal_to_precision('-0.0006', TRUNCATE, 0.0001, TICK_SIZE) == '-0.0006'
assert exchange.decimal_to_precision('0.6', TRUNCATE, 0.2, TICK_SIZE) == '0.6'
assert exchange.decimal_to_precision('-0.6', TRUNCATE, 0.2, TICK_SIZE) == '-0.6'
assert exchange.decimal_to_precision('1.2', ROUND, 0.4, TICK_SIZE) == '1.2'
assert exchange.decimal_to_precision('-1.2', ROUND, 0.4, TICK_SIZE) == '-1.2'
assert exchange.decimal_to_precision('1.2', ROUND, 0.02, TICK_SIZE) == '1.2'
assert exchange.decimal_to_precision('-1.2', ROUND, 0.02, TICK_SIZE) == '-1.2'
assert exchange.decimal_to_precision('44', ROUND, 4.4, TICK_SIZE) == '44'
assert exchange.decimal_to_precision('-44', ROUND, 4.4, TICK_SIZE) == '-44'
assert exchange.decimal_to_precision('44.00000001', ROUND, 4.4, TICK_SIZE) == '44'
assert exchange.decimal_to_precision('-44.00000001', ROUND, 4.4, TICK_SIZE) == '-44'
# https://github.com/ccxt/ccxt/issues/6731
assert exchange.decimal_to_precision('20', TRUNCATE, 1e-8, TICK_SIZE) == '20'
assert exchange.decimal_to_precision('0.000123456789', TRUNCATE, 1e-8, TICK_SIZE) == '0.00012345'
# ----------------------------------------------------------------------------
# Negative Numbers
assert exchange.decimal_to_precision('-0.123456', TRUNCATE, 5, DECIMAL_PLACES) == '-0.12345'
assert exchange.decimal_to_precision('-0.123456', ROUND, 5, DECIMAL_PLACES) == '-0.12346'
# ----------------------------------------------------------------------------
# without dot / trailing dot
assert exchange.decimal_to_precision('123', TRUNCATE, 0) == '123'
assert exchange.decimal_to_precision('123', TRUNCATE, 5, DECIMAL_PLACES) == '123'
assert exchange.decimal_to_precision('123', TRUNCATE, 5, DECIMAL_PLACES, PAD_WITH_ZERO) == '123.00000'
assert exchange.decimal_to_precision('123.', TRUNCATE, 0, DECIMAL_PLACES) == '123'
assert exchange.decimal_to_precision('123.', TRUNCATE, 5, DECIMAL_PLACES, PAD_WITH_ZERO) == '123.00000'
assert exchange.decimal_to_precision('0.', TRUNCATE, 0) == '0'
assert exchange.decimal_to_precision('0.', TRUNCATE, 5, DECIMAL_PLACES, PAD_WITH_ZERO) == '0.00000'
# ----------------------------------------------------------------------------
# rounding for equidistant digits
assert exchange.decimal_to_precision('1.44', ROUND, 1, DECIMAL_PLACES) == '1.4'
assert exchange.decimal_to_precision('1.45', ROUND, 1, DECIMAL_PLACES) == '1.5'
assert exchange.decimal_to_precision('1.45', ROUND, 0, DECIMAL_PLACES) == '1' # not 2
# ----------------------------------------------------------------------------
# negative precision only implemented so far in python
# pretty useless for decimal applications as anything |x| < 5 === 0
# NO_PADDING and PAD_WITH_ZERO are ignored
assert exchange.decimal_to_precision('5', ROUND, -1, DECIMAL_PLACES) == '10'
assert exchange.decimal_to_precision('4.999', ROUND, -1, DECIMAL_PLACES) == '0'
assert exchange.decimal_to_precision('0.0431531423', ROUND, -1, DECIMAL_PLACES) == '0'
assert exchange.decimal_to_precision('-69.3', ROUND, -1, DECIMAL_PLACES) == '-70'
assert exchange.decimal_to_precision('5001', ROUND, -4, DECIMAL_PLACES) == '10000'
assert exchange.decimal_to_precision('4999.999', ROUND, -4, DECIMAL_PLACES) == '0'
assert exchange.decimal_to_precision('69.3', TRUNCATE, -2, DECIMAL_PLACES) == '0'
assert exchange.decimal_to_precision('-69.3', TRUNCATE, -2, DECIMAL_PLACES) == '0'
assert exchange.decimal_to_precision('69.3', TRUNCATE, -1, SIGNIFICANT_DIGITS) == '60'
assert exchange.decimal_to_precision('-69.3', TRUNCATE, -1, SIGNIFICANT_DIGITS) == '-60'
assert exchange.decimal_to_precision('69.3', TRUNCATE, -2, SIGNIFICANT_DIGITS) == '0'
assert exchange.decimal_to_precision('1602000000000000000000', TRUNCATE, 3, SIGNIFICANT_DIGITS) == '1600000000000000000000'
# ----------------------------------------------------------------------------
# stringified precision
assert exchange.decimal_to_precision('-0.000123456789', ROUND, '0.00000012', TICK_SIZE) == '-0.00012348'
assert exchange.decimal_to_precision('-0.000123456789', TRUNCATE, '0.00000012', TICK_SIZE) == '-0.00012336'
assert exchange.decimal_to_precision('-165', TRUNCATE, '110', TICK_SIZE) == '-110'
assert exchange.decimal_to_precision('-165', ROUND, '110', TICK_SIZE) == '-220'
# ----------------------------------------------------------------------------
# testDecimalToPrecisionErrorHandling (todo)
#
# throws (() =>
# decimalToPrecision ('123456.789', TRUNCATE, -2, DECIMAL_PLACES),
# 'negative precision is not yet supported')
#
# throws (() =>
# decimalToPrecision ('foo'),
# "invalid number (contains an illegal character 'f')")
#
# throws (() =>
# decimalToPrecision ('0.01', TRUNCATE, -1, TICK_SIZE),
# "TICK_SIZE cant be used with negative numPrecisionDigits")
# ----------------------------------------------------------------------------
# Additional Edge Cases
# Zero handling variations
assert exchange.decimal_to_precision('0.0', TRUNCATE, 2, DECIMAL_PLACES) == '0'
assert exchange.decimal_to_precision('0.00', ROUND, 3, DECIMAL_PLACES, PAD_WITH_ZERO) == '0.000'
assert exchange.decimal_to_precision('-0.0', TRUNCATE, 2, DECIMAL_PLACES) == '0'
assert exchange.decimal_to_precision('-0.00', ROUND, 1, DECIMAL_PLACES) == '0'
# Very small numbers close to zero
assert exchange.decimal_to_precision('0.0000000001', TRUNCATE, 8, DECIMAL_PLACES) == '0'
assert exchange.decimal_to_precision('0.0000000001', ROUND, 8, DECIMAL_PLACES) == '0'
assert exchange.decimal_to_precision('0.0000000001', TRUNCATE, 10, DECIMAL_PLACES) == '0.0000000001'
assert exchange.decimal_to_precision('0.00000000009', ROUND, 10, DECIMAL_PLACES) == '0.0000000001'
assert exchange.decimal_to_precision('0.00000000015', ROUND, 10, DECIMAL_PLACES) == '0.0000000002'
# Very large numbers
assert exchange.decimal_to_precision('99999999999999.99999', TRUNCATE, 2, DECIMAL_PLACES) == '99999999999999.99'
assert exchange.decimal_to_precision('99999999999999.99999', ROUND, 2, DECIMAL_PLACES) == '100000000000000'
assert exchange.decimal_to_precision('123456789012345', TRUNCATE, 3, SIGNIFICANT_DIGITS) == '123000000000000'
assert exchange.decimal_to_precision('123456789012345', ROUND, 3, SIGNIFICANT_DIGITS) == '123000000000000'
# Numbers with leading zeros
assert exchange.decimal_to_precision('000123.456', TRUNCATE, 2, DECIMAL_PLACES) == '123.45'
assert exchange.decimal_to_precision('000123.456', ROUND, 2, DECIMAL_PLACES) == '123.46'
assert exchange.decimal_to_precision('0000.123', TRUNCATE, 2, DECIMAL_PLACES) == '0.12'
# Boundary rounding cases (exactly at 0.5)
assert exchange.decimal_to_precision('1.5', ROUND, 0, DECIMAL_PLACES) == '2'
assert exchange.decimal_to_precision('2.5', ROUND, 0, DECIMAL_PLACES) == '3'
assert exchange.decimal_to_precision('-1.5', ROUND, 0, DECIMAL_PLACES) == '-2'
assert exchange.decimal_to_precision('-2.5', ROUND, 0, DECIMAL_PLACES) == '-3'
assert exchange.decimal_to_precision('1.25', ROUND, 1, DECIMAL_PLACES) == '1.3'
assert exchange.decimal_to_precision('1.35', ROUND, 1, DECIMAL_PLACES) == '1.4'
# Carry-over in rounding (cascading effects)
assert exchange.decimal_to_precision('9.999999', ROUND, 0, DECIMAL_PLACES) == '10'
assert exchange.decimal_to_precision('99.999999', ROUND, 0, DECIMAL_PLACES) == '100'
assert exchange.decimal_to_precision('999.999999', ROUND, 0, DECIMAL_PLACES) == '1000'
assert exchange.decimal_to_precision('9.999999', ROUND, 1, DECIMAL_PLACES) == '10'
assert exchange.decimal_to_precision('9.999999', ROUND, 2, DECIMAL_PLACES) == '10'
assert exchange.decimal_to_precision('-9.999999', ROUND, 0, DECIMAL_PLACES) == '-10'
assert exchange.decimal_to_precision('-99.999999', ROUND, 0, DECIMAL_PLACES) == '-100'
# Edge cases for TICK_SIZE with very small ticks
assert exchange.decimal_to_precision('1.2345', ROUND, 0.0001, TICK_SIZE) == '1.2345'
assert exchange.decimal_to_precision('1.23456', ROUND, 0.0001, TICK_SIZE) == '1.2346'
assert exchange.decimal_to_precision('1.23454', ROUND, 0.0001, TICK_SIZE) == '1.2345'
assert exchange.decimal_to_precision('1.23444', TRUNCATE, 0.0001, TICK_SIZE) == '1.2344'
# TICK_SIZE with numbers smaller than tick
assert exchange.decimal_to_precision('0.05', ROUND, 0.1, TICK_SIZE) == '0.1'
assert exchange.decimal_to_precision('0.04', ROUND, 0.1, TICK_SIZE) == '0'
assert exchange.decimal_to_precision('0.04', TRUNCATE, 0.1, TICK_SIZE) == '0'
assert exchange.decimal_to_precision('0.049999', ROUND, 0.1, TICK_SIZE) == '0'
# SIGNIFICANT_DIGITS edge cases
assert exchange.decimal_to_precision('10000000', TRUNCATE, 1, SIGNIFICANT_DIGITS) == '10000000'
assert exchange.decimal_to_precision('10000001', TRUNCATE, 1, SIGNIFICANT_DIGITS) == '10000000'
assert exchange.decimal_to_precision('19999999', TRUNCATE, 1, SIGNIFICANT_DIGITS) == '10000000'
assert exchange.decimal_to_precision('19999999', ROUND, 1, SIGNIFICANT_DIGITS) == '20000000'
# Precision with PAD_WITH_ZERO edge cases
assert exchange.decimal_to_precision('1', TRUNCATE, 0, DECIMAL_PLACES, PAD_WITH_ZERO) == '1'
assert exchange.decimal_to_precision('1.0', TRUNCATE, 0, DECIMAL_PLACES, PAD_WITH_ZERO) == '1'
assert exchange.decimal_to_precision('1', TRUNCATE, 3, DECIMAL_PLACES, PAD_WITH_ZERO) == '1.000'
assert exchange.decimal_to_precision('1.1', TRUNCATE, 5, DECIMAL_PLACES, PAD_WITH_ZERO) == '1.10000'
# Numbers that are exactly multiples of precision
assert exchange.decimal_to_precision('1.2', TRUNCATE, 0.1, TICK_SIZE) == '1.2'
assert exchange.decimal_to_precision('1.2', ROUND, 0.1, TICK_SIZE) == '1.2'
assert exchange.decimal_to_precision('12', TRUNCATE, 4, TICK_SIZE) == '12'
assert exchange.decimal_to_precision('12', ROUND, 4, TICK_SIZE) == '12'
# Very high precision values
assert exchange.decimal_to_precision('1.123456789012345', TRUNCATE, 15, DECIMAL_PLACES) == '1.123456789012345'
assert exchange.decimal_to_precision('1.123456789012345', TRUNCATE, 10, DECIMAL_PLACES) == '1.123456789'
assert exchange.decimal_to_precision('1.123456789012345', TRUNCATE, 10, DECIMAL_PLACES, PAD_WITH_ZERO) == '1.1234567890'
assert exchange.decimal_to_precision('0.123456789012345', TRUNCATE, 15, SIGNIFICANT_DIGITS) == '0.123456789012345'
# Mixed large and small components
assert exchange.decimal_to_precision('1000000.000001', TRUNCATE, 6, DECIMAL_PLACES) == '1000000.000001'
assert exchange.decimal_to_precision('1000000.000001', TRUNCATE, 5, DECIMAL_PLACES, PAD_WITH_ZERO) == '1000000.00000'
assert exchange.decimal_to_precision('1000000.000001', ROUND, 5, DECIMAL_PLACES, PAD_WITH_ZERO) == '1000000.00000'
# Edge cases around 1.0 boundary for significant digits
assert exchange.decimal_to_precision('0.999999', ROUND, 1, SIGNIFICANT_DIGITS) == '1'
assert exchange.decimal_to_precision('0.999999', ROUND, 2, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '1.0'
assert exchange.decimal_to_precision('0.999999', ROUND, 3, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '1.00'
assert exchange.decimal_to_precision('0.999949', ROUND, 4, SIGNIFICANT_DIGITS) == '0.9999'
assert exchange.decimal_to_precision('0.999951', ROUND, 4, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '1.000'
# ----------------------------------------------------------------------------
# https://github.com/ccxt/ccxt/issues/11765
assert exchange.decimal_to_precision('123456.12345678912', TRUNCATE, 1e-8, TICK_SIZE) == '123456.12345678'
# todo: not sure about below
assert exchange.decimal_to_precision('123456.12345674999', TRUNCATE, 5e-8, TICK_SIZE) == '123456.1234567'
assert exchange.decimal_to_precision('123456.12345674999', TRUNCATE, 5e-8, TICK_SIZE, PAD_WITH_ZERO) == '123456.12345670'
assert exchange.decimal_to_precision('123456.12345675001', TRUNCATE, 5e-8, TICK_SIZE) == '123456.12345675'
assert exchange.decimal_to_precision('123456.50000000001', TRUNCATE, 0.5, TICK_SIZE, PAD_WITH_ZERO) == '123456.5'
assert exchange.decimal_to_precision('123456.49999999999', TRUNCATE, 0.5, TICK_SIZE, PAD_WITH_ZERO) == '123456.0'
assert exchange.decimal_to_precision('123456.12345678912', TRUNCATE, '0.00000001', TICK_SIZE) == '123456.12345678'

View File

@@ -0,0 +1,23 @@
import os
import sys
root = 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 ccxt # noqa: F402
from ccxt.test.exchange.base import test_shared_methods # noqa E402
def test_deep_extend():
exchange = ccxt.Exchange({
'id': 'sampleexchange',
})
assert exchange.parse_to_numeric('1') == 1
return True # dummy for now

View File

@@ -0,0 +1,82 @@
import os
import sys
root = 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 ccxt # noqa: F402
def test_extend():
exchange = ccxt.Exchange({
'id': 'regirock',
})
obj1 = {
'a': 1,
'b': [1, 2],
'c': [{
'test1': 1,
'test2': 1,
}],
'd': None,
'e': 'not_undefined',
'sub': {
'a': 1,
'b': [1, 2],
'c': [{
'test1': 1,
'test2': 2,
}],
'd': None,
'e': 'not_undefined',
'other1': 'x',
},
'other1': 'x',
}
obj2 = {
'a': 2,
'b': [3, 4],
'c': [{
'test1': 2,
'test3': 3,
}],
'd': 'not_undefined',
'e': None,
'sub': {
'a': 2,
'b': [3, 4],
'c': [{
'test1': 2,
'test3': 3,
}],
'd': 'not_undefined',
'e': None,
'other2': 'y',
},
'other2': 'y',
}
# extend
extended = exchange.extend(obj1, obj2)
tbfe_check_extended(extended, True)
def tbfe_check_extended(extended, has_sub):
assert extended['a'] == 2
assert extended['b'][0] == 3
assert extended['b'][1] == 4
assert extended['c'][0]['test1'] == 2
assert not ('test2' in extended['c'][0])
assert extended['c'][0]['test3'] == 3
assert extended['d'] == 'not_undefined'
assert extended['e'] is None
assert extended['other1'] == 'x'
assert extended['other2'] == 'y'
if has_sub:
assert 'sub' in extended

View File

@@ -0,0 +1,49 @@
import os
import sys
root = 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 ccxt # noqa: F402
from ccxt.test.exchange.base import test_shared_methods # noqa E402
def test_filter_by():
exchange = ccxt.Exchange({
'id': 'sampleexchange',
})
sample_array = [{
'foo': 'a',
}, {
'foo': None,
}, {
'foo': 'b',
}, {
'foo': 'a',
'bar': 'b',
}, {
'foo': 'c',
}, {
'foo': 'd',
}, {
'foo': 'b',
}, {
'foo': 'c',
}, {
'foo': 'c',
}]
current_value = exchange.filter_by(sample_array, 'foo', 'a')
stored_value = [{
'foo': 'a',
}, {
'foo': 'a',
'bar': 'b',
}]
test_shared_methods.assert_deep_equal(exchange, None, 'testFilterBy', current_value, stored_value)

View File

@@ -0,0 +1,53 @@
import os
import sys
root = 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 ccxt # noqa: F402
from ccxt.test.exchange.base import test_shared_methods # noqa E402
def test_group_by():
exchange = ccxt.Exchange({
'id': 'sampleexchange',
})
sample_array = [{
'foo': 'a',
}, {
'foo': 'b',
}, {
'foo': 'c',
}, {
'foo': 'b',
}, {
'foo': 'c',
}, {
'foo': 'c',
}]
current_value = exchange.group_by(sample_array, 'foo')
stored_value = {
'a': [{
'foo': 'a',
}],
'b': [{
'foo': 'b',
}, {
'foo': 'b',
}],
'c': [{
'foo': 'c',
}, {
'foo': 'c',
}, {
'foo': 'c',
}],
}
test_shared_methods.assert_deep_equal(exchange, None, 'testGroupBy', current_value, stored_value)

View File

@@ -0,0 +1,93 @@
import os
import sys
root = 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 ccxt # noqa: F402
def helper_test_handle_market_type_and_params():
exchange = ccxt.Exchange({
'id': 'sampleexchange',
'options': {
'defaultType': 'valueFromOptions',
'fetchX': {
'defaultType': 'valueFromMethodOptions',
},
},
})
initial_params = {
'defaultType': 'valueFromParam',
}
market = exchange.safe_market('TEST1/TEST2')
market['type'] = 'spot'
#
# ########### test different variations ###########
#
# case #1, should prevail: param
#
[market_type_1, params1] = exchange.handle_market_type_and_params('fetchX', market, initial_params, 'valueDefault')
assert 'defaultType' in initial_params
assert not ('defaultType' in params1)
assert market_type_1 == 'valueFromParam'
#
# case #2, should prevail: market.type
#
[market_type_2, params2] = exchange.handle_market_type_and_params('fetchX', market, {}, 'valueDefault')
assert market_type_2 == 'spot'
#
# case #3, should prevail: valueDefault
#
[market_type_3, params3] = exchange.handle_market_type_and_params('fetchX', None, {}, 'valueDefault')
assert market_type_3 == 'valueDefault'
#
# case #4, should prevail: method options
#
[market_type_4, params4] = exchange.handle_market_type_and_params('fetchX', None, {})
assert market_type_4 == 'valueFromMethodOptions'
#
# case #5, should prevail: options
#
[market_type_5, params5] = exchange.handle_market_type_and_params('fetchY', None, {}, None)
assert market_type_5 == 'valueFromOptions'
#
# case #6, should prevail: spot (because hardcoded in base)
#
exchange.options['defaultType'] = None
[market_type_6, params6] = exchange.handle_market_type_and_params('fetchY', None, {}, None)
assert market_type_6 == 'spot'
# fake assertion to avoid unused vars
assert params1 is not None or params2 is not None or params3 is not None or params4 is not None or params5 is not None or params6 is not None
def helper_test_handle_network_request():
exchange = ccxt.Exchange({
'id': 'sampleexchange',
'options': {
'networks': {
'XYZ': 'Xyz',
},
},
})
exchange.currencies = exchange.create_safe_dictionary() # todo: initialize in C# base files
currency_code = 'ETH' # todo: in future with complex cases
# no-case
[request1, params1] = exchange.handle_request_network({
'network': 'XYZ',
}, {}, 'chain_id', currency_code, False)
assert not ('network' in params1)
assert 'chain_id' in request1
assert request1['chain_id'] == 'Xyz'
def test_handle_methods():
helper_test_handle_market_type_and_params()
helper_test_handle_network_request()

View File

@@ -0,0 +1,42 @@
import os
import sys
root = 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 ccxt # noqa: F402
from ccxt.base.errors import BadRequest # noqa E402
def test_json():
exchange = ccxt.Exchange({
'id': 'regirock',
})
# Test: object
obj = {
'k': 'v',
}
obj_json = exchange.json(obj)
assert obj_json == '{"k":"v"}'
# Test: list
list = [1, 2]
list_json = exchange.json(list)
assert list_json == '[1,2]'
assert 'GO_SKIP_START'
try:
raise BadRequest('some error')
except Exception as e:
err_string = exchange.json(e)
assert err_string == '{"name":"BadRequest"}'
assert 'GO_SKIP_END'
# Test: json a string
str = 'ccxt, rocks!'
serialized_string = exchange.json(str)
assert serialized_string == '"ccxt, rocks!"'

View File

@@ -0,0 +1,342 @@
import os
import sys
root = 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
from ccxt.base.decimal_to_precision import NO_PADDING # 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 SIGNIFICANT_DIGITS # noqa E402
from ccxt.base.decimal_to_precision import PAD_WITH_ZERO # 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
import ccxt # noqa: F402
from ccxt.base.precise import Precise # noqa E402
def test_number():
exchange = ccxt.Exchange({
'id': 'regirock',
})
# ----------------------------------------------------------------------------
# numberToString
assert exchange.number_to_string(-7.8e-7) == '-0.00000078'
assert exchange.number_to_string(7.8e-7) == '0.00000078'
assert exchange.number_to_string(-0.0000017805) == '-0.0000017805'
assert exchange.number_to_string(0.0000017805) == '0.0000017805'
assert exchange.number_to_string(-7.0005e+27) == '-7000500000000000000000000000'
assert exchange.number_to_string(7.0005e+27) == '7000500000000000000000000000'
assert exchange.number_to_string(-7.9e+27) == '-7900000000000000000000000000'
assert exchange.number_to_string(7e+27) == '7000000000000000000000000000'
assert exchange.number_to_string(7.9e+27) == '7900000000000000000000000000'
assert exchange.number_to_string(-12.345) == '-12.345'
assert exchange.number_to_string(12.345) == '12.345'
assert exchange.number_to_string(0) == '0'
assert exchange.number_to_string(7.35946e+21) == '7359460000000000000000'
assert exchange.number_to_string(1e-8) == '0.00000001'
assert exchange.number_to_string(1e-7) == '0.0000001'
assert exchange.number_to_string(-1e-7) == '-0.0000001'
# ----------------------------------------------------------------------------
# testDecimalToPrecisionTruncationToNDigitsAfterDot
assert exchange.decimal_to_precision('12.3456000', TRUNCATE, 100, DECIMAL_PLACES) == '12.3456'
assert exchange.decimal_to_precision('12.3456', TRUNCATE, 100, DECIMAL_PLACES) == '12.3456'
assert exchange.decimal_to_precision('12.3456', TRUNCATE, 4, DECIMAL_PLACES) == '12.3456'
assert exchange.decimal_to_precision('12.3456', TRUNCATE, 3, DECIMAL_PLACES) == '12.345'
assert exchange.decimal_to_precision('12.3456', TRUNCATE, 2, DECIMAL_PLACES) == '12.34'
assert exchange.decimal_to_precision('12.3456', TRUNCATE, 1, DECIMAL_PLACES) == '12.3'
assert exchange.decimal_to_precision('12.3456', TRUNCATE, 0, DECIMAL_PLACES) == '12'
# ['12.3456', TRUNCATE, -1, DECIMAL_PLACES, '10'], # not yet supported
# ['123.456', TRUNCATE, -2, DECIMAL_PLACES, '120'], # not yet supported
# ['123.456', TRUNCATE, -3, DECIMAL_PLACES, '100'], # not yet supported
assert exchange.decimal_to_precision('0.0000001', TRUNCATE, 8, DECIMAL_PLACES) == '0.0000001'
assert exchange.decimal_to_precision('0.00000001', TRUNCATE, 8, DECIMAL_PLACES) == '0.00000001'
assert exchange.decimal_to_precision('0.000000000', TRUNCATE, 9, DECIMAL_PLACES, PAD_WITH_ZERO) == '0.000000000'
assert exchange.decimal_to_precision('0.000000001', TRUNCATE, 9, DECIMAL_PLACES, PAD_WITH_ZERO) == '0.000000001'
assert exchange.decimal_to_precision('12.3456', TRUNCATE, -1, DECIMAL_PLACES) == '10'
assert exchange.decimal_to_precision('123.456', TRUNCATE, -1, DECIMAL_PLACES) == '120'
assert exchange.decimal_to_precision('123.456', TRUNCATE, -2, DECIMAL_PLACES) == '100'
assert exchange.decimal_to_precision('9.99999', TRUNCATE, -1, DECIMAL_PLACES) == '0'
assert exchange.decimal_to_precision('99.9999', TRUNCATE, -1, DECIMAL_PLACES) == '90'
assert exchange.decimal_to_precision('99.9999', TRUNCATE, -2, DECIMAL_PLACES) == '0'
assert exchange.decimal_to_precision('0', TRUNCATE, 0, DECIMAL_PLACES) == '0'
assert exchange.decimal_to_precision('-0.9', TRUNCATE, 0, DECIMAL_PLACES) == '0'
# ----------------------------------------------------------------------------
# testDecimalToPrecisionTruncationToNSignificantDigits
assert exchange.decimal_to_precision('0.000123456700', TRUNCATE, 100, SIGNIFICANT_DIGITS) == '0.0001234567'
assert exchange.decimal_to_precision('0.0001234567', TRUNCATE, 100, SIGNIFICANT_DIGITS) == '0.0001234567'
assert exchange.decimal_to_precision('0.0001234567', TRUNCATE, 7, SIGNIFICANT_DIGITS) == '0.0001234567'
assert exchange.decimal_to_precision('0.000123456', TRUNCATE, 6, SIGNIFICANT_DIGITS) == '0.000123456'
assert exchange.decimal_to_precision('0.000123456', TRUNCATE, 5, SIGNIFICANT_DIGITS) == '0.00012345'
assert exchange.decimal_to_precision('0.000123456', TRUNCATE, 2, SIGNIFICANT_DIGITS) == '0.00012'
assert exchange.decimal_to_precision('0.000123456', TRUNCATE, 1, SIGNIFICANT_DIGITS) == '0.0001'
assert exchange.decimal_to_precision('123.0000987654', TRUNCATE, 10, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '123.0000987'
assert exchange.decimal_to_precision('123.0000987654', TRUNCATE, 8, SIGNIFICANT_DIGITS) == '123.00009'
assert exchange.decimal_to_precision('123.0000987654', TRUNCATE, 7, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '123.0000'
assert exchange.decimal_to_precision('123.0000987654', TRUNCATE, 6, SIGNIFICANT_DIGITS) == '123'
assert exchange.decimal_to_precision('123.0000987654', TRUNCATE, 5, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '123.00'
assert exchange.decimal_to_precision('123.0000987654', TRUNCATE, 4, SIGNIFICANT_DIGITS) == '123'
assert exchange.decimal_to_precision('123.0000987654', TRUNCATE, 4, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '123.0'
assert exchange.decimal_to_precision('123.0000987654', TRUNCATE, 3, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '123'
assert exchange.decimal_to_precision('123.0000987654', TRUNCATE, 2, SIGNIFICANT_DIGITS) == '120'
assert exchange.decimal_to_precision('123.0000987654', TRUNCATE, 1, SIGNIFICANT_DIGITS) == '100'
assert exchange.decimal_to_precision('123.0000987654', TRUNCATE, 1, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '100'
assert exchange.decimal_to_precision('1234', TRUNCATE, 5, SIGNIFICANT_DIGITS) == '1234'
assert exchange.decimal_to_precision('1234', TRUNCATE, 5, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '1234.0'
assert exchange.decimal_to_precision('1234', TRUNCATE, 4, SIGNIFICANT_DIGITS) == '1234'
assert exchange.decimal_to_precision('1234', TRUNCATE, 4, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '1234'
assert exchange.decimal_to_precision('1234.69', TRUNCATE, 0, SIGNIFICANT_DIGITS) == '0'
assert exchange.decimal_to_precision('1234.69', TRUNCATE, 0, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '0'
# ----------------------------------------------------------------------------
# testDecimalToPrecisionRoundingToNDigitsAfterDot
assert exchange.decimal_to_precision('12.3456000', ROUND, 100, DECIMAL_PLACES) == '12.3456'
assert exchange.decimal_to_precision('12.3456', ROUND, 100, DECIMAL_PLACES) == '12.3456'
assert exchange.decimal_to_precision('12.3456', ROUND, 4, DECIMAL_PLACES) == '12.3456'
assert exchange.decimal_to_precision('12.3456', ROUND, 3, DECIMAL_PLACES) == '12.346'
assert exchange.decimal_to_precision('12.3456', ROUND, 2, DECIMAL_PLACES) == '12.35'
assert exchange.decimal_to_precision('12.3456', ROUND, 1, DECIMAL_PLACES) == '12.3'
assert exchange.decimal_to_precision('12.3456', ROUND, 0, DECIMAL_PLACES) == '12'
# todo:
# ['9.999', ROUND, 3, DECIMAL_PLACES, NO_PADDING, '9.999'],
# ['9.999', ROUND, 2, DECIMAL_PLACES, NO_PADDING, '10'],
# ['9.999', ROUND, 2, DECIMAL_PLACES, PAD_WITH_ZERO, '10.00'],
# ['99.999', ROUND, 2, DECIMAL_PLACES, PAD_WITH_ZERO, '100.00'],
# ['-99.999', ROUND, 2, DECIMAL_PLACES, PAD_WITH_ZERO, '-100.00'],
# ['12.3456', ROUND, -1, DECIMAL_PLACES, NO_PADDING, '10'], # not yet supported
# ['123.456', ROUND, -1, DECIMAL_PLACES, NO_PADDING, '120'], # not yet supported
# ['123.456', ROUND, -2, DECIMAL_PLACES, NO_PADDING, '100'], # not yet supported
# a problematic case in PHP
assert exchange.decimal_to_precision('10000', ROUND, 6, DECIMAL_PLACES) == '10000'
assert exchange.decimal_to_precision('0.00003186', ROUND, 8, DECIMAL_PLACES) == '0.00003186'
assert exchange.decimal_to_precision('12.3456', ROUND, -1, DECIMAL_PLACES) == '10'
assert exchange.decimal_to_precision('123.456', ROUND, -1, DECIMAL_PLACES) == '120'
assert exchange.decimal_to_precision('123.456', ROUND, -2, DECIMAL_PLACES) == '100'
assert exchange.decimal_to_precision('9.99999', ROUND, -1, DECIMAL_PLACES) == '10'
assert exchange.decimal_to_precision('99.9999', ROUND, -1, DECIMAL_PLACES) == '100'
assert exchange.decimal_to_precision('99.9999', ROUND, -2, DECIMAL_PLACES) == '100'
assert exchange.decimal_to_precision('9.999', ROUND, 3, DECIMAL_PLACES) == '9.999'
assert exchange.decimal_to_precision('9.999', ROUND, 2, DECIMAL_PLACES) == '10'
assert exchange.decimal_to_precision('9.999', ROUND, 2, DECIMAL_PLACES, PAD_WITH_ZERO) == '10.00'
assert exchange.decimal_to_precision('99.999', ROUND, 2, DECIMAL_PLACES, PAD_WITH_ZERO) == '100.00'
assert exchange.decimal_to_precision('-99.999', ROUND, 2, DECIMAL_PLACES, PAD_WITH_ZERO) == '-100.00'
# ----------------------------------------------------------------------------
# testDecimalToPrecisionRoundingToNSignificantDigits
assert exchange.decimal_to_precision('0.000123456700', ROUND, 100, SIGNIFICANT_DIGITS) == '0.0001234567'
assert exchange.decimal_to_precision('0.0001234567', ROUND, 100, SIGNIFICANT_DIGITS) == '0.0001234567'
assert exchange.decimal_to_precision('0.0001234567', ROUND, 7, SIGNIFICANT_DIGITS) == '0.0001234567'
assert exchange.decimal_to_precision('0.000123456', ROUND, 6, SIGNIFICANT_DIGITS) == '0.000123456'
assert exchange.decimal_to_precision('0.000123456', ROUND, 5, SIGNIFICANT_DIGITS) == '0.00012346'
assert exchange.decimal_to_precision('0.000123456', ROUND, 4, SIGNIFICANT_DIGITS) == '0.0001235'
assert exchange.decimal_to_precision('0.00012', ROUND, 2, SIGNIFICANT_DIGITS) == '0.00012'
assert exchange.decimal_to_precision('0.0001', ROUND, 1, SIGNIFICANT_DIGITS) == '0.0001'
assert exchange.decimal_to_precision('123.0000987654', ROUND, 7, SIGNIFICANT_DIGITS) == '123.0001'
assert exchange.decimal_to_precision('123.0000987654', ROUND, 6, SIGNIFICANT_DIGITS) == '123'
assert exchange.decimal_to_precision('0.00098765', ROUND, 2, SIGNIFICANT_DIGITS) == '0.00099'
assert exchange.decimal_to_precision('0.00098765', ROUND, 2, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '0.00099'
assert exchange.decimal_to_precision('0.00098765', ROUND, 1, SIGNIFICANT_DIGITS) == '0.001'
assert exchange.decimal_to_precision('0.00098765', ROUND, 10, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '0.0009876500000'
assert exchange.decimal_to_precision('0.098765', ROUND, 1, SIGNIFICANT_DIGITS, PAD_WITH_ZERO) == '0.1'
assert exchange.decimal_to_precision('0', ROUND, 0, SIGNIFICANT_DIGITS) == '0'
assert exchange.decimal_to_precision('-0.123', ROUND, 0, SIGNIFICANT_DIGITS) == '0'
assert exchange.decimal_to_precision('0.00000044', ROUND, 5, SIGNIFICANT_DIGITS) == '0.00000044'
# ----------------------------------------------------------------------------
# testDecimalToPrecisionRoundingToTickSize
assert exchange.decimal_to_precision('0.000123456700', ROUND, 0.00012, TICK_SIZE) == '0.00012'
assert exchange.decimal_to_precision('0.0001234567', ROUND, 0.00013, TICK_SIZE) == '0.00013'
assert exchange.decimal_to_precision('0.0001234567', TRUNCATE, 0.00013, TICK_SIZE) == '0'
assert exchange.decimal_to_precision('101.000123456700', ROUND, 100, TICK_SIZE) == '100'
assert exchange.decimal_to_precision('0.000123456700', ROUND, 100, TICK_SIZE) == '0'
assert exchange.decimal_to_precision('165', TRUNCATE, 110, TICK_SIZE) == '110'
assert exchange.decimal_to_precision('3210', TRUNCATE, 1110, TICK_SIZE) == '2220'
assert exchange.decimal_to_precision('165', ROUND, 110, TICK_SIZE) == '220'
assert exchange.decimal_to_precision('0.000123456789', ROUND, 1.2e-7, TICK_SIZE) == '0.00012348'
assert exchange.decimal_to_precision('0.000123456789', TRUNCATE, 1.2e-7, TICK_SIZE) == '0.00012336'
assert exchange.decimal_to_precision('0.000273398', ROUND, 1e-7, TICK_SIZE) == '0.0002734'
assert exchange.decimal_to_precision('0.00005714', TRUNCATE, 1e-8, TICK_SIZE) == '0.00005714'
# this line causes problems in JS, fix with Precise
# assert (exchange.decimalToPrecision ('0.0000571495257361', TRUNCATE, 0.00000001, TICK_SIZE) === '0.00005714');
assert exchange.decimal_to_precision('0.01', ROUND, 0.0001, TICK_SIZE, PAD_WITH_ZERO) == '0.0100'
assert exchange.decimal_to_precision('0.01', TRUNCATE, 0.0001, TICK_SIZE, PAD_WITH_ZERO) == '0.0100'
assert exchange.decimal_to_precision('-0.000123456789', ROUND, 1.2e-7, TICK_SIZE) == '-0.00012348'
assert exchange.decimal_to_precision('-0.000123456789', TRUNCATE, 1.2e-7, TICK_SIZE) == '-0.00012336'
assert exchange.decimal_to_precision('-165', TRUNCATE, 110, TICK_SIZE) == '-110'
assert exchange.decimal_to_precision('-165', ROUND, 110, TICK_SIZE) == '-220'
assert exchange.decimal_to_precision('-1650', TRUNCATE, 1100, TICK_SIZE) == '-1100'
assert exchange.decimal_to_precision('-1650', ROUND, 1100, TICK_SIZE) == '-2200'
assert exchange.decimal_to_precision('0.0006', TRUNCATE, 0.0001, TICK_SIZE) == '0.0006'
assert exchange.decimal_to_precision('-0.0006', TRUNCATE, 0.0001, TICK_SIZE) == '-0.0006'
assert exchange.decimal_to_precision('0.6', TRUNCATE, 0.2, TICK_SIZE) == '0.6'
assert exchange.decimal_to_precision('-0.6', TRUNCATE, 0.2, TICK_SIZE) == '-0.6'
assert exchange.decimal_to_precision('1.2', ROUND, 0.4, TICK_SIZE) == '1.2'
assert exchange.decimal_to_precision('-1.2', ROUND, 0.4, TICK_SIZE) == '-1.2'
assert exchange.decimal_to_precision('1.2', ROUND, 0.02, TICK_SIZE) == '1.2'
assert exchange.decimal_to_precision('-1.2', ROUND, 0.02, TICK_SIZE) == '-1.2'
assert exchange.decimal_to_precision('44', ROUND, 4.4, TICK_SIZE) == '44'
assert exchange.decimal_to_precision('-44', ROUND, 4.4, TICK_SIZE) == '-44'
assert exchange.decimal_to_precision('44.00000001', ROUND, 4.4, TICK_SIZE) == '44'
assert exchange.decimal_to_precision('-44.00000001', ROUND, 4.4, TICK_SIZE) == '-44'
# https://github.com/ccxt/ccxt/issues/6731
assert exchange.decimal_to_precision('20', TRUNCATE, 1e-8, TICK_SIZE) == '20'
# ----------------------------------------------------------------------------
# testDecimalToPrecisionNegativeNumbers
assert exchange.decimal_to_precision('-0.123456', TRUNCATE, 5, DECIMAL_PLACES) == '-0.12345'
assert exchange.decimal_to_precision('-0.123456', ROUND, 5, DECIMAL_PLACES) == '-0.12346'
# ----------------------------------------------------------------------------
# decimalToPrecision: without dot / trailing dot
assert exchange.decimal_to_precision('123', TRUNCATE, 0) == '123'
assert exchange.decimal_to_precision('123', TRUNCATE, 5, DECIMAL_PLACES) == '123'
assert exchange.decimal_to_precision('123', TRUNCATE, 5, DECIMAL_PLACES, PAD_WITH_ZERO) == '123.00000'
assert exchange.decimal_to_precision('123.', TRUNCATE, 0, DECIMAL_PLACES) == '123'
assert exchange.decimal_to_precision('123.', TRUNCATE, 5, DECIMAL_PLACES, PAD_WITH_ZERO) == '123.00000'
assert exchange.decimal_to_precision('0.', TRUNCATE, 0) == '0'
assert exchange.decimal_to_precision('0.', TRUNCATE, 5, DECIMAL_PLACES, PAD_WITH_ZERO) == '0.00000'
# ----------------------------------------------------------------------------
# decimalToPrecision: rounding for equidistant digits
assert exchange.decimal_to_precision('1.44', ROUND, 1, DECIMAL_PLACES) == '1.4'
assert exchange.decimal_to_precision('1.45', ROUND, 1, DECIMAL_PLACES) == '1.5'
assert exchange.decimal_to_precision('1.45', ROUND, 0, DECIMAL_PLACES) == '1' # not 2
# ----------------------------------------------------------------------------
# negative precision only implemented so far in python
# pretty useless for decimal applications as anything |x| < 5 === 0
# NO_PADDING and PAD_WITH_ZERO are ignored
assert exchange.decimal_to_precision('5', ROUND, -1, DECIMAL_PLACES) == '10'
assert exchange.decimal_to_precision('4.999', ROUND, -1, DECIMAL_PLACES) == '0'
assert exchange.decimal_to_precision('0.0431531423', ROUND, -1, DECIMAL_PLACES) == '0'
assert exchange.decimal_to_precision('-69.3', ROUND, -1, DECIMAL_PLACES) == '-70'
assert exchange.decimal_to_precision('5001', ROUND, -4, DECIMAL_PLACES) == '10000'
assert exchange.decimal_to_precision('4999.999', ROUND, -4, DECIMAL_PLACES) == '0'
assert exchange.decimal_to_precision('69.3', TRUNCATE, -2, DECIMAL_PLACES) == '0'
assert exchange.decimal_to_precision('-69.3', TRUNCATE, -2, DECIMAL_PLACES) == '0'
assert exchange.decimal_to_precision('69.3', TRUNCATE, -1, SIGNIFICANT_DIGITS) == '60'
assert exchange.decimal_to_precision('-69.3', TRUNCATE, -1, SIGNIFICANT_DIGITS) == '-60'
assert exchange.decimal_to_precision('69.3', TRUNCATE, -2, SIGNIFICANT_DIGITS) == '0'
assert exchange.decimal_to_precision('1602000000000000000000', TRUNCATE, 3, SIGNIFICANT_DIGITS) == '1600000000000000000000'
# ----------------------------------------------------------------------------
# decimal_to_precision: stringified precision
assert exchange.decimal_to_precision('-0.000123456789', ROUND, '0.00000012', TICK_SIZE) == '-0.00012348'
assert exchange.decimal_to_precision('-0.000123456789', TRUNCATE, '0.00000012', TICK_SIZE) == '-0.00012336'
assert exchange.decimal_to_precision('-165', TRUNCATE, '110', TICK_SIZE) == '-110'
assert exchange.decimal_to_precision('-165', ROUND, '110', TICK_SIZE) == '-220'
# ----------------------------------------------------------------------------
# testDecimalToPrecisionErrorHandling (todo)
#
# throws (() =>
# decimalToPrecision ('123456.789', TRUNCATE, -2, DECIMAL_PLACES),
# 'negative precision is not yet supported')
#
# throws (() =>
# decimalToPrecision ('foo'),
# "invalid number (contains an illegal character 'f')")
#
# throws (() =>
# decimalToPrecision ('0.01', TRUNCATE, -1, TICK_SIZE),
# "TICK_SIZE cant be used with negative numPrecisionDigits")
# ----------------------------------------------------------------------------
w = '-1.123e-6'
x = '0.00000002'
y = '69696900000'
z = '0'
a = '1e8'
assert Precise.string_mul(x, y) == '1393.938'
assert Precise.string_mul(y, x) == '1393.938'
assert Precise.string_add(x, y) == '69696900000.00000002'
assert Precise.string_add(y, x) == '69696900000.00000002'
assert Precise.string_sub(x, y) == '-69696899999.99999998'
assert Precise.string_sub(y, x) == '69696899999.99999998'
assert Precise.string_div(x, y, 1) == '0'
assert Precise.string_div(x, y) == '0'
assert Precise.string_div(x, y, 19) == '0.0000000000000000002'
assert Precise.string_div(x, y, 20) == '0.00000000000000000028'
assert Precise.string_div(x, y, 21) == '0.000000000000000000286'
assert Precise.string_div(x, y, 22) == '0.0000000000000000002869'
assert Precise.string_div(y, x) == '3484845000000000000'
assert Precise.string_mul(x, w) == '-0.00000000000002246'
assert Precise.string_mul(w, x) == '-0.00000000000002246'
assert Precise.string_add(x, w) == '-0.000001103'
assert Precise.string_add(w, x) == '-0.000001103'
assert Precise.string_sub(x, w) == '0.000001143'
assert Precise.string_sub(w, x) == '-0.000001143'
assert Precise.string_div(x, w) == '-0.017809439002671415'
assert Precise.string_div(w, x) == '-56.15'
assert Precise.string_mul(z, w) == '0'
assert Precise.string_mul(z, x) == '0'
assert Precise.string_mul(z, y) == '0'
assert Precise.string_mul(w, z) == '0'
assert Precise.string_mul(x, z) == '0'
assert Precise.string_mul(y, z) == '0'
assert Precise.string_add(z, w) == '-0.000001123'
assert Precise.string_add(z, x) == '0.00000002'
assert Precise.string_add(z, y) == '69696900000'
assert Precise.string_add(w, z) == '-0.000001123'
assert Precise.string_add(x, z) == '0.00000002'
assert Precise.string_add(y, z) == '69696900000'
assert Precise.string_mul(x, a) == '2'
assert Precise.string_mul(a, x) == '2'
assert Precise.string_mul(y, a) == '6969690000000000000'
assert Precise.string_mul(a, y) == '6969690000000000000'
assert Precise.string_div(y, a) == '696.969'
assert Precise.string_div(y, a, -1) == '690'
assert Precise.string_div(y, a, 0) == '696'
assert Precise.string_div(y, a, 1) == '696.9'
assert Precise.string_div(y, a, 2) == '696.96'
assert Precise.string_div(a, y) == '0.001434784043479695'
assert Precise.string_abs('0') == '0'
assert Precise.string_abs('-0') == '0'
assert Precise.string_abs('-500.1') == '500.1'
assert Precise.string_abs('213') == '213'
assert Precise.string_neg('0') == '0'
assert Precise.string_neg('-0') == '0'
assert Precise.string_neg('-500.1') == '500.1'
assert Precise.string_neg('213') == '-213'
assert Precise.string_mod('57.123', '10') == '7.123'
assert Precise.string_mod('18', '6') == '0'
assert Precise.string_mod('10.1', '0.5') == '0.1'
assert Precise.string_mod('10000000', '5555') == '1000'
assert Precise.string_mod('5550', '120') == '30'
assert Precise.string_equals('1.0000', '1')
assert Precise.string_equals('-0.0', '0')
assert Precise.string_equals('-0.0', '0.0')
assert Precise.string_equals('5.534000', '5.5340')
assert Precise.string_min('1.0000', '2') == '1'
assert Precise.string_min('2', '1.2345') == '1.2345'
assert Precise.string_min('3.1415', '-2') == '-2'
assert Precise.string_min('-3.1415', '-2') == '-3.1415'
assert Precise.string_min('0.000', '-0.0') == '0'
assert Precise.string_max('1.0000', '2') == '2'
assert Precise.string_max('2', '1.2345') == '2'
assert Precise.string_max('3.1415', '-2') == '3.1415'
assert Precise.string_max('-3.1415', '-2') == '-2'
assert Precise.string_max('0.000', '-0.0') == '0'
assert not Precise.string_gt('1.0000', '2')
assert Precise.string_gt('2', '1.2345')
assert Precise.string_gt('3.1415', '-2')
assert not Precise.string_gt('-3.1415', '-2')
assert not Precise.string_gt('3.1415', '3.1415')
assert Precise.string_gt('3.14150000000000000000001', '3.1415')
assert not Precise.string_ge('1.0000', '2')
assert Precise.string_ge('2', '1.2345')
assert Precise.string_ge('3.1415', '-2')
assert not Precise.string_ge('-3.1415', '-2')
assert Precise.string_ge('3.1415', '3.1415')
assert Precise.string_ge('3.14150000000000000000001', '3.1415')
assert Precise.string_lt('1.0000', '2')
assert not Precise.string_lt('2', '1.2345')
assert not Precise.string_lt('3.1415', '-2')
assert Precise.string_lt('-3.1415', '-2')
assert not Precise.string_lt('3.1415', '3.1415')
assert Precise.string_lt('3.1415', '3.14150000000000000000001')
assert Precise.string_le('1.0000', '2')
assert not Precise.string_le('2', '1.2345')
assert not Precise.string_le('3.1415', '-2')
assert Precise.string_le('-3.1415', '-2')
assert Precise.string_le('3.1415', '3.1415')
assert Precise.string_le('3.1415', '3.14150000000000000000001')

View File

@@ -0,0 +1,39 @@
import os
import sys
root = 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 number_to_string # noqa E402
import ccxt # noqa: F402
def test_number_to_string():
exchange = ccxt.Exchange({
'id': 'regirock',
})
# ----------------------------------------------------------------------------
# numberToString
assert exchange.number_to_string(-7.8e-7) == '-0.00000078'
assert exchange.number_to_string(7.8e-7) == '0.00000078'
assert exchange.number_to_string(-0.0000017805) == '-0.0000017805'
assert exchange.number_to_string(0.0000017805) == '0.0000017805'
assert exchange.number_to_string(-7.0005e+27) == '-7000500000000000000000000000'
assert exchange.number_to_string(7.0005e+27) == '7000500000000000000000000000'
assert exchange.number_to_string(-7.9e+27) == '-7900000000000000000000000000'
assert exchange.number_to_string(7e+27) == '7000000000000000000000000000'
assert exchange.number_to_string(7.9e+27) == '7900000000000000000000000000'
assert exchange.number_to_string(-12.345) == '-12.345'
assert exchange.number_to_string(12.345) == '12.345'
assert exchange.number_to_string(0) == '0'
assert exchange.number_to_string(7.35946e+21) == '7359460000000000000000'
assert exchange.number_to_string(1e-8) == '0.00000001'
assert exchange.number_to_string(1e-7) == '0.0000001'
assert exchange.number_to_string(-1e-7) == '-0.0000001'

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.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 ccxt # noqa: F402
from ccxt.test.exchange.base import test_shared_methods # noqa E402
def test_omit():
exchange = ccxt.Exchange({
'id': 'sampleexchange',
})
test_shared_methods.assert_deep_equal(exchange, None, 'testOmit', exchange.omit({}, 'foo'), {})
test_shared_methods.assert_deep_equal(exchange, None, 'testOmit', exchange.omit({
'foo': 2,
}, 'foo'), {})
test_shared_methods.assert_deep_equal(exchange, None, 'testOmit', exchange.omit({
'foo': 2,
'bar': 3,
}, 'foo'), {
'bar': 3,
})
test_shared_methods.assert_deep_equal(exchange, None, 'testOmit', exchange.omit({
'foo': 2,
'bar': 3,
}, ['foo']), {
'bar': 3,
})

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.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 ccxt # noqa: F402
def test_parse_precision():
exchange = ccxt.Exchange({
'id': 'sampleexchange',
})
assert exchange.parse_precision('15') == '0.000000000000001'
assert exchange.parse_precision('1') == '0.1'
assert exchange.parse_precision('0') == '1'
assert exchange.parse_precision('-5') == '100000'

View File

@@ -0,0 +1,116 @@
import os
import sys
root = 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
def test_precise():
w = '-1.123e-6'
x = '0.00000002'
y = '69696900000'
z = '0'
a = '1e8'
assert Precise.string_mul(x, y) == '1393.938'
assert Precise.string_mul(y, x) == '1393.938'
assert Precise.string_add(x, y) == '69696900000.00000002'
assert Precise.string_add(y, x) == '69696900000.00000002'
assert Precise.string_sub(x, y) == '-69696899999.99999998'
assert Precise.string_sub(y, x) == '69696899999.99999998'
assert Precise.string_div(x, y, 1) == '0'
assert Precise.string_div(x, y) == '0'
assert Precise.string_div(x, y, 19) == '0.0000000000000000002'
assert Precise.string_div(x, y, 20) == '0.00000000000000000028'
assert Precise.string_div(x, y, 21) == '0.000000000000000000286'
assert Precise.string_div(x, y, 22) == '0.0000000000000000002869'
assert Precise.string_div(y, x) == '3484845000000000000'
assert Precise.string_mul(x, w) == '-0.00000000000002246'
assert Precise.string_mul(w, x) == '-0.00000000000002246'
assert Precise.string_add(x, w) == '-0.000001103'
assert Precise.string_add(w, x) == '-0.000001103'
assert Precise.string_sub(x, w) == '0.000001143'
assert Precise.string_sub(w, x) == '-0.000001143'
assert Precise.string_div(x, w) == '-0.017809439002671415'
assert Precise.string_div(w, x) == '-56.15'
assert Precise.string_mul(z, w) == '0'
assert Precise.string_mul(z, x) == '0'
assert Precise.string_mul(z, y) == '0'
assert Precise.string_mul(w, z) == '0'
assert Precise.string_mul(x, z) == '0'
assert Precise.string_mul(y, z) == '0'
assert Precise.string_add(z, w) == '-0.000001123'
assert Precise.string_add(z, x) == '0.00000002'
assert Precise.string_add(z, y) == '69696900000'
assert Precise.string_add(w, z) == '-0.000001123'
assert Precise.string_add(x, z) == '0.00000002'
assert Precise.string_add(y, z) == '69696900000'
assert Precise.string_mul(x, a) == '2'
assert Precise.string_mul(a, x) == '2'
assert Precise.string_mul(y, a) == '6969690000000000000'
assert Precise.string_mul(a, y) == '6969690000000000000'
assert Precise.string_div(y, a) == '696.969'
assert Precise.string_div(y, a, -1) == '690'
assert Precise.string_div(y, a, 0) == '696'
assert Precise.string_div(y, a, 1) == '696.9'
assert Precise.string_div(y, a, 2) == '696.96'
assert Precise.string_div(a, y) == '0.001434784043479695'
assert Precise.string_abs('0') == '0'
assert Precise.string_abs('-0') == '0'
assert Precise.string_abs('-500.1') == '500.1'
assert Precise.string_abs('213') == '213'
assert Precise.string_neg('0') == '0'
assert Precise.string_neg('-0') == '0'
assert Precise.string_neg('-500.1') == '500.1'
assert Precise.string_neg('213') == '-213'
assert Precise.string_mod('57.123', '10') == '7.123'
assert Precise.string_mod('18', '6') == '0'
assert Precise.string_mod('10.1', '0.5') == '0.1'
assert Precise.string_mod('10000000', '5555') == '1000'
assert Precise.string_mod('5550', '120') == '30'
assert Precise.string_equals('1.0000', '1')
assert Precise.string_equals('-0.0', '0')
assert Precise.string_equals('-0.0', '0.0')
assert Precise.string_equals('5.534000', '5.5340')
assert Precise.string_min('1.0000', '2') == '1'
assert Precise.string_min('2', '1.2345') == '1.2345'
assert Precise.string_min('3.1415', '-2') == '-2'
assert Precise.string_min('-3.1415', '-2') == '-3.1415'
assert Precise.string_min('0.000', '-0.0') == '0'
assert Precise.string_max('1.0000', '2') == '2'
assert Precise.string_max('2', '1.2345') == '2'
assert Precise.string_max('3.1415', '-2') == '3.1415'
assert Precise.string_max('-3.1415', '-2') == '-2'
assert Precise.string_max('0.000', '-0.0') == '0'
assert not Precise.string_gt('1.0000', '2')
assert Precise.string_gt('2', '1.2345')
assert Precise.string_gt('3.1415', '-2')
assert not Precise.string_gt('-3.1415', '-2')
assert not Precise.string_gt('3.1415', '3.1415')
assert Precise.string_gt('3.14150000000000000000001', '3.1415')
assert not Precise.string_ge('1.0000', '2')
assert Precise.string_ge('2', '1.2345')
assert Precise.string_ge('3.1415', '-2')
assert not Precise.string_ge('-3.1415', '-2')
assert Precise.string_ge('3.1415', '3.1415')
assert Precise.string_ge('3.14150000000000000000001', '3.1415')
assert Precise.string_lt('1.0000', '2')
assert not Precise.string_lt('2', '1.2345')
assert not Precise.string_lt('3.1415', '-2')
assert Precise.string_lt('-3.1415', '-2')
assert not Precise.string_lt('3.1415', '3.1415')
assert Precise.string_lt('3.1415', '3.14150000000000000000001')
assert Precise.string_le('1.0000', '2')
assert not Precise.string_le('2', '1.2345')
assert not Precise.string_le('3.1415', '-2')
assert Precise.string_le('-3.1415', '-2')
assert Precise.string_le('3.1415', '3.1415')
assert Precise.string_le('3.1415', '3.14150000000000000000001')

View File

@@ -0,0 +1,74 @@
import os
import sys
root = 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 ccxt # noqa: F402
def test_remove_repeated_elements_from_array():
exchange = ccxt.Exchange({
'id': 'sampleexchange',
})
# CASE 1: by id
array1 = [{
'id': 'a',
'timestamp': 1,
'uniq': 'x1',
}, {
'id': 'b',
'timestamp': 2,
'uniq': 'x2',
}, {
'id': 'a',
'timestamp': 3,
'uniq': 'x3',
}, {
'id': 'c',
'timestamp': 1,
'uniq': 'x4',
}]
res1 = exchange.remove_repeated_elements_from_array(array1, False)
res1_length = len(res1)
assert res1_length == 3
assert res1[0]['uniq'] == 'x1'
assert res1[1]['uniq'] == 'x2'
assert res1[2]['uniq'] == 'x4'
# CASE 2: by timestamp
array2 = [{
'id': None,
'timestamp': 1,
'uniq': 'x1',
}, {
'id': None,
'timestamp': 2,
'uniq': 'x2',
}, {
'id': None,
'timestamp': 1,
'uniq': 'x3',
}, {
'id': None,
'timestamp': 3,
'uniq': 'x4',
}]
res2 = exchange.remove_repeated_elements_from_array(array2, True)
res2_length = len(res2)
assert res2_length == 3
assert res2[0]['uniq'] == 'x1'
assert res2[1]['uniq'] == 'x2'
assert res2[2]['uniq'] == 'x4'
# CASE 3: by timestamp index (used in ohlcv)
array3 = [[555, 1, 1, 'x1'], [666, 1, 1, 'x2'], [555, 1, 1, 'x3']]
res3 = exchange.remove_repeated_elements_from_array(array3, True)
assert len(res3) == 2
assert res3[0][3] == 'x1'
assert res3[1][3] == 'x2'

View File

@@ -0,0 +1,275 @@
import os
import sys
root = 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 ccxt # noqa: F402
def equals(a, b):
return a == b
def test_safe_methods():
exchange = ccxt.Exchange({
'id': 'regirock',
})
input_dict = {
'i': 1,
'f': 0.123,
'bool': True,
'list': [1, 2, 3],
'dict': {
'a': 1,
},
'str': 'heLlo',
'strNumber': '3',
'zeroNumeric': 0,
'zeroString': '0',
'undefined': None,
'emptyString': '',
'floatNumeric': 0.123,
'floatString': '0.123',
}
input_list = ['Hi', 2]
compare_dict = {
'a': 1,
}
compare_list = [1, 2, 3]
factor = 10
# safeValue
assert exchange.safe_value(input_dict, 'i') == 1
assert exchange.safe_value(input_dict, 'f') == 0.123
assert exchange.safe_value(input_dict, 'bool')
assert equals(exchange.safe_value(input_dict, 'list'), compare_list)
dict_object = exchange.safe_value(input_dict, 'dict')
assert equals(dict_object, compare_dict)
assert exchange.safe_value(input_dict, 'str') == 'heLlo'
assert exchange.safe_value(input_dict, 'strNumber') == '3'
assert exchange.safe_value(input_list, 0) == 'Hi'
# safeValue2
assert exchange.safe_value_2(input_dict, 'a', 'i') == 1
assert exchange.safe_value_2(input_dict, 'a', 'f') == 0.123
assert exchange.safe_value_2(input_dict, 'a', 'bool')
assert equals(exchange.safe_value_2(input_dict, 'a', 'list'), compare_list)
dict_object = exchange.safe_value_2(input_dict, 'a', 'dict')
assert equals(dict_object, compare_dict)
assert exchange.safe_value_2(input_dict, 'a', 'str') == 'heLlo'
assert exchange.safe_value_2(input_dict, 'a', 'strNumber') == '3'
assert exchange.safe_value_2(input_list, 2, 0) == 'Hi'
# safeValueN
assert exchange.safe_value_n(input_dict, ['a', 'b', 'i']) == 1
assert exchange.safe_value_n(input_dict, ['a', 'b', 'f']) == 0.123
assert exchange.safe_value_n(input_dict, ['a', 'b', 'bool'])
assert equals(exchange.safe_value_n(input_dict, ['a', 'b', 'list']), compare_list)
dict_object = exchange.safe_value_n(input_dict, ['a', 'b', 'dict'])
assert equals(dict_object, compare_dict)
assert exchange.safe_value_n(input_dict, ['a', 'b', 'str']) == 'heLlo'
assert exchange.safe_value_n(input_dict, ['a', 'b', 'strNumber']) == '3'
assert exchange.safe_value_n(input_list, [3, 2, 0]) == 'Hi'
# safeDict
dict_object = exchange.safe_dict(input_dict, 'dict')
assert equals(dict_object, compare_dict)
list_object = exchange.safe_dict(input_dict, 'list')
assert list_object is None
assert exchange.safe_dict(input_list, 1) is None
# safeDict2
dict_object = exchange.safe_dict_2(input_dict, 'a', 'dict')
assert equals(dict_object, compare_dict)
list_object = exchange.safe_dict_2(input_dict, 'a', 'list')
assert list_object is None
# @ts-expect-error
assert exchange.safe_dict_2(input_list, 2, 1) is None
# safeDictN
dict_object = exchange.safe_dict_n(input_dict, ['a', 'b', 'dict'])
assert equals(dict_object, compare_dict)
list_object = exchange.safe_dict_n(input_dict, ['a', 'b', 'list'])
assert list_object is None
assert exchange.safe_dict_n(input_list, [3, 2, 1]) is None
# safeList
list_object = exchange.safe_list(input_dict, 'list')
assert equals(dict_object, compare_dict)
assert exchange.safe_list(input_dict, 'dict') is None
assert exchange.safe_list(input_list, 1) is None
# safeList2
list_object = exchange.safe_list_2(input_dict, 'a', 'list')
assert equals(dict_object, compare_dict)
assert exchange.safe_list_2(input_dict, 'a', 'dict') is None
# @ts-expect-error
assert exchange.safe_list_2(input_list, 2, 1) is None
# safeListN
list_object = exchange.safe_list_n(input_dict, ['a', 'b', 'list'])
assert equals(dict_object, compare_dict)
assert exchange.safe_list_n(input_dict, ['a', 'b', 'dict']) is None
assert exchange.safe_list_n(input_list, [3, 2, 1]) is None
# safeString
assert exchange.safe_string(input_dict, 'i') == '1'
assert exchange.safe_string(input_dict, 'f') == '0.123'
# assert (exchange.safeString (inputDict, 'bool') === 'true'); returns True in python and 'true' in js
assert exchange.safe_string(input_dict, 'str') == 'heLlo'
assert exchange.safe_string(input_dict, 'strNumber') == '3'
assert exchange.safe_string(input_list, 0) == 'Hi'
# safeString2
assert exchange.safe_string_2(input_dict, 'a', 'i') == '1'
assert exchange.safe_string_2(input_dict, 'a', 'f') == '0.123'
assert exchange.safe_string_2(input_dict, 'a', 'str') == 'heLlo'
assert exchange.safe_string_2(input_dict, 'a', 'strNumber') == '3'
assert exchange.safe_string_2(input_list, 2, 0) == 'Hi'
# safeStringN
assert exchange.safe_string_n(input_dict, ['a', 'b', 'i']) == '1'
assert exchange.safe_string_n(input_dict, ['a', 'b', 'f']) == '0.123'
assert exchange.safe_string_n(input_dict, ['a', 'b', 'str']) == 'heLlo'
assert exchange.safe_string_n(input_dict, ['a', 'b', 'strNumber']) == '3'
assert exchange.safe_string_n(input_list, [3, 2, 0]) == 'Hi'
# safeStringLower
assert exchange.safe_string_lower(input_dict, 'i') == '1'
assert exchange.safe_string_lower(input_dict, 'f') == '0.123'
assert exchange.safe_string_lower(input_dict, 'str') == 'hello'
assert exchange.safe_string_lower(input_dict, 'strNumber') == '3'
assert exchange.safe_string_lower(input_list, 0) == 'hi'
# safeStringLower2
assert exchange.safe_string_lower_2(input_dict, 'a', 'i') == '1'
assert exchange.safe_string_lower_2(input_dict, 'a', 'f') == '0.123'
assert exchange.safe_string_lower_2(input_dict, 'a', 'str') == 'hello'
assert exchange.safe_string_lower_2(input_dict, 'a', 'strNumber') == '3'
assert exchange.safe_string_lower_2(input_list, 2, 0) == 'hi'
# safeStringLowerN
assert exchange.safe_string_lower_n(input_dict, ['a', 'b', 'i']) == '1'
assert exchange.safe_string_lower_n(input_dict, ['a', 'b', 'f']) == '0.123'
assert exchange.safe_string_lower_n(input_dict, ['a', 'b', 'str']) == 'hello'
assert exchange.safe_string_lower_n(input_dict, ['a', 'b', 'strNumber']) == '3'
assert exchange.safe_string_lower_n(input_list, [3, 2, 0]) == 'hi'
# safeStringUpper
assert exchange.safe_string_upper(input_dict, 'i') == '1'
assert exchange.safe_string_upper(input_dict, 'f') == '0.123'
assert exchange.safe_string_upper(input_dict, 'str') == 'HELLO'
assert exchange.safe_string_upper(input_dict, 'strNumber') == '3'
assert exchange.safe_string_upper(input_list, 0) == 'HI'
# safeStringUpper2
assert exchange.safe_string_upper_2(input_dict, 'a', 'i') == '1'
assert exchange.safe_string_upper_2(input_dict, 'a', 'f') == '0.123'
assert exchange.safe_string_upper_2(input_dict, 'a', 'str') == 'HELLO'
assert exchange.safe_string_upper_2(input_dict, 'a', 'strNumber') == '3'
assert exchange.safe_string_upper_2(input_list, 2, 0) == 'HI'
# safeStringUpperN
assert exchange.safe_string_upper_n(input_dict, ['a', 'b', 'i']) == '1'
assert exchange.safe_string_upper_n(input_dict, ['a', 'b', 'f']) == '0.123'
assert exchange.safe_string_upper_n(input_dict, ['a', 'b', 'str']) == 'HELLO'
assert exchange.safe_string_upper_n(input_dict, ['a', 'b', 'strNumber']) == '3'
assert exchange.safe_string_upper_n(input_list, [3, 2, 0]) == 'HI'
# safeInteger
assert exchange.safe_integer(input_dict, 'i') == 1
assert exchange.safe_integer(input_dict, 'f') == 0
assert exchange.safe_integer(input_dict, 'strNumber') == 3
assert exchange.safe_integer(input_list, 1) == 2
# safeInteger2
assert exchange.safe_integer_2(input_dict, 'a', 'i') == 1
assert exchange.safe_integer_2(input_dict, 'a', 'f') == 0
assert exchange.safe_integer_2(input_dict, 'a', 'strNumber') == 3
assert exchange.safe_integer_2(input_list, 2, 1) == 2
# safeIntegerN
assert exchange.safe_integer_n(input_dict, ['a', 'b', 'i']) == 1
assert exchange.safe_integer_n(input_dict, ['a', 'b', 'f']) == 0
assert exchange.safe_integer_n(input_dict, ['a', 'b', 'strNumber']) == 3
assert exchange.safe_integer_n(input_list, [3, 2, 1]) == 2
# safeIntegerOmitZero
assert exchange.safe_integer_omit_zero(input_dict, 'i') == 1
assert exchange.safe_integer_omit_zero(input_dict, 'f') is None
assert exchange.safe_integer_omit_zero(input_dict, 'strNumber') == 3
assert exchange.safe_integer_omit_zero(input_list, 1) == 2
# safeIntegerProduct
assert exchange.safe_integer_product(input_dict, 'i', factor) == 10
assert exchange.safe_integer_product(input_dict, 'f', factor) == 1 # NB the result is 1
assert exchange.safe_integer_product(input_dict, 'strNumber', factor) == 30
assert exchange.safe_integer_product(input_list, 1, factor) == 20
# safeIntegerProduct2
assert exchange.safe_integer_product_2(input_dict, 'a', 'i', factor) == 10
assert exchange.safe_integer_product_2(input_dict, 'a', 'f', factor) == 1 # NB the result is 1
assert exchange.safe_integer_product_2(input_dict, 'a', 'strNumber', factor) == 30
assert exchange.safe_integer_product_2(input_list, 2, 1, factor) == 20
# safeIntegerProductN
assert exchange.safe_integer_product_n(input_dict, ['a', 'b', 'i'], factor) == 10
assert exchange.safe_integer_product_n(input_dict, ['a', 'b', 'f'], factor) == 1 # NB the result is 1
assert exchange.safe_integer_product_n(input_dict, ['a', 'b', 'strNumber'], factor) == 30
assert exchange.safe_integer_product_n(input_list, [3, 2, 1], factor) == 20
# safeTimestamp
assert exchange.safe_timestamp(input_dict, 'i') == 1000
assert exchange.safe_timestamp(input_dict, 'f') == 123
assert exchange.safe_timestamp(input_dict, 'strNumber') == 3000
assert exchange.safe_timestamp(input_list, 1) == 2000
# safeTimestamp2
assert exchange.safe_timestamp_2(input_dict, 'a', 'i') == 1000
assert exchange.safe_timestamp_2(input_dict, 'a', 'f') == 123
assert exchange.safe_timestamp_2(input_dict, 'a', 'strNumber') == 3000
assert exchange.safe_timestamp_2(input_list, 2, 1) == 2000
# safeTimestampN
assert exchange.safe_timestamp_n(input_dict, ['a', 'b', 'i']) == 1000
assert exchange.safe_timestamp_n(input_dict, ['a', 'b', 'f']) == 123
assert exchange.safe_timestamp_n(input_dict, ['a', 'b', 'strNumber']) == 3000
assert exchange.safe_timestamp_n(input_list, [3, 2, 1]) == 2000
# safeFloat
# @ts-expect-error
assert exchange.safe_float(input_dict, 'i') == float(1)
assert exchange.safe_float(input_dict, 'f') == 0.123
# @ts-expect-error
assert exchange.safe_float(input_dict, 'strNumber') == float(3)
# @ts-expect-error
assert exchange.safe_float(input_list, 1) == float(2)
# safeFloat2
# @ts-expect-error
assert exchange.safe_float_2(input_dict, 'a', 'i') == float(1)
assert exchange.safe_float_2(input_dict, 'a', 'f') == 0.123
# @ts-expect-error
assert exchange.safe_float_2(input_dict, 'a', 'strNumber') == float(3)
# @ts-expect-error
assert exchange.safe_float_2(input_list, 2, 1) == float(2)
# safeFloatN
# @ts-expect-error
assert exchange.safe_float_n(input_dict, ['a', 'b', 'i']) == float(1)
assert exchange.safe_float_n(input_dict, ['a', 'b', 'f']) == 0.123
# @ts-expect-error
assert exchange.safe_float_n(input_dict, ['a', 'b', 'strNumber']) == float(3)
# @ts-expect-error
assert exchange.safe_float_n(input_list, [3, 2, 1]) == float(2)
# safeNumber
assert exchange.safe_number(input_dict, 'i') == exchange.parse_number(1)
assert exchange.safe_number(input_dict, 'f') == exchange.parse_number(0.123)
assert exchange.safe_number(input_dict, 'strNumber') == exchange.parse_number(3)
assert exchange.safe_number(input_list, 1) == exchange.parse_number(2)
assert exchange.safe_number(input_list, 'bool') is None
assert exchange.safe_number(input_list, 'list') is None
assert exchange.safe_number(input_list, 'dict') is None
assert exchange.safe_number(input_list, 'str') is None
# safeNumber2
assert exchange.safe_number_2(input_dict, 'a', 'i') == exchange.parse_number(1)
assert exchange.safe_number_2(input_dict, 'a', 'f') == exchange.parse_number(0.123)
assert exchange.safe_number_2(input_dict, 'a', 'strNumber') == exchange.parse_number(3)
assert exchange.safe_number_2(input_list, 2, 1) == exchange.parse_number(2)
# safeNumberN
assert exchange.safe_number_n(input_dict, ['a', 'b', 'i']) == exchange.parse_number(1)
assert exchange.safe_number_n(input_dict, ['a', 'b', 'f']) == exchange.parse_number(0.123)
assert exchange.safe_number_n(input_dict, ['a', 'b', 'strNumber']) == exchange.parse_number(3)
assert exchange.safe_number_n(input_list, [3, 2, 1]) == exchange.parse_number(2)
# safeBool
assert exchange.safe_bool(input_dict, 'bool')
assert exchange.safe_bool(input_list, 1) is None
# safeBool2
assert exchange.safe_bool_2(input_dict, 'a', 'bool')
assert exchange.safe_bool_2(input_list, 2, 1) is None
# safeBoolN
assert exchange.safe_bool_n(input_dict, ['a', 'b', 'bool'])
assert exchange.safe_bool_n(input_list, [3, 2, 1]) is None
# safeNumberOmitZero
assert exchange.safe_number_omit_zero(input_dict, 'zeroNumeric') is None
assert exchange.safe_number_omit_zero(input_dict, 'zeroString') is None
assert exchange.safe_number_omit_zero(input_dict, 'undefined') is None
assert exchange.safe_number_omit_zero(input_dict, 'emptyString') is None
assert exchange.safe_number_omit_zero(input_dict, 'floatNumeric') is not None
assert exchange.safe_number_omit_zero(input_dict, 'floatString') is not None

View File

@@ -0,0 +1,137 @@
import os
import sys
root = 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 ccxt # noqa: F402
from ccxt.base.precise import Precise # noqa E402
def precise_equal_str(exchange, result, key, expected):
return Precise.string_eq(exchange.safe_string(result, key), expected)
def test_safe_ticker():
exchange = ccxt.Exchange({
'id': 'sampleexchange',
})
# CASE 1 - by open
ticker1 = {
'open': 5,
'change': 1,
}
result1 = exchange.safe_ticker(ticker1)
assert precise_equal_str(exchange, result1, 'percentage', '20.0')
assert precise_equal_str(exchange, result1, 'average', '5.5')
assert precise_equal_str(exchange, result1, 'close', '6.0')
assert precise_equal_str(exchange, result1, 'last', '6.0')
# CASE 2 - by open
ticker2 = {
'open': 5,
'percentage': 20,
}
result2 = exchange.safe_ticker(ticker2)
assert precise_equal_str(exchange, result2, 'change', '1.0')
assert precise_equal_str(exchange, result2, 'average', '5.5')
assert precise_equal_str(exchange, result2, 'close', '6.0')
assert precise_equal_str(exchange, result2, 'last', '6.0')
# CASE 3 - by close
ticker3 = {
'close': 6,
'change': 1,
}
result3 = exchange.safe_ticker(ticker3)
assert precise_equal_str(exchange, result3, 'open', '5.0')
assert precise_equal_str(exchange, result3, 'percentage', '20.0')
assert precise_equal_str(exchange, result3, 'average', '5.5')
assert precise_equal_str(exchange, result3, 'last', '6.0')
# CASE 4 - by close
ticker4 = {
'close': 6,
'percentage': 20,
}
result4 = exchange.safe_ticker(ticker4)
assert precise_equal_str(exchange, result4, 'open', '5.0')
assert precise_equal_str(exchange, result4, 'change', '1.0')
assert precise_equal_str(exchange, result4, 'average', '5.5')
assert precise_equal_str(exchange, result4, 'last', '6.0')
# CASE 5 - by average
ticker5 = {
'average': 5.5,
'percentage': 20,
}
result5 = exchange.safe_ticker(ticker5)
assert precise_equal_str(exchange, result5, 'open', '5.0')
assert precise_equal_str(exchange, result5, 'change', '1.0')
assert precise_equal_str(exchange, result5, 'close', '6.0')
assert precise_equal_str(exchange, result5, 'last', '6.0')
# CASE 6
ticker6 = {
'average': 5.5,
'change': 1,
}
result6 = exchange.safe_ticker(ticker6)
assert precise_equal_str(exchange, result6, 'open', '5.0')
assert precise_equal_str(exchange, result6, 'percentage', '20.0')
assert precise_equal_str(exchange, result6, 'close', '6.0')
assert precise_equal_str(exchange, result6, 'last', '6.0')
# CASE 7 - by open and close
ticker7 = {
'open': 5,
'close': 6,
}
result7 = exchange.safe_ticker(ticker7)
assert precise_equal_str(exchange, result7, 'change', '1.0')
assert precise_equal_str(exchange, result7, 'percentage', '20.0')
assert precise_equal_str(exchange, result7, 'average', '5.5')
assert precise_equal_str(exchange, result7, 'last', '6.0')
# CASE 8 - full ticker
ticker8 = {
'open': 5,
'close': 6,
'last': 6,
'high': 6.5,
'low': 4.5,
'average': 5.5,
'bid': 5.9,
'bidVolume': 100,
'ask': 6.1,
'askVolume': 200,
'change': 1,
'percentage': 20,
'vwap': 5.75,
'baseVolume': 1000,
'quoteVolume': 5750,
'previousClose': 4.9,
'indexPrice': 5.8,
'markPrice': 5.9,
'info': {},
}
result8 = exchange.safe_ticker(ticker8)
assert precise_equal_str(exchange, result8, 'open', '5.0')
assert precise_equal_str(exchange, result8, 'high', '6.5')
assert precise_equal_str(exchange, result8, 'low', '4.5')
assert precise_equal_str(exchange, result8, 'close', '6.0')
assert precise_equal_str(exchange, result8, 'last', '6.0')
assert precise_equal_str(exchange, result8, 'change', '1.0')
assert precise_equal_str(exchange, result8, 'percentage', '20.0')
assert precise_equal_str(exchange, result8, 'average', '5.5')
assert precise_equal_str(exchange, result8, 'bid', '5.9')
assert precise_equal_str(exchange, result8, 'bidVolume', '100.0')
assert precise_equal_str(exchange, result8, 'ask', '6.1')
assert precise_equal_str(exchange, result8, 'askVolume', '200.0')
assert precise_equal_str(exchange, result8, 'vwap', '5.75')
assert precise_equal_str(exchange, result8, 'baseVolume', '1000.0')
assert precise_equal_str(exchange, result8, 'quoteVolume', '5750.0')
assert precise_equal_str(exchange, result8, 'previousClose', '4.9')
assert precise_equal_str(exchange, result8, 'indexPrice', '5.8')
assert precise_equal_str(exchange, result8, 'markPrice', '5.9')
assert result8['info'] is not None

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.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 ccxt # noqa: F402
from ccxt.test.exchange.base import test_shared_methods # noqa E402
def test_sort():
# todo: other argument checks
exchange = ccxt.Exchange({
'id': 'sampleexchange',
})
arr = ['b', 'a', 'c', 'd']
sorted_arr = exchange.sort(arr)
test_shared_methods.assert_deep_equal(exchange, None, 'sort', sorted_arr, ['a', 'b', 'c', 'd'])

View File

@@ -0,0 +1,65 @@
import os
import sys
root = 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 ccxt # noqa: F402
from ccxt.test.exchange.base import test_shared_methods # noqa E402
def test_sort_by():
# todo: other argument checks
exchange = ccxt.Exchange({
'id': 'sampleexchange',
})
arr = [{
'x': 5,
}, {
'x': 2,
}, {
'x': 4,
}, {
'x': 0,
}, {
'x': 1,
}, {
'x': 3,
}]
new_array = exchange.sort_by(arr, 'x')
test_shared_methods.assert_deep_equal(exchange, None, 'sortBy', new_array, [{
'x': 0,
}, {
'x': 1,
}, {
'x': 2,
}, {
'x': 3,
}, {
'x': 4,
}, {
'x': 5,
}])
new_array_descending = exchange.sort_by(arr, 'x', True)
test_shared_methods.assert_deep_equal(exchange, None, 'sortBy', new_array_descending, [{
'x': 5,
}, {
'x': 4,
}, {
'x': 3,
}, {
'x': 2,
}, {
'x': 1,
}, {
'x': 0,
}])
empty_array = exchange.sort_by([], 'x')
test_shared_methods.assert_deep_equal(exchange, None, 'sortBy', empty_array, [])

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.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 ccxt # noqa: F402
from ccxt.test.exchange.base import test_shared_methods # noqa E402
def test_sum():
exchange = ccxt.Exchange({
'id': 'sampleexchange',
})
# testSharedMethods.assertDeepEqual (exchange, undefined, 'testSum', exchange.sum (), undefined); # todo: bugs in py
test_shared_methods.assert_deep_equal(exchange, None, 'testSum', exchange.sum(2), 2)
test_shared_methods.assert_deep_equal(exchange, None, 'testSum', exchange.sum(2, 30, 400), 432)

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.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_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.base.test_decimal_to_precision import test_decimal_to_precision # noqa E402
from ccxt.test.base.test_number_to_string import test_number_to_string # noqa E402
from ccxt.test.base.test_precise import test_precise # noqa E402
from ccxt.test.base.test_datetime import test_datetime # noqa E402
from ccxt.test.base.test_cryptography import test_cryptography # noqa E402
from ccxt.test.base.test_extend import test_extend # noqa E402
from ccxt.test.base.test_deep_extend import test_deep_extend # noqa E402
from ccxt.test.base.language_specific.test_language_specific import test_language_specific # noqa E402
from ccxt.test.base.test_safe_methods import test_safe_methods # noqa E402
from ccxt.test.base.test_safe_ticker import test_safe_ticker # noqa E402
from ccxt.test.base.test_sort_by import test_sort_by # noqa E402
from ccxt.test.base.test_sum import test_sum # noqa E402
from ccxt.test.base.test_omit import test_omit # noqa E402
from ccxt.test.base.test_group_by import test_group_by # noqa E402
from ccxt.test.base.test_filter_by import test_filter_by # noqa E402
from ccxt.test.base.test_after_constructor import test_after_constructor # noqa E402
from ccxt.test.base.test_handle_methods import test_handle_methods # noqa E402
from ccxt.test.base.test_remove_repeated_elements_from_array import test_remove_repeated_elements_from_array # noqa E402
from ccxt.test.base.test_parse_precision import test_parse_precision # noqa E402
from ccxt.test.base.test_arrays_concat import test_arrays_concat # noqa E402
def base_tests_init():
test_language_specific()
test_after_constructor()
test_extend()
test_deep_extend()
test_cryptography()
test_datetime()
test_decimal_to_precision()
test_number_to_string()
test_precise()
test_safe_methods()
test_safe_ticker()
# testJson ();
test_sort_by()
test_sum()
test_omit()
test_group_by()
test_filter_by()
test_handle_methods()
test_remove_repeated_elements_from_array()
test_parse_precision()
test_arrays_concat()

0
ccxt/test/custom/.gitignore vendored Normal file
View File

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

Some files were not shown because too many files have changed in this diff Show More