@ -7,6 +7,7 @@ import pytest
from freqtrade . commands . analyze_commands import start_analysis_entries_exits
from freqtrade . commands . optimize_commands import start_backtesting
from freqtrade . enums import ExitType
from freqtrade . exceptions import OperationalException
from freqtrade . optimize . backtesting import Backtesting
from tests . conftest import get_args , patch_exchange , patched_configuration_load_config_file
@ -256,3 +257,306 @@ def test_backtest_analysis_on_entry_and_rejected_signals_nomock(
start_analysis_entries_exits ( args )
captured = capsys . readouterr ( )
assert " no rejected signals " in captured . out
def test_backtest_analysis_with_invalid_config (
default_conf , mocker , caplog , testdatadir , user_dir , capsys
) :
caplog . set_level ( logging . INFO )
( user_dir / " backtest_results " ) . mkdir ( parents = True , exist_ok = True )
default_conf . update (
{
" use_exit_signal " : True ,
" exit_profit_only " : False ,
" exit_profit_offset " : 0.0 ,
" ignore_roi_if_entry_signal " : False ,
}
)
patch_exchange ( mocker )
result1 = pd . DataFrame (
{
" pair " : [ " ETH/BTC " , " LTC/BTC " , " ETH/BTC " , " LTC/BTC " ] ,
" profit_ratio " : [ 0.025 , 0.05 , - 0.1 , - 0.05 ] ,
" profit_abs " : [ 0.5 , 2.0 , - 4.0 , - 2.0 ] ,
" open_date " : pd . to_datetime (
[
" 2018-01-29 18:40:00 " ,
" 2018-01-30 03:30:00 " ,
" 2018-01-30 08:10:00 " ,
" 2018-01-31 13:30:00 " ,
] ,
utc = True ,
) ,
" close_date " : pd . to_datetime (
[
" 2018-01-29 20:45:00 " ,
" 2018-01-30 05:35:00 " ,
" 2018-01-30 09:10:00 " ,
" 2018-01-31 15:00:00 " ,
] ,
utc = True ,
) ,
" trade_duration " : [ 235 , 40 , 60 , 90 ] ,
" is_open " : [ False , False , False , False ] ,
" stake_amount " : [ 0.01 , 0.01 , 0.01 , 0.01 ] ,
" open_rate " : [ 0.104445 , 0.10302485 , 0.10302485 , 0.10302485 ] ,
" close_rate " : [ 0.104969 , 0.103541 , 0.102041 , 0.102541 ] ,
" is_short " : [ False , False , False , False ] ,
" enter_tag " : [
" enter_tag_long_a " ,
" enter_tag_long_b " ,
" enter_tag_long_a " ,
" enter_tag_long_b " ,
] ,
" exit_reason " : [
ExitType . ROI . value ,
ExitType . EXIT_SIGNAL . value ,
ExitType . STOP_LOSS . value ,
ExitType . TRAILING_STOP_LOSS . value ,
] ,
}
)
backtestmock = MagicMock (
side_effect = [
{
" results " : result1 ,
" config " : default_conf ,
" locks " : [ ] ,
" rejected_signals " : 20 ,
" timedout_entry_orders " : 0 ,
" timedout_exit_orders " : 0 ,
" canceled_trade_entries " : 0 ,
" canceled_entry_orders " : 0 ,
" replaced_entry_orders " : 0 ,
" final_balance " : 1000 ,
}
]
)
mocker . patch (
" freqtrade.plugins.pairlistmanager.PairListManager.whitelist " ,
PropertyMock ( return_value = [ " ETH/BTC " , " LTC/BTC " , " DASH/BTC " ] ) ,
)
mocker . patch ( " freqtrade.optimize.backtesting.Backtesting.backtest " , backtestmock )
patched_configuration_load_config_file ( mocker , default_conf )
args = [
" backtesting " ,
" --config " ,
" config.json " ,
" --datadir " ,
str ( testdatadir ) ,
" --user-data-dir " ,
str ( user_dir ) ,
" --timeframe " ,
" 5m " ,
" --timerange " ,
" 1515560100-1517287800 " ,
" --export " ,
" signals " ,
" --cache " ,
" none " ,
]
args = get_args ( args )
start_backtesting ( args )
captured = capsys . readouterr ( )
assert " BACKTESTING REPORT " in captured . out
assert " EXIT REASON STATS " in captured . out
assert " LEFT OPEN TRADES REPORT " in captured . out
base_args = [
" backtesting-analysis " ,
" --config " ,
" config.json " ,
" --datadir " ,
str ( testdatadir ) ,
" --user-data-dir " ,
str ( user_dir ) ,
]
# test with both entry and exit only arguments
args = get_args (
base_args
+ [
" --analysis-groups " ,
" 0 " ,
" --indicator-list " ,
" close " ,
" rsi " ,
" profit_abs " ,
" --entry-only " ,
" --exit-only " ,
]
)
with pytest . raises (
OperationalException ,
match = r " Cannot use --entry-only and --exit-only at the same time. Please choose one. " ,
) :
start_analysis_entries_exits ( args )
def test_backtest_analysis_on_entry_and_rejected_signals_only_entry_signals (
default_conf , mocker , caplog , testdatadir , user_dir , capsys
) :
caplog . set_level ( logging . INFO )
( user_dir / " backtest_results " ) . mkdir ( parents = True , exist_ok = True )
default_conf . update (
{
" use_exit_signal " : True ,
" exit_profit_only " : False ,
" exit_profit_offset " : 0.0 ,
" ignore_roi_if_entry_signal " : False ,
}
)
patch_exchange ( mocker )
result1 = pd . DataFrame (
{
" pair " : [ " ETH/BTC " , " LTC/BTC " , " ETH/BTC " , " LTC/BTC " ] ,
" profit_ratio " : [ 0.025 , 0.05 , - 0.1 , - 0.05 ] ,
" profit_abs " : [ 0.5 , 2.0 , - 4.0 , - 2.0 ] ,
" open_date " : pd . to_datetime (
[
" 2018-01-29 18:40:00 " ,
" 2018-01-30 03:30:00 " ,
" 2018-01-30 08:10:00 " ,
" 2018-01-31 13:30:00 " ,
] ,
utc = True ,
) ,
" close_date " : pd . to_datetime (
[
" 2018-01-29 20:45:00 " ,
" 2018-01-30 05:35:00 " ,
" 2018-01-30 09:10:00 " ,
" 2018-01-31 15:00:00 " ,
] ,
utc = True ,
) ,
" trade_duration " : [ 235 , 40 , 60 , 90 ] ,
" is_open " : [ False , False , False , False ] ,
" stake_amount " : [ 0.01 , 0.01 , 0.01 , 0.01 ] ,
" open_rate " : [ 0.104445 , 0.10302485 , 0.10302485 , 0.10302485 ] ,
" close_rate " : [ 0.104969 , 0.103541 , 0.102041 , 0.102541 ] ,
" is_short " : [ False , False , False , False ] ,
" enter_tag " : [
" enter_tag_long_a " ,
" enter_tag_long_b " ,
" enter_tag_long_a " ,
" enter_tag_long_b " ,
] ,
" exit_reason " : [
ExitType . ROI . value ,
ExitType . EXIT_SIGNAL . value ,
ExitType . STOP_LOSS . value ,
ExitType . TRAILING_STOP_LOSS . value ,
] ,
}
)
backtestmock = MagicMock (
side_effect = [
{
" results " : result1 ,
" config " : default_conf ,
" locks " : [ ] ,
" rejected_signals " : 20 ,
" timedout_entry_orders " : 0 ,
" timedout_exit_orders " : 0 ,
" canceled_trade_entries " : 0 ,
" canceled_entry_orders " : 0 ,
" replaced_entry_orders " : 0 ,
" final_balance " : 1000 ,
}
]
)
mocker . patch (
" freqtrade.plugins.pairlistmanager.PairListManager.whitelist " ,
PropertyMock ( return_value = [ " ETH/BTC " , " LTC/BTC " , " DASH/BTC " ] ) ,
)
mocker . patch ( " freqtrade.optimize.backtesting.Backtesting.backtest " , backtestmock )
patched_configuration_load_config_file ( mocker , default_conf )
args = [
" backtesting " ,
" --config " ,
" config.json " ,
" --datadir " ,
str ( testdatadir ) ,
" --user-data-dir " ,
str ( user_dir ) ,
" --timeframe " ,
" 5m " ,
" --timerange " ,
" 1515560100-1517287800 " ,
" --export " ,
" signals " ,
" --cache " ,
" none " ,
]
args = get_args ( args )
start_backtesting ( args )
captured = capsys . readouterr ( )
assert " BACKTESTING REPORT " in captured . out
assert " EXIT REASON STATS " in captured . out
assert " LEFT OPEN TRADES REPORT " in captured . out
base_args = [
" backtesting-analysis " ,
" --config " ,
" config.json " ,
" --datadir " ,
str ( testdatadir ) ,
" --user-data-dir " ,
str ( user_dir ) ,
]
# test group 0 and indicator list
args = get_args (
base_args
+ [
" --analysis-groups " ,
" 0 " ,
" --indicator-list " ,
" close " ,
" rsi " ,
" profit_abs " ,
" --entry-only " ,
]
)
start_analysis_entries_exits ( args )
captured = capsys . readouterr ( )
assert " LTC/BTC " in captured . out
assert " ETH/BTC " in captured . out
assert " enter_tag_long_a " in captured . out
assert " enter_tag_long_b " in captured . out
assert " exit_signal " in captured . out
assert " roi " in captured . out
assert " stop_loss " in captured . out
assert " trailing_stop_loss " in captured . out
assert " 0.5 " in captured . out
assert " -4 " in captured . out
assert " -2 " in captured . out
assert " -3.5 " in captured . out
assert " 50 " in captured . out
assert " 0 " in captured . out
assert " 0.016 " in captured . out
assert " 34.049 " in captured . out
assert " 0.104 " in captured . out
assert " 52.829 " in captured . out
# assert indicator list
assert " close " in captured . out
assert " close (entry) " not in captured . out
assert " 0.016 " in captured . out
assert " rsi (entry) " not in captured . out
assert " rsi " in captured . out
assert " 54.320 " in captured . out
assert " close (exit) " not in captured . out
assert " rsi (exit) " not in captured . out
assert " 52.829 " in captured . out
assert " profit_abs " in captured . out