Update docs, add test

This commit is contained in:
froggleston 2022-05-24 20:27:15 +01:00
parent 8c03ebb78f
commit 3adda84b96
5 changed files with 117 additions and 21 deletions

View File

@ -22,23 +22,19 @@ DataFrame of the candles that resulted in buy signals. Depending on how many buy
makes, this file may get quite large, so periodically check your `user_data/backtest_results`
folder to delete old exports.
To analyze the buy tags, we need to use the `buy_reasons.py` script from
[froggleston's repo](https://github.com/froggleston/freqtrade-buyreasons). Follow the instructions
in their README to copy the script into your `freqtrade/scripts/` folder.
Before running your next backtest, make sure you either delete your old backtest results or run
backtesting with the `--cache none` option to make sure no cached results are used.
If all goes well, you should now see a `backtest-result-{timestamp}_signals.pkl` file in the
`user_data/backtest_results` folder.
Now run the `buy_reasons.py` script, supplying a few options:
To analyze the entry/exit tags, we now need to use the `freqtrade analysis` command:
``` bash
python3 scripts/buy_reasons.py -c <config.json> -s <strategy_name> -t <timerange> -g0,1,2,3,4
freqtrade analysis -c <config.json> -s <strategy_name> --analysis_groups 0,1,2,3,4
```
The `-g` option is used to specify the various tabular outputs, ranging from the simplest (0)
The `--analysis_groups` option is used to specify the various tabular outputs, ranging from the simplest (0)
to the most detailed per pair, per buy and per sell tag (4). More options are available by
running with the `-h` option.
@ -54,18 +50,18 @@ To show only certain buy and sell tags in the displayed output, use the followin
For example:
```bash
python3 scripts/buy_reasons.py -c <config.json> -s <strategy_name> -t <timerange> -g0,1,2,3,4 --enter_reason_list "enter_tag_a,enter_tag_b" --exit_reason_list "roi,custom_exit_tag_a,stop_loss"
freqtrade analysis -c <config.json> -s <strategy_name> --analysis_groups 0,1,2,3,4 --enter_reason_list "enter_tag_a,enter_tag_b" --exit_reason_list "roi,custom_exit_tag_a,stop_loss"
```
### Outputting signal candle indicators
The real power of the buy_reasons.py script comes from the ability to print out the indicator
The real power of `freqtrade analysis` comes from the ability to print out the indicator
values present on signal candles to allow fine-grained investigation and tuning of buy signal
indicators. To print out a column for a given set of indicators, use the `--indicator-list`
option:
```bash
python3 scripts/buy_reasons.py -c <config.json> -s <strategy_name> -t <timerange> -g0,1,2,3,4 --enter_reason_list "enter_tag_a,enter_tag_b" --exit_reason_list "roi,custom_exit_tag_a,stop_loss" --indicator_list "rsi,rsi_1h,bb_lowerband,ema_9,macd,macdsignal"
freqtrade analysis -c <config.json> -s <strategy_name> --analysis_groups 0,1,2,3,4 --enter_reason_list "enter_tag_a,enter_tag_b" --exit_reason_list "roi,custom_exit_tag_a,stop_loss" --indicator_list "rsi,rsi_1h,bb_lowerband,ema_9,macd,macdsignal"
```
The indicators have to be present in your strategy's main DataFrame (either for your main

View File

@ -52,8 +52,6 @@ def start_analysis_entries_exits(args: Dict[str, Any]) -> None:
# Initialize configuration
config = setup_analyze_configuration(args, RunMode.BACKTEST)
print(config)
logger.info('Starting freqtrade in analysis mode')
process_entry_exit_reasons(Path(config['user_data_dir'], 'backtest_results'),

View File

@ -15,10 +15,18 @@ logger = logging.getLogger(__name__)
def _load_signal_candles(backtest_dir: Path):
if backtest_dir.is_dir():
scpf = Path(backtest_dir,
os.path.splitext(
get_latest_backtest_filename(backtest_dir))[0] + "_signals.pkl"
)
else:
scpf = Path(os.path.splitext(
get_latest_backtest_filename(backtest_dir))[0] + "_signals.pkl"
)
print(scpf)
try:
scp = open(scpf, "rb")
signal_candles = joblib.load(scp)
@ -246,7 +254,6 @@ def process_entry_exit_reasons(backtest_dir: Path,
signal_candles = _load_signal_candles(backtest_dir)
analysed_trades_dict = _process_candles_and_indicators(pairlist, strategy_name,
trades, signal_candles)
_print_results(analysed_trades_dict,
strategy_name,
analysis_groups,

View File

@ -0,0 +1,94 @@
from pathlib import Path
from unittest.mock import MagicMock, PropertyMock
import pandas as pd
from freqtrade.commands.analyze_commands import start_analysis_entries_exits
from freqtrade.commands.optimize_commands import start_backtesting
from freqtrade.enums import ExitType
from tests.conftest import get_args, patch_exchange, patched_configuration_load_config_file
def test_backtest_analysis_nomock(default_conf, mocker, caplog, testdatadir, capsys):
default_conf.update({
"use_exit_signal": True,
"exit_profit_only": False,
"exit_profit_offset": 0.0,
"ignore_roi_if_entry_signal": False,
'analysis_groups': "0",
'enter_reason_list': "all",
'exit_reason_list': "all",
'indicator_list': "bb_upperband,ema_10"
})
patch_exchange(mocker)
result1 = pd.DataFrame({'pair': ['ETH/BTC', 'LTC/BTC'],
'profit_ratio': [0.0, 0.0],
'profit_abs': [0.0, 0.0],
'open_date': pd.to_datetime(['2018-01-29 18:40:00',
'2018-01-30 03:30:00', ], utc=True
),
'close_date': pd.to_datetime(['2018-01-29 20:45:00',
'2018-01-30 05:35:00', ], utc=True),
'trade_duration': [235, 40],
'is_open': [False, False],
'stake_amount': [0.01, 0.01],
'open_rate': [0.104445, 0.10302485],
'close_rate': [0.104969, 0.103541],
"is_short": [False, False],
'enter_tag': ["enter_tag_long", "enter_tag_long"],
'exit_reason': [ExitType.ROI, ExitType.ROI]
})
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),
'--strategy-path', str(Path(__file__).parents[1] / 'strategy/strats'),
'--timeframe', '5m',
'--timerange', '1515560100-1517287800',
'--export', 'signals',
'--cache', 'none',
'--strategy-list',
'StrategyTestV3',
]
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
args = [
'analysis',
'--config', 'config.json',
'--datadir', str(testdatadir),
'--analysis_groups', '0',
'--strategy',
'StrategyTestV3',
]
args = get_args(args)
start_analysis_entries_exits(args)
captured = capsys.readouterr()
assert 'enter_tag_long' in captured.out

View File

@ -143,12 +143,13 @@ class StrategyTestV3(IStrategy):
(dataframe['adx'] > 65) &
(dataframe['plus_di'] > self.buy_plusdi.value)
),
'enter_long'] = 1
['enter_long', 'enter_tag']] = 1, 'enter_tag_long'
dataframe.loc[
(
qtpylib.crossed_below(dataframe['rsi'], self.sell_rsi.value)
),
'enter_short'] = 1
['enter_short', 'enter_tag']] = 1, 'enter_tag_short'
return dataframe
@ -166,13 +167,13 @@ class StrategyTestV3(IStrategy):
(dataframe['adx'] > 70) &
(dataframe['minus_di'] > self.sell_minusdi.value)
),
'exit_long'] = 1
['exit_long', 'exit_tag']] = 1, 'exit_tag_long'
dataframe.loc[
(
qtpylib.crossed_above(dataframe['rsi'], self.buy_rsi.value)
),
'exit_short'] = 1
['exit_long', 'exit_tag']] = 1, 'exit_tag_short'
return dataframe