本文在上一篇文章(vectorbt学习_17DMA之二网格参数优选)基础上,采用滚动窗口+网格参数优选,分析出动态最优参数。
01,基础配置信息
1 | #conda envs:vectorbt_env |
02,行情获取和可视化
a,时间交易参数配置
1 | # Enter your parameters here |
b,获取行情和行情mask
1 | # Download data with time buffer |
origin ohlcv_wbuf size: (978, 5)
Index(['Open', 'High', 'Low', 'Close', 'Volume'], dtype='object')
wobuf_mask ohlcv size: (728, 5)

20,行情的滑窗处理
注意点:
01,训练集和验证集比例3:1,或者2:1,对应:window_len和set_lens为4:1(或3:1),过大了历史包袱沉重,无法及时响应最新行情,过小了则容易参数跳变,形成类似过拟合效果
02,直观感受是验证集最好收尾相接,实际并非最佳,验证集过短会导致无法触发信号生成,从而形成无交易区间。
a,参数设置和效果预览
1 | # 滚动周期参数设置和大致效果可视化 |

(200, 7) 7
(80, 7) 7
Int64Index([0, 1, 2, 3, 4, 5, 6], dtype='int64', name='split_idx')
split_idx 0 1 2 3 4 5 6
0 48.17 56.98 81.93 175.29 169.00 223.97 310.26
1 48.04 56.98 82.92 177.97 164.51 227.50 311.99
2 48.28 58.00 82.18 173.24 169.07 241.23 306.78
fast_window slow_window split_idx
10 11 0 -0.354158
1 1.117491
2 0.551415
Name: sharpe_ratio, dtype: float64
b,根据滑窗参数切分行情数据
1 | (in_price, in_indexes), (out_price, out_indexes) = roll_in_and_out_samples(price, **split_kwargs) |
(200, 7) 7
(80, 7) 7
[DatetimeIndex(['2020-01-02 00:00:00+00:00', '2020-01-03 00:00:00+00:00', '2020-01-06 00:00:00+00:00', '2020-01-07 00:00:00+00:00', '2020-01-08 00:00:00+00:00', '2020-01-09 00:00:00+00:00', '2020-01-10 00:00:00+00:00', '2020-01-13 00:00:00+00:00', '2020-01-14 00:00:00+00:00', '2020-01-15 00:00:00+00:00',
...
'2020-10-20 00:00:00+00:00', '2020-10-21 00:00:00+00:00', '2020-10-22 00:00:00+00:00', '2020-10-23 00:00:00+00:00', '2020-10-26 00:00:00+00:00', '2020-10-27 00:00:00+00:00', '2020-10-28 00:00:00+00:00', '2020-10-29 00:00:00+00:00', '2020-10-30 00:00:00+00:00', '2020-11-02 00:00:00+00:00'], dtype='datetime64[ns, UTC]', name='split_0', length=200, freq=None), DatetimeIndex(['2020-04-27 00:00:00+00:00', '2020-04-28 00:00:00+00:00', '2020-04-29 00:00:00+00:00', '2020-04-30 00:00:00+00:00', '2020-05-06 00:00:00+00:00', '2020-05-07 00:00:00+00:00', '2020-05-08 00:00:00+00:00', '2020-05-11 00:00:00+00:00', '2020-05-12 00:00:00+00:00', '2020-05-13 00:00:00+00:00',
...
'2021-02-03 00:00:00+00:00', '2021-02-04 00:00:00+00:00', '2021-02-05 00:00:00+00:00', '2021-02-08 00:00:00+00:00', '2021-02-09 00:00:00+00:00', '2021-02-10 00:00:00+00:00', '2021-02-18 00:00:00+00:00', '2021-02-19 00:00:00+00:00', '2021-02-22 00:00:00+00:00', '2021-02-23 00:00:00+00:00'], dtype='datetime64[ns, UTC]', name='split_1', length=200, freq=None), DatetimeIndex(['2020-08-14 00:00:00+00:00', '2020-08-17 00:00:00+00:00', '2020-08-18 00:00:00+00:00', '2020-08-19 00:00:00+00:00', '2020-08-20 00:00:00+00:00', '2020-08-21 00:00:00+00:00', '2020-08-24 00:00:00+00:00', '2020-08-25 00:00:00+00:00', '2020-08-26 00:00:00+00:00', '2020-08-27 00:00:00+00:00',
...
'2021-05-31 00:00:00+00:00', '2021-06-01 00:00:00+00:00', '2021-06-02 00:00:00+00:00', '2021-06-03 00:00:00+00:00', '2021-06-04 00:00:00+00:00', '2021-06-07 00:00:00+00:00', '2021-06-08 00:00:00+00:00', '2021-06-09 00:00:00+00:00', '2021-06-10 00:00:00+00:00', '2021-06-11 00:00:00+00:00'], dtype='datetime64[ns, UTC]', name='split_2', length=200, freq=None)]
###################
2020-01-02 00:00:00+00:00
2020-04-27 00:00:00+00:00
DatetimeIndex(['2020-02-14 00:00:00+00:00', '2020-02-17 00:00:00+00:00'], dtype='datetime64[ns, UTC]', name='split_0', freq=None)
21,滑窗的收益数据计算
a,持有参数收益
在此区间,基础标的物表现
1 | def simulate_holding(price, **kwargs): |
split_idx
0 3.604669
1 3.897711
2 2.890238
3 1.095362
4 1.425303
Name: sharpe_ratio, dtype: float64
split_idx
0 1.849248
1 1.152267
2 1.266940
3 -0.093093
4 1.274854
Name: sharpe_ratio, dtype: float64
b,网格参数收益(训练集和验证集)
1 | def simulate_all_params(price, windows, **kwargs): |
(5460,)
fast_window slow_window split_idx
10 11 0 -0.354158
1 1.117491
2 0.551415
3 0.336980
4 -0.918363
...
48 49 2 -0.758895
3 -0.629667
4 -0.100832
5 -1.404637
6 -0.398260
Name: sharpe_ratio, Length: 5460, dtype: float64
fast_window slow_window split_idx
10 11 0 1.827234
1 -1.103760
2 -2.128081
3 -1.757578
4 1.088042
...
48 49 2 inf
3 1.676608
4 -3.392528
5 3.175129
6 -2.545182
Name: sharpe_ratio, Length: 5460, dtype: float64
c,训练集上的最佳参数用于验证集
大致思路:
01,获取各split_idx的最佳收益(sharp_radio)的参数组合idxmax,也就是fast_window,slow_window,split_idx,三维索引元组
02,按照split_idx进行聚类,取得各split_idx对应的最佳参数。实际含义就是各滑动窗口的最佳参数
1 | def get_best_index(performance, higher_better=True): |
MultiIndex([(40, 44, 0),
(12, 13, 1),
(10, 13, 2),
(10, 40, 3),
(12, 37, 4)],
names=['fast_window', 'slow_window', 'split_idx'])
[[40 44]
[12 13]
[10 13]
[10 40]
[12 37]]

将滚动获取的最佳参数用于验证集,统计收益信息
1 | def simulate_best_params(price, best_fast_windows, best_slow_windows, **kwargs): |
ma_window ma_window split_idx
40 44 0 -0.863821
12 13 1 0.441460
10 13 2 -0.895217
40 3 3.233424
12 37 4 2.764636
Name: sharpe_ratio, dtype: float64
22,sharp ratio的汇总可视化
1 | cv_results_df = pd.DataFrame({ |

关注点:
蓝色部分
正常排序是(从上到下):点线,实现,线段,
橘色部分
实线对实线
说明测试集和验证集的周期收益情况,二者同时出现0轴同侧较好(同时上涨,同时下跌,保持行情的稳定性or延续性)
线段对线段
二者一方面随着各自颜色的实线趋势变化(受各自实线影响较大),其他应该无必然联系
点线对点线
蓝色点高于橘色点线,蓝色是训练集内最佳,橘色则是训练集得到最优参数用于验证集结果收益,大概率低于验证集。
测试,验证集时间长度差异,引入偏差
由于测试集一般是验证集的2-3倍(或更多),对于单边行情(假如上涨),则(测试集的)实线收益。蓝色线大概率位于橘色线上方。
如果下跌,则相反。蓝色由于时间长,大概率位于橘色下方。
注意:
01,202406,对于当前case,y周取值为sharp ratio夏普比,而非收益率。所以数据点高低并不反映收益率。
所以,以上结论需要稍斟酌,并不完全准确。
23,滚动回测收益可视化

可见,整体结果并不很理想,由于参数是滚动的,相比固定参数,期望取得更好收益,实际上并非如此。
大概率是由于技术指标的预热问题,下一篇会修复此问题。