问题描述
解决方案
在 QMT 中实现“日线策略在上午 10:00 执行”,需要根据您的使用场景(回测还是实盘)选择不同的实现方式。
由于 QMT 的回测机制基于 K 线数据,如果您在“日线(1d)”周期下回测,系统只有开盘、收盘、最高、最低四个价格,无法模拟“10:00”这个时间点的精确成交。
因此,最稳健的解决方案是将策略运行周期设置为 分钟线(如 5分钟 或 1分钟),在代码中判断时间是否为 10:00,同时获取日线数据进行指标计算。
以下是两种实现方案:
方案一:分钟周期运行(推荐,支持回测和实盘)
原理:将策略运行周期设置为 5分钟 或 1分钟。在 handlebar 中判断当前 K 线时间是否为 10:00。如果是,则获取日线数据计算信号并下单。
优点:可以在回测中真实模拟 10:00 的价格成交。
# -*- coding: gbk -*-
import pandas as pd
def init(ContextInfo):
# 设置资金账号
ContextInfo.accID = '6000000000' # 请替换为您的资金账号
ContextInfo.set_account(ContextInfo.accID)
# 设置股票池
ContextInfo.target = '600000.SH'
ContextInfo.set_universe([ContextInfo.target])
def handlebar(ContextInfo):
# 1. 获取当前 K 线的时间
# get_bar_timetag 获取的是毫秒时间戳
timetag = ContextInfo.get_bar_timetag(ContextInfo.barpos)
# 转换为 HHMMSS 格式字符串
current_time = timetag_to_datetime(timetag, '%H%M%S')
# 2. 判断时间是否为 10:00
# 注意:如果是5分钟线,10:00的bar代表 09:55-10:00 的数据,通常在 10:00 这一刻完成
if current_time == '100000':
print(f"当前时间: {current_time}, 触发定时交易逻辑")
# 3. 获取日线数据进行策略计算 (关键步骤)
# 虽然策略跑在分钟线上,但我们需要日线的指标(如日线MA)
# count=2 表示获取昨天和今天的数据(今天的数据是不完整的,视策略需求而定)
# 如果需要基于昨天收盘价计算,取倒数第二个数据
daily_data = ContextInfo.get_market_data_ex(
fields=['close', 'open'],
stock_code=[ContextInfo.target],
period='1d',
count=5,
dividend_type='front'
)
if ContextInfo.target not in daily_data:
return
df_daily = daily_data[ContextInfo.target]
# 计算简单的日线策略逻辑,例如:昨天收盘价 > 前天收盘价
if len(df_daily) >= 2:
last_close = df_daily.iloc[-2]['close'] # 昨收
prev_close = df_daily.iloc[-3]['close'] # 前收
# 4. 执行交易
# 示例:金叉买入
if last_close > prev_close:
print("满足条件,执行买入")
# 对手价下单 100 股
passorder(23, 1101, ContextInfo.accID, ContextInfo.target, 14, -1, 100, ContextInfo)
else:
print("不满足条件")
设置说明:
- 在 QMT 界面运行或回测时,请将**“周期”**设置为 5分钟 或 1分钟。
方案二:定时器任务(仅限实盘/模拟盘)
原理:使用 QMT 提供的 run_time 定时函数。
注意:根据文档,run_time 函数在回测模式下无效,仅在实盘或模拟交易中生效。如果您只需要实盘功能,且希望主图保留在日线周期,可以使用此方法。
# -*- coding: gbk -*-
def init(ContextInfo):
# 设置资金账号
ContextInfo.accID = '6000000000'
ContextInfo.set_account(ContextInfo.accID)
# 设置定时任务
# 参数说明: 回调函数名, 周期(1d表示每天), 开始时间, 市场
# 这将在每天的 10:00:00 调用 my_trade_func 函数
ContextInfo.run_time("my_trade_func", "1d", "2023-01-01 10:00:00", "SH")
def handlebar(ContextInfo):
# 日线周期的 handlebar 仅用于画图或盘后处理
pass
def my_trade_func(ContextInfo):
"""
这是专门在 10:00 被调用的交易函数
"""
print("定时任务触发:上午 10:00")
target_stock = '600000.SH'
# 获取日线数据
daily_data = ContextInfo.get_market_data_ex(
fields=['close'],
stock_code=[target_stock],
period='1d',
count=5,
dividend_type='front'
)
if target_stock in daily_data:
df = daily_data[target_stock]
# 获取最新价格(此时是10:00的实时价格)
current_price = df.iloc[-1]['close']
print(f"当前 {target_stock} 价格: {current_price}")
# 下单逻辑
passorder(23, 1101, ContextInfo.accID, target_stock, 14, -1, 100, ContextInfo)
总结
- 如果您需要回测验证策略有效性:请务必使用 方案一,并将策略周期设为分钟线。这是量化交易中处理“日内特定时间交易”的标准做法。
- 如果您只跑实盘且不想改周期:可以使用 方案二 的
run_time接口。
Q&A
Q: 方案一中,我在分钟周期下获取 period='1d' 的数据,获取到的是什么数据?
A: get_market_data_ex 获取日线数据时,最后一行(iloc[-1])是截止到当前时刻的日线数据(即包含从开盘到 10:00 的数据生成的日 K 线),而倒数第二行(iloc[-2])是昨天完整的收盘数据。计算指标(如均线)时通常使用昨天及以前的数据以保持稳定,或者使用包含今日实时数据的动态指标。
Q: 为什么回测不能直接用日线周期在 10:00 交易?
A: 日线回测的数据精度只有“天”。对于回测引擎来说,一天就是一个数据点(O,H,L,C)。它不知道 10:00 时的价格是多少,只能假设你在开盘价或收盘价成交。只有使用分钟线回测,引擎才有 10:00 的分时数据来撮合交易。