免责声明:本文基于个人学习经验整理,仅供技术交流参考,不构成投资建议。
一、前言
在期货量化这条路上,我已经走了整整二十年。这些年踩过最多的坑,就是参数优化。
很多人把回测曲线调得漂亮无比,一到实盘就不行了。问题出在哪?大多是过拟合——策略只是"记住"了历史数据,而不是学会了市场规律。
2026年了,参数优化的方法论已经很成熟。今天这篇文章,我来系统讲讲科学的参数优化方法。
二、参数优化的常见误区
误区1:追求完美回测曲线
年化100%、最大回撤3%、胜率90%——这种曲线99%是过拟合的结果。
误区2:参数越多越好
参数越多,过拟合风险越大。简单的策略往往更稳健。
误区3:只看最优参数
只关注收益最高的参数组合,忽视参数稳定性。
误区4:用全部数据优化
没有留出样本外数据验证,导致"看着答案做题"。
三、科学的参数优化流程
1. 数据分割 → 2. 参数搜索 → 3. 稳定性验证 → 4. 样本外测试 → 5. 滚动验证四、Step 1:数据分割
将数据分为三部分:
| 数据集 | 占比 | 用途 |
|---|---|---|
| 训练集 | 60% | 参数优化 |
| 验证集 | 20% | 参数筛选 |
| 测试集 | 20% | 最终验证 |
代码示例:
fromtqsdkimportTqApi,TqAuth,TqBacktest,TqSimfromdatetimeimportdate# 数据分割# 训练集:2023-01 到 2024-06 (18个月)# 验证集:2024-07 到 2024-12 (6个月)# 测试集:2025-01 到 2025-06 (6个月)TRAIN_START=date(2023,1,1)TRAIN_END=date(2024,6,30)VALID_START=date(2024,7,1)VALID_END=date(2024,12,31)TEST_START=date(2025,1,1)TEST_END=date(2025,6,30)五、Step 2:参数搜索
方法1:网格搜索
遍历所有参数组合:
importitertoolsfromtqsdkimportTqApi,TqAuth,TqBacktest,TqSimfromdatetimeimportdate# 参数网格param_grid={'ma_fast':[5,10,15,20],'ma_slow':[20,30,40,50,60],'stop_loss':[0.01,0.02,0.03]}results=[]# 网格搜索forma_fast,ma_slow,stop_lossinitertools.product(param_grid['ma_fast'],param_grid['ma_slow'],param_grid['stop_loss']):# 跳过无效组合ifma_fast>=ma_slow:continue# 运行回测profit=run_backtest(ma_fast,ma_slow,stop_loss,TRAIN_START,TRAIN_END)results.append({'ma_fast':ma_fast,'ma_slow':ma_slow,'stop_loss':stop_loss,'profit':profit})# 按收益排序importpandasaspd df_results=pd.DataFrame(results)df_results=df_results.sort_values('profit',ascending=False)print(df_results.head(10))方法2:随机搜索
当参数空间很大时,随机搜索效率更高:
importrandomdefrandom_search(n_iter=100):results=[]foriinrange(n_iter):# 随机采样参数params={'ma_fast':random.randint(5,30),'ma_slow':random.randint(20,100),'stop_loss':random.uniform(0.01,0.05)}ifparams['ma_fast']>=params['ma_slow']:continueprofit=run_backtest(**params,start_dt=TRAIN_START,end_dt=TRAIN_END)results.append({**params,'profit':profit})returnpd.DataFrame(results)六、Step 3:参数稳定性验证
好的参数应该是"稳健"的——参数小幅变化时,策略表现不会剧烈波动。
defcheck_param_stability(best_params,df_results):"""检查参数稳定性"""# 找到最优参数附近的参数组合nearby=df_results[(abs(df_results['ma_fast']-best_params['ma_fast'])<=5)&(abs(df_results['ma_slow']-best_params['ma_slow'])<=10)]iflen(nearby)<5:print("附近参数组合太少,无法评估稳定性")returnFalse# 计算收益的标准差profit_std=nearby['profit'].std()profit_mean=nearby['profit'].mean()# 变异系数 < 0.5 认为稳定cv=profit_std/abs(profit_mean)ifprofit_mean!=0elsefloat('inf')print(f"参数稳定性评估:")print(f" 附近参数组合数:{len(nearby)}")print(f" 收益均值:{profit_mean:.2%}")print(f" 收益标准差:{profit_std:.2%}")print(f" 变异系数:{cv:.2f}")ifcv<0.5:print(" ✅ 参数稳定性良好")returnTrueelse:print(" ❌ 参数稳定性较差,可能存在过拟合风险")returnFalse七、Step 4:样本外测试
用验证集数据测试参数:
defvalidate_params(params,valid_start,valid_end):"""在验证集上测试参数"""# 在验证集上运行回测profit=run_backtest(**params,start_dt=valid_start,end_dt=valid_end)returnprofit# 测试Top 5参数组合top_params=df_results.head(5).to_dict('records')print("验证集测试结果:")fori,paramsinenumerate(top_params):train_profit=params['profit']valid_profit=validate_params(params,VALID_START,VALID_END)# 计算衰减率decay=(train_profit-valid_profit)/train_profitiftrain_profit>0elsefloat('inf')print(f"参数组合{i+1}:")print(f" 训练集收益:{train_profit:.2%}")print(f" 验证集收益:{valid_profit:.2%}")print(f" 衰减率:{decay:.2%}")print()衰减率解读:
- < 30%:参数泛化能力较好
- 30%-50%:可接受
50%:可能存在过拟合
八、Step 5:滚动验证
更严格的验证方法——滚动窗口测试:
fromdatetimeimportdate,timedeltafromdateutil.relativedeltaimportrelativedeltadefrolling_validation(params,windows):"""滚动窗口验证"""results=[]fortrain_start,train_end,test_start,test_endinwindows:# 训练(这里只是验证,不重新优化参数)train_profit=run_backtest(**params,start_dt=train_start,end_dt=train_end)# 测试test_profit=run_backtest(**params,start_dt=test_start,end_dt=test_end)results.append({'train_start':train_start,'train_end':train_end,'test_start':test_start,'test_end':test_end,'train_profit':train_profit,'test_profit':test_profit})returnpd.DataFrame(results)# 定义滚动窗口windows=[(date(2023,1,1),date(2023,12,31),date(2024,1,1),date(2024,6,30)),(date(2023,7,1),date(2024,6,30),date(2024,7,1),date(2024,12,31)),(date(2024,1,1),date(2024,12,31),date(2025,1,1),date(2025,6,30)),]# 运行滚动验证rolling_results=rolling_validation(best_params,windows)print(rolling_results)# 计算测试集收益的稳定性test_profits=rolling_results['test_profit']print(f"\n滚动验证汇总:")print(f" 测试集收益均值:{test_profits.mean():.2%}")print(f" 测试集收益标准差:{test_profits.std():.2%}")print(f" 正收益比例:{(test_profits>0).mean():.2%}")九、完整优化流程代码
fromtqsdkimportTqApi,TqAuth,TqBacktest,TqSimfromdatetimeimportdateimportpandasaspdimportnumpyasnpimportitertools# ========== 配置 ==========SYMBOL="SHFE.rb2505"TRAIN_START=date(2023,1,1)TRAIN_END=date(2024,6,30)VALID_START=date(2024,7,1)VALID_END=date(2024,12,31)TEST_START=date(2025,1,1)TEST_END=date(2025,6,30)# ========== 回测函数 ==========defrun_backtest(ma_fast,ma_slow,stop_loss,start_dt,end_dt):"""运行回测,返回收益率"""api=TqApi(TqSim(init_balance=100000),backtest=TqBacktest(start_dt=start_dt,end_dt=end_dt),auth=TqAuth("账户","密码"))# ... 策略代码 ...final_balance=api.get_account().balance api.close()return(final_balance-100000)/100000# ========== 主流程 ==========print("="*50)print("Step 1: 参数网格搜索(训练集)")print("="*50)param_grid={'ma_fast':[5,10,15,20],'ma_slow':[30,40,50,60],'stop_loss':[0.02,0.03]}results=[]forma_fast,ma_slow,stop_lossinitertools.product(*param_grid.values()):ifma_fast>=ma_slow:continueprofit=run_backtest(ma_fast,ma_slow,stop_loss,TRAIN_START,TRAIN_END)results.append({'ma_fast':ma_fast,'ma_slow':ma_slow,'stop_loss':stop_loss,'profit':profit})df_results=pd.DataFrame(results).sort_values('profit',ascending=False)print(df_results.head(10))print("\n"+"="*50)print("Step 2: 参数稳定性验证")print("="*50)best_params=df_results.iloc[0].to_dict()check_param_stability(best_params,df_results)print("\n"+"="*50)print("Step 3: 验证集测试")print("="*50)valid_profit=run_backtest(best_params['ma_fast'],best_params['ma_slow'],best_params['stop_loss'],VALID_START,VALID_END)print(f"验证集收益:{valid_profit:.2%}")print("\n"+"="*50)print("Step 4: 最终测试集验证")print("="*50)test_profit=run_backtest(best_params['ma_fast'],best_params['ma_slow'],best_params['stop_loss'],TEST_START,TEST_END)print(f"测试集收益:{test_profit:.2%}")print("\n"+"="*50)print("最终结果")print("="*50)print(f"最优参数:{best_params}")print(f"训练集收益:{best_params['profit']:.2%}")print(f"验证集收益:{valid_profit:.2%}")print(f"测试集收益:{test_profit:.2%}")十、总结
2026年期货策略参数优化的核心原则:
- 数据分割:训练集、验证集、测试集分开
- 参数稳定性:选择稳健的参数,而非最优的参数
- 样本外验证:必须在未见过的数据上测试
- 滚动验证:多时间段验证增加可信度
- 保持简单:参数越少越好
希望这篇文章能帮助你科学地进行参数优化,避免过拟合的陷阱!
声明:本文基于个人学习经验整理,仅供技术交流参考,不构成任何投资建议。