3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在多因子量化选股策略中,获取因子在全市场的截面相对排名是构建多因子模型和因子组合的核心步骤。QMT(迅投量化)平台提供了强大的扩展数据排名接口 ext_data_rank(),可高效计算全市场截面排名。
ext_data_rank 用于获取引用的扩展数据(如自定义指标、因子)在所有品种中的实时排名。
ext_data_rank(extdataname, stockcode, deviation, ContextInfo)
string,扩展数据名称(须先在客户端系统中创建或引入该扩展数据)。string,品种代码(带市场后缀),例如 '600000.SH'。number,K线偏移量,0 表示当前Bar不偏移,N 表示向右偏移,-N 表示向左偏移。pythonObj,策略上下文全局环境对象。number,该品种在该扩展数据指标下的全市场数值排名(如第 1 名、第 10 名等)。ContextInfo.get_stock_list_in_sector('沪深300') 或 全A股 板块。ext_data_rank 遍历股票池中的每只股票,获取排名,并计算相对百分比分位数:handlebar 或结合 run_time 定时器进行周期性调仓,使用 passorder 进行一键目标调整。以下示例展示了如何在 QMT 中利用 ext_data_rank 进行截面筛选并按固定调仓周期进行买卖:
#coding:gbk
import pandas as pd
def init(ContextInfo):
# 1. 设定资金账号与股票池
ContextInfo.accountID = '6000000001'
ContextInfo.set_account(ContextInfo.accountID)
# 设定基准与交易参数
ContextInfo.start = '2023-01-01 09:30:00'
ContextInfo.end = '2023-12-31 15:00:00'
ContextInfo.capital = 1000000
# 设定扩展数据名称(请确保客户端已存在该扩展数据,例如 'mycci' 或自定义因子)
ContextInfo.factor_name = 'mycci'
# 选股分位数比例:选取全市场排名前 10% 的股票
ContextInfo.top_percent = 0.10
# 调仓周期控制(例如每20个Bar调仓一次)
ContextInfo.trade_period = 20
ContextInfo.hold_count = 10 # 最终持仓目标股票数量
def handlebar(ContextInfo):
# 判断调仓周期
if ContextInfo.barpos % ContextInfo.trade_period != 0:
return
# 2. 获取股票池成份股列表(以沪深300为例)
stock_pool = ContextInfo.get_stock_list_in_sector('沪深300')
total_count = len(stock_pool)
if total_count == 0:
return
# 3. 遍历股票池,利用 ext_data_rank 计算全市场排名
rank_dict = {}
for stock in stock_pool:
# 排除停牌股
if ContextInfo.is_suspended_stock(stock):
continue
# 获取扩展数据排名
rank = ext_data_rank(ContextInfo.factor_name, stock, 0, ContextInfo)
if rank > 0:
rank_dict[stock] = rank
if not rank_dict:
return
# 4. 转化为 DataFrame 进行百分比截面筛选
df_rank = pd.DataFrame(list(rank_dict.items()), columns=['stock', 'rank'])
df_rank.sort_values(by='rank', ascending=True, inplace=True) # 升序,数值越小排名越靠前
# 截取前 top_percent 的股票
cutoff_idx = int(len(df_rank) * ContextInfo.top_percent)
selected_stocks = df_rank.head(cutoff_idx)['stock'].tolist()[:ContextInfo.hold_count]
print(f"Barpos: {ContextInfo.barpos} | 截选目标持仓股票: {selected_stocks}")
# 5. 执行组合调仓:采用目标比例下单方式 (orderType=1113,比例分配)
weight_per_stock = 1.0 / len(selected_stocks) if selected_stocks else 0
# 调仓:卖出不在目标池中的持仓
positions = get_trade_detail_data(ContextInfo.accountID, 'STOCK', 'POSITION')
current_holding = [pos.m_strInstrumentID for pos in positions if pos.m_nVolume > 0]
for stock in current_holding:
if stock not in selected_stocks:
# 卖出平仓
passorder(24, 1101, ContextInfo.accountID, stock, 5, -1, pos.m_nVolume, '多因子平仓', 1, ContextInfo)
# 买入目标选股池股票
for stock in selected_stocks:
# 利用可用资金的固定比例(orderType=1123)或总资产比例买入
passorder(23, 1101, ContextInfo.accountID, stock, 5, -1, int(weight_per_stock * 100), '多因子开仓', 1, ContextInfo)
ext_data_rank 前,需确保客户端【扩展数据管理】中已配置好对应名称的扩展数据,并完成了历史数据刷新。ext_data_rank 会基于实时推送截面重新计算排名。ContextInfo.is_suspended_stock() 剔除停牌股票,避免无效信号下单。