Merge branch 'develop' into pr/samgermain/6780

This commit is contained in:
Matthias
2022-07-16 15:35:00 +02:00
151 changed files with 22464 additions and 18288 deletions

View File

@@ -154,6 +154,7 @@ def test_stoploss_adjust_binance(mocker, default_conf, sl1, sl2, sl3, side):
order = {
'type': 'stop_loss_limit',
'price': 1500,
'stopPrice': 1500,
'info': {'stopPrice': 1500},
}
assert exchange.stoploss_adjust(sl1, order, side=side)
@@ -490,11 +491,11 @@ def test_fill_leverage_tiers_binance_dryrun(default_conf, mocker, leverage_tiers
default_conf['margin_mode'] = MarginMode.ISOLATED
exchange = get_patched_exchange(mocker, default_conf, api_mock, id="binance")
exchange.fill_leverage_tiers()
leverage_tiers = leverage_tiers
assert len(exchange._leverage_tiers.keys()) > 100
for key, value in leverage_tiers.items():
assert exchange._leverage_tiers[key] == value
v = exchange._leverage_tiers[key]
assert isinstance(v, list)
assert len(v) == len(value)
def test__set_leverage_binance(mocker, default_conf):

View File

@@ -13,6 +13,7 @@ import pytest
from freqtrade.enums import CandleType
from freqtrade.exchange import timeframe_to_minutes, timeframe_to_prev_date
from freqtrade.exchange.exchange import timeframe_to_msecs
from freqtrade.resolvers.exchange_resolver import ExchangeResolver
from tests.conftest import get_default_conf_usdt
@@ -135,6 +136,7 @@ def exchange_futures(request, exchange_conf, class_mocker):
class_mocker.patch(
'freqtrade.exchange.binance.Binance.fill_leverage_tiers')
class_mocker.patch('freqtrade.exchange.exchange.Exchange.fetch_trading_fees')
class_mocker.patch('freqtrade.exchange.okx.Okx.additional_exchange_init')
exchange = ExchangeResolver.load_exchange(request.param, exchange_conf, validate=True)
yield exchange, request.param
@@ -151,6 +153,25 @@ class TestCCXTExchange():
assert isinstance(markets[pair], dict)
assert exchange.market_is_spot(markets[pair])
def test_has_validations(self, exchange):
exchange, exchangename = exchange
exchange.validate_ordertypes({
'entry': 'limit',
'exit': 'limit',
'stoploss': 'limit',
})
if exchangename == 'gateio':
# gateio doesn't have market orders on spot
return
exchange.validate_ordertypes({
'entry': 'market',
'exit': 'market',
'stoploss': 'market',
})
def test_load_markets_futures(self, exchange_futures):
exchange, exchangename = exchange_futures
if not exchange:
@@ -197,8 +218,13 @@ class TestCCXTExchange():
l2 = exchange.fetch_l2_order_book(pair)
assert 'asks' in l2
assert 'bids' in l2
assert len(l2['asks']) >= 1
assert len(l2['bids']) >= 1
l2_limit_range = exchange._ft_has['l2_limit_range']
l2_limit_range_required = exchange._ft_has['l2_limit_range_required']
if exchangename == 'gateio':
# TODO: Gateio is unstable here at the moment, ignoring the limit partially.
return
for val in [1, 2, 5, 25, 100]:
l2 = exchange.fetch_l2_order_book(pair, val)
if not l2_limit_range or val in l2_limit_range:
@@ -218,7 +244,7 @@ class TestCCXTExchange():
assert len(l2['asks']) == next_limit
assert len(l2['asks']) == next_limit
def test_fetch_ohlcv(self, exchange):
def test_ccxt_fetch_ohlcv(self, exchange):
exchange, exchangename = exchange
pair = EXCHANGES[exchangename]['pair']
timeframe = EXCHANGES[exchangename]['timeframe']
@@ -230,11 +256,44 @@ class TestCCXTExchange():
assert len(ohlcv[pair_tf]) == len(exchange.klines(pair_tf))
# assert len(exchange.klines(pair_tf)) > 200
# Assume 90% uptime ...
assert len(exchange.klines(pair_tf)) > exchange.ohlcv_candle_limit(timeframe) * 0.90
assert len(exchange.klines(pair_tf)) > exchange.ohlcv_candle_limit(
timeframe, CandleType.SPOT) * 0.90
# Check if last-timeframe is within the last 2 intervals
now = datetime.now(timezone.utc) - timedelta(minutes=(timeframe_to_minutes(timeframe) * 2))
assert exchange.klines(pair_tf).iloc[-1]['date'] >= timeframe_to_prev_date(timeframe, now)
def test_ccxt__async_get_candle_history(self, exchange):
exchange, exchangename = exchange
# For some weired reason, this test returns random lengths for bittrex.
if not exchange._ft_has['ohlcv_has_history'] or exchangename == 'bittrex':
return
pair = EXCHANGES[exchangename]['pair']
timeframe = EXCHANGES[exchangename]['timeframe']
candle_type = CandleType.SPOT
timeframe_ms = timeframe_to_msecs(timeframe)
now = timeframe_to_prev_date(
timeframe, datetime.now(timezone.utc))
for offset in (360, 120, 30, 10, 5, 2):
since = now - timedelta(days=offset)
since_ms = int(since.timestamp() * 1000)
res = exchange.loop.run_until_complete(exchange._async_get_candle_history(
pair=pair,
timeframe=timeframe,
since_ms=since_ms,
candle_type=candle_type
)
)
assert res
assert res[0] == pair
assert res[1] == timeframe
assert res[2] == candle_type
candles = res[3]
candle_count = exchange.ohlcv_candle_limit(timeframe, candle_type, since_ms) * 0.9
candle_count1 = (now.timestamp() * 1000 - since_ms) // timeframe_ms
assert len(candles) >= min(candle_count, candle_count1)
assert candles[0][0] == since_ms or (since_ms + timeframe_ms)
def test_ccxt_fetch_funding_rate_history(self, exchange_futures):
exchange, exchangename = exchange_futures
if not exchange:

View File

@@ -0,0 +1,75 @@
from ccxt import Precise
ws = Precise('-1.123e-6')
ws = Precise('-1.123e-6')
xs = Precise('0.00000002')
ys = Precise('69696900000')
zs = Precise('0')
def test_precise():
assert ys * xs == '1393.938'
assert xs * ys == '1393.938'
assert ys + xs == '69696900000.00000002'
assert xs + ys == '69696900000.00000002'
assert xs - ys == '-69696899999.99999998'
assert ys - xs == '69696899999.99999998'
assert xs / ys == '0'
assert ys / xs == '3484845000000000000'
assert ws * xs == '-0.00000000000002246'
assert xs * ws == '-0.00000000000002246'
assert ws + xs == '-0.000001103'
assert xs + ws == '-0.000001103'
assert xs - ws == '0.000001143'
assert ws - xs == '-0.000001143'
assert xs / ws == '-0.017809439002671415'
assert ws / xs == '-56.15'
assert zs * ws == '0'
assert zs * xs == '0'
assert zs * ys == '0'
assert ws * zs == '0'
assert xs * zs == '0'
assert ys * zs == '0'
assert zs + ws == '-0.000001123'
assert zs + xs == '0.00000002'
assert zs + ys == '69696900000'
assert ws + zs == '-0.000001123'
assert xs + zs == '0.00000002'
assert ys + zs == '69696900000'
assert abs(Precise('-500.1')) == '500.1'
assert abs(Precise('213')) == '213'
assert abs(Precise('-500.1')) == '500.1'
assert -Precise('213') == '-213'
assert Precise('10.1') % Precise('0.5') == '0.1'
assert Precise('5550') % Precise('120') == '30'
assert Precise('-0.0') == Precise('0')
assert Precise('5.534000') == Precise('5.5340')
assert min(Precise('-3.1415'), Precise('-2')) == '-3.1415'
assert max(Precise('3.1415'), Precise('-2')) == '3.1415'
assert Precise('2') > Precise('1.2345')
assert not Precise('-3.1415') > Precise('-2')
assert not Precise('3.1415') > Precise('3.1415')
assert Precise.string_gt('3.14150000000000000000001', '3.1415')
assert Precise('3.1415') >= Precise('3.1415')
assert Precise('3.14150000000000000000001') >= Precise('3.1415')
assert not Precise('3.1415') < Precise('3.1415')
assert Precise('3.1415') <= Precise('3.1415')
assert Precise('3.1415') <= Precise('3.14150000000000000000001')

View File

@@ -17,9 +17,9 @@ from freqtrade.exceptions import (DDosProtection, DependencyException, InvalidOr
from freqtrade.exchange import Binance, Bittrex, Exchange, Kraken
from freqtrade.exchange.common import (API_FETCH_ORDER_RETRY_COUNT, API_RETRY_COUNT,
calculate_backoff, remove_credentials)
from freqtrade.exchange.exchange import (market_is_active, timeframe_to_minutes, timeframe_to_msecs,
timeframe_to_next_date, timeframe_to_prev_date,
timeframe_to_seconds)
from freqtrade.exchange.exchange import (date_minus_candles, market_is_active, timeframe_to_minutes,
timeframe_to_msecs, timeframe_to_next_date,
timeframe_to_prev_date, timeframe_to_seconds)
from freqtrade.resolvers.exchange_resolver import ExchangeResolver
from tests.conftest import get_mock_coro, get_patched_exchange, log_has, log_has_re, num_log_has_re
@@ -99,6 +99,8 @@ def test_remove_credentials(default_conf, caplog) -> None:
def test_init_ccxt_kwargs(default_conf, mocker, caplog):
mocker.patch('freqtrade.exchange.Exchange._load_markets', MagicMock(return_value={}))
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
aei_mock = mocker.patch('freqtrade.exchange.Exchange.additional_exchange_init')
caplog.set_level(logging.INFO)
conf = copy.deepcopy(default_conf)
conf['exchange']['ccxt_async_config'] = {'aiohttp_trust_env': True, 'asyncio_loop': True}
@@ -108,6 +110,7 @@ def test_init_ccxt_kwargs(default_conf, mocker, caplog):
caplog)
assert ex._api_async.aiohttp_trust_env
assert not ex._api.aiohttp_trust_env
assert aei_mock.call_count == 1
# Reset logging and config
caplog.clear()
@@ -302,6 +305,7 @@ def test_amount_to_precision(
(234.53, 4, 0.5, 235.0),
(0.891534, 4, 0.0001, 0.8916),
(64968.89, 4, 0.01, 64968.89),
(0.000000003483, 4, 1e-12, 0.000000003483),
])
def test_price_to_precision(default_conf, mocker, price, precision_mode, precision, expected):
@@ -936,6 +940,7 @@ def test_validate_timeframes_emulated_ohlcvi_2(default_conf, mocker):
def test_validate_timeframes_not_in_config(default_conf, mocker):
# TODO: this test does not assert ...
del default_conf["timeframe"]
api_mock = MagicMock()
id_mock = PropertyMock(return_value='test_exchange')
@@ -951,6 +956,7 @@ def test_validate_timeframes_not_in_config(default_conf, mocker):
mocker.patch('freqtrade.exchange.Exchange.validate_pairs')
mocker.patch('freqtrade.exchange.Exchange.validate_stakecurrency')
mocker.patch('freqtrade.exchange.Exchange.validate_pricing')
mocker.patch('freqtrade.exchange.Exchange.validate_required_startup_candles')
Exchange(default_conf)
@@ -1081,6 +1087,13 @@ def test_validate_required_startup_candles(default_conf, mocker, caplog):
with pytest.raises(OperationalException, match=r'This strategy requires 6000.*'):
Exchange(default_conf)
# Emulate kraken mode
ex._ft_has['ohlcv_has_history'] = False
with pytest.raises(OperationalException,
match=r'This strategy requires 2500.*, '
r'which is more than the amount.*'):
ex.validate_required_startup_candles(2500, '5m')
def test_exchange_has(default_conf, mocker):
exchange = get_patched_exchange(mocker, default_conf)
@@ -1122,7 +1135,7 @@ def test_create_dry_run_order(default_conf, mocker, side, exchange_name, leverag
assert order["symbol"] == "ETH/BTC"
assert order["amount"] == 1
assert order["leverage"] == leverage
assert order["cost"] == 1 * 200 / leverage
assert order["cost"] == 1 * 200
@pytest.mark.parametrize('side,is_short,order_reason', [
@@ -1913,7 +1926,7 @@ def test_get_historic_ohlcv(default_conf, mocker, caplog, exchange_name, candle_
exchange._async_get_candle_history = Mock(wraps=mock_candle_hist)
# one_call calculation * 1.8 should do 2 calls
since = 5 * 60 * exchange.ohlcv_candle_limit('5m') * 1.8
since = 5 * 60 * exchange.ohlcv_candle_limit('5m', CandleType.SPOT) * 1.8
ret = exchange.get_historic_ohlcv(
pair,
"5m",
@@ -1979,7 +1992,7 @@ def test_get_historic_ohlcv_as_df(default_conf, mocker, exchange_name, candle_ty
exchange._async_get_candle_history = Mock(wraps=mock_candle_hist)
# one_call calculation * 1.8 should do 2 calls
since = 5 * 60 * exchange.ohlcv_candle_limit('5m') * 1.8
since = 5 * 60 * exchange.ohlcv_candle_limit('5m', CandleType.SPOT) * 1.8
ret = exchange.get_historic_ohlcv_as_df(
pair,
"5m",
@@ -2033,7 +2046,7 @@ async def test__async_get_historic_ohlcv(default_conf, mocker, caplog, exchange_
)
# Required candles
candles = (end_ts - start_ts) / 300_000
exp = candles // exchange.ohlcv_candle_limit('5m') + 1
exp = candles // exchange.ohlcv_candle_limit('5m', CandleType.SPOT) + 1
# Depending on the exchange, this should be called between 1 and 6 times.
assert exchange._api_async.fetch_ohlcv.call_count == exp
@@ -2183,6 +2196,8 @@ async def test__async_get_candle_history(default_conf, mocker, caplog, exchange_
@pytest.mark.asyncio
async def test__async_kucoin_get_candle_history(default_conf, mocker, caplog):
from freqtrade.exchange.common import _reset_logging_mixin
_reset_logging_mixin()
caplog.set_level(logging.INFO)
api_mock = MagicMock()
api_mock.fetch_ohlcv = MagicMock(side_effect=ccxt.DDoSProtection(
@@ -2836,6 +2851,7 @@ def test_get_historic_trades_notsupported(default_conf, mocker, caplog, exchange
until=trades_history[-1][0])
@pytest.mark.usefixtures("init_persistence")
@pytest.mark.parametrize("exchange_name", EXCHANGES)
def test_cancel_order_dry_run(default_conf, mocker, exchange_name):
default_conf['dry_run'] = True
@@ -3001,6 +3017,7 @@ def test_cancel_stoploss_order_with_result(default_conf, mocker, exchange_name):
exchange.cancel_stoploss_order_with_result(order_id='_', pair='TKN/BTC', amount=123)
@pytest.mark.usefixtures("init_persistence")
@pytest.mark.parametrize("exchange_name", EXCHANGES)
def test_fetch_order(default_conf, mocker, exchange_name, caplog):
default_conf['dry_run'] = True
@@ -3053,6 +3070,7 @@ def test_fetch_order(default_conf, mocker, exchange_name, caplog):
order_id='_', pair='TKN/BTC')
@pytest.mark.usefixtures("init_persistence")
@pytest.mark.parametrize("exchange_name", EXCHANGES)
def test_fetch_stoploss_order(default_conf, mocker, exchange_name):
# Don't test FTX here - that needs a separate test
@@ -3380,7 +3398,7 @@ def test_ohlcv_candle_limit(default_conf, mocker, exchange_name):
expected = exchange._ft_has['ohlcv_candle_limit_per_timeframe'][timeframe]
# This should only run for bittrex
assert exchange_name == 'bittrex'
assert exchange.ohlcv_candle_limit(timeframe) == expected
assert exchange.ohlcv_candle_limit(timeframe, CandleType.SPOT) == expected
def test_timeframe_to_minutes():
@@ -3462,6 +3480,17 @@ def test_timeframe_to_next_date():
assert timeframe_to_next_date("5m", date) == date + timedelta(minutes=5)
def test_date_minus_candles():
date = datetime(2019, 8, 12, 13, 25, 0, tzinfo=timezone.utc)
assert date_minus_candles("5m", 3, date) == date - timedelta(minutes=15)
assert date_minus_candles("5m", 5, date) == date - timedelta(minutes=25)
assert date_minus_candles("1m", 6, date) == date - timedelta(minutes=6)
assert date_minus_candles("1h", 3, date) == date - timedelta(hours=3, minutes=25)
assert date_minus_candles("1h", 3) == timeframe_to_prev_date('1h') - timedelta(hours=3)
@pytest.mark.parametrize(
"market_symbol,base,quote,exchange,spot,margin,futures,trademode,add_dict,expected_result",
[
@@ -3556,7 +3585,7 @@ def test_order_has_fee(order, expected) -> None:
def test_extract_cost_curr_rate(mocker, default_conf, order, expected) -> None:
mocker.patch('freqtrade.exchange.Exchange.calculate_fee_rate', MagicMock(return_value=0.01))
ex = get_patched_exchange(mocker, default_conf)
assert ex.extract_cost_curr_rate(order) == expected
assert ex.extract_cost_curr_rate(order['fee'], order['symbol'], cost=20, amount=1) == expected
@pytest.mark.parametrize("order,unknown_fee_rate,expected", [
@@ -3594,6 +3623,9 @@ def test_extract_cost_curr_rate(mocker, default_conf, order, expected) -> None:
'fee': {'currency': 'POINT', 'cost': 2.0, 'rate': None}}, 1, 4.0),
({'symbol': 'POINT/BTC', 'amount': 0.04, 'cost': 0.5,
'fee': {'currency': 'POINT', 'cost': 2.0, 'rate': None}}, 2, 8.0),
# Missing currency
({'symbol': 'ETH/BTC', 'amount': 0.04, 'cost': 0.05,
'fee': {'currency': None, 'cost': 0.005}}, None, None),
])
def test_calculate_fee_rate(mocker, default_conf, order, expected, unknown_fee_rate) -> None:
mocker.patch('freqtrade.exchange.Exchange.fetch_ticker', return_value={'last': 0.081})
@@ -3602,7 +3634,8 @@ def test_calculate_fee_rate(mocker, default_conf, order, expected, unknown_fee_r
ex = get_patched_exchange(mocker, default_conf)
assert ex.calculate_fee_rate(order) == expected
assert ex.calculate_fee_rate(order['fee'], order['symbol'],
cost=order['cost'], amount=order['amount']) == expected
@pytest.mark.parametrize('retrycount,max_retries,expected', [
@@ -3831,6 +3864,7 @@ def test_validate_trading_mode_and_margin_mode(
("bibox", "spot", {"has": {"fetchCurrencies": False}}),
("bibox", "margin", {"has": {"fetchCurrencies": False}, "options": {"defaultType": "margin"}}),
("bibox", "futures", {"has": {"fetchCurrencies": False}, "options": {"defaultType": "swap"}}),
("bybit", "spot", {"options": {"defaultType": "spot"}}),
("bybit", "futures", {"options": {"defaultType": "linear"}}),
("ftx", "futures", {"options": {"defaultType": "swap"}}),
("gateio", "futures", {"options": {"defaultType": "swap"}}),
@@ -3929,6 +3963,70 @@ def test_calculate_funding_fees(
) == kraken_fee
@pytest.mark.parametrize(
'mark_price,funding_rate,futures_funding_rate', [
(1000, 0.001, None),
(1000, 0.001, 0.01),
(1000, 0.001, 0.0),
(1000, 0.001, -0.01),
])
def test_combine_funding_and_mark(
default_conf,
mocker,
funding_rate,
mark_price,
futures_funding_rate,
):
exchange = get_patched_exchange(mocker, default_conf)
prior2_date = timeframe_to_prev_date('1h', datetime.now(timezone.utc) - timedelta(hours=2))
prior_date = timeframe_to_prev_date('1h', datetime.now(timezone.utc) - timedelta(hours=1))
trade_date = timeframe_to_prev_date('1h', datetime.now(timezone.utc))
funding_rates = DataFrame([
{'date': prior2_date, 'open': funding_rate},
{'date': prior_date, 'open': funding_rate},
{'date': trade_date, 'open': funding_rate},
])
mark_rates = DataFrame([
{'date': prior2_date, 'open': mark_price},
{'date': prior_date, 'open': mark_price},
{'date': trade_date, 'open': mark_price},
])
df = exchange.combine_funding_and_mark(funding_rates, mark_rates, futures_funding_rate)
assert 'open_mark' in df.columns
assert 'open_fund' in df.columns
assert len(df) == 3
funding_rates = DataFrame([
{'date': trade_date, 'open': funding_rate},
])
mark_rates = DataFrame([
{'date': prior2_date, 'open': mark_price},
{'date': prior_date, 'open': mark_price},
{'date': trade_date, 'open': mark_price},
])
df = exchange.combine_funding_and_mark(funding_rates, mark_rates, futures_funding_rate)
if futures_funding_rate is not None:
assert len(df) == 3
assert df.iloc[0]['open_fund'] == futures_funding_rate
assert df.iloc[1]['open_fund'] == futures_funding_rate
assert df.iloc[2]['open_fund'] == funding_rate
else:
assert len(df) == 1
# Empty funding rates
funding_rates = DataFrame([], columns=['date', 'open'])
df = exchange.combine_funding_and_mark(funding_rates, mark_rates, futures_funding_rate)
if futures_funding_rate is not None:
assert len(df) == 3
assert df.iloc[0]['open_fund'] == futures_funding_rate
assert df.iloc[1]['open_fund'] == futures_funding_rate
assert df.iloc[2]['open_fund'] == futures_funding_rate
else:
assert len(df) == 0
def test_get_or_calculate_liquidation_price(mocker, default_conf):
api_mock = MagicMock()
@@ -4799,8 +4897,10 @@ def test__get_params(mocker, default_conf, exchange_name):
if exchange_name == 'okx':
params2['tdMode'] = 'isolated'
params2['posSide'] = 'net'
assert exchange._get_params(
side="buy",
ordertype='market',
reduceOnly=False,
time_in_force='gtc',
@@ -4808,6 +4908,7 @@ def test__get_params(mocker, default_conf, exchange_name):
) == params1
assert exchange._get_params(
side="buy",
ordertype='market',
reduceOnly=False,
time_in_force='ioc',
@@ -4815,6 +4916,7 @@ def test__get_params(mocker, default_conf, exchange_name):
) == params1
assert exchange._get_params(
side="buy",
ordertype='limit',
reduceOnly=False,
time_in_force='gtc',
@@ -4827,6 +4929,7 @@ def test__get_params(mocker, default_conf, exchange_name):
exchange._params = {'test': True}
assert exchange._get_params(
side="buy",
ordertype='limit',
reduceOnly=True,
time_in_force='ioc',

View File

@@ -174,6 +174,7 @@ def test_stoploss_adjust_ftx(mocker, default_conf, sl1, sl2, sl3, side):
assert not exchange.stoploss_adjust(sl3, order, side=side)
@pytest.mark.usefixtures("init_persistence")
def test_fetch_stoploss_order_ftx(default_conf, mocker, limit_sell_order, limit_buy_order):
default_conf['dry_run'] = True
order = MagicMock()

View File

@@ -33,7 +33,14 @@ def test_validate_order_types_gateio(default_conf, mocker):
match=r'Exchange .* does not support market orders.'):
ExchangeResolver.load_exchange('gateio', default_conf, True)
# market-orders supported on futures markets.
default_conf['trading_mode'] = 'futures'
default_conf['margin_mode'] = 'isolated'
ex = ExchangeResolver.load_exchange('gateio', default_conf, True)
assert ex
@pytest.mark.usefixtures("init_persistence")
def test_fetch_stoploss_order_gateio(default_conf, mocker):
exchange = get_patched_exchange(mocker, default_conf, id='gateio')
@@ -46,6 +53,25 @@ def test_fetch_stoploss_order_gateio(default_conf, mocker):
assert fetch_order_mock.call_args_list[0][1]['pair'] == 'ETH/BTC'
assert fetch_order_mock.call_args_list[0][1]['params'] == {'stop': True}
default_conf['trading_mode'] = 'futures'
default_conf['margin_mode'] = 'isolated'
exchange = get_patched_exchange(mocker, default_conf, id='gateio')
exchange.fetch_order = MagicMock(return_value={
'status': 'closed',
'id': '1234',
'stopPrice': 5.62,
'info': {
'trade_id': '222555'
}
})
exchange.fetch_stoploss_order('1234', 'ETH/BTC')
assert exchange.fetch_order.call_count == 2
assert exchange.fetch_order.call_args_list[0][1]['order_id'] == '1234'
assert exchange.fetch_order.call_args_list[1][1]['order_id'] == '222555'
def test_cancel_stoploss_order_gateio(default_conf, mocker):
exchange = get_patched_exchange(mocker, default_conf, id='gateio')

View File

@@ -123,5 +123,5 @@ def test_stoploss_adjust_kucoin(mocker, default_conf):
assert exchange.stoploss_adjust(1501, order, 'sell')
assert not exchange.stoploss_adjust(1499, order, 'sell')
# Test with invalid order case
order['info']['stop'] = None
assert not exchange.stoploss_adjust(1501, order, 'sell')
order['stopPrice'] = None
assert exchange.stoploss_adjust(1501, order, 'sell')

View File

@@ -1,7 +1,40 @@
from datetime import datetime, timedelta, timezone
from unittest.mock import MagicMock, PropertyMock
import pytest
from freqtrade.enums import MarginMode, TradingMode
from tests.conftest import get_patched_exchange
from freqtrade.enums.candletype import CandleType
from freqtrade.exchange.exchange import timeframe_to_minutes
from tests.conftest import get_mock_coro, get_patched_exchange
from tests.exchange.test_exchange import ccxt_exceptionhandlers
def test_okx_ohlcv_candle_limit(default_conf, mocker):
exchange = get_patched_exchange(mocker, default_conf, id='okx')
timeframes = ('1m', '5m', '1h')
start_time = int(datetime(2021, 1, 1, tzinfo=timezone.utc).timestamp() * 1000)
for timeframe in timeframes:
assert exchange.ohlcv_candle_limit(timeframe, CandleType.SPOT) == 300
assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUTURES) == 300
assert exchange.ohlcv_candle_limit(timeframe, CandleType.MARK) == 100
assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUNDING_RATE) == 100
assert exchange.ohlcv_candle_limit(timeframe, CandleType.SPOT, start_time) == 100
assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUTURES, start_time) == 100
assert exchange.ohlcv_candle_limit(timeframe, CandleType.MARK, start_time) == 100
assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUNDING_RATE, start_time) == 100
one_call = int((datetime.now(timezone.utc) - timedelta(
minutes=290 * timeframe_to_minutes(timeframe))).timestamp() * 1000)
assert exchange.ohlcv_candle_limit(timeframe, CandleType.SPOT, one_call) == 300
assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUTURES, one_call) == 300
one_call = int((datetime.now(timezone.utc) - timedelta(
minutes=320 * timeframe_to_minutes(timeframe))).timestamp() * 1000)
assert exchange.ohlcv_candle_limit(timeframe, CandleType.SPOT, one_call) == 100
assert exchange.ohlcv_candle_limit(timeframe, CandleType.FUTURES, one_call) == 100
def test_get_maintenance_ratio_and_amt_okx(
@@ -170,13 +203,77 @@ def test_get_max_pair_stake_amount_okx(default_conf, mocker, leverage_tiers):
assert exchange.get_max_pair_stake_amount('TTT/USDT', 1.0) == float('inf') # Not in tiers
@pytest.mark.parametrize('mode,side,reduceonly,result', [
('net', 'buy', False, 'net'),
('net', 'sell', True, 'net'),
('net', 'sell', False, 'net'),
('net', 'buy', True, 'net'),
('longshort', 'buy', False, 'long'),
('longshort', 'sell', True, 'long'),
('longshort', 'sell', False, 'short'),
('longshort', 'buy', True, 'short'),
])
def test__get_posSide(default_conf, mocker, mode, side, reduceonly, result):
exchange = get_patched_exchange(mocker, default_conf, id="okx")
exchange.net_only = mode == 'net'
assert exchange._get_posSide(side, reduceonly) == result
def test_additional_exchange_init_okx(default_conf, mocker):
api_mock = MagicMock()
api_mock.fetch_accounts = MagicMock(return_value=[
{'id': '2555',
'type': '2',
'currency': None,
'info': {'acctLv': '2',
'autoLoan': False,
'ctIsoMode': 'automatic',
'greeksType': 'PA',
'level': 'Lv1',
'levelTmp': '',
'mgnIsoMode': 'automatic',
'posMode': 'long_short_mode',
'uid': '2555'}}])
default_conf['dry_run'] = False
exchange = get_patched_exchange(mocker, default_conf, id="okx", api_mock=api_mock)
assert api_mock.fetch_accounts.call_count == 0
exchange.trading_mode = TradingMode.FUTURES
# Default to netOnly
assert exchange.net_only
exchange.additional_exchange_init()
assert api_mock.fetch_accounts.call_count == 1
assert not exchange.net_only
api_mock.fetch_accounts = MagicMock(return_value=[
{'id': '2555',
'type': '2',
'currency': None,
'info': {'acctLv': '2',
'autoLoan': False,
'ctIsoMode': 'automatic',
'greeksType': 'PA',
'level': 'Lv1',
'levelTmp': '',
'mgnIsoMode': 'automatic',
'posMode': 'net_mode',
'uid': '2555'}}])
exchange.additional_exchange_init()
assert api_mock.fetch_accounts.call_count == 1
assert exchange.net_only
default_conf['trading_mode'] = 'futures'
default_conf['margin_mode'] = 'isolated'
ccxt_exceptionhandlers(mocker, default_conf, api_mock, 'okx',
"additional_exchange_init", "fetch_accounts")
def test_load_leverage_tiers_okx(default_conf, mocker, markets):
api_mock = MagicMock()
type(api_mock).has = PropertyMock(return_value={
'fetchLeverageTiers': False,
'fetchMarketLeverageTiers': True,
})
api_mock.fetch_market_leverage_tiers = MagicMock(side_effect=[
api_mock.fetch_market_leverage_tiers = get_mock_coro(side_effect=[
[
{
'tier': 1,