fixato problema interno di CVXPY/ARPACK durante ccertificazione matrice PSD

This commit is contained in:
fredmaloggia
2025-12-01 07:52:38 +01:00
parent 62fc9310c8
commit d5b66f79dc

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
"""
Ottimizzatore Lite
Ottimizzatore ITA
"""
# =========================
@@ -22,6 +22,26 @@ from pypfopt import risk_models
from pypfopt.efficient_frontier import EfficientFrontier
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
OUTPUT_DIR = "Output"
INPUT_DIR = "Input"
@@ -256,6 +276,37 @@ def h_min_100(returns: pd.Series, month_len: int = 21):
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 ---
params = {}
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()
annual_returns_mean = daily_returns_mean * days_per_year
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 ----------
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_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_vec = w_series.values