3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在量化投资中,截面轮动策略(Cross-sectional Momentum/Rotation)是一种非常经典的策略。它通过在同一时间截面上,对全市场或特定股票池中的股票按照某种指标(如动量、估值、技术指标等)进行排序,选择排名靠前的股票买入,排名靠后的股票卖出或空仓。
在国信证券 QMT (Quantitative Trading System) 平台中,ext_data_rank 函数是实现截面轮动策略的核心利器。本文将详细介绍该函数的用法,并给出一个完整的截面轮动策略实现方案。
ext_data_rankext_data_rank 用于获取引用的扩展数据(如自定义的技术指标、因子值等)在当前时间截面上,所有品种中的排名。通过排名,我们可以非常方便地筛选出强势股或高性价比标的。
ext_data_rank(extdataname, stockcode, deviation, ContextInfo)
extdataname (string): 扩展数据名称(需提前在客户端的“扩展数据”中配置并计算,例如自定义的 mycci、mymomentum 等)。stockcode (string): 股票代码,格式为 'code.market',例如 '600000.SH'。deviation (number): K 线偏移量。0 表示不偏移(当前 K 线),N 表示向右偏移 N 根 K 线,-N 表示向左偏移 N 根 K 线。ContextInfo: 策略运行环境对象。number: 返回该股票在指定扩展数据中的截面排名(数值越小通常代表排名越靠前,具体取决于扩展数据的定义)。一个标准的截面轮动策略通常包含以下步骤:
ext_data_rank 获取股票池中所有股票的自定义指标排名。以下是基于 QMT 平台编写的截面轮动策略示例。策略每期获取股票池中指标排名靠前的股票并进行轮动调仓:
#encoding:gbk
import pandas as pd
def init(ContextInfo):
# 1. 设定股票池(以沪深300成份股为例)
# 实际运行前请确保已下载历史数据
ContextInfo.stock_pool = ContextInfo.get_stock_list_in_sector('沪深300')
ContextInfo.set_universe(ContextInfo.stock_pool)
# 2. 设定交易账号
ContextInfo.account_id = '6000000248' # 请替换为您的真实/模拟资金账号
ContextInfo.set_account(ContextInfo.account_id)
# 3. 策略参数设置
ContextInfo.hold_num = 5 # 持股数量
ContextInfo.ext_data_name = 'mycci' # 预先在QMT配置好的扩展数据名称
print("策略初始化完成,股票池数量:", len(ContextInfo.stock_pool))
def handlebar(ContextInfo):
# 仅在最后一根 K 线的第一个 tick 触发调仓(避免盘中频繁抖动)
if not ContextInfo.is_last_bar():
return
print("----------------- 收到调仓信号 -----------------")
# 1. 获取当前截面所有股票的排名
rank_dict = {}
for stock in ContextInfo.stock_pool:
# 排除停牌股
if ContextInfo.is_suspended_stock(stock):
continue
# 获取该股在 'mycci' 扩展数据中的截面排名
rank = ext_data_rank(ContextInfo.ext_data_name, stock, 0, ContextInfo)
# 过滤掉无有效排名的数据
if rank is not None and rank > 0:
rank_dict[stock] = rank
if not rank_dict:
print("未获取到有效的扩展数据排名,跳过本期调仓。")
return
# 2. 按照排名从小到大排序(选择排名靠前的股票)
sorted_stocks = sorted(rank_dict.items(), key=lambda x: x[1])
target_holdings = [stock for stock, rank in sorted_stocks[:ContextInfo.hold_num]]
print("本期目标持仓股票:", target_holdings)
# 3. 获取当前实际持仓
position_info = get_trade_detail_data(ContextInfo.account_id, 'STOCK', 'POSITION')
current_holdings = [pos.m_strInstrumentID for pos in position_info if pos.m_nVolume > 0]
print("当前实际持仓股票:", current_holdings)
# 4. 执行调仓交易
# 4.1 卖出不在目标持仓中的股票
for stock in current_holdings:
if stock not in target_holdings:
print(f"卖出股票: {stock}")
# 使用指定目标比例交易,调仓到 0% 仓位即卖出
order_target_percent(stock, 0.0, 'LATEST', ContextInfo, ContextInfo.account_id)
# 4.2 买入目标持仓中未持有的股票(等权重分配)
target_percent = 1.0 / ContextInfo.hold_num
for stock in target_holdings:
print(f"调仓/买入股票: {stock},目标比例: {target_percent:.2%}")
order_target_percent(stock, target_percent, 'LATEST', ContextInfo, ContextInfo.account_id)
ext_data_rank 之前,必须在 QMT 客户端的 “操作” -> “扩展数据管理” 中新建对应的扩展数据(如 mycci),并勾选需要计算的股票池与周期。否则代码运行会返回 None 或报错。ContextInfo.is_suspended_stock() 剔除停牌股,避免因无法交易导致资金占用或策略失真。