🚀 AI 一键生成 qmt 策略代码

如何使用 QMT 构建和回测全天候投资组合策略?

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

问题描述

请帮我用 Python 写一个全天候投资组合策略

解决方案

这是一个基于 QMT (Quant My Trading) 平台的 全天候(All-Weather)投资组合策略 的 Python 实现代码。

策略核心逻辑

全天候策略由桥水基金(Bridgewater)创始人瑞·达利欧提出,旨在通过配置不同相关性的资产,在各种经济环境(通胀、通缩、经济增长、经济衰退)下都能获得相对稳定的收益。

针对中国市场的 ETF 配置示例(简化版):

  1. 股票 (30%): 代表经济增长。使用 沪深300 ETF (510300.SH)
  2. 长期债券 (40%): 对抗通缩和经济衰退。使用 十年国债 ETF (511260.SH)
  3. 中期债券 (15%): 提供基础收益和防御。使用 五年国债 ETF (511010.SH)
  4. 黄金/大宗商品 (15%): 对抗通胀。使用 黄金 ETF (518880.SH)

策略运行机制

  • 周期: 日线 (1d)。
  • 调仓频率: 每 20 个交易日(约一个月)进行一次再平衡,使各资产回归目标权重。
  • 交易接口: 使用 order_target_percent 按照账户总资产比例下单。

QMT 策略代码

# -*- coding: gbk -*-
import pandas as pd
import time

def init(ContextInfo):
    """
    策略初始化函数
    """
    # 1. 设置资金账号 (请替换为您自己的实盘或模拟账号)
    # 注意:回测模式下,此账号仅作为标识,资金由回测参数设定
    ContextInfo.account_id = '6000000000' 
    ContextInfo.set_account(ContextInfo.account_id)
    
    # 2. 定义全天候策略的资产组合及目标权重
    # 键为ETF代码,值为目标百分比权重
    ContextInfo.target_portfolio = {
        '510300.SH': 0.30,  # 股票:沪深300 ETF
        '511260.SH': 0.40,  # 长债:十年国债 ETF
        '511010.SH': 0.15,  # 中债:五年国债 ETF
        '518880.SH': 0.15   # 商品/黄金:黄金 ETF
    }
    
    # 3. 设置股票池 (用于行情订阅和回测数据下载)
    ContextInfo.set_universe(list(ContextInfo.target_portfolio.keys()))
    
    # 4. 设置调仓参数
    ContextInfo.rebalance_days = 20  # 每20个交易日调仓一次
    ContextInfo.days_counter = 0     # 计数器
    
    print("全天候策略初始化完成")
    print("目标组合: ", ContextInfo.target_portfolio)

def handlebar(ContextInfo):
    """
    K线周期运行函数
    """
    # 仅在K线结束时运行策略逻辑,避免盘中Tick波动频繁触发
    if not ContextInfo.is_last_bar():
        return

    # 获取当前K线索引
    bar_index = ContextInfo.barpos
    
    # 获取当前时间
    current_time = ContextInfo.get_bar_timetag(bar_index)
    current_date = timetag_to_datetime(current_time, '%Y%m%d')
    
    # 计数器递增
    ContextInfo.days_counter += 1
    
    # 判断是否达到调仓周期
    # 逻辑:每 rebalance_days 天,或者第一天运行的时候进行调仓
    if ContextInfo.days_counter % ContextInfo.rebalance_days == 0 or ContextInfo.days_counter == 1:
        print(f"日期: {current_date},触发调仓信号,开始执行再平衡...")
        rebalance(ContextInfo)

def rebalance(ContextInfo):
    """
    再平衡执行函数:将持仓调整至目标权重
    """
    # 获取目标组合
    targets = ContextInfo.target_portfolio
    account_id = ContextInfo.account_id
    
    # 遍历目标组合中的每个标的
    for stock_code, target_weight in targets.items():
        # 获取当前标的的最新价格,用于计算(虽然order_target_percent内部会自动处理,但为了日志记录可以获取一下)
        # 注意:order_target_percent 是按照总资产(现金+持仓市值)的比例下单
        
        # 检查标的是否停牌,停牌则跳过
        if ContextInfo.is_suspended_stock(stock_code):
            print(f"标的 {stock_code} 停牌,跳过调仓")
            continue
            
        # 执行下单:调整至目标比例
        # order_target_percent 会自动计算买卖方向和数量
        # 1101 代表单股/单账号/普通/股数下单方式 (此处函数内部会转换为按比例计算出的股数)
        # 注意:QMT的 order_target_percent 在回测和实盘中表现一致
        
        print(f"调整 {stock_code} 仓位至 {target_weight * 100}%")
        
        # 调用 QMT 的目标比例下单函数
        # 参数说明: 标的代码, 目标比例(0-1), 下单选价类型(5为最新价), 价格(-1为无效), ContextInfo, 账号
        order_target_percent(stock_code, target_weight, 5, -1, ContextInfo, account_id)

def timetag_to_datetime(timetag, format_str):
    """
    辅助函数:将时间戳转换为日期字符串
    """
    import time
    return time.strftime(format_str, time.localtime(timetag / 1000))

代码详细解析

  1. init(ContextInfo) 初始化:

    • ContextInfo.target_portfolio: 这里定义了核心资产配置。你可以根据实际需求修改 ETF 代码。例如,如果你想增加风险偏好,可以提高 510300.SH 的权重。
    • ContextInfo.set_universe: 这一步至关重要,它告诉 QMT 系统需要准备哪些标的的历史数据。
    • ContextInfo.rebalance_days: 设定为 20,意味着大约每个月进行一次仓位检查和调整。
  2. handlebar(ContextInfo) 核心循环:

    • ContextInfo.is_last_bar(): 确保逻辑只在 K 线走完时(或回测的每一天结束时)运行一次,防止盘中重复发单。
    • 调仓逻辑: 使用取模运算 % 来判断是否到达第 20 天。
  3. rebalance(ContextInfo) 交易执行:

    • order_target_percent: 这是 QMT 中非常强大的函数。
      • 如果当前该资产持仓为 0,它会买入直到达到目标比例(例如 30%)。
      • 如果当前持仓因价格上涨变成了 35%,它会自动卖出多余的 5%,使其回归 30%。
      • 如果当前持仓因价格下跌变成了 25%,它会自动买入补足至 30%。
    • 停牌检查: 使用 is_suspended_stock 防止对停牌股票下单导致报错或废单。

使用注意事项

  1. 数据补充:

    • 在运行回测之前,请务必在 QMT 客户端的【数据管理】中下载上述 ETF(510300.SH, 511260.SH 等)的日线数据
    • 注意:511260.SH (十年国债ETF) 上市时间较晚(2017年左右),如果你回测时间很早(比如2015年),代码会因为取不到数据而报错或不交易。回测早期数据时,可以用 511010.SH 代替或寻找其他债券标的。
  2. 实盘配置:

    • init 函数中,将 ContextInfo.account_id 修改为你真实的资金账号。
    • 在 QMT 界面右侧的【模型交易】或【回测】面板中,设置好初始资金。
  3. ETF 最小交易单位:

    • ETF 交易单位通常为 100 份(1手)。如果账户总资金太少(例如只有几千元),可能无法精确分配 7.5% 或 15% 的比例,导致分配失败。建议资金量至少在 5万元以上以获得较好的拟合效果。
  4. 费率设置:

    • ETF 交易通常免印花税,佣金较低。在回测设置中,建议将费率设置得比股票低一些(例如万分之一或万分之二),以更接近真实情况。

常见问题 (Q&A)

Q: 为什么选择 ETF 而不是直接买股票或债券?
A: 在 QMT 量化中,ETF 是实现大类资产配置最便捷的工具。它们流动性好,交易费用低,且能通过一个代码覆盖一篮子资产(如沪深300),非常适合全天候策略。

Q: 如何修改调仓频率?
A: 修改 init 函数中的 ContextInfo.rebalance_days 变量。例如,改为 5 就是每周调仓,改为 60 就是每季度调仓。

Q: 这个策略能保证盈利吗?
A: 全天候策略的目标是降低波动率最大回撤,而不是追求短期暴利。在股市大牛市中,它可能跑不赢纯股票策略;但在股市崩盘或经济衰退时,它的表现通常会优于纯股票策略。

Q: order_target_percent 是按什么基准计算的?
A: 它是按照账户总资产(可用资金 + 持仓市值)来计算的。例如账户总资产 100万,目标权重 0.3,系统会确保该标的持仓市值调整为 30万。