问题描述
在回测时,下单成功后,读取order对象的属性,发现有些属性比如股票代码、成交量、成交价格等可以正常读取,但有些属性比如证券名称、市场名称、投资备注等读取到的值为空字符串。好疑惑,是回测时不支持这些属性读取吗?还是版本问题?示例代码如图片所示。股票代码正常读取,但证券名称和投资备注却是空字符串
解决方案
您好!在 QMT 平台的回测模式下,遇到 get_trade_detail_data 获取的 order 对象部分属性(如证券名称 m_strInstrumentName、市场名称 m_strExchangeName、投资备注 m_strRemark)为空字符串,这并非您的代码错误或单纯的版本问题,而是 QMT 回测引擎的底层机制决定的。
一、 为什么回测时部分属性为空?
根据 QMT 的运行机制,回测模式和实盘/模拟模式使用的是两套不同的撮合引擎:
- 回测引擎(虚拟撮合):为了追求极致的回测速度和降低内存消耗,回测引擎在生成虚拟的
order(委托)和deal(成交)对象时,只保留了计算净值和回测指标最核心的数值型字段(如m_strInstrumentID证券代码、m_nVolumeTotalOriginal委托量、m_dLimitPrice委托价、买卖方向等)。对于描述性的中文字段(证券名称、市场名称)以及用户自定义的透传字段(投资备注),回测引擎通常会省略赋值,因此读取到的是空字符串。 - 实盘/模拟引擎:在实盘或连接仿真柜台时,委托指令会真实经过柜台系统,柜台返回的完整数据包中会包含所有的详细信息,此时这些属性都能正常读取。
二、 替代解决方案
虽然回测引擎没有直接在 order 对象中填充这些属性,但我们可以通过 QMT 提供的其他 API 或 Python 的数据结构来轻松实现相同的功能。
1. 获取“证券名称”的替代方案
既然 order 对象中已经有了证券代码 (m_strInstrumentID),您可以直接调用 ContextInfo.get_stock_name() 函数来动态获取证券名称。
def handlebar(ContextInfo):
# 获取委托列表
order_list = get_trade_detail_data(ContextInfo.accid, 'stock', 'order')
for order in order_list:
stock_code = order.m_strInstrumentID
# 替代方案:通过代码获取名称
stock_name = ContextInfo.get_stock_name(stock_code)
print(f"委托代码: {stock_code}, 证券名称: {stock_name}")
2. 获取“投资备注”的替代方案
在回测中,如果需要追踪某笔订单的自定义备注(例如区分是哪个子策略触发的下单),建议在 ContextInfo 中维护一个全局字典,将委托号或股票代码+时间映射到您的备注信息上。
def init(ContextInfo):
ContextInfo.accid = '您的测试账号'
# 初始化一个字典用于记录投资备注
ContextInfo.order_remarks = {}
def handlebar(ContextInfo):
stock_code = '000001.SZ'
remark = '均线金叉买入策略'
# 下单
passorder(23, 1101, ContextInfo.accid, stock_code, 5, -1, 100, ContextInfo)
# 获取最新委托号并记录备注
order_id = get_last_order_id(ContextInfo.accid, 'stock', 'order')
if order_id != '-1':
ContextInfo.order_remarks[order_id] = remark
# 遍历委托对象时读取备注
order_list = get_trade_detail_data(ContextInfo.accid, 'stock', 'order')
for order in order_list:
sys_id = order.m_strOrderSysID
# 从自定义字典中获取备注,如果不存在则返回默认值
my_remark = ContextInfo.order_remarks.get(sys_id, '无备注')
print(f"委托号: {sys_id}, 投资备注: {my_remark}")
总结
在 QMT 编写策略时,建议核心逻辑依赖于代码(Code)、价格(Price)、数量(Volume)和状态(Status)等硬核字段。对于名称、备注等辅助性字段,在回测阶段可以通过 ContextInfo 的辅助函数或全局变量自行映射解决。当您的策略切换到实盘模式时,order.m_strRemark 等字段自然就会有值了。