问题描述
解决方案
在 QMT 量化交易平台中,init 和 handlebar 是 Python 策略脚本中必须定义的两个核心函数。它们分别负责策略的“初始化”和“周期性执行”。
以下是这两个函数的详细作用、区别及使用场景的解释:
1. init(ContextInfo):初始化函数
作用:
init 是策略启动时的入口,主要用于配置策略运行所需的初始环境和静态参数。
-
执行频率:
- 在策略整个生命周期中,只执行一次。
- 它是在策略加载或点击“运行/回测”按钮的瞬间最先被调用的。
-
主要任务:
- 设置账号: 使用
ContextInfo.set_account()绑定交易账号。 - 设置股票池: 使用
ContextInfo.set_universe()设定策略要关注的标的列表。 - 初始化全局变量: 在
ContextInfo对象上绑定自定义变量(如ContextInfo.count = 0),以便在handlebar中跨周期调用和修改。 - 设置回测参数(仅回测模式): 如设置起止时间、初始资金、手续费率等(虽然这些通常在界面设置,但代码中设置优先级更高)。
- 设置定时器: 使用
ContextInfo.run_time()设置定时任务。
- 设置账号: 使用
代码示例:
def init(ContextInfo):
# 1. 设置交易账号
ContextInfo.set_account('6000001234')
# 2. 设置股票池(例如:平安银行)
ContextInfo.set_universe(['000001.SZ'])
# 3. 初始化自定义全局变量
ContextInfo.hold_days = 0 # 记录持仓天数
print("策略初始化完成")
2. handlebar(ContextInfo):核心执行函数
作用:
handlebar 是策略的“心脏”,包含了所有的交易逻辑、数据处理和信号判断。
-
执行频率:
- 回测模式: 按照 K 线的时间序列,从开始时间到结束时间,每根 K 线(Bar)执行一次。
- 实盘/模拟交易模式:
- 首先对历史 K 线逐根执行(用于计算指标初始状态)。
- 运行到最新一根 K 线(实时行情)时,每一个 Tick(分笔数据)推送都会触发一次执行。
- 通常交易信号是在当前 K 线结束(Last Tick)或下一根 K 线开始(New Bar)时确认。
-
主要任务:
- 获取数据: 调用
get_market_data或get_history_data获取行情。 - 计算指标: 根据行情计算 MA、MACD 等技术指标。
- 逻辑判断: 判断是否满足买入或卖出条件。
- 执行交易: 满足条件时调用
passorder、order_shares等函数下单。 - 绘图输出: 使用
ContextInfo.paint()在界面画图。
- 获取数据: 调用
代码示例:
def handlebar(ContextInfo):
# 1. 获取当前 K 线位置
index = ContextInfo.barpos
# 2. 获取当前主图品种的收盘价
# 注意:这里仅为演示,实际获取数据建议使用 get_market_data_ex
close_price = ContextInfo.get_market_data(['close'])
# 3. 简单的逻辑判断
if close_price > 100:
print(f"当前价格 {close_price} 大于 100,触发逻辑")
# order_shares(...) # 下单逻辑
3. 核心区别对比表
| 特性 | init(ContextInfo) | handlebar(ContextInfo) |
|---|---|---|
| 中文名称 | 初始化函数 | 行情事件/处理函数 |
| 执行次数 | 仅 1 次(启动时) | 多次(随 K 线和 Tick 更新不断执行) |
| 主要用途 | 环境配置、参数设置、变量定义 | 策略逻辑、信号计算、下单交易 |
| 数据状态 | 此时尚未开始遍历行情数据 | 可以获取当前时间点的具体行情数据 |
| 变量传递 | 负责定义全局变量 | 负责读取和修改全局变量 |
4. 变量传递机制(ContextInfo)
QMT 使用 ContextInfo 对象在 init 和 handlebar 之间传递数据。
- 如果你在
init中定义了ContextInfo.my_money = 10000。 - 那么你在
handlebar中就可以通过ContextInfo.my_money读取或修改这个值。 - 注意: 不要使用 Python 原生的
global关键字,建议将所有需要跨函数使用的变量都挂载到ContextInfo对象下。
Q&A
Q: 如果我不写 init 函数会怎样?
A: 策略会报错无法运行。QMT 规定 Python 策略必须包含 init 和 handlebar 两个方法的定义,即使 init 中什么都不做(写 pass),也必须定义它。
Q: 我可以在 init 中下单交易吗?
A: 不建议。init 运行时行情数据流尚未开始驱动,且账号状态可能未完全就绪。交易指令应在 handlebar 中根据行情逻辑触发。
Q: handlebar 在实盘中是每秒运行一次吗?
A: 不是固定的每秒一次。它是行情驱动的。如果有新的 Tick 数据(分笔成交)推送到终端,handlebar 就会被调用一次。如果市场静止无成交,它就不会运行。
Q: 如何判断 handlebar 当前运行的是历史 K 线还是最新的实时 K 线?
A: 可以使用 ContextInfo.is_last_bar() 方法。如果返回 True,表示当前运行到了最后一根 K 线(即实时行情阶段)。