import pandas as pd import numpy as np from statsmodels.tsa.stattools import coint from statsmodels.regression.linear_model import OLS from statsmodels.tools import add_constant def test_cointegration(prices_a: pd.Series, prices_b: pd.Series) -> dict: """ Effectue le test de cointégration d'Engle-Granger sur deux séries de prix. Étapes : 1. Régression linéaire : prices_a = alpha + beta * prices_b + résidus 2. Test ADF (Augmented Dickey-Fuller) sur les résidus 3. Si p-value < 0.05 → la paire est cointégrée Parameters ---------- prices_a : pd.Series Prix du premier actif. prices_b : pd.Series Prix du second actif. Returns ------- dict Résultats du test avec les clés : - is_cointegrated (bool) - p_value (float) - beta (float) : coefficient de hedge - alpha (float) : intercept de la régression - test_statistic (float) - critical_values (dict) : seuils à 1%, 5%, 10% """ # Régression OLS : prices_a = alpha + beta * prices_b prices_b_avec_constante = add_constant(prices_b) modele = OLS(prices_a, prices_b_avec_constante).fit() alpha = modele.params.iloc[0] beta = modele.params.iloc[1] # Test de cointégration d'Engle-Granger via statsmodels statistique_test, p_value, valeurs_critiques = coint(prices_a, prices_b) return { "is_cointegrated": p_value < 0.05, "p_value": round(float(p_value), 6), "beta": round(float(beta), 6), "alpha": round(float(alpha), 6), "test_statistic": round(float(statistique_test), 4), "critical_values": { "1%": round(float(valeurs_critiques[0]), 4), "5%": round(float(valeurs_critiques[1]), 4), "10%": round(float(valeurs_critiques[2]), 4), }, } def compute_spread(prices_a: pd.Series, prices_b: pd.Series, beta: float) -> pd.Series: """ Calcule le spread entre deux actifs. spread = prices_a - beta * prices_b Parameters ---------- prices_a : pd.Series Prix du premier actif. prices_b : pd.Series Prix du second actif. beta : float Coefficient de hedge issu de la régression. Returns ------- pd.Series Le spread entre les deux actifs. """ return prices_a - beta * prices_b def compute_zscore(spread: pd.Series, window: int = 60) -> pd.Series: """ Calcule le z-score rolling du spread. z = (spread - rolling_mean) / rolling_std Parameters ---------- spread : pd.Series Le spread entre les deux actifs. window : int Fenêtre glissante en jours (défaut : 60, ~3 mois de trading). Returns ------- pd.Series Le z-score rolling du spread. """ moyenne_glissante = spread.rolling(window=window).mean() ecart_type_glissant = spread.rolling(window=window).std() zscore = (spread - moyenne_glissante) / ecart_type_glissant return zscore