11.3.7 性能回测
在金融市场,回测在评估交易策略性能方面起着关键作用。在强化学习应用中,自动化的回测工具更受欢迎,因为它减少了人为错误。在本项目中,使用Quantopian的pyfolio包来回测我们的交易策略。pyfolio易于使用,包括各种独立的图表,提供了交易策略性能的全面图像。
(1)从经过预处理的数据 processed 中选择在测试期间的唯一交易日期,并将它们存储在名为 unique_trade_date 的变量中。最终,unique_trade_date 将包含测试期间的唯一交易日期。
unique_trade_date = processed[(processed.date > TEST_START_DATE)&(processed.date <= TEST_END_DATE)].date.unique()
对上述代码的具体说明如下:
- processed[(processed.date > TEST_START_DATE)&(processed.date <= TEST_END_DATE)]:选择 processed 数据框中日期在测试期间(介于TEST_START_DATE和TEST_END_DATE之间)的数据。
- .date.unique():从所选日期中提取唯一的日期值,即去重,然后将这些唯一日期存储在 unique_trade_date 变量中。
(2)加载和处理策略的账户价值数据,并计算夏普比率等性能指标,以便对策略的表现进行评估和分析。这对于确定策略的盈利性和风险调整性能非常重要。具体实现代码如下所示。
df_trade_date = pd.DataFrame({'datadate':unique_trade_date})
df_account_value=pd.DataFrame()
for i in range(rebalance_window+validation_window, len(unique_trade_date)+1,rebalance_window):
temp = pd.read_csv('results/account_value_trade_{}_{}.csv'.format('ensemble',i))
df_account_value = df_account_value.append(temp,ignore_index=True)
sharpe=(252**0.5)*df_account_value.account_value.pct_change(1).mean()/df_account_value.account_value.pct_change(1).std()
print('Sharpe Ratio: ',sharpe)
df_account_value=df_account_value.join(df_trade_date[validation_window:].reset_index(drop=True))
对上述代码的具体说明如下:
- 创建一个 df_trade_date 数据框,其中包含了测试期间的唯一交易日期。
- 初始化一个空的 df_account_value 数据框,用于存储策略在不同时间段的账户价值数据。
- 使用循环迭代,依次读取不同时间段的账户价值数据文件,并将它们附加到 df_account_value 数据框中。这些数据文件包含有关策略在不同时间段的账户价值信息。
- 计算策略的夏普比率(Sharpe Ratio),这是一个用于评估策略风险和回报关系的指标。
- 将 df_account_value 数据框与 df_trade_date 数据框合并,以将交易日期与相应的账户价值数据关联起来,以便进一步的分析和可视化。
执行会后输出:
Sharpe Ratio: 0.4778632248462412
(3)输出显示 df_account_value 数据框的前几行,以便查看我们的策略在不同时间段的账户价值数据。具体实现代码如下所示。
df_account_value.head()
执行后会输出:
account_value date daily_return datadate
0 1.000000e+06 2021-04-06 NaN 2021-04-06
1 1.000223e+06 2021-04-07 0.000223 2021-04-07
2 1.001045e+06 2021-04-08 0.000822 2021-04-08
3 1.010268e+06 2021-04-09 0.009213 2021-04-09
4 1.008733e+06 2021-04-12 -0.001520 2021-04-12
(4)绘制 df_account_value 数据框中列account_value的折线图,这个折线图表示了策略在不同时间段内的账户价值变化情况。具体实现代码如下所示。
df_account_value.account_value.plot()
执行效果如图13-1所示,通过绘制账户价值曲线,可以直观地查看策略的表现,了解账户价值的增长或下降趋势。这有助于评估策略的盈利性和风险,以及确定其在不同市场条件下的表现。
图13-1 列account_value的折线图
(4)获取策略回测结果的详细统计信息,以便进行更深入的分析和评估。这些统计信息通常包括夏普比率、年化回报率、最大回撤等指标,以便我们能更全面地了解策略的性能。具体实现代码如下所示。
print("==============Get Backtest Results===========")
now = datetime.datetime.now().strftime('%Y%m%d-%Hh%M')
perf_stats_all = backtest_stats(account_value=df_account_value)
perf_stats_all = pd.DataFrame(perf_stats_all)
对上述代码的具体说明如下:
- 获取当前的日期和时间,并将其格式化为字符串,存储在 now 变量中。
- 调用 backtest_stats 函数,将账户价值数据 df_account_value 作为参数传递。这个函数用于计算回测统计信息,包括各种性能指标和统计数据。
- 将回测统计信息存储在名为 perf_stats_all 的变量中,并将其转换为数据框(DataFrame),以便进一步分析和可视化。
执行后会输出:
==============Get Backtest Results===========
Annual return 0.063630
Cumulative returns 0.063630
Annual volatility 0.154483
Sharpe ratio 0.477863
Calmar ratio 0.501244
Stability 0.188279
Max drawdown -0.126944
Omega ratio 1.084593
Sortino ratio 0.690577
Skew NaN
Kurtosis NaN
Tail ratio 0.909262
Daily value at risk -0.019170
dtype: float64
(5)获取基准指数的回测统计信息,以便将策略的性能与基准进行比较和评估,这有助于确定策略相对于市场表现的优势或劣势。具体实现代码如下所示。
print("==============Get Baseline Stats===========")
baseline_df = get_baseline(
ticker="^DJI",
start = df_account_value.loc[0,'date'],
end = df_account_value.loc[len(df_account_value)-1,'date'])
stats = backtest_stats(baseline_df, value_col_name = 'close')
执行后会输出:
==============Get Baseline Stats===========
[*********************100%***********************] 1 of 1 completed
Shape of DataFrame: (251, 8)
Annual return 0.037486
Cumulative returns 0.037335
Annual volatility 0.134331
Sharpe ratio 0.342028
Calmar ratio 0.331049
Stability 0.066383
Max drawdown -0.113235
Omega ratio 1.058031
Sortino ratio 0.480831
Skew NaN
Kurtosis NaN
Tail ratio 0.970301
Daily value at risk -0.016742
dtype: float64
(6)绘制可视化折线图,展示策略与DJIA的账户价值曲线,以便我们能更清楚地了解策略相对于市场指数的表现,这有助于评估策略的相对优势或劣势。具体实现代码如下所示。
print("==============Compare to DJIA===========")
%matplotlib inline
# S&P 500: ^GSPC
# Dow Jones Index: ^DJI
# NASDAQ 100: ^NDX
backtest_plot(df_account_value,
baseline_ticker = '^DJI',
baseline_start = df_account_value.loc[0,'date'],
baseline_end = df_account_value.loc[len(df_account_value)-1,'date'])
执行后会创建多个子图来显示不同的图形元素或信息,如图13-2所示。
图13-2 绘制的折线图
注意:本项目执行后绘制多个子图来显示不同的图形元素或信息。这是因为在 backtest_plot 函数内部,它创建了多个子图来显示不同的图形元素或信息。通常,绘制一个包含多个子图的组合图表有助于更全面地展示不同方面的数据,以便更全面地呈现策略的性能和特征。