3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
在进行投资组合优化时,过于频繁或剧烈的调仓会导致高昂的交易手续费与市场冲击成本,从而侵蚀策略收益。JoinQuant 提供了内置的投资组合优化器 portfolio_optimizer,并支持通过约束条件 TurnoverConstraint 来精准限制调仓换手率。
TurnoverConstraint 用于限制优化后的新投资组合相对于当前持仓(或设定基准持仓)的换手比例。
TurnoverConstraint(limit, current_portfolio=None)
limit (float): 换手率上限(例如 0.5 表示调仓换手率不超过 50%)。current_portfolio (pandas.Series 或 None): 当前投资组合的权重序列。如果为 None,默认认为初始状态为空仓。jqlib.optimizer 导入相关的优化器及约束函数。current_portfolio。portfolio_optimizer 时,将 TurnoverConstraint(limit, current_portfolio) 加入到 constraints 列表中。以下示例展示了如何在聚宽按月调仓策略中,使用组合优化器 portfolio_optimizer,并利用 TurnoverConstraint 将单次调仓换手率限制在 30% 以内:
import pandas as pd
from jqdata import *
from jqlib.optimizer import *
def initialize(context):
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(rebalance, monthday=1, time='9:30', reference_security='000300.XSHG')
def rebalance(context):
# 1. 确定目标股票池(例如沪深300成分股的前20只)
securities = get_index_stocks('000300.XSHG')[:20]
# 2. 计算当前账户各标的的权重
total_value = context.portfolio.total_value
current_weights = {}
for stock in securities:
position = context.portfolio.positions.get(stock)
if position and position.total_amount > 0:
current_weights[stock] = position.value / total_value
else:
current_weights[stock] = 0.0
current_portfolio = pd.Series(current_weights)
# 3. 设置换手率约束:单次调仓换手率不超过 30%
turnover_limit = 0.30
constraints = [
WeightConstraint(low=0.0, high=1.0),
TurnoverConstraint(limit=turnover_limit, current_portfolio=current_portfolio)
]
# 4. 设置标的权重边界(每只股票不超过 15%)
bounds = [Bound(low=0.0, high=0.15)]
# 5. 运行投资组合优化器(以组合风险最小化 MinVariance 为例)
target = MinVariance(count=250)
optimized_weight = portfolio_optimizer(
date=context.previous_date,
securities=securities,
target=target,
constraints=constraints,
bounds=bounds,
default_port_weight_range=[0.0, 1.0],
return_none_if_fail=True
)
# 6. 执行调仓下单
if optimized_weight is not None:
log.info("优化权重成功:\n", optimized_weight)
for stock in securities:
target_val = total_value * optimized_weight.get(stock, 0.0)
order_target_value(stock, target_val)
else:
log.warn("组合优化失败,保持当前持仓!")
TurnoverConstraint 的 current_portfolio 的索引(Index)与传入 securities 的列表保持一致,未持有的标的权重填 0.0。None。建议设置 return_none_if_fail=True 并编写兜底降级逻辑。TurnoverConstraint 可与 WeightConstraint(总权重限制)、BarraConstraint(风险暴露限制)等组合叠加使用,实现更精细的组合风险管理。