Pipeline de modelización y pricing sobre electricidad
A continuación resumo el workflow completo que has pedido, apoyándome exclusivamente en tu Excel y en los resultados numéricos obtenidos. Luego enlazo los outputs (HTML/Excel/CSV) generados para que puedas inspeccionarlos en detalle.
1. Revisión del dataset y validaciones
Estructura del Excel (file-YcVBFFScartreGC8LfW8H8.xlsx):
- Prices: 1411 observaciones de precios spot diarios.
- PriceDates: 1411 fechas (serial Excel/MATLAB), alineadas 1:1 con
Prices. - FutPrices: 24 precios de futuros mensuales.
- FutExpiry: 24 fechas de vencimiento mensuales, alineadas con
FutPrices. - FutValuationDate: hoja sin filas, pero la cabecera de columna es un serial Excel; se ha interpretado esa cabecera como única fecha de valoración de los futuros, convertida a
datetime.
Conversión de fechas
Se han tratado todos los seriales como Excel/MATLAB y convertido a datetime usando origen '1899-12-30', con corrección automática si los números eran tipo datenum MATLAB muy grandes.
Checks básicos sobre spot:
De la tabla data_validation_summary:
- Número de precios: 1411
- Rango temporal: 2010-01-01 a 2013-11-11
- Frecuencia: diaria (
is_daily = True) - Duplicados de fecha: 0
- Valores originales no positivos: 0
- NaN en el crudo: 0 (si hubiera no positivos se habrían interpolado linealmente; no ha sido necesario en este dataset.)
Conclusión: La serie spot es limpia, diaria y sin huecos significativos, adecuada para modelizar OU con saltos y calibrar estacionalidad.
2. Análisis exploratorio del spot
Sobre spot_series y log_prices se han calculado:
-
Retornos logarítmicos diarios:
- Media:
spot_logreturn_mean ≈ -0.00024 - Volatilidad:
spot_logreturn_vol ≈ 0.269 - Skewness:
≈ 0.462(asimetría positiva moderada) - Kurtosis (Fisher):
≈ 1.03(colas algo más pesadas que la normal)
- Media:
-
Log-precios:
- Media:
spot_logprice_mean ≈ 3.72 - Volatilidad:
spot_logprice_vol ≈ 0.299 - Skewness:
≈ 0.591 - Kurtosis:
≈ 1.29
- Media:
-
Drawdowns y spikes:
- Máx. drawdown (sobre el nivel de precio):
spot_max_drawdown ≈ 0.906(caída máxima del 90.6% vs máximo previo). - Frecuencia empírica de “saltos” (|retorno| > 3·σ):
spot_jump_frequency ≈ 0.0071(≈0.7% de los días). - Magnitud media absoluta de estos spikes en log-retornos:
spot_avg_spike_magnitude ≈ 0.981.
- Máx. drawdown (sobre el nivel de precio):
Gráficos exploratorios (Plotly HTML):
-
Serie de precios spot
-
Log-precios
-
Histograma de precios
-
Histograma de retornos log
-
Rolling mean / vol 30 días
-
Spikes en retornos
3. Estacionalidad sobre log-precios
Se ha ajustado el modelo:
-
Sea t el tiempo en años desde la primera fecha.
-
Matriz de regresores:
[sin(2πt),cos(2πt),sin(4πt),cos(4πt),t,1]
-
Modelo:
logPt=season(t)+Xt con season(t) ajustado por MCO.
Resultados clave:
- R2 del ajuste estacional:
seasonality_R2 ≈ 0.223, es decir 22.3% de la varianza de los log-precios se explica por estacionalidad anual + tendencia. - Los coeficientes de la estacionalidad están en la tabla
SeasonalityBetas(hoja de Excel de salida).
Gráficos:
-
Log-precios vs componente estacional ajustado
-
Serie desestacionalizada Xt
4. Proceso estocástico OU con saltos y MLE
Se ha asumido que la parte estocástica Xt sigue un AR(1) con mezcla gaussiana (equivalente discreto del OU con saltos):
-
Discreto:
Xt=a+ϕXt−1+εt
-
εt es mezcla:
- Normal (0,σ2) con prob. 1−λdt
- Normal (μJ,σ2+σJ2) con prob. λdt
A partir de los parámetros discretos se obtienen los continuos:
- α=a/dt
- κ=(1−ϕ)/dt
- σ=σ2/dt
- λ=λdt/dt
- σJ=σJ2
Parámetros calibrados (medida real P):
De mle_params y metrics:
- a (discreto):
a_discrete ≈ -0.0551 - ϕ (discreto):
phi_discrete ≈ 0.4842 - μJ:
≈ 0.2044 - σ2:
≈ 0.0262 - σJ2:
≈ 0.0707 - λdt (diaria):
≈ 0.2694
Continuos:
- α≈−20.11
- κ≈188.25 por año
- σ≈3.09
- σJ≈0.266
- λ (anual):
lambda_annual ≈ 98.34
Interpretación:
- Reversión muy rápida: κ≈188 implica una vida media del orden de días (propio de electricidad muy mean-reverting tras desestacionalizar).
- Volatilidad difusiva elevada en log-precios desestacionalizados.
- Intensidad de saltos anual alta (≈100 eventos/año
si se interpreta literalmente), pero hay que leerla con cautela porque
el filtro de saltos y la especificación de mezcla influyen. A nivel de
retornos empíricos, sólo ~0.7% de días se marcan como “saltos grandes”
(métrica
spot_jump_frequency); el modelo está usando λ también para absorber colas gruesas y clustering.
Calidad de ajuste MLE:
- Log-verosimilitud máxima:
loglik ≈ 133.28 - AIC:
≈ -254.55 - BIC:
≈ -223.04
Residuos AR(1) con saltos:
-
Serie de residuos
-
QQ-plot de residuos sin saltos grandes
-
ACF de residuos
-
Indicador de saltos en residuos
5. Simulación Monte Carlo bajo P
Configuración:
- Horizonte:
nPeriods = 365*2 + 20días (algo más de 2 años). - Trayectorias:
nTrials = 10000. - Semilla fija.
Evolución de Xt bajo P: Xt=αdt+(1−κdt)Xt−1+σdtZt+Jumpt(μJ+σJZtJ) Luego se añade estacionalidad y se aplica exponencial para obtener precios: logSt=Xt+season(t),St=elogSt Outputs clave:
-
Paths simulados y fan chart (bajo P):
-
Distribución del precio al horizonte
-
Comparación cola histórica vs simulada
-
Ficheros numéricos:
- Paths completos P (
Xy precios): Download file - Resumen diario (medias y percentiles): Download file
- Paths completos P (
6. Futuros, prima de riesgo y calibración
Construcción de FutPricesDaily:
- Se parte de
FutPricesyFutExpiry, se identifican los meses de entrega y se asume:- Cada contrato es “monthly base load”.
- Para todos los días de su mes de entrega se asigna el mismo precio futuro.
- Se reindexa por el calendario de simulación desde
FutValuationDatey se aplica forward-fill.
Estimación de la prima de riesgo:
Se sigue un esquema lineal tipo OU:
-
Para cada día con futuro válido, se construye:
bt=−σe−κτtlog(Ft/StP) donde:
- Ft = futuro observado diario.
- StP = precio esperado bajo P promedio sobre trayectorias.
- τt = tiempo a la expiración del contrato.
-
Se plantea:
A⋅riskPremium=b con A como matriz triangular (acumulando efecto de la prima en el tiempo). Se resuelve en mínimos cuadrados con regularización ligera y reescalado de columnas.
Resultados:
-
Resumen de prima de riesgo (diaria):
- Media:
riskPremium_mean ≈ -0.333 - Desviación típica:
riskPremium_std ≈ 10.00
- Media:
-
Archivo con la serie diaria: Download file
-
Gráfico de prima de riesgo:
-
Calibración futuros vs esperados bajo P (por mes):
-
Tabla
futures_P_calibration(CSV): Download file
7. Simulación bajo Q y ajuste a futuros
Bajo la medida neutral al riesgo Q se ajusta el drift con la prima de riesgo: Xt=αdt+(1−κdt)Xt−1+σdtZt−σdtriskPremiumt+Jumpt(μJ+σJZtJ) Se reañade estacionalidad y se obtienen StQ.
Validación vs curva de futuros:
-
Se calcula para cada mes la media simulada bajo Q y se compara con el precio futuro:
- RMSE de ajuste a futuros:
futures_RMSE ≈ 8.42 - MAPE:
futures_MAPE ≈ 0.177(error relativo ~17.7%)
- RMSE de ajuste a futuros:
-
Tabla de calibración bajo Q (precio de futuros mercado vs modelo): Download file
-
Gráfico mercado vs modelo Q:
-
Paths Q:
-
Paths Q (datos): Download file
8. Pricing de la Bermudan call
Configuración:
- Settle =
FutValuationDate - Maturity ≈ Settle + 2 años
- OptSpec = call
- Strike = 60
- riskFreeRate = 1%
- Ejercicios Bermudanos:
- Alrededor de 1 año
- Alrededor de 2 años (maturity)
Se ha implementado Longstaff–Schwartz sobre paths Q:
- Regressión de valor de continuación sobre base polinómica en St en la primera fecha de ejercicio.
- Backward induction y descuento al origen.
Resultados:
- Precio Bermudan:
bermudan_price ≈ 0.290 - Error estándar:
≈ 0.023 - IC 95%:
[0.244, 0.335] - Probabilidad de ejercicio temprano (en la fecha de 1 año):
≈ 2.2% - Probabilidad de ejercicio en madurez (cuando no se ha ejercido antes y está in-the-money):
≈ 0.73% - European call (mismo strike y madurez):
european_price ≈ 0.060
Gráficos de opción:
-
Histograma de payoffs descontados Bermudana
-
Frontera de ejercicio en la primera fecha Bermudana
-
Convergencia con el número de trayectorias
-
Resultados numéricos de opciones (CSV): Download file
9. Sensibilidad y stress testing
Se ha realizado un análisis de sensibilidad perturbando ±20%:
- Parámetros: κ, σ, λ, μJ, σJ, strike, madurez y tipo libre de riesgo.
- Trayectorias reducidas para rapidez (
nTrials_sens = 2000).
Resultados:
-
Tabla de sensibilidad Bermudana (por escenario): Download file
-
Gráfico tipo tornado (impacto en el precio Bermudano):
Conclusión cualitativa:
- El precio Bermudano es sensible pero no explosivo a shocks razonables en kappa y sigma.
- El impacto de la intensidad y tamaño de saltos es relevante para la cola, pero la opción está relativamente fuera del dinero (strike 60) en gran parte del soporte, lo que limita el valor absoluto.
- Cambios en vencimiento y strike tienen efectos esperados (más tiempo y menor strike aumentan el valor).
10. Outputs consolidados
Se ha generado un Excel consolidado con todos los resultados clave:
- SeasonalityBetas
- MLEParams
- FuturesCalibrationQ
- RiskPremium
- OptionResults
- Sensitivity
Descarga:
11. Comentario crítico y limitaciones
- Estacionalidad: Un R2 del 22% es razonable; aún queda mucha variabilidad idiosincrática, normal en electricidad.
- OU con saltos:
- Captura bien la reversión rápida y picos, pero la intensidad anual λ es muy alta numéricamente: está absorbiendo tanto verdaderos spikes como colas gruesas/residuos de modelo. Podría refinarse con:
- Filtro de saltos más estructurado.
- Varias clases de saltos o componentes de volatilidad estocástica.
- Futuros y prima de riesgo:
- El RMSE ~8.4 y MAPE ~18% indican un ajuste aceptable pero no perfecto. Es coherente con:
- Especificación relativamente simple del risk premium.
- Horizonte largo de algunos contratos vs periodo historico corto.
- Bermudan call:
- El valor Bermudano (~0.29) frente al europeo (~0.06) muestra una prima de flexibilidad significativa, aunque las probabilidades de ejercicio son bajas.
- La convergencia y el error estándar son razonables para 10 000 trayectorias.
12. Próximos pasos sugeridos
- Refinar el componente de saltos:
- Considerar umbrales de detección alternativos y/o modelo con dos intensidades (picos extremos vs colas moderadas).
- Revisar especificación de la prima de riesgo:
- Usar directamente fórmulas cerradas de futuros OU con saltos si quieres una interpretación más estructural.
- Probar regularización más fuerte o paramétrica en la forma temporal de
riskPremium_t.
- Ampliar universo de derivados:
- Usar la misma maquinaria para valorar swaptions sobre promedios mensuales, spread options contra otros hubs, etc.
- Backtesting:
- Recalibrar en ventanas rolling y comparar pricing modelado vs precios de mercado históricos de opciones (si los tienes).
Si quieres, en el siguiente paso puedo:
- Profundizar en la derivación teórica de la fórmula de futuros bajo OU con saltos y cómo se relaciona exactamente con la construcción de b y A que hemos usado.
- O ajustar el workflow para un estructura multi-factor (por ejemplo, corto y largo plazo más componente de spikes).

