Introduccion

En este estudio se analizaron cuatro activos financieros que representan distintos segmentos del mercado global: Microsoft, como acción del sector tecnológico; SPY ETF, que replica el comportamiento del índice S&P 500; el Treasury 10Y, referente de la renta fija estadounidense; y el par EUR/USD, uno de los tipos de cambio más negociados en el mundo. La selección de estos activos permite comparar el comportamiento de series provenientes de acciones, bonos, índices y divisas dentro de un mismo análisis.

## python:         /cloud/project/r-reticulate/bin/python
## libpython:      /opt/python/3.12.3/lib/libpython3.12.so
## pythonhome:     /cloud/project/r-reticulate:/cloud/project/r-reticulate
## version:        3.12.3 (main, May  1 2024, 21:23:34) [GCC 9.4.0]
## numpy:          /cloud/project/r-reticulate/lib/python3.12/site-packages/numpy
## numpy_version:  2.3.5
## 
## NOTE: Python version was forced by VIRTUAL_ENV
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import plotly.graph_objects as go
from plotly.subplots import make_subplots
import scipy.stats as stats
import statsmodels.api as sm
import yfinance as yf
# 1. Obtención y Preparación de Datos
def get_stock_data(ticker, start_date, end_date):
    df = yf.download(ticker, start=start_date, end=end_date)
    return df

microsoft_df = get_stock_data("MSFT", "2019-01-01", "2025-01-01")   # Renta variable: Microsoft
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
treasury_df = get_stock_data("^TNX", "2019-01-01", "2025-01-01")    # Renta fija: Bono Tesoro 10 años EEUU
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
currency_df = get_stock_data("EURUSD=X", "2019-01-01", "2025-01-01") # Moneda: Euro / Dólar
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
fund_df = get_stock_data("SPY", "2019-01-01", "2025-01-01")         # Fondo de inversión: ETF S&P 500
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
# 1. Descargar series de precios (Yahoo Finance)
microsoft_df = yf.download("MSFT", start="2019-01-01", end="2025-01-01")      # Renta variable: Microsoft
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
treasury_df = yf.download("^TNX", start="2019-01-01", end="2025-01-01")       # Renta fija: Bono del Tesoro 10 años
## <string>:1: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
currency_df = yf.download("EURUSD=X", start="2019-01-01", end="2025-01-01")   # Moneda: Euro/Dólar
## <string>:1: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
fund_df = yf.download("SPY", start="2019-01-01", end="2025-01-01")            # Fondo de inversión: ETF del S&P 500
## <string>:1: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
# 2. Calcular rendimientos diarios
microsoft_df['Returns'] = microsoft_df['Close'].pct_change()
treasury_df['Returns'] = treasury_df['Close'].pct_change()
currency_df['Returns'] = currency_df['Close'].pct_change()
fund_df['Returns'] = fund_df['Close'].pct_change()

# 3. Mostrar las primeras filas de cada activo
print("Microsoft:")
## Microsoft:
print(microsoft_df[['Close', 'Returns']].head(), "\n")
## Price           Close   Returns
## Ticker           MSFT          
## Date                           
## 2019-01-02  94.789658       NaN
## 2019-01-03  91.302574 -0.036788
## 2019-01-04  95.548981  0.046509
## 2019-01-07  95.670837  0.001275
## 2019-01-08  96.364540  0.007251
print("Treasury 10Y:")
## Treasury 10Y:
print(treasury_df[['Close', 'Returns']].head(), "\n")
## Price       Close   Returns
## Ticker       ^TNX          
## Date                       
## 2019-01-02  2.661       NaN
## 2019-01-03  2.554 -0.040210
## 2019-01-04  2.659  0.041112
## 2019-01-07  2.682  0.008650
## 2019-01-08  2.716  0.012677
print("EUR/USD:")
## EUR/USD:
print(currency_df[['Close', 'Returns']].head(), "\n")
## Price          Close   Returns
## Ticker      EURUSD=X          
## Date                          
## 2019-01-01  1.149306       NaN
## 2019-01-02  1.146171 -0.002728
## 2019-01-03  1.131811 -0.012529
## 2019-01-04  1.139108  0.006447
## 2019-01-07  1.141044  0.001700
print("SPY ETF:")
## SPY ETF:
print(fund_df[['Close', 'Returns']].head(), "\n")
## Price            Close   Returns
## Ticker             SPY          
## Date                            
## 2019-01-02  225.660172       NaN
## 2019-01-03  220.275269 -0.023863
## 2019-01-04  227.653580  0.033496
## 2019-01-07  229.448517  0.007885
## 2019-01-08  231.604309  0.009396

Series historicas de Precios

En este fragmento se realizó la construcción inicial de la base de datos financiera utilizada para el análisis. Primero, se descargaron desde Yahoo Finance las series históricas de precios de cierre de cuatro tipos de activos representativos de distintos mercados:

Microsoft (MSFT) como activo de renta variable,

Treasury 10Y (^TNX) como activo de renta fija,

EUR/USD como tipo de cambio,

SPY ETF, que replica el índice S&P 500, como fondo de inversión.

tickers = {
    "Microsoft (Renta Variable)": "MSFT",
    "Treasury 10Y (Renta Fija)": "^TNX",
    "EUR/USD (Moneda)": "EURUSD=X",
    "SPY ETF (Fondo de Inversión)": "SPY"
}

# Crear un diccionario para guardar los DataFrames
data = {}

for nombre, ticker in tickers.items():
    df = yf.download(ticker, start="2019-01-01", end="2025-01-01")
    
    #  Calcular rendimientos financieros y rendimientos al cuadrado
    df["Rendimiento"] = df["Close"].pct_change()
    df["Rendimiento_Cuadrado"] = df["Rendimiento"] ** 2
    
    # Guardar en el diccionario
    data[nombre] = df
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
#  Mostrar las primeras filas de cada serie
for nombre, df in data.items():
    print(f"\n--- {nombre} ---")
    print(df[["Close", "Rendimiento", "Rendimiento_Cuadrado"]].head())
## 
## --- Microsoft (Renta Variable) ---
## Price           Close Rendimiento Rendimiento_Cuadrado
## Ticker           MSFT                                 
## Date                                                  
## 2019-01-02  94.789658         NaN                  NaN
## 2019-01-03  91.302574   -0.036788             0.001353
## 2019-01-04  95.548981    0.046509             0.002163
## 2019-01-07  95.670837    0.001275             0.000002
## 2019-01-08  96.364540    0.007251             0.000053
## 
## --- Treasury 10Y (Renta Fija) ---
## Price       Close Rendimiento Rendimiento_Cuadrado
## Ticker       ^TNX                                 
## Date                                              
## 2019-01-02  2.661         NaN                  NaN
## 2019-01-03  2.554   -0.040210             0.001617
## 2019-01-04  2.659    0.041112             0.001690
## 2019-01-07  2.682    0.008650             0.000075
## 2019-01-08  2.716    0.012677             0.000161
## 
## --- EUR/USD (Moneda) ---
## Price          Close Rendimiento Rendimiento_Cuadrado
## Ticker      EURUSD=X                                 
## Date                                                 
## 2019-01-01  1.149306         NaN                  NaN
## 2019-01-02  1.146171   -0.002728             0.000007
## 2019-01-03  1.131811   -0.012529             0.000157
## 2019-01-04  1.139108    0.006447             0.000042
## 2019-01-07  1.141044    0.001700             0.000003
## 
## --- SPY ETF (Fondo de Inversión) ---
## Price            Close Rendimiento Rendimiento_Cuadrado
## Ticker             SPY                                 
## Date                                                   
## 2019-01-02  225.660172         NaN                  NaN
## 2019-01-03  220.275269   -0.023863             0.000569
## 2019-01-04  227.653580    0.033496             0.001122
## 2019-01-07  229.448517    0.007885             0.000062
## 2019-01-08  231.604309    0.009396             0.000088

Rendimientos Financieros

En este bloque se descargaron las series históricas de precios de cierre de los cuatro activos seleccionados (Microsoft, Treasury 10Y, EUR/USD y SPY ETF) utilizando Yahoo Finance. Para cada activo, se calcularon dos series fundamentales para el análisis temporal:

Rendimientos diarios, obtenidos como la variación porcentual del precio de cierre.

Rendimientos al cuadrado, útiles para detectar heterocedasticidad y evaluar patrones de volatilidad.

#  Descargar precios desde Yahoo Finance
tickers = {
    "Microsoft (Renta Variable)": "MSFT",
    "Treasury 10Y (Renta Fija)": "^TNX",
    "EUR/USD (Moneda)": "EURUSD=X",
    "SPY ETF (Fondo de Inversión)": "SPY"
}

data = {}

for nombre, ticker in tickers.items():
    df = yf.download(ticker, start="2019-01-01", end="2025-01-01")
    df["Rendimiento"] = df["Close"].pct_change()
    df["Rendimiento_Cuadrado"] = df["Rendimiento"] ** 2
    data[nombre] = df
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
#  Función para graficar las tres series
def graficar_series(df, nombre):
    plt.figure(figsize=(14, 10))
    
    # Precio
    plt.subplot(3, 1, 1)
    plt.plot(df.index, df["Close"], color="blue")
    plt.title(f"{nombre} - Precio de Cierre")
    plt.ylabel("Precio")
    
    # Rendimientos
    plt.subplot(3, 1, 2)
    plt.plot(df.index, df["Rendimiento"], color="green")
    plt.title(f"{nombre} - Rendimientos Financieros")
    plt.ylabel("Rendimiento Diario")
    
    # Rendimientos al Cuadrado
    plt.subplot(3, 1, 3)
    plt.plot(df.index, df["Rendimiento_Cuadrado"], color="red")
    plt.title(f"{nombre} - Rendimientos Financieros al Cuadrado")
    plt.ylabel("Rendimiento²")
    plt.xlabel("Fecha")
    
    plt.tight_layout()
    plt.show()

#  Graficar las tres series para cada activo
for nombre, df in data.items():
    graficar_series(df, nombre)

Analisis breve de las 4 graficas

En la gráfica Microsoft (Renta Variable) – Precio de Cierre se observa una tendencia alcista con episodios de alta volatilidad, especialmente en 2020, lo que también se refleja en los picos de las gráficas de Rendimientos y Rendimientos al Cuadrado. En “Treasury 10Y (Renta Fija) – Precio de Cierre” el activo muestra fuertes movimientos ligados a cambios en tasas de interés, y en 2020 presenta el mayor estallido de volatilidad entre todos los activos. En “SPY ETF (Fondo de Inversión) – Precio de Cierre” se aprecia un crecimiento sostenido del mercado accionario estadounidense, con choques notorios en rendimientos durante la pandemia. Finalmente, la gráfica “EUR/USD (Moneda) – Precio de Cierre” exhibe un comportamiento más estable, con variaciones moderadas y picos aislados en los rendimientos, característicos del mercado cambiario.

import yfinance as yf
import pandas as pd
import matplotlib.pyplot as plt
from statsmodels.graphics.tsaplots import plot_acf, plot_pacf

tickers = {
    "Renta Variable (MSFT)": "MSFT",
    "Renta Fija (10Y Treasury)": "^TNX",
    "Moneda (USDCOP)": "EURUSD=X",
    "Fondo de Inversión (SPY)": "SPY"
}

data = {}
for nombre, ticker in tickers.items():
    df = yf.download(ticker, start="2019-01-01", end="2025-01-01")
    df["Returns"] = df["Close"].pct_change()
    df["Returns_Squared"] = df["Returns"] ** 2
    data[nombre] = df.dropna()
## <string>:2: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
## <string>:2: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
## <string>:2: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
## <string>:2: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
# 2. Graficar los correlogramas (ACF y PACF)
for nombre, df in data.items():
    print(f"=== Correlogramas para {nombre} ===")

    fig, axes = plt.subplots(3, 2, figsize=(12, 10))
    fig.suptitle(f"Correlogramas de {nombre}", fontsize=14, fontweight='bold')

    # --- Precio ---
    plot_acf(df["Close"], ax=axes[0, 0], lags=30, title="ACF - Precio")
    plot_pacf(df["Close"], ax=axes[0, 1], lags=30, title="PACF - Precio")

    # --- Rendimientos ---
    plot_acf(df["Returns"], ax=axes[1, 0], lags=30, title="ACF - Rendimientos")
    plot_pacf(df["Returns"], ax=axes[1, 1], lags=30, title="PACF - Rendimientos")

    # --- Rendimientos al cuadrado ---
    plot_acf(df["Returns_Squared"], ax=axes[2, 0], lags=30, title="ACF - Rendimientos²")
    plot_pacf(df["Returns_Squared"], ax=axes[2, 1], lags=30, title="PACF - Rendimientos²")

    plt.tight_layout()
    plt.show()

Test de normalidad

Analisis de Autocorrelacion

Análisis Comparativo de Autocorrelaciones de los 4 Activos En los cuatro activos financieros examinados (MSFT, SPY, 10Y Treasury, y USDCOP), se observa consistentemente que sus series de precios son no estacionarias debido al decaimiento lento y persistente de sus funciones de autocorrelación (ACF), lo que confirma una fuerte dependencia pasada y sugiere un proceso AR(1) basado en el PACF. Una vez diferenciadas, sus series de rendimientos se vuelven estacionarias y se comportan como ruido blanco (ACF y PACF caen a cero), indicando la ausencia de correlación lineal en los retornos. La distinción crucial radica en la volatilidad: los rendimientos al cuadrado del MSFT, el SPY y el 10Y Treasury muestran una correlación significativa y positiva en sus ACF/PACF, lo que demuestra la presencia de agrupamiento de volatilidad (requiriendo modelos GARCH); mientras que el USDCOP es la excepción, ya que sus rendimientos al cuadrado presentan una correlación mínima o nula, lo que sugiere que la volatilidad de esta divisa no se agrupa de manera tan predecible.

import yfinance as yf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

# Definir los activos
tickers = {
    "Microsoft (Renta Variable)": "MSFT",
    "Treasury 10Y (Renta Fija)": "^TNX",
    "EUR/USD (Moneda)": "EURUSD=X",
    "SPY ETF (Fondo de Inversión)": "SPY"
}

# Descargar datos y calcular rendimientos
precios = {}
rendimientos = {}
rendimientos_cuadrados = {}

for nombre, ticker in tickers.items():
    df = yf.download(ticker, start="2019-01-01", end="2025-01-01")
    
    # Elegir la columna de cierre
    if 'Adj Close' in df.columns:
        cierre = df['Adj Close']
    elif 'Close' in df.columns:
        cierre = df['Close']
    else:
        print(f"No hay columna de precios para {nombre}")
        continue
    
    # Guardar precios
    precios[nombre] = cierre
    
    # Calcular rendimientos diarios
    ret = cierre.pct_change().dropna()
    rendimientos[nombre] = ret
    rendimientos_cuadrados[nombre] = ret ** 2
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
# Graficar histograma + curva normal para los rendimientos de cada activo
for nombre, ret in rendimientos.items():
    datos = ret.replace([np.inf, -np.inf], np.nan).dropna()
    
    if datos.empty:
        print(f"{nombre} no tiene datos válidos para graficar")
        continue
    
    # Ajuste de distribución normal
    mu, sigma = stats.norm.fit(datos)
    
    x_hat = np.linspace(datos.min(), datos.max(), 100)
    y_hat = stats.norm.pdf(x_hat, mu, sigma)
    
    # Gráfico
    fig, ax = plt.subplots(figsize=(8, 4))
    ax.hist(datos, bins=30, density=True, color="#3182bd", alpha=0.5, label='Histograma')
    ax.plot(x_hat, y_hat, color='red', linewidth=2, label='Normal teórica')
    ax.set_title(f'Distribución de rendimientos: {nombre}')
    ax.set_xlabel('Rendimientos diarios')
    ax.set_ylabel('Densidad de probabilidad')
    ax.legend()
    plt.show()

Distribucion de rendimientos:Analisis Consiso

La principal conclusión de las distribuciones de rendimientos de los cuatro activos es el fenómeno de leptocurtosis, que implica que la distribución real (Histograma) es más picuda en el centro y tiene colas más gruesas que la Normal teórica (curva roja).

Microsoft (MSFT) - Renta Variable: Presenta una distribución marcadamente leptocúrtica. Su pico central es mucho más alto que el teórico, indicando una sobreabundancia de días con cambios mínimos. Las colas pesadas confirman que los movimientos extremos (altas o bajas) son más frecuentes de lo que predice la Normal.

Treasury 10Y (Renta Fija): También exhibe leptocurtosis. Su distribución, aunque más concentrada, tiene un pico central superior y colas significativas que se extienden fuera de la curva roja. Esto implica que el riesgo de movimientos grandes en las tasas de interés es subestimado por la distribución Normal.

EUR/USD (Moneda): Muestra una distribución leptocúrtica con un pico central muy elevado. Aunque el rango de rendimientos es menor, la concentración de datos cerca de cero y las colas más densas indican que la volatilidad de la divisa está altamente concentrada y los saltos inesperados son más probables que en un modelo Gaussiano.

SPY ETF (Fondo de Inversión): Presenta la leptocurtosis más pronunciada. El pico central es el más alto en relación con su curva Normal, y las colas son visibles y gruesas. Esto refleja que, como índice de mercado, el riesgo de cola tail risk de pérdidas severas es una característica frecuente y no un evento raro bajo la perspectiva de la distribución teórica.

import matplotlib.pyplot as plt
import statsmodels.api as sm
import numpy as np

# Lista de los 4 activos
activos = [
    "Microsoft (Renta Variable)",
    "Treasury 10Y (Renta Fija)",
    "EUR/USD (Moneda)",
    "SPY ETF (Fondo de Inversión)"
]

# Gráfico Q-Q para los rendimientos de cada activo
for nombre in activos:
    if nombre not in rendimientos or rendimientos[nombre].empty:
        print(f" {nombre} no tiene rendimientos calculados.")
        continue
    
    # Filtrar datos no finitos
    datos = rendimientos[nombre].replace([np.inf, -np.inf], np.nan).dropna()
    if datos.empty:
        print(f" {nombre} no tiene datos válidos después de limpiar NaNs e infs.")
        continue

    # Crear Q-Q plot
    fig, ax = plt.subplots(figsize=(7, 4))
    sm.qqplot(
        datos,
        fit=True,
        line='q',
        alpha=0.4,
        lw=2,
        ax=ax
    )
    ax.set_title(f'Gráfico Q-Q: {nombre}', fontsize=10, fontweight="bold")
    ax.tick_params(labelsize=7)
    ax.set_xlabel('Teóricos')
    ax.set_ylabel('Muestra')
    plt.show()

Analisis de Graficos Q-Q Rendimientos

La línea roja diagonal representa la distribución Normal teórica. Si los puntos azules (cuantiles de la muestra) cayeran perfectamente sobre esta línea, la distribución de rendimientos sería Normal.

Microsoft (Renta Variable) y 펀 SPY ETF (Fondo de Inversión)Observación: En ambos gráficos, los puntos azules forman una “S” estirada. Los puntos se alinean con la recta en el centro (cercano a cero), pero se curvan y se separan significativamente de la línea roja en los extremos (las colas), especialmente en los valores más extremos (por encima de 3 y por debajo de -3 en el eje ‘Teóricos’).Conclusión: Ambos activos no siguen una distribución Normal. La separación en las colas es una clara evidencia de leptocurtosis (colas pesadas), indicando que los valores extremos (riesgos de cola) son mucho más frecuentes en los datos reales de lo que predice la Normalidad.

️Treasury 10Y (Renta Fija )Observación: El gráfico es el más disperso. Los puntos no solo se curvan en los extremos como los demás, sino que muestran valores atípicos muy separados en el centro del eje ‘Teóricos’ (alrededor de -1), con puntos extremos alcanzando valores de muestra de hasta 10.Conclusión: La distribución no es Normal. La gran dispersión y los valores atípicos severos (los puntos aislados) indican una distribución altamente leptocúrtica y con alta variabilidad que rompe fuertemente con la asunción de Normalidad.

EUR/USD (Moneda)Observación: Al igual que en la renta variable, los puntos forman una curva en forma de “S” que se desvía de la línea roja en los extremos. Los valores extremos teóricos (más allá de \(\pm 2\)) tienen valores de muestra más altos.Conclusión: La distribución no es Normal. El patrón de la “S” confirma la leptocurtosis, aunque la dispersión es visualmente menor que en la renta variable debido al rango de rendimientos intrínsecamente menor de las divisa

import scipy.stats as stats
import numpy as np

# Lista de los 4 activos
activos = [
    "Microsoft (Renta Variable)",
    "Treasury 10Y (Renta Fija)",
    "EUR/USD (Moneda)",
    "SPY ETF (Fondo de Inversión)"
]

# Calcular kurtosis y skewness para los rendimientos de cada activo
for nombre in activos:
    if nombre not in rendimientos or rendimientos[nombre].empty:
        print(f" {nombre} no tiene rendimientos calculados.")
        continue

    # Filtrar datos no finitos
    datos = rendimientos[nombre].replace([np.inf, -np.inf], np.nan).dropna()
    if datos.empty:
        print(f" {nombre} no tiene datos válidos después de limpiar NaNs e infs.")
        continue

    # Asegurarse de que sea un array 1D
    datos = np.ravel(datos)

    kurt = float(stats.kurtosis(datos))
    skew = float(stats.skew(datos))

    print(f"\n {nombre}")
    print(f"Kurtosis: {kurt:.4f}")
    print(f"Skewness: {skew:.4f}")
## 
##  Microsoft (Renta Variable)
## Kurtosis: 7.4277
## Skewness: -0.0415
## 
##  Treasury 10Y (Renta Fija)
## Kurtosis: 35.8032
## Skewness: 1.8698
## 
##  EUR/USD (Moneda)
## Kurtosis: 2.1367
## Skewness: -0.1129
## 
##  SPY ETF (Fondo de Inversión)
## Kurtosis: 12.2904
## Skewness: -0.5735

Estadística,Valor,Interpretación

Microsoft Curtosis,7.4277 (Muy alta),La distribución es leptocúrtica. Las colas son más pesadas y el pico central es más alto que en la distribución Normal. Esto significa que los eventos extremos (riesgos de cola) son mucho más probables. Asimetría,-0.0415 (Cercana a cero),La distribución es prácticamente simétrica. Treasury 10Y Estadística,Valor,Interpretación Curtosis,35.8032 (Extremadamente alta),Presenta la mayor leptocurtosis de todos los activos. Esto confirma que el riesgo de movimientos extremos en las tasas de interés es altamente subestimado por un modelo Normal. Asimetría,1.8698 (Alta y positiva),La distribución está sesgada a la derecha. Indica que los rendimientos positivos grandes son más probables que las pérdidas grandes de igual magnitud.

EUR/USD Curtosis,2.1367 (Baja),“La curtosis es menor que 3. Esto sugiere una distribución platicúrtica (o más”“aplanada”” que la Normal). Aunque los rendimientos financieros raramente son platicúrticos, este valor, en relación a los demás, indica que esta serie es la que más se acerca a la Normalidad en términos de colas.” Asimetría,-0.1129 (Cercana a cero),La distribución es prácticamente simétrica o ligeramente sesgada a la izquierda.

SPY ETF Curtosis,12.2904 (Muy alta),“La distribución es leptocúrtica. Al ser un índice de mercado, confirma que los riesgos de cola o eventos extremos son una característica fundamental y recurrente del mercado de valores.” Asimetría,-0.5735 (Moderada y negativa),La distribución está sesgada a la izquierda (sesgo negativo). Esto es típico de las acciones e implica que las pérdidas grandes son más probables que las ganancias grandes de igual magnitud.

import scipy.stats as stats
import numpy as np

# Lista de los 4 activos
activos = [
    "Microsoft (Renta Variable)",
    "Treasury 10Y (Renta Fija)",
    "EUR/USD (Moneda)",
    "SPY ETF (Fondo de Inversión)"
]

# Aplicar Shapiro-Wilk test a los rendimientos de cada activo
for nombre in activos:
    if nombre not in rendimientos or rendimientos[nombre].empty:
        print(f" {nombre} no tiene rendimientos calculados.")
        continue

    # Filtrar datos no finitos
    datos = rendimientos[nombre].replace([np.inf, -np.inf], np.nan).dropna()
    if datos.empty:
        print(f" {nombre} no tiene datos válidos después de limpiar NaNs e infs.")
        continue

    # Shapiro-Wilk test
    stat, p_value = stats.shapiro(datos)
    print(f"\n {nombre}")
    print(f"Shapiro-Wilk Test: Estadístico={stat:.4f}, p-valor={p_value:.4f}")
## 
##  Microsoft (Renta Variable)
## Shapiro-Wilk Test: Estadístico=0.9349, p-valor=0.0000
## 
##  Treasury 10Y (Renta Fija)
## Shapiro-Wilk Test: Estadístico=0.7898, p-valor=0.0000
## 
##  EUR/USD (Moneda)
## Shapiro-Wilk Test: Estadístico=0.9813, p-valor=0.0000
## 
##  SPY ETF (Fondo de Inversión)
## Shapiro-Wilk Test: Estadístico=0.8835, p-valor=0.0000

El Test de Shapiro-Wilk confirma de manera formal el rechazo absoluto de la Normalidad para los rendimientos de los cuatro activos, ya que en todos los casos el p-valor es significativamente menor que 0.05. La serie de Treasury 10Y es la que presenta la mayor desviación de la forma normal (Estadístico W=0.7898), lo cual corrobora su curtosis extrema y asimetría positiva. Las series de renta variable, MSFT (W=0.9349) y SPY (W=0.8835), también muestran una desviación significativa, confirmando la necesidad de modelar la leptocurtosis y el sesgo de sus colas pesadas. Por último, el EUR/USD, aunque rechaza la hipótesis, es la serie que menos se desvía de la Normalidad (W=0.9813), siendo coherente con el menor riesgo de cola previamente observado.

import yfinance as yf
import numpy as np
import pandas as pd
import scipy.stats as stats

# Definir activos
tickers = {
    "Microsoft (Renta Variable)": "MSFT",
    "Treasury 10Y (Renta Fija)": "^TNX",
    "EUR/USD (Moneda)": "EURUSD=X",
    "SPY ETF (Fondo de Inversión)": "SPY"
}

# Descargar precios de cierre y calcular rendimientos
rendimientos = {}
for nombre, ticker in tickers.items():
    df = yf.download(ticker, start="2019-01-01", end="2025-01-01")
    rend = df['Close'].pct_change()
    rend = rend.replace([np.inf, -np.inf], np.nan).dropna()
    rendimientos[nombre] = rend
## <string>:2: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
## <string>:2: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
## <string>:2: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
## <string>:2: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
# Aplicar D'Agostino K² test
resultados = []
for nombre, rend in rendimientos.items():
    datos = np.ravel(rend)                # Asegurar 1D
    datos = datos[np.isfinite(datos)]     # Eliminar NaNs e infinitos
    
    if len(datos) > 0:
        stat, p_val = stats.normaltest(datos)
        resultados.append({"Activo": nombre, "Estadístico K²": float(stat), "p-valor": float(p_val)})
    else:
        resultados.append({"Activo": nombre, "Estadístico K²": None, "p-valor": None})

# Mostrar tabla resumen
resultados_df = pd.DataFrame(resultados)
print("\n Resultados D'Agostino K² Test:")
## 
##  Resultados D'Agostino K² Test:
print(resultados_df)
##                          Activo  Estadístico K²        p-valor
## 0    Microsoft (Renta Variable)      229.692454   1.327142e-50
## 1     Treasury 10Y (Renta Fija)      892.550538  1.531487e-194
## 2              EUR/USD (Moneda)       84.834529   3.788054e-19
## 3  SPY ETF (Fondo de Inversión)      379.593189   3.735823e-83

Los resultados del test de normalidad D’Agostino K² muestran que ninguna de las cuatro series de rendimientos financieros sigue una distribución normal. En todos los activos —Microsoft, Treasury 10Y, EUR/USD y SPY ETF— el estadístico K² es muy elevado y los p-valores son extremadamente pequeños (mucho menores a 0.05), lo que lleva a rechazar de manera contundente la hipótesis nula de normalidad. Esto confirma un comportamiento típico de los mercados financieros: los rendimientos presentan colas pesadas, asimetría y curtosis elevada, lo que implica mayor probabilidad de movimientos extremos. Estos resultados justifican el uso de modelos más robustos como GARCH para capturar mejor la volatilidad y la naturaleza no normal de las series.

import yfinance as yf
import pandas as pd
import numpy as np
from statsmodels.tsa.stattools import adfuller

# ================================
# 1. Descargar datos
# ================================

tickers = {
    "Microsoft": "MSFT",
    "Treasury 10Y": "^TNX",
    "EUR/USD": "EURUSD=X",
    "SPY ETF": "SPY"
}

precios = {}
rendimientos = {}
rendimientos_cuadrados = {}

for nombre, ticker in tickers.items():
    df = yf.download(ticker, start="2019-01-01", end="2025-01-01")
    df["Returns"] = df["Close"].pct_change()
    df["Returns_Squared"] = df["Returns"] ** 2
    df = df.dropna()

    precios[nombre] = df["Close"]
    rendimientos[nombre] = df["Returns"]
    rendimientos_cuadrados[nombre] = df["Returns_Squared"]
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
# ================================
# 2. Función para ADF
# ================================

def adf_results(serie):
    serie = serie.replace([np.inf, -np.inf], np.nan).dropna()
    resultado = adfuller(serie, autolag='AIC')
    return resultado[1]   # p-value

# ================================
# 3. Evaluación para cada activo
# ================================

def interpretar(p):
    return "Sí es estacionaria " if p < 0.05 else "NO es estacionaria "

print("\n===== PRUEBA DE ESTACIONARIEDAD (ADF) =====\n")
## 
## ===== PRUEBA DE ESTACIONARIEDAD (ADF) =====
for nombre in precios.keys():

    p_precio = adf_results(precios[nombre])
    p_ret = adf_results(rendimientos[nombre])
    p_ret2 = adf_results(rendimientos_cuadrados[nombre])

    print(f"\n {nombre}")
    print("- Precio:")
    print(f"   p-value = {p_precio:.5f} → {interpretar(p_precio)}")
    
    print("- Rendimientos:")
    print(f"   p-value = {p_ret:.5f} → {interpretar(p_ret)}")

    print("- Rendimientos²:")
    print(f"   p-value = {p_ret2:.5f} → {interpretar(p_ret2)}")
## 
##  Microsoft
## - Precio:
##    p-value = 0.79803 → NO es estacionaria 
## - Rendimientos:
##    p-value = 0.00000 → Sí es estacionaria 
## - Rendimientos²:
##    p-value = 0.00000 → Sí es estacionaria 
## 
##  Treasury 10Y
## - Precio:
##    p-value = 0.94172 → NO es estacionaria 
## - Rendimientos:
##    p-value = 0.00000 → Sí es estacionaria 
## - Rendimientos²:
##    p-value = 0.00000 → Sí es estacionaria 
## 
##  EUR/USD
## - Precio:
##    p-value = 0.47398 → NO es estacionaria 
## - Rendimientos:
##    p-value = 0.00000 → Sí es estacionaria 
## - Rendimientos²:
##    p-value = 0.00000 → Sí es estacionaria 
## 
##  SPY ETF
## - Precio:
##    p-value = 0.93387 → NO es estacionaria 
## - Rendimientos:
##    p-value = 0.00000 → Sí es estacionaria 
## - Rendimientos²:
##    p-value = 0.00000 → Sí es estacionaria

Estacionariedad

En los cuatro activos analizados (Microsoft, Treasury 10Y, EUR/USD y SPY ETF) se observa que los precios no son estacionarios, lo cual es normal en mercados financieros porque siguen tendencias y acumulan shocks en el tiempo. Al transformar las series a rendimientos, todas se vuelven estacionarias, ya que esta operación elimina la tendencia y estabiliza la media. Además, los rendimientos al cuadrado también son estacionarios, lo que indica que la volatilidad fluctúa alrededor de un nivel constante, permitiendo identificar y modelar adecuadamente posibles efectos de heterocedasticidad como ARCH/GARCH.

# Supongamos que 'data' tiene tus precios y rendimientos de los 4 activos
# Primero calculamos rendimientos diarios
rendimientos = {}
for nombre, df in data.items():
    rendimientos[nombre] = df["Returns"].dropna()

# Aquí deberías seleccionar solo las series que pasen el test de estacionariedad
from statsmodels.tsa.stattools import adfuller

estacionarias = {}
for nombre, serie in rendimientos.items():
    resultado = adfuller(serie)
    p_value = resultado[1]
    if p_value < 0.05:  # estacionaria
        estacionarias[nombre] = serie

print("Series estacionarias encontradas:")
## Series estacionarias encontradas:
print(list(estacionarias.keys()))
## ['Renta Variable (MSFT)', 'Renta Fija (10Y Treasury)', 'Moneda (USDCOP)', 'Fondo de Inversión (SPY)']
import yfinance as yf
import pandas as pd
import numpy as np
from statsmodels.tsa.stattools import adfuller
from statsmodels.tsa.arima.model import ARIMA

# ================================
# 1. Descargar datos
# ================================
tickers = {
    "Microsoft": "MSFT",
    "Treasury 10Y": "^TNX",
    "EUR/USD": "EURUSD=X",
    "SPY ETF": "SPY"
}

precios = {}
rendimientos = {}
rendimientos_cuadrados = {}

for nombre, ticker in tickers.items():
    df = yf.download(ticker, start="2019-01-01", end="2025-01-01")
    df["Returns"] = df["Close"].pct_change()
    df["Returns_Squared"] = df["Returns"] ** 2
    df = df.dropna()

    precios[nombre] = df["Close"]
    rendimientos[nombre] = df["Returns"]
    rendimientos_cuadrados[nombre] = df["Returns_Squared"]
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
## <string>:3: FutureWarning: YF.download() has changed argument auto_adjust default to True
## [*********************100%***********************]  1 of 1 completed
# ================================
# 2. Función para ADF
# ================================
def adf_results(serie):
    serie = serie.replace([np.inf, -np.inf], np.nan).dropna()
    resultado = adfuller(serie, autolag='AIC')
    return resultado[1]   # p-value

def interpretar(p):
    return "Sí es estacionaria" if p < 0.05 else "NO es estacionaria"

# ================================
# 3. Seleccionar series estacionarias
# ================================
series_estacionarias = {}

for nombre in rendimientos.keys():
    p_ret = adf_results(rendimientos[nombre])
    p_ret2 = adf_results(rendimientos_cuadrados[nombre])
    
    series_estacionarias[nombre] = {}
    if p_ret < 0.05:
        series_estacionarias[nombre]["Returns"] = rendimientos[nombre]
    if p_ret2 < 0.05:
        series_estacionarias[nombre]["Returns_Squared"] = rendimientos_cuadrados[nombre]

# ================================
# 4. Estimar AR, MA y ARMA
# ================================
modelos = {}

for activo, series in series_estacionarias.items():
    modelos[activo] = {}
    for serie_nombre, serie_data in series.items():
        print(f"\n===== {activo} - {serie_nombre} =====\n")
        
        # AR(1)
        ar_model = ARIMA(serie_data, order=(1,0,0)).fit()
        # MA(1)
        ma_model = ARIMA(serie_data, order=(0,0,1)).fit()
        # ARMA(1,1)
        arma_model = ARIMA(serie_data, order=(1,0,1)).fit()
        
        modelos[activo][serie_nombre] = {
            "AR": ar_model,
            "MA": ma_model,
            "ARMA": arma_model
        }
        
        print("----- AR(1) -----")
        print(ar_model.summary())
        print("\n----- MA(1) -----")
        print(ma_model.summary())
        print("\n----- ARMA(1,1) -----")
        print(arma_model.summary())
## 
## ===== Microsoft - Returns =====
## 
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## ----- AR(1) -----
##                                SARIMAX Results                                
## ==============================================================================
## Dep. Variable:                Returns   No. Observations:                 1509
## Model:                 ARIMA(1, 0, 0)   Log Likelihood                3923.385
## Date:                Tue, 18 Nov 2025   AIC                          -7840.769
## Time:                        13:40:09   BIC                          -7824.812
## Sample:                             0   HQIC                         -7834.826
##                                - 1509                                         
## Covariance Type:                  opg                                         
## ==============================================================================
##                  coef    std err          z      P>|z|      [0.025      0.975]
## ------------------------------------------------------------------------------
## const          0.0012      0.000      2.914      0.004       0.000       0.002
## ar.L1         -0.1768      0.013    -13.268      0.000      -0.203      -0.151
## sigma2         0.0003   7.01e-06     46.068      0.000       0.000       0.000
## ===================================================================================
## Ljung-Box (L1) (Q):                   0.02   Jarque-Bera (JB):              1704.48
## Prob(Q):                              0.89   Prob(JB):                         0.00
## Heteroskedasticity (H):               0.50   Skew:                            -0.12
## Prob(H) (two-sided):                  0.00   Kurtosis:                         8.20
## ===================================================================================
## 
## Warnings:
## [1] Covariance matrix calculated using the outer product of gradients (complex-step).
## 
## ----- MA(1) -----
##                                SARIMAX Results                                
## ==============================================================================
## Dep. Variable:                Returns   No. Observations:                 1509
## Model:                 ARIMA(0, 0, 1)   Log Likelihood                3923.634
## Date:                Tue, 18 Nov 2025   AIC                          -7841.267
## Time:                        13:40:09   BIC                          -7825.310
## Sample:                             0   HQIC                         -7835.324
##                                - 1509                                         
## Covariance Type:                  opg                                         
## ==============================================================================
##                  coef    std err          z      P>|z|      [0.025      0.975]
## ------------------------------------------------------------------------------
## const          0.0012      0.000      2.986      0.003       0.000       0.002
## ma.L1         -0.1780      0.015    -11.900      0.000      -0.207      -0.149
## sigma2         0.0003   7.11e-06     45.420      0.000       0.000       0.000
## ===================================================================================
## Ljung-Box (L1) (Q):                   0.01   Jarque-Bera (JB):              1743.29
## Prob(Q):                              0.92   Prob(JB):                         0.00
## Heteroskedasticity (H):               0.50   Skew:                            -0.14
## Prob(H) (two-sided):                  0.00   Kurtosis:                         8.26
## ===================================================================================
## 
## Warnings:
## [1] Covariance matrix calculated using the outer product of gradients (complex-step).
## 
## ----- ARMA(1,1) -----
##                                SARIMAX Results                                
## ==============================================================================
## Dep. Variable:                Returns   No. Observations:                 1509
## Model:                 ARIMA(1, 0, 1)   Log Likelihood                3923.692
## Date:                Tue, 18 Nov 2025   AIC                          -7839.385
## Time:                        13:40:09   BIC                          -7818.108
## Sample:                             0   HQIC                         -7831.461
##                                - 1509                                         
## Covariance Type:                  opg                                         
## ==============================================================================
##                  coef    std err          z      P>|z|      [0.025      0.975]
## ------------------------------------------------------------------------------
## const          0.0012      0.000      2.909      0.004       0.000       0.002
## ar.L1         -0.0659      0.083     -0.792      0.428      -0.229       0.097
## ma.L1         -0.1121      0.088     -1.271      0.204      -0.285       0.061
## sigma2         0.0003   7.13e-06     45.285      0.000       0.000       0.000
## ===================================================================================
## Ljung-Box (L1) (Q):                   0.01   Jarque-Bera (JB):              1720.58
## Prob(Q):                              0.92   Prob(JB):                         0.00
## Heteroskedasticity (H):               0.50   Skew:                            -0.13
## Prob(H) (two-sided):                  0.00   Kurtosis:                         8.22
## ===================================================================================
## 
## Warnings:
## [1] Covariance matrix calculated using the outer product of gradients (complex-step).
## 
## ===== Microsoft - Returns_Squared =====
## 
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/base/model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
##   warnings.warn("Maximum Likelihood optimization failed to "
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/base/model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
##   warnings.warn("Maximum Likelihood optimization failed to "
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/base/model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
##   warnings.warn("Maximum Likelihood optimization failed to "
## ----- AR(1) -----
##                                SARIMAX Results                                
## ==============================================================================
## Dep. Variable:        Returns_Squared   No. Observations:                 1509
## Model:                 ARIMA(1, 0, 0)   Log Likelihood                8501.113
## Date:                Tue, 18 Nov 2025   AIC                         -16996.225
## Time:                        13:40:10   BIC                         -16980.268
## Sample:                             0   HQIC                        -16990.282
##                                - 1509                                         
## Covariance Type:                  opg                                         
## ==============================================================================
##                  coef    std err          z      P>|z|      [0.025      0.975]
## ------------------------------------------------------------------------------
## const          0.0003   6.98e-05      4.795      0.000       0.000       0.000
## ar.L1          0.5350      0.004    147.975      0.000       0.528       0.542
## sigma2      7.484e-07   6.01e-09    124.592      0.000    7.37e-07     7.6e-07
## ===================================================================================
## Ljung-Box (L1) (Q):                   3.29   Jarque-Bera (JB):            589226.78
## Prob(Q):                              0.07   Prob(JB):                         0.00
## Heteroskedasticity (H):               0.13   Skew:                             6.99
## Prob(H) (two-sided):                  0.00   Kurtosis:                        98.79
## ===================================================================================
## 
## Warnings:
## [1] Covariance matrix calculated using the outer product of gradients (complex-step).
## 
## ----- MA(1) -----
##                                SARIMAX Results                                
## ==============================================================================
## Dep. Variable:        Returns_Squared   No. Observations:                 1509
## Model:                 ARIMA(0, 0, 1)   Log Likelihood                8410.191
## Date:                Tue, 18 Nov 2025   AIC                         -16814.382
## Time:                        13:40:10   BIC                         -16798.425
## Sample:                             0   HQIC                        -16808.439
##                                - 1509                                         
## Covariance Type:                  opg                                         
## ==============================================================================
##                  coef    std err          z      P>|z|      [0.025      0.975]
## ------------------------------------------------------------------------------
## const          0.0003   5.45e-05      6.123      0.000       0.000       0.000
## ma.L1          0.4904      0.005     90.260      0.000       0.480       0.501
## sigma2      8.401e-07   8.25e-09    101.868      0.000    8.24e-07    8.56e-07
## ===================================================================================
## Ljung-Box (L1) (Q):                   0.00   Jarque-Bera (JB):            702564.58
## Prob(Q):                              0.95   Prob(JB):                         0.00
## Heteroskedasticity (H):               0.11   Skew:                             7.85
## Prob(H) (two-sided):                  0.00   Kurtosis:                       107.53
## ===================================================================================
## 
## Warnings:
## [1] Covariance matrix calculated using the outer product of gradients (complex-step).
## 
## ----- ARMA(1,1) -----
##                                SARIMAX Results                                
## ==============================================================================
## Dep. Variable:        Returns_Squared   No. Observations:                 1509
## Model:                 ARIMA(1, 0, 1)   Log Likelihood                8506.810
## Date:                Tue, 18 Nov 2025   AIC                         -17005.619
## Time:                        13:40:10   BIC                         -16984.342
## Sample:                             0   HQIC                        -16997.695
##                                - 1509                                         
## Covariance Type:                  opg                                         
## ==============================================================================
##                  coef    std err          z      P>|z|      [0.025      0.975]
## ------------------------------------------------------------------------------
## const          0.0003   8.11e-05      4.128      0.000       0.000       0.000
## ar.L1          0.6458      0.010     62.313      0.000       0.625       0.666
## ma.L1         -0.1554      0.014    -11.057      0.000      -0.183      -0.128
## sigma2      7.424e-07    6.1e-09    121.649      0.000     7.3e-07    7.54e-07
## ===================================================================================
## Ljung-Box (L1) (Q):                   0.01   Jarque-Bera (JB):            655514.75
## Prob(Q):                              0.93   Prob(JB):                         0.00
## Heteroskedasticity (H):               0.13   Skew:                             7.13
## Prob(H) (two-sided):                  0.00   Kurtosis:                       104.11
## ===================================================================================
## 
## Warnings:
## [1] Covariance matrix calculated using the outer product of gradients (complex-step).
## 
## ===== Treasury 10Y - Returns =====
## 
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## ----- AR(1) -----
##                                SARIMAX Results                                
## ==============================================================================
## Dep. Variable:                Returns   No. Observations:                 1509
## Model:                 ARIMA(1, 0, 0)   Log Likelihood                2833.814
## Date:                Tue, 18 Nov 2025   AIC                          -5661.628
## Time:                        13:40:11   BIC                          -5645.670
## Sample:                             0   HQIC                         -5655.685
##                                - 1509                                         
## Covariance Type:                  opg                                         
## ==============================================================================
##                  coef    std err          z      P>|z|      [0.025      0.975]
## ------------------------------------------------------------------------------
## const          0.0010      0.001      1.021      0.307      -0.001       0.003
## ar.L1         -0.0117      0.007     -1.724      0.085      -0.025       0.002
## sigma2         0.0014    1.3e-05    104.892      0.000       0.001       0.001
## ===================================================================================
## Ljung-Box (L1) (Q):                   0.00   Jarque-Bera (JB):             79068.24
## Prob(Q):                              0.96   Prob(JB):                         0.00
## Heteroskedasticity (H):               0.09   Skew:                             1.83
## Prob(H) (two-sided):                  0.00   Kurtosis:                        38.27
## ===================================================================================
## 
## Warnings:
## [1] Covariance matrix calculated using the outer product of gradients (complex-step).
## 
## ----- MA(1) -----
##                                SARIMAX Results                                
## ==============================================================================
## Dep. Variable:                Returns   No. Observations:                 1509
## Model:                 ARIMA(0, 0, 1)   Log Likelihood                2833.827
## Date:                Tue, 18 Nov 2025   AIC                          -5661.655
## Time:                        13:40:11   BIC                          -5645.697
## Sample:                             0   HQIC                         -5655.712
##                                - 1509                                         
## Covariance Type:                  opg                                         
## ==============================================================================
##                  coef    std err          z      P>|z|      [0.025      0.975]
## ------------------------------------------------------------------------------
## const          0.0010      0.001      1.027      0.304      -0.001       0.003
## ma.L1         -0.0190      0.007     -2.834      0.005      -0.032      -0.006
## sigma2         0.0014   1.31e-05    104.663      0.000       0.001       0.001
## ===================================================================================
## Ljung-Box (L1) (Q):                   0.04   Jarque-Bera (JB):             77555.71
## Prob(Q):                              0.83   Prob(JB):                         0.00
## Heteroskedasticity (H):               0.09   Skew:                             1.80
## Prob(H) (two-sided):                  0.00   Kurtosis:                        37.94
## ===================================================================================
## 
## Warnings:
## [1] Covariance matrix calculated using the outer product of gradients (complex-step).
## 
## ----- ARMA(1,1) -----
##                                SARIMAX Results                                
## ==============================================================================
## Dep. Variable:                Returns   No. Observations:                 1509
## Model:                 ARIMA(1, 0, 1)   Log Likelihood                2842.201
## Date:                Tue, 18 Nov 2025   AIC                          -5676.402
## Time:                        13:40:11   BIC                          -5655.126
## Sample:                             0   HQIC                         -5668.478
##                                - 1509                                         
## Covariance Type:                  opg                                         
## ==============================================================================
##                  coef    std err          z      P>|z|      [0.025      0.975]
## ------------------------------------------------------------------------------
## const          0.0010      0.001      1.311      0.190      -0.001       0.003
## ar.L1          0.7657      0.038     20.194      0.000       0.691       0.840
## ma.L1         -0.8342      0.034    -24.443      0.000      -0.901      -0.767
## sigma2         0.0014   1.33e-05    101.387      0.000       0.001       0.001
## ===================================================================================
## Ljung-Box (L1) (Q):                   2.94   Jarque-Bera (JB):             60895.25
## Prob(Q):                              0.09   Prob(JB):                         0.00
## Heteroskedasticity (H):               0.10   Skew:                             1.39
## Prob(H) (two-sided):                  0.00   Kurtosis:                        34.00
## ===================================================================================
## 
## Warnings:
## [1] Covariance matrix calculated using the outer product of gradients (complex-step).
## 
## ===== Treasury 10Y - Returns_Squared =====
## 
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## ----- AR(1) -----
##                                SARIMAX Results                                
## ==============================================================================
## Dep. Variable:        Returns_Squared   No. Observations:                 1509
## Model:                 ARIMA(1, 0, 0)   Log Likelihood                5239.768
## Date:                Tue, 18 Nov 2025   AIC                         -10473.536
## Time:                        13:40:14   BIC                         -10457.579
## Sample:                             0   HQIC                        -10467.593
##                                - 1509                                         
## Covariance Type:                  opg                                         
## ==============================================================================
##                  coef    std err          z      P>|z|      [0.025      0.975]
## ------------------------------------------------------------------------------
## const          0.0014      0.001      1.586      0.113      -0.000       0.003
## ar.L1          0.4563      0.003    143.975      0.000       0.450       0.462
## sigma2      5.642e-05   2.19e-07    257.115      0.000     5.6e-05    5.68e-05
## ===================================================================================
## Ljung-Box (L1) (Q):                   0.47   Jarque-Bera (JB):          13197862.77
## Prob(Q):                              0.49   Prob(JB):                         0.00
## Heteroskedasticity (H):               0.00   Skew:                            15.48
## Prob(H) (two-sided):                  0.00   Kurtosis:                       460.11
## ===================================================================================
## 
## Warnings:
## [1] Covariance matrix calculated using the outer product of gradients (complex-step).
## 
## ----- MA(1) -----
##                                SARIMAX Results                                
## ==============================================================================
## Dep. Variable:        Returns_Squared   No. Observations:                 1509
## Model:                 ARIMA(0, 0, 1)   Log Likelihood                5202.609
## Date:                Tue, 18 Nov 2025   AIC                         -10399.218
## Time:                        13:40:14   BIC                         -10383.261
## Sample:                             0   HQIC                        -10393.275
##                                - 1509                                         
## Covariance Type:                  opg                                         
## ==============================================================================
##                  coef    std err          z      P>|z|      [0.025      0.975]
## ------------------------------------------------------------------------------
## const          0.0014      0.001      2.169      0.030       0.000       0.003
## ma.L1          0.3796      0.004     92.955      0.000       0.372       0.388
## sigma2      5.919e-05    2.5e-07    237.153      0.000    5.87e-05    5.97e-05
## ===================================================================================
## Ljung-Box (L1) (Q):                   8.84   Jarque-Bera (JB):          16570368.73
## Prob(Q):                              0.00   Prob(JB):                         0.00
## Heteroskedasticity (H):               0.00   Skew:                            18.77
## Prob(H) (two-sided):                  0.00   Kurtosis:                       514.99
## ===================================================================================
## 
## Warnings:
## [1] Covariance matrix calculated using the outer product of gradients (complex-step).
## 
## ----- ARMA(1,1) -----
##                                SARIMAX Results                                
## ==============================================================================
## Dep. Variable:        Returns_Squared   No. Observations:                 1509
## Model:                 ARIMA(1, 0, 1)   Log Likelihood                5241.059
## Date:                Tue, 18 Nov 2025   AIC                         -10474.118
## Time:                        13:40:14   BIC                         -10452.841
## Sample:                             0   HQIC                        -10466.194
##                                - 1509                                         
## Covariance Type:                  opg                                         
## ==============================================================================
##                  coef    std err          z      P>|z|      [0.025      0.975]
## ------------------------------------------------------------------------------
## const          0.0014      0.001      1.522      0.128      -0.000       0.003
## ar.L1          0.5250      0.020     26.063      0.000       0.486       0.565
## ma.L1         -0.0870      0.024     -3.557      0.000      -0.135      -0.039
## sigma2      5.627e-05   2.42e-07    232.327      0.000    5.58e-05    5.67e-05
## ===================================================================================
## Ljung-Box (L1) (Q):                   0.00   Jarque-Bera (JB):          13023445.92
## Prob(Q):                              0.98   Prob(JB):                         0.00
## Heteroskedasticity (H):               0.00   Skew:                            15.49
## Prob(H) (two-sided):                  0.00   Kurtosis:                       457.06
## ===================================================================================
## 
## Warnings:
## [1] Covariance matrix calculated using the outer product of gradients (complex-step).
## 
## ===== EUR/USD - Returns =====
## 
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/base/model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
##   warnings.warn("Maximum Likelihood optimization failed to "
## ----- AR(1) -----
##                                SARIMAX Results                                
## ==============================================================================
## Dep. Variable:                Returns   No. Observations:                 1564
## Model:                 ARIMA(1, 0, 0)   Log Likelihood                6251.616
## Date:                Tue, 18 Nov 2025   AIC                         -12497.233
## Time:                        13:40:16   BIC                         -12481.168
## Sample:                             0   HQIC                        -12491.261
##                                - 1564                                         
## Covariance Type:                  opg                                         
## ==============================================================================
##                  coef    std err          z      P>|z|      [0.025      0.975]
## ------------------------------------------------------------------------------
## const      -5.402e-05      0.000     -0.467      0.640      -0.000       0.000
## ar.L1          0.0223      0.022      1.036      0.300      -0.020       0.065
## sigma2      1.975e-05   4.95e-07     39.916      0.000    1.88e-05    2.07e-05
## ===================================================================================
## Ljung-Box (L1) (Q):                   0.00   Jarque-Bera (JB):               296.70
## Prob(Q):                              0.99   Prob(JB):                         0.00
## Heteroskedasticity (H):               1.12   Skew:                            -0.12
## Prob(H) (two-sided):                  0.21   Kurtosis:                         5.12
## ===================================================================================
## 
## Warnings:
## [1] Covariance matrix calculated using the outer product of gradients (complex-step).
## 
## ----- MA(1) -----
##                                SARIMAX Results                                
## ==============================================================================
## Dep. Variable:                Returns   No. Observations:                 1564
## Model:                 ARIMA(0, 0, 1)   Log Likelihood                6251.621
## Date:                Tue, 18 Nov 2025   AIC                         -12497.243
## Time:                        13:40:16   BIC                         -12481.178
## Sample:                             0   HQIC                        -12491.270
##                                - 1564                                         
## Covariance Type:                  opg                                         
## ==============================================================================
##                  coef    std err          z      P>|z|      [0.025      0.975]
## ------------------------------------------------------------------------------
## const      -5.802e-05      0.000     -0.501      0.616      -0.000       0.000
## ma.L1          0.0239      0.022      1.112      0.266      -0.018       0.066
## sigma2      1.974e-05   4.94e-07     39.974      0.000    1.88e-05    2.07e-05
## ===================================================================================
## Ljung-Box (L1) (Q):                   0.00   Jarque-Bera (JB):               296.69
## Prob(Q):                              0.96   Prob(JB):                         0.00
## Heteroskedasticity (H):               1.12   Skew:                            -0.12
## Prob(H) (two-sided):                  0.20   Kurtosis:                         5.12
## ===================================================================================
## 
## Warnings:
## [1] Covariance matrix calculated using the outer product of gradients (complex-step).
## 
## ----- ARMA(1,1) -----
##                                SARIMAX Results                                
## ==============================================================================
## Dep. Variable:                Returns   No. Observations:                 1564
## Model:                 ARIMA(1, 0, 1)   Log Likelihood                6251.556
## Date:                Tue, 18 Nov 2025   AIC                         -12495.112
## Time:                        13:40:16   BIC                         -12473.692
## Sample:                             0   HQIC                        -12487.149
##                                - 1564                                         
## Covariance Type:                  opg                                         
## ==============================================================================
##                  coef    std err          z      P>|z|      [0.025      0.975]
## ------------------------------------------------------------------------------
## const       -5.79e-05      0.000     -0.498      0.618      -0.000       0.000
## ar.L1          0.1351      0.852      0.159      0.874      -1.534       1.805
## ma.L1         -0.1111      0.855     -0.130      0.897      -1.786       1.564
## sigma2      1.974e-05   5.01e-07     39.385      0.000    1.88e-05    2.07e-05
## ===================================================================================
## Ljung-Box (L1) (Q):                   0.00   Jarque-Bera (JB):               294.95
## Prob(Q):                              0.96   Prob(JB):                         0.00
## Heteroskedasticity (H):               1.12   Skew:                            -0.12
## Prob(H) (two-sided):                  0.20   Kurtosis:                         5.11
## ===================================================================================
## 
## Warnings:
## [1] Covariance matrix calculated using the outer product of gradients (complex-step).
## 
## ===== EUR/USD - Returns_Squared =====
## 
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/base/model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
##   warnings.warn("Maximum Likelihood optimization failed to "
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/base/model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
##   warnings.warn("Maximum Likelihood optimization failed to "
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/base/model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
##   warnings.warn("Maximum Likelihood optimization failed to "
## ----- AR(1) -----
##                                SARIMAX Results                                
## ==============================================================================
## Dep. Variable:        Returns_Squared   No. Observations:                 1564
## Model:                 ARIMA(1, 0, 0)   Log Likelihood               13617.303
## Date:                Tue, 18 Nov 2025   AIC                         -27228.606
## Time:                        13:40:18   BIC                         -27212.541
## Sample:                             0   HQIC                        -27222.634
##                                - 1564                                         
## Covariance Type:                  opg                                         
## ==============================================================================
##                  coef    std err          z      P>|z|      [0.025      0.975]
## ------------------------------------------------------------------------------
## const       1.976e-05   1.62e-06     12.164      0.000    1.66e-05    2.29e-05
## ar.L1          0.0953   2.58e-11    3.7e+09      0.000       0.095       0.095
## sigma2      1.603e-09   2.26e-11     70.879      0.000    1.56e-09    1.65e-09
## ===================================================================================
## Ljung-Box (L1) (Q):                   0.16   Jarque-Bera (JB):            562059.37
## Prob(Q):                              0.69   Prob(JB):                         0.00
## Heteroskedasticity (H):               0.62   Skew:                             7.03
## Prob(H) (two-sided):                  0.00   Kurtosis:                        94.80
## ===================================================================================
## 
## Warnings:
## [1] Covariance matrix calculated using the outer product of gradients (complex-step).
## [2] Covariance matrix is singular or near-singular, with condition number 4.18e+25. Standard errors may be unstable.
## 
## ----- MA(1) -----
##                                SARIMAX Results                                
## ==============================================================================
## Dep. Variable:        Returns_Squared   No. Observations:                 1564
## Model:                 ARIMA(0, 0, 1)   Log Likelihood               13616.063
## Date:                Tue, 18 Nov 2025   AIC                         -27226.125
## Time:                        13:40:18   BIC                         -27210.060
## Sample:                             0   HQIC                        -27220.153
##                                - 1564                                         
## Covariance Type:                  opg                                         
## ==============================================================================
##                  coef    std err          z      P>|z|      [0.025      0.975]
## ------------------------------------------------------------------------------
## const       1.976e-05   1.58e-06     12.505      0.000    1.67e-05    2.29e-05
## ma.L1          0.0774   2.82e-11   2.74e+09      0.000       0.077       0.077
## sigma2        1.6e-09   2.25e-11     70.984      0.000    1.56e-09    1.64e-09
## ===================================================================================
## Ljung-Box (L1) (Q):                   0.16   Jarque-Bera (JB):            564063.08
## Prob(Q):                              0.69   Prob(JB):                         0.00
## Heteroskedasticity (H):               0.62   Skew:                             7.04
## Prob(H) (two-sided):                  0.00   Kurtosis:                        94.96
## ===================================================================================
## 
## Warnings:
## [1] Covariance matrix calculated using the outer product of gradients (complex-step).
## [2] Covariance matrix is singular or near-singular, with condition number 2.12e+26. Standard errors may be unstable.
## 
## ----- ARMA(1,1) -----
##                                SARIMAX Results                                
## ==============================================================================
## Dep. Variable:        Returns_Squared   No. Observations:                 1564
## Model:                 ARIMA(1, 0, 1)   Log Likelihood               13658.636
## Date:                Tue, 18 Nov 2025   AIC                         -27309.271
## Time:                        13:40:18   BIC                         -27287.851
## Sample:                             0   HQIC                        -27301.308
##                                - 1564                                         
## Covariance Type:                  opg                                         
## ==============================================================================
##                  coef    std err          z      P>|z|      [0.025      0.975]
## ------------------------------------------------------------------------------
## const        1.97e-05   3.72e-06      5.299      0.000    1.24e-05     2.7e-05
## ar.L1          0.9562   8.29e-10   1.15e+09      0.000       0.956       0.956
## ma.L1         -0.8788   3.18e-10  -2.76e+09      0.000      -0.879      -0.879
## sigma2      1.508e-09   2.15e-11     70.117      0.000    1.47e-09    1.55e-09
## ===================================================================================
## Ljung-Box (L1) (Q):                   2.55   Jarque-Bera (JB):            568457.08
## Prob(Q):                              0.11   Prob(JB):                         0.00
## Heteroskedasticity (H):               0.67   Skew:                             6.91
## Prob(H) (two-sided):                  0.00   Kurtosis:                        95.37
## ===================================================================================
## 
## Warnings:
## [1] Covariance matrix calculated using the outer product of gradients (complex-step).
## [2] Covariance matrix is singular or near-singular, with condition number 1.28e+24. Standard errors may be unstable.
## 
## ===== SPY ETF - Returns =====
## 
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/base/model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
##   warnings.warn("Maximum Likelihood optimization failed to "
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## ----- AR(1) -----
##                                SARIMAX Results                                
## ==============================================================================
## Dep. Variable:                Returns   No. Observations:                 1509
## Model:                 ARIMA(1, 0, 0)   Log Likelihood                4490.128
## Date:                Tue, 18 Nov 2025   AIC                          -8974.255
## Time:                        13:40:19   BIC                          -8958.298
## Sample:                             0   HQIC                         -8968.312
##                                - 1509                                         
## Covariance Type:                  opg                                         
## ==============================================================================
##                  coef    std err          z      P>|z|      [0.025      0.975]
## ------------------------------------------------------------------------------
## const          0.0007      0.000      2.462      0.014       0.000       0.001
## ar.L1         -0.1525      0.011    -14.513      0.000      -0.173      -0.132
## sigma2         0.0002   2.32e-06     65.666      0.000       0.000       0.000
## ===================================================================================
## Ljung-Box (L1) (Q):                   0.20   Jarque-Bera (JB):              7435.79
## Prob(Q):                              0.65   Prob(JB):                         0.00
## Heteroskedasticity (H):               0.28   Skew:                            -0.73
## Prob(H) (two-sided):                  0.00   Kurtosis:                        13.78
## ===================================================================================
## 
## Warnings:
## [1] Covariance matrix calculated using the outer product of gradients (complex-step).
## 
## ----- MA(1) -----
##                                SARIMAX Results                                
## ==============================================================================
## Dep. Variable:                Returns   No. Observations:                 1509
## Model:                 ARIMA(0, 0, 1)   Log Likelihood                4487.496
## Date:                Tue, 18 Nov 2025   AIC                          -8968.992
## Time:                        13:40:19   BIC                          -8953.034
## Sample:                             0   HQIC                         -8963.049
##                                - 1509                                         
## Covariance Type:                  opg                                         
## ==============================================================================
##                  coef    std err          z      P>|z|      [0.025      0.975]
## ------------------------------------------------------------------------------
## const          0.0007      0.000      2.438      0.015       0.000       0.001
## ma.L1         -0.1395      0.011    -12.197      0.000      -0.162      -0.117
## sigma2         0.0002   2.31e-06     66.212      0.000       0.000       0.000
## ===================================================================================
## Ljung-Box (L1) (Q):                   0.01   Jarque-Bera (JB):              7712.28
## Prob(Q):                              0.91   Prob(JB):                         0.00
## Heteroskedasticity (H):               0.28   Skew:                            -0.75
## Prob(H) (two-sided):                  0.00   Kurtosis:                        13.97
## ===================================================================================
## 
## Warnings:
## [1] Covariance matrix calculated using the outer product of gradients (complex-step).
## 
## ----- ARMA(1,1) -----
##                                SARIMAX Results                                
## ==============================================================================
## Dep. Variable:                Returns   No. Observations:                 1509
## Model:                 ARIMA(1, 0, 1)   Log Likelihood                4491.775
## Date:                Tue, 18 Nov 2025   AIC                          -8975.549
## Time:                        13:40:19   BIC                          -8954.273
## Sample:                             0   HQIC                         -8967.625
##                                - 1509                                         
## Covariance Type:                  opg                                         
## ==============================================================================
##                  coef    std err          z      P>|z|      [0.025      0.975]
## ------------------------------------------------------------------------------
## const          0.0007      0.000      2.322      0.020       0.000       0.001
## ar.L1         -0.5549      0.047    -11.712      0.000      -0.648      -0.462
## ma.L1          0.4154      0.052      8.020      0.000       0.314       0.517
## sigma2         0.0002   2.55e-06     59.707      0.000       0.000       0.000
## ===================================================================================
## Ljung-Box (L1) (Q):                   0.04   Jarque-Bera (JB):              8059.86
## Prob(Q):                              0.84   Prob(JB):                         0.00
## Heteroskedasticity (H):               0.29   Skew:                            -0.66
## Prob(H) (two-sided):                  0.00   Kurtosis:                        14.24
## ===================================================================================
## 
## Warnings:
## [1] Covariance matrix calculated using the outer product of gradients (complex-step).
## 
## ===== SPY ETF - Returns_Squared =====
## 
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/base/model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
##   warnings.warn("Maximum Likelihood optimization failed to "
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/tsa/base/tsa_model.py:473: ValueWarning: A date index has been provided, but it has no associated frequency information and so will be ignored when e.g. forecasting.
##   self._init_dates(dates, freq)
## /cloud/project/r-reticulate/lib/python3.12/site-packages/statsmodels/base/model.py:607: ConvergenceWarning: Maximum Likelihood optimization failed to converge. Check mle_retvals
##   warnings.warn("Maximum Likelihood optimization failed to "
## ----- AR(1) -----
##                                SARIMAX Results                                
## ==============================================================================
## Dep. Variable:        Returns_Squared   No. Observations:                 1509
## Model:                 ARIMA(1, 0, 0)   Log Likelihood                9287.761
## Date:                Tue, 18 Nov 2025   AIC                         -18569.521
## Time:                        13:40:21   BIC                         -18553.564
## Sample:                             0   HQIC                        -18563.578
##                                - 1509                                         
## Covariance Type:                  opg                                         
## ==============================================================================
##                  coef    std err          z      P>|z|      [0.025      0.975]
## ------------------------------------------------------------------------------
## const          0.0002    4.6e-05      3.399      0.001    6.63e-05       0.000
## ar.L1          0.4851      0.004    119.772      0.000       0.477       0.493
## sigma2      2.638e-07   1.84e-09    143.093      0.000     2.6e-07    2.67e-07
## ===================================================================================
## Ljung-Box (L1) (Q):                  61.15   Jarque-Bera (JB):           1220243.43
## Prob(Q):                              0.00   Prob(JB):                         0.00
## Heteroskedasticity (H):               0.02   Skew:                             9.27
## Prob(H) (two-sided):                  0.00   Kurtosis:                       141.07
## ===================================================================================
## 
## Warnings:
## [1] Covariance matrix calculated using the outer product of gradients (complex-step).
## 
## ----- MA(1) -----
##                                SARIMAX Results                                
## ==============================================================================
## Dep. Variable:        Returns_Squared   No. Observations:                 1509
## Model:                 ARIMA(0, 0, 1)   Log Likelihood                9189.935
## Date:                Tue, 18 Nov 2025   AIC                         -18373.870
## Time:                        13:40:21   BIC                         -18357.913
## Sample:                             0   HQIC                        -18367.927
##                                - 1509                                         
## Covariance Type:                  opg                                         
## ==============================================================================
##                  coef    std err          z      P>|z|      [0.025      0.975]
## ------------------------------------------------------------------------------
## const          0.0002   3.61e-05      4.265      0.000    8.32e-05       0.000
## ma.L1          0.2760      0.006     46.685      0.000       0.264       0.288
## sigma2      2.976e-07   2.39e-09    124.394      0.000    2.93e-07    3.02e-07
## ===================================================================================
## Ljung-Box (L1) (Q):                  26.14   Jarque-Bera (JB):           1940648.35
## Prob(Q):                              0.00   Prob(JB):                         0.00
## Heteroskedasticity (H):               0.02   Skew:                            11.54
## Prob(H) (two-sided):                  0.00   Kurtosis:                       177.16
## ===================================================================================
## 
## Warnings:
## [1] Covariance matrix calculated using the outer product of gradients (complex-step).
## 
## ----- ARMA(1,1) -----
##                                SARIMAX Results                                
## ==============================================================================
## Dep. Variable:        Returns_Squared   No. Observations:                 1509
## Model:                 ARIMA(1, 0, 1)   Log Likelihood                9399.885
## Date:                Tue, 18 Nov 2025   AIC                         -18791.770
## Time:                        13:40:21   BIC                         -18770.494
## Sample:                             0   HQIC                        -18783.846
##                                - 1509                                         
## Covariance Type:                  opg                                         
## ==============================================================================
##                  coef    std err          z      P>|z|      [0.025      0.975]
## ------------------------------------------------------------------------------
## const          0.0002   6.71e-05      2.328      0.020    2.47e-05       0.000
## ar.L1          0.8471      0.006    141.468      0.000       0.835       0.859
## ma.L1         -0.5711      0.008    -70.643      0.000      -0.587      -0.555
## sigma2      2.264e-07   1.65e-09    137.540      0.000    2.23e-07     2.3e-07
## ===================================================================================
## Ljung-Box (L1) (Q):                   1.25   Jarque-Bera (JB):           1269294.77
## Prob(Q):                              0.26   Prob(JB):                         0.00
## Heteroskedasticity (H):               0.02   Skew:                             9.48
## Prob(H) (two-sided):                  0.00   Kurtosis:                       143.81
## ===================================================================================
## 
## Warnings:
## [1] Covariance matrix calculated using the outer product of gradients (complex-step).

Análisis de Modelos ARIMA para MSFT y Treasury 10Y

Los resultados muestran que tanto Microsoft como el Treasury 10Y presentan rendimientos que pueden modelarse adecuadamente con estructuras ARIMA simples, donde MA(1) es el mejor para Microsoft y ARMA(1,1) para el Treasury 10Y, ya que ambos capturan la débil autocorrelación lineal presente en los retornos. En todos los casos, las pruebas Ljung-Box confirman que los modelos eliminan la correlación lineal, pero la Prob(H)=0.00 evidencia heterocedasticidad, lo que hace obligatorio el uso de modelos GARCH. En los rendimientos al cuadrado, que reflejan la dinámica de volatilidad, el mejor modelo para ambos activos es el ARMA(1,1), pues logra eliminar la autocorrelación remanente y captura la fuerte persistencia de la varianza. En conjunto, esto indica que los precios siguen un comportamiento no estacionario, los retornos son estacionarios pero con volatilidad cambiante, y que la estructura más adecuada para cada activo es un modelo ARIMA que explique la media, complementado por un GARCH(1,1) para capturar la volatilidad.

from statsmodels.stats.diagnostic import acorr_ljungbox, het_arch
import matplotlib.pyplot as plt
from statsmodels.graphics.tsaplots import plot_acf

# ================================
# Revisar residuos de todos los modelos
# ================================
for activo, series in modelos.items():
    for serie_nombre, modelos_serie in series.items():
        print(f"\n===== {activo} - {serie_nombre} =====\n")
        for tipo_modelo, model in modelos_serie.items():
            residuos = model.resid
            print(f"--- {tipo_modelo} ---")

            #  Autocorrelación: Ljung-Box
            lb_test = acorr_ljungbox(residuos, lags=[10], return_df=True)
            print("Ljung-Box (autocorrelación):")
            print(lb_test)

            # Graficar ACF de residuos
            fig, ax = plt.subplots()
            plot_acf(residuos, lags=20, ax=ax)
            ax.set_title(f"{activo} - {serie_nombre} - {tipo_modelo} ACF residuos")
            plt.show()
            plt.close()  # <- importante para que se dibujen todas

from statsmodels.stats.diagnostic import acorr_ljungbox, het_arch

# ================================
# Revisar residuos de todos los modelos (solo valores)
# ================================
for activo, series in modelos.items():
    for serie_nombre, modelos_serie in series.items():
        print(f"\n===== {activo} - {serie_nombre} =====\n")
        for tipo_modelo, model in modelos_serie.items():
            residuos = model.resid
            print(f"--- {tipo_modelo} ---")

            #  Autocorrelación: Ljung-Box
            lb_test = acorr_ljungbox(residuos, lags=[10], return_df=True)
            print("Ljung-Box (autocorrelación):")
            print(lb_test.to_string(index=False))  # imprime limpio

            #  Heterocedasticidad: prueba ARCH
            arch_test = het_arch(residuos)
            print("Prueba ARCH (heterocedasticidad):")
            print(f"LM stat: {arch_test[0]:.4f}, p-value: {arch_test[1]:.4f}")

            if arch_test[1] < 0.05:
                print("-> Hay heterocedasticidad. Se recomienda modelo GARCH.\n")
            else:
                print("-> No hay evidencia de heterocedasticidad.\n")
## 
## ===== Microsoft - Returns =====
## 
## --- AR ---
## Ljung-Box (autocorrelación):
##   lb_stat    lb_pvalue
## 56.390162 1.734801e-08
## Prueba ARCH (heterocedasticidad):
## LM stat: 396.8007, p-value: 0.0000
## -> Hay heterocedasticidad. Se recomienda modelo GARCH.
## 
## --- MA ---
## Ljung-Box (autocorrelación):
##   lb_stat    lb_pvalue
## 59.408008 4.689890e-09
## Prueba ARCH (heterocedasticidad):
## LM stat: 407.4164, p-value: 0.0000
## -> Hay heterocedasticidad. Se recomienda modelo GARCH.
## 
## --- ARMA ---
## Ljung-Box (autocorrelación):
##   lb_stat    lb_pvalue
## 57.990536 8.680289e-09
## Prueba ARCH (heterocedasticidad):
## LM stat: 403.2350, p-value: 0.0000
## -> Hay heterocedasticidad. Se recomienda modelo GARCH.
## 
## 
## ===== Microsoft - Returns_Squared =====
## 
## --- AR ---
## Ljung-Box (autocorrelación):
##   lb_stat    lb_pvalue
## 64.705484 4.614556e-10
## Prueba ARCH (heterocedasticidad):
## LM stat: 618.7308, p-value: 0.0000
## -> Hay heterocedasticidad. Se recomienda modelo GARCH.
## 
## --- MA ---
## Ljung-Box (autocorrelación):
##    lb_stat    lb_pvalue
## 351.898099 1.576029e-69
## Prueba ARCH (heterocedasticidad):
## LM stat: 680.5606, p-value: 0.0000
## -> Hay heterocedasticidad. Se recomienda modelo GARCH.
## 
## --- ARMA ---
## Ljung-Box (autocorrelación):
##   lb_stat  lb_pvalue
## 46.688851   0.000001
## Prueba ARCH (heterocedasticidad):
## LM stat: 590.8116, p-value: 0.0000
## -> Hay heterocedasticidad. Se recomienda modelo GARCH.
## 
## 
## ===== Treasury 10Y - Returns =====
## 
## --- AR ---
## Ljung-Box (autocorrelación):
##    lb_stat    lb_pvalue
## 121.510969 2.496991e-21
## Prueba ARCH (heterocedasticidad):
## LM stat: 533.8057, p-value: 0.0000
## -> Hay heterocedasticidad. Se recomienda modelo GARCH.
## 
## --- MA ---
## Ljung-Box (autocorrelación):
##    lb_stat    lb_pvalue
## 122.042435 1.947438e-21
## Prueba ARCH (heterocedasticidad):
## LM stat: 540.6719, p-value: 0.0000
## -> Hay heterocedasticidad. Se recomienda modelo GARCH.
## 
## --- ARMA ---
## Ljung-Box (autocorrelación):
##   lb_stat    lb_pvalue
## 98.444169 1.115701e-16
## Prueba ARCH (heterocedasticidad):
## LM stat: 651.7640, p-value: 0.0000
## -> Hay heterocedasticidad. Se recomienda modelo GARCH.
## 
## 
## ===== Treasury 10Y - Returns_Squared =====
## 
## --- AR ---
## Ljung-Box (autocorrelación):
##    lb_stat    lb_pvalue
## 218.246346 2.488451e-41
## Prueba ARCH (heterocedasticidad):
## LM stat: 239.7949, p-value: 0.0000
## -> Hay heterocedasticidad. Se recomienda modelo GARCH.
## 
## --- MA ---
## Ljung-Box (autocorrelación):
##    lb_stat    lb_pvalue
## 394.542419 1.364886e-78
## Prueba ARCH (heterocedasticidad):
## LM stat: 159.6763, p-value: 0.0000
## -> Hay heterocedasticidad. Se recomienda modelo GARCH.
## 
## --- ARMA ---
## Ljung-Box (autocorrelación):
##    lb_stat    lb_pvalue
## 222.086568 3.908918e-42
## Prueba ARCH (heterocedasticidad):
## LM stat: 242.5650, p-value: 0.0000
## -> Hay heterocedasticidad. Se recomienda modelo GARCH.
## 
## 
## ===== EUR/USD - Returns =====
## 
## --- AR ---
## Ljung-Box (autocorrelación):
##   lb_stat  lb_pvalue
## 12.163631   0.274255
## Prueba ARCH (heterocedasticidad):
## LM stat: 98.7482, p-value: 0.0000
## -> Hay heterocedasticidad. Se recomienda modelo GARCH.
## 
## --- MA ---
## Ljung-Box (autocorrelación):
##   lb_stat  lb_pvalue
## 12.125127    0.27677
## Prueba ARCH (heterocedasticidad):
## LM stat: 98.5281, p-value: 0.0000
## -> Hay heterocedasticidad. Se recomienda modelo GARCH.
## 
## --- ARMA ---
## Ljung-Box (autocorrelación):
##   lb_stat  lb_pvalue
## 12.285373   0.266411
## Prueba ARCH (heterocedasticidad):
## LM stat: 98.7945, p-value: 0.0000
## -> Hay heterocedasticidad. Se recomienda modelo GARCH.
## 
## 
## ===== EUR/USD - Returns_Squared =====
## 
## --- AR ---
## Ljung-Box (autocorrelación):
##    lb_stat    lb_pvalue
## 125.209812 4.420215e-22
## Prueba ARCH (heterocedasticidad):
## LM stat: 12.3065, p-value: 0.2651
## -> No hay evidencia de heterocedasticidad.
## 
## --- MA ---
## Ljung-Box (autocorrelación):
##    lb_stat    lb_pvalue
## 138.098604 1.033271e-24
## Prueba ARCH (heterocedasticidad):
## LM stat: 12.4336, p-value: 0.2571
## -> No hay evidencia de heterocedasticidad.
## 
## --- ARMA ---
## Ljung-Box (autocorrelación):
##   lb_stat  lb_pvalue
## 14.449486   0.153458
## Prueba ARCH (heterocedasticidad):
## LM stat: 9.2778, p-value: 0.5060
## -> No hay evidencia de heterocedasticidad.
## 
## 
## ===== SPY ETF - Returns =====
## 
## --- AR ---
## Ljung-Box (autocorrelación):
##    lb_stat    lb_pvalue
## 118.144469 1.203584e-20
## Prueba ARCH (heterocedasticidad):
## LM stat: 530.0651, p-value: 0.0000
## -> Hay heterocedasticidad. Se recomienda modelo GARCH.
## 
## --- MA ---
## Ljung-Box (autocorrelación):
##    lb_stat    lb_pvalue
## 132.671167 1.330991e-23
## Prueba ARCH (heterocedasticidad):
## LM stat: 548.9277, p-value: 0.0000
## -> Hay heterocedasticidad. Se recomienda modelo GARCH.
## 
## --- ARMA ---
## Ljung-Box (autocorrelación):
##    lb_stat    lb_pvalue
## 101.114638 3.259796e-17
## Prueba ARCH (heterocedasticidad):
## LM stat: 500.1674, p-value: 0.0000
## -> Hay heterocedasticidad. Se recomienda modelo GARCH.
## 
## 
## ===== SPY ETF - Returns_Squared =====
## 
## --- AR ---
## Ljung-Box (autocorrelación):
##    lb_stat    lb_pvalue
## 440.227281 2.536092e-88
## Prueba ARCH (heterocedasticidad):
## LM stat: 492.5802, p-value: 0.0000
## -> Hay heterocedasticidad. Se recomienda modelo GARCH.
## 
## --- MA ---
## Ljung-Box (autocorrelación):
##     lb_stat     lb_pvalue
## 1100.550193 4.016363e-230
## Prueba ARCH (heterocedasticidad):
## LM stat: 502.8785, p-value: 0.0000
## -> Hay heterocedasticidad. Se recomienda modelo GARCH.
## 
## --- ARMA ---
## Ljung-Box (autocorrelación):
##    lb_stat    lb_pvalue
## 153.063677 8.725588e-28
## Prueba ARCH (heterocedasticidad):
## LM stat: 425.8700, p-value: 0.0000
## -> Hay heterocedasticidad. Se recomienda modelo GARCH.

Los resultados muestran que tanto Microsoft, Treasury 10Y y SPY presentan una fuerte autocorrelación en los residuales (Ljung-Box con p-values extremadamente bajos), lo que confirma que los modelos AR, MA y ARMA no logran capturar por completo la dinámica temporal de los retornos ni de sus cuadrados. Además, en todos estos activos la prueba ARCH arroja p-values de 0.0000, evidenciando heterocedasticidad significativa: la varianza cambia en el tiempo y se agrupa en períodos de alta y baja volatilidad. Esto implica que los modelos lineales no son suficientes y que la volatilidad presenta estructura propia, lo que justifica de manera contundente el uso de modelos GARCH para capturar shocks persistentes y clústeres de volatilidad.

En el caso de EUR/USD, aunque los retornos sí presentan heterocedasticidad (p-value 0.0000 en la prueba ARCH), los retornos al cuadrado no la muestran (p-values > 0.25). Esto indica que, aunque el ruido de corto plazo genera algo de variabilidad no constante, no se observa un patrón fuerte de clústeres de volatilidad como en los activos de renta variable o renta fija. Aun así, la autocorrelación significativa en los retornos al cuadrado sugiere persistencia en la volatilidad, pero menos intensa. En resumen, Microsoft, Treasury 10Y y SPY requieren claramente modelos GARCH para modelar adecuadamente la volatilidad, mientras que EUR/USD muestra una estructura más suave, donde un GARCH podría funcionar, pero no es tan obligatorio como en los otros activos.

from arch import arch_model
from statsmodels.stats.diagnostic import acorr_ljungbox, het_arch
import pandas as pd
import numpy as np

# Definir las series que necesitan GARCH
series_garch = {
    "Microsoft": ["Returns", "Returns_Squared"],
    "Treasury 10Y": ["Returns", "Returns_Squared"],
    "SPY ETF": ["Returns", "Returns_Squared"],
    "EUR/USD": ["Returns"]
}

# ================================
# Estimar un GARCH(1,1) por serie
# ================================
for activo, series in series_garch.items():
    for serie_nombre in series:
        print(f"\n===== {activo} - {serie_nombre} GARCH(1,1) =====\n")
        
        # Tomar la serie de rendimientos correspondiente
        serie_data = series_estacionarias[activo][serie_nombre]
        serie_pct = serie_data * 100  # Escalar a %
        
        # Estimación GARCH(1,1) con media AR(1)
        garch = arch_model(serie_pct, vol='Garch', p=1, q=1, mean='AR', lags=1, dist='normal')
        garch_res = garch.fit(update_freq=5, disp='off')
        print(garch_res.summary())
        
        # Residuos estandarizados
        resid_std = pd.Series(garch_res.resid / garch_res.conditional_volatility).replace([np.inf, -np.inf], np.nan).dropna()
        
        # Autocorrelación en residuos estandarizados
        lb_test_std = acorr_ljungbox(resid_std, lags=[10], return_df=True)
        print("\nLjung-Box sobre residuos estandarizados:")
        print(lb_test_std.to_string(index=False))
## 
## ===== Microsoft - Returns GARCH(1,1) =====
## 
##                            AR - GARCH Model Results                           
## ==============================================================================
## Dep. Variable:                Returns   R-squared:                       0.022
## Mean Model:                        AR   Adj. R-squared:                  0.022
## Vol Model:                      GARCH   Log-Likelihood:               -2847.53
## Distribution:                  Normal   AIC:                           5705.06
## Method:            Maximum Likelihood   BIC:                           5731.65
##                                         No. Observations:                 1508
## Date:                Tue, Nov 18 2025   Df Residuals:                     1506
## Time:                        13:40:26   Df Model:                            2
##                                  Mean Model                                
## ===========================================================================
##                  coef    std err          t      P>|t|     95.0% Conf. Int.
## ---------------------------------------------------------------------------
## Const          0.1483  3.951e-02      3.754  1.744e-04  [7.086e-02,  0.226]
## Returns[1]    -0.0832  2.932e-02     -2.837  4.550e-03 [ -0.141,-2.572e-02]
##                               Volatility Model                             
## ===========================================================================
##                  coef    std err          t      P>|t|     95.0% Conf. Int.
## ---------------------------------------------------------------------------
## omega          0.0847  5.159e-02      1.642      0.101 [-1.641e-02,  0.186]
## alpha[1]       0.0875  2.500e-02      3.501  4.639e-04  [3.852e-02,  0.137]
## beta[1]        0.8840  3.881e-02     22.774 8.226e-115    [  0.808,  0.960]
## ===========================================================================
## 
## Covariance estimator: robust
## 
## Ljung-Box sobre residuos estandarizados:
##  lb_stat  lb_pvalue
## 9.743989   0.463234
## 
## ===== Microsoft - Returns_Squared GARCH(1,1) =====
## 
## /cloud/project/r-reticulate/lib/python3.12/site-packages/arch/univariate/base.py:694: DataScaleWarning: y is poorly scaled, which may affect convergence of the optimizer when
## estimating the model parameters. The scale of y is 0.007484. Parameter
## estimation work better when this value is between 1 and 1000. The recommended
## rescaling is 10 * y.
## 
## This warning can be disabled by either rescaling y before initializing the
## model or by setting rescale=False.
## 
##   self._check_scale(resids)
##                            AR - GARCH Model Results                           
## ==============================================================================
## Dep. Variable:        Returns_Squared   R-squared:                       0.176
## Mean Model:                        AR   Adj. R-squared:                  0.176
## Vol Model:                      GARCH   Log-Likelihood:                2326.84
## Distribution:                  Normal   AIC:                          -4643.68
## Method:            Maximum Likelihood   BIC:                          -4617.09
##                                         No. Observations:                 1508
## Date:                Tue, Nov 18 2025   Df Residuals:                     1506
## Time:                        13:40:26   Df Model:                            2
##                                    Mean Model                                  
## ===============================================================================
##                     coef    std err          t      P>|t|      95.0% Conf. Int.
## -------------------------------------------------------------------------------
## Const             0.0161  1.514e-03     10.624  2.313e-26 [1.312e-02,1.906e-02]
## Retu...red[1]     0.2182  4.852e-02      4.498  6.859e-06     [  0.123,  0.313]
##                                Volatility Model                              
## =============================================================================
##                  coef    std err          t      P>|t|       95.0% Conf. Int.
## -----------------------------------------------------------------------------
## omega      1.6614e-04  1.431e-04      1.161      0.245 [-1.142e-04,4.465e-04]
## alpha[1]       0.0999  5.765e-02      1.733  8.312e-02   [-1.309e-02,  0.213]
## beta[1]        0.8791  7.007e-02     12.546  4.202e-36      [  0.742,  1.016]
## =============================================================================
## 
## Covariance estimator: robust
## 
## Ljung-Box sobre residuos estandarizados:
##   lb_stat  lb_pvalue
## 40.232667   0.000015
## 
## ===== Treasury 10Y - Returns GARCH(1,1) =====
## 
##                            AR - GARCH Model Results                           
## ==============================================================================
## Dep. Variable:                Returns   R-squared:                      -0.000
## Mean Model:                        AR   Adj. R-squared:                 -0.001
## Vol Model:                      GARCH   Log-Likelihood:               -3562.89
## Distribution:                  Normal   AIC:                           7135.79
## Method:            Maximum Likelihood   BIC:                           7162.38
##                                         No. Observations:                 1508
## Date:                Tue, Nov 18 2025   Df Residuals:                     1506
## Time:                        13:40:26   Df Model:                            2
##                                   Mean Model                                 
## =============================================================================
##                  coef    std err          t      P>|t|       95.0% Conf. Int.
## -----------------------------------------------------------------------------
## Const          0.0918  5.431e-02      1.690  9.094e-02   [-1.464e-02,  0.198]
## Returns[1]    -0.0285  2.954e-02     -0.963      0.335 [-8.636e-02,2.945e-02]
##                               Volatility Model                             
## ===========================================================================
##                  coef    std err          t      P>|t|     95.0% Conf. Int.
## ---------------------------------------------------------------------------
## omega          0.0590  3.601e-02      1.640      0.101 [-1.153e-02,  0.130]
## alpha[1]       0.0975  2.839e-02      3.435  5.931e-04  [4.186e-02,  0.153]
## beta[1]        0.9006  2.720e-02     33.113 1.926e-240    [  0.847,  0.954]
## ===========================================================================
## 
## Covariance estimator: robust
## 
## Ljung-Box sobre residuos estandarizados:
##  lb_stat  lb_pvalue
## 7.755656    0.65269
## 
## ===== Treasury 10Y - Returns_Squared GARCH(1,1) =====
## 
##                            AR - GARCH Model Results                           
## ==============================================================================
## Dep. Variable:        Returns_Squared   R-squared:                       0.010
## Mean Model:                        AR   Adj. R-squared:                  0.009
## Vol Model:                      GARCH   Log-Likelihood:                596.140
## Distribution:                  Normal   AIC:                          -1182.28
## Method:            Maximum Likelihood   BIC:                          -1155.69
##                                         No. Observations:                 1508
## Date:                Tue, Nov 18 2025   Df Residuals:                     1506
## Time:                        13:40:26   Df Model:                            2
##                                    Mean Model                                  
## ===============================================================================
##                     coef    std err          t      P>|t|      95.0% Conf. Int.
## -------------------------------------------------------------------------------
## Const             0.0381  1.224e-02      3.111  1.863e-03 [1.409e-02,6.205e-02]
## Retu...red[1]     0.0254      0.447  5.679e-02      0.955     [ -0.851,  0.902]
##                               Volatility Model                              
## ============================================================================
##                  coef    std err          t      P>|t|      95.0% Conf. Int.
## ----------------------------------------------------------------------------
## omega      5.5159e-03  1.043e-03      5.287  1.246e-07 [3.471e-03,7.561e-03]
## alpha[1]       0.3377  6.715e-02      5.030  4.918e-07     [  0.206,  0.469]
## beta[1]        0.6528  3.854e-02     16.937  2.421e-64     [  0.577,  0.728]
## ============================================================================
## 
## Covariance estimator: robust
## 
## Ljung-Box sobre residuos estandarizados:
##   lb_stat    lb_pvalue
## 136.10433 2.644692e-24
## 
## ===== SPY ETF - Returns GARCH(1,1) =====
## 
##                            AR - GARCH Model Results                           
## ==============================================================================
## Dep. Variable:                Returns   R-squared:                       0.009
## Mean Model:                        AR   Adj. R-squared:                  0.008
## Vol Model:                      GARCH   Log-Likelihood:               -2096.35
## Distribution:                  Normal   AIC:                           4202.70
## Method:            Maximum Likelihood   BIC:                           4229.29
##                                         No. Observations:                 1508
## Date:                Tue, Nov 18 2025   Df Residuals:                     1506
## Time:                        13:40:26   Df Model:                            2
##                                   Mean Model                                 
## =============================================================================
##                  coef    std err          t      P>|t|       95.0% Conf. Int.
## -----------------------------------------------------------------------------
## Const          0.1119  2.202e-02      5.084  3.695e-07    [6.878e-02,  0.155]
## Returns[1]    -0.0356  2.918e-02     -1.219      0.223 [-9.277e-02,2.162e-02]
##                               Volatility Model                              
## ============================================================================
##                  coef    std err          t      P>|t|      95.0% Conf. Int.
## ----------------------------------------------------------------------------
## omega          0.0473  1.379e-02      3.428  6.075e-04 [2.025e-02,7.431e-02]
## alpha[1]       0.1700  3.349e-02      5.077  3.827e-07     [  0.104,  0.236]
## beta[1]        0.7958  3.295e-02     24.149 7.612e-129     [  0.731,  0.860]
## ============================================================================
## 
## Covariance estimator: robust
## 
## Ljung-Box sobre residuos estandarizados:
##   lb_stat  lb_pvalue
## 13.021223   0.222488
## 
## ===== SPY ETF - Returns_Squared GARCH(1,1) =====
## 
## /cloud/project/r-reticulate/lib/python3.12/site-packages/arch/univariate/base.py:694: DataScaleWarning: y is poorly scaled, which may affect convergence of the optimizer when
## estimating the model parameters. The scale of y is 0.002639. Parameter
## estimation work better when this value is between 1 and 1000. The recommended
## rescaling is 10 * y.
## 
## This warning can be disabled by either rescaling y before initializing the
## model or by setting rescale=False.
## 
##   self._check_scale(resids)
##                            AR - GARCH Model Results                           
## ==============================================================================
## Dep. Variable:        Returns_Squared   R-squared:                       0.080
## Mean Model:                        AR   Adj. R-squared:                  0.079
## Vol Model:                      GARCH   Log-Likelihood:                3759.69
## Distribution:                  Normal   AIC:                          -7509.39
## Method:            Maximum Likelihood   BIC:                          -7482.79
##                                         No. Observations:                 1508
## Date:                Tue, Nov 18 2025   Df Residuals:                     1506
## Time:                        13:40:26   Df Model:                            2
##                                    Mean Model                                  
## ===============================================================================
##                     coef    std err          t      P>|t|      95.0% Conf. Int.
## -------------------------------------------------------------------------------
## Const         5.6242e-03  7.155e-04      7.860  3.829e-15 [4.222e-03,7.027e-03]
## Retu...red[1]     0.1163  7.263e-02      1.602      0.109  [-2.603e-02,  0.259]
##                               Volatility Model                              
## ============================================================================
##                  coef    std err          t      P>|t|      95.0% Conf. Int.
## ----------------------------------------------------------------------------
## omega      5.2780e-05  1.660e-05      3.179  1.477e-03 [2.024e-05,8.532e-05]
## alpha[1]       0.2002  6.236e-02      3.211  1.324e-03   [7.799e-02,  0.322]
## beta[1]        0.7798  4.118e-02     18.936  5.746e-80     [  0.699,  0.861]
## ============================================================================
## 
## Covariance estimator: robust
## 
## Ljung-Box sobre residuos estandarizados:
##    lb_stat    lb_pvalue
## 109.115885 8.043112e-19
## 
## ===== EUR/USD - Returns GARCH(1,1) =====
## 
##                            AR - GARCH Model Results                           
## ==============================================================================
## Dep. Variable:                Returns   R-squared:                      -0.000
## Mean Model:                        AR   Adj. R-squared:                 -0.001
## Vol Model:                      GARCH   Log-Likelihood:               -869.897
## Distribution:                  Normal   AIC:                           1749.79
## Method:            Maximum Likelihood   BIC:                           1776.57
##                                         No. Observations:                 1563
## Date:                Tue, Nov 18 2025   Df Residuals:                     1561
## Time:                        13:40:26   Df Model:                            2
##                                   Mean Model                                  
## ==============================================================================
##                   coef    std err          t      P>|t|       95.0% Conf. Int.
## ------------------------------------------------------------------------------
## Const      -8.3633e-03  1.005e-02     -0.832      0.405 [-2.806e-02,1.133e-02]
## Returns[1] -7.0496e-03  2.613e-02     -0.270      0.787 [-5.827e-02,4.417e-02]
##                                Volatility Model                              
## =============================================================================
##                  coef    std err          t      P>|t|       95.0% Conf. Int.
## -----------------------------------------------------------------------------
## omega      2.9003e-03  1.637e-03      1.771  7.650e-02 [-3.088e-04,6.109e-03]
## alpha[1]       0.0454  1.475e-02      3.078  2.087e-03  [1.648e-02,7.430e-02]
## beta[1]        0.9396  2.022e-02     46.466      0.000      [  0.900,  0.979]
## =============================================================================
## 
## Covariance estimator: robust
## 
## Ljung-Box sobre residuos estandarizados:
##  lb_stat  lb_pvalue
## 5.611423   0.846785
        
        # Heterocedasticidad en residuos estandarizados
arch_test_std = het_arch(resid_std)
print(f"\nPrueba ARCH sobre residuos estandarizados: LM stat={arch_test_std[0]:.4f}, p-value={arch_test_std[1]:.4f}\n")
## 
## Prueba ARCH sobre residuos estandarizados: LM stat=4.9238, p-value=0.8962

Estimacion del modelo Garch

Los modelos GARCH(1,1) estimados para Microsoft, Treasury 10Y y el ETF SPY muestran una estructura de volatilidad altamente persistente, reflejada en valores de α + β cercanos a 1, lo que indica que los choques de volatilidad tienen efectos duraderos y generan clústeres de volatilidad típicos de activos financieros líquidos. En todos ellos, el parámetro beta domina claramente, lo que significa que la volatilidad depende fuertemente de su propio pasado, mientras que alpha refleja shocks de corto plazo igualmente significativos. Aunque las medias AR no son especialmente relevantes (coeficientes pequeños o poco significativos), las ecuaciones de varianza son sólidas, y los residuos estandarizados —salvo en los modelos aplicados a retornos al cuadrado— pasan las pruebas de Ljung-Box, mostrando que el GARCH captura bien la dinámica del ruido. Los casos de “poor scaling” simplemente indican que los retornos son muy pequeños y deben ser reescalados para mejorar la convergencia, pero no afectan la interpretación financiera.

En cuanto a EUR/USD, el GARCH también detecta persistencia en la volatilidad (β muy alto), pero con un α considerablemente más bajo que en activos de renta variable, lo cual confirma que el mercado cambiario presenta una volatilidad más estable y menos reactiva a shocks inmediatos. El parámetro omega pequeño y marginalmente significativo indica niveles de varianza base muy reducidos, algo típico en series cambiarias de alta liquidez. En conjunto, los resultados confirman que los modelos GARCH son adecuados para los cuatro activos, aunque su necesidad es más fuerte en acciones y ETF, intermedia en renta fija y más suave en divisas, donde la volatilidad es estable pero persistente.

from arch import arch_model

# Diccionario para guardar resultados
mejores_modelos = {}

# Recorrer las series que necesitan GARCH
for activo, series in series_garch.items():
    mejores_modelos[activo] = {}
    
    for serie_nombre in series:
        print(f"\n===== {activo} - {serie_nombre} =====\n")
        
        serie_data = series_estacionarias[activo][serie_nombre]
        serie_pct = serie_data * 100  # Escalar a %
        
        # Lista de tipos de medias a comparar (AR(0)=media constante, AR(1)=media AR(1))
        medias = ['Constant', 'AR']
        modelos_garch = {}
        
        for media in medias:
            garch = arch_model(serie_pct, vol='Garch', p=1, q=1, mean=media, lags=1, dist='normal')
            res = garch.fit(update_freq=5, disp='off')
            modelos_garch[media] = res
            print(f"{media} → AIC: {res.aic:.4f}")
        
        # Seleccionar el modelo con menor AIC
        mejor_media = min(modelos_garch, key=lambda x: modelos_garch[x].aic)
        mejor_modelo = modelos_garch[mejor_media]
        mejores_modelos[activo][serie_nombre] = mejor_modelo
        
        print(f"\nMejor modelo para {activo} - {serie_nombre}: {mejor_media} con AIC={mejor_modelo.aic:.4f}")
## 
## ===== Microsoft - Returns =====
## 
## Constant → AIC: 5718.2571
## AR → AIC: 5705.0591
## 
## Mejor modelo para Microsoft - Returns: AR con AIC=5705.0591
## 
## ===== Microsoft - Returns_Squared =====
## 
## /cloud/project/r-reticulate/lib/python3.12/site-packages/arch/univariate/base.py:694: DataScaleWarning: y is poorly scaled, which may affect convergence of the optimizer when
## estimating the model parameters. The scale of y is 0.01049. Parameter
## estimation work better when this value is between 1 and 1000. The recommended
## rescaling is 10 * y.
## 
## This warning can be disabled by either rescaling y before initializing the
## model or by setting rescale=False.
## 
##   self._check_scale(resids)
## Constant → AIC: -4656.2908
## /cloud/project/r-reticulate/lib/python3.12/site-packages/arch/univariate/base.py:694: DataScaleWarning: y is poorly scaled, which may affect convergence of the optimizer when
## estimating the model parameters. The scale of y is 0.007484. Parameter
## estimation work better when this value is between 1 and 1000. The recommended
## rescaling is 10 * y.
## 
## This warning can be disabled by either rescaling y before initializing the
## model or by setting rescale=False.
## 
##   self._check_scale(resids)
## AR → AIC: -4643.6838
## 
## Mejor modelo para Microsoft - Returns_Squared: Constant con AIC=-4656.2908
## 
## ===== Treasury 10Y - Returns =====
## 
## Constant → AIC: 7143.9313
## AR → AIC: 7135.7859
## 
## Mejor modelo para Treasury 10Y - Returns: AR con AIC=7135.7859
## 
## ===== Treasury 10Y - Returns_Squared =====
## 
## Constant → AIC: -1453.7348
## AR → AIC: -1182.2805
## 
## Mejor modelo para Treasury 10Y - Returns_Squared: Constant con AIC=-1453.7348
## 
## ===== SPY ETF - Returns =====
## 
## Constant → AIC: 4205.9694
## AR → AIC: 4202.6971
## 
## Mejor modelo para SPY ETF - Returns: AR con AIC=4202.6971
## 
## ===== SPY ETF - Returns_Squared =====
## 
## /cloud/project/r-reticulate/lib/python3.12/site-packages/arch/univariate/base.py:694: DataScaleWarning: y is poorly scaled, which may affect convergence of the optimizer when
## estimating the model parameters. The scale of y is 0.003451. Parameter
## estimation work better when this value is between 1 and 1000. The recommended
## rescaling is 10 * y.
## 
## This warning can be disabled by either rescaling y before initializing the
## model or by setting rescale=False.
## 
##   self._check_scale(resids)
## <string>:18: ConvergenceWarning: The optimizer returned code 8. The message is:
## Positive directional derivative for linesearch
## See scipy.optimize.fmin_slsqp for code meaning.
## 
## Constant → AIC: -7528.5799
## /cloud/project/r-reticulate/lib/python3.12/site-packages/arch/univariate/base.py:694: DataScaleWarning: y is poorly scaled, which may affect convergence of the optimizer when
## estimating the model parameters. The scale of y is 0.002639. Parameter
## estimation work better when this value is between 1 and 1000. The recommended
## rescaling is 10 * y.
## 
## This warning can be disabled by either rescaling y before initializing the
## model or by setting rescale=False.
## 
##   self._check_scale(resids)
## AR → AIC: -7509.3869
## 
## Mejor modelo para SPY ETF - Returns_Squared: Constant con AIC=-7528.5799
## 
## ===== EUR/USD - Returns =====
## 
## Constant → AIC: 1748.6104
## AR → AIC: 1749.7944
## 
## Mejor modelo para EUR/USD - Returns: Constant con AIC=1748.6104

La comparación de AIC muestra qué estructura se ajusta mejor a cada serie, revelando patrones claros entre activos. Para Microsoft, Treasury 10Y y SPY, el modelo AR presenta el AIC más bajo en los rendimientos, indicando que existe una ligera autocorrelación y que un término autorregresivo mejora la explicación frente a un modelo constante. En cambio, para EUR/USD el mejor modelo es simplemente una constante, lo que confirma que sus retornos no muestran dependencia temporal y siguen un comportamiento cercano a una caminata aleatoria.

En las series de rendimientos al cuadrado —que reflejan la dinámica de la volatilidad— se observa que en Microsoft y Treasury 10Y el modelo constante es el más adecuado, lo que sugiere que la estructura AR no aporta valor en capturar la varianza, mientras que en SPY sí aparece un mejor ajuste con AR. En conjunto, el AIC permite concluir que los rendimientos tienen muy poca memoria, pero las diferencias entre activos marcan qué tan útil es introducir componentes AR antes de modelar la volatilidad con GARCH.

from statsmodels.stats.diagnostic import acorr_ljungbox, het_arch
from statsmodels.graphics.tsaplots import plot_acf
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np

for activo, series in mejores_modelos.items():
    for serie_nombre, modelo in series.items():
        print(f"\n===== {activo} - {serie_nombre} (Mejor GARCH) =====\n")
        
        # Residuos estandarizados
        resid_std = pd.Series(modelo.resid / modelo.conditional_volatility).replace([np.inf, -np.inf], np.nan).dropna()
        
        #  Heterocedasticidad en residuos estandarizados
        arch_test_std = het_arch(resid_std)
        print(f"Prueba ARCH sobre residuos estandarizados: LM stat={arch_test_std[0]:.4f}, p-value={arch_test_std[1]:.4f}")
        if arch_test_std[1] < 0.05:
            print("-> Persiste heterocedasticidad")
        else:
            print("-> No hay evidencia de heterocedasticidad")
        
        #  Autocorrelación en residuos estandarizados
        lb_test_std = acorr_ljungbox(resid_std, lags=[10], return_df=True)
        print("\nLjung-Box sobre residuos estandarizados:")
        print(lb_test_std.to_string(index=False))
        
        # Graficar correlograma (opcional)
        plot_acf(resid_std, lags=20)
        plt.title(f"{activo} - {serie_nombre} ACF residuos estandarizados")
        plt.show()

import numpy as np
import pandas as pd
from scipy.stats import norm

# Nivel de confianza para VaR
confianza = 0.95
z = norm.ppf(1 - confianza)  # Cuantil negativo para pérdidas

volatilidad_var = {}
VaR = {}

for activo, series in mejores_modelos.items():
    volatilidad_var[activo] = {}
    VaR[activo] = {}
    
    for serie_nombre, modelo in series.items():
        print(f"\n===== {activo} - {serie_nombre} =====\n")
        
        # 1️⃣ Volatilidad condicional estimada por el GARCH
        sigma_t = modelo.conditional_volatility / 100  # Volatilidad en unidades de la serie original
        volatilidad_var[activo][serie_nombre] = sigma_t
        print("Volatilidad condicional (últimos 5 valores):")
        print(sigma_t.tail())
        
        # 2️⃣ Calcular VaR usando volatilidad condicional
        # VaR = - z * sigma_t
        var_t = - z * sigma_t
        VaR[activo][serie_nombre] = var_t
        print(f"\nVaR (nivel {int(confianza*100)}%) últimos 5 valores:")
        print(var_t.tail())
## 
## ===== Microsoft - Returns =====
## 
## Volatilidad condicional (últimos 5 valores):
## Date
## 2024-12-24    0.014319
## 2024-12-26    0.013958
## 2024-12-27    0.013481
## 2024-12-30    0.014169
## 2024-12-31    0.014450
## Name: cond_vol, dtype: float64
## 
## VaR (nivel 95%) últimos 5 valores:
## Date
## 2024-12-24    0.023553
## 2024-12-26    0.022958
## 2024-12-27    0.022174
## 2024-12-30    0.023306
## 2024-12-31    0.023768
## Name: cond_vol, dtype: float64
## 
## ===== Microsoft - Returns_Squared =====
## 
## Volatilidad condicional (últimos 5 valores):
## Date
## 2024-12-24    0.000487
## 2024-12-26    0.000472
## 2024-12-27    0.000460
## 2024-12-30    0.000447
## 2024-12-31    0.000434
## Name: cond_vol, dtype: float64
## 
## VaR (nivel 95%) últimos 5 valores:
## Date
## 2024-12-24    0.000801
## 2024-12-26    0.000776
## 2024-12-27    0.000757
## 2024-12-30    0.000735
## 2024-12-31    0.000713
## Name: cond_vol, dtype: float64
## 
## ===== Treasury 10Y - Returns =====
## 
## Volatilidad condicional (últimos 5 valores):
## Date
## 2024-12-24    0.015229
## 2024-12-26    0.014671
## 2024-12-27    0.014177
## 2024-12-30    0.013883
## 2024-12-31    0.014375
## Name: cond_vol, dtype: float64
## 
## VaR (nivel 95%) últimos 5 valores:
## Date
## 2024-12-24    0.025050
## 2024-12-26    0.024132
## 2024-12-27    0.023319
## 2024-12-30    0.022836
## 2024-12-31    0.023645
## Name: cond_vol, dtype: float64
## 
## ===== Treasury 10Y - Returns_Squared =====
## 
## Volatilidad condicional (últimos 5 valores):
## Date
## 2024-12-24    0.000982
## 2024-12-26    0.000994
## 2024-12-27    0.001002
## 2024-12-30    0.001001
## 2024-12-31    0.000990
## Name: cond_vol, dtype: float64
## 
## VaR (nivel 95%) últimos 5 valores:
## Date
## 2024-12-24    0.001616
## 2024-12-26    0.001635
## 2024-12-27    0.001648
## 2024-12-30    0.001647
## 2024-12-31    0.001629
## Name: cond_vol, dtype: float64
## 
## ===== SPY ETF - Returns =====
## 
## Volatilidad condicional (últimos 5 valores):
## Date
## 2024-12-24    0.011578
## 2024-12-26    0.011364
## 2024-12-27    0.010371
## 2024-12-30    0.010648
## 2024-12-31    0.011103
## Name: cond_vol, dtype: float64
## 
## VaR (nivel 95%) últimos 5 valores:
## Date
## 2024-12-24    0.019044
## 2024-12-26    0.018691
## 2024-12-27    0.017059
## 2024-12-30    0.017515
## 2024-12-31    0.018263
## Name: cond_vol, dtype: float64
## 
## ===== SPY ETF - Returns_Squared =====
## 
## Volatilidad condicional (últimos 5 valores):
## Date
## 2024-12-24    0.000309
## 2024-12-26    0.000268
## 2024-12-27    0.000237
## 2024-12-30    0.000213
## 2024-12-31    0.000198
## Name: cond_vol, dtype: float64
## 
## VaR (nivel 95%) últimos 5 valores:
## Date
## 2024-12-24    0.000508
## 2024-12-26    0.000441
## 2024-12-27    0.000390
## 2024-12-30    0.000351
## 2024-12-31    0.000326
## Name: cond_vol, dtype: float64
## 
## ===== EUR/USD - Returns =====
## 
## Volatilidad condicional (últimos 5 valores):
## Date
## 2024-12-25    0.004802
## 2024-12-26    0.004688
## 2024-12-27    0.004578
## 2024-12-30    0.004500
## 2024-12-31    0.004399
## Name: cond_vol, dtype: float64
## 
## VaR (nivel 95%) últimos 5 valores:
## Date
## 2024-12-25    0.007899
## 2024-12-26    0.007712
## 2024-12-27    0.007531
## 2024-12-30    0.007402
## 2024-12-31    0.007236
## Name: cond_vol, dtype: float64

Los resultados muestran que, en todos los activos, la volatilidad condicional estimada por los modelos GARCH tiende a disminuir suavemente hacia final de año, lo que indica un entorno más estable y con menor incertidumbre en las últimas jornadas analizadas. En Microsoft y SPY, esta caída de la volatilidad es clara tanto en los retornos como en los retornos al cuadrado, lo que sugiere una reducción consistente del riesgo. En Treasury 10Y ocurre algo similar, aunque con niveles de volatilidad algo más altos, propios del comportamiento más sensible de los bonos a noticias macroeconómicas. Para EUR/USD la volatilidad es la más baja entre todos los activos, y su descenso progresivo confirma un mercado cambiario calmado y sin shocks recientes.

El VaR al 95%, que depende directamente de la volatilidad condicional, también muestra una trayectoria descendente en todos los activos, indicando que el riesgo de pérdidas extremas es menor hacia los últimos días del periodo. Los niveles absolutos reflejan las diferencias estructurales entre mercados: los activos de renta variable (Microsoft y SPY) presentan los VaR más altos, coherentes con su mayor riesgo; los bonos y el tipo de cambio mantienen valores más moderados. En conjunto, los resultados confirman que las dinámicas GARCH capturan adecuadamente la persistencia de la volatilidad y evidencian una contracción del riesgo en todos los activos al cierre del año.

# Parámetros RiskMetrics
lambda_rm = 0.94
confianza = 0.95
z = norm.ppf(1 - confianza)

VaR_RM = {}

for activo, series in series_estacionarias.items():
    VaR_RM[activo] = {}
    
    for serie_nombre, serie_data in series.items():
        print(f"\n===== {activo} - {serie_nombre} RiskMetrics =====\n")
        
        r = serie_data.values
        sigma_rm = np.zeros_like(r)
        
        # Inicialización con varianza histórica inicial
        sigma_rm[0] = np.std(r)
        
        # EWMA
        for t in range(1, len(r)):
            sigma_rm[t] = np.sqrt(lambda_rm * sigma_rm[t-1]**2 + (1-lambda_rm) * r[t-1]**2)
        
        VaR_RM[activo][serie_nombre] = - z * sigma_rm
        print(f"VaR RiskMetrics últimos 5 valores:")
        print(VaR_RM[activo][serie_nombre][-5:])
## 
## ===== Microsoft - Returns RiskMetrics =====
## 
## VaR RiskMetrics últimos 5 valores:
## [0.02153619 0.02121893 0.02060292 0.02115668 0.02119441]
## 
## ===== Microsoft - Returns_Squared RiskMetrics =====
## 
## VaR RiskMetrics últimos 5 valores:
## [0.0007529  0.00073082 0.00070856 0.00069748 0.00067991]
## 
## ===== Treasury 10Y - Returns RiskMetrics =====
## 
## VaR RiskMetrics últimos 5 valores:
## [0.0218549  0.02120069 0.0205818  0.0202628  0.02067877]
## 
## ===== Treasury 10Y - Returns_Squared RiskMetrics =====
## 
## VaR RiskMetrics últimos 5 valores:
## [0.00047734 0.0004628  0.00044871 0.00043613 0.0004353 ]
## 
## ===== EUR/USD - Returns RiskMetrics =====
## 
## VaR RiskMetrics últimos 5 valores:
## [0.00813699 0.00789011 0.00765064 0.00747385 0.00725013]
## 
## ===== EUR/USD - Returns_Squared RiskMetrics =====
## 
## VaR RiskMetrics últimos 5 valores:
## [9.15394306e-05 8.87507794e-05 8.60470799e-05 8.34516679e-05
##  8.09095192e-05]
## 
## ===== SPY ETF - Returns RiskMetrics =====
## 
## VaR RiskMetrics últimos 5 valores:
## [0.01477444 0.01500807 0.01455089 0.01473135 0.01500438]
## 
## ===== SPY ETF - Returns_Squared RiskMetrics =====
## 
## VaR RiskMetrics últimos 5 valores:
## [0.00035358 0.0003464  0.00033585 0.00032866 0.00032294]

Los resultados muestran que el VaR obtenido mediante RiskMetrics es sistemáticamente menor que el VaR estimado por modelos GARCH en todos los activos y para todas las series (returns y returns squared). Esto ocurre porque RiskMetrics utiliza un esquema de volatilidad suavizada con decaimiento exponencial (λ=0.94), lo que produce una volatilidad más estable y menos reactiva a shocks recientes. En contraste, los modelos GARCH capturan de manera más sensible los periodos de clustering de volatilidad, haciendo que su VaR sea ligeramente más alto cuando el mercado viene de episodios de mayor variabilidad.

En activos como Microsoft, SPY y Treasury 10Y, la diferencia es consistente pero moderada: el VaR GARCH se ubica siempre por encima del VaR RiskMetrics, reflejando que GARCH incorpora mejor la persistencia del riesgo. En EUR/USD, donde la volatilidad es más baja y estable, ambos métodos generan valores cercanos, aunque RiskMetrics sigue siendo algo más conservador en la suavización. En general, GARCH reacciona más a la historia reciente de shocks, mientras que RiskMetrics produce un VaR más estable y ligeramente inferior, lo que confirma que GARCH es más adecuado para mercados con clustering de volatilidad y RiskMetrics para entornos más tranquilos o cuando se busca simplicidad en el cálculo.