我有一个
pd.DataFrame
,每日股票收益形状为 (250,10)
,还有一个 pd.Series
,我的基准日收益形状为 (250,)
。目标是最大限度地减少股票投资组合与基准之间的跟踪误差。
跟踪误差是(投资组合 - 基准)的标准差
但不知何故,scipy.minimize
无法正确最小化跟踪误差函数,结果没有任何意义。对于其他功能,例如最大化回报,它可以完美地工作。
最终这两行应该非常相似,但事实并非如此。 scipy 不会抱怨,但结果却不是人们所期望的,你知道为什么这个目标函数会困扰 scipy 吗?
MWE:
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()
我不清楚是否有解决这个问题。
您有 10 只股票可供选择,它们都有随机回报。您有一个也是随机创建的索引。您会期望任意两组随机数之间的相关性几乎为零,因此任何投资组合与基准之间的匹配度都会相当差。如果我改变问题,使其确实有一个解决方案,通过随机创建一些权重,计算给定这些权重的股票收益,然后在给定股票收益的情况下求解原始权重,它的工作相当可靠。
true_weight = np.random.rand(10)
true_weight /= true_weight.sum() # Ensure weights sum to 1
stocks_returns = pd.DataFrame(np.random.normal(0, 0.02, (250, 10)))
benchmark_returns = pd.Series((stocks_returns.values @ true_weight))
现在您知道了真实的权重,您可以检查最小化是否能够找到它们。
average_pct_error = np.abs((((result.x - true_weight) / true_weight) * 100)).mean()
print(f"Average portfolio component was wrong from true weight by {average_pct_error:.2f}%")
累积回报图也符合。执行此操作时,误差约为 0.1%,您可以通过
ftol
选项将其降低到接近零:
result = minimize(portfolio_te, x0=[0.1 for i in range(10)],
bounds=[(0,0.3) for i in range(10)], method='SLSQP',
options=dict(ftol=1e-10),
args=(stocks_returns, benchmark_returns))
指定损失函数的另一种方法是最小化累积收益 RMSE。这改进了您正在制作的图表,但我担心它会高估时间序列早期匹配回报与稍后匹配回报的价值。