第 6 章 · 02 回测实战与报告 本节摘要:本节是回测章的实战部分。先讲 命令的常见用法——单策略回测、指定起始资金、限定时间范围、对比多策略、禁止导出。然后重点讲怎么读懂回测报告:六大张表(主报告、未平仓表、入场标签统计、出场原因统计、混合标签统计、汇总指标)分别回答什么问题,以及最关键的几个数字——总收益、胜率、最大回撤、Sharpe、Sortino、Calmar、Profit Factor、Expectancy——各自的含义和判断标准。最后讲 和 两个事后分析命令,以及 按日/周/月/年拆分收益。读完本节,你能从一个回测报告里读出策略的真实成色,而不是只盯着「赚了多少」。 内容来源:原项目文档 、 ,汉化并套用体系化模板。
本节摘要:本节是回测章的实战部分。先讲
backtesting命令的常见用法——单策略回测、指定起始资金、限定时间范围、对比多策略、禁止导出。然后重点讲怎么读懂回测报告:六大张表(主报告、未平仓表、入场标签统计、出场原因统计、混合标签统计、汇总指标)分别回答什么问题,以及最关键的几个数字——总收益、胜率、最大回撤、Sharpe、Sortino、Calmar、Profit Factor、Expectancy——各自的含义和判断标准。最后讲backtesting-show和backtesting-analysis两个事后分析命令,以及--breakdown按日/周/月/年拆分收益。读完本节,你能从一个回测报告里读出策略的真实成色,而不是只盯着「赚了多少」。
内容来源:原项目文档
docs/backtesting.md、docs/advanced-backtesting.md,汉化并套用体系化模板。
⚠️ 风险提示:回测报告里的盈利数字是「在历史数据 + 一系列假设下」的结果,不是未来承诺。永远结合第 04/05 节的 lookahead / recursive 检测一起看,警惕「好得难以置信」。
阅读完本节,你应当能够:
最简形式(用配置里的交易所、币种、周期):
freqtrade backtesting --strategy AwesomeStrategy
--strategy / -s 指向 user_data/strategies/ 目录下某个 Python 文件里的策略类名。常用变体:
# 指定起始资金(默认 1000) freqtrade backtesting --strategy AwesomeStrategy --dry-run-wallet 1000 # 限定时间范围 freqtrade backtesting --strategy AwesomeStrategy --timerange 20260101-20260801 # 换 1m 周期数据 freqtrade backtesting --strategy AwesomeStrategy --timeframe 1m # 换数据目录 freqtrade backtesting --strategy AwesomeStrategy --datadir user_data/data/binance-2026 # 对比多个策略(数据只读一次,更快) freqtrade backtesting --strategy-list StrategyA StrategyB --timeframe 5m # 不导出交易文件(确定不再分析时) freqtrade backtesting --strategy AwesomeStrategy --export none # 指定自定义手续费(见第 03 节) freqtrade backtesting --strategy AwesomeStrategy --fee 0.001
--timerange 支持多种格式:-20260801(到 8 月 1 日)、20260101-(从 1 月 1 日)、20260101-20260801(区间)、甚至 POSIX 时间戳 1527595200-1527618600。
跑之前请回顾第 01 节讲的假设:入场按开盘价、出场信号按下一根开盘、止损精确成交、无滑点全额成交、同根 K 线内 low 先于 high。报告里的一切数字都建立在这些假设之上。
回测会输出多张表,按顺序回答不同问题。
按交易对列出每笔已平仓交易:
| 列 | 含义 |
|---|---|
| Pair | 交易对 |
| Trades | 该交易对的交易笔数 |
| Avg Profit % | 每笔平均收益率 |
| Tot Profit | 该交易对总绝对盈亏(计价币) |
| Tot Profit % | 相对起始资金的总收益率 |
| Avg Duration | 平均持仓时长 |
| Win/Draw/Loss/Win% | 胜/平/负笔数与胜率 |
最后一行 TOTAL 是整体表现。Tot Profit %(不是 Avg Profit %)才是最常引用的「总收益率」,算法是 绝对盈亏 / 起始资金。
回测结束时还没平仓的交易,会被强制平仓(force_exit)以呈现完整画面。这些交易也包含在表 1 里,但单独列出方便观察「如果回测再跑久一点会怎样」。
如果你的策略用 enter_tag 给入场信号分类(如 enter_tag="rsi_oversold"、"bb_bounce"),这张表按标签拆分盈亏,告诉你哪类入场信号最赚钱。
按出场原因(roi / exit_signal / stop_loss / force_exit / trailing_stop)拆分:
┃ Exit Reason ┃ Exits ┃ Avg Profit % ┃ Tot Profit ┃ Win Draw Loss Win% ┃ ┃ roi ┃ 67 ┃ 1.06 ┃ 245.117 ┃ 67 0 0 100 ┃ ┃ exit_signal ┃ 4 ┃ -2.23 ┃ -31.226 ┃ 0 0 4 0 ┃ ┃ stop_loss ┃ 3 ┃ -10.14 ┃ -112.273 ┃ 0 0 3 0 ┃
这张表是调策略的指南针:
exit_signal 大量亏损 → 出场信号有问题,要么改进、要么关掉 use_exit_signal。stop_loss 笔数过多 → 入场质量差,或止损太紧。roi 笔数过多但单笔利润极低 → ROI 阶梯太松或太紧,需要调。把入场标签 × 出场原因交叉,看「某类入场信号在什么出场方式下表现如何」。表很大,适合 CSV 导出后细看。
这是回测的「成绩单」,关键指标见下一节。
| 指标 | 含义 | 经验判断 |
|---|---|---|
| Total profit % | 总收益率 = 绝对盈亏 / 起始资金 | 不能孤立看,要结合回撤和样本量 |
| CAGR % | 年化复合增长率 | 跨周期比较时用 |
| Sharpe | 收益 / 波动(标准差),衡量「风险调整后收益」 | > 1 可接受,> 2 优秀,> 3 极佳 |
| Sortino | 类似 Sharpe,但只用下行波动 | 比 Sharpe 更宽容上涨波动;> 2 算好 |
| Calmar | 年化收益 / 最大回撤 | > 3 算稳健 |
| Profit Factor | 总盈利 / 总亏损 | > 1.5 可考虑,> 2 优秀;< 1 亏 |
| Expectancy (Ratio) | 每笔交易平均期望收益 | 必须为正;负则策略必亏 |
| Max % underwater | 最大回撤比例 | 越小越好;> 30% 心理难承受 |
| Drawdown duration | 最大回撤持续时长 | 越短越好 |
| Mean profit p-value | 单样本 t 检验,「平均收益是否显著非零」 | < 0.05 才算统计显著(非运气) |
| Best/Worst Pair | 表现最好/最差的交易对 | 揪异常币 |
| Max Consecutive Wins/Loss | 最大连胜/连亏 | 评估心理承受 |
新版本多了「Wallet based Metrics」一组指标,基于含未实现盈亏的钱包余额计算,比只看已平仓交易更全面:
Sharpe (daily wallet balance):含浮亏的 Sharpe,通常比 Sharpe (closed trades) 更保守、更真实。Absolute drawdown (wallet balance):含浮亏的最大回撤。💡 优先看 Wallet 口径:它把「账面浮亏」算进来,更接近实盘体验。如果 Wallet 口径的回撤远大于 closed trades 口径,说明策略有大量「浮亏扛单」。
Mean profit p-value 回答的是:「如果策略真没有优势,纯靠运气得到至少这么大的平均收益的概率是多少?」< 0.05 通常算「统计显著」。但要注意:
用 --breakdown 把收益按日/周/月/年拆分,看策略在不同时间段的表现是否稳定:
freqtrade backtesting --strategy MyStrategy --breakdown month year
输出形如月度表、年度表,显示每期的交易数、绝对盈亏、Profit Factor、胜率。如果某几个月巨亏、其他月份巨赚,说明策略对行情 regime 敏感,稳定性差。
默认情况下,如果策略和配置与最近一天内的某次回测完全一致,freqtrade 会复用缓存结果。想强制重跑:
freqtrade backtesting --strategy MyStrategy --cache none
⚠️ 缓存陷阱:开区间
--timerange 20260101-会自动禁用缓存(因为数据可能变了)。但如果你之前回测时数据末尾缺数据、后来补全了,缓存可能误用旧结果——这时务必--cache none跑一次。
回测默认导出到 user_data/backtest_results/,是一个 zip 包,内含:
这保证结果可复现(在数据不变的前提下)。但注意:策略的依赖文件不在 zip 里,要自己保管。
回测跑完后,可以进一步分析导出的结果文件。
回看某次回测的细节,不必重跑:
freqtrade backtesting-show --export-filename user_data/backtest_results/backtest-result-20260805-10-30-00.zip
需要先在回测时加 --export signals(导出信号和交易详情):
freqtrade backtesting -c config.json --strategy MyStrategy --export signals
然后分析:
# 按 0-5 不同粒度分组(0 最简,4 最细——按 pair+enter_tag+exit_tag) freqtrade backtesting-analysis -c config.json --analysis-groups 0 1 2 3 4 5
--analysis-groups 的含义:
0:按 enter_tag 的总胜率和盈亏1:按 enter_tag 分组2:按 enter_tag × exit_tag3:按 pair × enter_tag4:按 pair × enter_tag × exit_tag(表很大)5:按 exit_tag最强大的功能是打印信号 K 线上的指标值,辅助精细调参:
freqtrade backtesting-analysis -c config.json \ --analysis-groups 0 2 \ --enter-reason-list enter_tag_a enter_tag_b \ --exit-reason-list roi stop_loss \ --indicator-list rsi bb_lowerband ema_9
输出会在每笔交易的进场点和出场点列出这些指标的当时值,帮你判断「信号触发时的市场状态是否符合预期」。指标必须在策略的 DataFrame 里存在,否则被忽略。
--timerange 20220101-20220201:只看某段时间的交易。--rejected-signals:打印被拒掉的信号(满仓没下单的)。--analysis-to-csv:大表写 CSV 而非打印。--backtest-filename / --backtest-directory:分析历史或他处的结果。backtesting --strategy X,--dry-run-wallet(起始资金)、--timerange、--timeframe、--strategy-list(对比)、--fee、--cache none(强制重跑)。backtesting-show 看细节;backtesting-analysis --analysis-groups 按标签拆分、--indicator-list 看信号 K 线指标值、--rejected-signals 看被拒信号。下一节,我们专门讲滑点与手续费——它们是回测默认偏乐观的两大来源,正确设置才能让回测更接近实盘。