You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

scipy.minimize最小化投资组合跟踪误差结果异常问题排查

跟踪误差最小化优化异常的原因分析

我有一个形状为(250,10)的pd.DataFrame存储每日股票收益,以及一个形状为(250,)的pd.Series存储基准每日收益。目标是最小化股票投资组合与基准之间的跟踪误差(定义为(投资组合收益-基准收益)的标准差),但使用scipy.minimize时结果完全不符合预期——本该高度相似的累积收益曲线差异极大,而最大化收益等其他目标函数运行正常,scipy也未抛出错误。请问该目标函数为何会给scipy带来困扰?

最小可复现代码

import numpy as np
import pandas as pd
from scipy.optimize import minimize

def portfolio_te(weights, rets, bm_rets):
    port_returns = np.dot(rets, weights)
    te = np.sqrt(np.mean((port_returns - bm_rets)**2))
    return te

stocks_returns = pd.DataFrame(np.random.normal(0, 0.02, (250, 10)))
benchmark_returns = pd.Series(np.random.normal(0, 0.02, 250))

result = minimize(portfolio_te, x0=[0.1 for i in range(10)],
        bounds=[(0,0.3) for i in range(10)], method='SLSQP',
        args=(stocks_returns, benchmark_returns))
        
port_returns = pd.Series(np.dot(stocks_returns, result.x))

ts = pd.concat([(1+port_returns).cumprod(), (1+benchmark_returns).cumprod()], axis=1)
ts.plot()

问题根源与解决方案

1. 缺少核心约束:权重和为1

当前优化仅设置了单权重的上下界,但未添加投资组合最关键的权重和等于1的等式约束。没有这个约束,优化器可能输出权重和远小于1的结果,导致组合收益整体被缩放,自然无法匹配基准收益的量级。

需要在minimize中补充约束:

constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})

并在调用时传入constraints=constraints参数。

2. 目标函数的冗余运算

跟踪误差是(组合收益-基准收益)的标准差,即方差的平方根。由于平方根是单调递增函数,最小化方差等价于最小化标准差,去掉根号可以简化计算,避免潜在的数值精度问题,同时不改变优化结果:

def portfolio_te(weights, rets, bm_rets):
    port_returns = np.dot(rets, weights)
    # 直接返回方差,等价于最小化标准差
    return np.mean((port_returns - bm_rets)**2)

3. 优化方法的适配性

SLSQP方法对目标函数平滑性和约束处理的要求较高,若添加约束后仍有异常,可尝试切换到trust-constr方法,它在处理带约束的优化问题时稳定性更强。


修正后的完整代码

import numpy as np
import pandas as pd
from scipy.optimize import minimize

def portfolio_te(weights, rets, bm_rets):
    port_returns = np.dot(rets, weights)
    # 最小化方差等价于最小化标准差,去掉根号减少计算
    return np.mean((port_returns - bm_rets)**2)

stocks_returns = pd.DataFrame(np.random.normal(0, 0.02, (250, 10)))
benchmark_returns = pd.Series(np.random.normal(0, 0.02, 250))

# 添加权重和为1的等式约束
constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
result = minimize(portfolio_te, x0=[0.1 for i in range(10)],
        bounds=[(0,0.3) for i in range(10)], method='SLSQP',
        args=(stocks_returns, benchmark_returns),
        constraints=constraints)
        
port_returns = pd.Series(np.dot(stocks_returns, result.x))

ts = pd.concat([(1+port_returns).cumprod(), (1+benchmark_returns).cumprod()], axis=1)
ts.plot()

内容的提问来源于stack exchange,提问作者Quastiat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 03:37:14