问题描述
在策略实现中,python 调用 passorder 函数进行下单:
passorder(23, 1123, C.account_id, i, 5, -1, 1, C)
后跟 :
print(f"{bar_date}——{i}触发买入")
日志已经打印了“触发买入”
但是在副图和历史持仓里面并没有看到有任何下单操作。
已经用了快速下单 quicktrade = 1 ,并且回测时间在界面上和代码中都已经设置,而且两者保持一致。
历史日线数据也已经补充完毕。
解决方案
在 QMT 平台回测中,遇到 passorder 函数成功调用(日志已打印)但没有产生实际持仓和交易记录的情况,通常是由参数传递错误、资金不足或回测撮合机制引起的。根据您提供的代码 passorder(23, 1123, C.account_id, i, 5, -1, 1, C),以下是详细的排查方向和解决方案:
1. quickTrade 参数并未真正生效(核心原因)
您提到“已经用了快速下单 quicktrade = 1”,但在您提供的代码中:
passorder(23, 1123, C.account_id, i, 5, -1, 1, C)
并没有传入 quickTrade 参数!
根据 QMT API 文档,passorder 的完整参数顺序为:
passorder(opType, orderType, accountid, orderCode, prType, modelprice, volume[, strategyName, quickTrade, userOrderId], ContextInfo)
如果您直接把 C (ContextInfo) 放在第 8 个参数的位置,系统会将其识别为 ContextInfo,而中间的可选参数(strategyName, quickTrade, userOrderId)全部使用了默认值(quickTrade 默认为 0)。
默认机制(quickTrade=0)下:信号在当前 K 线的最后一个 tick 确认,在下一根 K 线的第一个 tick 才会触发下单。如果您的买入信号发生在回测时间段的最后一根 K 线,或者下一根 K 线没有数据,就不会产生实际交易。
修改建议:
补全可选参数,显式传入 quickTrade=1:
# 补全 strategyName, quickTrade, userOrderId
passorder(23, 1123, C.account_id, i, 5, -1, 1, "MyStrategy", 1, "Order001", C)
2. orderType=1123(按可用资金比例下单)的资金问题
您使用的 orderType 是 1123,代表单股、单账号、可用资金、比例下单。此时 volume=1 代表使用 100% 的可用资金。
- 初始资金未设置:如果在
init中没有设置ContextInfo.capital,或者回测界面初始资金过小,导致 100% 的可用资金不足以买入 1 手(100股)该股票,QMT 会直接忽略该订单,且不会报错。 - 资金已被占用:如果前面的代码已经触发了买入,可用资金变为 0,后续的
passorder即使调用了,按 100% 比例计算出的买入量也是 0。
排查方法:
在下单前打印一下当前可用资金,确认资金是否足够:
print(f"当前可用资金: {C.capital}") # 或者通过 get_trade_detail_data 获取真实可用资金
3. 股票代码格式不规范
QMT 严格要求股票代码必须包含市场后缀,例如平安银行必须是 '000001.SZ',贵州茅台必须是 '600519.SH'。如果您的变量 i 只是 '000001',底层 C++ 接口会解析失败,导致无法生成委托。
排查方法:
打印变量 i,确保其格式为 代码.市场。
4. 回测选价类型(prType)的限制
您使用的 prType=5(最新价)。根据 QMT 官方文档:
注意:回测时,除了指定价(11),其他下单选价类型均以当期 K 线收盘价结算。
虽然 prType=5 在回测中通常会自动转为收盘价撮合,但为了避免某些极端行情(如一字涨停导致无法买入),建议在回测中明确使用**指定价(11)**进行测试。
💡 终极修改方案
建议您将下单代码修改为如下形式,增加容错和明确的参数传递:
def handlebar(C):
# 假设 i 是股票代码,例如 '000001.SZ'
i = '000001.SZ'
# 获取当前 K 线的收盘价作为指定价
close_price = C.get_market_data(['close'], [i], period='1d', count=1)['close'][0]
# 使用 1101 (按股数/手数下单) 或 1123 (按比例下单)
# 这里演示修复后的 1123 按比例下单,明确传入 quickTrade=1
# 参数顺序: opType, orderType, accountID, orderCode, prType, price, volume, strategyName, quickTrade, userOrderId, ContextInfo
passorder(23, 1123, C.account_id, i, 11, close_price, 1, "StrategyA", 1, "BuyOrder", C)
print(f"{C.get_bar_timetag(C.barpos)}——{i}触发买入,指定价格:{close_price}")
总结检查清单:
- 检查
passorder参数个数,确保quickTrade=1传在了正确的位置(第 9 个参数)。 - 检查回测初始资金是否足够买入 1 手标的。
- 检查股票代码
i是否带有.SH或.SZ后缀。 - 确保触发信号的 K 线之后,还有至少一根 K 线的数据(如果未使用 quickTrade=1)。