FinRL-Meta 基准评测体系指南:统一绩效指标、基线策略与回测实战
【免费下载链接】FinRLFinRL®: Financial Reinforcement Learning. 🔥项目地址: https://gitcode.com/gh_mirrors/fi/FinRL-Library
导读
本文以 FinRL-Meta 的 Benchmark 文档(docs/source/finrl_meta/Benchmark.rst)为骨架,系统讲解 FinRL 项目中用于衡量交易策略的统一绩效指标体系、官方提供的基线策略定义,以及基于这些指标和基线开展回测对比的完整实践路径。读完本文,你将掌握累计收益、年化收益、年化波动率、Sharpe 比率、最大回撤五类核心指标的数学定义与仓库内计算实现,了解被动策略、均值-方差/最小方差策略、等权策略三类基线的工作原理,并能够使用仓库自带的backtest_stats、backtest_plot等工具对 DRL 智能体与 DJIA、MVO 等基线进行公平对比。
一、FinRL-Meta 的统一绩效指标:为什么需要一套标准
在深度强化学习(DRL)交易实验中,不同论文、不同代码库对"策略好不好"的度量口径往往不一致:有的只看期末总资产,有的用年化收益率,有的用 Sharpe 比率。口径不一致会带来两个直接问题:一是 DRL 算法之间无法横向对比,二是实验结果难以复现。FinRL-Meta 为此定义了一套统一的绩效指标(Performance Metrics),作为所有策略——包括 DRL 智能体与各类基线——的公共度量标准。该设计与其 DataOps 管线的第四步"Performance monitoring(性能监控)"一一对应,即"将 DRL 智能体的表现与若干基线交易策略进行对比"(见 docs/source/finrl_meta/overview.rst)。
下文逐一给出五类指标的定义与解读,公式遵循 Benchmark 文档的原始定义。
1.1 累计收益(Cumulative Return)
累计收益衡量投资期末组合价值相对初始资金的整体增值比例:
$$R = \frac{V - V_0}{V_0}$$
其中 $V$ 为期末组合价值(final portfolio value),$V_0$ 为初始资金(original capital)。这是最直观的"赚了多少"指标,但忽略了时间长度与波动风险,因此通常需要与其他指标配合使用。
1.2 年化收益(Annualized Return)
为消除持有期长短差异,将累计收益折算为年度口径:
$$r = (1+R)^{\frac{365}{t}} - 1$$
其中 $t$ 为实际交易天数(number of trading days)。注意 FinRL-Meta 使用的是 365 天/自然日口径,而非 252 个交易日口径;这一细节在对比不同论文结果时需要留意。
1.3 年化波动率(Annualized Volatility)
波动率度量收益的不确定性,年化波动率按下式给出:
$$\sigma_a = \sqrt{\frac{\sum_{i=1}^{n}{(r_i-\bar{r})^2}}{n-1}}$$
其中 $r_i$ 为第 $i$ 年的年化收益,$\bar{r}$ 为各年年化收益的均值,$n$ 为年数。波动率越高,代表收益路径越颠簸、风险越大。
1.4 Sharpe 比率(Sharpe Ratio)
Sharpe 比率是"风险调整后收益"的核心指标,衡量每承担一单位波动能换来多少超额收益:
$$S = \frac{r - r_f}{\sigma_a}$$
其中 $r$ 为年化收益,$r_f$ 为无风险利率(risk-free rate,实践中常取 0 或国债收益率),$\sigma_a$ 为年化波动率。Sharpe 比率越高,说明策略在相同风险水平下获得了更高回报,是论文与实践中使用最频繁的对比指标。
1.5 最大回撤(Max. Drawdown)
最大回撤定义为组合价值从历史峰值到后续谷底的最大百分比损失(The maximal percentage loss in portfolio value),刻画策略在最坏行情下可能承受的亏损幅度,是衡量尾部风险与回撤控制能力的重要指标。
1.6 指标在仓库中的实际计算位置
上述指标并非只停留在文档公式层面,而是贯穿于 FinRL 的多个实现点:
- 环境内置的 Sharpe 计算:在 finrl/meta/env_stock_trading/env_stocktrading.py 的
step()终止分支中,环境根据account_value的日收益率序列直接计算sharpe = (252**0.5) * daily_return.mean() / daily_return.std(),并在每个 episode 结束时打印end_total_asset、total_reward、total_cost、total_trades与 Sharpe 值。此处采用的是 252 个交易日的年化口径,与文档中 365 天口径的差异恰好印证了"指标口径必须显式声明"的必要性。 - pyfolio 驱动的完整绩效报表:在 finrl/plot.py 中,
backtest_stats(account_value, value_col_name="account_value")将账户价值序列通过get_daily_return()转换为日收益率序列后,交给pyfolio.timeseries.perf_stats()输出包括年化收益、年化波动率、Sharpe、Sortino、最大回撤等在内的完整绩效统计。 - 集成策略脚本的 Sharpe 复算:finrl/applications/stock_trading/ensemble_stock_trading.py 在汇总 ensemble 回测账户价值后,以
(252**0.5) * pct_change(1).mean() / pct_change(1).std()的形式复核 Sharpe 比率。
二、官方基线策略:DRL 智能体的"对照组"
Benchmark 文档规定,DRL 智能体的表现必须与以下三类基线策略(baseline trading strategies)进行对比,以回答"DRL 是否真的比传统方法强"这一核心问题。
2.1 被动交易策略(Passive Trading Strategy)
被动策略即经典的"买入并持有"(buy and hold):投资者买入选定股票或指数后不再进行任何主动操作,长期持有直至期末。它代表市场本身(如买入 DJIA 指数)的收益水平,是判断主动策略是否创造超额收益的最低参照。
在仓库回测示例 examples/FinRL_StockTrading_2026_3_Backtest.py 中,DJIA 指数基线通过yfinance拉取^DJI收盘价,并按首日价格归一化到 1,000,000 美元的初始资金,从而与 DRL 智能体的账户价值曲线处于同一量纲直接对比:
df_dji = yf.download("^DJI", start=TRADE_START_DATE, end=TRADE_END_DATE) fst_day = df_dji["close"].iloc[0] dji = pd.merge( df_dji["date"], df_dji["close"].div(fst_day).mul(1000000), how="outer", left_index=True, right_index=True, ).set_index("date")此外,finrl/plot.py 的get_baseline(ticker, start, end)提供了通用化的基线获取函数,默认 ticker 为^DJI(道琼斯工业指数),也支持^GSPC(标普 500)、^NDX(纳斯达克 100)等指数。
2.2 均值-方差与最小方差策略(Mean-Variance & Min-Variance)
均值-方差(Mean-Variance)与最小方差(Min-Variance)策略源自马科维茨现代投资组合理论,两者都在风险与收益之间寻求平衡:通过构建分散化投资组合,在更低风险下追求更高收益。区别在于优化目标——均值-方差策略最大化每单位风险对应的超额收益(如最大化 Sharpe 比率),最小方差策略则只最小化组合方差。
仓库在 examples/FinRL_StockTrading_2026_3_Backtest.py 中给出了基于pypfopt库的完整 MVO 基线实现,可作为理解该策略的参考骨架:
# 计算训练期各资产的收益率均值与协方差矩阵 meanReturns = np.mean(arReturns, axis=0) covReturns = np.cov(arReturns, rowvar=False) # 用 EfficientFrontier 求解最大 Sharpe 组合,权重限制在 0~0.5 之间 from pypfopt.efficient_frontier import EfficientFrontier ef_mean = EfficientFrontier(meanReturns, covReturns, weight_bounds=(0, 0.5)) raw_weights_mean = ef_mean.max_sharpe() cleaned_weights_mean = ef_mean.clean_weights() # 将最优权重按 1,000,000 美元初始资金换算为各资产份额 mvo_weights = np.array([1000000 * cleaned_weights_mean[i] for i in range(len(cleaned_weights_mean))]) Portfolio_Assets = TradeData @ Initial_Portfolio # 在测试期滚动持有 MVO_result = pd.DataFrame(Portfolio_Assets, columns=["Mean Var"])值得注意的关键细节:MVO 的均值与协方差矩阵仅在训练期数据上估计,随后将训练期末得到的权重在测试期(trade 数据)上持有,这一"训练/测试隔离"做法与 DRL 的训练-测试-交易管线保持一致,避免信息泄露导致对比失真。
2.3 等权策略(Equally Weighted Strategy)
等权策略给组合内不同资产分配相同权重,避免将过高权重集中于个别股票上,是一种天然分散、无需任何估计与优化的朴素基准。它经常作为"无脑分散"的下限参照,用于检验更复杂的权重优化(无论是 MVO 还是 DRL)是否真正带来了超越平均分配的增量价值。
2.4 对比结果的组织方式
examples/FinRL_StockTrading_2026_3_Backtest.py 将五个 DRL 智能体(A2C、DDPG、PPO、TD3、SAC)与 MVO、DJIA 两套基线汇入同一 DataFrame 并绘制"Portfolio Value Over Time"对比曲线,直接呼应 Benchmark 文档"以统一指标度量、以基线为参照"的评测范式。
三、回测实战:从账户价值到绩效报表
理解了指标与基线之后,实战环节的核心是把 DRL 智能体的交易轨迹转化为可比较的绩效数字。FinRL 在 finrl/plot.py 中封装了完整工具链。
3.1 获取账户价值曲线
回测的第一步是让训练好的智能体在测试/交易环境上运行,得到逐日的account_value序列。在 examples/FinRL_StockTrading_2026_3_Backtest.py 中,通过DRLAgent.DRL_prediction(model=trained_ppo, environment=e_trade_gym)依次获得各算法(A2C/DDPG/PPO/TD3/SAC)的账户价值 DataFrame;环境配置中的hmax=100(单笔最大交易股数)、initial_amount=1000000(初始资金)、buy_cost_pct/sell_cost_pct=0.001(双边 0.1% 交易成本)等参数直接决定了回测曲线的形态与真实性。
3.2 核心工具函数
get_daily_return(df, value_col_name="account_value")(finrl/plot.py):对账户价值做pct_change(1)得到日收益率序列,并将日期索引转换为 UTC 时区,供 pyfolio 使用。backtest_stats(account_value, value_col_name="account_value")(finrl/plot.py):调用pyfolio.timeseries.perf_stats()生成完整绩效统计表,直接覆盖本文第一部分所述的年化收益、年化波动率、Sharpe、最大回撤等核心指标。backtest_plot(account_value, baseline_start, baseline_end, baseline_ticker="^DJI", ...)(finrl/plot.py):将策略日收益率与基线(默认 DJIA)日收益率一同交给pyfolio.create_full_tear_sheet(),输出包含累计收益曲线、回撤曲线、月度收益热力图等在内的完整分析报表。get_baseline(ticker, start, end)(finrl/plot.py):基于YahooDownloader拉取指数收盘价作为被动策略基线。
3.3 与集成策略示例的衔接
finrl/applications/stock_trading/ensemble_stock_trading.py 给出了上述工具在生产式回测中的完整调用顺序:先backtest_stats(account_value=df_account_value)输出 DRL 集成策略绩效,再对^DJI基线执行backtest_stats(baseline_df, value_col_name="close")得到基线绩效,最后backtest_plot(...)生成对比报表——这套"策略统计 + 基线统计 + 对比图"的三段式流程正是 Benchmark 文档指标与基线设计的直接落地。
四、Jupyter Notebook 教程:Benchmark 的完整用例集合
Benchmark 文档明确指出,为帮助新手熟悉"数据 → 环境 → 智能体 → 回测对比"的完整管线,FinRL 提供了系列 Jupyter Notebook 教程(位于 FinRL-Tutorials 仓库)。这些教程本身就是 Benchmark 体系的"用例集",覆盖了从单任务到多任务、从训练到部署的全场景:
| 教程主题 | 核心内容 | 对应仓库落地参考 |
|---|---|---|
| 股票交易(Stock trading) | 用主流 DRL 算法交易多只股票 | examples/FinRL_StockTrading_2026_2_train.py、examples/FinRL_StockTrading_2026_3_Backtest.py |
| 组合配置(Portfolio allocation) | 用 DRL 智能体优化一组股票的资产配置 | finrl/meta/env_portfolio_allocation/env_portfolio.py |
| 加密货币交易(Cryptocurrency trading) | 复现 10 种主流加密货币上的交易实验 | finrl/meta/env_cryptocurrency_trading/ |
| 多智能体清算策略(Multi-agent RL for liquidation) | 复现文献[7]实验:多智能体优化清算任务的 shortfall,即在给定周期内顺序卖出给定数量股票,权衡市场冲击成本与风险厌恶 | finrl/meta/env_portfolio_optimization/ |
| 集成策略(Ensemble strategy) | 复现多个 DRL 算法集成的股票交易实验 | finrl/applications/stock_trading/ensemble_stock_trading.py |
| 模拟盘交易(Paper trading demo) | 将自研策略或训练好的智能体接入模拟盘交易 | finrl/meta/paper_trading/alpaca.py、finrl/meta/env_stock_trading/env_stock_papertrading.py |
| 中国 A 股示例(China A-share demo) | 基于中国 A 股市场数据开展实验 | docs/source/tutorial/1-Introduction.rst |
| 超参数调优(Hyperparameter tuning) | 使用 Optuna 或 Ray Tune 进行超参数调优 | finrl/agents/stablebaselines3/tune_sb3.py |
4.1 集成策略中的关键机制:rebalance_window
在 finrl/applications/stock_trading/ensemble_stock_trading.py 中,集成策略通过DRLEnsembleAgent实现,其核心参数rebalance_window=63(每 63 天重新训练一次模型)与validation_window=63(验证与交易窗口同为 63 天)控制滚动再平衡节奏,三个子算法 A2C/PPO/DDPG 的模型参数分别通过A2C_model_kwargs、PPO_model_kwargs、DDPG_model_kwargs传入,各算法训练步数由timesteps_dict指定:
A2C_model_kwargs = {"n_steps": 5, "ent_coef": 0.005, "learning_rate": 0.0007} PPO_model_kwargs = {"ent_coef": 0.01, "n_steps": 2048, "learning_rate": 0.00025, "batch_size": 128} DDPG_model_kwargs = {"buffer_size": 10_000, "learning_rate": 0.0005, "batch_size": 64} timesteps_dict = {"a2c": 10_000, "ppo": 10_000, "ddpg": 10_000} df_summary = ensemble_agent.run_ensemble_strategy(A2C_model_kwargs, PPO_model_kwargs, DDPG_model_kwargs, timesteps_dict)4.2 超参数调优:性能提升的关键环节
Benchmark 文档特别强调超参数调优对 DRL 性能的关键作用。仓库在 finrl/agents/stablebaselines3/tune_sb3.py 中实现了基于 Ray Tune 的调优封装,而 finrl/agents/stablebaselines3/hyperparams_opt.py 提供各算法的超参数搜索空间。同时 finrl/config.py 中预置了 A2C、PPO、DDPG、TD3、SAC、ElegantRL 的默认参数(如PPO_PARAMS = {"n_steps": 2048, "ent_coef": 0.01, "learning_rate": 0.00025, "batch_size": 64}),作为调优的起点与对照组。
4.3 中国 A 股数据的配置支撑
中国 A 股示例依托 finrl/config.py 中的时区配置(如TIME_ZONE_SHANGHAI = "Asia/Shanghai"对应沪深与恒生指数)以及 finrl/meta/data_processors/processor_joinquant.py、finrl/meta/data_processors/processor_tushare.py(若存在)等数据源处理器,说明 Benchmark 的指标与基线体系同样适用于非美股市场。
五、测试流程中的基准评测入口
除 Notebook 教程外,仓库还提供脚本化入口 finrl/test.py 用于对已训练模型执行统一的回测评估。test()函数接收起止日期、ticker 列表、数据源、技术指标列表、DRL 库(elegantrl/rllib/stable_baselines3)与模型名,加载训练好的模型后运行环境得到episode_total_assets:
account_value_erl = test( start_date=TEST_START_DATE, end_date=TEST_END_DATE, ticker_list=DOW_30_TICKER, data_source="yahoofinance", time_interval="1D", technical_indicator_list=INDICATORS, drl_lib="elegantrl", env=env, model_name="ppo", cwd="./test_ppo", net_dimension=512, )其中TEST_START_DATE/TEST_END_DATE与TRADE_START_DATE/TRADE_END_DATE在 finrl/config.py 中定义(如TEST_START_DATE = "2026-01-01"),INDICATORS列表(macd、boll_ub、boll_lb、rsi_30 等 8 个技术指标)决定状态空间构成。该测试结果可直接输入backtest_stats生成绩效报表,完成 Benchmark 文档所要求的"训练-测试-交易"闭环中的评测环节。
六、实践要点总结
- 指标口径要显式声明:文档公式中的年化收益采用 365 天口径,而 env_stocktrading.py 与集成脚本中的 Sharpe 采用 252 交易日口径,引用他人结果前务必核对口径。
- 基线不可省略:被动(DJIA 指数)、MVO、等权三类基线分别代表"市场本身""均值-方差优化""朴素分散"三个参照层次,缺一不可。
- 训练/测试隔离是公平对比的前提:MVO 的协方差矩阵估计与 DRL 的训练集划分都必须严格限定在训练期数据内(见 examples/FinRL_StockTrading_2026_3_Backtest.py)。
- 标准化工具开箱即用:
backtest_stats+backtest_plot+get_baseline三件套(finrl/plot.py)即可完成从账户价值到完整绩效报表与对比图的全流程。 - 从教程到复现:Benchmark 文档列出的八类 Notebook 教程对应仓库中的落地实现与示例脚本,可作为新任务的起点模板。
【免费下载链接】FinRLFinRL®: Financial Reinforcement Learning. 🔥项目地址: https://gitcode.com/gh_mirrors/fi/FinRL-Library
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考