🚀 AI 一键生成 qmt 策略代码

如何在 QMT 中构建并管理一个包含股票、期货和 ETF 的多资产投资组合?

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

问题描述

请帮我构建一个包含多种资产的投资组合策略。

解决方案

这是一个非常好的量化交易方向。构建多资产投资组合(Multi-Asset Portfolio)通常旨在通过分散投资来降低风险并平滑收益曲线。

由于您没有指定具体的资产类别(如股票、期货、债券)或具体的配置算法(如风险平价、均值方差、固定比例),我将为您构建一个经典的**固定比例资产配置策略(Fixed Weight Asset Allocation)**作为示例。

策略逻辑说明

本策略将资金分配到三种不同相关性的资产类别中,以实现分散投资:

  1. 权益类(股票):使用沪深300 ETF(510300.SH),代表大盘股表现,权重 40%
  2. 债券类:使用国债 ETF(511010.SH),代表无风险或低风险收益,权重 40%
  3. 大宗商品(黄金):使用黄金 ETF(518880.SH),用于抗通胀和避险,权重 20%

交易逻辑:

  • 调仓频率:按月调仓(每月第一个交易日)。
  • 交易执行:计算当前账户总资产,根据目标权重计算各标的的目标市值,使用 order_target_percent 函数自动调整仓位(多退少补)。

QMT Python 策略代码

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

def init(ContextInfo):
    """
    策略初始化函数
    """
    # 1. 设置资金账号 (请替换为您自己的实盘或模拟账号)
    # 格式如: '6000001234'
    ContextInfo.accID = '6000001234' 
    ContextInfo.set_account(ContextInfo.accID)
    
    # 2. 定义投资组合及其目标权重
    # 这里的标的均为ETF,方便在股票账户中统一交易
    # 510300.SH: 沪深300ETF (权益)
    # 511010.SH: 国债ETF (债券)
    # 518880.SH: 黄金ETF (商品)
    ContextInfo.target_portfolio = {
        '510300.SH': 0.40,
        '511010.SH': 0.40,
        '518880.SH': 0.20
    }
    
    # 3. 设置股票池
    ContextInfo.set_universe(list(ContextInfo.target_portfolio.keys()))
    
    # 4. 初始化全局变量,用于记录上一次调仓的月份
    ContextInfo.last_month = -1
    
    print("策略初始化完成,投资组合目标:", ContextInfo.target_portfolio)

def handlebar(ContextInfo):
    """
    K线周期运行函数
    假设运行在日线周期 (1d)
    """
    # 获取当前K线的时间
    index = ContextInfo.barpos
    realtime = ContextInfo.get_bar_timetag(index)
    # 将时间戳转换为 datetime 对象
    current_date = timetag_to_datetime(realtime, '%Y%m%d')
    
    # 提取当前月份
    current_month = int(current_date[4:6])
    
    # --- 调仓逻辑判断 ---
    # 如果当前月份与上一次调仓月份不同,说明进入了新的月份,执行调仓
    if current_month != ContextInfo.last_month:
        print(f"=== 检测到新月份 {current_month},开始执行月度调仓 ===")
        rebalance_portfolio(ContextInfo)
        
        # 更新上一次调仓月份
        ContextInfo.last_month = current_month

def rebalance_portfolio(ContextInfo):
    """
    执行调仓的核心逻辑
    """
    # 获取当前账户的资产信息(用于计算目标持仓市值)
    # 注意:回测模式下 order_target_percent 会自动使用回测虚拟资金
    # 实盘模式下,建议先获取账户总资产
    
    # 遍历投资组合中的每个标的
    for stock_code, target_weight in ContextInfo.target_portfolio.items():
        
        # 检查标的是否停牌,停牌则跳过
        if ContextInfo.is_suspended_stock(stock_code):
            print(f"标的 {stock_code} 停牌,跳过本次调仓")
            continue
            
        # 获取最新价格,用于日志记录(非下单必须,因为order_target_percent会自动处理)
        last_price = ContextInfo.get_market_data(['close'], stock_code=[stock_code], count=1, period='1d')
        
        if last_price is None or len(last_price) == 0:
            print(f"无法获取 {stock_code} 的行情数据")
            continue
            
        # --- 执行下单 ---
        # order_target_percent 会自动计算当前持仓与目标权重的差额
        # 如果当前持仓不足,会自动买入;如果持仓过多,会自动卖出
        # 参数说明: 
        # stock_code: 代码
        # target_weight: 目标仓位比例 (0.4 代表 40%)
        # ContextInfo: 上下文
        # ContextInfo.accID: 账号
        
        print(f"调整 {stock_code} 仓位至目标权重: {target_weight * 100}%")
        
        # 注意:order_target_percent 在实盘中通常按市价或最新价下单
        # 这里使用默认设置。如果需要指定价格类型,需查阅API文档调整 style 参数
        order_target_percent(stock_code, target_weight, ContextInfo, ContextInfo.accID)

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

代码关键点解析

  1. # -*- coding: gbk -*-:

    • QMT 的 Python 编辑器默认使用 GBK 编码,这行代码对于防止中文注释乱码至关重要。
  2. ContextInfo.target_portfolio:

    • 我们使用一个字典来管理资产代码和对应的权重。这种设计使得策略具有很好的扩展性。如果您想增加资产(例如加入纳指ETF 513100.SH),只需修改这个字典即可。
  3. order_target_percent:

    • 这是 QMT 中非常强大的一个函数。它会自动读取您当前的持仓市值和账户总资产,计算出需要买入或卖出多少股才能达到设定的 0.4 (40%) 比例。这极大地简化了多资产策略的编写难度。
  4. 调仓逻辑 (current_month != ContextInfo.last_month):

    • 这是一个简单的月度调仓触发器。当策略遍历 K 线时,一旦发现当前 K 线的月份与上一次记录的月份不同,就意味着进入了新的一个月,从而触发调仓。

如何在 QMT 中运行

  1. 新建策略:在 QMT 客户端的“策略研究”或“模型研究”界面,新建一个 Python 策略。
  2. 粘贴代码:将上述代码完整复制进去。
  3. 设置参数
    • 账号:修改 init 函数中的 ContextInfo.accID 为您的真实资金账号。
    • 周期:在界面上选择运行周期为 日线 (1d)
    • 回测/实盘
      • 回测:设置好开始和结束时间,点击“回测”。
      • 实盘:点击“运行”,策略会根据实时行情在每个交易日检查是否需要调仓。

进阶扩展建议

如果您希望让这个策略更加专业,可以考虑以下扩展方向:

  1. 动态权重(风险平价/均值方差)
    • 目前是固定权重。您可以引入 scipy 库,在 rebalance_portfolio 中获取历史数据,计算协方差矩阵,动态计算出最优权重,而不是写死 40%/40%/20%。
  2. 加入期货资产
    • 如果组合中包含股指期货(如 IF)或商品期货,需要注意期货是保证金交易,order_target_percent 的逻辑可能需要针对期货的保证金占用进行调整(通常按合约价值计算)。
  3. 风控模块
    • 添加最大回撤控制,当组合净值回撤超过一定比例(如 10%)时,强制平仓或降低权益类资产权重。

如果您需要针对上述任何一个进阶方向进行代码修改,请随时告诉我!


Q&A

Q: 为什么使用 ETF 而不是直接买股票或期货?
A: 在多资产策略的演示中,ETF 是门槛最低的工具。它允许在一个普通的股票账户中同时配置股票、债券、黄金甚至海外资产(QDII),且交易机制统一,便于代码实现和资金管理。

Q: order_target_percent 在实盘中是按什么价格下单的?
A: 默认情况下,QMT 的这个函数通常以最新价(Latest)或对手价下单。在实盘中,为了保证成交,有时需要结合 passorder 函数手动控制报价模式(如使用五档最优价格),但这会增加代码复杂度。

Q: 如何将调仓频率改为每周?
A: 可以利用 ContextInfo.get_bar_timetag 获取的时间戳计算当前是周几。例如,判断 datetime.weekday() == 0 (周一) 且上一次调仓不在本周,即可实现周度调仓。