3 分钟快速生成代码
输入想法,AI 即刻生成可运行代码
最小方差模型(Minimum Variance Portfolio)是现代资产配置理论(MPT)中的经典模型。其核心思想是在不考虑预期收益率的情况下,通过计算资产之间的协方差矩阵,寻找一组投资权重,使得整个投资组合的总体方差(即风险)达到最小。这对于追求稳健收益、规避剧烈波动的量化交易者非常适用。
在聚宽(JoinQuant)平台上,我们可以直接调用内置的 portfolio_optimizer 函数,配合 MinVariance 目标函数,轻松实现这一优化过程。
要构建最小方差模型,我们需要使用 jqlib.optimizer 模块中的以下组件:
portfolio_optimizer(date, securities, target, constraints, bounds=[Bound(0.0, 1.0)], ...)
MinVariance(count=250):组合风险最小化(最小化组合方差)。count 参数表示向前取历史收益率的天数,默认 250 天。WeightConstraint(low=0.0, high=1.0):限制组合总权重范围。AnnualProfitConstraint(limit=0.1, count=250):限制组合年化收益率预期下限。Bound(low, high):限制单只标的的权重上下限。以下是一个在聚宽平台运行的完整月频调仓策略。该策略选取上证50部分成分股与ETF构建股票池,并在每月初利用 portfolio_optimizer 计算最小方差权重,同时设定了总权重在 90%~100% 之间,且单只标的权重不超过 10% 的约束。
# 导入聚宽函数库与优化器库
import pandas as pd
from jqdata import *
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(before_market_open, monthday=1, time='09:00', reference_security='000300.XSHG')
run_monthly(market_open, monthday=1, time='09:30', reference_security='000300.XSHG')
def before_market_open(context):
log.info('今日调仓日期:%s' % context.current_dt.date())
# 选取上证50成分股的后15只,加上部分ETF构建候选池
etf = [
'159902.XSHE',
'159903.XSHE',
'510050.XSHG'
]
g.buy_list = list(get_index_stocks('000016.XSHG')[-15:]) + etf
def market_open(context):
# 1. 卖出不在当前候选池中的持仓标的
sell_list = set(context.portfolio.positions.keys()) - set(g.buy_list)
for stock in sell_list:
order_target_value(stock, 0)
# 2. 调用投资组合优化器计算最小方差权重
# 约束条件:组合总权重在 90% 到 100% 之间;单只标的权重限制在 0% 到 10% 之间
optimized_weight = portfolio_optimizer(
date=context.previous_date,
securities=g.buy_list,
target=MinVariance(count=250), # 最小化组合方差
constraints=[WeightConstraint(low=0.9, high=1.0)], # 总权重约束
bounds=[Bound(0.0, 0.1)], # 单只标的权重上限 10%
default_port_weight_range=[0.0, 1.0],
ftol=1e-09,
return_none_if_fail=True
)
# 3. 执行调仓操作
if optimized_weight is None:
log.warn('警告:组合优化失败,保持原仓位或执行默认等权重')
else:
log.info("优化后的权重结果:")
log.info(optimized_weight)
total_value = context.portfolio.total_value # 获取当前总资产
for stock in optimized_weight.keys():
target_value = total_value * optimized_weight[stock] # 计算目标金额
order_target_value(stock, target_value) # 调整至目标权重
portfolio_optimizer 时,date 参数必须传入 context.previous_date(前一交易日),切勿传入 context.current_dt,否则会引入未来数据导致回测失真。None。代码中必须对 optimized_weight is None 进行判断,防止策略抛出异常中断。initialize 中调用 set_option('use_real_price', True)。在真实价格模式下,分红送股会自动调整持仓,使回测结果更贴近实盘。