fixato problema interno di CVXPY/ARPACK durante ccertificazione matrice PSD
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
"""
|
"""
|
||||||
Ottimizzatore Lite
|
Ottimizzatore ITA
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# =========================
|
# =========================
|
||||||
@@ -22,6 +22,26 @@ from pypfopt import risk_models
|
|||||||
from pypfopt.efficient_frontier import EfficientFrontier
|
from pypfopt.efficient_frontier import EfficientFrontier
|
||||||
from pypfopt.exceptions import OptimizationError
|
from pypfopt.exceptions import OptimizationError
|
||||||
|
|
||||||
|
# ---------------------------------------------------
|
||||||
|
# Patch PyPortfolioOpt: usa cp.psd_wrap sulla covarianza
|
||||||
|
# ---------------------------------------------------
|
||||||
|
import cvxpy as cp
|
||||||
|
from pypfopt import objective_functions as _obj
|
||||||
|
|
||||||
|
def portfolio_variance_psdwrap(w, cov_matrix):
|
||||||
|
"""
|
||||||
|
Versione patchata di portfolio_variance:
|
||||||
|
usa cp.psd_wrap(cov_matrix) per evitare che CVXPY
|
||||||
|
faccia il controllo spettrale con ARPACK.
|
||||||
|
Comportamento identico all'originale, ma più robusto.
|
||||||
|
"""
|
||||||
|
variance = cp.quad_form(w, cp.psd_wrap(cov_matrix))
|
||||||
|
return _obj._objective_value(w, variance)
|
||||||
|
|
||||||
|
# Monkey patch globale: da qui in poi EfficientFrontier usa questa versione
|
||||||
|
_obj.portfolio_variance = portfolio_variance_psdwrap
|
||||||
|
|
||||||
|
|
||||||
# Cartelle di input/output/plot
|
# Cartelle di input/output/plot
|
||||||
OUTPUT_DIR = "Output"
|
OUTPUT_DIR = "Output"
|
||||||
INPUT_DIR = "Input"
|
INPUT_DIR = "Input"
|
||||||
@@ -256,6 +276,37 @@ def h_min_100(returns: pd.Series, month_len: int = 21):
|
|||||||
|
|
||||||
return np.nan, np.nan
|
return np.nan, np.nan
|
||||||
|
|
||||||
|
# ---------------------------------
|
||||||
|
# Utility per rendere PSD/robusta la covarianza
|
||||||
|
# ---------------------------------
|
||||||
|
def regularize_covariance(cov_df: pd.DataFrame, ridge_factor: float = 1e-6) -> pd.DataFrame:
|
||||||
|
"""
|
||||||
|
Rende la matrice di covarianza numericamente piu' robusta:
|
||||||
|
- la simmetrizza
|
||||||
|
- aggiunge un piccolo termine di ridge sulla diagonale
|
||||||
|
Ritorna un nuovo DataFrame con stessa index/columns.
|
||||||
|
"""
|
||||||
|
if cov_df.empty:
|
||||||
|
return cov_df
|
||||||
|
|
||||||
|
Sigma = cov_df.values.astype(float)
|
||||||
|
|
||||||
|
# simmetrizza (elimina piccole asimmetrie numeriche)
|
||||||
|
Sigma = 0.5 * (Sigma + Sigma.T)
|
||||||
|
|
||||||
|
# piccolo ridge proporzionato alla scala media delle varianze
|
||||||
|
n = Sigma.shape[0]
|
||||||
|
trace = np.trace(Sigma)
|
||||||
|
if np.isfinite(trace) and n > 0:
|
||||||
|
eps = ridge_factor * (trace / n)
|
||||||
|
else:
|
||||||
|
eps = ridge_factor
|
||||||
|
|
||||||
|
Sigma_reg = Sigma + eps * np.eye(n)
|
||||||
|
|
||||||
|
return pd.DataFrame(Sigma_reg, index=cov_df.index, columns=cov_df.columns)
|
||||||
|
|
||||||
|
|
||||||
# --- Lettura parametri dal file connection.txt ---
|
# --- Lettura parametri dal file connection.txt ---
|
||||||
params = {}
|
params = {}
|
||||||
with open("connection.txt", "r") as f:
|
with open("connection.txt", "r") as f:
|
||||||
@@ -359,6 +410,9 @@ for (years, target_vol), name in volatility_targets.items():
|
|||||||
daily_returns_mean = period_df.mean()
|
daily_returns_mean = period_df.mean()
|
||||||
annual_returns_mean = daily_returns_mean * days_per_year
|
annual_returns_mean = daily_returns_mean * days_per_year
|
||||||
annual_covariance_matrix = risk_models.sample_cov(period_df, returns_data=True)
|
annual_covariance_matrix = risk_models.sample_cov(period_df, returns_data=True)
|
||||||
|
# --- Regularizzazione covarianza per l'ottimizzatore ---
|
||||||
|
annual_covariance_matrix = regularize_covariance(annual_covariance_matrix)
|
||||||
|
|
||||||
|
|
||||||
# ---------- PER-ASSET METRICS ----------
|
# ---------- PER-ASSET METRICS ----------
|
||||||
n_days = int(period_df.shape[0])
|
n_days = int(period_df.shape[0])
|
||||||
@@ -519,6 +573,9 @@ for (years, target_vol), name in volatility_targets.items():
|
|||||||
annual_returns_mean = daily_returns_mean * days_per_year
|
annual_returns_mean = daily_returns_mean * days_per_year
|
||||||
annual_covariance_matrix = risk_models.sample_cov(period_df, returns_data=True)
|
annual_covariance_matrix = risk_models.sample_cov(period_df, returns_data=True)
|
||||||
|
|
||||||
|
# --- Regularizzazione covarianza per l'ottimizzatore ---
|
||||||
|
annual_covariance_matrix = regularize_covariance(annual_covariance_matrix)
|
||||||
|
|
||||||
w_series = optimized_weights[name].reindex(period_df.columns).fillna(0.0)
|
w_series = optimized_weights[name].reindex(period_df.columns).fillna(0.0)
|
||||||
w_vec = w_series.values
|
w_vec = w_series.values
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user