我已经完成了马科维茨投资组合优化的 Python 实现。最小化函数将确保风险最小化,同时解决优化器基于股票列表生成一定百分比的回报。它还考虑到权重之和应等于 1。大多数时候我生成的结果是不可行的。可能是什么原因?
import pandas as pd
import numpy as np
from helper_functions.get_data import download_data
from scipy.optimize import minimize
def optimizer(tickers, start_date, end_date, required_return=0.02):
df = download_data(tickers, start_date, end_date)
# Calculate daily returns
returns = df['Close'].pct_change()
# Calculate mean returns and covariance
mean_returns = returns.mean()
cov_matrix = returns.cov()
# Number of portfolio assets
num_assets = len(mean_returns)
# Initialize weights
weights_initial = num_assets * [1. / num_assets,]
# Constraints
constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1},
{'type': 'eq', 'fun': lambda x: np.sum(x*mean_returns) - required_return})
# Bounds
bounds = tuple((0,1) for asset in range(num_assets))
# Objective function
def objective(weights):
return np.dot(weights.T, np.dot(cov_matrix, weights))
# Optimize
result = minimize(objective, weights_initial, method='SLSQP', bounds=bounds, constraints=constraints)
# Return optimization results
return result
如上所述,将等式约束更改为不等式可以解决该问题。不必要地对浮点数施加等式约束绝不是一个好主意。投资者实际上寻求具有最低要求回报的投资组合(即回报大于或等于......)。
实施来了:
def find_min_var_portfolio(
exp_rets: np.array, cov: np.array, r_min: float = 0, w_max: float = 1
):
"""Find portfolio with minimum variance given constraint return
Solve the following optimization problem
min: w.T*COV*w
subjto: w.T * r_ann >= r_min
sum(w) = 1
0 <= w[i] <= w_max for every i
Parameters
==========
exp_rets: annualized expected returns
cov: covariance matrix
r_min: minimum portfolio return (constraint)
w_max: maximum individual weight (constraint)
Returns
=======
(w, r_opt, vol_opt)
w: portfolio weights
r_opt: return of optimal portfolio
vol_opt: volatility of optimal portfolio
"""
def calc_var(w, cov):
"""Calculate portfolio Variance"""
return np.dot(w.T, np.dot(cov, w))
n_assets = len(exp_rets)
constraints = [
# sum(w_i) = 1
{"type": "eq", "fun": lambda x: np.sum(x) - 1},
# sum(r_i * w_i >= r_min)
{"type": "ineq", "fun": lambda x: np.dot(x.T, exp_rets) - r_min},
]
bounds = tuple((0, w_max) for asset in range(n_assets)) # sequence of (min,max)
opts = sco.minimize(
# Objective Function
fun=calc_var,
# Initial guess
x0=n_assets * [1.0 / n_assets],
# Extra Arguments to objective function
args=(cov,),
method="SLSQP",
options={"ftol": 1e-7, "maxiter": 100},
bounds=bounds,
constraints=constraints,
)
w = opts["x"]
r_opt = np.dot(w, exp_rets)
vol_opt = np.sqrt(calc_var(w, cov))
return w, r_opt, vol_opt
以下函数是(公共)Markowitz optimization Streamlit 应用程序的一部分: https://markowitz.streamlit.app 你可以在那里尝试一下。 源代码可在 Github 上获取:https://github.com/MarekOzana/streamlit_markowitz/blob/main/src/optimization.py