🚀 AI 一键生成 qmt 策略代码

QMT策略中run_time定时器导致循环下单的解决方法

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

问题描述

这段代码为什么一直在循环跑呀,完全停不下来,买入卖出好多遍,请指点,谢谢

#coding:gbk

import time

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

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

# 假设这些是您要卖出和买入的股票代码和金额
sell_stocks_info = [
{'stock_code': '161631.sz', 'amount': 200},
# {'stock_code': '000002.SZ', 'amount': 15000}
]

buy_stocks_info = [
{'stock_code': '161631.SZ', 'amount': 200},
# {'stock_code': '000004.SZ', 'amount': 8000}
]

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:
passorder(24, 1102, '8886006288', stock['stock_code'], 5, -1, stock['amount'], ContextInfo)

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

解决方案

导致您的代码一直循环买入卖出的原因在于 ContextInfo.run_time 函数的第二个参数设置。

在您的代码中:

ContextInfo.run_time("sell_stocks", "1nSecond", trade_date + " " + sell_time)

这里的 "1nSecond" 表示每隔1秒钟重复调用一次回调函数。因此,当时间到达您设定的 startTime 后,系统就会每秒钟执行一次 sell_stocksbuy_stocks,从而导致无限循环下单。

解决方法

如果您只希望在指定时间执行一次,可以通过设置全局标志位(Flag)来控制,或者改用在 handlebar 中判断时间的方式。

方案一:使用全局标志位控制(推荐修改最少)

ContextInfo 中添加标志位,执行过一次后就将其设为 True,下次触发时直接跳过。

#coding:gbk
import time

trade_date = "2024-12-27"
sell_time = "10:05:01"
buy_time = "10:05:05"

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

def init(ContextInfo):
    print("程序开始运行了...")
    # 初始化标志位,防止重复下单
    ContextInfo.has_sold = False
    ContextInfo.has_bought = False
    
    # 依然使用定时器,但内部会判断标志位
    ContextInfo.run_time("sell_stocks", "1nSecond", trade_date + " " + sell_time)
    ContextInfo.run_time("buy_stocks", "1nSecond", trade_date + " " + buy_time)

def sell_stocks(ContextInfo):
    if not ContextInfo.has_sold:
        print("执行卖出操作")
        for stock in sell_stocks_info:
            passorder(24, 1102, '8886006288', stock['stock_code'], 5, -1, stock['amount'], ContextInfo)
        ContextInfo.has_sold = True  # 标记为已卖出

def buy_stocks(ContextInfo):
    if not ContextInfo.has_bought:
        print("执行买入操作")
        for stock in buy_stocks_info:
            passorder(23, 1102, '8886006288', stock['stock_code'], 5, -1, stock['amount'], ContextInfo)
        ContextInfo.has_bought = True  # 标记为已买入

def handlebar(ContextInfo):
    pass

方案二:在 handlebar 中判断时间(更符合行情驱动逻辑)

不使用 run_time,而是利用 QMT 的行情驱动机制,在 handlebar 中获取当前时间进行判断。

#coding:gbk
import time

trade_date = "20241227" # 注意时间格式转换为纯数字方便比较
sell_time = "100501"
buy_time = "100505"

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

def init(ContextInfo):
    print("程序开始运行了...")
    ContextInfo.has_sold = False
    ContextInfo.has_bought = False

def handlebar(ContextInfo):
    # 获取当前K线/Tick的时间戳并转换为字符串
    tick_time = ContextInfo.get_tick_timetag()
    current_date = time.strftime("%Y%m%d", time.localtime(tick_time / 1000))
    current_time = time.strftime("%H%M%S", time.localtime(tick_time / 1000))
    
    # 判断日期是否匹配
    if current_date == trade_date:
        # 判断卖出时间
        if current_time >= sell_time and not ContextInfo.has_sold:
            print("到达卖出时间,执行卖出")
            for stock in sell_stocks_info:
                passorder(24, 1102, '8886006288', stock['stock_code'], 5, -1, stock['amount'], ContextInfo)
            ContextInfo.has_sold = True
            
        # 判断买入时间
        if current_time >= buy_time and not ContextInfo.has_bought:
            print("到达买入时间,执行买入")
            for stock in buy_stocks_info:
                passorder(23, 1102, '8886006288', stock['stock_code'], 5, -1, stock['amount'], ContextInfo)
            ContextInfo.has_bought = True

总结run_time 是一个循环定时器,如果只需要单次触发,必须配合状态变量(如 True/False)来拦截后续的重复执行。