3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在量化交易中,行业轮动策略(Sector Rotation Strategy)是一种经典的自上而下的选股逻辑。本文将介绍如何在 ptrade 量化交易平台 中利用 get_industry_stocks 接口获取证监会行业分类(ZJHHY)的成分股,计算各行业的动量指标,并定期轮动配置动量最强的行业组合。
get_industry_stocks(industry_code)用于获取指定行业分类下的全部成分股列表。
industry_code(行业编码,后缀必须为 .XBHS,如农业 A01000.XBHS、软件和信息技术服务业 I65000.XBHS)。list[str])。get_history(count, frequency, field, security_list, ...)用于获取历史行情数据,计算行业动量或股票近期的累积涨幅。
# ptrade 证监会行业动量轮动策略
import pandas as pd
import numpy as np
def initialize(context):
# 设置调仓周期:每月第一个交易日运行
run_daily(context, rebalance, time='09:31')
# 选定的证监会行业列表(尾缀必须为 .XBHS)
g.industry_codes = [
'A01000.XBHS', # 农业
'B06000.XBHS', # 煤炭开采和洗选业
'C27000.XBHS', # 医药制造业
'C36000.XBHS', # 汽车制造业
'C39000.XBHS', # 计算机、通信和其他电子设备制造业
'I65000.XBHS', # 软件和信息技术服务业
'J66000.XBHS', # 货币金融服务
'K70000.XBHS' # 房地产业
]
g.lookback_days = 20 # 计算动量的回看天数
g.top_k_industries = 2 # 选择动量最强的行业数量
g.stocks_per_industry = 3 # 每个行业选择的股票数量
g.trade_flag = False
def before_trading_start(context, data):
# 标记调仓状态
g.trade_flag = True
def calc_industry_momentum(industry_code, lookback):
"""计算单个行业的平均动量得分"""
stocks = get_industry_stocks(industry_code)
if not stocks:
return -999
# 获取行业内成分股的历史收盘价
hist = get_history(lookback, '1d', 'close', security_list=stocks, fq='pre')
if hist is None or hist.empty:
return -999
# 计算每只股票在回看期内的涨跌幅
returns = (hist.iloc[-1] - hist.iloc[0]) / hist.iloc[0]
# 行业动量取成分股中位涨跌幅(避免异常值干扰)
return returns.median()
def rebalance(context):
if not g.trade_flag:
return
# 1. 计算所有行业的动量
industry_scores = {}
for ind in g.industry_codes:
score = calc_industry_momentum(ind, g.lookback_days)
industry_scores[ind] = score
# 2. 选择排名靠前的前 K 个行业
sorted_industries = sorted(industry_scores.items(), key=lambda x: x[1], reverse=True)
selected_industries = [x[0] for x in sorted_industries[:g.top_k_industries]]
log.info("选中动量前%d行业: %s" % (g.top_k_industries, selected_industries))
# 3. 收集目标股票
target_stocks = []
for ind in selected_industries:
stocks = get_industry_stocks(ind)
if stocks:
# 获取标的近 5 日收盘价计算短线动量筛选个股
hist = get_history(5, '1d', 'close', security_list=stocks, fq='pre')
if hist is not None and not hist.empty:
ret = (hist.iloc[-1] - hist.iloc[0]) / hist.iloc[0]
top_stocks = ret.sort_values(ascending=False).index[:g.stocks_per_industry].tolist()
target_stocks.extend(top_stocks)
if not target_stocks:
return
# 4. 执行调仓卖出非目标持仓
current_positions = context.portfolio.positions
for sid in list(current_positions.keys()):
if sid not in target_stocks and current_positions[sid].amount > 0:
order_target(sid, 0)
log.info("卖出非目标股: %s" % sid)
# 5. 等权重买入目标股票
capital_per_stock = context.portfolio.portfolio_value / len(target_stocks)
for sid in target_stocks:
order_value(sid, capital_capital_per_stock)
log.info("买入目标股: %s" % sid)
g.trade_flag = False
def handle_data(context, data):
pass
get_industry_stocks 获取的是最新的行业成分股。在历史回测中需注意成分股调入调出的截面偏差。filter_stock_by_status 过滤停牌(HALT)、退市(DELISTING)及 ST 股票,提升策略实盘稳定性。run_interval)中频繁请求历史行情,建议将计算逻辑集中在盘前或日线级别调仓时段。