La distribución logística es ampliamente utilizada en modelado financiero, especialmente para modelar retornos de activos. En este análisis, exploraremos cómo la distribución logística se ajusta a los retornos del S&P 500, comparándola con la distribución normal.
La distribución logística está definida por la siguiente función de densidad de probabilidad (PDF):
\[ f(x | \mu, s) = \frac{e^{-\frac{x - \mu}{s}}}{s(1+e^{-\frac{x - \mu}{s}})^2}, \quad -\infty < x < \infty. \]
Donde: - \(\mu\) es el parámetro de ubicación, que define la media de la distribución. - \(s\) es el parámetro de escala, que determina la dispersión de los datos.
La función de distribución acumulativa (CDF) está dada por:
\[ F(x | \mu, s) = \frac{1}{1+e^{-\frac{x - \mu}{s}}}. \]
A continuación, presentamos una tabla con la descripción de las principales columnas del archivo Excel:
| Columna | Descripción |
|---|---|
| S&P 500 | Valor del índice S&P 500 en distintas fechas. |
| Return | Retorno diario del índice calculado como la variación porcentual respecto al día anterior. |
| Ranked return | Retornos ordenados de menor a mayor. |
| Empirical CDF | Función de distribución acumulativa empírica basada en los datos observados. |
| Normal CDF | Función de distribución acumulativa de una normal ajustada a los datos. |
| Logistic CDF | Función de distribución acumulativa de la distribución logística ajustada a los datos. |
Cargamos los datos del archivo de Excel:
library(readxl)
library(ggplot2)
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(MASS)
##
## Attaching package: 'MASS'
## The following object is masked from 'package:dplyr':
##
## select
df_logistic <- read_excel("NEDL_Distributions.xlsx", sheet = "NEDL_Logistic")
## Warning: Expecting numeric in B1262 / R1262C2: got 'average'
## Warning: Expecting numeric in D1262 / R1262C4: got 'Logistic CDF:'
## Warning: Expecting numeric in B1263 / R1263C2: got 'stdev'
## Warning: Expecting numeric in B1264 / R1264C2: got 'a (scale)'
## New names:
## • `` -> `...1`
head(df_logistic)
## # A tibble: 6 × 8
## ...1 `S&P 500` Return Rank `Ranked return` `Empirical CDF`
## <dttm> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 2014-12-31 00:00:00 2059. NA NA NA NA
## 2 2015-01-02 00:00:00 2058. -0.000340 1 -0.0410 0.000795
## 3 2015-01-05 00:00:00 2021. -0.0183 2 -0.0394 0.00159
## 4 2015-01-06 00:00:00 2003. -0.00889 3 -0.0375 0.00238
## 5 2015-01-07 00:00:00 2026. 0.0116 4 -0.0359 0.00318
## 6 2015-01-08 00:00:00 2062. 0.0179 5 -0.0329 0.00397
## # ℹ 2 more variables: `Normal CDF` <dbl>, `Logistic CDF` <dbl>
Filtramos valores faltantes e infinitos en la columna
Return:
df_logistic <- df_logistic %>%
filter(!is.na(Return) & is.finite(Return))
Visualizamos la distribución de los retornos con etiquetas:
ggplot(df_logistic, aes(x = `Return`)) +
geom_histogram(aes(y = ..density..), bins = 50, fill = "steelblue", alpha = 0.6) +
geom_density(color = "blue", size = 1) +
ggtitle("Distribución de los Retornos del S&P 500") +
theme_minimal() +
labs(x = "Retorno del S&P 500", y = "Densidad",
caption = "El histograma representa la distribución empírica de los retornos, mientras que la línea roja muestra la estimación de densidad.")
## Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
## ℹ Please use `linewidth` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
## Warning: The dot-dot notation (`..density..`) was deprecated in ggplot2 3.4.0.
## ℹ Please use `after_stat(density)` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
Ajustamos una distribución logística a los datos:
fit_log <- fitdistr(df_logistic$`Return`, "logistic")
## Warning in densfun(x, parm[1], parm[2], ...): NaNs produced
## Warning in densfun(x, parm[1], parm[2], ...): NaNs produced
## Warning in densfun(x, parm[1], parm[2], ...): NaNs produced
## Warning in densfun(x, parm[1], parm[2], ...): NaNs produced
## Warning in densfun(x, parm[1], parm[2], ...): NaNs produced
## Warning in densfun(x, parm[1], parm[2], ...): NaNs produced
fit_log
## location scale
## 6.306995e-04 4.359456e-03
## (2.078378e-04) (8.945205e-05)
ggplot(df_logistic, aes(x = `Return`)) +
geom_histogram(aes(y = ..density..), bins = 50, fill = "gray", alpha = 0.4) +
stat_function(fun = dnorm, args = list(mean = mean(df_logistic$`Return`, na.rm = TRUE),
sd = sd(df_logistic$`Return`, na.rm = TRUE)),
color = "orange", linetype = "dashed", size = 1) +
stat_function(fun = dlogis, args = list(location = fit_log$estimate[1],
scale = fit_log$estimate[2]),
color = "red", linetype = "solid", size = 1) +
geom_density(color = "blue", size = 1, linetype = "dotdash") +
ggtitle("Comparación de Distribuciones: Normal vs Logística vs KDE") +
theme_minimal() +
annotate("text", x = 0.02, y = 25,
label = "Distribución Normal",
color = "orange", size = 4, hjust = 0) +
annotate("text", x = 0.02, y = 22,
label = "Distribución Logística",
color = "red", size = 4, hjust = 0) +
annotate("text", x = 0.02, y = 19,
label = "KDE Estimado", color = "blue",
size = 4, hjust = 0) +
labs(x = "Retorno del S&P 500", y = "Densidad",
caption = "El histograma representa la distribución empírica de los retornos.")