🚀 AI 一键生成 qmt 策略代码

QMT Python 策略:如何实现一个动态跟踪沪深300的指数复刻策略?

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

问题描述

我想写一个策略,每天自动获取沪深300的成分股,然后根据它们的权重买入,怎么实现?

解决方案

这是一个非常经典的指数增强或指数复制策略。在 QMT 中实现该策略主要涉及以下三个核心步骤:

  1. 获取成分股:使用 get_sector 获取沪深300当天的成分股列表。
  2. 获取权重:使用 get_weight_in_index 获取每只股票在指数中的权重。
  3. 交易执行:使用 order_target_percent 根据权重自动调整仓位(该函数会自动计算买入或卖出的股数,非常适合此类策略)。

策略实现代码

以下是完整的 Python 策略代码。请在 QMT 的策略编辑器中新建一个 Python 策略,并将代码复制进去。

注意

  1. 代码第一行必须包含 # -*- coding: gbk -*- 以防止中文乱码。
  2. 请将 YOUR_ACCOUNT_ID 替换为你实际的资金账号。
  3. 建议将策略运行周期设置为 “日线” (1d)
# -*- coding: gbk -*-
import pandas as pd

def init(ContextInfo):
    """
    初始化函数,策略启动时执行一次
    """
    # 1. 设置资金账号 (请替换为您的真实账号)
    ContextInfo.account_id = 'YOUR_ACCOUNT_ID' 
    ContextInfo.set_account(ContextInfo.account_id)
    
    # 2. 设置目标指数:沪深300
    ContextInfo.index_code = '000300.SH'
    
    print("策略初始化完成,目标指数:沪深300")

def handlebar(ContextInfo):
    """
    K线执行函数,每根K线执行一次
    建议在日线周期下运行
    """
    # 获取当前K线的时间戳
    index = ContextInfo.barpos
    realtime = ContextInfo.get_bar_timetag(index)
    
    # 1. 获取沪深300当天的成分股列表
    # get_sector 获取指定板块在指定时间的成分股
    stock_list = ContextInfo.get_sector(ContextInfo.index_code, realtime)
    
    if not stock_list:
        print(f"未获取到 {ContextInfo.index_code} 的成分股数据,请检查数据下载情况。")
        return

    print(f"当前日期检测到 {len(stock_list)} 只成分股,开始执行调仓...")

    # 2. 遍历成分股,获取权重并下单
    # 注意:为了防止持仓中有被剔除出指数的股票,建议先获取当前持仓进行对比(此处为简化逻辑,直接按目标权重下单)
    # order_target_percent 会自动处理:如果没持仓则买入,如果持仓过多则卖出,如果持仓不足则补仓
    
    for stock in stock_list:
        # 获取个股在指数中的绝对权重 (返回值为百分比,例如 1.5 代表 1.5%)
        weight = ContextInfo.get_weight_in_index(ContextInfo.index_code, stock)
        
        # 过滤无效权重
        if weight <= 0:
            continue
            
        # order_target_percent 接受的参数是小数 (例如 1.5% 需要转换为 0.015)
        target_percent = weight / 100.0
        
        # 执行目标比例下单
        # 注意:实盘中建议添加 try-except 块或检查股票停牌状态
        order_target_percent(stock, target_percent, ContextInfo, ContextInfo.account_id)
    
    # 3. 清理非成分股持仓 (可选逻辑)
    # 如果您希望严格复制指数,需要卖出那些已经不在沪深300里的持仓股票
    clean_non_index_stocks(ContextInfo, stock_list)

def clean_non_index_stocks(ContextInfo, index_stocks):
    """
    辅助函数:卖出不在指数成分股列表中的持仓
    """
    # 获取当前持仓信息
    positions = get_trade_detail_data(ContextInfo.account_id, 'stock', 'position')
    
    for obj in positions:
        stock_code = obj.m_strInstrumentID
        # 如果当前持仓的股票不在当天的指数成分股列表中,且持仓量大于0
        if stock_code not in index_stocks and obj.m_nVolume > 0:
            print(f"{stock_code} 已被剔除出指数,执行清仓。")
            # 将目标仓位设为 0,即卖出所有持仓
            order_target_percent(stock_code, 0, ContextInfo, ContextInfo.account_id)

代码关键点解析

  1. get_sector(sector, realtime):

    • 这是获取成分股的核心函数。传入 '000300.SH' 和当前时间戳,它会返回该时间点该指数包含的所有股票代码列表。这保证了策略能自动适应指数的定期调整。
  2. get_weight_in_index(indexcode, stockcode):

    • 获取某只股票在指数中的权重。
    • 注意单位:该函数返回的是百分比数值(如 5.0 代表 5%),而下单函数 order_target_percent 需要的是小数(如 0.05),所以在代码中进行了 / 100.0 的处理。
  3. order_target_percent(stockcode, percent, ...):

    • 这是最方便的调仓函数。你不需要计算要买多少股,只需要告诉它“我希望这只股票占我总资产的多少比例”。
    • 如果当前没货,它会买入;如果当前仓位不够,它会加仓;如果当前仓位超了,它会卖出。
  4. clean_non_index_stocks 函数:

    • 这是一个增强逻辑。因为 order_target_percent 只处理我们传入列表中的股票。如果某只股票昨天还在沪深300里,今天被剔除了,主循环不会遍历到它,它就会一直留在账户里。这个辅助函数用于检测并卖出这些被剔除的股票。

运行前准备

  1. 补充数据
    • 在 QMT 界面上方菜单栏点击 “数据管理” -> “数据下载”
    • 确保下载了 “板块数据”“权重数据”(通常包含在基础数据或财务数据中),否则 get_sectorget_weight_in_index 可能取不到历史数据。
  2. 设置周期
    • 在策略编辑界面的右侧或上方,将“默认周期”设置为 “日线”
  3. 回测设置
    • 设置好初始资金(建议设置大一点,因为沪深300成分股多,资金太小可能很多股票买不够一手)。

Q&A

Q: 为什么回测时有些股票没买入?
A: 可能是资金不足。沪深300有300只股票,部分高价股(如贵州茅台)一手需要十几万资金。如果权重计算出的金额不足买入一手(100股),系统会自动忽略该笔交易。

Q: 这个策略每天都会全仓买卖吗?
A: 不会。order_target_percent 是智能调仓。如果某只股票昨天的权重是 1.0%,今天还是 1.0%,且股价波动导致市值占比变化不大,它可能不会产生交易,或者只进行微调。只有权重发生变化或股价大幅波动导致持仓比例偏离目标时,才会触发买卖。

Q: 如何避免每天频繁微调带来的手续费?
A: 可以在下单前增加一个阈值判断。例如:if abs(current_percent - target_percent) > 0.001: order_target_percent(...),即只有当目标比例和当前比例偏差超过 0.1% 时才交易。