问题描述
解决方案
在 QMT (Quant Trader) 平台中,对策略进行参数优化(Parameter Optimization)是一个内置的核心功能。它允许你设定参数的变化范围,系统会自动遍历所有组合进行回测,并生成一份绩效对比报告,帮助你找到表现最好的参数组。
以下是在 QMT 中进行参数优化的详细步骤和代码示例:
QMT 参数优化流程
1. 编写策略代码(引用变量)
在 Python 代码中,你不需要硬编码具体的数值(例如 ma_period = 5),而是直接使用变量名。这些变量名稍后将在 QMT 的界面中定义。
示例策略代码:
这是一个简单的双均线策略,我们需要优化快线周期 (fast_period) 和慢线周期 (slow_period)。
# -*- coding: gbk -*-
def init(ContextInfo):
# 策略初始化
# 注意:fast_period 和 slow_period 这两个变量不需要在这里定义具体数值
# 它们将由 QMT 界面上的“参数设置”面板传入
ContextInfo.set_account('你的资金账号')
def handlebar(ContextInfo):
# 获取当前主图品种
stock_code = ContextInfo.stockcode + '.' + ContextInfo.market
# 获取历史行情数据 (使用 get_market_data_ex 接口)
# 注意:为了计算均线,我们需要获取足够长的数据,这里取 slow_period + 10 条
# 在实际优化时,slow_period 是动态变化的,这里取一个安全的最大值或动态获取
# 为演示方便,假设最大周期不超过 60
data = ContextInfo.get_market_data_ex(
['close'],
[stock_code],
period=ContextInfo.period,
count=100,
dividend_type='front'
)
if stock_code not in data:
return
close_prices = data[stock_code]['close']
if len(close_prices) < slow_period:
return
# 计算均线
# fast_period 和 slow_period 是全局变量,直接使用
ma_fast = close_prices.rolling(fast_period).mean().iloc[-1]
ma_slow = close_prices.rolling(slow_period).mean().iloc[-1]
# 获取当前持仓
positions = ContextInfo.get_trade_detail_data(ContextInfo.accid, 'stock', 'position')
current_vol = 0
for pos in positions:
if pos.m_strInstrumentID == stock_code:
current_vol = pos.m_nVolume
break
# 交易逻辑:金叉买入,死叉卖出
if ma_fast > ma_slow and current_vol == 0:
# 全仓买入
order_target_percent(stock_code, 1.0, "FIX", -1, ContextInfo, ContextInfo.accid)
print(f"买入: 快线{fast_period} > 慢线{slow_period}")
elif ma_fast < ma_slow and current_vol > 0:
# 清仓卖出
order_target_percent(stock_code, 0.0, "FIX", -1, ContextInfo, ContextInfo.accid)
print(f"卖出: 快线{fast_period} < 慢线{slow_period}")
2. 在界面设置参数范围
编写完代码后,不要直接点击运行,请关注编辑器右侧(或下方)的 【参数设置】 面板。
你需要在这里添加你在代码中使用的变量名,并设置优化的范围:
- 参数名:填写代码中的变量名,例如
fast_period。 - 最新值:这是默认值,用于单次运行或回测。
- 最小:优化遍历的起始值(例如
5)。 - 最大:优化遍历的结束值(例如
20)。 - 步长:每次增加的数值(例如
5)。
设置示例:
| 参数名 | 最新值 | 最小 | 最大 | 步长 | 含义 |
|---|---|---|---|---|---|
fast_period |
5 | 5 | 20 | 5 | 将遍历: 5, 10, 15, 20 |
slow_period |
20 | 30 | 60 | 10 | 将遍历: 30, 40, 50, 60 |
系统会计算所有组合(笛卡尔积)。在这个例子中,组合数为 4 (fast) * 4 (slow) = 16 种组合。
3. 补充数据
非常重要:在进行优化之前,必须确保本地有足够的数据。
- 点击客户端顶部的菜单 【数据管理】。
- 选择你需要回测的品种(如沪深300成分股)和周期(如日线)。
- 下载对应时间段的历史数据。如果不补充数据,回测和优化将无法进行或结果不准确。
4. 运行优化
- 在策略编辑器顶部工具栏,找到 【优化】 按钮(通常在【回测】按钮旁边)。
- 点击后,系统会弹出一个进度条,开始在后台快速运行这 16 次回测。
5. 分析优化结果
优化完成后,会弹出一个 【评测结果】 窗口(或叫优化报告)。
- 表格展示:每一行代表一组参数组合(例如
fast=5, slow=30)。 - 绩效指标:列出该组合对应的 年化收益率、夏普比率、最大回撤、胜率 等。
- 排序筛选:你可以点击表头,例如点击“夏普比率”,将结果从高到低排序,从而找出风险收益比最好的参数组合。
- 应用参数:选中你满意的某一行,通常可以右键选择“应用参数”,系统会将这组最优参数填回【参数设置】的“最新值”中。
注意事项
- 全局变量机制:QMT 的参数优化机制是将界面上定义的参数名作为 Python 的全局变量注入到策略中。因此,在代码中直接使用变量名即可,无需在
init中声明global(读取时)。 - 避免过度拟合 (Overfitting):
- 不要为了追求最高的收益率而选择极其怪异的参数组合。
- 好的参数通常具有参数平原特征,即最优参数周边的参数表现也应该不错。如果
MA(5, 30)表现极好,但MA(5, 29)和MA(5, 31)表现极差,这通常是过拟合,实盘中不可靠。
- 计算量控制:
- 组合数量 = 参数A步数 × 参数B步数 × ...
- 如果参数过多或步长过小,计算量会呈指数级增长,导致优化时间过长。建议先用大步长锁定范围,再用小步长精细搜索。
- 数据引用:在
handlebar中获取数据时,count(获取的数据长度)应确保大于参数的最大值,否则会导致指标计算在某些大参数下因数据不足而返回NaN。
Q&A
Q: 为什么我在代码里写了 fast_period = 10,优化功能就不起作用了?
A: 如果你在代码中显式赋值了 fast_period = 10,那么无论界面上传入什么参数,代码执行时都会被你的赋值语句覆盖。请删除代码中的赋值语句,或者仅在 try...except 块中设置默认值以防本地调试报错,但在 QMT 界面中必须配置同名参数。
Q: 优化结果中的“夏普比率”和“年化收益”哪个更重要?
A: 这取决于你的风险偏好。通常建议优先关注 夏普比率 (Sharpe Ratio) 和 最大回撤 (Max Drawdown)。高收益如果伴随着巨大的回撤(例如腰斩),在实盘中往往难以坚持。夏普比率高意味着单位风险下的收益更高,策略更稳健。
Q: 可以优化止损止盈的比例吗?
A: 可以。只要将止损比例(如 stop_loss_rate)和止盈比例(如 take_profit_rate)作为变量写入代码逻辑,并在参数面板中设置范围(例如 0.05 到 0.15,步长 0.01),即可进行优化。