3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在因子投资与组合构建中,为了防止策略在特定行业过度暴露风险,通常需要控制组合相对于基准指数(如沪深 300)的行业权重偏离,实现行业中性或行业对冲。JoinQuant 提供了内置的投资组合优化器 portfolio_optimizer,并配套了针对行业偏离度的约束模块。
portfolio_optimizer 优化器函数聚宽提供的投资组合优化函数,基于指定的优化目标(如夏普比率最大化、风险最小化、因子暴露最大化等)和约束条件计算最优持仓权重。
IndustriesDeviationConstraint 行业分类偏离度限制用于设定某行业分类(如聚宽一级行业 jq_l1)下所有行业权重相对于基准指数偏离度的上下限。
IndustriesDeviationConstraint(industry_code, benchmark, limit)industry_code:行业分类代码,例如 'jq_l1'(聚宽一级行业)。benchmark:基准指数代码,例如 '000300.XSHG'。limit:允许偏离的最大绝对值(如 0.05 表示允许相比基准行业权重上下偏离 5%)。IndustryDeviationConstraint 单行业偏离度限制若只需限制特定单一行业的偏离度,可以使用该函数:
IndustryDeviationConstraint(industry_code, benchmark, limit)industry_code:具体行业代码或列表,如 'HY001' 或 ['HY001', 'HY007']。以下策略展示了如何在月度调仓时,利用 portfolio_optimizer 和 IndustriesDeviationConstraint 构建一个对标沪深 300、控制行业偏离度不超过 5% 的优化组合。
import pandas as pd
from jqdata import *
from jqfactor import Factor
from jqlib.optimizer import *
def initialize(context):
# 设定沪深300作为基准
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 设置交易手续费
set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
# 定时运行:每月第一个交易日开盘调仓
run_monthly(market_open, monthday=1, time='09:30', reference_security='000300.XSHG')
def market_open(context):
# 1. 确定股票池(例如沪深300成分股)
security_list = get_index_stocks('000300.XSHG')
# 2. 设置组合优化目标(例如:风险最小化 / MinVariance)
target = MinVariance(count=250)
# 3. 设置约束条件
constraints = [
# 组合总权重限制在 90% ~ 100%
WeightConstraint(low=0.9, high=1.0),
# 行业分类偏离度约束:聚宽一级行业相比沪深300指数偏离度不超过 5%
IndustriesDeviationConstraint(industry_code='jq_l1', benchmark='000300.XSHG', limit=0.05)
]
# 4. 设置单只股票权重边界(单只股票最大权重不超过 5%)
bounds = [Bound(low=0.0, high=0.05)]
# 5. 调用组合优化器求解
optimized_weight = portfolio_optimizer(
date=context.previous_date,
securities=security_list,
target=target,
constraints=constraints,
bounds=bounds,
default_port_weight_range=[0.0, 1.0],
ftol=1e-09,
return_none_if_fail=True
)
# 6. 根据优化权重进行调仓
if optimized_weight is not None:
# 先平仓不在优化结果中的股票
for stock in context.portfolio.positions.keys():
if stock not in optimized_weight or optimized_weight[stock] == 0:
order_target_value(stock, 0)
# 按目标价值调仓
total_value = context.portfolio.total_value
for stock, weight in optimized_weight.items():
if weight > 0:
order_target_value(stock, total_value * weight)
else:
log.warn('组合优化失败,保持当前持仓。')
from jqlib.optimizer import * 模块。date 参数时,建议使用 context.previous_date,避免在开盘时引入当天的未收盘数据造成未来函数。None。建议设置 return_none_if_fail=True 并编写兜底降级逻辑。