🚀 AI 一键生成 qmt 策略代码

QMT 特色策略:如何利用“日历效应”进行交易?

qmt | 发布时间: 2025/12/16
以下内容由 EasyQuant 生成。

问题描述

如何编写一个利用星期效应(例如周五买入,周一卖出)的交易策略?

解决方案

这是一个基于**星期效应(Weekend Effect)**的交易策略请求。该策略的核心逻辑非常清晰:利用日历效应,在周五买入持有过周末,并在周一卖出。

策略设计思路

  1. 运行周期:建议使用 日线(1d) 周期。
  2. 核心逻辑
    • 获取当前 K 线的时间。
    • 判断当前日期是星期几。
    • 如果是 星期五:全仓买入(持有过周末)。
    • 如果是 星期一:清仓卖出(获利了结或止损)。
    • 其他时间:空仓观望。
  3. 使用的 API
    • get_bar_timetagtimetag_to_datetime:用于获取和转换时间。
    • datetime 库:用于判断星期几(0代表周一,4代表周五)。
    • order_target_percent:用于目标仓位管理(1.0 代表满仓,0.0 代表空仓)。

QMT 策略代码实现

# -*- coding: gbk -*-
import datetime

def init(ContextInfo):
    """
    初始化函数,设定资金账号、标的和其他参数
    """
    # 1. 设置标的股票,这里以沪深300ETF(510300.SH)为例
    ContextInfo.stock_code = '510300.SH'
    
    # 2. 设置股票池
    ContextInfo.set_universe([ContextInfo.stock_code])
    
    # 3. 设置资金账号 (请替换为您真实的资金账号)
    ContextInfo.account_id = 'YOUR_ACCOUNT_ID' 
    ContextInfo.set_account(ContextInfo.account_id)
    
    # 4. 设置策略运行参数
    # 0: 周一, 1: 周二, ..., 4: 周五, 5: 周六, 6: 周日
    ContextInfo.buy_day = 4   # 周五
    ContextInfo.sell_day = 0  # 周一

def handlebar(ContextInfo):
    """
    K线逐根运行函数
    """
    # 获取当前K线的索引位置
    index = ContextInfo.barpos
    
    # 获取当前K线的时间戳 (毫秒)
    timetag = ContextInfo.get_bar_timetag(index)
    
    # 将时间戳转换为字符串格式 'YYYYMMDD'
    date_str = timetag_to_datetime(timetag, '%Y%m%d')
    
    # 将字符串转换为 datetime 对象,以便获取星期几
    try:
        current_date = datetime.datetime.strptime(date_str, '%Y%m%d')
    except:
        # 防止解析错误
        return

    # 获取星期几 (0=周一, 4=周五)
    weekday = current_date.weekday()
    
    # 获取当前标的
    stock = ContextInfo.stock_code
    
    # --- 交易逻辑 ---
    
    # 情况1:如果是周五,且当前没有满仓,则买入
    if weekday == ContextInfo.buy_day:
        # 使用 order_target_percent 调整至 100% 仓位
        # 注意:实盘中建议检查 is_last_bar() 避免历史K线重复发单,
        # 但 order_target_percent 本身具有幂等性(即已经是满仓则不会重复买)
        order_target_percent(stock, 1.0, ContextInfo, ContextInfo.account_id)
        
        # 仅在最后一根K线打印日志,避免回测日志过多
        if ContextInfo.is_last_bar():
            print(f"日期: {date_str} (周五) - 触发买入信号: {stock}")

    # 情况2:如果是周一,且当前持有仓位,则卖出
    elif weekday == ContextInfo.sell_day:
        # 使用 order_target_percent 调整至 0% 仓位 (清仓)
        order_target_percent(stock, 0.0, ContextInfo, ContextInfo.account_id)
        
        if ContextInfo.is_last_bar():
            print(f"日期: {date_str} (周一) - 触发卖出信号: {stock}")
            
    # 情况3:其他时间 (周二、三、四),保持空仓 (如果策略要求严格只持仓周末)
    else:
        # 确保仓位为0 (防止手动干预后策略状态不对)
        # 如果您希望周一卖出后,周二到周四可以做其他操作,请注释掉下面这行
        order_target_percent(stock, 0.0, ContextInfo, ContextInfo.account_id)

代码详解与注意事项

  1. 编码格式
    代码第一行 # -*- coding: gbk -*- 是必须的,因为 QMT 的 Python 环境默认使用 GBK 编码,防止中文注释乱码。

  2. 时间处理

    • ContextInfo.get_bar_timetag(index) 获取的是毫秒级时间戳。
    • timetag_to_datetime 是 QMT 内置函数,将其转为字符串。
    • datetime.datetime.strptime 将字符串转为 Python 的日期对象,从而可以使用 .weekday() 方法。
  3. 交易函数选择

    • 使用了 order_target_percent。这是一个非常方便的高级函数。
    • 1.0 表示调整仓位至总资产的 100%(全仓买入)。
    • 0.0 表示调整仓位至 0%(全仓卖出)。
    • 相比于 passorder,这个函数自动计算需要买卖的数量,非常适合这种简单的资产配置策略。
  4. 回测设置建议

    • 周期:日线。
    • 手续费:由于该策略每周进行一次买卖(高频周转),交易成本(印花税、佣金)对净值影响巨大。回测时请务必设置真实的费率(如万分之二或万分之三)。
    • 成交价格:在日线回测模式下,QMT 通常以当根 K 线的收盘价作为成交价。这意味着策略逻辑是“周五收盘买入,周一收盘卖出”。
  5. 实盘/模拟盘提示

    • 如果在实盘运行,日线周期下,handlebar 通常在行情更新时触发。
    • 为了确保在周五收盘前成交,您可能需要结合 ContextInfo.run_time 定时器功能,或者在盘中(例如 14:55)运行策略检查信号。上述代码在日线图上运行时,通常会在收盘后或盘中最新价触发,具体取决于您的运行模式设置。

常见问题 (Q&A)

Q: 如果周一休市(例如端午节),策略会怎么做?
A: 按照上述代码逻辑,如果周一没有 K 线数据,代码就不会运行。到了周二(weekday=1),代码会进入 else 分支执行 order_target_percent(stock, 0.0),即在周二卖出。这符合“非周五即空仓”的逻辑。

Q: 我想在周一开盘就卖出,而不是收盘,怎么改?
A: 在 QMT 的回测中,日线级别很难精确控制“开盘买/卖”。如果需要更精细的控制,建议将回测周期改为 分钟线(如 15m 或 1h)
在分钟线逻辑中,你需要判断:if weekday == 0 and (是当天的第一根K线): 卖出

Q: 如何更换交易标的?
A: 修改 init 函数中的 ContextInfo.stock_code = '510300.SH',将其改为您想交易的股票代码(如 '600519.SH')即可。