问题描述
解决方案
在 QMT (Quantitative Trading Platform) 平台中,策略运行出现错误时,可以通过以下几个步骤和方法进行排查和定位。主要依赖于平台提供的日志输出面板、Python 标准的打印调试以及特定的回调函数。
以下是详细的排查步骤:
QMT 策略运行报错排查指南
1. 查看日志输出面板 (Log Output)
这是最直接的排查方式。当策略运行出错(如语法错误、运行时异常)时,报错信息会直接显示在 QMT 界面下方的 “日志输出” 面板中。
- 操作方法:
- 在策略编辑器界面,找到底部的“日志输出”标签页。
- 查看红色的报错信息。通常会包含
Traceback,指出错误发生的文件行号(Line number)和具体的错误类型(如NameError,SyntaxError,KeyError等)。 - 根据行号回到代码中检查对应的逻辑。
2. 使用 print() 进行断点调试
由于 QMT 的 Python 策略是由 C++ 底层调用的,使用 IDE 的断点调试可能不便,最常用且有效的方法是在关键代码段插入 print() 语句。
- 操作方法:
- 在
init()或handlebar()中打印关键变量的值,确认数据是否获取成功。 - 打印标记字符串(如
print("Step 1 reached")),以确定代码执行到了哪一步中断。 - 注意:
handlebar会在每根 K 线或每个 Tick 触发,打印过多会导致日志刷新过快,建议配合ContextInfo.barpos或ContextInfo.is_last_bar()使用。
- 在
def handlebar(ContextInfo):
# 仅在最后一根K线打印,避免刷屏
if ContextInfo.is_last_bar():
index = ContextInfo.barpos
price = ContextInfo.get_market_data(['close'], stock_code=['600000.SH'])
print(f"当前Bar索引: {index}, 获取到的价格数据: {price}")
3. 调整日志显示级别
如果在回测模式下,可以通过设置 ContextInfo.data_info_level 来控制系统日志的详细程度,以便过滤无用信息或查看更详细的警告。
-
参数说明:
0: 信息 (Info) - 最详细1: 警告 (Warning)2: 错误 (Error)3: 致命 (Fatal) - 仅显示严重错误
-
代码示例:
def init(ContextInfo):
# 设置为 0 可以看到所有级别的日志,有助于排查逻辑细节
ContextInfo.data_info_level = 0
4. 检查数据获取返回值
很多运行时错误(如 AttributeError: 'NoneType' object has no attribute... 或 KeyError)是由于数据获取失败导致的。
- 常见原因:
- 未下载本地数据(QMT 很多接口依赖本地数据)。
get_market_data或get_market_data_ex返回了空值或空 DataFrame。- 引用了不存在的字段名。
- 排查建议:
在使用数据前,务必判断数据是否为空。
def handlebar(ContextInfo):
data = ContextInfo.get_market_data_ex(['close'], ['600000.SH'], period='1d')
# 检查数据是否为空
if '600000.SH' not in data or data['600000.SH'].empty:
print("警告:未获取到 600000.SH 的数据,请检查是否已补充数据")
return
# 正常逻辑...
5. 利用异常下单回调函数 (orderError_callback)
如果是交易环节出错(例如下单后未成交、废单),单纯看代码逻辑无法发现问题,需要使用 orderError_callback 来捕获柜台或验资验券端的拒绝原因。
- 代码示例:
def init(ContextInfo):
ContextInfo.set_account('您的资金账号')
def orderError_callback(ContextInfo, orderArgs, errMsg):
# 当下单异常时,会触发此函数
print("下单出现错误!")
print(f"错误信息: {errMsg}")
print(f"涉及订单参数: {orderArgs}")
6. 常见错误类型速查
- NameError: 变量名拼写错误,或者使用了未在
init中定义且未加global声明的全局变量。 - IndentationError: 缩进错误,Python 对缩进敏感,请确保统一使用空格或 Tab。
- KeyError: 尝试访问字典中不存在的键,通常发生在行情数据获取失败或字段名拼写错误时。
- AttributeError: 尝试调用对象不存在的方法,例如
ContextInfo拼写错误,或者获取的对象为空(None)。
Q&A: QMT 策略调试常见问题
Q: 为什么我的 print 输出在日志面板里看不到?
A: 请检查策略是否正在运行。如果是回测模式,确保回测进度条已经开始走动。如果是实盘/模拟模式,确保行情连接正常。另外,检查是否在 handlebar 中加了限制条件导致代码未执行到 print 语句处。
Q: 报错提示 "global name 'xxxx' is not defined",但我明明在 init 里定义了?
A: 在 QMT 的 Python 框架中,init 和 handlebar 是两个独立的作用域。如果你想在 handlebar 中使用 init 里定义的变量,建议将变量绑定到 ContextInfo 对象上(例如 ContextInfo.my_var = 1),这样它就在全局生命周期内可用了。
Q: 策略没有报错,但是不下单,怎么排查?
A:
- 检查
ContextInfo.set_account()是否正确设置。 - 检查
passorder或order_shares等交易函数的参数是否正确(如opType)。 - 检查是否处于
ContextInfo.is_last_bar()判断中(实盘通常只在最新 K 线交易)。 - 使用
orderError_callback查看是否有柜台拒单信息(如资金不足、非交易时间等)。