Merge branch 'develop' into pr/th0rntwig/7495
This commit is contained in:
@@ -200,6 +200,8 @@ def patch_freqtradebot(mocker, config) -> None:
|
||||
mocker.patch('freqtrade.freqtradebot.RPCManager._init', MagicMock())
|
||||
mocker.patch('freqtrade.freqtradebot.RPCManager.send_msg', MagicMock())
|
||||
patch_whitelist(mocker, config)
|
||||
mocker.patch('freqtrade.freqtradebot.ExternalMessageConsumer')
|
||||
mocker.patch('freqtrade.configuration.config_validation._validate_consumers')
|
||||
|
||||
|
||||
def get_patched_freqtradebot(mocker, config) -> FreqtradeBot:
|
||||
|
@@ -235,7 +235,7 @@ def test_calculate_market_change(testdatadir):
|
||||
data = load_data(datadir=testdatadir, pairs=pairs, timeframe='5m')
|
||||
result = calculate_market_change(data)
|
||||
assert isinstance(result, float)
|
||||
assert pytest.approx(result) == 0.00955514
|
||||
assert pytest.approx(result) == 0.01100002
|
||||
|
||||
|
||||
def test_combine_dataframes_with_mean(testdatadir):
|
||||
|
@@ -139,10 +139,10 @@ def test_jsondatahandler_ohlcv_purge(mocker, testdatadir):
|
||||
def test_jsondatahandler_ohlcv_load(testdatadir, caplog):
|
||||
dh = JsonDataHandler(testdatadir)
|
||||
df = dh.ohlcv_load('XRP/ETH', '5m', 'spot')
|
||||
assert len(df) == 711
|
||||
assert len(df) == 712
|
||||
|
||||
df_mark = dh.ohlcv_load('UNITTEST/USDT', '1h', candle_type="mark")
|
||||
assert len(df_mark) == 99
|
||||
assert len(df_mark) == 100
|
||||
|
||||
df_no_mark = dh.ohlcv_load('UNITTEST/USDT', '1h', 'spot')
|
||||
assert len(df_no_mark) == 0
|
||||
|
@@ -124,8 +124,8 @@ def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, tmp
|
||||
assert '0' in captured.out
|
||||
assert '0.01616' in captured.out
|
||||
assert '34.049' in captured.out
|
||||
assert '0.104104' in captured.out
|
||||
assert '47.0996' in captured.out
|
||||
assert '0.104411' in captured.out
|
||||
assert '52.8292' in captured.out
|
||||
|
||||
# test group 1
|
||||
args = get_args(base_args + ['--analysis-groups', "1"])
|
||||
|
@@ -377,8 +377,8 @@ def test_load_partial_missing(testdatadir, caplog) -> None:
|
||||
td = ((end - start).total_seconds() // 60 // 5) + 1
|
||||
assert td != len(data['UNITTEST/BTC'])
|
||||
|
||||
# Shift endtime with +5 - as last candle is dropped (partial candle)
|
||||
end_real = arrow.get(data['UNITTEST/BTC'].iloc[-1, 0]).shift(minutes=5)
|
||||
# Shift endtime with +5
|
||||
end_real = arrow.get(data['UNITTEST/BTC'].iloc[-1, 0])
|
||||
assert log_has(f'UNITTEST/BTC, spot, 5m, '
|
||||
f'data ends at {end_real.strftime(DATETIME_PRINT_FORMAT)}',
|
||||
caplog)
|
||||
@@ -447,7 +447,7 @@ def test_get_timerange(default_conf, mocker, testdatadir) -> None:
|
||||
)
|
||||
min_date, max_date = get_timerange(data)
|
||||
assert min_date.isoformat() == '2017-11-04T23:02:00+00:00'
|
||||
assert max_date.isoformat() == '2017-11-14T22:58:00+00:00'
|
||||
assert max_date.isoformat() == '2017-11-14T22:59:00+00:00'
|
||||
|
||||
|
||||
def test_validate_backtest_data_warn(default_conf, mocker, caplog, testdatadir) -> None:
|
||||
@@ -470,7 +470,7 @@ def test_validate_backtest_data_warn(default_conf, mocker, caplog, testdatadir)
|
||||
min_date, max_date, timeframe_to_minutes('1m'))
|
||||
assert len(caplog.record_tuples) == 1
|
||||
assert log_has(
|
||||
"UNITTEST/BTC has missing frames: expected 14396, got 13680, that's 716 missing values",
|
||||
"UNITTEST/BTC has missing frames: expected 14397, got 13681, that's 716 missing values",
|
||||
caplog)
|
||||
|
||||
|
||||
|
@@ -501,6 +501,24 @@ def test_fill_leverage_tiers_binance_dryrun(default_conf, mocker, leverage_tiers
|
||||
assert len(v) == len(value)
|
||||
|
||||
|
||||
def test_additional_exchange_init_binance(default_conf, mocker):
|
||||
api_mock = MagicMock()
|
||||
api_mock.fapiPrivateGetPositionsideDual = MagicMock(return_value={"dualSidePosition": True})
|
||||
api_mock.fapiPrivateGetMultiAssetsMargin = MagicMock(return_value={"multiAssetsMargin": True})
|
||||
default_conf['dry_run'] = False
|
||||
default_conf['trading_mode'] = TradingMode.FUTURES
|
||||
default_conf['margin_mode'] = MarginMode.ISOLATED
|
||||
with pytest.raises(OperationalException,
|
||||
match=r"Hedge Mode is not supported.*\nMulti-Asset Mode is not supported.*"):
|
||||
get_patched_exchange(mocker, default_conf, id="binance", api_mock=api_mock)
|
||||
api_mock.fapiPrivateGetPositionsideDual = MagicMock(return_value={"dualSidePosition": False})
|
||||
api_mock.fapiPrivateGetMultiAssetsMargin = MagicMock(return_value={"multiAssetsMargin": False})
|
||||
exchange = get_patched_exchange(mocker, default_conf, id="binance", api_mock=api_mock)
|
||||
assert exchange
|
||||
ccxt_exceptionhandlers(mocker, default_conf, api_mock, 'binance',
|
||||
"additional_exchange_init", "fapiPrivateGetPositionsideDual")
|
||||
|
||||
|
||||
def test__set_leverage_binance(mocker, default_conf):
|
||||
|
||||
api_mock = MagicMock()
|
||||
|
@@ -137,6 +137,7 @@ def exchange_futures(request, exchange_conf, class_mocker):
|
||||
'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')
|
||||
class_mocker.patch('freqtrade.exchange.binance.Binance.additional_exchange_init')
|
||||
class_mocker.patch('freqtrade.exchange.exchange.Exchange.load_cached_leverage_tiers',
|
||||
return_value=None)
|
||||
class_mocker.patch('freqtrade.exchange.exchange.Exchange.cache_leverage_tiers')
|
||||
|
@@ -80,7 +80,7 @@ def load_data_test(what, testdatadir):
|
||||
data.loc[:, 'close'] = np.sin(data.index * hz) / 1000 + base
|
||||
|
||||
return {'UNITTEST/BTC': clean_ohlcv_dataframe(data, timeframe='1m', pair='UNITTEST/BTC',
|
||||
fill_missing=True)}
|
||||
fill_missing=True, drop_incomplete=True)}
|
||||
|
||||
|
||||
# FIX: fixturize this?
|
||||
@@ -323,7 +323,7 @@ def test_data_to_dataframe_bt(default_conf, mocker, testdatadir) -> None:
|
||||
backtesting = Backtesting(default_conf)
|
||||
backtesting._set_strategy(backtesting.strategylist[0])
|
||||
processed = backtesting.strategy.advise_all_indicators(data)
|
||||
assert len(processed['UNITTEST/BTC']) == 102
|
||||
assert len(processed['UNITTEST/BTC']) == 103
|
||||
|
||||
# Load strategy to compare the result between Backtesting function and strategy are the same
|
||||
strategy = StrategyResolver.load_strategy(default_conf)
|
||||
@@ -1165,9 +1165,9 @@ def test_backtest_start_timerange(default_conf, mocker, caplog, testdatadir):
|
||||
'Parameter --timerange detected: 1510694220-1510700340 ...',
|
||||
f'Using data directory: {testdatadir} ...',
|
||||
'Loading data from 2017-11-14 20:57:00 '
|
||||
'up to 2017-11-14 22:58:00 (0 days).',
|
||||
'up to 2017-11-14 22:59:00 (0 days).',
|
||||
'Backtesting with data from 2017-11-14 21:17:00 '
|
||||
'up to 2017-11-14 22:58:00 (0 days).',
|
||||
'up to 2017-11-14 22:59:00 (0 days).',
|
||||
'Parameter --enable-position-stacking detected ...'
|
||||
]
|
||||
|
||||
@@ -1244,9 +1244,9 @@ def test_backtest_start_multi_strat(default_conf, mocker, caplog, testdatadir):
|
||||
'Parameter --timerange detected: 1510694220-1510700340 ...',
|
||||
f'Using data directory: {testdatadir} ...',
|
||||
'Loading data from 2017-11-14 20:57:00 '
|
||||
'up to 2017-11-14 22:58:00 (0 days).',
|
||||
'up to 2017-11-14 22:59:00 (0 days).',
|
||||
'Backtesting with data from 2017-11-14 21:17:00 '
|
||||
'up to 2017-11-14 22:58:00 (0 days).',
|
||||
'up to 2017-11-14 22:59:00 (0 days).',
|
||||
'Parameter --enable-position-stacking detected ...',
|
||||
f'Running backtesting for Strategy {CURRENT_TEST_STRATEGY}',
|
||||
'Running backtesting for Strategy StrategyTestV2',
|
||||
@@ -1355,9 +1355,9 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat
|
||||
'Parameter --timerange detected: 1510694220-1510700340 ...',
|
||||
f'Using data directory: {testdatadir} ...',
|
||||
'Loading data from 2017-11-14 20:57:00 '
|
||||
'up to 2017-11-14 22:58:00 (0 days).',
|
||||
'up to 2017-11-14 22:59:00 (0 days).',
|
||||
'Backtesting with data from 2017-11-14 21:17:00 '
|
||||
'up to 2017-11-14 22:58:00 (0 days).',
|
||||
'up to 2017-11-14 22:59:00 (0 days).',
|
||||
'Parameter --enable-position-stacking detected ...',
|
||||
f'Running backtesting for Strategy {CURRENT_TEST_STRATEGY}',
|
||||
'Running backtesting for Strategy StrategyTestV2',
|
||||
@@ -1371,7 +1371,7 @@ def test_backtest_start_multi_strat_nomock(default_conf, mocker, caplog, testdat
|
||||
assert 'EXIT REASON STATS' in captured.out
|
||||
assert 'DAY BREAKDOWN' in captured.out
|
||||
assert 'LEFT OPEN TRADES REPORT' in captured.out
|
||||
assert '2017-11-14 21:17:00 -> 2017-11-14 22:58:00 | Max open trades : 1' in captured.out
|
||||
assert '2017-11-14 21:17:00 -> 2017-11-14 22:59:00 | Max open trades : 1' in captured.out
|
||||
assert 'STRATEGY SUMMARY' in captured.out
|
||||
|
||||
|
||||
@@ -1503,9 +1503,9 @@ def test_backtest_start_nomock_futures(default_conf_usdt, mocker,
|
||||
'Parameter -i/--timeframe detected ... Using timeframe: 1h ...',
|
||||
f'Using data directory: {testdatadir} ...',
|
||||
'Loading data from 2021-11-17 01:00:00 '
|
||||
'up to 2021-11-21 03:00:00 (4 days).',
|
||||
'up to 2021-11-21 04:00:00 (4 days).',
|
||||
'Backtesting with data from 2021-11-17 21:00:00 '
|
||||
'up to 2021-11-21 03:00:00 (3 days).',
|
||||
'up to 2021-11-21 04:00:00 (3 days).',
|
||||
'XRP/USDT, funding_rate, 8h, data starts at 2021-11-18 00:00:00',
|
||||
'XRP/USDT, mark, 8h, data starts at 2021-11-18 00:00:00',
|
||||
f'Running backtesting for Strategy {CURRENT_TEST_STRATEGY}',
|
||||
@@ -1616,9 +1616,9 @@ def test_backtest_start_multi_strat_nomock_detail(default_conf, mocker,
|
||||
'Parameter --timeframe-detail detected, using 1m for intra-candle backtesting ...',
|
||||
f'Using data directory: {testdatadir} ...',
|
||||
'Loading data from 2019-10-11 00:00:00 '
|
||||
'up to 2019-10-13 11:10:00 (2 days).',
|
||||
'up to 2019-10-13 11:15:00 (2 days).',
|
||||
'Backtesting with data from 2019-10-11 01:40:00 '
|
||||
'up to 2019-10-13 11:10:00 (2 days).',
|
||||
'up to 2019-10-13 11:15:00 (2 days).',
|
||||
f'Running backtesting for Strategy {CURRENT_TEST_STRATEGY}',
|
||||
]
|
||||
|
||||
@@ -1719,7 +1719,7 @@ def test_backtest_start_multi_strat_caching(default_conf, mocker, caplog, testda
|
||||
'Parameter --timerange detected: 1510694220-1510700340 ...',
|
||||
f'Using data directory: {testdatadir} ...',
|
||||
'Loading data from 2017-11-14 20:57:00 '
|
||||
'up to 2017-11-14 22:58:00 (0 days).',
|
||||
'up to 2017-11-14 22:59:00 (0 days).',
|
||||
'Parameter --enable-position-stacking detected ...',
|
||||
]
|
||||
|
||||
@@ -1732,7 +1732,7 @@ def test_backtest_start_multi_strat_caching(default_conf, mocker, caplog, testda
|
||||
'Running backtesting for Strategy StrategyTestV2',
|
||||
'Running backtesting for Strategy StrategyTestV3',
|
||||
'Ignoring max_open_trades (--disable-max-market-positions was used) ...',
|
||||
'Backtesting with data from 2017-11-14 21:17:00 up to 2017-11-14 22:58:00 (0 days).',
|
||||
'Backtesting with data from 2017-11-14 21:17:00 up to 2017-11-14 22:59:00 (0 days).',
|
||||
]
|
||||
elif run_id == '2' and min_backtest_date < start_time:
|
||||
assert backtestmock.call_count == 0
|
||||
@@ -1745,7 +1745,7 @@ def test_backtest_start_multi_strat_caching(default_conf, mocker, caplog, testda
|
||||
'Reusing result of previous backtest for StrategyTestV2',
|
||||
'Running backtesting for Strategy StrategyTestV3',
|
||||
'Ignoring max_open_trades (--disable-max-market-positions was used) ...',
|
||||
'Backtesting with data from 2017-11-14 21:17:00 up to 2017-11-14 22:58:00 (0 days).',
|
||||
'Backtesting with data from 2017-11-14 21:17:00 up to 2017-11-14 22:59:00 (0 days).',
|
||||
]
|
||||
assert backtestmock.call_count == 1
|
||||
|
||||
|
@@ -93,11 +93,16 @@ def test_backtest_position_adjustment(default_conf, fee, mocker, testdatadir) ->
|
||||
t["close_rate"], 6) < round(ln.iloc[0]["high"], 6))
|
||||
|
||||
|
||||
def test_backtest_position_adjustment_detailed(default_conf, fee, mocker) -> None:
|
||||
@pytest.mark.parametrize('leverage', [
|
||||
1, 2
|
||||
])
|
||||
def test_backtest_position_adjustment_detailed(default_conf, fee, mocker, leverage) -> None:
|
||||
default_conf['use_exit_signal'] = False
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_fee', fee)
|
||||
mocker.patch("freqtrade.exchange.Exchange.get_min_pair_stake_amount", return_value=10)
|
||||
mocker.patch("freqtrade.exchange.Exchange.get_max_pair_stake_amount", return_value=float('inf'))
|
||||
mocker.patch("freqtrade.exchange.Exchange.get_max_leverage", return_value=10)
|
||||
|
||||
patch_exchange(mocker)
|
||||
default_conf.update({
|
||||
"stake_amount": 100.0,
|
||||
@@ -105,6 +110,7 @@ def test_backtest_position_adjustment_detailed(default_conf, fee, mocker) -> Non
|
||||
"strategy": "StrategyTestV3"
|
||||
})
|
||||
backtesting = Backtesting(default_conf)
|
||||
backtesting._can_short = True
|
||||
backtesting._set_strategy(backtesting.strategylist[0])
|
||||
pair = 'XRP/USDT'
|
||||
row = [
|
||||
@@ -120,18 +126,19 @@ def test_backtest_position_adjustment_detailed(default_conf, fee, mocker) -> Non
|
||||
'', # enter_tag
|
||||
'', # exit_tag
|
||||
]
|
||||
backtesting.strategy.leverage = MagicMock(return_value=leverage)
|
||||
trade = backtesting._enter_trade(pair, row=row, direction='long')
|
||||
trade.orders[0].close_bt_order(row[0], trade)
|
||||
assert trade
|
||||
assert pytest.approx(trade.stake_amount) == 100.0
|
||||
assert pytest.approx(trade.amount) == 47.61904762
|
||||
assert pytest.approx(trade.amount) == 47.61904762 * leverage
|
||||
assert len(trade.orders) == 1
|
||||
backtesting.strategy.adjust_trade_position = MagicMock(return_value=None)
|
||||
|
||||
trade = backtesting._get_adjust_trade_entry_for_candle(trade, row)
|
||||
assert trade
|
||||
assert pytest.approx(trade.stake_amount) == 100.0
|
||||
assert pytest.approx(trade.amount) == 47.61904762
|
||||
assert pytest.approx(trade.amount) == 47.61904762 * leverage
|
||||
assert len(trade.orders) == 1
|
||||
# Increase position by 100
|
||||
backtesting.strategy.adjust_trade_position = MagicMock(return_value=100)
|
||||
@@ -140,7 +147,7 @@ def test_backtest_position_adjustment_detailed(default_conf, fee, mocker) -> Non
|
||||
|
||||
assert trade
|
||||
assert pytest.approx(trade.stake_amount) == 200.0
|
||||
assert pytest.approx(trade.amount) == 95.23809524
|
||||
assert pytest.approx(trade.amount) == 95.23809524 * leverage
|
||||
assert len(trade.orders) == 2
|
||||
|
||||
# Reduce by more than amount - no change to trade.
|
||||
@@ -150,7 +157,7 @@ def test_backtest_position_adjustment_detailed(default_conf, fee, mocker) -> Non
|
||||
|
||||
assert trade
|
||||
assert pytest.approx(trade.stake_amount) == 200.0
|
||||
assert pytest.approx(trade.amount) == 95.23809524
|
||||
assert pytest.approx(trade.amount) == 95.23809524 * leverage
|
||||
assert len(trade.orders) == 2
|
||||
assert trade.nr_of_successful_entries == 2
|
||||
|
||||
@@ -160,7 +167,7 @@ def test_backtest_position_adjustment_detailed(default_conf, fee, mocker) -> Non
|
||||
|
||||
assert trade
|
||||
assert pytest.approx(trade.stake_amount) == 100.0
|
||||
assert pytest.approx(trade.amount) == 47.61904762
|
||||
assert pytest.approx(trade.amount) == 47.61904762 * leverage
|
||||
assert len(trade.orders) == 3
|
||||
assert trade.nr_of_successful_entries == 2
|
||||
assert trade.nr_of_successful_exits == 1
|
||||
@@ -171,7 +178,7 @@ def test_backtest_position_adjustment_detailed(default_conf, fee, mocker) -> Non
|
||||
|
||||
assert trade
|
||||
assert pytest.approx(trade.stake_amount) == 100.0
|
||||
assert pytest.approx(trade.amount) == 47.61904762
|
||||
assert pytest.approx(trade.amount) == 47.61904762 * leverage
|
||||
assert len(trade.orders) == 3
|
||||
assert trade.nr_of_successful_entries == 2
|
||||
assert trade.nr_of_successful_exits == 1
|
||||
|
@@ -9,6 +9,7 @@ import pytest
|
||||
import time_machine
|
||||
|
||||
from freqtrade.constants import AVAILABLE_PAIRLISTS
|
||||
from freqtrade.data.dataprovider import DataProvider
|
||||
from freqtrade.enums import CandleType, RunMode
|
||||
from freqtrade.exceptions import OperationalException
|
||||
from freqtrade.persistence import Trade
|
||||
@@ -40,6 +41,12 @@ def whitelist_conf(default_conf):
|
||||
"sort_key": "quoteVolume",
|
||||
},
|
||||
]
|
||||
default_conf.update({
|
||||
"external_message_consumer": {
|
||||
"enabled": True,
|
||||
"producers": [],
|
||||
}
|
||||
})
|
||||
return default_conf
|
||||
|
||||
|
||||
@@ -126,7 +133,7 @@ def test_log_cached(mocker, static_pl_conf, markets, tickers):
|
||||
def test_load_pairlist_noexist(mocker, markets, default_conf):
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf)
|
||||
mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets))
|
||||
plm = PairListManager(freqtrade.exchange, default_conf)
|
||||
plm = PairListManager(freqtrade.exchange, default_conf, MagicMock())
|
||||
with pytest.raises(OperationalException,
|
||||
match=r"Impossible to load Pairlist 'NonexistingPairList'. "
|
||||
r"This class does not exist or contains Python code errors."):
|
||||
@@ -137,7 +144,7 @@ def test_load_pairlist_noexist(mocker, markets, default_conf):
|
||||
def test_load_pairlist_verify_multi(mocker, markets_static, default_conf):
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf)
|
||||
mocker.patch('freqtrade.exchange.Exchange.markets', PropertyMock(return_value=markets_static))
|
||||
plm = PairListManager(freqtrade.exchange, default_conf)
|
||||
plm = PairListManager(freqtrade.exchange, default_conf, MagicMock())
|
||||
# Call different versions one after the other, should always consider what was passed in
|
||||
# and have no side-effects (therefore the same check multiple times)
|
||||
assert plm.verify_whitelist(['ETH/BTC', 'XRP/BTC', ], print) == ['ETH/BTC', 'XRP/BTC']
|
||||
@@ -269,7 +276,7 @@ def test_refresh_pairlist_dynamic(mocker, shitcoinmarkets, tickers, whitelist_co
|
||||
with pytest.raises(OperationalException,
|
||||
match=r'`number_assets` not specified. Please check your configuration '
|
||||
r'for "pairlist.config.number_assets"'):
|
||||
PairListManager(freqtrade.exchange, whitelist_conf)
|
||||
PairListManager(freqtrade.exchange, whitelist_conf, MagicMock())
|
||||
|
||||
|
||||
def test_refresh_pairlist_dynamic_2(mocker, shitcoinmarkets, tickers, whitelist_conf_2):
|
||||
@@ -694,7 +701,7 @@ def test_PrecisionFilter_error(mocker, whitelist_conf) -> None:
|
||||
|
||||
with pytest.raises(OperationalException,
|
||||
match=r"PrecisionFilter can only work with stoploss defined\..*"):
|
||||
PairListManager(MagicMock, whitelist_conf)
|
||||
PairListManager(MagicMock, whitelist_conf, MagicMock())
|
||||
|
||||
|
||||
def test_PerformanceFilter_error(mocker, whitelist_conf, caplog) -> None:
|
||||
@@ -703,7 +710,7 @@ def test_PerformanceFilter_error(mocker, whitelist_conf, caplog) -> None:
|
||||
del Trade.query
|
||||
mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True))
|
||||
exchange = get_patched_exchange(mocker, whitelist_conf)
|
||||
pm = PairListManager(exchange, whitelist_conf)
|
||||
pm = PairListManager(exchange, whitelist_conf, MagicMock())
|
||||
pm.refresh_pairlist()
|
||||
|
||||
assert log_has("PerformanceFilter is not available in this mode.", caplog)
|
||||
@@ -1167,6 +1174,10 @@ def test_spreadfilter_invalid_data(mocker, default_conf, markets, tickers, caplo
|
||||
"[{'OffsetFilter': 'OffsetFilter - Taking 10 Pairs, starting from 5.'}]",
|
||||
None
|
||||
),
|
||||
({"method": "ProducerPairList"},
|
||||
"[{'ProducerPairList': 'ProducerPairList - default'}]",
|
||||
None
|
||||
),
|
||||
])
|
||||
def test_pricefilter_desc(mocker, whitelist_conf, markets, pairlistconfig,
|
||||
desc_expected, exception_expected):
|
||||
@@ -1341,3 +1352,77 @@ def test_expand_pairlist_keep_invalid(wildcardlist, pairs, expected):
|
||||
expand_pairlist(wildcardlist, pairs, keep_invalid=True)
|
||||
else:
|
||||
assert sorted(expand_pairlist(wildcardlist, pairs, keep_invalid=True)) == sorted(expected)
|
||||
|
||||
|
||||
def test_ProducerPairlist_no_emc(mocker, whitelist_conf):
|
||||
mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True))
|
||||
|
||||
whitelist_conf['pairlists'] = [
|
||||
{
|
||||
"method": "ProducerPairList",
|
||||
"number_assets": 10,
|
||||
"producer_name": "hello_world",
|
||||
}
|
||||
]
|
||||
del whitelist_conf['external_message_consumer']
|
||||
|
||||
with pytest.raises(OperationalException,
|
||||
match=r"ProducerPairList requires external_message_consumer to be enabled."):
|
||||
get_patched_freqtradebot(mocker, whitelist_conf)
|
||||
|
||||
|
||||
def test_ProducerPairlist(mocker, whitelist_conf, markets):
|
||||
mocker.patch('freqtrade.exchange.Exchange.exchange_has', MagicMock(return_value=True))
|
||||
mocker.patch.multiple('freqtrade.exchange.Exchange',
|
||||
markets=PropertyMock(return_value=markets),
|
||||
exchange_has=MagicMock(return_value=True),
|
||||
)
|
||||
whitelist_conf['pairlists'] = [
|
||||
{
|
||||
"method": "ProducerPairList",
|
||||
"number_assets": 2,
|
||||
"producer_name": "hello_world",
|
||||
}
|
||||
]
|
||||
whitelist_conf.update({
|
||||
"external_message_consumer": {
|
||||
"enabled": True,
|
||||
"producers": [
|
||||
{
|
||||
"name": "hello_world",
|
||||
"host": "null",
|
||||
"port": 9891,
|
||||
"ws_token": "dummy",
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
exchange = get_patched_exchange(mocker, whitelist_conf)
|
||||
dp = DataProvider(whitelist_conf, exchange, None)
|
||||
pairs = ['ETH/BTC', 'LTC/BTC', 'XRP/BTC']
|
||||
# different producer
|
||||
dp._set_producer_pairs(pairs + ['MEEP/USDT'], 'default')
|
||||
pm = PairListManager(exchange, whitelist_conf, dp)
|
||||
pm.refresh_pairlist()
|
||||
assert pm.whitelist == []
|
||||
# proper producer
|
||||
dp._set_producer_pairs(pairs, 'hello_world')
|
||||
pm.refresh_pairlist()
|
||||
|
||||
# Pairlist reduced to 2
|
||||
assert pm.whitelist == pairs[:2]
|
||||
assert len(pm.whitelist) == 2
|
||||
whitelist_conf['exchange']['pair_whitelist'] = ['TKN/BTC']
|
||||
|
||||
whitelist_conf['pairlists'] = [
|
||||
{"method": "StaticPairList"},
|
||||
{
|
||||
"method": "ProducerPairList",
|
||||
"producer_name": "hello_world",
|
||||
}
|
||||
]
|
||||
pm = PairListManager(exchange, whitelist_conf, dp)
|
||||
pm.refresh_pairlist()
|
||||
assert len(pm.whitelist) == 4
|
||||
assert pm.whitelist == ['TKN/BTC'] + pairs
|
||||
|
@@ -276,6 +276,8 @@ async def test_emc_create_connection_error(default_conf, caplog, mocker):
|
||||
|
||||
|
||||
async def test_emc_receive_messages_valid(default_conf, caplog, mocker):
|
||||
caplog.set_level(logging.DEBUG)
|
||||
|
||||
default_conf.update({
|
||||
"external_message_consumer": {
|
||||
"enabled": True,
|
||||
|
@@ -365,6 +365,14 @@ def test_exception_send_msg(default_conf, mocker, caplog):
|
||||
with pytest.raises(NotImplementedError):
|
||||
webhook.send_msg(msg)
|
||||
|
||||
# Test no failure for not implemented but known messagetypes
|
||||
for e in RPCMessageType:
|
||||
msg = {
|
||||
'type': e,
|
||||
'status': 'whatever'
|
||||
}
|
||||
webhook.send_msg(msg)
|
||||
|
||||
|
||||
def test__send_msg(default_conf, mocker, caplog):
|
||||
default_conf["webhook"] = get_webhook_dict()
|
||||
|
@@ -288,7 +288,7 @@ def test_advise_all_indicators(default_conf, testdatadir) -> None:
|
||||
data = load_data(testdatadir, '1m', ['UNITTEST/BTC'], timerange=timerange,
|
||||
fill_up_missing=True)
|
||||
processed = strategy.advise_all_indicators(data)
|
||||
assert len(processed['UNITTEST/BTC']) == 102 # partial candle was removed
|
||||
assert len(processed['UNITTEST/BTC']) == 103
|
||||
|
||||
|
||||
def test_populate_any_indicators(default_conf, testdatadir) -> None:
|
||||
@@ -300,7 +300,7 @@ def test_populate_any_indicators(default_conf, testdatadir) -> None:
|
||||
processed = strategy.populate_any_indicators('UNITTEST/BTC', data, '5m')
|
||||
assert processed == data
|
||||
assert id(processed) == id(data)
|
||||
assert len(processed['UNITTEST/BTC']) == 102 # partial candle was removed
|
||||
assert len(processed['UNITTEST/BTC']) == 103
|
||||
|
||||
|
||||
def test_freqai_not_initialized(default_conf) -> None:
|
||||
|
@@ -2661,6 +2661,7 @@ def test_manage_open_orders_exit_usercustom(
|
||||
rpc_mock = patch_RPCManager(mocker)
|
||||
cancel_order_mock = MagicMock()
|
||||
patch_exchange(mocker)
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_min_pair_stake_amount', return_value=0.0)
|
||||
et_mock = mocker.patch('freqtrade.freqtradebot.FreqtradeBot.execute_trade_exit')
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
@@ -2673,7 +2674,6 @@ def test_manage_open_orders_exit_usercustom(
|
||||
open_trade_usdt.open_date = arrow.utcnow().shift(hours=-5).datetime
|
||||
open_trade_usdt.close_date = arrow.utcnow().shift(minutes=-601).datetime
|
||||
open_trade_usdt.close_profit_abs = 0.001
|
||||
open_trade_usdt.is_open = False
|
||||
|
||||
Trade.query.session.add(open_trade_usdt)
|
||||
Trade.commit()
|
||||
@@ -2687,7 +2687,6 @@ def test_manage_open_orders_exit_usercustom(
|
||||
freqtrade.manage_open_orders()
|
||||
assert cancel_order_mock.call_count == 0
|
||||
assert rpc_mock.call_count == 1
|
||||
assert open_trade_usdt.is_open is False
|
||||
assert freqtrade.strategy.check_exit_timeout.call_count == 1
|
||||
assert freqtrade.strategy.check_entry_timeout.call_count == 0
|
||||
|
||||
@@ -2697,7 +2696,6 @@ def test_manage_open_orders_exit_usercustom(
|
||||
freqtrade.manage_open_orders()
|
||||
assert cancel_order_mock.call_count == 0
|
||||
assert rpc_mock.call_count == 1
|
||||
assert open_trade_usdt.is_open is False
|
||||
assert freqtrade.strategy.check_exit_timeout.call_count == 1
|
||||
assert freqtrade.strategy.check_entry_timeout.call_count == 0
|
||||
|
||||
@@ -2707,7 +2705,6 @@ def test_manage_open_orders_exit_usercustom(
|
||||
freqtrade.manage_open_orders()
|
||||
assert cancel_order_mock.call_count == 1
|
||||
assert rpc_mock.call_count == 2
|
||||
assert open_trade_usdt.is_open is True
|
||||
assert freqtrade.strategy.check_exit_timeout.call_count == 1
|
||||
assert freqtrade.strategy.check_entry_timeout.call_count == 0
|
||||
|
||||
@@ -2748,14 +2745,14 @@ def test_manage_open_orders_exit(
|
||||
'freqtrade.exchange.Exchange',
|
||||
fetch_ticker=ticker_usdt,
|
||||
fetch_order=MagicMock(return_value=limit_sell_order_old),
|
||||
cancel_order=cancel_order_mock
|
||||
cancel_order=cancel_order_mock,
|
||||
get_min_pair_stake_amount=MagicMock(return_value=0),
|
||||
)
|
||||
freqtrade = FreqtradeBot(default_conf_usdt)
|
||||
|
||||
open_trade_usdt.open_date = arrow.utcnow().shift(hours=-5).datetime
|
||||
open_trade_usdt.close_date = arrow.utcnow().shift(minutes=-601).datetime
|
||||
open_trade_usdt.close_profit_abs = 0.001
|
||||
open_trade_usdt.is_open = False
|
||||
open_trade_usdt.is_short = is_short
|
||||
|
||||
Trade.query.session.add(open_trade_usdt)
|
||||
@@ -2796,7 +2793,6 @@ def test_check_handle_cancelled_exit(
|
||||
|
||||
open_trade_usdt.open_date = arrow.utcnow().shift(hours=-5).datetime
|
||||
open_trade_usdt.close_date = arrow.utcnow().shift(minutes=-601).datetime
|
||||
open_trade_usdt.is_open = False
|
||||
open_trade_usdt.is_short = is_short
|
||||
|
||||
Trade.query.session.add(open_trade_usdt)
|
||||
@@ -3004,6 +3000,7 @@ def test_handle_cancel_enter(mocker, caplog, default_conf_usdt, limit_order, is_
|
||||
trade.open_rate = 200
|
||||
trade.is_short = False
|
||||
trade.entry_side = "buy"
|
||||
trade.amount = 100
|
||||
l_order['filled'] = 0.0
|
||||
l_order['status'] = 'open'
|
||||
trade.nr_of_successful_entries = 0
|
||||
@@ -3092,6 +3089,7 @@ def test_handle_cancel_enter_corder_empty(mocker, default_conf_usdt, limit_order
|
||||
trade.entry_side = "buy"
|
||||
trade.open_order_id = "open_order_noop"
|
||||
trade.nr_of_successful_entries = 0
|
||||
trade.amount = 100
|
||||
l_order['filled'] = 0.0
|
||||
l_order['status'] = 'open'
|
||||
reason = CANCEL_REASON['TIMEOUT']
|
||||
@@ -3121,20 +3119,21 @@ def test_handle_cancel_exit_limit(mocker, default_conf_usdt, fee) -> None:
|
||||
amount=2,
|
||||
exchange='binance',
|
||||
open_rate=0.245441,
|
||||
open_order_id="123456",
|
||||
open_order_id="sell_123456",
|
||||
open_date=arrow.utcnow().shift(days=-2).datetime,
|
||||
fee_open=fee.return_value,
|
||||
fee_close=fee.return_value,
|
||||
close_rate=0.555,
|
||||
close_date=arrow.utcnow().datetime,
|
||||
exit_reason="sell_reason_whatever",
|
||||
stake_amount=0.245441 * 2,
|
||||
)
|
||||
trade.orders = [
|
||||
Order(
|
||||
Order(
|
||||
ft_order_side='buy',
|
||||
ft_pair=trade.pair,
|
||||
ft_is_open=True,
|
||||
order_id='123456',
|
||||
ft_is_open=False,
|
||||
order_id='buy_123456',
|
||||
status="closed",
|
||||
symbol=trade.pair,
|
||||
order_type="market",
|
||||
@@ -3147,15 +3146,33 @@ def test_handle_cancel_exit_limit(mocker, default_conf_usdt, fee) -> None:
|
||||
order_date=trade.open_date,
|
||||
order_filled_date=trade.open_date,
|
||||
),
|
||||
Order(
|
||||
ft_order_side='sell',
|
||||
ft_pair=trade.pair,
|
||||
ft_is_open=True,
|
||||
order_id='sell_123456',
|
||||
status="open",
|
||||
symbol=trade.pair,
|
||||
order_type="limit",
|
||||
side="sell",
|
||||
price=trade.open_rate,
|
||||
average=trade.open_rate,
|
||||
filled=0.0,
|
||||
remaining=trade.amount,
|
||||
cost=trade.open_rate * trade.amount,
|
||||
order_date=trade.open_date,
|
||||
order_filled_date=trade.open_date,
|
||||
),
|
||||
]
|
||||
order = {'id': "123456",
|
||||
order = {'id': "sell_123456",
|
||||
'remaining': 1,
|
||||
'amount': 1,
|
||||
'status': "open"}
|
||||
reason = CANCEL_REASON['TIMEOUT']
|
||||
send_msg_mock.reset_mock()
|
||||
assert freqtrade.handle_cancel_exit(trade, order, reason)
|
||||
assert cancel_order_mock.call_count == 1
|
||||
assert send_msg_mock.call_count == 2
|
||||
assert send_msg_mock.call_count == 1
|
||||
assert trade.close_rate is None
|
||||
assert trade.exit_reason is None
|
||||
|
||||
@@ -3181,8 +3198,9 @@ def test_handle_cancel_exit_limit(mocker, default_conf_usdt, fee) -> None:
|
||||
def test_handle_cancel_exit_cancel_exception(mocker, default_conf_usdt) -> None:
|
||||
patch_RPCManager(mocker)
|
||||
patch_exchange(mocker)
|
||||
mocker.patch(
|
||||
'freqtrade.exchange.Exchange.cancel_order_with_result', side_effect=InvalidOrderException())
|
||||
mocker.patch('freqtrade.exchange.Exchange.get_min_pair_stake_amount', return_value=0.0)
|
||||
mocker.patch('freqtrade.exchange.Exchange.cancel_order_with_result',
|
||||
side_effect=InvalidOrderException())
|
||||
|
||||
freqtrade = FreqtradeBot(default_conf_usdt)
|
||||
|
||||
|
@@ -2,7 +2,7 @@ from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
from freqtrade.enums import ExitCheckTuple, ExitType
|
||||
from freqtrade.enums import ExitCheckTuple, ExitType, TradingMode
|
||||
from freqtrade.persistence import Trade
|
||||
from freqtrade.persistence.models import Order
|
||||
from freqtrade.rpc.rpc import RPC
|
||||
@@ -455,10 +455,12 @@ def test_dca_order_adjust(default_conf_usdt, ticker_usdt, fee, mocker) -> None:
|
||||
assert pytest.approx(trade.orders[-1].amount) == 61.538461232
|
||||
|
||||
|
||||
def test_dca_exiting(default_conf_usdt, ticker_usdt, fee, mocker, caplog) -> None:
|
||||
@pytest.mark.parametrize('leverage', [1, 2])
|
||||
def test_dca_exiting(default_conf_usdt, ticker_usdt, fee, mocker, caplog, leverage) -> None:
|
||||
default_conf_usdt['position_adjustment_enable'] = True
|
||||
|
||||
freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt)
|
||||
freqtrade.trading_mode = TradingMode.FUTURES
|
||||
mocker.patch.multiple(
|
||||
'freqtrade.exchange.Exchange',
|
||||
fetch_ticker=ticker_usdt,
|
||||
@@ -467,15 +469,17 @@ def test_dca_exiting(default_conf_usdt, ticker_usdt, fee, mocker, caplog) -> Non
|
||||
price_to_precision=lambda s, x, y: y,
|
||||
get_min_pair_stake_amount=MagicMock(return_value=10),
|
||||
)
|
||||
mocker.patch("freqtrade.exchange.Exchange.get_max_leverage", return_value=10)
|
||||
|
||||
patch_get_signal(freqtrade)
|
||||
freqtrade.strategy.leverage = MagicMock(return_value=leverage)
|
||||
freqtrade.enter_positions()
|
||||
|
||||
assert len(Trade.get_trades().all()) == 1
|
||||
trade = Trade.get_trades().first()
|
||||
assert len(trade.orders) == 1
|
||||
assert pytest.approx(trade.stake_amount) == 60
|
||||
assert pytest.approx(trade.amount) == 30.0
|
||||
assert pytest.approx(trade.amount) == 30.0 * leverage
|
||||
assert trade.open_rate == 2.0
|
||||
|
||||
# Too small size
|
||||
@@ -484,8 +488,9 @@ def test_dca_exiting(default_conf_usdt, ticker_usdt, fee, mocker, caplog) -> Non
|
||||
trade = Trade.get_trades().first()
|
||||
assert len(trade.orders) == 1
|
||||
assert pytest.approx(trade.stake_amount) == 60
|
||||
assert pytest.approx(trade.amount) == 30.0
|
||||
assert log_has_re("Remaining amount of 1.6.* would be smaller than the minimum of 10.", caplog)
|
||||
assert pytest.approx(trade.amount) == 30.0 * leverage
|
||||
assert log_has_re(
|
||||
r"Remaining amount of \d\.\d+.* would be smaller than the minimum of 10.", caplog)
|
||||
|
||||
freqtrade.strategy.adjust_trade_position = MagicMock(return_value=-20)
|
||||
|
||||
@@ -494,7 +499,7 @@ def test_dca_exiting(default_conf_usdt, ticker_usdt, fee, mocker, caplog) -> Non
|
||||
assert len(trade.orders) == 2
|
||||
assert trade.orders[-1].ft_order_side == 'sell'
|
||||
assert pytest.approx(trade.stake_amount) == 40.198
|
||||
assert pytest.approx(trade.amount) == 20.099
|
||||
assert pytest.approx(trade.amount) == 20.099 * leverage
|
||||
assert trade.open_rate == 2.0
|
||||
assert trade.is_open
|
||||
caplog.clear()
|
||||
|
Reference in New Issue
Block a user