Simulación GARCH

El modelo GARCH es un modelo autorregresivo generalizado que captura las agrupaciones de volatilidad de las rentabilidades a través de la varianza condicional. Este modelo encuentra la volatilidad promedio a medio plazo mediante una autorregresión que depende de la suma de perturbaciones y de la suma de varianzas.

El Departamento de Riesgos se propone a presentar una simulación de algún activo de nuestro portafolio mediante esta metodología. En este caso, haremos uso del titulo DO0125, Bono Soberano con vencimiento enero del 2025.

Veamos el comportamiento historico del titulo hasta la fecha

plot(sample, type="l", main = paste("Evolución del precio de", symbol), col="darkblue")

Ahora, dividamos la data historica en dos muestras para hacer un out of sample, con la cual validaremos el modelo que entrenaremos.

H1.oos <- sample["2023::"] 

ticker <- sample["2014::2022"] 
ticker$daily.vol <- diff(log(Cl(ticker)))
ticker <- na.omit(ticker)
ticker <- ticker[!is.infinite(rowSums(ticker)),]

Utilizaremos una función que probarÔ distintos modelos con diferentes distribuciones de probabilidad.

tab_out <- do_arch_test(x = ticker$daily.vol, max_lag = 5)

#Definimos los modelos de rezago, es decir, cuantas observaciones atrƔs.
max_lag_AR <- 1 # m - parametro AR
max_lag_MA <- 1 # n - parametro MA
max_lag_ARCH <- 1 # p - parametro ARCH
max_lag_GARCH <- 1 # q - parametro GARCH
dist_to_use <- c('norm','std','sstd','jsu', 'snorm') #Modelos de distribución a probar, rugarchspecs para ver mÔs
models_to_estimate <- c('sGARCH', 'eGARCH','gjrGARCH') #Modelos autoregresivos

out <- find_best_arch_model(x = ticker$daily.vol, 
                            type_models = models_to_estimate,
                            dist_to_use = dist_to_use,
                            max_lag_AR = max_lag_AR,
                            max_lag_MA = max_lag_MA,
                            max_lag_ARCH = max_lag_ARCH,
                            max_lag_GARCH = max_lag_GARCH)
## Estimating ARMA(0,0)-sGARCH(1,1) dist = norm Done
## Estimating ARMA(0,1)-sGARCH(1,1) dist = norm Done
## Estimating ARMA(1,0)-sGARCH(1,1) dist = norm Done
## Estimating ARMA(1,1)-sGARCH(1,1) dist = norm Done
## Estimating ARMA(0,0)-sGARCH(1,1) dist = std  Done
## Estimating ARMA(0,1)-sGARCH(1,1) dist = std  Done
## Estimating ARMA(1,0)-sGARCH(1,1) dist = std  Done
## Estimating ARMA(1,1)-sGARCH(1,1) dist = std  Done
## Estimating ARMA(0,0)-sGARCH(1,1) dist = sstd Done
## Estimating ARMA(0,1)-sGARCH(1,1) dist = sstd Done
## Estimating ARMA(1,0)-sGARCH(1,1) dist = sstd Done
## Estimating ARMA(1,1)-sGARCH(1,1) dist = sstd Done
## Estimating ARMA(0,0)-sGARCH(1,1) dist = jsu  Done
## Estimating ARMA(0,1)-sGARCH(1,1) dist = jsu  Done
## Estimating ARMA(1,0)-sGARCH(1,1) dist = jsu  Done
## Estimating ARMA(1,1)-sGARCH(1,1) dist = jsu  Done
## Estimating ARMA(0,0)-sGARCH(1,1) dist = snorm    Done
## Estimating ARMA(0,1)-sGARCH(1,1) dist = snorm    Done
## Estimating ARMA(1,0)-sGARCH(1,1) dist = snorm    Done
## Estimating ARMA(1,1)-sGARCH(1,1) dist = snorm    Done
## Estimating ARMA(0,0)-eGARCH(1,1) dist = norm Done
## Estimating ARMA(0,1)-eGARCH(1,1) dist = norm Done
## Estimating ARMA(1,0)-eGARCH(1,1) dist = norm Done
## Estimating ARMA(1,1)-eGARCH(1,1) dist = norm Done
## Estimating ARMA(0,0)-eGARCH(1,1) dist = std  Done
## Estimating ARMA(0,1)-eGARCH(1,1) dist = std  Done
## Estimating ARMA(1,0)-eGARCH(1,1) dist = std  Done
## Estimating ARMA(1,1)-eGARCH(1,1) dist = std  Done
## Estimating ARMA(0,0)-eGARCH(1,1) dist = sstd Done
## Estimating ARMA(0,1)-eGARCH(1,1) dist = sstd Done
## Estimating ARMA(1,0)-eGARCH(1,1) dist = sstd Done
## Estimating ARMA(1,1)-eGARCH(1,1) dist = sstd Done
## Estimating ARMA(0,0)-eGARCH(1,1) dist = jsu  Done
## Estimating ARMA(0,1)-eGARCH(1,1) dist = jsu  Done
## Estimating ARMA(1,0)-eGARCH(1,1) dist = jsu  Done
## Estimating ARMA(1,1)-eGARCH(1,1) dist = jsu  Done
## Estimating ARMA(0,0)-eGARCH(1,1) dist = snorm    Done
## Estimating ARMA(0,1)-eGARCH(1,1) dist = snorm    Done
## Estimating ARMA(1,0)-eGARCH(1,1) dist = snorm    Done
## Estimating ARMA(1,1)-eGARCH(1,1) dist = snorm    Done
## Estimating ARMA(0,0)-gjrGARCH(1,1) dist = norm   Done
## Estimating ARMA(0,1)-gjrGARCH(1,1) dist = norm   Done
## Estimating ARMA(1,0)-gjrGARCH(1,1) dist = norm   Done
## Estimating ARMA(1,1)-gjrGARCH(1,1) dist = norm   Done
## Estimating ARMA(0,0)-gjrGARCH(1,1) dist = std    Done
## Estimating ARMA(0,1)-gjrGARCH(1,1) dist = std    Done
## Estimating ARMA(1,0)-gjrGARCH(1,1) dist = std    Done
## Estimating ARMA(1,1)-gjrGARCH(1,1) dist = std    Done
## Estimating ARMA(0,0)-gjrGARCH(1,1) dist = sstd   Done
## Estimating ARMA(0,1)-gjrGARCH(1,1) dist = sstd   Done
## Estimating ARMA(1,0)-gjrGARCH(1,1) dist = sstd   Done
## Estimating ARMA(1,1)-gjrGARCH(1,1) dist = sstd   Done
## Estimating ARMA(0,0)-gjrGARCH(1,1) dist = jsu    Done
## Estimating ARMA(0,1)-gjrGARCH(1,1) dist = jsu    Done
## Estimating ARMA(1,0)-gjrGARCH(1,1) dist = jsu    Done
## Estimating ARMA(1,1)-gjrGARCH(1,1) dist = jsu    Done
## Estimating ARMA(0,0)-gjrGARCH(1,1) dist = snorm  Done
## Estimating ARMA(0,1)-gjrGARCH(1,1) dist = snorm  Done
## Estimating ARMA(1,0)-gjrGARCH(1,1) dist = snorm  Done
## Estimating ARMA(1,1)-gjrGARCH(1,1) dist = snorm  Done
# Tabla con algunos de los modelos que se probaron 
tab_out <- out$tab_out
print(tab_out)
## # A tibble: 60 Ɨ 9
##    lag_ar lag_ma lag_arch lag_garch   AIC   BIC type_model type_dist model_name 
##     <int>  <int>    <int>     <int> <dbl> <dbl> <chr>      <chr>     <chr>      
##  1      0      0        1         1 -8.22 -8.21 sGARCH     norm      ARMA(0,0)+…
##  2      0      1        1         1 -8.06 -8.04 sGARCH     norm      ARMA(0,1)+…
##  3      1      0        1         1 -8.06 -8.05 sGARCH     norm      ARMA(1,0)+…
##  4      1      1        1         1 -8.07 -8.05 sGARCH     norm      ARMA(1,1)+…
##  5      0      0        1         1 -8.96 -8.94 sGARCH     std       ARMA(0,0)+…
##  6      0      1        1         1 -9.00 -8.98 sGARCH     std       ARMA(0,1)+…
##  7      1      0        1         1 -9.00 -8.98 sGARCH     std       ARMA(1,0)+…
##  8      1      1        1         1 -9.00 -8.98 sGARCH     std       ARMA(1,1)+…
##  9      0      0        1         1 -8.96 -8.94 sGARCH     sstd      ARMA(0,0)+…
## 10      0      1        1         1 -9.00 -8.97 sGARCH     sstd      ARMA(0,1)+…
## # … with 50 more rows

Veamos cuales son los mejores modelos

models_names <- unique(tab_out$model_name)
best_models <- c(tab_out$model_name[which.min(tab_out$AIC)],
                 tab_out$model_name[which.min(tab_out$BIC)])
print(best_models)
## [1] "ARMA(1,0)+eGARCH(1,1) jsu" "ARMA(1,0)+eGARCH(1,1) jsu"

Basado en el criterio de información bayesiano, tomaremos el mejor modelo que minimice el error. Veamos también la media y la varianza de las observaciones del modelo para ver el comportamiento de la volatilidad del activo.

La vida media es el tiempo necesario para que la volatilidad retroceda hasta la mitad de su media.

# Define el modelo que minimiza el BIC
best_spec = ugarchspec(variance.model = list(model =  out$best_bic$type_model, 
                                             garchOrder = c(out$best_bic$lag_arch,
                                                            out$best_bic$lag_garch)),
                       mean.model = list(armaOrder = c(out$best_bic$lag_ar, 
                                                       out$best_bic$lag_ma)),
                       distribution = out$best_bic$type_dist)

# Implementa el modelo definido
my_best_garch <- ugarchfit(spec = best_spec, 
                           data = ticker$daily.vol)
my_best_garch
## 
## *---------------------------------*
## *          GARCH Model Fit        *
## *---------------------------------*
## 
## Conditional Variance Dynamics    
## -----------------------------------
## GARCH Model  : eGARCH(1,1)
## Mean Model   : ARFIMA(1,0,0)
## Distribution : jsu 
## 
## Optimal Parameters
## ------------------------------------
##         Estimate  Std. Error  t value Pr(>|t|)
## mu      0.000038    0.000079  0.48754  0.62588
## ar1     0.204939    0.024561  8.34404  0.00000
## omega  -1.820766    0.339620 -5.36118  0.00000
## alpha1  0.036437    0.039423  0.92426  0.35535
## beta1   0.840377    0.029770 28.22878  0.00000
## gamma1  0.585894    0.076075  7.70149  0.00000
## skew   -0.023512    0.042223 -0.55685  0.57763
## shape   0.962326    0.043921 21.91033  0.00000
## 
## Robust Standard Errors:
##         Estimate  Std. Error  t value Pr(>|t|)
## mu      0.000038    0.000084  0.45394  0.64987
## ar1     0.204939    0.027765  7.38112  0.00000
## omega  -1.820766    0.657374 -2.76976  0.00561
## alpha1  0.036437    0.050160  0.72641  0.46759
## beta1   0.840377    0.058029 14.48192  0.00000
## gamma1  0.585894    0.103818  5.64349  0.00000
## skew   -0.023512    0.043068 -0.54593  0.58512
## shape   0.962326    0.056193 17.12545  0.00000
## 
## LogLikelihood : 7591.454 
## 
## Information Criteria
## ------------------------------------
##                     
## Akaike       -9.0118
## Bayes        -8.9860
## Shibata      -9.0119
## Hannan-Quinn -9.0023
## 
## Weighted Ljung-Box Test on Standardized Residuals
## ------------------------------------
##                         statistic  p-value
## Lag[1]                      2.177 0.140045
## Lag[2*(p+q)+(p+q)-1][2]     2.950 0.038836
## Lag[4*(p+q)+(p+q)-1][5]     7.732 0.009847
## d.o.f=1
## H0 : No serial correlation
## 
## Weighted Ljung-Box Test on Standardized Squared Residuals
## ------------------------------------
##                         statistic p-value
## Lag[1]                  0.0004606  0.9829
## Lag[2*(p+q)+(p+q)-1][5] 0.4554646  0.9643
## Lag[4*(p+q)+(p+q)-1][9] 0.8470126  0.9917
## d.o.f=2
## 
## Weighted ARCH LM Tests
## ------------------------------------
##             Statistic Shape Scale P-Value
## ARCH Lag[3]  0.004266 0.500 2.000  0.9479
## ARCH Lag[5]  0.758186 1.440 1.667  0.8058
## ARCH Lag[7]  0.838919 2.315 1.543  0.9383
## 
## Nyblom stability test
## ------------------------------------
## Joint Statistic:  2.1745
## Individual Statistics:              
## mu     0.13110
## ar1    0.15956
## omega  1.13329
## alpha1 0.20405
## beta1  1.10336
## gamma1 0.07803
## skew   0.14518
## shape  0.83654
## 
## Asymptotic Critical Values (10% 5% 1%)
## Joint Statistic:          1.89 2.11 2.59
## Individual Statistic:     0.35 0.47 0.75
## 
## Sign Bias Test
## ------------------------------------
##                    t-value   prob sig
## Sign Bias          1.44859 0.1476    
## Negative Sign Bias 0.08853 0.9295    
## Positive Sign Bias 0.19831 0.8428    
## Joint Effect       2.38828 0.4958    
## 
## 
## Adjusted Pearson Goodness-of-Fit Test:
## ------------------------------------
##   group statistic p-value(g-1)
## 1    20     20.42     0.369571
## 2    30     53.24     0.003953
## 3    40     52.16     0.077330
## 4    50     75.02     0.009794
## 
## 
## Elapsed time : 0.4382138
plot(my_best_garch, which="all")
## 
## please wait...calculating quantiles...

#Parametros del mejor modelo
infocriteria(my_best_garch)
##                       
## Akaike       -9.011829
## Bayes        -8.986026
## Shibata      -9.011874
## Hannan-Quinn -9.002272
#Unconditional mean, media si se mantienen los mismo niveles del pasado 
uncmean(my_best_garch) 
## [1] 3.829966e-05
#Unconditional variance: omega/(alpha1 + beta1), varianza si se mantienen los mismo niveles del pasado
uncvariance(my_best_garch) 
## [1] 1.112088e-05
#persistence: alpha1 + beta1, Si es 1 = persiste, si es 0 = no persiste
persistence(my_best_garch) 
## [1] 0.8403773
# half-life: No. dĆ­as donde la volatilidad revierte 50%
halflife(my_best_garch)
## [1] 3.985796

Hagamos un pronostico de la volatilidad en los proximos 10 dĆ­as. El cono amarillo ilustra el rango en que se pronostica estarĆ” la volatilidad.

# Predicción 10 días hacia adelante
garch.forecast = ugarchforecast(my_best_garch, n.ahead = 10)
garch.forecast
## 
## *------------------------------------*
## *       GARCH Model Forecast         *
## *------------------------------------*
## Model: eGARCH
## Horizon: 10
## Roll Steps: 0
## Out of Sample: 0
## 
## 0-roll forecast [T0=2022-12-30]:
##          Series    Sigma
## T+1  -1.270e-04 0.002750
## T+2   4.431e-06 0.002836
## T+3   3.136e-05 0.002910
## T+4   3.688e-05 0.002974
## T+5   3.801e-05 0.003029
## T+6   3.824e-05 0.003076
## T+7   3.829e-05 0.003116
## T+8   3.830e-05 0.003150
## T+9   3.830e-05 0.003179
## T+10  3.830e-05 0.003203
# Visualizar el forecast
par(mfrow=c(2,1))
plot(garch.forecast, which=1)
plot(garch.forecast, which=3)

Simulación de Montecarlo

Con nuestro modelo, ahora haremos mil simulaciones del proximo aƱo para ver cuƔl seria el comportamiento del precio. Marcaremos algunos niveles de confianza del modelo en 1%, 5%, 25%, 50%, 75%, 95%, 99%.

days.ahead = 365
n.sim <- 1000
garch.sim <- matrix(nrow = days.ahead, ncol=n.sim) #Matriz de las simulaciones
set.seed(123)
#Empecemos las simulaciones
for(i in 1:n.sim){
  p.sim = ugarchsim(my_best_garch, n.sim=days.ahead, startMethod="sample")
  garch.sim[,i] <- p.sim@simulation$seriesSim
}

#Convertimos a df
garch.sim <- as.data.frame(garch.sim)

# Agregamos y determinamos los percentiles correspondientes
garch.sim$Q25 <- NA
garch.sim$Q05 <- NA
garch.sim$Q01 <- NA
garch.sim$Q75 <- NA
garch.sim$Q95 <- NA
garch.sim$Q99 <- NA
garch.sim$Q01 <- apply(garch.sim[,2:(ncol(garch.sim)-6)], FUN = function(x){quantile(na.omit(x),0.01)}, MARGIN = 1)
garch.sim$Q05 <- apply(garch.sim[,2:(ncol(garch.sim)-6)], FUN = function(x){quantile(na.omit(x),0.05)}, MARGIN = 1)
garch.sim$Q25 <- apply(garch.sim[,2:(ncol(garch.sim)-6)], FUN = function(x){quantile(na.omit(x),0.25)}, MARGIN = 1)
garch.sim$Q75 <- apply(garch.sim[,2:(ncol(garch.sim)-6)], FUN = function(x){quantile(na.omit(x),0.75)}, MARGIN = 1)
garch.sim$Q95 <- apply(garch.sim[,2:(ncol(garch.sim)-6)], FUN = function(x){quantile(na.omit(x),0.95)}, MARGIN = 1)
garch.sim$Q99 <- apply(garch.sim[,2:(ncol(garch.sim)-6)], FUN = function(x){quantile(na.omit(x),0.99)}, MARGIN = 1)

Veamos nuestras percentiles de corte y la simulación, asi podemos comparar con la muestra Out of Sample para determinar en que escenario del mercado estamos.

##                 Q01      Q05      Q25         mean      Q75      Q95      Q99
## 2023-12-16 46.64312 81.88670 94.26395 2.516871e+16 106.4918 120.3343 146.9976
## 2023-12-17 46.68024 81.96934 94.32296 2.520902e+16 106.5084 120.5762 146.8188
## 2023-12-18 46.93437 81.90934 94.37117 2.522905e+16 106.4801 120.4104 147.0254
## 2023-12-19 46.88501 82.31160 94.36260 2.521798e+16 106.6137 120.3122 147.2256
## 2023-12-20 45.96637 82.71885 94.29029 2.520326e+16 106.4699 120.0142 147.3843
## 2023-12-21 45.82483 82.76551 94.29489 2.523283e+16 106.4415 120.0391 147.1165
## 2023-12-22 45.81703 82.39409 94.30924 2.523370e+16 106.3941 120.1943 146.9367
## 2023-12-23 45.63811 82.25303 94.40409 2.518668e+16 106.2963 120.2572 146.8846
## 2023-12-24 45.60923 82.27281 94.24579 2.512664e+16 106.3513 120.2911 146.8801
## 2023-12-25 45.60184 82.28922 94.29892 2.514545e+16 106.2896 120.1014 147.1561
## 2023-12-26 45.66139 82.38704 94.28718 2.510144e+16 106.3568 120.0865 146.8618
## 2023-12-27 45.67012 82.28125 94.17652 2.507112e+16 106.3139 120.2915 146.6147
## 2023-12-28 45.75546 81.98214 94.20344 2.516144e+16 106.2790 120.4861 146.9333
## 2023-12-29 45.82064 81.84285 94.19516 2.515754e+16 106.3500 120.4728 147.1810
## 2023-12-30 45.91247 81.62431 94.13334 2.507118e+16 106.3289 120.5874 147.0965

Hacemos una revisión hacia atras del modelo y lo recalibramos para mejorar el modelo. El backtest también nos ayuda a verificar si las observaciones de los fueron mÔs que las que predecía el modelo, nos da una prueba de hipotesis del modelo y nos dice si los excesos son dependientes o sucesivos, uno tras otro.

garch.roll = ugarchroll(best_spec, ticker$daily.vol, n.ahead=1,
                        forecast.length = 1000, solver = "hybrid",
                        refit.every=30, refit.window="moving", VaR.alpha=c(0.01, 0.05, 0.95, 0.99)) #Predecimos un dia hacia adelante, recalibrando el modelo cada 30 dias.

# Prueba de modelo
report(garch.roll, type="VaR")
## VaR Backtest Report
## ===========================================
## Model:               eGARCH-jsu
## Backtest Length: 1000
## Data:                
## 
## ==========================================
## alpha:               1%
## Expected Exceed: 10
## Actual VaR Exceed:   10
## Actual %:            1%
## 
## Unconditional Coverage (Kupiec)
## Null-Hypothesis: Correct Exceedances
## LR.uc Statistic: 0
## LR.uc Critical:      3.841
## LR.uc p-value:       1
## Reject Null:     NO
## 
## Conditional Coverage (Christoffersen)
## Null-Hypothesis: Correct Exceedances and
##                  Independence of Failures
## LR.cc Statistic: 0.202
## LR.cc Critical:      5.991
## LR.cc p-value:       0.904
## Reject Null:     NO

Veamos las mƩtricas del GARCH Roll

report(garch.roll, type="fpm")
## 
## GARCH Roll Mean Forecast Performance Measures
## ---------------------------------------------
## Model        : eGARCH
## No.Refits    : 34
## No.Forecasts: 1000
## 
##         Stats
## MSE 0.0000308
## MAE 0.0023180
## DAC 0.5640000

Veamos la grƔfica de los excesos

a <- rolling.var.backtest(rolling.garch.object=garch.roll, symbol=symbol, return.series=ticker$daily.vol, n=1000)


# static VaR. LT
asset1.ret <- ticker$daily.vol
var05.breach <- which(garch.roll@forecast$VaR$realized < as.numeric(quantile(asset1.ret, 0.05)))
var01.breach <- which(garch.roll@forecast$VaR$realized < as.numeric(quantile(asset1.ret, 0.01)))
var95.breach <- which(garch.roll@forecast$VaR$realized > as.numeric(quantile(asset1.ret, 0.95)))
var99.breach <- which(garch.roll@forecast$VaR$realized > as.numeric(quantile(asset1.ret, 0.99)))
rows <- index(garch.roll@forecast$VaR[var95.breach,'realized'])

forecast.VaR <- as.data.frame(garch.roll@forecast$VaR)
forecast.VaR$var05.breach <- ifelse(forecast.VaR$realized < garch.roll@forecast$VaR$`alpha(5%)`,1,0)
forecast.VaR$var01.breach <- ifelse(forecast.VaR$realized < garch.roll@forecast$VaR$`alpha(1%)`,1,0)
forecast.VaR$var95.breach <- ifelse(forecast.VaR$realized > garch.roll@forecast$VaR$`alpha(95%)`,1,0)
forecast.VaR$var99.breach <- ifelse(forecast.VaR$realized > garch.roll@forecast$VaR$`alpha(99%)`,1,0)
forecast.VaR$nextday.ret <- lead(forecast.VaR$realized)

breach.days <- forecast.VaR[forecast.VaR$var95.breach == 1,]
breach.return <- forecast.VaR[forecast.VaR$var95.breach == 1,'nextday.ret']
breach.return <- cumprod(1 + na.omit(breach.return))

forecast.VaR <- as.xts(forecast.VaR)
forecast.density <- as.data.frame(garch.roll@forecast$density)
forecast.density <- as.xts(forecast.density)
forecast.density$price <- as.numeric(tail(asset1.ret,1000))

# see consecutive breaches
forecast.VaR <- a[[1]]
forecast.VaR1 <- as.data.frame(a[[1]][a[[1]]$var95.breach==1,])
forecast.VaR1$date <- ymd(rownames(forecast.VaR1))
forecast.VaR1$days.between <- NA
for(i in 2:nrow(forecast.VaR1)){
  forecast.VaR1$days.between[i] <- forecast.VaR1$date[i] - forecast.VaR1$date[i-1]
}

# Plot 1. VaR Only
par(mfrow=c(1,1), mar=c(3,3,3,3))
rolling.plot <- plot(forecast.VaR$realized, ylim=c(min(forecast.VaR$`alpha(1%)` -0.01), max(forecast.VaR$`alpha(99%)` +0.01)), main=paste(symbol,"t+1 Rolling eGARCH VaR Estimation w/ 30-Day Refit"), type="h", col="black", lwd=0.50)
rolling.plot <- lines(forecast.VaR$`alpha(5%)`, on=1, col="orange", lty=1, lwd=0.75)
rolling.plot <- lines(forecast.VaR$`alpha(1%)`, on=1, col="red", lty=1, lwd=1)
rolling.plot <- lines(forecast.VaR$`alpha(95%)`, on=1, col="orange", lty=1, lwd=0.75)
rolling.plot <- lines(forecast.VaR$`alpha(99%)`, on=1, col="red", lty=1, lwd=1)
rolling.plot <- points(forecast.VaR[forecast.VaR$var99.breach==1,5], col="red", cex=1.25, pch=16)
rolling.plot <- points(forecast.VaR[forecast.VaR$var01.breach==1,1], col="red", cex=1.25, pch=16)
rolling.plot <- addLegend("bottomleft", legend.names=c(paste("05pctile: Current", round(last(forecast.VaR$`alpha(5%)`)*100,2),"%"), 
                                                       paste("01pctile: Current", round(last(forecast.VaR$`alpha(1%)`)*100,2),"%")), lty=c(1,1), col=c("orange","red"), bty="n", y.intersp = 0.75)
rolling.plot <- addLegend("topleft", legend.names=c(paste("99pctile: Current", round(last(forecast.VaR$`alpha(99%)`)*100,2),"%"), 
                                                    paste("95pctile: Current", round(last(forecast.VaR$`alpha(95%)`)*100,2),"%")), lty=c(1,1), col=c("red","orange"), bty="n", y.intersp = 0.75)

plot(rolling.plot)