"""
NexQuant Risk Management - Korrelation, Portfolio-Optimierung
"""

import numpy as np
import pandas as pd


class CorrelationAnalyzer:
    def __init__(self, lookback: int = 60):
        self.lookback = lookback

    def calculate_matrix(self, returns: pd.DataFrame) -> pd.DataFrame:
        return returns.dropna().corr()

    def find_uncorrelated(self, corr: pd.DataFrame, threshold: float = 0.3) -> list[str]:
        result = []
        for f in corr.columns:
            others = [x for x in corr.columns if x != f]
            if corr.loc[f, others].abs().mean() < threshold:
                result.append(f)
        return result

class PortfolioOptimizer:
    def mean_variance(self, exp_ret: pd.Series, cov: pd.DataFrame) -> np.ndarray:
        try:
            w = np.linalg.inv(cov.values) @ exp_ret.values
            return w / np.sum(w)
        except (np.linalg.LinAlgError, ValueError):
            return np.ones(len(exp_ret)) / len(exp_ret)

    def risk_parity(self, cov: pd.DataFrame, max_iter: int = 100) -> np.ndarray:
        n = cov.shape[0]
        w = np.ones(n) / n
        for _ in range(max_iter):
            marginal = cov.values @ w
            vol = np.sqrt(w @ cov.values @ w)
            if vol == 0: break
            risk_contrib = w * marginal / vol
            scale = np.sum(risk_contrib) / (n * risk_contrib + 1e-10)
            new_w = w * scale
            new_w = new_w / np.sum(new_w)
            if np.max(np.abs(new_w - w)) < 1e-6: break
            w = new_w
        return w

class AdvancedRiskManager:
    def __init__(self, max_pos: float = 0.2, max_lev: float = 5.0, max_dd: float = 0.20):
        self.max_pos = max_pos
        self.max_lev = max_lev
        self.max_dd = max_dd
        self.corr_analyzer = CorrelationAnalyzer()
        self.optimizer = PortfolioOptimizer()

    def check_limits(self, weights: np.ndarray, vol: float, dd: float) -> dict[str, bool]:
        return {
            "position_limit": np.max(np.abs(weights)) <= self.max_pos,
            "leverage_limit": np.sum(np.abs(weights)) <= self.max_lev,
            "drawdown_limit": abs(dd) <= self.max_dd,
        }

if __name__ == "__main__":
    print("=== Risk Test ===")
    np.random.seed(42)
    n, names = 252, ["Mom", "MeanRev", "Vol", "Volu", "ML"]
    ret = pd.DataFrame(np.random.randn(n, 5), columns=names)

    corr = CorrelationAnalyzer().calculate_matrix(ret)
    print("Korrelationsmatrix:")
    print(corr.round(2))

    opt = PortfolioOptimizer()
    exp_ret = pd.Series([0.1, 0.08, 0.06, 0.07, 0.12], index=names)
    cov = ret.cov() * 252

    mv = opt.mean_variance(exp_ret, cov)
    print("\nMean-Variance:")
    for n, w in zip(names, mv): print(f"  {n}: {w:.2%}")

    rp = opt.risk_parity(cov)
    print("\nRisk Parity:")
    for n, w in zip(names, rp): print(f"  {n}: {w:.2%}")

    rm = AdvancedRiskManager()
    checks = rm.check_limits(mv, 0.15, -0.08)
    print(f"\nLimits OK: {all(checks.values())}")
    print("✅ Test bestanden!")
