3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在量化投资中,指数成分股的定期调整(如沪深300指数每半年或每季度调整一次成分股)往往会带来显著的“日历效应”与资金流向变化。同时,换手率作为衡量股票活跃度与投资者情绪的重要指标,常被用于构建反转或动量因子。
本文将详细介绍如何在 QMT (Quantitative Multi-trade) 平台 上,结合 get_his_index_data(获取指数历史调整日成分股)与 get_turnover_rate(获取换手率)API,编写一个完整的成分股换手率轮动交易策略。
ContextInfo.get_his_index_data(index)index_data = ContextInfo.get_his_index_data('000300.SH')
ContextInfo.get_turnover_rate(stock_list, startTime, endTime)df = ContextInfo.get_turnover_rate(['600000.SH', '000001.SZ'], '20230101', '20230110')
pandas.DataFrame,行索引为日期,列为股票代码,值为换手率。get_his_index_data 获取沪深300(000300.SH)的历史调整日。当回测运行到指数调整日(或其附近交易日)时触发调仓。order_target_percent 自动将仓位调整至目标比例,卖出不在新名单中的股票。请在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%}")
get_his_index_data 完美地记录了历史每个时间节点的真实成分股,避免了使用当前成分股回溯历史的“未来函数”错误。