🚀 AI 一键生成 qmt 策略代码

QMT定时交易代码不执行的原因分析与修正(run_time与order_lots)

qmt | 发布时间: 2026/5/27
以下内容由 EasyQuant 生成。

问题描述

这段代码有问题吗,为什么没有执行成功?

#coding:gbk

import time

# 单独维护交易日期
trade_date = "2024-12-27"

# 固定的交易时间
sell_time = "09:55:01"
buy_time = "09:55:05"

# 假设这些是您要卖出和买入的股票代码和手数/金额
sell_stocks_info = [
# {'stock_code': '511880.sh', 'lots': 800},
# {'stock_code': '511010.sh', 'lots': 300},
{'stock_code': '161631.SZ', 'lots': 100},
{'stock_code': '161631.SZ', 'lots': 100}
]

buy_stocks_info = [
{'stock_code': '161631.SZ', 'amount': 170000},
# {'stock_code': '511260.sh', 'amount': 100000}
]

def init(ContextInfo):
print("程序开始运行了天爷...")
# 设置定时器,在指定日期和卖出时间触发卖出操作
ContextInfo.run_time("sell_stocks", "1nSecond", trade_date + " " + sell_time)
# 设置定时器,在指定日期和买入时间触发买入操作
ContextInfo.run_time("buy_stocks", "1nSecond", trade_date + " " + buy_time)

def sell_stocks(ContextInfo):
# 卖出股票的代码逻辑
for stock in sell_stocks_info:
# 使用order_lots函数按手数卖出
order_lots(stock['stock_code'], stock['lots'], ContextInfo, '8886006288')

def buy_stocks(ContextInfo):
# 买入股票的代码逻辑
for stock in buy_stocks_info:
passorder(23, 1102, '8886006288', stock['stock_code'], 5, -1, stock['amount'], ContextInfo)

def handlebar(ContextInfo):
return

解决方案

这段代码主要存在以下几个导致无法成功执行或执行结果不符合预期的核心问题:

1. run_time 函数缺少 market 参数

根据 QMT API 文档,ContextInfo.run_time 的标准用法为 ContextInfo.run_time(funcName, period, startTime, market)。您的代码中缺少了第四个参数 market(市场代码,如 'SH''SZ'),这会导致底层 C++ 框架解析参数失败,从而定时器无法启动。

2. order_lots 卖出时手数必须为负数

在 QMT 中,使用 order_lotsorder_value 等快捷下单函数时,正数代表买入,负数代表卖出。您的 sell_stocks_infolots100,在 sell_stocks 函数中直接传入 100,系统会将其识别为买入 100 手,而不是卖出。

3. 定时器执行频率问题(逻辑隐患)

您设置的 period"1nSecond",这意味着从设定的时间开始,每隔 1 秒钟就会触发一次回调函数。如果不加控制,您的程序会在 09:55:01 之后每秒钟疯狂发送一次卖出委托,在 09:55:05 之后每秒钟疯狂发送一次买入委托。如果只想执行一次,建议在回调函数执行后取消定时器,或者在 handlebar 中通过时间判断来触发(更推荐)。

4. 运行模式限制

run_time 定时器函数仅在实盘/模拟运行模式下有效,在历史回测模式下是没有意义且不会触发的。请确保您是在“运行”模式下测试该策略。


修正后的代码方案

为了避免定时器每秒重复下单的隐患,推荐直接在 handlebar 中通过判断当前时间戳来触发一次性交易,或者在回调中增加全局变量作为“已执行”的标记。以下是修复了上述问题的代码:

#coding:gbk
import time

# 单独维护交易日期
trade_date = "2024-12-27"

# 固定的交易时间
sell_time = "09:55:01"
buy_time = "09:55:05"

# 假设这些是您要卖出和买入的股票代码和手数/金额
sell_stocks_info = [
    {'stock_code': '161631.SZ', 'lots': 100}, # 注意:这里保持正数,在下单时取负
    {'stock_code': '161631.SZ', 'lots': 100}
]

buy_stocks_info = [
    {'stock_code': '161631.SZ', 'amount': 170000},
]

def init(ContextInfo):
    print("程序开始运行了...")
    # 增加防重复下单的标记
    ContextInfo.has_sold = False
    ContextInfo.has_bought = False
    
    # 修复1:补全 run_time 的 market 参数(这里以 'SZ' 为例,实际上只要填入合法市场即可)
    ContextInfo.run_time("sell_stocks", "1nSecond", trade_date + " " + sell_time, "SZ")
    ContextInfo.run_time("buy_stocks", "1nSecond", trade_date + " " + buy_time, "SZ")

def sell_stocks(ContextInfo):
    # 修复3:防止每秒重复下单
    if ContextInfo.has_sold:
        return
    
    print("触发卖出逻辑...")
    for stock in sell_stocks_info:
        # 修复2:卖出时,lots 必须为负数
        sell_lots = -abs(stock['lots'])
        order_lots(stock['stock_code'], sell_lots, ContextInfo, '8886006288')
        
    ContextInfo.has_sold = True

def buy_stocks(ContextInfo):
    # 修复3:防止每秒重复下单
    if ContextInfo.has_bought:
        return
        
    print("触发买入逻辑...")
    for stock in buy_stocks_info:
        # passorder 23为买入,1102为按金额买入
        passorder(23, 1102, '8886006288', stock['stock_code'], 5, -1, stock['amount'], ContextInfo)
        
    ContextInfo.has_bought = True

def handlebar(ContextInfo):
    return

总结建议

  1. 检查运行模式:务必点击**“运行”**而不是“回测”。
  2. 检查资金账号:确保 '8886006288' 是您当前登录且有效的资金账号。
  3. 检查标的后缀:QMT 中深交所后缀为 .SZ,上交所为 .SH,请确保大小写及后缀准确无误。