🚀 AI 一键生成 qmt 策略代码
立即体验

QMT平台如何编写指数成分股历史调整日换手率轮动策略?(附Python源码)

qmt | 发布时间: 2026/8/13
以下内容由 EasyQuant 生成。

问题描述

QMT 选股策略:基于指数成分股季度调整日的成分股换手率轮动模型
如何结合 get_his_index_data 与换手率 API 编写一个成分股换入换出轮动策略?

解决方案

QMT选股策略:基于指数成分股季度调整日的成分股换手率轮动模型

在量化投资中,指数成分股的定期调整(如沪深300指数每半年或每季度调整一次成分股)往往会带来显著的“日历效应”与资金流向变化。同时,换手率作为衡量股票活跃度与投资者情绪的重要指标,常被用于构建反转或动量因子。

本文将详细介绍如何在 QMT (Quantitative Multi-trade) 平台 上,结合 get_his_index_data(获取指数历史调整日成分股)与 get_turnover_rate(获取换手率)API,编写一个完整的成分股换手率轮动交易策略。


一、 核心API接口解析

1. 获取指数历史调整成分股:ContextInfo.get_his_index_data(index)

  • 释义:获取某只指数历史调整日的成分股列表(需要提前在数据管理中下载历史数据)。
  • 用法
    index_data = ContextInfo.get_his_index_data('000300.SH')
    
  • 返回:一个字典,key为调整日期,value为该日期调整后的成分股列表。

2. 获取换手率数据:ContextInfo.get_turnover_rate(stock_list, startTime, endTime)

  • 释义:获取指定股票列表在特定时间段内的换手率。
  • 用法
    df = ContextInfo.get_turnover_rate(['600000.SH', '000001.SZ'], '20230101', '20230110')
    
  • 返回pandas.DataFrame,行索引为日期,列为股票代码,值为换手率。

二、 策略构建逻辑

  1. 确定调仓时机:利用 get_his_index_data 获取沪深300(000300.SH)的历史调整日。当回测运行到指数调整日(或其附近交易日)时触发调仓。
  2. 筛选候选池:获取当前最新的指数成分股列表。
  3. 计算换手率因子:获取候选池股票过去N个交易日的平均换手率。
  4. 轮动排序与交易
    • 低换手率轮动(拥挤度规避):选择成分股中换手率最低的10只股票买入。
    • 等权重调仓:使用 order_target_percent 自动将仓位调整至目标比例,卖出不在新名单中的股票。

三、 QMT Python 策略源码实现

请在QMT编辑器中新建Python策略,并粘贴以下代码:

#coding:gbk
import pandas as pd
import numpy as np

def init(ContextInfo):
    # 设定基准与交易账号
    ContextInfo.benchmark = '000300.SH'
    ContextInfo.set_universe(['000300.SH'])
    
    # 策略参数设置
    ContextInfo.index_code = '000300.SH' # 目标指数
    ContextInfo.hold_num = 10            # 持股数量
    ContextInfo.lookback_days = 20       # 换手率计算回溯天数
    
    # 获取指数历史调整数据
    # 注:运行前请确保在“数据管理”中下载了000300.SH的历史成分股数据
    ContextInfo.his_index_dict = ContextInfo.get_his_index_data(ContextInfo.index_code)
    # 提取所有历史调整日期并排序
    ContextInfo.adjust_dates = sorted(list(ContextInfo.his_index_dict.keys()))
    
    print(f"成功加载指数历史调整数据,共包含 {len(ContextInfo.adjust_dates)} 个调整窗口。")

def handlebar(ContextInfo):
    # 获取当前K线的时间戳并转换为YYYYMMDD格式
    bar_timetag = ContextInfo.get_bar_timetag(ContextInfo.barpos)
    current_date = timetag_to_datetime(bar_timetag, '%Y%m%d')
    
    # 判断当前日期是否为指数成分股调整日
    if current_date not in ContextInfo.adjust_dates:
        return
        
    print(f"\n--- 触发成分股调整日轮动调仓: {current_date} ---")
    
    # 1. 获取当前调整日的新成分股列表
    current_constituents = ContextInfo.his_index_dict[current_date]
    if not current_constituents:
        return
        
    # 2. 计算回溯期时间范围
    start_date = timetag_to_datetime(bar_timetag - ContextInfo.lookback_days * 24 * 3600 * 1000, '%Y%m%d')
    
    # 3. 获取成分股的换手率数据
    try:
        turnover_df = ContextInfo.get_turnover_rate(current_constituents, start_date, current_date)
    except Exception as e:
        print(f"获取换手率数据失败: {e}")
        return
        
    if turnover_df.empty:
        print("换手率数据为空,跳过本次调仓。")
        return
        
    # 4. 计算平均换手率并排序(剔除停牌或无数据的股票)
    mean_turnover = turnover_df.mean().dropna()
    # 按换手率升序排序(选择低换手率股票)
    selected_stocks = mean_turnover.sort_values(ascending=True).head(ContextInfo.hold_num).index.tolist()
    
    print(f"选股结果: {selected_stocks}")
    
    # 5. 获取当前持仓
    account_id = ContextInfo.get_universe()[0] # 默认使用绑定的第一个账号
    positions = get_trade_detail_data(account_id, 'STOCK', 'POSITION')
    current_holdings = [pos.m_strInstrumentID for pos in positions if pos.m_nVolume > 0]
    
    # 6. 执行调仓交易
    # 卖出不在新选股池中的股票
    for stock in current_holdings:
        if stock not in selected_stocks:
            order_target_percent(stock, 0, 'LATEST', ContextInfo, account_id)
            print(f"卖出清仓: {stock}")
            
    # 买入/调整目标股票至等权重
    target_weight = 1.0 / ContextInfo.hold_num
    for stock in selected_stocks:
        order_target_percent(stock, target_weight, 'LATEST', ContextInfo, account_id)
        print(f"配置目标股: {stock},目标权重: {target_weight:.2%}")

四、 策略优化与注意事项

  1. 数据补充:此策略高度依赖历史成分股数据与换手率数据。回测前,请务必通过QMT客户端的 “操作 -> 数据管理 -> 补充数据”,下载完整的沪深300指数历史成分股以及对应个股的日线、换手率数据。
  2. 幸存者偏差规避get_his_index_data 完美地记录了历史每个时间节点的真实成分股,避免了使用当前成分股回溯历史的“未来函数”错误。
  3. 交易成本控制:由于指数调整频率较低(通常为半年或季度),该策略的换手率较低,印花税与佣金损耗较小,适合中长期资金配置。