问题描述
我用下单函数 passorder(23, 1102, C.account, i, 3, 0, 1000, f'趋势_{name}', 2, f'趋势_{name}', C)成交了一笔(其中:i 是的值'159915.SZ',name 的值是'创业板 ETF')
用 orderid = get_last_order_id(C.accid, 'stock', 'order')能正确返回委托号
但加上策略名参数后,orderid = get_last_order_id(C.accid, 'stock', 'order', '趋势_创业板 ETF'),就返回-1,不能正确返回委托号了,是哪里的问题呢?
解决方案
在 QMT 平台中,使用 get_last_order_id 加上 strategyName 参数返回 -1,通常是因为传入的策略名与下单时记录的策略名在底层没有完全匹配上,或者触发了该参数的本地生命周期限制。结合您的代码,主要有以下几个排查方向:
1. 全角/半角字符与空格问题(最常见)
观察您提供的代码:f'趋势_{name}',这里的下划线 _ 是全角下划线,而不是常用的英文半角下划线 _。此外,name 的值是 '创业板 ETF',中间包含了一个空格。
在 Python 字符串拼接和底层 C++ 接口传递时,极容易因为全角/半角、多余的空格导致字符串不一致。只要有一个字节不同,底层匹配就会失败并返回 -1。
建议:统一使用英文半角字符,并去除不必要的空格。
# 下单时
strategy_name = f'trend_{name.replace(" ", "")}' # 例如变成 'trend_创业板ETF'
passorder(23, 1102, C.account, i, 3, 0, 1000, strategy_name, 2, strategy_name, C)
# 查询时
orderid = get_last_order_id(C.accid, 'stock', 'order', strategy_name)
2. 中文编码问题
QMT 的底层是 C++,官方文档明确指出 Python 策略脚本需统一使用 GBK 编码(#coding:gbk)。如果在传递包含中文的 strategyName 时发生了隐式的编码转换(例如 UTF-8 与 GBK 混用),底层记录的字符串和您查询时传入的字符串在字节层面上就不相等了。
建议:作为最佳实践,strategyName 和 userOrderId 尽量只使用纯英文和数字,避免使用中文,这样可以彻底杜绝编码带来的匹配问题。
3. 官方文档的“本地客户端”限制
根据 QMT 官方 API 文档对 strategyName 的说明:
*注:strategyName 只对同账号本地客户端有效,即 strategyName 只对当前客户端下的单进行策略区分,且该策略区分只能当前客户端使用。
这意味着:
- 如果您下了单之后,重启了 QMT 客户端,那么之前下单时绑定的
strategyName映射关系在本地内存中就丢失了。此时带策略名查询会返回-1,而不带策略名查询(直接查柜台最新委托)依然能查到。 - 如果您在 A 电脑下单,在 B 电脑查询,带策略名也会失效。
总结与调试建议
为了定位问题,您可以先用一个最简单的纯英文字符串进行测试:
def handlebar(ContextInfo):
# 1. 使用纯英文无空格的策略名
test_strategy_name = 'test_strategy_01'
# 2. 下单
passorder(23, 1102, ContextInfo.account, '159915.SZ', 3, 0, 1000, test_strategy_name, 2, test_strategy_name, ContextInfo)
# 3. 立即查询(确保没有重启客户端)
orderid_all = get_last_order_id(ContextInfo.accid, 'stock', 'order')
orderid_specific = get_last_order_id(ContextInfo.accid, 'stock', 'order', test_strategy_name)
print(f"全局最新委托号: {orderid_all}")
print(f"指定策略委托号: {orderid_specific}")
如果上述纯英文测试能成功返回委托号,说明问题确实出在您原本的全角下划线、空格或中文编码上。修改命名规范即可解决。