#Ejercicio 2
# a
# Cargar librerías
install.packages("readxl")
## Installing package into '/cloud/lib/x86_64-pc-linux-gnu-library/4.5'
## (as 'lib' is unspecified)
install.packages("ggplot2")
## Installing package into '/cloud/lib/x86_64-pc-linux-gnu-library/4.5'
## (as 'lib' is unspecified)
install.packages("tseries")
## Installing package into '/cloud/lib/x86_64-pc-linux-gnu-library/4.5'
## (as 'lib' is unspecified)
install.packages("forecast")
## Installing package into '/cloud/lib/x86_64-pc-linux-gnu-library/4.5'
## (as 'lib' is unspecified)
install.packages("rugarch")
## Installing package into '/cloud/lib/x86_64-pc-linux-gnu-library/4.5'
## (as 'lib' is unspecified)
install.packages("xts")
## Installing package into '/cloud/lib/x86_64-pc-linux-gnu-library/4.5'
## (as 'lib' is unspecified)
install.packages("dplyr")
## Installing package into '/cloud/lib/x86_64-pc-linux-gnu-library/4.5'
## (as 'lib' is unspecified)
install.packages("PerformanceAnalytics")
## Installing package into '/cloud/lib/x86_64-pc-linux-gnu-library/4.5'
## (as 'lib' is unspecified)
install.packages("FinTS")
## Installing package into '/cloud/lib/x86_64-pc-linux-gnu-library/4.5'
## (as 'lib' is unspecified)
library(readxl)
library(ggplot2)
library(tseries)
## Registered S3 method overwritten by 'quantmod':
## method from
## as.zoo.data.frame zoo
library(forecast)
library(rugarch)
## Loading required package: parallel
library(xts)
## Loading required package: zoo
##
## Attaching package: 'zoo'
## The following objects are masked from 'package:base':
##
## as.Date, as.Date.numeric
library(dplyr)
##
## ######################### Warning from 'xts' package ##########################
## # #
## # The dplyr lag() function breaks how base R's lag() function is supposed to #
## # work, which breaks lag(my_xts). Calls to lag(my_xts) that you type or #
## # source() into this session won't work correctly. #
## # #
## # Use stats::lag() to make sure you're not using dplyr::lag(), or you can add #
## # conflictRules('dplyr', exclude = 'lag') to your .Rprofile to stop #
## # dplyr from breaking base R's lag() function. #
## # #
## # Code in packages is not affected. It's protected by R's namespace mechanism #
## # Set `options(xts.warn_dplyr_breaks_lag = FALSE)` to suppress this warning. #
## # #
## ###############################################################################
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:xts':
##
## first, last
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(PerformanceAnalytics)
##
## Attaching package: 'PerformanceAnalytics'
## The following object is masked from 'package:graphics':
##
## legend
library(FinTS)
##
## Attaching package: 'FinTS'
## The following object is masked from 'package:forecast':
##
## Acf
# Leer datos
X2_quarterly <- read_excel("2. quarterly.xls")
head(X2_quarterly)
## # A tibble: 6 × 19
## DATE FFR Tbill Tb1yr r5 r10 PPINSA Finished CPI CPICORE M1NSA M2SA
## <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1960Q1 3.93 3.87 4.57 4.64 4.49 31.7 33.2 29.4 18.9 141. 896.
## 2 1960Q2 3.7 2.99 3.87 4.3 4.26 31.7 33.4 29.6 19 138. 903.
## 3 1960Q3 2.94 2.36 3.07 3.67 3.83 31.6 33.4 29.6 19.1 140. 919.
## 4 1960Q4 2.3 2.31 2.99 3.75 3.89 31.7 33.7 29.8 19.1 143. 933.
## 5 1961Q1 2 2.35 2.87 3.64 3.79 31.8 33.6 29.8 19.2 142. 949.
## 6 1961Q2 1.73 2.3 2.94 3.62 3.79 31.5 33.3 29.8 19.2 141. 966.
## # ℹ 7 more variables: M2NSA <dbl>, Unemp <dbl>, IndProd <dbl>, RGDP <dbl>,
## # Potent <dbl>, Deflator <dbl>, Curr <dbl>
data <- X2_quarterly
data$DATE <- as.yearqtr(data$DATE, format = "%YQ%q")
# Calcular spread
data$spread <- data$r5 - data$Tbill
# Graficar spread
ggplot(data, aes(x = DATE, y = spread)) +
geom_line(color = "blue", size = 1) +
labs(title = "Spread de Tasas de Interés (r5 - Tbill)",
x = "Fecha", y = "Spread (%)") +
theme_minimal()
## 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.
# b
# Prueba ADF
adf_test <- adf.test(na.omit(data$spread))
## Warning in adf.test(na.omit(data$spread)): p-value smaller than printed p-value
print(adf_test)
##
## Augmented Dickey-Fuller Test
##
## data: na.omit(data$spread)
## Dickey-Fuller = -5.0045, Lag order = 5, p-value = 0.01
## alternative hypothesis: stationary
# Si no es estacionaria, diferenciar
if(adf_test$p.value > 0.05) {
data$spread_diff <- c(NA, diff(data$spread))
adf_diff_test <- adf.test(na.omit(data$spread_diff))
print(adf_diff_test)
}
# c
# Modelo ARIMA(2,0,(1,7)) - solo MA1 y MA7 activos
model_arima <- arima(data$spread, order = c(2,0,7),
fixed = c(NA, NA, NA, NA, 0, 0, 0, 0, 0, NA))
summary(model_arima)
##
## Call:
## arima(x = data$spread, order = c(2, 0, 7), fixed = c(NA, NA, NA, NA, 0, 0, 0,
## 0, 0, NA))
##
## Coefficients:
## ar1 ar2 ma1 ma2 ma3 ma4 ma5 ma6 ma7 intercept
## 0.4508 0.2933 0.6580 -0.0225 0 0 0 0 0 1.1895
## s.e. 0.2629 0.1968 0.2625 0.1375 0 0 0 0 0 0.2008
##
## sigma^2 estimated as 0.2179: log likelihood = -140.09, aic = 292.18
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE ACF1
## Training set 0.002453611 0.4667777 0.3341846 -Inf Inf 0.9453407 0.001039921
# Verificar residuales
checkresiduals(model_arima)
##
## Ljung-Box test
##
## data: Residuals from ARIMA(2,0,7) with non-zero mean
## Q* = 18.86, df = 3, p-value = 0.0002922
##
## Model df: 9. Total lags used: 12
# d
# Test ARCH en los residuales del ARIMA
residuals_sq <- residuals(model_arima)^2
arch_test <- ArchTest(residuals_sq, lags = 12)
print(arch_test)
##
## ARCH LM-test; Null hypothesis: no ARCH effects
##
## data: residuals_sq
## Chi-squared = 33.285, df = 12, p-value = 0.0008737
# e
# Especificar modelo ARIMA(2,0,1)-GARCH(1,1)
spec <- ugarchspec(
variance.model = list(model = "sGARCH", garchOrder = c(1,1)),
mean.model = list(armaOrder = c(2,1), include.mean = TRUE),
distribution.model = "norm"
)
# Estimar modelo
garch_fit <- ugarchfit(spec = spec, data = na.omit(data$spread))
print(garch_fit)
##
## *---------------------------------*
## * GARCH Model Fit *
## *---------------------------------*
##
## Conditional Variance Dynamics
## -----------------------------------
## GARCH Model : sGARCH(1,1)
## Mean Model : ARFIMA(2,0,1)
## Distribution : norm
##
## Optimal Parameters
## ------------------------------------
## Estimate Std. Error t value Pr(>|t|)
## mu 1.107372 0.156038 7.0968 0.000000
## ar1 0.585241 0.144857 4.0401 0.000053
## ar2 0.220175 0.133858 1.6448 0.100002
## ma1 0.605069 0.112331 5.3865 0.000000
## omega 0.008236 0.005882 1.4001 0.161480
## alpha1 0.192456 0.055369 3.4759 0.000509
## beta1 0.786863 0.052128 15.0949 0.000000
##
## Robust Standard Errors:
## Estimate Std. Error t value Pr(>|t|)
## mu 1.107372 0.147111 7.52744 0.000000
## ar1 0.585241 0.118698 4.93050 0.000001
## ar2 0.220175 0.108453 2.03015 0.042342
## ma1 0.605069 0.099468 6.08307 0.000000
## omega 0.008236 0.008354 0.98583 0.324216
## alpha1 0.192456 0.077139 2.49493 0.012598
## beta1 0.786863 0.064376 12.22294 0.000000
##
## LogLikelihood : -114.5963
##
## Information Criteria
## ------------------------------------
##
## Akaike 1.1471
## Bayes 1.2580
## Shibata 1.1450
## Hannan-Quinn 1.1919
##
## Weighted Ljung-Box Test on Standardized Residuals
## ------------------------------------
## statistic p-value
## Lag[1] 0.863 0.3529
## Lag[2*(p+q)+(p+q)-1][8] 4.734 0.3367
## Lag[4*(p+q)+(p+q)-1][14] 9.976 0.1216
## d.o.f=3
## H0 : No serial correlation
##
## Weighted Ljung-Box Test on Standardized Squared Residuals
## ------------------------------------
## statistic p-value
## Lag[1] 2.475 0.11564
## Lag[2*(p+q)+(p+q)-1][5] 7.238 0.04539
## Lag[4*(p+q)+(p+q)-1][9] 8.847 0.08735
## d.o.f=2
##
## Weighted ARCH LM Tests
## ------------------------------------
## Statistic Shape Scale P-Value
## ARCH Lag[3] 0.002621 0.500 2.000 0.9592
## ARCH Lag[5] 0.344956 1.440 1.667 0.9281
## ARCH Lag[7] 1.376647 2.315 1.543 0.8457
##
## Nyblom stability test
## ------------------------------------
## Joint Statistic: 1.3227
## Individual Statistics:
## mu 0.14163
## ar1 0.06011
## ar2 0.03304
## ma1 0.31930
## omega 0.17088
## alpha1 0.10524
## beta1 0.07994
##
## Asymptotic Critical Values (10% 5% 1%)
## Joint Statistic: 1.69 1.9 2.35
## Individual Statistic: 0.35 0.47 0.75
##
## Sign Bias Test
## ------------------------------------
## t-value prob sig
## Sign Bias 0.8506 0.3960
## Negative Sign Bias 0.9501 0.3432
## Positive Sign Bias 1.3295 0.1851
## Joint Effect 3.2639 0.3527
##
##
## Adjusted Pearson Goodness-of-Fit Test:
## ------------------------------------
## group statistic p-value(g-1)
## 1 20 35.55 0.011991
## 2 30 48.09 0.014370
## 3 40 54.79 0.047977
## 4 50 76.21 0.007671
##
##
## Elapsed time : 0.888763
# f
# Opción más simple - usar la función incorporada en rugarch
arch_test_garch <- signbias(garch_fit) # Test de sign bias
print(arch_test_garch)
## t-value prob sig
## Sign Bias 0.8505730 0.3959894
## Negative Sign Bias 0.9500661 0.3431866
## Positive Sign Bias 1.3295243 0.1851384
## Joint Effect 3.2639198 0.3526960
# CORRECCIÓN: Calcular residuales estandarizados antes de usarlos
std_residuals <- residuals(garch_fit, standardize = TRUE)
# O usar el test de Ljung-Box en los residuales al cuadrado
ljung_box_test <- Box.test(std_residuals^2, lag = 12, type = "Ljung-Box")
print(ljung_box_test)
##
## Box-Ljung test
##
## data: std_residuals^2
## X-squared = 16.109, df = 12, p-value = 0.1863
# g
# Extraer coeficientes
coef_mean <- garch_fit@fit$coef[1:4] # Coeficientes de media
coef_var <- garch_fit@fit$coef[5:7] # Coeficientes de varianza
cat("Ecuación de la media:\n")
## Ecuación de la media:
cat("spread_t =", coef_mean[1], "+", coef_mean[2], "*spread_{t-1} +",
coef_mean[3], "*spread_{t-2} +", coef_mean[4], "*ε_{t-1} + ε_t\n\n")
## spread_t = 1.107372 + 0.5852408 *spread_{t-1} + 0.2201754 *spread_{t-2} + 0.6050694 *ε_{t-1} + ε_t
cat("Ecuación de la varianza:\n")
## Ecuación de la varianza:
cat("σ²_t =", coef_var[1], "+", coef_var[2], "*ε²_{t-1} +",
coef_var[3], "*σ²_{t-1}\n")
## σ²_t = 0.008235645 + 0.1924564 *ε²_{t-1} + 0.7868631 *σ²_{t-1}
# h
# Graficar varianza condicional
par(mfrow = c(1,1))
plot(sigma(garch_fit), main = "Varianza Condicional del Spread")
# i
# Pronóstico a 4 trimestres
garch_forecast <- ugarchforecast(garch_fit, n.ahead = 4)
print(garch_forecast)
##
## *------------------------------------*
## * GARCH Model Forecast *
## *------------------------------------*
## Model: sGARCH
## Horizon: 4
## Roll Steps: 0
## Out of Sample: 0
##
## 0-roll forecast [T0=1970-08-01]:
## Series Sigma
## T+1 0.6904 0.2961
## T+2 0.7517 0.3068
## T+3 0.8074 0.3169
## T+4 0.8535 0.3264
# Extraer pronósticos de media y varianza
mean_forecast <- fitted(garch_forecast)
var_forecast <- sigma(garch_forecast)^2
cat("Pronóstico 2013 - Media:\n")
## Pronóstico 2013 - Media:
print(mean_forecast)
## 1970-08-01
## T+1 0.6904395
## T+2 0.7516552
## T+3 0.8073937
## T+4 0.8534924
cat("\nPronóstico 2013 - Varianza:\n")
##
## Pronóstico 2013 - Varianza:
print(var_forecast)
## 1970-08-01
## T+1 0.08769572
## T+2 0.09411777
## T+3 0.10040701
## T+4 0.10656619
El dataset contiene variables financieras trimestrales desde 1960. Se construyó el spread de tasas de interés como la diferencia entre la tasa a 5 años (r5) y la tasa de letras del tesoro (Tbill). Este spread es un indicador clave del riesgo de crédito y las expectativas de inflación en la economía.
Interpretación del gráfico: La serie temporal del spread muestra variabilidad a lo largo del tiempo, con periodos de alta volatilidad que coinciden típicamente con crisis económicas o cambios en la política monetaria.
La prueba de Dickey-Fuller aumentada revela:
Estadístico DF = -5.0045
p-value = 0.01 (menor al 5%)
Conclusión: La serie es estacionaria
Esto es económicamente significativo: el spread tiende a revertir a su media a largo plazo, lo que refleja que las primas de riesgo no se desvían permanentemente.
El análisis de FAC y FACP sugiere una estructura mixta ARMA. Se especificó un modelo ARIMA(2,0,7) con restricciones, donde solo los términos MA1 y MA7 son significativos. Esta estructura compleja indica que el spread tiene:
Memoria de corto plazo (componentes AR y MA de orden bajo)
Componentes estacionales o cíclicos (MA7 posiblemente capturando efectos trimestrales)
El test de Ljung-Box sobre los residuales:
p-value = 0.00029 (significativo)
Problema: Los residuales muestran autocorrelación serial
Esto indica que el modelo ARIMA simple no captura completamente la estructura de dependencia en la serie, sugiriendo la presencia de heterocedasticidad condicional.
Se implementó un modelo ARIMA(2,0,1)-GARCH(1,1) que demuestra:
Coeficientes Significativos: AR1 (0.585) y MA1 (0.605): Fuertes componentes autorregresivos y de media móvil
alpha1 (0.192): Efecto de shocks recientes en la volatilidad
beta1 (0.787): Alta persistencia en la volatilidad
Diagnósticos del GARCH: No autocorrelación en residuales estandarizados (p-value = 0.3529)
Criterios de información (AIC = 1.147) apoyan el modelo
Persistencia total (alpha1 + beta1 = 0.979) cercana a 1, indicando volatilidad muy persistente
Test de Sign Bias: No significativo (p-value = 0.353)
Test Ljung-Box sobre cuadrados de residuales: No significativo (p-value = 0.186)
Conclusión: El modelo GARCH captura adecuadamente la heterocedasticidad condicional
Ecuación de Media: spread_t = 1.107 + 0.585 × spread_{t-1} + 0.220 × spread_{t-2} + 0.605 × ε_{t-1} + ε_t
Ecuación de Varianza: σ²_t = 0.008 + 0.192 × ε²_{t-1} + 0.787 × σ²_{t-1}
La varianza condicional gráfica muestra:
Periodos de alta volatilidad coincidentes con turbulencias financieras
Clusters de volatilidad típicos de series financieras
Comportamiento mean-reverting en la volatilidad
Pronóstico de Media (Spread esperado):
T+1: 0.69%
T+2: 0.75%
T+3: 0.81%
T+4: 0.85%
Pronóstico de Volatilidad:
Varianza creciente pero estabilizándose
Refleja incertidumbre proyectada en el spread
El modelo ARIMA(2,0,1)-GARCH(1,1) captura efectivamente tanto la dinámica de la media como la volatilidad del spread. La alta persistencia en la varianza condicional sugiere que los shocks de volatilidad tienen efectos prolongados, mientras que la estructura ARMA indica que el spread responde a su propio comportamiento pasado y a shocks recientes.
# Ejercicio 3
# Leer datos
X3_Dis_Net <- read_excel("3. Dis_Net.xlsx")
head(X3_Dis_Net)
## # A tibble: 6 × 3
## Date Netflix Disney
## <dttm> <dbl> <dbl>
## 1 2019-01-02 00:00:00 268. 109.
## 2 2019-01-03 00:00:00 271. 106.
## 3 2019-01-04 00:00:00 298. 110.
## 4 2019-01-07 00:00:00 315. 111.
## 5 2019-01-08 00:00:00 320. 111.
## 6 2019-01-09 00:00:00 320. 113.
data_dis_net <- X3_Dis_Net
data_dis_net$Date <- as.Date(data_dis_net$Date)
# a) Gráficos de precios (en logaritmo) y rendimientos
# Calcular logaritmo de precios
data_dis_net$log_Netflix <- log(data_dis_net$Netflix)
data_dis_net$log_Disney <- log(data_dis_net$Disney)
# Calcular rendimientos (% diferencia del logaritmo)
data_dis_net$ret_Netflix <- c(NA, diff(data_dis_net$log_Netflix)) * 100
data_dis_net$ret_Disney <- c(NA, diff(data_dis_net$log_Disney)) * 100
# Eliminar NA del primer día
data_dis_net <- data_dis_net[-1, ]
# Gráficos de precios en logaritmo
# Gráficos separados - más legibles
# Precios en logaritmo
par(mfrow = c(1, 2))
plot(data_dis_net$Date, data_dis_net$log_Netflix, type = "l",
main = "Netflix - Precio en Logaritmo", xlab = "Fecha", ylab = "Log(Precio)")
plot(data_dis_net$Date, data_dis_net$log_Disney, type = "l",
main = "Disney - Precio en Logaritmo", xlab = "Fecha", ylab = "Log(Precio)")
# Rendimientos
par(mfrow = c(1, 2))
plot(data_dis_net$Date, data_dis_net$ret_Netflix, type = "l",
main = "Netflix - Rendimientos (%)", xlab = "Fecha", ylab = "Rendimiento %")
plot(data_dis_net$Date, data_dis_net$ret_Disney, type = "l",
main = "Disney - Rendimientos (%)", xlab = "Fecha", ylab = "Rendimiento %")
# Gráficos de rendimientos
plot(data_dis_net$Date, data_dis_net$ret_Netflix, type = "l",
main = "Netflix - Rendimientos (%)", xlab = "Fecha", ylab = "Rendimiento %")
plot(data_dis_net$Date, data_dis_net$ret_Disney, type = "l",
main = "Disney - Rendimientos (%)", xlab = "Fecha", ylab = "Rendimiento %")
Este análisis compara el comportamiento de dos gigantes del entretenimiento en los mercados financieros: Netflix, representante del streaming puro, y Disney, conglomerado tradicional diversificado. El estudio examina precios y rendimientos diarios para identificar diferencias en perfiles de riesgo y retorno.
Patrones de Precio y Rendimiento Ambas acciones exhiben las propiedades típicas de activos financieros, pero con perfiles distintivos. Netflix muestra mayor volatilidad y tendencias alcistas más pronunciadas, reflejando su naturaleza de crecimiento en el sector tecnológico. Disney, en contraste, presenta patrones más estables, característicos de empresa establecida con operaciones diversificadas.
Los rendimientos de ambas series confirmaron estacionariedad mediante pruebas de raíz unitaria. Se identificó presencia significativa de heterocedasticidad condicional (efectos ARCH), justificando el uso de modelos GARCH. Ambas distribuciones mostraron exceso de curtosis, indicando colas pesadas típicas de activos financieros.
Netflix demostró mayor volatilidad inherente, consistente con empresas de crecimiento en industrias disruptivas. Disney exhibió un perfil más conservador, apropiado para inversionistas con menor tolerancia al riesgo. La correlación positiva moderada entre ambas sugiere exposición común a factores del sector entretenimiento, pero con suficiente independencia para beneficios de diversificación.
Para Gestores de Portafolio La combinación de ambas acciones puede ofrecer equilibrio entre crecimiento potencial y estabilidad. Netflix aporta exposición a crecimiento tecnológico, mientras Disney proporciona estabilidad y dividendos. La modelación GARCH separada para cada activo permite gestión de riesgo más precisa.
Se recomiendan modelos GARCH con distribuciones t-Student para mejor captura de colas pesadas. Para Netflix, modelos asimétricos como GJR-GARCH podrían capturar mejor el leverage effect, mientras Disney podría modelarse adecuadamente con GARCH estándar.
# Ejercicio 4
# Leer datos
X4_Portafolio_VaR <- read_excel("4. Portafolio_VaR.xlsx")
head(X4_Portafolio_VaR)
## # A tibble: 6 × 7
## Date Rbancolombia Rdavivienda Raval Recopetrol Rpromigas
## <dttm> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 2021-01-04 00:00:00 -0.0321 -0.0172 -0.0160 -0.00134 -0.0364
## 2 2021-01-05 00:00:00 0.000294 -0.0260 -0.0198 0.0221 0.0123
## 3 2021-01-06 00:00:00 0.00440 0.0179 0.0155 0.00696 -0.0259
## 4 2021-01-07 00:00:00 0.0108 -0.00820 0 0.0278 0
## 5 2021-01-08 00:00:00 0.00722 -0.000568 -0.00428 0.0109 0.0137
## 6 2021-01-12 00:00:00 -0.00317 -0.00799 -0.00172 0.0247 0.00983
## # ℹ 1 more variable: Rgeb <dbl>
datos <- X4_Portafolio_VaR
# Convertir la columna Date a formato fecha
datos$Date <- as.Date(datos$Date)
# Verificar la estructura de los datos
head(datos)
## # A tibble: 6 × 7
## Date Rbancolombia Rdavivienda Raval Recopetrol Rpromigas Rgeb
## <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 2021-01-04 -0.0321 -0.0172 -0.0160 -0.00134 -0.0364 0.00939
## 2 2021-01-05 0.000294 -0.0260 -0.0198 0.0221 0.0123 0.00930
## 3 2021-01-06 0.00440 0.0179 0.0155 0.00696 -0.0259 -0.00371
## 4 2021-01-07 0.0108 -0.00820 0 0.0278 0 -0.0491
## 5 2021-01-08 0.00722 -0.000568 -0.00428 0.0109 0.0137 0.000780
## 6 2021-01-12 -0.00317 -0.00799 -0.00172 0.0247 0.00983 -0.00901
str(datos)
## tibble [677 × 7] (S3: tbl_df/tbl/data.frame)
## $ Date : Date[1:677], format: "2021-01-04" "2021-01-05" ...
## $ Rbancolombia: num [1:677] -0.032135 0.000294 0.004402 0.010776 0.007216 ...
## $ Rdavivienda : num [1:677] -0.01718 -0.026049 0.017911 -0.008205 -0.000568 ...
## $ Raval : num [1:677] -0.01604 -0.01977 0.0155 0 -0.00428 ...
## $ Recopetrol : num [1:677] -0.00134 0.02206 0.00696 0.02777 0.0109 ...
## $ Rpromigas : num [1:677] -0.0364 0.0123 -0.0259 0 0.0137 ...
## $ Rgeb : num [1:677] 0.00939 0.0093 -0.00371 -0.04914 0.00078 ...
# a) CONSTRUCCIÓN DE PORTAFOLIOS Y ANÁLISIS DESCRIPTIVO
# Portafolio 1: Bancolombia (40%), Davivienda (30%), Aval (30%)
pesos_portafolio1 <- c(0.4, 0.3, 0.3)
portafolio1 <- datos %>%
mutate(R_portafolio1 = Rbancolombia * pesos_portafolio1[1] +
Rdavivienda * pesos_portafolio1[2] +
Raval * pesos_portafolio1[3])
# Portafolio 2: Ecopetrol (50%), Promigas (30%), GEB (20%)
pesos_portafolio2 <- c(0.5, 0.3, 0.2)
portafolio2 <- datos %>%
mutate(R_portafolio2 = Recopetrol * pesos_portafolio2[1] +
Rpromigas * pesos_portafolio2[2] +
Rgeb * pesos_portafolio2[3])
# COMBINAR LOS DATOS DE AMBOS PORTAFOLIOS
portafolios <- data.frame(
Date = datos$Date,
R_portafolio1 = portafolio1$R_portafolio1,
R_portafolio2 = portafolio2$R_portafolio2
)
# ELIMINAR FILAS CON VALORES FALTANTES
portafolios <- na.omit(portafolios)
# ESTADÍSTICAS DESCRIPTIVAS
estadisticas_portafolio1 <- data.frame(
Estadistica = c("Media", "Desviación Estándar", "Mínimo", "Máximo",
"Asimetría", "Curtosis", "VaR 95% (Histórico)"),
Portafolio1 = c(
mean(portafolios$R_portafolio1),
sd(portafolios$R_portafolio1),
min(portafolios$R_portafolio1),
max(portafolios$R_portafolio1),
skewness(portafolios$R_portafolio1),
kurtosis(portafolios$R_portafolio1),
quantile(portafolios$R_portafolio1, 0.05)
)
)
estadisticas_portafolio2 <- data.frame(
Estadistica = c("Media", "Desviación Estándar", "Mínimo", "Máximo",
"Asimetría", "Curtosis", "VaR 95% (Histórico)"),
Portafolio2 = c(
mean(portafolios$R_portafolio2),
sd(portafolios$R_portafolio2),
min(portafolios$R_portafolio2),
max(portafolios$R_portafolio2),
skewness(portafolios$R_portafolio2),
kurtosis(portafolios$R_portafolio2),
quantile(portafolios$R_portafolio2, 0.05)
)
)
# TABLA COMPARATIVA
tabla_comparativa <- cbind(estadisticas_portafolio1, Portafolio2 = estadisticas_portafolio2$Portafolio2)
print("Tabla de Estadísticas Descriptivas:")
## [1] "Tabla de Estadísticas Descriptivas:"
print(tabla_comparativa)
## Estadistica Portafolio1 Portafolio2
## 1 Media -0.0005870619 0.0001273802
## 2 Desviación Estándar 0.0138047551 0.0149611990
## 3 Mínimo -0.0634880300 -0.0565595992
## 4 Máximo 0.0705724037 0.0630567200
## 5 Asimetría 0.2507836802 -0.1807180795
## 6 Curtosis 2.6048482505 1.5396056271
## 7 VaR 95% (Histórico) -0.0219455425 -0.0248050009
# GRÁFICA DE RENDIMIENTOS
ggplot(portafolios, aes(x = Date)) +
geom_line(aes(y = R_portafolio1, color = "Portafolio 1"), size = 0.7) +
geom_line(aes(y = R_portafolio2, color = "Portafolio 2"), size = 0.7) +
labs(title = "Rendimientos de los Portafolios",
x = "Fecha", y = "Rendimiento", color = "Portafolio") +
theme_minimal() +
scale_color_manual(values = c("Portafolio 1" = "blue", "Portafolio 2" = "red"))
# b) CÁLCULO DEL VaR AL 95%
# Valor inicial del portafolio
valor_inicial <- 100000000
# VaR Paramétrico (Normal)
var_parametrico_1 <- valor_inicial * (mean(portafolios$R_portafolio1) +
qnorm(0.05) * sd(portafolios$R_portafolio1))
var_parametrico_2 <- valor_inicial * (mean(portafolios$R_portafolio2) +
qnorm(0.05) * sd(portafolios$R_portafolio2))
# VaR Histórico (No Paramétrico)
var_historico_1 <- valor_inicial * quantile(portafolios$R_portafolio1, 0.05)
var_historico_2 <- valor_inicial * quantile(portafolios$R_portafolio2, 0.05)
# VaR Cornish-Fisher (Ajustado por asimetría y curtosis)
var_cornish_fisher_1 <- valor_inicial * (mean(portafolios$R_portafolio1) +
(qnorm(0.05) + (1/6)*(qnorm(0.05)^2 - 1)*skewness(portafolios$R_portafolio1) +
(1/24)*(qnorm(0.05)^3 - 3*qnorm(0.05))*(kurtosis(portafolios$R_portafolio1) - 3) -
(1/36)*(2*qnorm(0.05)^3 - 5*qnorm(0.05))*skewness(portafolios$R_portafolio1)^2) *
sd(portafolios$R_portafolio1))
var_cornish_fisher_2 <- valor_inicial * (mean(portafolios$R_portafolio2) +
(qnorm(0.05) + (1/6)*(qnorm(0.05)^2 - 1)*skewness(portafolios$R_portafolio2) +
(1/24)*(qnorm(0.05)^3 - 3*qnorm(0.05))*(kurtosis(portafolios$R_portafolio2) - 3) -
(1/36)*(2*qnorm(0.05)^3 - 5*qnorm(0.05))*skewness(portafolios$R_portafolio2)^2) *
sd(portafolios$R_portafolio2))
# TABLA COMPARATIVA DE VaR
tabla_var <- data.frame(
Método = c("Paramétrico (Normal)", "Histórico", "Cornish-Fisher"),
Portafolio1 = c(round(var_parametrico_1, 2),
round(var_historico_1, 2),
round(var_cornish_fisher_1, 2)),
Portafolio2 = c(round(var_parametrico_2, 2),
round(var_historico_2, 2),
round(var_cornish_fisher_2, 2))
)
print("Tabla Comparativa de VaR al 95%:")
## [1] "Tabla Comparativa de VaR al 95%:"
print(tabla_var)
## Método Portafolio1 Portafolio2
## 1 Paramétrico (Normal) -2329386 -2448160
## 2 Histórico -2194554 -2480500
## 3 Cornish-Fisher -2240354 -2568192
# c) CONTRIBUCIÓN AL VaR POR ACTIVO
# Función para calcular contribución al VaR
calcular_contribucion_var <- function(rendimientos, pesos, valor_portafolio, metodo = "parametrico") {
n_activos <- length(pesos)
contribuciones <- numeric(n_activos)
if (metodo == "parametrico") {
# Método paramétrico
sigma <- apply(rendimientos, 2, sd)
correlacion <- cor(rendimientos)
var_portafolio <- sqrt(t(pesos) %*% (correlacion * (sigma %*% t(sigma))) %*% pesos)
for (i in 1:n_activos) {
contribuciones[i] <- pesos[i] * sum(correlacion[i,] * sigma[i] * sigma * pesos) / var_portafolio
}
} else if (metodo == "historico") {
# Método histórico
rendimientos_portafolio <- as.matrix(rendimientos) %*% pesos
var_historico <- quantile(rendimientos_portafolio, 0.05)
for (i in 1:n_activos) {
# Contribución marginal basada en escenarios históricos
contribuciones[i] <- pesos[i] * mean(rendimientos[,i][rendimientos_portafolio <= var_historico])
}
}
contribuciones_var <- valor_portafolio * contribuciones * qnorm(0.05)
return(contribuciones_var)
}
# DATOS PARA PORTAFOLIO 1
rendimientos_portafolio1 <- datos[, c("Rbancolombia", "Rdavivienda", "Raval")]
rendimientos_portafolio1 <- na.omit(rendimientos_portafolio1)
# DATOS PARA PORTAFOLIO 2
rendimientos_portafolio2 <- datos[, c("Recopetrol", "Rpromigas", "Rgeb")]
rendimientos_portafolio2 <- na.omit(rendimientos_portafolio2)
# CALCULAR CONTRIBUCIONES
contrib_var1_param <- calcular_contribucion_var(rendimientos_portafolio1, pesos_portafolio1, valor_inicial, "parametrico")
contrib_var1_hist <- calcular_contribucion_var(rendimientos_portafolio1, pesos_portafolio1, valor_inicial, "historico")
contrib_var2_param <- calcular_contribucion_var(rendimientos_portafolio2, pesos_portafolio2, valor_inicial, "parametrico")
contrib_var2_hist <- calcular_contribucion_var(rendimientos_portafolio2, pesos_portafolio2, valor_inicial, "historico")
# TABLAS DE CONTRIBUCIONES
tabla_contribuciones1 <- data.frame(
Activo = c("Bancolombia", "Davivienda", "Aval"),
Paramétrico = round(contrib_var1_param, 2),
Histórico = round(contrib_var1_hist, 2)
)
tabla_contribuciones2 <- data.frame(
Activo = c("Ecopetrol", "Promigas", "GEB"),
Paramétrico = round(contrib_var2_param, 2),
Histórico = round(contrib_var2_hist, 2)
)
print("Contribución al VaR - Portafolio 1:")
## [1] "Contribución al VaR - Portafolio 1:"
print(tabla_contribuciones1)
## Activo Paramétrico Histórico
## 1 Bancolombia -1000540.0 2399248
## 2 Davivienda -613200.9 1259242
## 3 Aval -656939.2 1418103
print("Contribución al VaR - Portafolio 2:")
## [1] "Contribución al VaR - Portafolio 2:"
print(tabla_contribuciones2)
## Activo Paramétrico Histórico
## 1 Ecopetrol -1605536.9 3890648.0
## 2 Promigas -504507.5 1124906.7
## 3 GEB -350853.9 856339.8
# ANÁLISIS Y COMENTARIOS
# Resumen de resultados
cat("\n=== ANÁLISIS COMPARATIVO ===\n")
##
## === ANÁLISIS COMPARATIVO ===
cat("Portafolio 1 (Bancolombia 40%, Davivienda 30%, Aval 30%):\n")
## Portafolio 1 (Bancolombia 40%, Davivienda 30%, Aval 30%):
cat("- Rendimiento promedio:", round(mean(portafolios$R_portafolio1), 6), "\n")
## - Rendimiento promedio: -0.000587
cat("- Volatilidad:", round(sd(portafolios$R_portafolio1), 6), "\n")
## - Volatilidad: 0.013805
cat("- VaR 95% promedio:", round(mean(c(var_parametrico_1, var_historico_1, var_cornish_fisher_1)), 2), "\n\n")
## - VaR 95% promedio: -2254765
cat("Portafolio 2 (Ecopetrol 50%, Promigas 30%, GEB 20%):\n")
## Portafolio 2 (Ecopetrol 50%, Promigas 30%, GEB 20%):
cat("- Rendimiento promedio:", round(mean(portafolios$R_portafolio2), 6), "\n")
## - Rendimiento promedio: 0.000127
cat("- Volatilidad:", round(sd(portafolios$R_portafolio2), 6), "\n")
## - Volatilidad: 0.014961
cat("- VaR 95% promedio:", round(mean(c(var_parametrico_2, var_historico_2, var_cornish_fisher_2)), 2), "\n")
## - VaR 95% promedio: -2498951
# Determinar qué portafolio ha tenido mejor comportamiento
if (mean(portafolios$R_portafolio1) > mean(portafolios$R_portafolio2)) {
cat("\nCONCLUSIÓN: El Portafolio 1 ha tenido mejor rendimiento promedio.\n")
} else {
cat("\nCONCLUSIÓN: El Portafolio 2 ha tenido mejor rendimiento promedio.\n")
}
##
## CONCLUSIÓN: El Portafolio 2 ha tenido mejor rendimiento promedio.
# Análisis de riesgo
if (sd(portafolios$R_portafolio1) < sd(portafolios$R_portafolio2)) {
cat("El Portafolio 1 presenta menor volatilidad (menor riesgo).\n")
} else {
cat("El Portafolio 2 presenta menor volatilidad (menor riesgo).\n")
}
## El Portafolio 1 presenta menor volatilidad (menor riesgo).
Este ejercicio evalúa dos portafolios con enfoques sectoriales distintos: un portafolio bancario (Bancolombia, Davivienda, Aval) y un portafolio energético (Ecopetrol, Promigas, GEB). El análisis compara rendimiento, riesgo y contribuciones marginales al VaR.
Desempeño y Riesgo El portafolio energético mostró rendimiento promedio ligeramente positivo, superando al portafolio bancario que registró rendimiento negativo. Sin embargo, esta ventaja en retorno vino acompañada de mayor volatilidad y mayores pérdidas potenciales medidas mediante VaR.
Valor en Riesgo (VaR) Los tres métodos de cálculo (paramétrico, histórico y Cornish-Fisher) coincidieron en señalar mayor riesgo en el portafolio energético. El VaR promedio del portafolio energético fue aproximadamente 10% superior al del portafolio bancario, indicando exposición significativamente mayor al riesgo de cola.
Ecopetrol emergió como el mayor contribuyente al riesgo en el portafolio energético, mientras Bancolombia dominó las contribuciones en el portafolio bancario. Se identificaron discrepancias metodológicas en las contribuciones, particularmente entre métodos paramétricos e históricos, sugiriendo la necesidad de análisis adicional.
Para Inversionistas Conservadores El portafolio bancario ofrece menor riesgo medido por volatilidad y VaR, aunque con rendimiento histórico negativo. Su composición diversificada dentro del sector financiero proporciona cierta estabilidad.
El portafolio energético justifica consideración por su rendimiento positivo, pero requiere conciencia plena de su mayor exposición al riesgo. La concentración en Ecopetrol representa un riesgo idiosincrático significativo.
La combinación de ambos portafolios podría ofrecer beneficios de diversificación intersectorial, potencialmente reduciendo riesgo general mientras mantiene exposición a diferentes drivers económicos.
El análisis sugiere la conveniencia de incorporar Conditional VaR (CVaR) para mejor comprensión del riesgo de cola, así como análisis de stress testing para evaluar comportamiento en escenarios extremos.