Introduction

Dans ce document nous appliquons les résultats de la première partie à deux produits dérivés : un future sur le S&P500 et un call européen sur le S&P500. L’objectif est de calculer les mesures de risque pour ces produits selon les différentes méthodologies présentées et d’en analyser l’efficacité au regard du P&L effectif réalisé. Nous noterons dans la suite la VaR d’un actif comme variation de la valeur de l’actif (log-rendement), elle sera donc notée négativement sans perte de généralité.

Les données que nous allons utiliser dans cette seconde partie de notre étude sont les prix quotidiens ajustés de clôture (‘Adj. Close Price’) du S&P500 sur la période allant de Septembre 2000 à fin Août 2020. Le set de données sera divisé en deux plages temporelles. La première, de Septembre 2000 à fin Août 2015 servira d’historique pour la détermination des meilleurs modèles a priori. La seconde, de Septembre 2015 à fin Août 2020 servira pour le backtesting de nos modèles. Notre étude revient donc à considérer que nous sommes actuellement à la fin Août 2015 et que nous établissons des modèles que l’on backtestera avec les P&L réalisés à partir de Septembre 2015.

1. Import des données

Ci-dessous, nous importons les prix quotidiens de clôture ajustés sur les 20 ans d’historique (2000-2020). Nous formons ensuite les deux sets de données :

# Import des données du S&P500 depuis Yahoo finance et calcul des rendements
prices <- read.zoo("data/^GSPC.csv", index.column = 1,
                   header=T, sep=";", format = "%d/%m/%Y")
returns<-log(prices/stats::lag(prices,-1))

# Prix et rendements pour le choix du modèle (2000-2015)
prices_md<- as.xts(prices)["/20150831"]
returns_md<- as.xts(returns)["/20150831"]

# Prix et rendements pour le backtesting (2015-2020)
prices_bt<- as.xts(prices)["20150901/20200831"]
returns_bt<- as.xts(returns)["20150901/20200831"]

rm(prices, returns)

2. Première analyse des données

Dans cette section nous débuterons l’analyse des données du S&P500. Commencons tout d’abord par afficher l’évolution des prix sur la période.

# Affichage des prix quotidiens du S&P500 sur la période (2000-2015)
plot(as.zoo(prices_md), main="Évolution des prix du S&P500", xlab="Date", ylab="Prix de clôture ajusté", col="red")

Nous aperçevons que cette série temporelle possède des clusters de prix hauts et bas à certaines périodes. Le prix évolue au cours du temps et est donc volatil. La présence de clusters semble indiquer un phénomène de corrélation entre les prix : à un prix haut succèdera probablement un prix haut. Voyons ce qu’il en est à l’aide des fonctions d’autocorrélation (ACF et PACF) :

# Affichage du graphique ACF et PACF des prix du S&P500
par(mar=c(3,3,3,0))
acf(prices_md, main="ACF des prix du S&P500 (2000-2015)")

pacf(prices_md, main="PACF des prix du S&P500 (2000-2015)")

Nous observons que l’ACF diminue lentement vers zéro, ce qui signifie que les chocs affectent le processus de facon permanente. Nous pouvons donc conclure que la série n’est pas stationnaire. Nous nous intéresserons donc aux rendements journaliers (log-rendements) du S&P500.

3. Première analyse des log-rendements

Affichons l’évolution des rendements sur la période :

plot(as.zoo(returns_md), main="Rendements du S&P500 (2000-2015)", xlab="Année", ylab="Rendement")

On observe des périodes de volatilité extrême nottament vers 2002, 2008-2009 et 2010-2012. Néanmoins, les rendements restent autour de la valeur zéro ce qui indique une certaine stationnarité a priori. Intéréssons nous à l’autocorrélation des rendements avec les graphiques ACF et PACF.

par(mar=c(3,3,3,0))
acf(returns_md, main="ACF des rendements du S&P500 (2000-2015)")

pacf(returns_md, main="PACF des rendements du S&P500 (2000-2015)")

Les rendements ne semblent pas être fortement corrélés mais il existe tout de même une relation non négligeable entre eux (Lag =1, 2, 5 par exemple) dont il conviendra de tenir compte dans la suite.

3.1. Étude de la normalité des rendements

Analysons les statistiques usuelles de notre échantillon de rendements.

# Calcul des statistiques de l'échantillon
st.sp<-basicStats(returns_md)
colnames(st.sp)<-"Valeur de paramètres"
p.table(st.sp, "Statistiques des rendements du S\\&P500 (2000-2015)")
Statistiques des rendements du S&amp;P500 (2000-2015)
Valeur de paramètres
nobs 3771.000000
NAs 0.000000
Minimum -0.094695
Maximum 0.109572
  1. Quartile
-0.005371
  1. Quartile
0.005832
Mean 0.000069
Median 0.000564
Sum 0.261957
SE Mean 0.000206
LCL Mean -0.000334
UCL Mean 0.000473
Variance 0.000160
Stdev 0.012641
Skewness -0.180626
Kurtosis 8.466389

Nous observons que la moyenne des rendements est très proche de zéro et que la distribution des rendements a un kurtosis très élevé (ce qui indique des queues de distribution épaisses). La distribution possède, par ailleurs, un skew négatif ce qui signifie que la queue gauche de la distribution est plus étalée. Affichons l’histogramme des rendements, la densité empirique associée et la densité gaussienne afin d’observer graphiquement les variations :

hist(returns_md, xlab="Rendements du S&P500 (2000-2015)", ylab="Densité", freq=FALSE, main="Histogramme des rendements du S&P500 (2000-2015)", ylim=c(0,55), breaks=20)
lines(density(returns_md), col="blue")
legend("right", legend=c("Densité normale", "Densité empirique"),
       col=c("red", "blue"), lty=1, cex=0.8)
curve(dnorm(x, mean=mean(returns_md), sd=sd(returns_md)), add=TRUE, col="red")

L’allure de la coubre semble correspondre plus ou moins à celle d’une loi normale bien qu’effectivement, les valeurs autour de la moyenne semblent plus fréquentes que le prévoit la distribution gaussienne. Intéréssons nous aux quantiles de la distribution empirique face à ceux de la loi normale.

qqnorm(returns_md, main="Comparaison des quantiles empriques et gaussiens", xlab="Quantiles gaussiens", ylab="Quantiles empiriques")
qqline(returns_md, col=2)

D’après l’histogramme et le QQ-Plot, on conclut que les rendements possèdent une distribution proche d’une gaussienne mais avec des queues plus épaisses à chaque extrémité et des valeurs plus fréquemment proches de zéro. Afin d’étudier la corrélation entre les rendements, que l’on entrevoyait à la lumière du graphique de l’ACF, nous étudions ci-dessous le carré des rendements et la valeur absolue des rendements.

3.2. Étude du carré des rendements et de la valeur absolue des rendements

Commencons tout d’abord par afficher les rendements au carré et les rendements absolus.

plot(as.zoo(abs(returns_md)), main="Évolution de la valeur absolue des rendements", xlab="Année", ylab="Valeur absolue des rendements")

plot(as.zoo(returns_md^2), main="Évolution du carré des rendements", xlab="Année", ylab="Valeur du carré des rendements")

On observe sur ces graphiques, surtout le second, que des clusters de volatilité sont notables. Par exemple, une forte volatilité autour de 2008. Ceci semble indiquer que la volatilité conditionnelle n’est pas constante : un choc de volatilité a un impact sur la volatilité lors de petites périodes de temps. L’hypothèse consistant a prendre une volatilité constante est donc déclinée. Il faudra utiliser des modèles à volatilité stochastique. Recherchons donc la présence d’un effet ARCH dans les deux séries de données. Pour ce faire, traçons les graphiques ACF et PACF du carré des rendements et de la valeur absolue des rendements :

par(mar=c(3,3,3,0))
acf(abs(returns_md), main="ACF de la valeur absolue des rendements")

pacf(abs(returns_md), main="PACF de la valeur absolue des rendements")

acf(returns_md^2, main="ACF du carré des rendements")

pacf(returns_md^2, main="PACF du carré des rendements")

D’après les graphiques précédents, il est évident que la valeur absolue des rendements et le carré des rendements sont fortement autocorrélés. Les rendements ont ainsi une forte dépendance non-linéaire. Vérifions à nouveau cela grâce à un test de Ljung-Box. Dans un premier temps sur la valeur absolue des rendements :

Box.test(abs(returns_md), lag=2, type="Ljung")
## 
##  Box-Ljung test
## 
## data:  abs(returns_md)
## X-squared = 712.88, df = 2, p-value < 2.2e-16
Box.test(abs(returns_md), lag=4, type="Ljung")
## 
##  Box-Ljung test
## 
## data:  abs(returns_md)
## X-squared = 1432.5, df = 4, p-value < 2.2e-16
Box.test(abs(returns_md), lag=6, type="Ljung")
## 
##  Box-Ljung test
## 
## data:  abs(returns_md)
## X-squared = 2301.9, df = 6, p-value < 2.2e-16

Puis sur le carré des rendements :

Box.test(returns_md^2, lag=2, type="Ljung")
## 
##  Box-Ljung test
## 
## data:  returns_md^2
## X-squared = 734.83, df = 2, p-value < 2.2e-16
Box.test(returns_md^2, lag=4, type="Ljung")
## 
##  Box-Ljung test
## 
## data:  returns_md^2
## X-squared = 1240.3, df = 4, p-value < 2.2e-16
Box.test(returns_md^2, lag=6, type="Ljung")
## 
##  Box-Ljung test
## 
## data:  returns_md^2
## X-squared = 2016.6, df = 6, p-value < 2.2e-16

Les tests de Ljung-Box ci-dessus montrent tous que l’hypothèse nulle de non-autocorrélation est fortement rejetée dans les deux cas (carré et valeur absolue). Ceci indique un effet ARCH sur les rendements du S&P500. C’est-à-dire que la variance des rendements est conditionnelle et autorégréssive. L’idée d’utiliser des modèles à volatilité ARCH est donc bien fondée. Nous nous intéresserons donc dans la suite de notre étude aux modèles ARMA(p,q)-GARCH(p’,q’)/eGARCH(p’,q’) dont la loi des erreurs reste à déterminer.

4. Choix du meilleur modèle de type ARMA-GARCH et de la loi des erreurs

Le choix des meilleurs paramètres de modèle se réalise sur la base du critère d’information d’Akaike (AIC). Le critère d’information d’Akaike (AIC) est une méthode mathématique permettant d’évaluer la mesure dans laquelle un modèle correspond aux données dont il est issu. En statistiques, l’AIC est utilisé pour comparer différents modèles possibles et déterminer lequel est le mieux adapté aux données. L’AIC est calculé à partir :

Le modèle le mieux adapté, selon l’AIC, est celui qui explique le plus grand nombre de variations avec le moins de variables indépendantes possibles. Plus l’AIC est petit et plus le modèle est adapté.

4.1. Choix des ordres p et q pour la composante ARMA(p,q)

Nous allons calculer l’AIC pour chacun des modèles et choisir celui qui semble le meilleur. Pour ce faire nous allons tester les valeurs p et q allant de 0 à 4 :

aic.arma<-matrix(nrow=5,ncol=5)
colnames(aic.arma)<-c("p = 0","p = 1","p = 2","p = 3","p = 4")
rownames(aic.arma)<-c("q = 0","q = 1","q = 2","q = 3","q = 4")

for (p in 0:4) for (q in 0:4) {
  if ( p == 0 && q == 0) {
    next
  }
  arimaFit = tryCatch( arima(returns_md, order=c(p, 0, q)), error=function( err ) FALSE, warning=function( err ) FALSE )
  if( !is.logical( arimaFit ) ) {
    aic.arma[q+1,p+1]<-AIC(arimaFit)
  } else {
    next
  }
}
p.table(aic.arma, "AIC des modèles ARMA(p,q)")
AIC des modèles ARMA(p,q)
p = 0 p = 1 p = 2 p = 3 p = 4
q = 0 NA -22282.29 -22293.22 -22292.27 -22290.99
q = 1 -22285.17 -22290.54 -22292.20 -22290.35 -22293.33
q = 2 -22292.44 -22291.61 -22291.30 -22288.22 -22295.05
q = 3 -22291.55 -22289.66 NA -22312.13 -22310.31
q = 4 -22291.13 -22292.89 -22298.88 -22310.21 -22308.27
rm(aic.arma, arimaFit)

D’après le tableau précédent, le meilleur modèle semble être ARMA(3,3) car il a le AIC le plus bas (-22312,13).

4.2. Choix du meilleur modèle avec volatilité GARCH

Dans cette section nous allons définir une liste de modèles qui paraissent être de bons candidats avant de calculer pour chacun leur AIC. Nous choisirons parmi ceux-ci celui avec l’AIC le plus bas. Par ailleur, un autre facteur pesant dans notre décision sera le comportement des résidus ou erreurs (autocorrélation ou non) et le Goodness-of-fit test qui permettront respectivement de savoir, si le caractère ARCH a été entièrement abosrbé par le modèle (plus d’autocorrélation des résidus) et si les résidus suivent la loi des erreurs définie préalablement. Les modèles auxquels nous nous intérésserons sont les suivants :

  • ARMA(3,3)-GARCH(p’,q’) avec erreurs normales
  • ARMA(3,3)-GARCH(p’,q’) avec erreurs student-t
  • ARMA(3,3)-GARCH(p’,q’) avec erreurs skewed student-t
  • ARMA(3,3)-GARCH(p’,q’) avec erreurs ged (general excess distribution)
  • ARMA(3,3)-GARCH(p’,q’) avec erreurs sged (skewed ged)

Ci-dessous un tableau des AIC des différents modèles avec p’ et q’ variant de 1 à 2 :

distribution<-list("norm", "std", "sstd", "ged", "sged")
names(distribution)<-c("normales", "student-t", "skewed student-t", "ged", "skewed ged")
aic.garch<-data.frame(matrix(ncol = 1, nrow = 20))
j=1
for (p in 1:2){
  for (q in 1:2){
    for (d in 1:5){
      lg<-paste("ARMA(3,3)-GARCH(", p, ",", q, ") avec erreurs ", names(distribution)[d], sep="")
      rownames(aic.garch)[j]<-lg
      spec<-ugarchspec(variance.model = list(model='sGARCH', garchOrder=c(p,q)), mean.model=list(armaOrder=c(3, 3), include.mean=T), distribution.model =distribution[[d]] )
      model = tryCatch( infocriteria(ugarchfit(spec, returns_md))[1], error=function( err ) FALSE, warning=function( err ) FALSE )
      if(! is.logical(model)){
        aic.garch[j,1]<-model
      }
      else{
        aic.garch[j,1]<-"Pas de convergence"
      }
      j=j+1
    }
  }
}
colnames(aic.garch)<-"Valeur de l'AIC"
p.table(aic.garch, "AIC des modèles ARMA(3,3)-GARCH(p',q')")
AIC des modèles ARMA(3,3)-GARCH(p’,q’)
Valeur de l’AIC
ARMA(3,3)-GARCH(1,1) avec erreurs normales -6.385217277782
ARMA(3,3)-GARCH(1,1) avec erreurs student-t -6.41245710270281
ARMA(3,3)-GARCH(1,1) avec erreurs skewed student-t -6.42341885522205
ARMA(3,3)-GARCH(1,1) avec erreurs ged Pas de convergence
ARMA(3,3)-GARCH(1,1) avec erreurs skewed ged -6.43148697406279
ARMA(3,3)-GARCH(1,2) avec erreurs normales -6.38533343504641
ARMA(3,3)-GARCH(1,2) avec erreurs student-t -6.413277839403
ARMA(3,3)-GARCH(1,2) avec erreurs skewed student-t -6.42675940965929
ARMA(3,3)-GARCH(1,2) avec erreurs ged -6.41800517712916
ARMA(3,3)-GARCH(1,2) avec erreurs skewed ged -6.43095660513104
ARMA(3,3)-GARCH(2,1) avec erreurs normales -6.39087307202355
ARMA(3,3)-GARCH(2,1) avec erreurs student-t -6.4232661333643
ARMA(3,3)-GARCH(2,1) avec erreurs skewed student-t -6.43116937741502
ARMA(3,3)-GARCH(2,1) avec erreurs ged -6.42421646891744
ARMA(3,3)-GARCH(2,1) avec erreurs skewed ged -6.43778003864725
ARMA(3,3)-GARCH(2,2) avec erreurs normales -6.39090900554299
ARMA(3,3)-GARCH(2,2) avec erreurs student-t -6.41949564268906
ARMA(3,3)-GARCH(2,2) avec erreurs skewed student-t -6.43067360723962
ARMA(3,3)-GARCH(2,2) avec erreurs ged Pas de convergence
ARMA(3,3)-GARCH(2,2) avec erreurs skewed ged -6.43734829885591
rm(spec, lg, model, distribution, aic.garch)

D’après le tableau ci-dessus, le meilleur modèle est ARMA(3,3)-GARCH(2,1) avec erreurs skewed-ged avec un AIC à -6.43778. Étudions plus en détail ce modèle en affichant l’ensemble des données obtenues :

spec<-ugarchspec(variance.model=list(model="sGARCH" , garchOrder=c(2,1)),
          mean.model=list(armaOrder=c(3, 3), include.mean=T),
          distribution.model="sged")
garch21<-ugarchfit(spec, returns_md)
garch21
## 
## *---------------------------------*
## *          GARCH Model Fit        *
## *---------------------------------*
## 
## Conditional Variance Dynamics    
## -----------------------------------
## GARCH Model  : sGARCH(2,1)
## Mean Model   : ARFIMA(3,0,3)
## Distribution : sged 
## 
## Optimal Parameters
## ------------------------------------
##         Estimate  Std. Error    t value Pr(>|t|)
## mu      0.000415    0.000105    3.94399 0.000080
## ar1     0.095894    0.011969    8.01169 0.000000
## ar2    -0.557020    0.021102  -26.39601 0.000000
## ar3     0.682000    0.011160   61.11102 0.000000
## ma1    -0.176276    0.006979  -25.25922 0.000000
## ma2     0.513474    0.020389   25.18343 0.000000
## ma3    -0.751036    0.005215 -144.00842 0.000000
## omega   0.000002    0.000002    1.27088 0.203770
## alpha1  0.007830    0.014992    0.52227 0.601482
## alpha2  0.116543    0.029521    3.94786 0.000079
## beta1   0.860202    0.026363   32.62965 0.000000
## skew    0.860564    0.018364   46.86189 0.000000
## shape   1.399892    0.053332   26.24857 0.000000
## 
## Robust Standard Errors:
##         Estimate  Std. Error   t value Pr(>|t|)
## mu      0.000415    0.000115   3.59585 0.000323
## ar1     0.095894    0.019362   4.95266 0.000001
## ar2    -0.557020    0.028644 -19.44611 0.000000
## ar3     0.682000    0.016286  41.87668 0.000000
## ma1    -0.176276    0.007749 -22.74907 0.000000
## ma2     0.513474    0.022619  22.70075 0.000000
## ma3    -0.751036    0.007965 -94.29631 0.000000
## omega   0.000002    0.000008   0.26303 0.792529
## alpha1  0.007830    0.020871   0.37515 0.707549
## alpha2  0.116543    0.107822   1.08089 0.279748
## beta1   0.860202    0.116188   7.40356 0.000000
## skew    0.860564    0.033180  25.93633 0.000000
## shape   1.399892    0.138655  10.09622 0.000000
## 
## LogLikelihood : 12151.43 
## 
## Information Criteria
## ------------------------------------
##                     
## Akaike       -6.4378
## Bayes        -6.4163
## Shibata      -6.4378
## Hannan-Quinn -6.4301
## 
## Weighted Ljung-Box Test on Standardized Residuals
## ------------------------------------
##                          statistic p-value
## Lag[1]                       3.884 0.04874
## Lag[2*(p+q)+(p+q)-1][17]    15.370 0.00000
## Lag[4*(p+q)+(p+q)-1][29]    21.471 0.02054
## d.o.f=6
## H0 : No serial correlation
## 
## Weighted Ljung-Box Test on Standardized Squared Residuals
## ------------------------------------
##                          statistic p-value
## Lag[1]                       5.303 0.02128
## Lag[2*(p+q)+(p+q)-1][8]      8.348 0.07999
## Lag[4*(p+q)+(p+q)-1][14]    11.153 0.12947
## d.o.f=3
## 
## Weighted ARCH LM Tests
## ------------------------------------
##             Statistic Shape Scale P-Value
## ARCH Lag[4]   0.02901 0.500 2.000  0.8648
## ARCH Lag[6]   1.73649 1.461 1.711  0.5515
## ARCH Lag[8]   2.92895 2.368 1.583  0.5568
## 
## Nyblom stability test
## ------------------------------------
## Joint Statistic:  64.9286
## Individual Statistics:               
## mu      0.55266
## ar1     0.06092
## ar2     0.20706
## ar3     0.04285
## ma1     0.03847
## ma2     0.18062
## ma3     0.07511
## omega  10.50900
## alpha1  0.17469
## alpha2  0.27752
## beta1   0.33099
## skew    0.72458
## shape   0.65129
## 
## Asymptotic Critical Values (10% 5% 1%)
## Joint Statistic:          2.89 3.15 3.69
## Individual Statistic:     0.35 0.47 0.75
## 
## Sign Bias Test
## ------------------------------------
##                    t-value      prob sig
## Sign Bias            2.310 2.094e-02  **
## Negative Sign Bias   1.158 2.469e-01    
## Positive Sign Bias   2.562 1.044e-02  **
## Joint Effect        37.819 3.087e-08 ***
## 
## 
## Adjusted Pearson Goodness-of-Fit Test:
## ------------------------------------
##   group statistic p-value(g-1)
## 1    20     24.73       0.1696
## 2    30     30.60       0.3846
## 3    40     44.44       0.2531
## 4    50     53.91       0.2920
## 
## 
## Elapsed time : 4.282763
rm(spec)

On note que la distribution des erreurs correspond bien à ce que l’on attend car les p-values du test Goodness-of-fit sont supérieures à 0,05. Mais en ce qui concerne les résidus, on observe toujours un comportement ARCH. Ceci signifie que malgré l’ordre (2,1) de la composante GARCH, une autocorrélation persiste. Nous allons essayer d’y remédier en passant à un autre modèle de volatilité : eGARCH ou GARCH exponentiel. Il se note mathématiquement comme suit : \[\log\sigma_{t}^2=\omega+\sum_{k=1}^{p}(\alpha_k\epsilon_{t-k}+\gamma_k(|\epsilon_{t-k}|-E(|\epsilon_{t-k}|)))+\sum_{k=1}^{q}\beta_{k}\log\sigma_{t-k}^{2}\\\] Avec \(\sigma_{t}^{2}\) la variance conditionnelle, \(\omega\), \(\beta\), \(\alpha\) et \(\gamma\) des coefficients correspondant respectivement à :

  • la log-variance non-conditionnelle
  • l’auto-régression de la log-variance
  • l’impact des chocs précédents sur la log-variance
  • l’impact de la valeur absolue des chocs précédents sur la log-variance

Dans l’équation précédente \(\epsilon_{t}=\sigma_{t}z_{t}\) et \(z_{t}\) correspond à la loi des erreurs. La présence des deux coefficients \(\alpha\) et \(\gamma\) permet de tenir compte de l’asymétrie de l’impact des chocs (erreurs ou résidus) sur la log-variance. En effet un choc négatif et positif peuvent entretenir des relations distinctes avec la log-variance. Par exemple un choc négatif peut avoir un impact plus fort qu’un choc positif : ce qui signifie que les marchés sont plus sensibles à une baisse qu’à une hausse.

4.3. Choix du meilleur modèle avec volatilité eGARCH

Nous allons reprendre la méthodologie précédente avec les modèles de volatilité eGARCH. C’est-à-dire que nous allons tester les modèles et comparer leur AIC.

distribution<-list("norm", "std", "sstd", "ged", "sged")
names(distribution)<-c("normales", "student-t", "skewed student-t", "ged", "skewed ged")
aic.egarch<-data.frame(matrix(ncol = 1, nrow = 20))
j=1
for (p in 1:2){
  for (q in 1:2){
    for (d in 1:5){
      lg<-paste("ARMA(3,3)-eGARCH(", p, ",", q, ") avec erreurs ", names(distribution)[d], sep="")
      rownames(aic.egarch)[j]<-lg
      spec<-ugarchspec(variance.model = list(model='eGARCH', garchOrder=c(p,q)), mean.model=list(armaOrder=c(3, 3), include.mean=T), distribution.model =distribution[[d]] )
      model= tryCatch(infocriteria(ugarchfit(spec, returns_md))[1], error=function( err ) FALSE, warning=function( err ) FALSE)
      if(!is.logical(model)){
        aic.egarch[j,1]<-model
      }
      else{
        aic.egarch[j,1]<-"Pas de convergence"
      }
      j=j+1
    }
  }
}
colnames(aic.egarch)<-"Valeur de l'AIC"
p.table(aic.egarch, "AIC des modèles ARMA(3,3)-eGARCH(p',q')")
AIC des modèles ARMA(3,3)-eGARCH(p’,q’)
Valeur de l’AIC
ARMA(3,3)-eGARCH(1,1) avec erreurs normales -6.429423
ARMA(3,3)-eGARCH(1,1) avec erreurs student-t -6.453156
ARMA(3,3)-eGARCH(1,1) avec erreurs skewed student-t -6.465592
ARMA(3,3)-eGARCH(1,1) avec erreurs ged -6.455587
ARMA(3,3)-eGARCH(1,1) avec erreurs skewed ged -6.469677
ARMA(3,3)-eGARCH(1,2) avec erreurs normales -6.428911
ARMA(3,3)-eGARCH(1,2) avec erreurs student-t -6.450146
ARMA(3,3)-eGARCH(1,2) avec erreurs skewed student-t -6.463021
ARMA(3,3)-eGARCH(1,2) avec erreurs ged -6.453905
ARMA(3,3)-eGARCH(1,2) avec erreurs skewed ged -6.469147
ARMA(3,3)-eGARCH(2,1) avec erreurs normales -6.444099
ARMA(3,3)-eGARCH(2,1) avec erreurs student-t -6.465958
ARMA(3,3)-eGARCH(2,1) avec erreurs skewed student-t -6.479528
ARMA(3,3)-eGARCH(2,1) avec erreurs ged -6.466031
ARMA(3,3)-eGARCH(2,1) avec erreurs skewed ged -6.483143
ARMA(3,3)-eGARCH(2,2) avec erreurs normales -6.443893
ARMA(3,3)-eGARCH(2,2) avec erreurs student-t -6.465681
ARMA(3,3)-eGARCH(2,2) avec erreurs skewed student-t -6.480653
ARMA(3,3)-eGARCH(2,2) avec erreurs ged -6.465722
ARMA(3,3)-eGARCH(2,2) avec erreurs skewed ged -6.482890
rm(aic.egarch, distribution, spec, model, lg)

On obtient pour le modèle ARMA(3,3)-eGARCH(2,1) avec erreurs skewed ged, un AIC à -6.483143, ce qui en fait le meilleur. Intéréssons nous plus en détail aux résultats fournis par ce modèle.

spec=ugarchspec(variance.model=list(model="eGARCH" , garchOrder=c(2,1)),
          mean.model=list(armaOrder=c(3, 3), include.mean=T),
          distribution.model="sged")
egarch21<-ugarchfit(spec, returns_md)
egarch21
## 
## *---------------------------------*
## *          GARCH Model Fit        *
## *---------------------------------*
## 
## Conditional Variance Dynamics    
## -----------------------------------
## GARCH Model  : eGARCH(2,1)
## Mean Model   : ARFIMA(3,0,3)
## Distribution : sged 
## 
## Optimal Parameters
## ------------------------------------
##         Estimate  Std. Error     t value Pr(>|t|)
## mu      0.000172    0.000126     1.36596  0.17195
## ar1    -0.076891    0.007442   -10.33254  0.00000
## ar2    -0.664495    0.008422   -78.89622  0.00000
## ar3     0.511021    0.006501    78.60207  0.00000
## ma1     0.009105    0.010607     0.85842  0.39066
## ma2     0.628368    0.012437    50.52313  0.00000
## ma3    -0.568775    0.009775   -58.18813  0.00000
## omega  -0.193140    0.003119   -61.92515  0.00000
## alpha1 -0.266763    0.018735   -14.23853  0.00000
## alpha2  0.132320    0.011574    11.43240  0.00000
## beta1   0.979285    0.000019 51751.21266  0.00000
## gamma1 -0.161230    0.026508    -6.08240  0.00000
## gamma2  0.290467    0.020521    14.15428  0.00000
## skew    0.843722    0.016783    50.27280  0.00000
## shape   1.488384    0.049117    30.30261  0.00000
## 
## Robust Standard Errors:
##         Estimate  Std. Error     t value Pr(>|t|)
## mu      0.000172    0.000175     0.98409 0.325070
## ar1    -0.076891    0.003770   -20.39447 0.000000
## ar2    -0.664495    0.027003   -24.60791 0.000000
## ar3     0.511021    0.006298    81.13721 0.000000
## ma1     0.009105    0.009148     0.99529 0.319597
## ma2     0.628368    0.031492    19.95307 0.000000
## ma3    -0.568775    0.006801   -83.63296 0.000000
## omega  -0.193140    0.004113   -46.96386 0.000000
## alpha1 -0.266763    0.038770    -6.88068 0.000000
## alpha2  0.132320    0.045662     2.89779 0.003758
## beta1   0.979285    0.000048 20307.01569 0.000000
## gamma1 -0.161230    0.077390    -2.08335 0.037219
## gamma2  0.290467    0.021058    13.79344 0.000000
## skew    0.843722    0.021008    40.16217 0.000000
## shape   1.488384    0.057855    25.72596 0.000000
## 
## LogLikelihood : 12238.97 
## 
## Information Criteria
## ------------------------------------
##                     
## Akaike       -6.4831
## Bayes        -6.4583
## Shibata      -6.4832
## Hannan-Quinn -6.4743
## 
## Weighted Ljung-Box Test on Standardized Residuals
## ------------------------------------
##                          statistic p-value
## Lag[1]                      0.5529  0.4571
## Lag[2*(p+q)+(p+q)-1][17]    8.9173  0.5468
## Lag[4*(p+q)+(p+q)-1][29]   15.0814  0.4632
## d.o.f=6
## H0 : No serial correlation
## 
## Weighted Ljung-Box Test on Standardized Squared Residuals
## ------------------------------------
##                          statistic p-value
## Lag[1]                    0.001326  0.9710
## Lag[2*(p+q)+(p+q)-1][8]   1.365782  0.9422
## Lag[4*(p+q)+(p+q)-1][14]  4.222228  0.8583
## d.o.f=3
## 
## Weighted ARCH LM Tests
## ------------------------------------
##             Statistic Shape Scale P-Value
## ARCH Lag[4]  0.001483 0.500 2.000  0.9693
## ARCH Lag[6]  0.188978 1.461 1.711  0.9710
## ARCH Lag[8]  0.783332 2.368 1.583  0.9535
## 
## Nyblom stability test
## ------------------------------------
## Joint Statistic:  5.0759
## Individual Statistics:              
## mu     0.45526
## ar1    0.05284
## ar2    0.24938
## ar3    0.05605
## ma1    0.03149
## ma2    0.22912
## ma3    0.10355
## omega  0.31444
## alpha1 1.08159
## alpha2 0.80323
## beta1  0.30304
## gamma1 0.31294
## gamma2 0.14120
## skew   0.76517
## shape  0.51606
## 
## Asymptotic Critical Values (10% 5% 1%)
## Joint Statistic:          3.26 3.54 4.07
## Individual Statistic:     0.35 0.47 0.75
## 
## Sign Bias Test
## ------------------------------------
##                    t-value   prob sig
## Sign Bias           0.2335 0.8154    
## Negative Sign Bias  0.7214 0.4707    
## Positive Sign Bias  0.6889 0.4909    
## Joint Effect        1.3396 0.7198    
## 
## 
## Adjusted Pearson Goodness-of-Fit Test:
## ------------------------------------
##   group statistic p-value(g-1)
## 1    20     9.764       0.9585
## 2    30    25.714       0.6407
## 3    40    34.091       0.6931
## 4    50    38.613       0.8567
## 
## 
## Elapsed time : 6.514485
rm(spec)

Ce modèle satisfait à toutes nos exigences. En effet, les résidus ne semblent pas présenter de comportement ARCH contrairement au résultat obtenu avec un modèle GARCH classique. De plus, le test de Goodness-of-Fit ne permet pas de rejeter l’hypothèse de la distribution skewed ged.

4.4. Modèle retenu

4.4.1. Comparaison des AIC

D’après ce qui a été réalisé précédemment nous comparons les AIC des deux modèles ARMA(3,3)-GARCH(2,1) sged et ARMA(3,3)-eGARCH(2,1) sged :

comp<-matrix(nrow = 2, ncol = 1)
comp[1,1]<-infocriteria(garch21)[1]
comp[2,1]<-infocriteria(egarch21)[1]
comp<-data.frame(comp)
colnames(comp)<-"Valeur de l'AIC"
rownames(comp)<-c("ARMA(3,3)-GARCH(2,1) sged", "ARMA(3,3)-eGARCH(2,1) sged")
p.table(comp, "Comparaison des AIC")
Comparaison des AIC
Valeur de l’AIC
ARMA(3,3)-GARCH(2,1) sged -6.437780
ARMA(3,3)-eGARCH(2,1) sged -6.483143
rm(comp, garch21)

Le meilleur modèle est d’assez loin le modèle à volatilité eGARCH. C’est celui que nous retiendrons. Intéréssons nous maintenant à ses coefficients.

egarch21@fit$coef
##            mu           ar1           ar2           ar3           ma1 
##  0.0001718297 -0.0768908552 -0.6644951238  0.5110208741  0.0091052680 
##           ma2           ma3         omega        alpha1        alpha2 
##  0.6283683601 -0.5687746472 -0.1931395105 -0.2667631153  0.1323196434 
##         beta1        gamma1        gamma2          skew         shape 
##  0.9792846055 -0.1612302291  0.2904668375  0.8437220862  1.4883835679

Ce qui correspond au modèle suivant : \[r_t=0,000172-0,07689 r_{t-1}-0,6645 r_{t-2}+0,5110 r_{t-3}+0,0091 \epsilon_{t-1}+0,6284 \epsilon_{t-2}-0,5688 \epsilon_{t-3}+\epsilon_t\] \[\epsilon_{t}=\sigma_t z_t\] \[\log\sigma_t^2=-0,1931-0,2667 \epsilon_{t-1}-0,1612(|\epsilon_{t-1}|-E(|\epsilon_{t-1}|))\] \[+0,1323 \epsilon_{t-2}+0,2905(|\epsilon_{t-2}|-E(|\epsilon_{t-2}|))+0,9793\log\sigma_{t-1}^2\] \[\textrm{avec } z_t \textrm{ qui suit une loi générale des excès décalée avec } \xi=0,844 \textrm{ et } \nu=1,489.\]

4.4.2. Analyse des paramètres du modèle

4.4.2.1. Analyse de la significativité des coefficients du modèle

Nous allons étudier, dans cette section, la significativité des coefficients estimés pour notre modèle. Pour savoir si un coefficient est significatif, c’est-à-dire s’il ne vaut pas zéro, on utilisera la t-value qui est une mesure de l’écart entre le paramètre estimé et 0. Comme ce test repose sur une loi de student-t qui converge vers une loi normale centrée réduite, on utilise la règle du pouce qui nous dit que si la t-value est supérieure à 2 en valeur absolue (car 95% des valeurs de la loi normale se situent dans un intervalle de longueur 4\(\sigma\) centré autour de la moyenne i.e. leur valeur absolue est inférieure à 2\(\sigma\)=2) alors le paramètre est significatif. Ceci signifie donc que le vrai paramètre devrait être non-nul.

p.table(egarch21@fit$matcoef, "Paramètres du modèle")
Paramètres du modèle
Estimate Std. Error t value Pr(>|t|)
mu 0.0001718 0.0001258 1.3659574 0.1719523
ar1 -0.0768909 0.0074416 -10.3325422 0.0000000
ar2 -0.6644951 0.0084224 -78.8962168 0.0000000
ar3 0.5110209 0.0065014 78.6020686 0.0000000
ma1 0.0091053 0.0106070 0.8584175 0.3906619
ma2 0.6283684 0.0124372 50.5231294 0.0000000
ma3 -0.5687746 0.0097748 -58.1881296 0.0000000
omega -0.1931395 0.0031189 -61.9251486 0.0000000
alpha1 -0.2667631 0.0187353 -14.2385314 0.0000000
alpha2 0.1323196 0.0115741 11.4324014 0.0000000
beta1 0.9792846 0.0000189 51751.2126568 0.0000000
gamma1 -0.1612302 0.0265076 -6.0824042 0.0000000
gamma2 0.2904668 0.0205215 14.1542781 0.0000000
skew 0.8437221 0.0167829 50.2727985 0.0000000
shape 1.4883836 0.0491173 30.3026085 0.0000000
rm(egarch21)

En procédant de la sorte, on observe que tous les coefficients sont significatifs (|t-value|>2) à l’exception de \(\mu\) et de ma1. Pour le premier cela n’a pas d’importance car ce terme sera présent dans tous les modèles ARMA-GARCH. En ce qui concerne le paramètre ma1, nous voyons qu’il est peu significatif mais comme les paramètres ma2 et ma3 le sont on ne diminuera pas l’ordre du modèle. Intéréssons nous maintenant à une augmentation des ordres de notre modèle.

4.4.2.2. Overfitting

L’idée dans cette section est de procéder à l’inverse de ce qui a été fait précédemment, en s’intéressant aux modèles avec des ordres supérieurs et de déterminer si l’ajout de paramètres supplémentaires rend le modèle plus précis ou s’il le complexifie inutilement. Comme d’habitude nous comparons les modèles à l’aide de leur AIC :

aic.egarch<-data.frame(matrix(ncol = 1, nrow = 16))
j=1
for (p in 0:1){
  for (q in 0:1){
    for (r in 0:1){
      for (s in 0:1){
        lg<-paste("ARMA(", 3+p , ",", 3+q ,")-eGARCH(", 2+r, ",", 1+s, ") avec erreurs skewed-ged", sep="")
        rownames(aic.egarch)[j]<-lg
        spec<-ugarchspec(variance.model = list(model='eGARCH', garchOrder=c(2+r,1+s)),mean.model=list(armaOrder=c(3+p, 3+q), include.mean=T), distribution.model="sged")
        model = tryCatch(infocriteria(ugarchfit(spec, returns_md))[1], error=function( err ) FALSE, warning=function( err ) FALSE)
        if(!is.logical(model)){
          aic.egarch[j,1]<-model
        }
        else{
          aic.egarch[j,1]<-"Pas de convergence"
        }
        j=j+1
      }  
    }
  }
}
colnames(aic.egarch)<-"Valeur de l'AIC"
p.table(aic.egarch, "AIC des modèles overfittés")
AIC des modèles overfittés
Valeur de l’AIC
ARMA(3,3)-eGARCH(2,1) avec erreurs skewed-ged -6.483143
ARMA(3,3)-eGARCH(2,2) avec erreurs skewed-ged -6.482890
ARMA(3,3)-eGARCH(3,1) avec erreurs skewed-ged -6.488760
ARMA(3,3)-eGARCH(3,2) avec erreurs skewed-ged -6.488299
ARMA(3,4)-eGARCH(2,1) avec erreurs skewed-ged -6.482826
ARMA(3,4)-eGARCH(2,2) avec erreurs skewed-ged -6.483889
ARMA(3,4)-eGARCH(3,1) avec erreurs skewed-ged -6.487060
ARMA(3,4)-eGARCH(3,2) avec erreurs skewed-ged -6.488018
ARMA(4,3)-eGARCH(2,1) avec erreurs skewed-ged -6.482912
ARMA(4,3)-eGARCH(2,2) avec erreurs skewed-ged -6.482652
ARMA(4,3)-eGARCH(3,1) avec erreurs skewed-ged -6.488526
ARMA(4,3)-eGARCH(3,2) avec erreurs skewed-ged -6.488068
ARMA(4,4)-eGARCH(2,1) avec erreurs skewed-ged -6.482557
ARMA(4,4)-eGARCH(2,2) avec erreurs skewed-ged -6.485586
ARMA(4,4)-eGARCH(3,1) avec erreurs skewed-ged -6.488111
ARMA(4,4)-eGARCH(3,2) avec erreurs skewed-ged -6.487650
rm(spec, lg, model, aic.egarch)

Nous obtenons ci-dessus les AIC des modèles overfittés. Parmi les 16 modèles, 10 ont un meilleur AIC que le modèle retenu (-6,483143). Nous allons donc effectuer un test sur la significativité de leurs paramètres, afin de voir si les paramètres ajoutés ne sont pas statistiquement négligeables : ce qui revient à dire que l’on peut considérer qu’ils sont égaux à 0, et donc se ramener à un modèle plus simple.

models <- data.frame( c(3, 3, 3, 1),
                      c(3, 3, 3, 2),
                      c(3, 4, 2, 2),
                      c(3, 4, 3, 1),
                      c(3, 4, 3, 2),
                      c(4, 3, 3, 1),
                      c(4, 3, 3, 2),
                      c(4, 4, 2, 2),
                      c(4, 4, 3, 1),
                      c(4, 4, 3, 2))

models.names<-list("ARMA(3,3)-eGARCH(3,1) sged", "ARMA(3,3)-eGARCH(3,2) sged", "ARMA(3,4)-eGARCH(2,2) sged" , "ARMA(3,4)-eGARCH(3,1) sged", "ARMA(3,4)-eGARCH(3,2) sged", "ARMA(4,3)-eGARCH(3,1) sged",
                   "ARMA(4,3)-eGARCH(3,2) sged", "ARMA(4,4)-eGARCH(2,2) sged", "ARMA(4,4)-eGARCH(3,1) sged", "ARMA(4,4)-eGARCH(3,2) sged")
sgn.tbl<-data.frame(matrix(nrow=10, ncol=1))
for (l in 1:10){
  nosign<-""
  spec=ugarchspec(variance.model=list(model="eGARCH" , garchOrder=c(models[3,l],models[4,l])),
          mean.model=list(armaOrder=c(models[1,l], models[2,l]), include.mean=T),
          distribution.model="sged")
  model<-ugarchfit(spec, returns_md)
  tvalues<-model@fit$matcoef[,3]
  for (i in 2:length(tvalues)){
    if (abs(tvalues[i])<2){
      nosign<-paste(nosign, names(tvalues)[i], "=", round(tvalues[i],2), sep=" ")
    }
  }
  sgn.tbl[l,1]<-nosign
  rownames(sgn.tbl)[l]<-models.names[l]
}
colnames(sgn.tbl)<-"Paramètres non significatifs"
p.table(sgn.tbl, "Recherche des paramètres non significatifs des modèles overfittés")
Recherche des paramètres non significatifs des modèles overfittés
Paramètres non significatifs
ARMA(3,3)-eGARCH(3,1) sged alpha2 = 0.22 gamma3 = 1.08
ARMA(3,3)-eGARCH(3,2) sged alpha2 = 0.32 gamma3 = 0.97
ARMA(3,4)-eGARCH(2,2) sged ma4 = 1.03
ARMA(3,4)-eGARCH(3,1) sged ma4 = 0.83 alpha2 = 0.2 gamma3 = 1.05
ARMA(3,4)-eGARCH(3,2) sged ar1 = 1.51 ma4 = -0.71 alpha2 = 0.31 gamma3 = 0.92
ARMA(4,3)-eGARCH(3,1) sged ar4 = -0.39 alpha2 = 0.21 gamma3 = 1.03
ARMA(4,3)-eGARCH(3,2) sged ar4 = -1.23 alpha2 = 0.31 gamma3 = 0.92
ARMA(4,4)-eGARCH(2,2) sged beta2 = -1.81
ARMA(4,4)-eGARCH(3,1) sged alpha2 = 0.23 gamma3 = 1.03
ARMA(4,4)-eGARCH(3,2) sged alpha2 = 0.34
rm(models, models.names, spec, nosign, model, tvalues, sgn.tbl)

On constate que dans tous les modèles overfittés, certains paramètres deviennent non significatifs ce qui signifie que ces modèles sont simplifiables et ils tombent donc dans le piège de l’overfitting : l’ajout de paramètres supplémentaires qui compliquent le modèle à outrance. Le modèle ARMA(3,3)-eGARCH(2,1) sged est donc retenu pour sa relative simplicité (par rapport aux modèles ci-dessus) qui permettra de meilleures performances (temps de calcul) lors des phases de simulation.

5. Extreme Value Theory (EVT)

5.1. Méthode des maxima par bloc (BMM)

5.1.1. Choix de la taille des blocs et des paramètres de la GEV : \(\xi\), \(\mu\) et \(\sigma\)

L’idée de cette section est de découper les pertes (l’opposé des rendements) en blocs, et de prendre en compte les maxima sur chacun de ces blocs. La théorie nous permet ensuite d’utiliser la convergence de la loi des maxima vers une loi GEV dont les paramètres sont à déterminer. L’enjeu est dans un premier temps de choisir la taille des blocs sur lesquels prendre les maxima. Pour ceci nous essaierons plusieurs tailles de blocs et nous intéresserons à la convergence vers une loi GEV grâce à des tests statistiques. Nous recherchons des maxima qui sont à la fois stationnaires et dont la distribution correspond bien à une GEV. Les tests utilisés seront le test KPSS de stationnarité et le test KS (Kolmogorov-Smirnov) de Goodness-of-Fit.

# Calculons les pertes
loss_md<- -returns_md
# Création du tableau contenant les tests pour chaque taille de bloc
sizes<-c(seq(20,50, by=2))
res<-data.frame(matrix(nrow=length(sizes),ncol=5))
colnames(res)<-c("p-value KPSS", "p-value KS", "Param. de localisation", "Param. de forme", "Param. d'échelle")

# Boucle pour réaliser les tests sur chaque taille de bloc
j=1
for (i in sizes){
  # Maximum sur les blocs de i-journée
  returns_per_block<-blockMaxima(loss_md, block=i)
  
  # KPSS test : H0 -> stationnaire donc p-value>0.05 recherchée
  kpss<-round(as.double(kpss.test(returns_per_block, null="Trend")["p.value"]),3)
  
  # Fit d'une GEV pour la taille de bloc i-journée
  fit<-fgev(returns_per_block)
  
  # Paramètres obtenus pour la distribution GEV
  mu<-round(as.double(fit$param['loc']),3)
  xi<-round(as.double(fit$param['shape']),3)
  beta<-round(as.double(fit$param['scale']),3)

  # Test Goodness of Fit
  simgev<-gevSim(model=list(mu=fit$param['loc'], xi=fit$param['shape'], beta=fit$param['scale']), 10000)
  ks<-round(as.double(ks.test(returns_per_block, simgev)["p.value"]),3)
  
  # Ajout des tests au tableau des résultats
  res[j,]<-c(kpss,ks,mu,xi,beta)
  rownames(res)[j]<-paste("Taille de bloc :", i)
  j=j+1
}
p.table(res, "Tests statistiques sur les différentes tailles de bloc", scale=TRUE)
Tests statistiques sur les différentes tailles de bloc
p-value KPSS p-value KS Param. de localisation Param. de forme Param. d’échelle
Taille de bloc : 20 0.010 0.960 0.015 0.169 0.008
Taille de bloc : 22 0.019 0.869 0.015 0.269 0.007
Taille de bloc : 24 0.023 0.910 0.015 0.303 0.007
Taille de bloc : 26 0.019 0.702 0.016 0.212 0.008
Taille de bloc : 28 0.029 0.966 0.016 0.200 0.008
Taille de bloc : 30 0.044 0.757 0.016 0.292 0.007
Taille de bloc : 32 0.038 0.987 0.017 0.217 0.008
Taille de bloc : 34 0.050 0.790 0.017 0.231 0.008
Taille de bloc : 36 0.066 0.885 0.017 0.311 0.007
Taille de bloc : 38 0.059 0.978 0.018 0.254 0.008
Taille de bloc : 40 0.039 0.988 0.018 0.260 0.008
Taille de bloc : 42 0.056 0.952 0.018 0.254 0.008
Taille de bloc : 44 0.063 0.939 0.018 0.268 0.008
Taille de bloc : 46 0.047 0.846 0.019 0.272 0.008
Taille de bloc : 48 0.070 0.978 0.019 0.267 0.008
Taille de bloc : 50 0.072 0.868 0.019 0.283 0.008
rm(sizes, res, returns_per_block, kpss, fit, mu, xi, beta, simgev, ks)

D’après le tableau précédent, nous allons retenir une taille de bloc de 42, ce qui donne bien :

  • une p-value>0.05 au test KPSS de stationnarité

  • une p-value>0.05 au test de Kolmogorov-Smirnov de Goodness-of-Fit vis a vis de la GEV

On obtient donc un modèle qui consiste à dire que la pire perte sur 42 jours suit une loi GEV de paramètres :

  • localisation = \(\mu\) = 0,0181513

  • forme = \(\xi\) = 0,2539079

  • échelle = \(\sigma\) = 0,0079701

5.1.2. Diagnostique graphique de la loi des extrêmes estimée (GEV)

Analysons graphiquement la distribution estimée face à la distribution empirique des maxima pour une taille de bloc de 42 jours.

# Obtention des maxima
k=42
endpts <- endpoints(loss_md, "days") # indices de fin pour chaque jour
endpts <- endpts[seq(1, length(endpts), by = k)] # indices de fin pour 42 jours
maxima<- period.apply(loss_md, INDEX = endpts, FUN = max) # Maximum sur ces périodes
maxima<-data.frame(maxima)

# Estimation des paramètres
fitgev<-fgev(maxima$maxima)

# Affichage des différents graphiques obtenus permettant d'interpréter les données
plot(fitgev, which=1, xlab="Empirique", ylab="Modèle GEV estimé", main="Graphique de comparaison des probabilités (PP-plot)", ci=0.05)
legend("topleft", c("Empirique"), pch = c(4))
legend("bottomright", c("Théorique GEV", "Intervalle de confiance"), lty = 1:2)

plot(fitgev, which=2, xlab="Empirique", ylab="Modèle GEV estimé", main="Graphique de comparaison des quantiles (QQ-plot)", ci=0.05)
legend("topleft", c("Empirique"), pch = c(4))
legend("bottomright", c("Théorique GEV", "Intervalle de confiance"), lty = 1:2)

plot(fitgev, which=3, xlab="Quantile", ylab="Densité", main="Densité théorique GEV vs empirique des maxima", ci=0.05)
legend("topright", c("GEV estimée","Empirique"), lty=1:2)

plot(fitgev, which=4, xlab="Période de rendement", ylab="Niveau de rendement", main="Graphique du niveau de rendement", ci=0.05)
legend("topleft", c("Empirique"), pch = c(4))
legend("topright", c("Théorique GEV", "Intervalle de confiance"), lty = 1:2)

rm(endpts, maxima)

Les graphiques ci-dessus permettent de constater que la distribtuion GEV estimée est assez proche de la distribution empirique, ce qui nous donne donc une bonne approximation de la distribution des extrema du S&P500 sur 42 jours. On remarque que le paramètre \(\xi\) est estimé à 0,2539079, ce qui donne bien une distribution de Frechet comme nous l’attendions.

5.2. Méthode des peaks over treshold (POT)

Dans le cadre de la théorie des valeurs extrêmes, une autre méthode de modélisation est préferée à celle présentée ci-dessus. Elle modélise la distribution des données (pertes) au-dessus d’un certain seuil (“peaks-over-treshold” ou POT) et non plus les maxima sur une période donnée. L’avantage est de disposer de plus de données et donc d’une estimation plus précise. Pour estimer ces valeurs, au-dessus d’un seuil, c’est la distribution de Pareto généralisée qui est utilisée. On la note GPD en anglais ou DPG en français. Ceci requiert donc au préalable le choix d’un seuil noté \(u\) à partir duquel prendre en compte les données.

5.2.1. Choix du seuil \(u\)

Recherchons le seuil \(u\) adéquat. Dans un premier temps traçons la fonction des excès en moyenne :

mrlplot(loss_md, c(0, 0.06), main="Graphique de la moyenne en excès", xlab="Seuil", ylab="Moyenne en excès")
legend("topleft", c("Moyenne en excès", "Intervalle de confiance"), lty=c(1,3))

Pour nous aider, nous disposons également de la courbe de choix du seuil (“treshold choice plot”) qui donne une estimation des paramètres de la loi de Pareto en fonction du seuil choisi (\(\xi\) le paramètre de forme et \(\sigma\) celui d’échelle) :

u=0.032
tcplot(loss_md, c(0, 0.06), which = 1, xlab="Seuil", ylab="Paramètre d'échelle")
title(main="Paramètre d'échelle en fonction du seuil")
abline(v=u, col=2)

tcplot(loss_md, c(0, 0.06), which = 2, xlab="Seuil", ylab="Paramètre de forme")
title(main="Paramètre de forme en fonction du seuil")
abline(v=u, col=2)

D’après les graphiques précédents nous choisissons un seuil \(u\) d’une valeur de 0,032 soit 3,2%. Nous pouvons maintenant estimer les paramètres de la loi de Pareto qui correspond à la distribution des pertes au-delà de ce seuil.

5.2.2. Estimation des paramètres de la distribution de Pareto (DPG) : \(\xi\) et \(\sigma\)

fitpot<-fpot(loss_md, threshold=u)
fitpot
## 
## Call: fpot(x = loss_md, threshold = u) 
## Deviance: -342.2858 
## 
## Threshold: 0.032 
## Number Above: 53 
## Proportion Above: 0.0141 
## 
## Estimates
##     scale      shape  
## 1.457e-02  2.216e-13  
## 
## Standard Errors
##    scale     shape  
## 0.003149  0.147559  
## 
## Optimization Information
##   Convergence: successful 
##   Function Evaluations: 21 
##   Gradient Evaluations: 1

L’estimation des paramètres fournit les valeurs suivantes :

  • Paramètre de forme \(\xi = 2,216\times 10^{-13} \approx 0\)

  • Paramètre d’échelle \(\sigma = 0,01457\)

Il y a au total 53 observations au-dessus de ce seuil parmi les pertes historiques du S&P 500 de 2000 à 2015.

Voyons ce que ce choix de paramètre donne graphiquement :

plot(fitpot, which=1, xlab="Modèle estimé DPG", ylab="Empirique", main="PP-plot pertes empiriques au-delà de 0,032 vs DPG")
legend("topleft", c("Empirique"), pch = c(4))
legend("bottomright", c("Théorique DPG", "Intervalle de confiance"), lty = 1:2)

plot(fitpot, which=2, xlab="Modèle estimé DPG", ylab="Empirique", main="QQ-plot pertes empiriques au-delà de 0,032 vs DPG")
legend("topleft", c("Empirique"), pch = c(4))
legend("bottomright", c("Théorique DPG", "Intervalle de confiance"), lty = 1:2)

plot(fitpot, which=3, xlab="Pertes", ylab="Densité", main="Densité empirique vs théorique DPG")
legend("topright", c("DPG estimée","Empirique"), lty=1:2)

plot(fitpot, which=4, xlab="Période de rendement", ylab="Niveau de perte", main="Pertes empiriques au-delà de 0,032 vs DPG")
legend("topleft", c("Empirique"), pch = c(4))
legend("bottomright", c("Théorique DPG", "Intervalle de confiance"), lty = 1:2)

Le modèle obtenu semble plutôt bon car la densité de Pareto épouse mieux les données empiriques que la GEV estimée par la méthode des maxima par blocs.

6. Obtention des rendements des dérivés sur la période de backtesting et des données nécessaires aux calculs de VaR

6.1. Calcul des rendements du future sur le S&P 500 avec maturité constante de 30 jours

Afin d’obtenir les prix du future hypothétique de maturité constante 30 jours, deux problèmes se posent :

  • Les futures côtés ont des durées de vie courtes, il n’existe donc pas d’historique du prix d’un unique contrat sur 5 ans

  • Le prix d’un future évolue à mesure qu’il approche de sa maturité, ce qui ne convient pas à notre étude avec une maturité constante

Le premier problème se résout assez simplement, il suffit de concaténer les différents contrats : lorsqu’un future arrive à échéance, on effectue le roll avec le future suivant. C’est ce que nous avons ici fait en récupérant des prix de futures continus qui consistent en trois séries de prix. La première contient le prix du future qui est toujours le premier à arriver à maturité en fonction de la date. La seconde le prix du future qui arrive en second à maturité et ainsi de suite.

Par exemple, si nous sommes le 17 Septembre 2020, alors les séries de prix notées ES1, ES2 et ES3 correspondent respectivement à :

  • ES1 : contrat maturant le vendredi 18 Septembre 2020
  • ES2 : contrat maturant le vendredi 18 Décembre 2020
  • ES3 : contrat maturant le vendredi 19 Mars 2021

Lorsque la date de l’échéance passe on a alors au 19 Septembre 2020 :

  • ES1 : contrat maturant le 18 Décembre 2020
  • ES2 : contrat maturant le 19 Mars 2021
  • ES3 : contrat maturant le 18 Juin 2021

Les contrats s’enchainent ainsi au fil du temps dans les séries temporelles.

Pour répondre au second problème soulevé plus tôt, nous avons recours à une interpolation spline cubique utilisant les valeurs des 3 séries qui donnent les prix du future pour 3 temps à maturité différents. Par exemple au 17 Septembre, ES1 donne le prix du future avec une durée de vie de 1 jour, ES2 avec une durée de plus de trois mois etc. L’interpolation permet ainsi d’obtenir un prix de future à exactement 30 jours.

# Récupère les dates de roll
rollDates<-as.data.frame(timeNthNdayInMonth(timeSequence(from = "2014-12-01", to = "2021-12-01", by = "quarter"), nday = 5, nth = 3, format = "%Y-%m-%d"))[4:24,1]
rollDates<-as.Date(rollDates)

# Import des séries de prix ES1 ,ES2 et ES3
fut_data<-read.zoo("data/fut.csv", header=T, sep=";", index.column = 1, format = "%d/%m/%Y")
fut_data<-as.xts(fut_data)["20150831/20200831"]

# Création d'une série vide pour acceuillir les prix
fut_returns<-xts(order.by = index(fut_data))
fut_returns<- merge(fut_returns, dummy=0)

# Interpolation du prix du future avec maturité 30 jours
j=1
for(i in 1:length(index(fut_returns))){
  # Date de l'observation
  d<-index(fut_data)[i]
  # Si la date de roll n'est pas la date du jour
  if(d != rollDates[j]){
    # x1<- temps a maturité de ES1, x2<- temps a maturité de ES2 ...
    x1<-as.integer(rollDates[j]-d)
    x2<-as.integer(as.integer(rollDates[j+1]-d))
    x3<-as.integer(as.integer(rollDates[j+2]-d))
    z<-c(fut_data$ES1[i], fut_data$ES2[i], fut_data$ES3[i])
    # Interpolation
    spl<-splinefun(x=c(x1,x2, x3), y=z, method="fmm",  ties = mean)
    fut_returns[i]<-spl(30)
  }
  # Si la date de roll est la date du jour on incrémente la date à laquelle on compare dans les dates de roll
  else{
    fut_returns[i]<-fut_data$ES1[i]
    j=j+1
  }
}
fut_prices<-fut_returns
colnames(fut_prices)<-"prix"
# Calcul des rendements
fut_returns<-diff(log(fut_returns), lag=1)
colnames(fut_returns)<-"rdt"
rm(rollDates, fut_data, spl, x1, x2, x3, z, d)

Affichons les rendements du future ainsi obtenu et les statistiques correspondantes :

plot(as.zoo(fut_returns), main="Rendements du future S&P500 (2015-2020)", xlab="Année", ylab="Rendement")

p.table(basicStats(fut_returns$rdt), "Statistiques des rendements du future (2015-2020)")
Statistiques des rendements du future (2015-2020)
rdt
nobs 1262.000000
NAs 1.000000
Minimum -0.112726
Maximum 0.096515
  1. Quartile
-0.003091
  1. Quartile
0.005433
Mean 0.000457
Median 0.000629
Sum 0.575874
SE Mean 0.000344
LCL Mean -0.000219
UCL Mean 0.001132
Variance 0.000149
Stdev 0.012224
Skewness -1.195391
Kurtosis 20.811772

6.2. Calcul des rendements du call européen sur le S&P 500 à la monnaie de maturité constante de 30 jours

Les données historiques sur les options étant difficiles à obtenir, nous allons simplement en recalculer les prix historiques grâce à la formule de Black-Scholes. Le prix d’une option dépend de 5 paramètres : le prix spot du sous-jacent (\(S\)), le prix d’exercice (\(K\)), le taux sans risque (\(r\)), la volatilité du sous-jacent (\(\sigma\)), et le temps à maturité (\(T\)). Chaque jour nous utilisons :

  • \(S\) = prix historique du S&P500 (^GSPC)

  • \(K\) = \(S\) car on choisit une option constamment à la monnaie (Call ATM)

  • \(r\) = moyenne du taux historique du trésor américain à maturité constante de 1 mois (DGS1MO)

  • \(\sigma\) = volatilité implicite à un mois donnée par le VIX

  • \(T\) = 30/365

Nous importons donc les historiques du VIX en %, du taux DGS1MO en % et du prix du S&P500 (2015-2020). Ensuite nous calculons les prix et rendements quotidiens du call européen à la monnaie de maturité constante 30 jours. Nous affichons finalement les résultats :

# Import des données nécessaires
opt_data<-read.zoo("data/opt.csv", header=T, sep=";", index.column = 1, format = "%d/%m/%Y")
opt_data<-as.xts(opt_data)["20150831/20200831"]
colnames(opt_data)<-c("vix", "taux", "sp")

# Création d'une série vide pour acceuillir les prix
opt_returns<-xts(order.by = index(opt_data))
opt_returns<- merge(opt_returns, dummy=0, dummy=0, dummy=0)
colnames(opt_returns)<-c("prix", "delta", "gamma")
# Calcul du taux moyen sur la période
r<-mean(opt_data$taux)/100
# Calcul des prix de l'option, du delta et du gamma
for(i in 1:length(index(opt_data))){
  opt_returns$prix[i]<-bs.call(opt_data$sp[i], opt_data$sp[i], r, opt_data$vix[i]/100, 30/365)
  opt_returns$delta[i]<-Nd1(opt_data$sp[i], opt_data$sp[i], r, opt_data$vix[i]/100, 30/365)
  opt_returns$gamma[i]<-G(opt_data$sp[i], opt_data$sp[i], r, opt_data$vix[i]/100, 30/365)
}
# Calcul des rendements
opt_prices<-opt_returns$prix
opt_returns$prix<-diff(log(opt_returns$prix), lag=1)
colnames(opt_returns)<-c("rdt", "delta", "gamma")
# Affichage des résultats
plot(as.zoo(opt_returns$rdt), main="Rendements du call S&P500 (2015-2020)", xlab="Année", ylab="Rendement")

p.table(basicStats(opt_returns$rdt), "Statistiques des rendements du call (2015-2020)")
Statistiques des rendements du call (2015-2020)
rdt
nobs 1262.000000
NAs 1.000000
Minimum -0.279831
Maximum 0.714060
  1. Quartile
-0.040892
  1. Quartile
0.032755
Mean 0.000397
Median -0.004519
Sum 0.501088
SE Mean 0.002078
LCL Mean -0.003679
UCL Mean 0.004473
Variance 0.005443
Stdev 0.073777
Skewness 1.463771
Kurtosis 9.620168

7. Calcul de la Value-at-Risk (VaR)

7.1. Value-at-Risk paramétrique

7.1.1. VaR Delta-Normale (VaR-DN)

La Value-at-Risk Delta-Normale est fondée sur l’hypothèse que les rendements sont indépendants et qu’ils suivent une loi normale. Calculons la VaR Delta-Normale des dérivés en utilisant une volatilité RiskMetrics et une volatilité GARCH(1,1). Ci-dessous l’obtention des volatilités RiskMetrics et GARCH(1,1).

# Vecteur pour accueillir les vols
vol<-xts(order.by = index(fut_returns))
vol<- merge.xts(vol, dummy=0, dummy=0)
colnames(vol)<-c("rm", "garch")

# Volatilité RiskMetrics
vol$rm[1]<-0.012641
vol$rm[2]<-sqrt(0.06*vol$rm[1]^2+0.94*(-0.008427078)^2)
for (i in 3:length(index(vol))){
  vol$rm[i]<-sqrt(0.06*vol$rm[i-1]^2+0.94*returns_bt[i-2]^2)
}

# Volatilité GARCH(1,1)
vol$garch[1]<-0.012641
garch11<-garchFit(formula = ~ garch(1, 1), data = returns_md, trace=F)
# Extraction des paramètres
omega<-garch11@fit$coef[2]
mu<-garch11@fit$coef[1]
alpha<-garch11@fit$coef[3]
beta<-garch11@fit$coef[4]

# Calcul de la vol GARCH
vol$garch[2]<-sqrt(omega+alpha*(-0.008427078-mu)^2+beta*vol$garch[1]^2)
for(i in 3:length(index(vol))){
  vol$garch[i]<-sqrt(omega+alpha*(returns_bt[i-2]-mu)^2+beta*vol$garch[i-1]^2)
}
head(vol)
##                     rm      garch
## 2015-08-31 0.012641000 0.01264100
## 2015-09-01 0.008737414 0.01231662
## 2015-09-02 0.029186615 0.01507010
## 2015-09-03 0.018973856 0.01530323
## 2015-09-04 0.004782707 0.01450034
## 2015-09-08 0.015023438 0.01461265

Calculons à présent les VaR Delta-Normales à 95% et 99% du future et de l’option avec les deux volatilités GARCH et RiskMetrics :

delta<-var_d(vol, opt_returns, 0.000069)
head(delta[[1]])
##            var.fut.rm.95 var.fut.rm.99 var.fut.garch.95 var.fut.garch.99
## 2015-08-31   0.000000000    0.00000000       0.00000000       0.00000000
## 2015-09-01  -0.014302767   -0.02025726      -0.02019004      -0.02858375
## 2015-09-02  -0.047938709   -0.06782922      -0.02471910      -0.03498928
## 2015-09-03  -0.031140216   -0.04407079      -0.02510257      -0.03553163
## 2015-09-04  -0.007797853   -0.01105724      -0.02378194      -0.03366384
## 2015-09-08  -0.024642356   -0.03488074      -0.02396667      -0.03392511
##            var.opt.rm.95 var.opt.rm.99 var.opt.garch.95 var.opt.garch.99
## 2015-08-31   0.000000000   0.000000000       0.00000000       0.00000000
## 2015-09-01  -0.007464425  -0.010571998      -0.01053691      -0.01491748
## 2015-09-02  -0.024911606  -0.035247816      -0.01284541      -0.01818237
## 2015-09-03  -0.016176407  -0.022893452      -0.01304003      -0.01845761
## 2015-09-04  -0.004057540  -0.005753531      -0.01237471      -0.01751666
## 2015-09-08  -0.012794362  -0.018110153      -0.01244355      -0.01761399

7.1.2. VaR de Cornish-Fisher (VaR-CF)

Calculons la VaR de Cornish-Fisher :

# Obtention des cumulants
cum<-all.cumulants(all.moments(returns_md, order.max = 5))
# Calcul de la VaR CF
cf<-var_cornish_fisher(cum, mean(returns_md), stdev(returns_md), vol, opt_returns)
head(cf[[1]])
##            var.fut.rm.95 var.fut.rm.99 var.fut.garch.95 var.fut.garch.99
## 2015-08-31    0.00000000    0.00000000       0.00000000       0.00000000
## 2015-09-01   -0.01430190   -0.02025577      -0.02018901      -0.02858183
## 2015-09-02   -0.04793692   -0.06782532      -0.02471795      -0.03498705
## 2015-09-03   -0.03113889   -0.04406809      -0.02510141      -0.03552936
## 2015-09-04   -0.00779717   -0.01105621      -0.02378082      -0.03366167
## 2015-09-08   -0.02464121   -0.03487851      -0.02396554      -0.03392293
##            var.opt.rm.95 var.opt.rm.99 var.opt.garch.95 var.opt.garch.99
## 2015-08-31   0.000000000   0.000000000       0.00000000       0.00000000
## 2015-09-01  -0.007463975  -0.010571219      -0.01053638      -0.01491648
## 2015-09-02  -0.024910676  -0.035245791      -0.01284482      -0.01818121
## 2015-09-03  -0.016175718  -0.022892051      -0.01303943      -0.01845644
## 2015-09-04  -0.004057184  -0.005752996      -0.01237412      -0.01751553
## 2015-09-08  -0.012793766  -0.018108994      -0.01244296      -0.01761285

7.1.3. VaR avec la théorie des valeurs extrêmes

Dans le cadre de la théorie des valeurs extrêmes, nous avons proposé deux méthodologies de calcul de VaR. La première fondée sur la loi des maxima de pertes par blocs d’observations et la seconde sur la loi des pertes au-delà d’un seuil.

7.1.3.1. VaR par la méthode des blocs de maxima (VaR-BMM)

Nous avions vu dans la section dédiée à cette méthode que le choix du nombre de jours par bloc s’était porté sur 42 jours. Ainsi nous avions estimé les paramètres de la loi GEV qui correspondait au mieux à la loi de la perte maximale sur 42 jours. Utiliser le quantile au niveau \(\alpha_{gev}\) de la loi GEV estimée fournit une VaR pour la perte maximale sur 42 jours au niveau \(\alpha_{gev}\). Toutefois il nous faut faire le lien entre la loi de la perte maximale sur 42 jours et celle des pertes à un jour (notre VaR classique). Pour cela on utilise la notion de temps de retour : c’est le temps moyen au bout duquel le portefeuille subit une perte extrême. Après quelques calculs on obtient les relations suivante : \[\tau_{gev}=1/(1-\alpha_{gev})\] \[\tau=n\times\tau_{gev}\] \[\tau_{gev}=1/(n(1-\alpha))\] \[\alpha_{gev}=1-n(1-\alpha)\] Avec \(\tau_{gev}\) le temps de retour de la loi GEV, \(\alpha_{gev}\) le quantile de la loi GEV, \(n\) le nombre de jours dans le bloc (42 ici) et \(\alpha\) le quantile de la VaR à un jour recherchée. Nous obtenons alors le quantile de la loi GEV correspondant au niveau de VaR recherché. Toutefois, nous remarquons ici la limite de cette méthode puisque la VaR à 95% n’est pas calculable du fait du nombre de jours \(n\) trop élevé (le \(\alpha_{gev}\) calculé avec la méthode précédente n’étant pas compris entre 0 et 1 dans le cas \(\alpha=0,95\)). Nous ne calculerons donc que la VaR à 99% avec cette méthode.

n<-42
alpha_gev<-1-n*0.01

Nous obtenons en appliquant les formules ci-dessus que le quantile \(\alpha_{gev}=0,58\) fournira la VaR à un jour au niveau \(\alpha=0,99\). Calculons maintenant cette VaR sur notre période (2015-2020) :

param<-as.double(c(fitgev$param["loc"], fitgev$param["scale"], fitgev$param["shape"]))
bbm<-var_bmm(param, vol, opt_returns, mean(loss_md), stdev(loss_md), alpha_gev)
head(bbm[[1]])
##             var.fut.99  var.opt.99
## 2015-08-31  0.00000000  0.00000000
## 2015-09-01 -0.02338626 -0.01220498
## 2015-09-02 -0.02338626 -0.01215280
## 2015-09-03 -0.02338626 -0.01214846
## 2015-09-04 -0.02338626 -0.01216882
## 2015-09-08 -0.02338626 -0.01214220

Nous observons que dans le calcul de cette VaR, la volatilité conditionnelle n’est pas prise en compte. Nous obtenons donc une VaR constante sur la période pour le future et qui varie uniquement du fait du delta pour l’option. Un autre avantage non mentionné précédemment de la méthode des pics au-delà du seuil, c’est qu’elle permet une prise en compte de la volatilité conditionnelle grâce à la méthodologie de “Conditional Extreme Value Theory” développée par McNeil et Frey (2000).

7.1.3.2. VaR par la méthode des pics au-delà du seuil (VaR-POT)

Calculons la VaR des pertes au-dessus du seuil \(u=0,032\). Nous avions que sur l’échantillon, 53 pertes étaient au-dessus du seuil sur 3771 observations. Ce qui donne, d’après la formule d’estimation de la fonction des excès, les VaRs suivantes :

f<-as.double(3771/53)
param<-as.double(c(fitpot$param[1], fitpot$param[2]))
pot<- var_u(param, vol, opt_returns, mean(loss_md), stdev(loss_md), f, u)
head(pot[[1]])
##            var.fut.rm.99 var.fut.garch.99 var.opt.rm.99 var.opt.garch.99
## 2015-08-31    0.00000000       0.00000000   0.000000000       0.00000000
## 2015-09-01   -0.02209753      -0.03117805  -0.011532407      -0.01627141
## 2015-09-02   -0.07397755      -0.03816366  -0.038442832      -0.01983195
## 2015-09-03   -0.04806758      -0.03875512  -0.024969666      -0.02013212
## 2015-09-04   -0.01206436      -0.03671819  -0.006277575      -0.01910597
## 2015-09-08   -0.03804529      -0.03700312  -0.019753195      -0.01921210
rm(fitgev, fitpot, garch11, loss_md)

7.2. Value-at-Risk par simulation et méthodes semi-paramétriques

7.2.1. VaR par simulation historique des facteurs de risque et “full-repricing” (VaR-H)

Dans cette section nous allons calculer la VaR par simulation historique sur une fenêtre roulante de 1 an. Nous allons procéder par simulation classique sans modification de l’historique (Bootstrapping ou autres). La méthode consiste à utiliser les variations historiques des facteurs de risque et à repricer les dérivés avec ces nouveaux paramètres. Dans un premier temps calculons une VaR historique univariée (on ne fait varier que le S&P500 et on ne modifie par les autres paramètres).

vix_returns<-read.zoo("data/VIX_returns.csv", header=T, sep=";", index.column = 1, format = "%d/%m/%Y")
vix_returns<-as.xts(vix_returns)
colnames(vix_returns)<-"vix.r"
histo<-var_h(returns_md, returns_bt, opt_data, fut_prices, opt_prices, vol, vix_returns)
head(histo[[1]])
##             var.fut.95  var.fut.99  var.opt.95 var.opt.99
## 2015-08-31  0.00000000  0.00000000  0.00000000  0.0000000
## 2015-09-01 -0.01492499 -0.02120407 -0.49643558 -0.6035490
## 2015-09-02 -0.01571830 -0.02558734 -0.30352902 -0.4968900
## 2015-09-03 -0.01571830 -0.02558734 -0.02018628 -0.1992150
## 2015-09-04 -0.01571830 -0.02558734 -0.70631723 -0.9102195
## 2015-09-08 -0.01583198 -0.02558734 -0.04718755 -0.2309335

Voyons ce qu’il advient de la VaR si l’on fait également varier la volatilité (VIX) :

histo_mv<-var_h(returns_md, returns_bt, opt_data, fut_prices, opt_prices, vol, vix_returns, bi=TRUE)
head(histo_mv[[1]])
##             var.fut.95  var.fut.99  var.opt.95    var.opt.99
## 2015-08-31  0.00000000  0.00000000  0.00000000  0.0000000000
## 2015-09-01 -0.01492499 -0.02120407 -0.33427353 -0.4160765938
## 2015-09-02 -0.01571830 -0.02558734 -0.13061898 -0.2402013425
## 2015-09-03 -0.01571830 -0.02558734  0.12002719  0.0266744079
## 2015-09-04 -0.01571830 -0.02558734 -0.50522304 -0.6251409841
## 2015-09-08 -0.01583198 -0.02558734  0.09696997  0.0005414278

7.2.2. VaR par simulation Monte-Carlo des facteurs de risque et “full-repricing”

7.2.2.1. VaR par simulation Monte-Carlo univariée (VaR-MC-U)

Dans cette section nous allons calculer la VaR de deux manières différentes : en faisant varier le sous-jacent de manière normale et en faisant varier le sous-jacent d’après le meilleur modèle choisi précédemment(ARMA(3,3)-eGARCH(2,1)).

Ci-dessous la VaR Monte-Carlo normale (100000 simulations) :

mc_n<-var_mc(prices_bt, vol, fut_prices, opt_prices, opt_data, 100000)
head(mc_n[[1]])
##             var.fut.95  var.fut.99 var.opt.95 var.opt.99
## 2015-08-31  0.00000000  0.00000000  0.0000000  0.0000000
## 2015-09-01 -0.02021641 -0.02835235 -0.5864942 -0.7292960
## 2015-09-02 -0.02483492 -0.03507317 -0.4807842 -0.6909894
## 2015-09-03 -0.02512172 -0.03552858 -0.1895403 -0.3883070
## 2015-09-04 -0.02358653 -0.03366822 -0.8672598 -1.0830210
## 2015-09-08 -0.02406567 -0.03396933 -0.2006141 -0.3956459

Voyons maintenant ce que donne la VaR Monte-Carlo avec le modèle des rendements du S&P500 choisi auparavant (ARMA(3,3)-eGARCH(2,1) avec innovations suivant la loi sged) :

# Spécifications du modèle
fixed.p <- list(mu = 0.0001718297,
                ar1 = -0.0768908552,
                ar2 =  -0.6644951238,
                ar3 =  0.5110208741,
                ma1 = 0.0091052680,
                ma2 = 0.6283683601,
                ma3 = -0.5687746472,
                omega = -0.1931395105,
                alpha1= -0.2667631153,
                alpha2 = 0.132319643,
                beta1 = 0.9792846055,
                gamma1= -0.1612302291,
                gamma2= 0.2904668375,
                skew = 0.8437220862,
                shape= 1.4883835679)
armaOrder <- c(3,3)
garchOrder <- c(2,1) # GARCH order
varModel <- list(model = "eGARCH", garchOrder = garchOrder)
spec <- ugarchspec(varModel, mean.model = list(armaOrder = armaOrder),
                   fixed.pars = fixed.p, distribution.model = "sged")
# Calcul de la VaR
model<-var_model(prices_bt, vol, fut_prices, returns_bt, opt_prices, opt_data, opt_returns, spec, 10000)
head(model[[1]])
##             var.fut.95  var.fut.99  var.opt.95 var.opt.99
## 2015-08-31  0.00000000  0.00000000  0.00000000  0.0000000
## 2015-09-01 -0.01351801 -0.02416893 -0.47285331 -0.6552086
## 2015-09-02 -0.02122147 -0.03531484 -0.40942285 -0.6960965
## 2015-09-03 -0.05259818 -0.06632965 -0.74130773 -1.0507621
## 2015-09-04 -0.01459225 -0.02807041 -0.68379156 -0.9618848
## 2015-09-08 -0.01503474 -0.02805461 -0.03272965 -0.2777696

7.2.2.2. VaR par simulation Monte-Carlo bivariée (VaR-MC-BV)

La variation du prix de l’option est le fait de deux principaux facteurs de risque, le sous-jacent et la volatilité. C’est pourquoi nous allons calculer la VaR lorsque ces deux facteurs varient conjointement. Pour commencer nous allons supposer que les log-rendements du VIX varient de manière normale. Ceci peut être plus ou moins constaté ci-dessous avec la comparaison des rendements du VIX et de la densité normale correspondante :

vix_returns<-vix_returns["/20150831"]
hist(vix_returns, xlab="Rendement du VIX", ylab="Densité", freq=FALSE, main="Histogramme des rendements du VIX (2000-2015)", ylim=c(0,10), breaks=20)
lines(density(vix_returns), col="blue")
legend("right", legend=c("Densité normale", "Densité empirique"),
       col=c("red", "blue"), lty=1, cex=0.8)
curve(dnorm(x, mean=mean(vix_returns), sd=sd(vix_returns)), add=TRUE, col="red")

Les deux ne variant pas indépendemment, nous prendrons en compte la matrice de variance-covariance permettant de simuler l’évolution des facteurs simultanément. Ci-dessous, la VaR Monte-Carlo normale bivariée :

cov.matrix<-matrix(c(var(returns_md), cov(returns_md, vix_returns), cov(returns_md, vix_returns), var(vix_returns)), 2)
m<-c(mean(returns_md), mean(vix_returns))
mc_n_bv<-var_mc_mv(prices_bt, vol, fut_prices, opt_prices, opt_data, m, cov.matrix, 100000)
head(mc_n_bv[[1]])
##             var.fut.95  var.fut.99  var.opt.95 var.opt.99
## 2015-08-31  0.00000000  0.00000000  0.00000000  0.0000000
## 2015-09-01 -0.02066643 -0.02925489 -0.48957506 -0.5891183
## 2015-09-02 -0.02064332 -0.02928618 -0.30172899 -0.4200579
## 2015-09-03 -0.02070184 -0.02934561 -0.02913932 -0.1439349
## 2015-09-04 -0.02062906 -0.02920680 -0.68472652 -0.8038019
## 2015-09-08 -0.02074453 -0.02926246 -0.05648713 -0.1743710

Nous voyons ci-dessus que la loi normale semble sous-estimer les queues de la distribution des rendements du VIX, ce qui est aussi le cas avec celle des rendements du S&P500. Nous allons donc calculer une VaR bivariée avec deux lois de Student-t. Voyons ci-dessous le degré de liberté le mieux adapté :

hist(vix_returns, xlab="Rendement du VIX", ylab="Densité", freq=FALSE, main="Histogramme des rendements du VIX (2000-2015)", ylim=c(0,10), breaks=20)
lines(density(vix_returns), col="blue")
legend("right", legend=c("Densité Student-4", "Densité empirique"),
       col=c("red", "blue"), lty=1, cex=0.8)
curve(dstd(x, mean=mean(vix_returns), sd=sd(vix_returns), nu=4), add=TRUE, col="red")

Ci-dessus la comparaison de la densité empirique et Student-4 avec même moyenne et variance. On observe que cela semble mieux fitter que la loi normale. Voyons ce qu’il en est pour les rendements du S&P500 et la loi Student-4 :

hist(returns_md, xlab="Rendement du S&P500", ylab="Densité", freq=FALSE, main="Histogramme des rendements du S&P500 (2000-2015)", ylim=c(0,55), breaks=20)
lines(density(returns_md), col="blue")
legend("right", legend=c("Densité Student-4", "Densité empirique"),
       col=c("red", "blue"), lty=1, cex=0.8)
curve(dstd(x, mean=mean(returns_md), sd=sd(returns_md), nu=4), add=TRUE, col="red")

Cela n’est pas parfait mais nous nous en contenterons car les degrés de liberté des deux lois doivent être les mêmes pour la simulation. Voyons le niveau de risque fournit par la VaR Monte-Carlo Student-4 bivariée :

mc_std_bv<-var_mc_mv(prices_bt, vol, fut_prices, opt_prices, opt_data, m, cov.matrix, 100000, type="std")
head(mc_std_bv[[1]])
##             var.fut.95  var.fut.99 var.opt.95 var.opt.99
## 2015-08-31  0.00000000  0.00000000  0.0000000  0.0000000
## 2015-09-01 -0.02691459 -0.04776679 -0.5554255 -0.7802360
## 2015-09-02 -0.02675782 -0.04702541 -0.3796737 -0.6483538
## 2015-09-03 -0.02712778 -0.04755550 -0.1097622 -0.3698338
## 2015-09-04 -0.02691697 -0.04771269 -0.7625532 -1.0292627
## 2015-09-08 -0.02669791 -0.04693670 -0.1365017 -0.4199643

8. Calcul de la Tail Conditional Expectation (TCE)

Dans cette section, nous allons calculer la Tail Conditional Expectation en fonction des différents modèles de VaR. Les résultats sont donnés à titre indicatif, aucune étude statistique ne sera réalisée.

8.1. Tail Conditional Expectation paramétriques

8.1.1. TCE delta-normale (TCE-DN)

head(delta[[2]])
##            tce.fut.rm.95 tce.fut.rm.99 tce.fut.garch.95 tce.fut.garch.99
## 2015-08-31   0.000000000    0.00000000       0.00000000       0.00000000
## 2015-09-01  -0.017953775   -0.02321808      -0.02533665      -0.03275743
## 2015-09-02  -0.060134604   -0.07771958      -0.03101628      -0.04009603
## 2015-09-03  -0.039068616   -0.05050039      -0.03149716      -0.04071738
## 2015-09-04  -0.009796352   -0.01267794      -0.02984104      -0.03857752
## 2015-09-08  -0.030920038   -0.03997168      -0.03007270      -0.03887684
##            tce.opt.rm.95 tce.opt.rm.99 tce.opt.garch.95 tce.opt.garch.99
## 2015-08-31   0.000000000   0.000000000       0.00000000       0.00000000
## 2015-09-01  -0.009369838  -0.012117209      -0.01322286      -0.01709567
## 2015-09-02  -0.031249268  -0.040387395      -0.01611777      -0.02083612
## 2015-09-03  -0.020294973  -0.026233437      -0.01636183      -0.02115146
## 2015-09-04  -0.005097440  -0.006596847      -0.01552751      -0.02007345
## 2015-09-08  -0.016053747  -0.020753378      -0.01561381      -0.02018494

8.1.2. TCE de Cornish-Fisher (TCE-CF)

head(cf[[2]])
##            tce.fut.rm.95 tce.fut.rm.99 tce.fut.garch.95 tce.fut.garch.99
## 2015-08-31   0.000000000    0.00000000       0.00000000       0.00000000
## 2015-09-01  -0.017773396   -0.02312173      -0.02548288      -0.03307756
## 2015-09-02  -0.060618734   -0.07725859      -0.03111823      -0.03980853
## 2015-09-03  -0.039239778   -0.05042969      -0.03151818      -0.04077454
## 2015-09-04  -0.009761864   -0.01252632      -0.02981443      -0.03819585
## 2015-09-08  -0.030885942   -0.04018901      -0.02972432      -0.03913977
##            tce.opt.rm.95 tce.opt.rm.99 tce.opt.garch.95 tce.opt.garch.99
## 2015-08-31   0.000000000   0.000000000       0.00000000       0.00000000
## 2015-09-01  -0.009275701  -0.012066924      -0.01329918      -0.01726274
## 2015-09-02  -0.031500849  -0.040147840      -0.01617075      -0.02068672
## 2015-09-03  -0.020383886  -0.026196708      -0.01637275      -0.02118115
## 2015-09-04  -0.005079494  -0.006517951      -0.01551366      -0.01987485
## 2015-09-08  -0.016036044  -0.020866214      -0.01543293      -0.02032145

8.1.3. TCE avec la théorie des valeurs extrêmes

8.1.3.1. TCE par la méthode des blocs de maxima (TCE-BMM)

head(bbm[[2]])
##             tce.fut.99  tce.opt.99
## 2015-08-31  0.00000000  0.00000000
## 2015-09-01 -0.03878949 -0.02024372
## 2015-09-02 -0.03878949 -0.02015716
## 2015-09-03 -0.03878949 -0.02014997
## 2015-09-04 -0.03878949 -0.02018374
## 2015-09-08 -0.03878949 -0.02013958

8.1.3.2. TCE par la méthode des pics au-delà du seuil (TCE-POT)

head(pot[[2]])
##            tce.fut.rm.99 tce.fut.garch.99 tce.opt.rm.99 tce.opt.garch.99
## 2015-08-31    0.00000000       0.00000000   0.000000000       0.00000000
## 2015-09-01   -0.02229602      -0.03145786  -0.011636000      -0.01641744
## 2015-09-02   -0.07464062      -0.03850603  -0.038787397      -0.02000986
## 2015-09-03   -0.04849863      -0.03910278  -0.025193584      -0.02031272
## 2015-09-04   -0.01217301      -0.03704761  -0.006334112      -0.01927738
## 2015-09-08   -0.03838660      -0.03733509  -0.019930400      -0.01938446

8.2. Tail Conditional Expectation par simulation et semi-paramétriques

8.2.1. TCE par simulation historique des facteurs de risque et “full-repricing” (TCE-H)

Ci-dessous, la TCE par simulation historique univariée.

head(histo[[2]])
##             tce.fut.95  tce.fut.99 tce.opt.95 tce.opt.99
## 2015-08-31  0.00000000  0.00000000  0.0000000  0.0000000
## 2015-09-01 -0.02070759 -0.03130222 -0.5969759 -0.7848223
## 2015-09-02 -0.02184459 -0.03420111 -0.4246195 -0.6737173
## 2015-09-03 -0.02184459 -0.03420111 -0.1323587 -0.3633561
## 2015-09-04 -0.02184459 -0.03420111 -0.8338840 -1.0957556
## 2015-09-08 -0.02184459 -0.03420111 -0.1615753 -0.4015029

Ensuite, celle par simulation historique multivariée.

head(histo_mv[[2]])
##             tce.fut.95  tce.fut.99  tce.opt.95  tce.opt.99
## 2015-08-31  0.00000000  0.00000000  0.00000000  0.00000000
## 2015-09-01 -0.02070759 -0.03130222 -0.39588745 -0.51441934
## 2015-09-02 -0.02184459 -0.03420111 -0.21568886 -0.36738551
## 2015-09-03 -0.02184459 -0.03420111  0.04493656 -0.08055803
## 2015-09-04 -0.02184459 -0.03420111 -0.59565709 -0.77176111
## 2015-09-08 -0.02184459 -0.03420111  0.01689859 -0.10792735

8.2.2. TCE par simulation Monte-Carlo des facteurs de risque et “full-repricing”

8.2.2.1. TCE par simulation Monte-Carlo univarié (TCE-MC-U)

Dans un premier temps intéréssons nous à la TCE par simulation Monte-Carlo univariée normale :

head(mc_n[[2]])
##             tce.fut.95  tce.fut.99 tce.opt.95 tce.opt.99
## 2015-08-31  0.00000000  0.00000000  0.0000000  0.0000000
## 2015-09-01 -0.02527876 -0.03257711 -0.6755373 -0.8060922
## 2015-09-02 -0.03115663 -0.04030771 -0.6109769 -0.8043519
## 2015-09-03 -0.03152732 -0.04088150 -0.3123095 -0.4966182
## 2015-09-04 -0.02980381 -0.03872840 -1.0006487 -1.1964716
## 2015-09-08 -0.03007405 -0.03874635 -0.3192633 -0.4950882

Puis à la TCE Monte-Carlo univariée ARMA-eGARCH sged :

head(model[[2]])
##             tce.fut.95  tce.fut.99 tce.opt.95 tce.opt.99
## 2015-08-31  0.00000000  0.00000000  0.0000000  0.0000000
## 2015-09-01 -0.02029164 -0.02963261 -0.5891644 -0.7534044
## 2015-09-02 -0.02989381 -0.04261925 -0.5868841 -0.8571397
## 2015-09-03 -0.06117008 -0.07439445 -0.9359432 -1.2470640
## 2015-09-04 -0.02269803 -0.03458082 -0.8515927 -1.1051246
## 2015-09-08 -0.02294098 -0.03489756 -0.1825838 -0.4178324

8.2.2.2. TCE par simulation Monte-Carlo bivariée (TCE-MC-BV)

Commencons par le calcul de la TCE Monte-Carlo bivariée normale.

head(mc_n_bv[[2]])
##             tce.fut.95  tce.fut.99  tce.opt.95 tce.opt.99
## 2015-08-31  0.00000000  0.00000000  0.00000000  0.0000000
## 2015-09-01 -0.02594092 -0.03369448 -0.55159765 -0.6412785
## 2015-09-02 -0.02598386 -0.03346121 -0.37411991 -0.4764494
## 2015-09-03 -0.02591029 -0.03323886 -0.09975388 -0.1987867
## 2015-09-04 -0.02587930 -0.03355263 -0.75842821 -0.8656614
## 2015-09-08 -0.02591880 -0.03334924 -0.12940106 -0.2334256

La TCE Monte-Carlo bivariée Student-4 donne quant à elle les résultats suivants :

head(mc_std_bv[[2]])
##             tce.fut.95  tce.fut.99 tce.opt.95 tce.opt.99
## 2015-08-31  0.00000000  0.00000000  0.0000000  0.0000000
## 2015-09-01 -0.04033260 -0.06559608 -0.7069227 -0.9891363
## 2015-09-02 -0.04032826 -0.06568912 -0.5595485 -0.8969000
## 2015-09-03 -0.04067775 -0.06654061 -0.2798931 -0.6015127
## 2015-09-04 -0.04033648 -0.06528232 -0.9443700 -1.2902049
## 2015-09-08 -0.04029994 -0.06508614 -0.3161236 -0.6394484

9. Backtesting de la Value-at-Risk

Dans cette section nous nous concentrerons sur la performance des mesures de VaR. L’étude se scinde en trois parties : la performance de la VaR par rapport au S&P500, celle par rapport au future et finalement celle par rapport à l’option européenne.

9.1. Performance de la VaR du S&P500

9.1.1. VaRs à 95%

Voyons les résultats des différents tests statistiques sur les mesures de VaR entre 2015 et 2020 :

var.95<-merge(delta[[1]][,1],delta[[1]][,3], cf[[1]][,1], cf[[1]][,3], model[[3]][,1])
var.95<-comparison(var.95, returns_bt)
names<-c("Delta-normale volatilité RiskMetrics", "Delta-normale volatilité GARCH(1,1)", "Cornish-Fisher volatiltié RiskMetrics", "Cornish-Fisher volatiltié GARCH(1,1)", "ARMA(3,3)-eGARCH(2,1) sged")
n<-length(index(var.95))
p.table.back(tests(var.95, names, 0.95, n), "Tests statistiques sur les VaRs du S\\&P500 à 95\\% (2015-2020)", c(" "=1, "Traffic Light" = 3, "Kupiec"=1, "Christoffersen" =1), 5)
Tests statistiques sur les VaRs du S&amp;P500 à 95% (2015-2020)
Traffic Light
Kupiec
Christoffersen
% Nombre Zone Concluant Concluant
VaRs paramétriques et semi-paramétriques
VaR Delta-normale volatilité RiskMetrics 13 % 164 Rouge Non Oui
VaR Delta-normale volatilité GARCH(1,1) 3.7 % 46 Vert Non Non
VaR Cornish-Fisher volatiltié RiskMetrics 13 % 164 Rouge Non Oui
VaR Cornish-Fisher volatiltié GARCH(1,1) 3.7 % 46 Vert Non Non
VaR ARMA(3,3)-eGARCH(2,1) sged 6.6 % 83 Jaune Non Non
Remarque : les colonnes % et Nombre correspondent aux dépassements

La volatilité GARCH semble être le facteur déterminant à ce niveau de précision. Toutes les mesures avec volatilité RiskMetrics ne sont pas assez extrêmes et ont donc une fréquence de dépassement trop importante. Au niveau des tests de Kupiec et de Christoffersen, les résultats sont très mauvais. Étant donné que les modèles n’ont pas été recalibrés, ce qui est le cas dans la réalité puisque les banques revoient les paramètres de leurs modèles, voyons ce qu’il en est du backtesting sur 3 ans seulement.

var.95<-merge(delta[[1]][,1],delta[[1]][,3], cf[[1]][,1], cf[[1]][,3], model[[3]][,1])
var.95<-comparison(var.95, returns_bt)["/20180831"]
names<-c("Delta-normale volatilité RiskMetrics", "Delta-normale volatilité GARCH(1,1)", "Cornish-Fisher volatiltié RiskMetrics", "Cornish-Fisher volatiltié GARCH(1,1)", "ARMA(3,3)-eGARCH(2,1) sged")
n<-length(index(var.95))
p.table.back(tests(var.95, names, 0.95, n), "Tests statistiques sur les VaRs du S\\&P500 à 95\\% (2015-2018)", c(" "=1, "Traffic Light" = 3, "Kupiec"=1, "Christoffersen" =1), 5)
Tests statistiques sur les VaRs du S&amp;P500 à 95% (2015-2018)
Traffic Light
Kupiec
Christoffersen
% Nombre Zone Concluant Concluant
VaRs paramétriques et semi-paramétriques
VaR Delta-normale volatilité RiskMetrics 12.7 % 96 Rouge Non Oui
VaR Delta-normale volatilité GARCH(1,1) 2.9 % 22 Vert Non Non
VaR Cornish-Fisher volatiltié RiskMetrics 12.7 % 96 Rouge Non Oui
VaR Cornish-Fisher volatiltié GARCH(1,1) 2.9 % 22 Vert Non Non
VaR ARMA(3,3)-eGARCH(2,1) sged 5.7 % 43 Vert Oui Oui
Remarque : les colonnes % et Nombre correspondent aux dépassements

Les résultats sont bien meilleurs. La mesure de VaR ARMA-eGARCH est la seule qui réussit l’ensemble des tests. Les mesures Delta-normale et Cornish-Fisher avec volatilité GARCH sont trop conservatrices et échouent donc au test de Kupiec (et de Christoffersen).

9.1.2. VaRs à 99%

Comme ci-dessus, voyons les résultats pour les VaRs à 99% sur la période de 2015 à 2020 :

var.99<-merge(delta[[1]][,2],delta[[1]][,4], cf[[1]][,2], cf[[1]][,4], bbm[[1]][,1], pot[[1]][,1], pot[[1]][,2], model[[3]][,2])
var.99<-comparison(var.99, returns_bt)
names<-c("Delta-normale volatilité RiskMetrics", "Delta-normale volatilité GARCH(1,1)", "Cornish-Fisher volatilité RiskMetrics", "Cornish-Fisher volatilité GARCH(1,1)", "Maxima par blocs", "Peaks-Over-Treshold volatilité RiskMetrics", "Peaks-Over-Treshold volatilité GARCH(1,1)", "ARMA(3,3)-eGARCH(2,1) sged")
n<-length(index(var.99))
p.table.back(tests(var.99, names, 0.99, n), "Tests statistiques sur les VaRs du S\\&P500 à 99\\% (2015-2020)", c(" "=1, "Traffic Light" = 3, "Kupiec"=1, "Christoffersen" =1), 8)
Tests statistiques sur les VaRs du S&amp;P500 à 99% (2015-2020)
Traffic Light
Kupiec
Christoffersen
% Nombre Zone Concluant Concluant
VaRs paramétriques et semi-paramétriques
VaR Delta-normale volatilité RiskMetrics 9.1 % 115 Rouge Non Oui
VaR Delta-normale volatilité GARCH(1,1) 2.4 % 30 Rouge Non Non
VaR Cornish-Fisher volatilité RiskMetrics 9.1 % 115 Rouge Non Oui
VaR Cornish-Fisher volatilité GARCH(1,1) 2.4 % 30 Rouge Non Non
VaR Maxima par blocs 2.9 % 37 Rouge Non Oui
VaR Peaks-Over-Treshold volatilité RiskMetrics 8.3 % 105 Rouge Non Oui
VaR Peaks-Over-Treshold volatilité GARCH(1,1) 2 % 25 Jaune Non Non
VaR ARMA(3,3)-eGARCH(2,1) sged 2.5 % 32 Rouge Non Oui
Remarque : les colonnes % et Nombre correspondent aux dépassements

Encore une fois les résultats sont mauvais, aucune mesure ne convient. Voyons ce qu’il en est sur 3 ans :

var.99<-merge(delta[[1]][,2],delta[[1]][,4], cf[[1]][,2], cf[[1]][,4], bbm[[1]][,1], pot[[1]][,1], pot[[1]][,2], model[[3]][,2])
var.99<-comparison(var.99, returns_bt)["/20180831"]
names<-c("Delta-normale volatilité RiskMetrics", "Delta-normale volatilité GARCH(1,1)", "Cornish-Fisher volatilité RiskMetrics", "Cornish-Fisher volatilité GARCH(1,1)", "Maxima par blocs", "Peaks-Over-Treshold volatilité RiskMetrics", "Peaks-Over-Treshold volatilité GARCH(1,1)", "ARMA(3,3)-eGARCH(2,1) sged")
n<-length(index(var.99))
p.table.back(tests(var.99, names, 0.99, n), "Tests statistiques sur les VaRs du S\\&P500 à 99\\% (2015-2018)", c(" "=1, "Traffic Light" = 3, "Kupiec"=1, "Christoffersen" =1), 8)
Tests statistiques sur les VaRs du S&amp;P500 à 99% (2015-2018)
Traffic Light
Kupiec
Christoffersen
% Nombre Zone Concluant Concluant
VaRs paramétriques et semi-paramétriques
VaR Delta-normale volatilité RiskMetrics 9.8 % 74 Rouge Non Oui
VaR Delta-normale volatilité GARCH(1,1) 1.6 % 12 Jaune Oui Non
VaR Cornish-Fisher volatilité RiskMetrics 9.8 % 74 Rouge Non Oui
VaR Cornish-Fisher volatilité GARCH(1,1) 1.6 % 12 Jaune Oui Non
VaR Maxima par blocs 1.1 % 8 Vert Oui Oui
VaR Peaks-Over-Treshold volatilité RiskMetrics 8.9 % 67 Rouge Non Oui
VaR Peaks-Over-Treshold volatilité GARCH(1,1) 1.1 % 8 Vert Oui Non
VaR ARMA(3,3)-eGARCH(2,1) sged 1.7 % 13 Jaune Oui Oui
Remarque : les colonnes % et Nombre correspondent aux dépassements

Sur trois ans, on observe que les mesures issues de la théorie des valeurs extrêmes performent le mieux, ce qui est rassurant car c’est justement leur rôle : prévoir les évènements extrêmes ce qui correspond au niveau de confiance à 99%. Cependant la mesure par maxima par blocs ne représente absolument pas le risque quoitidien car elle est constante et ne permettrait donc pas en réalité à une banque d’ajuster son niveau de capital servant à couvrir ses risques. Les mesures les plus performantes sont finalement, selon ces critères, la VaR ARMA-eGARCH et la VaR-POT à volatilité GARCH. Toutefois la VaR POT ne réussit pas le test de Christoffersen, on considèrera que la meilleure mesure est la VaR ARMA-eGARCH.

9.2. Performance de la VaR du future sur le S&P500

9.2.1. VaRs à 95%

var.95<-merge(delta[[1]][,1],delta[[1]][,3], cf[[1]][,1], cf[[1]][,3], model[[3]][,1], model[[1]][,1], histo[[1]][,1], histo_mv[[1]][,1], mc_n[[1]][,1], mc_n_bv[[1]][,1], mc_std_bv[[1]][,1])
var.95<-comparison(var.95, fut_returns)
names<-c("Delta-normale volatilité RiskMetrics", "Delta-normale volatilité GARCH(1,1)", "Cornish-Fisher volatiltié RiskMetrics", "Cornish-Fisher volatiltié GARCH(1,1)","ARMA(3,3)-eGARCH(2,1) sged", "ARMA(3,3)-eGARCH(2,1) sged repricing", "Historique univariée", "Historique bivariée", "Monte-Carlo normale univariée", "Monte-Carlo normale bivariée", "Monte-Carlo Student-4 bivariée")
n<-length(index(var.95))
p.table.back(tests(var.95, names, 0.95, n), "Tests statistiques sur les VaRs du future sur le S\\&P500 à 95\\% (2015-2020)", c(" "=1, "Traffic Light" = 3, "Kupiec"=1, "Christoffersen" =1), 5, 11)
Tests statistiques sur les VaRs du future sur le S&amp;P500 à 95% (2015-2020)
Traffic Light
Kupiec
Christoffersen
% Nombre Zone Concluant Concluant
VaRs paramétriques et semi-paramétriques
VaR Delta-normale volatilité RiskMetrics 13.7 % 173 Rouge Non Oui
VaR Delta-normale volatilité GARCH(1,1) 4.1 % 52 Vert Oui Non
VaR Cornish-Fisher volatiltié RiskMetrics 13.7 % 173 Rouge Non Oui
VaR Cornish-Fisher volatiltié GARCH(1,1) 4.1 % 52 Vert Oui Non
VaR ARMA(3,3)-eGARCH(2,1) sged 6.5 % 82 Jaune Non Non
VaRs par simulation et repricing
VaR ARMA(3,3)-eGARCH(2,1) sged repricing 6.5 % 82 Jaune Non Non
VaR Historique univariée 5.6 % 70 Vert Oui Non
VaR Historique bivariée 5.6 % 70 Vert Oui Non
VaR Monte-Carlo normale univariée 4 % 51 Vert Oui Non
VaR Monte-Carlo normale bivariée 3.5 % 44 Vert Non Non
VaR Monte-Carlo Student-4 bivariée 2.1 % 26 Vert Non Oui
Remarque : les colonnes % et Nombre correspondent aux dépassements

Toutes les méthodes de simulation donnent des VaRs performantes du point de vue du Traffic Light Test, mais aucune des mesures ne réussit le test de Kupiec et celui de Christoffersen. Voyons ce qu’il en est sur 3 ans :

var.95<-merge(delta[[1]][,1],delta[[1]][,3], cf[[1]][,1], cf[[1]][,3], model[[3]][,1], model[[1]][,1], histo[[1]][,1], histo_mv[[1]][,1], mc_n[[1]][,1], mc_n_bv[[1]][,1], mc_std_bv[[1]][,1])
var.95<-comparison(var.95, fut_returns)["/20180831"]
names<-c("Delta-normale volatilité RiskMetrics", "Delta-normale volatilité GARCH(1,1)", "Cornish-Fisher volatiltié RiskMetrics", "Cornish-Fisher volatiltié GARCH(1,1)","ARMA(3,3)-eGARCH(2,1) sged", "ARMA(3,3)-eGARCH(2,1) sged repricing", "Historique univariée", "Historique bivariée", "Monte-Carlo normale univariée", "Monte-Carlo normale bivariée", "Monte-Carlo Student-4 bivariée")
n<-length(index(var.95))
p.table.back(tests(var.95, names, 0.95, n), "Tests statistiques sur les VaRs du future sur le S\\&P500 à 95\\% (2015-2018)", c(" "=1, "Traffic Light" = 3, "Kupiec"=1, "Christoffersen" =1), 5, 11)
Tests statistiques sur les VaRs du future sur le S&amp;P500 à 95% (2015-2018)
Traffic Light
Kupiec
Christoffersen
% Nombre Zone Concluant Concluant
VaRs paramétriques et semi-paramétriques
VaR Delta-normale volatilité RiskMetrics 12.9 % 98 Rouge Non Oui
VaR Delta-normale volatilité GARCH(1,1) 3 % 23 Vert Non Non
VaR Cornish-Fisher volatiltié RiskMetrics 12.9 % 98 Rouge Non Oui
VaR Cornish-Fisher volatiltié GARCH(1,1) 3 % 23 Vert Non Non
VaR ARMA(3,3)-eGARCH(2,1) sged 5.3 % 40 Vert Oui Oui
VaRs par simulation et repricing
VaR ARMA(3,3)-eGARCH(2,1) sged repricing 5.3 % 40 Vert Oui Oui
VaR Historique univariée 5.2 % 39 Vert Oui Non
VaR Historique bivariée 5.2 % 39 Vert Oui Non
VaR Monte-Carlo normale univariée 3 % 23 Vert Non Non
VaR Monte-Carlo normale bivariée 1.6 % 12 Vert Non Oui
VaR Monte-Carlo Student-4 bivariée 0.3 % 2 Vert Non Oui
Remarque : les colonnes % et Nombre correspondent aux dépassements

Sur cette période, hormis les mesures à volatilité RiskMetrics, toutes obtiennent un bon résultat au Traffic Light Test. En revanche, seule la VaR ARMA-eGARCH passe les tests de Kupiec et Christoffersen. C’est donc à nouveau la mesure de risque la plus performante. On remarque qu’avec repricing ou non les performances de ce modèle sont les mêmes. Ainsi les mesures paramétriques ou semi-paramétriques sans repricing peuvent être un bon choix pour les futures. Les VaRs par Monte-Carlo étant trop conservatrices elles échouent au test de Kupiec, tandis que les VaRs historiques, ne suivant pas les tendances réelles du marché au jour le jour, échouent au test de Christoffersen car les dépassements ne sont pas indépendants. Finalement, les VaRs paramétriques à volatilité GARCH sont trop conservatrices et elles échouent donc logiquement au test de Kupiec. On conclut donc que le meilleur modèle à 95% pour le future est le modèle ARMA-eGARCH sans repricing (car plus simple et aussi performant que son homologue avec repricing).

9.2.1. VaRs à 99%

var.99<-merge(delta[[1]][,2],delta[[1]][,4], cf[[1]][,2], cf[[1]][,4], bbm[[1]][,1], pot[[1]][,1], pot[[1]][,2], model[[3]][,2], model[[1]][,2], histo[[1]][,2], histo_mv[[1]][,2], mc_n[[1]][,2], mc_n_bv[[1]][,2], mc_std_bv[[1]][,2])
var.99<-comparison(var.99, fut_returns)
names<-c("Delta-normale volatilité RiskMetrics", "Delta-normale volatilité GARCH(1,1)", "Cornish-Fisher volatilité RiskMetrics", "Cornish-Fisher volatilité GARCH(1,1)", "Maxima par blocs", "Peaks-Over-Treshold volatilité RiskMetrics", "Peaks-Over-Treshold volatilité GARCH(1,1)", "ARMA(3,3)-eGARCH(2,1) sged", "ARMA(3,3)-eGARCH(2,1) sged repricing", "Historique univariée", "Historique bivariée", "Monte-Carlo normale univariée", "Monte-Carlo normale bivariée", "Monte-Carlo Student-4 bivariée")
n<-length(index(var.99))
p.table.back(tests(var.99, names, 0.99, n), "Tests statistiques sur les VaRs du future sur le S\\&P500 à 99\\% (2015-2020)", c(" "=1, "Traffic Light" = 3, "Kupiec"=1, "Christoffersen" =1), 8, 14)
Tests statistiques sur les VaRs du future sur le S&amp;P500 à 99% (2015-2020)
Traffic Light
Kupiec
Christoffersen
% Nombre Zone Concluant Concluant
VaRs paramétriques et semi-paramétriques
VaR Delta-normale volatilité RiskMetrics 10 % 126 Rouge Non Oui
VaR Delta-normale volatilité GARCH(1,1) 2.1 % 27 Jaune Non Oui
VaR Cornish-Fisher volatilité RiskMetrics 10 % 126 Rouge Non Oui
VaR Cornish-Fisher volatilité GARCH(1,1) 2.1 % 27 Jaune Non Oui
VaR Maxima par blocs 2.7 % 34 Rouge Non Oui
VaR Peaks-Over-Treshold volatilité RiskMetrics 9.5 % 120 Rouge Non Oui
VaR Peaks-Over-Treshold volatilité GARCH(1,1) 2 % 25 Jaune Non Oui
VaR ARMA(3,3)-eGARCH(2,1) sged 2.1 % 27 Jaune Non Oui
VaRs par simulation et repricing
VaR ARMA(3,3)-eGARCH(2,1) sged repricing 2.1 % 27 Jaune Non Oui
VaR Historique univariée 1.7 % 21 Jaune Oui Non
VaR Historique bivariée 1.7 % 21 Jaune Oui Non
VaR Monte-Carlo normale univariée 2.1 % 27 Jaune Non Oui
VaR Monte-Carlo normale bivariée 1.3 % 17 Vert Oui Oui
VaR Monte-Carlo Student-4 bivariée 0.7 % 9 Vert Oui Oui
Remarque : les colonnes % et Nombre correspondent aux dépassements

Les résultats sont encore une fois plutôt mauvais à l’exception des VaRs par simulation de Monte-Carlo bivariée. Voyons ce qu’il en est sur 3 ans :

var.99<-merge(delta[[1]][,2],delta[[1]][,4], cf[[1]][,2], cf[[1]][,4], bbm[[1]][,1], pot[[1]][,1], pot[[1]][,2], model[[3]][,2], model[[1]][,2], histo[[1]][,2], histo_mv[[1]][,2], mc_n[[1]][,2], mc_n_bv[[1]][,2], mc_std_bv[[1]][,2])
var.99<-comparison(var.99, fut_returns)["/20180831"]
names<-c("Delta-normale volatilité RiskMetrics", "Delta-normale volatilité GARCH(1,1)", "Cornish-Fisher volatilité RiskMetrics", "Cornish-Fisher volatilité GARCH(1,1)", "Maxima par blocs", "Peaks-Over-Treshold volatilité RiskMetrics", "Peaks-Over-Treshold volatilité GARCH(1,1)", "ARMA(3,3)-eGARCH(2,1) sged", "ARMA(3,3)-eGARCH(2,1) sged repricing", "Historique univariée", "Historique bivariée", "Monte-Carlo normale univariée", "Monte-Carlo normale bivariée", "Monte-Carlo Student-4 bivariée")
n<-length(index(var.99))
p.table.back(tests(var.99, names, 0.99, n), "Tests statistiques sur les VaRs du future sur le S\\&P500 à 99\\% (2015-2018)", c(" "=1, "Traffic Light" = 3, "Kupiec"=1, "Christoffersen" =1), 8, 14)
Tests statistiques sur les VaRs du future sur le S&amp;P500 à 99% (2015-2018)
Traffic Light
Kupiec
Christoffersen
% Nombre Zone Concluant Concluant
VaRs paramétriques et semi-paramétriques
VaR Delta-normale volatilité RiskMetrics 9.9 % 75 Rouge Non Oui
VaR Delta-normale volatilité GARCH(1,1) 1.3 % 10 Vert Oui Non
VaR Cornish-Fisher volatilité RiskMetrics 9.9 % 75 Rouge Non Oui
VaR Cornish-Fisher volatilité GARCH(1,1) 1.3 % 10 Vert Oui Non
VaR Maxima par blocs 0.9 % 7 Vert Oui Oui
VaR Peaks-Over-Treshold volatilité RiskMetrics 9.5 % 72 Rouge Non Oui
VaR Peaks-Over-Treshold volatilité GARCH(1,1) 1.2 % 9 Vert Oui Non
VaR ARMA(3,3)-eGARCH(2,1) sged 1.3 % 10 Vert Oui Oui
VaRs par simulation et repricing
VaR ARMA(3,3)-eGARCH(2,1) sged repricing 1.3 % 10 Vert Oui Oui
VaR Historique univariée 1.2 % 9 Vert Oui Oui
VaR Historique bivariée 1.2 % 9 Vert Oui Oui
VaR Monte-Carlo normale univariée 1.3 % 10 Vert Oui Non
VaR Monte-Carlo normale bivariée 0.3 % 2 Vert Oui Oui
VaR Monte-Carlo Student-4 bivariée 0.1 % 1 Vert Non Oui
Remarque : les colonnes % et Nombre correspondent aux dépassements

Parmi les méthodes paramétriques et semi-paramétriques, la VaR par maxima par blocs et la VaR ARMA-eGARCH passent l’ensemble des tests. Cependant, la première est constante sur la période et ne reflète donc pas les besoins de couverture d’une banque. Elle ne sera donc pas retenue. Cinq VaRs sont satisfaisantes selon nos critères :

  • VaR ARMA-eGARCH sans repricing
  • VaR ARMA-eGARCH avec repricing
  • VaR Historique univariée
  • VaR Historique bivariée
  • VaR Monte-Carlo normale bivariée

Seules les VaRs univariées font sens dans le cadre du future car intégrer la corrélation entre les variations du S&P500 et du VIX n’est pas nécessaire pour ce produit. On préfèrera donc les méthodes univariées. Ceci fournit finalement trois VaRs satisfaisantes, la VaR ARMA-eGARCH avec et sans repricing et la VaR Historique univariée. Nous retiendrons donc que les deux meilleures mesures sont la VaR ARMA-eGARCH sans repricing (plus simple que celle avec) et la VaR Historique univariée.

9.2. Performance de la VaR de l’option européenne sur le S&P500

9.2.1. VaRs à 95%

var.95<-merge(delta[[1]][,5],delta[[1]][,7], cf[[1]][,5], cf[[1]][,7], model[[3]][,3] ,model[[1]][,3], histo[[1]][,3], histo_mv[[1]][,3], mc_n[[1]][,3], mc_n_bv[[1]][,3], mc_std_bv[[1]][,3])
var.95<-comparison(var.95, opt_returns$rdt)
names<-c("Delta-normale volatilité RiskMetrics", "Delta-normale volatilité GARCH(1,1)", "Cornish-Fisher volatiltié RiskMetrics", "Cornish-Fisher volatiltié GARCH(1,1)","ARMA(3,3)-eGARCH(2,1) sged", "ARMA(3,3)-eGARCH(2,1) sged repricing", "Historique univariée", "Historique bivariée", "Monte-Carlo normale univariée", "Monte-Carlo normale bivariée", "Monte-Carlo Student-4 bivariée")
n<-length(index(var.95))
p.table.back(tests(var.95, names, 0.95, n), "Tests statistiques sur les VaRs de l'option sur le S\\&P500 à 95\\% (2015-2020)", c(" "=1, "Traffic Light" = 3, "Kupiec"=1, "Christoffersen" =1), 5, 11)
Tests statistiques sur les VaRs de l’option sur le S&amp;P500 à 95% (2015-2020)
Traffic Light
Kupiec
Christoffersen
% Nombre Zone Concluant Concluant
VaRs paramétriques et semi-paramétriques
VaR Delta-normale volatilité RiskMetrics 49.1 % 619 Rouge Non Non applicable
VaR Delta-normale volatilité GARCH(1,1) 47.4 % 597 Rouge Non Non applicable
VaR Cornish-Fisher volatiltié RiskMetrics 49.1 % 619 Rouge Non Non applicable
VaR Cornish-Fisher volatiltié GARCH(1,1) 47.4 % 597 Rouge Non Non applicable
VaR ARMA(3,3)-eGARCH(2,1) sged 46.7 % 588 Rouge Non Non applicable
VaRs par simulation et repricing
VaR ARMA(3,3)-eGARCH(2,1) sged repricing 1.1 % 14 Vert Non Oui
VaR Historique univariée 0.6 % 7 Vert Non Non
VaR Historique bivariée 1.1 % 14 Vert Non Oui
VaR Monte-Carlo normale univariée 0.1 % 1 Vert Non Oui
VaR Monte-Carlo normale bivariée 0.6 % 7 Vert Non Non
VaR Monte-Carlo Student-4 bivariée 0.5 % 6 Vert Non Non
Remarque : les colonnes % et Nombre correspondent aux dépassements

Il apparaît de manière évidente que les mesures paramétriques et semi-paramétriques sans repricing sont totalement inadaptées à l’option. Si les autres mesures réussissent le Traffic Light Test car très conservatrices, aucune ne passe les deux autres avec succès. Fait intéréssant, les mesures bivariées performent mieux que leurs homologues univariées avec, à chaque fois, un pourcentage de dépassement plus proche de 5%. Nous retiendrons ici les mesures de VaR ARMA-eGARCH avec repricing et de VaR Historique bivariée.

Sur 3 ans :

var.95<-merge(delta[[1]][,5],delta[[1]][,7], cf[[1]][,5], cf[[1]][,7], model[[3]][,3] ,model[[1]][,3], histo[[1]][,3], histo_mv[[1]][,3], mc_n[[1]][,3], mc_n_bv[[1]][,3], mc_std_bv[[1]][,3])
var.95<-comparison(var.95, opt_returns$rdt)["/20180831"]
names<-c("Delta-normale volatilité RiskMetrics", "Delta-normale volatilité GARCH(1,1)", "Cornish-Fisher volatiltié RiskMetrics", "Cornish-Fisher volatiltié GARCH(1,1)","ARMA(3,3)-eGARCH(2,1) sged", "ARMA(3,3)-eGARCH(2,1) sged repricing", "Historique univariée", "Historique bivariée", "Monte-Carlo normale univariée", "Monte-Carlo normale bivariée", "Monte-Carlo Student-4 bivariée")
n<-length(index(var.95))
p.table.back(tests(var.95, names, 0.95, n), "Tests statistiques sur les VaRs de l'option sur le S\\&P500 à 95\\% (2015-2018)", c(" "=1, "Traffic Light" = 3, "Kupiec"=1, "Christoffersen" =1), 5, 11)
Tests statistiques sur les VaRs de l’option sur le S&amp;P500 à 95% (2015-2018)
Traffic Light
Kupiec
Christoffersen
% Nombre Zone Concluant Concluant
VaRs paramétriques et semi-paramétriques
VaR Delta-normale volatilité RiskMetrics 49.5 % 375 Rouge Non Oui
VaR Delta-normale volatilité GARCH(1,1) 48.1 % 364 Rouge Non Oui
VaR Cornish-Fisher volatiltié RiskMetrics 49.5 % 375 Rouge Non Oui
VaR Cornish-Fisher volatiltié GARCH(1,1) 48.1 % 364 Rouge Non Oui
VaR ARMA(3,3)-eGARCH(2,1) sged 47 % 356 Rouge Non Oui
VaRs par simulation et repricing
VaR ARMA(3,3)-eGARCH(2,1) sged repricing 1.1 % 8 Vert Non Oui
VaR Historique univariée 0.4 % 3 Vert Non Oui
VaR Historique bivariée 0.9 % 7 Vert Non Oui
VaR Monte-Carlo normale univariée 0.1 % 1 Vert Non Oui
VaR Monte-Carlo normale bivariée 0.1 % 1 Vert Non Oui
VaR Monte-Carlo Student-4 bivariée 0.1 % 1 Vert Non Oui
Remarque : les colonnes % et Nombre correspondent aux dépassements

On réalise ici le même constat que précédemment avec en prime un avantage pour la VaR ARMA-eGARCH avec repricing qui performe un peu mieux que l’Historique bivariée.

9.2.1. VaRs à 99%

var.99<-merge(delta[[1]][,6],delta[[1]][,8], cf[[1]][,6], cf[[1]][,8], bbm[[1]][,1], pot[[1]][,3], pot[[1]][,4], model[[3]][,4] ,model[[1]][,4], histo[[1]][,4], histo_mv[[1]][,4], mc_n[[1]][,4], mc_n_bv[[1]][,4], mc_std_bv[[1]][,4])
var.99<-comparison(var.99, opt_returns$rdt)
names<-c("Delta-normale volatilité RiskMetrics", "Delta-normale volatilité GARCH(1,1)", "Cornish-Fisher volatiltié RiskMetrics", "Cornish-Fisher volatiltié GARCH(1,1)", "Maxima par blocs", "Peaks-Over-Treshold volatilité RiskMetrics", "Peaks-Over-Treshold volatilité GARCH(1,1)", "ARMA(3,3)-eGARCH(2,1) sged","ARMA(3,3)-eGARCH(2,1) sged repricing", "Historique univariée", "Historique bivariée", "Monte-Carlo normale univariée", "Monte-Carlo normale bivariée", "Monte-Carlo Student-4 bivariée")
n<-length(index(var.99))
p.table.back(tests(var.99, names, 0.99, n), "Tests statistiques sur les VaRs de l'option sur le S\\&P500 à 99\\% (2015-2020)", c(" "=1, "Traffic Light" = 3, "Kupiec"=1, "Christoffersen" =1), 8, 14)
Tests statistiques sur les VaRs de l’option sur le S&amp;P500 à 99% (2015-2020)
Traffic Light
Kupiec
Christoffersen
% Nombre Zone Concluant Concluant
VaRs paramétriques et semi-paramétriques
VaR Delta-normale volatilité RiskMetrics 47.2 % 595 Rouge Non Non applicable
VaR Delta-normale volatilité GARCH(1,1) 44.5 % 561 Rouge Non Non applicable
VaR Cornish-Fisher volatiltié RiskMetrics 47.2 % 595 Rouge Non Non applicable
VaR Cornish-Fisher volatiltié GARCH(1,1) 44.5 % 561 Rouge Non Non applicable
VaR Maxima par blocs 35.7 % 450 Rouge Non Non applicable
VaR Peaks-Over-Treshold volatilité RiskMetrics 46.9 % 591 Rouge Non Non applicable
VaR Peaks-Over-Treshold volatilité GARCH(1,1) 44 % 554 Rouge Non Non applicable
VaR ARMA(3,3)-eGARCH(2,1) sged 43.6 % 549 Rouge Non Non applicable
VaRs par simulation et repricing
VaR ARMA(3,3)-eGARCH(2,1) sged repricing 0.1 % 1 Vert Non Oui
VaR Historique univariée 0 % 0 Vert Non Oui
VaR Historique bivariée 0.5 % 6 Vert Oui Oui
VaR Monte-Carlo normale univariée 0.1 % 1 Vert Non Oui
VaR Monte-Carlo normale bivariée 0.4 % 5 Vert Oui Oui
VaR Monte-Carlo Student-4 bivariée 0.2 % 3 Vert Non Non
Remarque : les colonnes % et Nombre correspondent aux dépassements

Au niveau 99% ce sont les deux VaRs, Historique bivariée et Monte-Carlo normale bivariée qui performent le mieux en réussissant l’ensemble des tests. Les autres VaRs par simulation étant trop conservatrices.

Sur 3 ans :

var.99<-merge(delta[[1]][,6],delta[[1]][,8], cf[[1]][,6], cf[[1]][,8], bbm[[1]][,1], pot[[1]][,3], pot[[1]][,4], model[[3]][,4] ,model[[1]][,4], histo[[1]][,4], histo_mv[[1]][,4], mc_n[[1]][,4], mc_n_bv[[1]][,4], mc_std_bv[[1]][,4])
var.99<-comparison(var.99, opt_returns$rdt)["/20180831"]
names<-c("Delta-normale volatilité RiskMetrics", "Delta-normale volatilité GARCH(1,1)", "Cornish-Fisher volatiltié RiskMetrics", "Cornish-Fisher volatiltié GARCH(1,1)", "Maxima par blocs", "Peaks-Over-Treshold volatilité RiskMetrics", "Peaks-Over-Treshold volatilité GARCH(1,1)", "ARMA(3,3)-eGARCH(2,1) sged","ARMA(3,3)-eGARCH(2,1) sged repricing", "Historique univariée", "Historique bivariée", "Monte-Carlo normale univariée", "Monte-Carlo normale bivariée", "Monte-Carlo Student-4 bivariée")
n<-length(index(var.99))
p.table.back(tests(var.99, names, 0.99, n), "Tests statistiques sur les VaRs de l'option sur le S\\&P500 à 99\\% (2015-2018)", c(" "=1, "Traffic Light" = 3, "Kupiec"=1, "Christoffersen" =1), 8, 14)
Tests statistiques sur les VaRs de l’option sur le S&amp;P500 à 99% (2015-2018)
Traffic Light
Kupiec
Christoffersen
% Nombre Zone Concluant Concluant
VaRs paramétriques et semi-paramétriques
VaR Delta-normale volatilité RiskMetrics 48.6 % 368 Rouge Non Oui
VaR Delta-normale volatilité GARCH(1,1) 45.6 % 345 Rouge Non Oui
VaR Cornish-Fisher volatiltié RiskMetrics 48.6 % 368 Rouge Non Oui
VaR Cornish-Fisher volatiltié GARCH(1,1) 45.6 % 345 Rouge Non Oui
VaR Maxima par blocs 35.1 % 266 Rouge Non Oui
VaR Peaks-Over-Treshold volatilité RiskMetrics 48.3 % 366 Rouge Non Oui
VaR Peaks-Over-Treshold volatilité GARCH(1,1) 44.8 % 339 Rouge Non Oui
VaR ARMA(3,3)-eGARCH(2,1) sged 44.1 % 334 Rouge Non Oui
VaRs par simulation et repricing
VaR ARMA(3,3)-eGARCH(2,1) sged repricing 0 % 0 Vert Non Oui
VaR Historique univariée 0 % 0 Vert Non Oui
VaR Historique bivariée 0.3 % 2 Vert Oui Oui
VaR Monte-Carlo normale univariée 0.1 % 1 Vert Non Oui
VaR Monte-Carlo normale bivariée 0 % 0 Vert Non Oui
VaR Monte-Carlo Student-4 bivariée 0 % 0 Vert Non Oui
Remarque : les colonnes % et Nombre correspondent aux dépassements

Cette fois-ci, seule la VaR Historique bivariée réussit les tests. C’est donc celle-ci que l’on retiendra.

Conclusion

Le premier enseignement de cette étude est que les mesures de risque à volatilité RiskMetrics ne sont pas satisfaisantes : elles sous-estiment systématiquement le risque et connaissent ainsi beaucoup trop de dépassements. On leur préférera donc les mesures à volatilité GARCH. En outre, la nécessité de recalibrer les modèles s’impose à la vue des résultats de backtesting sur 5 ans qui sont très mauvais.

En ce qui concerne les VaRs du S&P500, à 95% les mesures de risque à volatilité GARCH et la VaR ARMA-eGARCH sont performantes au regard du Traffic Light Test. Cependant, les deux mesures de VaR à volatilité GARCH sont trop conservatrices et échouent donc au test de Kupiec si bien que la mesure la plus adaptée est la VaR ARMA-eGARCH. On note par ailleurs que les modèles Delta-normal et Cornish-Fisher fournissent quasiment les mêmes résultats si bien que le second paraît inutile. Les ajustements de kurtosis et de skew ne sont pas nécessaires. Au niveau 99%, le constat reste le même. De plus, les mesures de risque extrêmes, calculées uniquement à ce niveau de risque, sont performantes. Celle par la méthode des blocs de maxima ne sera toutefois pas retenue car elle est incompatible avec les exigences de couverture réelles des banques. Nous retiendrons finalement encore la mesure ARMA-eGARCH car elle est la seule à réussir l’ensemble des tests statistiques.

Pour les produits dérivés linéaires comme le future sur le S&P500, les mesures paramétriques à volatilité GARCH restent de bons choix en ce qui concerne le Traffic Light Test. Trop conservatrices, elles échouent au test de Kupiec et leurs dépassements ne sont pas indépendants. Ces mesures peuvent être utilisées comme première approximation pour les besoins de couverture mais ne sont pas satisfaisantes statistiquement. Étonnement, les VaRs historiques sont plus performantes que les VaRs Monte-Carlo (assez conservatrices mais pas à outrance), ce qui justifie le choix souvent effectué par les institutions financières. Toutefois, elles ne satisfont pas l’indépendance des dépassements. La VaR ARMA-eGARCH, elle, y souscrit. Les résultats avec ou sans repricing sont les mêmes, nous retiendrons donc que le modèle semi-paramétrique ARMA-eGARCH sans repricing est le meilleur choix pour les dérivés linéaires. Étant données la gourmandise calculatoire et la difficulté de mise en œuvre de cette méthode nous notons que la VaR historique univariée peut être une alternative judicieuse pour les produits dérivés linéaires. Par extension, bien que non calculée, on peut déduire qu’elle serait une bonne alternative comme mesure de VaR du S&P500 lui-même.

Les produits non linéaires comme les options nécessitent une attention toute particulière dans l’évaluation de leurs risques. Ces instruments demandent une réévaluation pour mieux tenir compte des risques. Les mesures paramétriques et semi-paramétriques sans repricing sont totalement inadaptées comme attendu. C’est donc sans surprise que les candidats satisfaisants se retrouvent parmi les VaRs par simulation et repricing. Dans l’ensemble, celles-ci sont très conservatrices si bien qu’elles réussissent très rarement le test de Kupiec. Au niveau 95%, la VaR ARMA-eGARCH est la moins conservatrice tout en restant dans la zone verte du Traffic Light Test : elle est donc un des meilleurs choix avec la VaR historique bivariée qui fournit des résultats comparables. Au niveau 99% c’est la VaR historique bivariée qui performe le mieux. En définitive, c’est cette dernière qui sera retenue car plus facile à mettre en oeuvre.

Nous pourrions donc résumer les enseignements de ce document comme suit :