问题描述
解决方案
在 QMT 平台中,要测试不同的参数组合(如均线周期)以找到最优解,通常不需要编写复杂的循环代码来反复运行回测。QMT 客户端内置了**参数优化(Optimization)**功能,可以直接在界面上设置参数的范围和步长,系统会自动遍历所有组合并给出绩效对比。
以下是实现参数优化的具体步骤和代码示例。
核心步骤
- 代码编写:在策略代码的全局位置(通常是文件开头)定义变量,作为你的策略参数。
- 界面设置:在 QMT 策略编辑器的右侧或下方的“参数设置”面板中,找到对应的变量名,设置其最小值、最大值和步长。
- 运行优化:点击编辑器工具栏上的“优化”按钮(通常在“回测”按钮旁边),系统将自动运行多次回测并生成结果列表。
策略代码示例
下面是一个基于双均线策略的完整代码示例。在这个例子中,SHORT_PERIOD(短期均线)和 LONG_PERIOD(长期均线)就是需要优化的参数。
# -*- coding: gbk -*-
import pandas as pd
import numpy as np
# ==============================================================================
# 策略参数定义 (供参数优化面板调用)
# 在QMT界面的【参数设置】面板中,可以设置这些变量的 最小值、最大值 和 步长
# 例如:SHORT_PERIOD 最小5,最大20,步长5; LONG_PERIOD 最小30,最大60,步长10
# ==============================================================================
SHORT_PERIOD = 5 # 短期均线周期默认值
LONG_PERIOD = 20 # 长期均线周期默认值
def init(ContextInfo):
# 设置账号 (请替换为您的实际账号)
ContextInfo.accid = '6000000000'
ContextInfo.set_account(ContextInfo.accid)
# 设置股票池 (示例使用 沪深300 ETF)
ContextInfo.set_universe(['510300.SH'])
# 设置回测参数 (仅回测模式有效)
ContextInfo.set_commission(0, [0.0001, 0.0001, 0.0003, 0.0003, 0, 5]) # 设置费率
ContextInfo.capital = 1000000 # 初始资金
def handlebar(ContextInfo):
# 获取当前K线位置
index = ContextInfo.barpos
# 获取当前图表的股票代码
stock_code = ContextInfo.get_universe()[0]
# 获取历史行情数据
# 注意:获取的数据长度要足够计算长期均线,这里取 LONG_PERIOD + 5 根
# period='1d' 表示日线,根据实际运行周期调整
data = ContextInfo.get_market_data_ex(
['close'],
[stock_code],
period='1d',
count=LONG_PERIOD + 5,
dividend_type='front'
)
# 如果数据获取失败或长度不足,直接返回
if stock_code not in data or len(data[stock_code]) < LONG_PERIOD:
return
# 提取收盘价序列
close_prices = data[stock_code]['close']
# 计算均线
# 使用 pandas 的 rolling().mean() 计算移动平均
ma_short = close_prices.rolling(window=SHORT_PERIOD).mean()
ma_long = close_prices.rolling(window=LONG_PERIOD).mean()
# 获取最新的均线值 (当前K线) 和 上一根K线的均线值
# iloc[-1] 为最新值,iloc[-2] 为上一个值
current_short = ma_short.iloc[-1]
current_long = ma_long.iloc[-1]
prev_short = ma_short.iloc[-2]
prev_long = ma_long.iloc[-2]
# 获取当前持仓
positions = get_trade_detail_data(ContextInfo.accid, 'stock', 'position')
current_vol = 0
for pos in positions:
if pos.m_strInstrumentID + '.' + pos.m_strExchangeID == stock_code:
current_vol = pos.m_nVolume
break
# ==========================================================================
# 交易逻辑:金叉买入,死叉卖出
# ==========================================================================
# 金叉:短期均线上穿长期均线
is_golden_cross = (prev_short <= prev_long) and (current_short > current_long)
# 死叉:短期均线下穿长期均线
is_death_cross = (prev_short >= prev_long) and (current_short < current_long)
# 执行交易
if is_golden_cross and current_vol == 0:
# 全仓买入
print(f"产生金叉信号: 短期{SHORT_PERIOD} > 长期{LONG_PERIOD},买入")
order_target_percent(stock_code, 1.0, "fix", close_prices.iloc[-1], ContextInfo, ContextInfo.accid)
elif is_death_cross and current_vol > 0:
# 清仓卖出
print(f"产生死叉信号: 短期{SHORT_PERIOD} < 长期{LONG_PERIOD},卖出")
order_target_percent(stock_code, 0.0, "fix", close_prices.iloc[-1], ContextInfo, ContextInfo.accid)
如何在 QMT 界面操作优化
- 保存代码:将上述代码复制到 QMT 的策略编辑器中并保存。
- 打开参数面板:在策略编辑器的右侧(或底部,取决于布局),找到**“参数”或“参数设置”**标签页。
- 识别参数:系统会自动识别代码中的全局变量
SHORT_PERIOD和LONG_PERIOD并显示在列表中。 - 设置范围:
- 选中
SHORT_PERIOD,设置:- 最小:5
- 最大:15
- 步长:5
- (这意味着系统会测试 5, 10, 15 三种情况)
- 选中
LONG_PERIOD,设置:- 最小:20
- 最大:60
- 步长:20
- (这意味着系统会测试 20, 40, 60 三种情况)
- 选中
- 运行优化:
- 点击工具栏上的**“优化”**按钮(注意不是“回测”)。
- 系统会遍历所有组合(例如 3x3=9 种组合)。
- 查看结果:
- 优化完成后,会弹出一个结果列表,显示每一组参数对应的年化收益率、夏普比率、最大回撤等指标。
- 你可以点击表头(如“年化收益率”)进行排序,从而找到表现最好的一组参数。
Q&A
Q: 为什么我在参数面板里看不到我的变量?
A: 确保变量是在函数外部(全局作用域)定义的,并且赋了初始值(如 MA = 5)。如果变量定义在 init 或 handlebar 函数内部,QMT 无法将其识别为可调节参数。
Q: 步长(Step)是什么意思?
A: 步长决定了参数遍历的密度。例如范围是 10 到 20,步长为 2,则测试的参数为 10, 12, 14, 16, 18, 20。步长越小,测试的组合越多,计算时间越长。
Q: 优化结果中的“夏普比率”高好还是低好?
A: 夏普比率(Sharpe Ratio)越高越好。它代表了策略在承担单位风险下获得的超额回报。通常在选择参数时,不仅要看收益率,还要看夏普比率和最大回撤,以防止过拟合。