Refactor and add documentation

This commit is contained in:
jainanuj94
2024-08-05 23:19:38 +05:30
parent ecf9c173c4
commit 7f0e5dd335
6 changed files with 40 additions and 47 deletions

View File

@@ -18,15 +18,15 @@ freqtrade backtesting -c <config.json> --timeframe <tf> --strategy <strategy_nam
```
This will tell freqtrade to output a pickled dictionary of strategy, pairs and corresponding
DataFrame of the candles that resulted in buy signals. Depending on how many buys your strategy
makes, this file may get quite large, so periodically check your `user_data/backtest_results`
folder to delete old exports.
DataFrame of the candles that resulted in buy and sell signals.
Depending on how many buys your strategy makes, this file may get quite large,
so periodically check your `user_data/backtest_results` folder to delete old exports.
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.
If all goes well, you should now see a `backtest-result-{timestamp}_signals.pkl` and
`backtest-result-{timestamp}_exited.pkl` files in the `user_data/backtest_results` folder.
To analyze the entry/exit tags, we now need to use the `freqtrade backtesting-analysis` command
with `--analysis-groups` option provided with space-separated arguments:
@@ -141,6 +141,14 @@ Use the `--rejected-signals` option to print out rejected signals.
freqtrade backtesting-analysis -c <config.json> --rejected-signals
```
### Printing analysis on exit signals
Use the `--exit-signals` option to print out analysis on exited signals.
```bash
freqtrade backtesting-analysis -c <config.json> --exit-signals
```
### Writing tables to CSV
Some of the tabular outputs can become large, so printing them out to the terminal is not preferable.

View File

@@ -51,7 +51,9 @@ def _load_exit_signal_candles(backtest_dir: Path):
return _load_backtest_analysis_data(backtest_dir, "exited")
def _process_candles_and_indicators(pairlist, strategy_name, trades, signal_candles):
def _process_candles_and_indicators(
pairlist, strategy_name, trades, signal_candles, analyse_on="open_date"
):
analysed_trades_dict = {strategy_name: {}}
try:
@@ -60,7 +62,7 @@ def _process_candles_and_indicators(pairlist, strategy_name, trades, signal_cand
for pair in pairlist:
if pair in signal_candles[strategy_name]:
analysed_trades_dict[strategy_name][pair] = _analyze_candles_and_indicators(
pair, trades, signal_candles[strategy_name][pair]
pair, trades, signal_candles[strategy_name][pair], analyse_on
)
except Exception as e:
print(f"Cannot process entry/exit reasons for {strategy_name}: ", e)
@@ -68,7 +70,9 @@ def _process_candles_and_indicators(pairlist, strategy_name, trades, signal_cand
return analysed_trades_dict
def _analyze_candles_and_indicators(pair, trades: pd.DataFrame, signal_candles: pd.DataFrame):
def _analyze_candles_and_indicators(
pair, trades: pd.DataFrame, signal_candles: pd.DataFrame, analyse_on="open_date"
):
buyf = signal_candles
if len(buyf) > 0:
@@ -78,8 +82,8 @@ def _analyze_candles_and_indicators(pair, trades: pd.DataFrame, signal_candles:
trades_inds = pd.DataFrame()
if trades_red.shape[0] > 0 and buyf.shape[0] > 0:
for t, v in trades_red.open_date.items():
allinds = buyf.loc[(buyf["date"] < v)]
for t, v in trades_red.iterrows():
allinds = buyf.loc[(buyf["date"] < v[analyse_on])]
if allinds.shape[0] > 0:
tmp_inds = allinds.iloc[[-1]]
@@ -339,8 +343,10 @@ def process_entry_exit_reasons(config: Config):
trades = load_backtest_data(config["exportfilename"], strategy_name)
if trades is not None and not trades.empty:
analyse_on = "open_date"
if do_exited is True:
signal_candles = _load_exit_signal_candles(config["exportfilename"])
analyse_on = "close_date"
else:
signal_candles = _load_signal_candles(config["exportfilename"])
@@ -356,7 +362,11 @@ def process_entry_exit_reasons(config: Config):
)
analysed_trades_dict = _process_candles_and_indicators(
config["exchange"]["pair_whitelist"], strategy_name, trades, signal_candles
config["exchange"]["pair_whitelist"],
strategy_name,
trades,
signal_candles,
analyse_on,
)
res_df = prepare_results(

View File

@@ -42,8 +42,7 @@ from freqtrade.optimize.bt_progress import BTProgress
from freqtrade.optimize.optimize_reports import (
generate_backtest_stats,
generate_rejected_signals,
generate_trade_entry_signal_candles,
generate_trade_exit_signal_candles,
generate_trade_signal_candles,
show_backtest_results,
store_backtest_analysis_results,
store_backtest_stats,
@@ -1560,14 +1559,14 @@ class Backtesting:
self.config.get("export", "none") == "signals"
and self.dataprovider.runmode == RunMode.BACKTEST
):
self.processed_dfs[strategy_name] = generate_trade_entry_signal_candles(
preprocessed_tmp, results
self.processed_dfs[strategy_name] = generate_trade_signal_candles(
preprocessed_tmp, results, "open_date"
)
self.rejected_df[strategy_name] = generate_rejected_signals(
preprocessed_tmp, self.rejected_dict
)
self.exited_dfs[strategy_name] = generate_trade_exit_signal_candles(
preprocessed_tmp, results
self.exited_dfs[strategy_name] = generate_trade_signal_candles(
preprocessed_tmp, results, "close_date"
)
return min_date, max_date

View File

@@ -25,7 +25,6 @@ from freqtrade.optimize.optimize_reports.optimize_reports import (
generate_strategy_comparison,
generate_strategy_stats,
generate_tag_metrics,
generate_trade_entry_signal_candles,
generate_trade_exit_signal_candles,
generate_trade_signal_candles,
generate_trading_stats,
)

View File

@@ -24,8 +24,8 @@ from freqtrade.util import decimals_per_coin, fmt_coin
logger = logging.getLogger(__name__)
def generate_trade_entry_signal_candles(
preprocessed_df: Dict[str, DataFrame], bt_results: Dict[str, Any]
def generate_trade_signal_candles(
preprocessed_df: Dict[str, DataFrame], bt_results: Dict[str, Any], analysis_on="open_date"
) -> Dict[str, DataFrame]:
signal_candles_only = {}
for pair in preprocessed_df.keys():
@@ -36,31 +36,8 @@ def generate_trade_entry_signal_candles(
pairresults = resdf.loc[(resdf["pair"] == pair)]
if pairdf.shape[0] > 0:
for t, v in pairresults.open_date.items():
allinds = pairdf.loc[(pairdf["date"] < v)]
signal_inds = allinds.iloc[[-1]]
signal_candles_only_df = concat(
[signal_candles_only_df.infer_objects(), signal_inds.infer_objects()]
)
signal_candles_only[pair] = signal_candles_only_df
return signal_candles_only
def generate_trade_exit_signal_candles(
preprocessed_df: Dict[str, DataFrame], bt_results: Dict[str, Any]
) -> Dict[str, DataFrame]:
signal_candles_only = {}
for pair in preprocessed_df.keys():
signal_candles_only_df = DataFrame()
pairdf = preprocessed_df[pair]
resdf = bt_results["results"]
pairresults = resdf.loc[(resdf["pair"] == pair)]
if pairdf.shape[0] > 0:
for t, v in pairresults.close_date.items():
allinds = pairdf.loc[(pairdf["date"] < v)]
for t, v in pairresults.iterrows():
allinds = pairdf.loc[(pairdf["date"] < v[analysis_on])]
signal_inds = allinds.iloc[[-1]]
signal_candles_only_df = concat(
[signal_candles_only_df.infer_objects(), signal_inds.infer_objects()]

View File

@@ -393,8 +393,8 @@ def test_backtest_analysis_on_exit_signals_nomock(
assert "0.5" in captured.out
assert "-4" in captured.out
assert "-2" in captured.out
assert "nan" in captured.out
assert "57.654" in captured.out
assert "44.428" in captured.out
assert "0" in captured.out
assert "0.104" in captured.out
assert "0.016" in captured.out