Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
braverock
GitHub Repository: braverock/portfolioanalytics
Path: blob/master/sandbox/paper_analysis/insample/estimationfunctions.R
1433 views
1
2
#-----------------------------------------------------------
3
# General functions
4
#-----------------------------------------------------------
5
6
vech <- function(x){
7
t(x[!upper.tri(x)])
8
}
9
10
lvech <- function(x){
11
t(x[!upper.tri(x, diag = T)])
12
}
13
14
#-----------------------------------------------------------
15
# Functions for the GARCH estimation
16
#-----------------------------------------------------------
17
18
hatsigma <- function( par , x ,uncH){
19
# see: code underlying fGarch package of Chalaby and Wuertz
20
alpha = par[1] ; beta = par[2];
21
omega = uncH*(1-alpha-beta)
22
s2 = rep( uncH , T )
23
e2 <- x^2
24
e2t <- omega + alpha*c(mean(e2),e2[-length(x)])
25
s2 <- filter(e2t, beta, "recursive", init = uncH )
26
return(s2)
27
}
28
29
llhGarch11N <- function(par, x, uncH){
30
# see: code underlying fGarch package of Chalaby and Wuertz
31
x = as.numeric(x)
32
s2 = hatsigma( par = par , x = x ,uncH=uncH)
33
return( sum( log(s2) + x^2/s2 ))
34
}
35
36
weightedvariance = function( u ){
37
k = qchisq(0.99,df=1) ;
38
jumpIndicator = ( (u/mad(u))^2<=k )
39
ufilt = u[jumpIndicator]
40
uncH = mean(ufilt^2,na.rm=TRUE)*(0.99/pchisq(k,df=3))
41
return(uncH)
42
# check: U = matrix( rnorm(500000),ncol=100) ; mean(apply(U,2,'weightedvariance'))
43
}
44
45
46
garchVol = function( mR.centered , parN ){
47
S = c();
48
S_forecast = c();
49
N = ncol(mR.centered)
50
vuncH = apply( mR.centered , 2 , 'weightedvariance' )
51
for( i in 1:N ){
52
uncH = vuncH[i]
53
# do the garch estimation
54
# fitN <- try( nlminb(start=parN, objective=llhGarch11N , x = mR.centered[,i], lower=lowN, upper=upN,
55
# control=list(x.tol = 1e-8,trace=0)) )
56
# do the garch estimation with constraints to unsure covariance stationarity ie alpha + beta < 1
57
fitN <- try( constrOptim( theta = parN , f = llhGarch11N , ui=rbind(c(1,0),c(0,1),c(-1,0),c(0,-1),c(-1,-1) ),
58
ci=c(0,0,-1,-1,-1), grad=NULL, x = mR.centered[,i], uncH=uncH) )
59
60
LLH_constant = llhGarch11N( par=c(0,0), x=mR.centered[,i], uncH = uncH )
61
if( !inherits(fitN, "try-error") ){ LLH_garch = -fitN$value }else{ LLH_garch = LLH_constant }
62
# Likelihood ratio test statistic for the case of time-varying garch effects
63
# cases where garch volatility is probably not reliable or the volatility forecasts are so erratic that a constant garch works fine
64
useGARCHd = TRUE
65
if( LLH_garch=="NaN" | (fitN$par[1]>= 0.1&fitN$par[2]<=0.7) | sum(fitN$par)>=0.999 ){
66
LLH_garch = LLH_constant ;
67
useGARCHd = F;
68
} #volatility is too erratic
69
# Data is from inception: once we start using garch, we continue to ensure stability of the forecasts
70
# Likelihood ratio test for a time-varying vol model
71
if( 2*(LLH_garch-LLH_constant) <= qchisq(0.999,df=2) & (!useGARCHd) ){
72
sigmat = rep( sd( as.vector(mR.centered[,i])), length(mR.centered[,i]) );
73
S_forecast = c( S_forecast ,sqrt(uncH))
74
}else{
75
sigmat = sqrt(hatsigma( par = fitN$par , x = mR.centered[,i] , uncH=uncH ) )
76
lastsigmat = tail(sigmat,1)
77
if( lastsigmat=="NaN" | is.na(lastsigmat) ){
78
print( c("NaN day", d , "for asset" , i) );
79
sigmat = rep( sqrt(uncH) , length(mR.centered[,i]) );
80
# print(c("unc sd",sqrt(uncH) ))
81
S_forecast = c( S_forecast , sqrt(uncH) )
82
}else{
83
e2 = as.numeric(tail(mR.centered[,i],1)^2)
84
S_forecast = c( S_forecast ,
85
sqrt( uncH*(1-sum(fitN$par))+ fitN$par[1]*e2+ fitN$par[2]*lastsigmat^2 ) )
86
}
87
}
88
S = cbind( S , sigmat )
89
}
90
return( list(S,S_forecast) )
91
}
92
93
#-----------------------------------------------------------
94
# Fuction for the shrinkage correlation
95
#-----------------------------------------------------------
96
97
98
shrinkagecorrelation = function( mDevolR.centered ){
99
N = ncol( mDevolR.centered )
100
# Unconditional correlation estimate is shrinkage between sample (spearman) correlation and equicorrelation
101
sample = cor(mDevolR.centered,method="spearman") #make it robust by using ranks
102
# Elton and Gruber: same correlation across all assets
103
rho = mean( lvech(sample) )
104
I = diag( rep(1,N) ) ; J = matrix( rep(1,N^2) , ncol=N )
105
target = (1-rho)*I + rho*J
106
# The shrinkage estimate = delta*target F + (1-delta)* sample S
107
kappahat = shrinkage.intensity( mDevolR.centered , prior = target , sample = sample )
108
delta = max( 0 , min(kappahat/T,1) )
109
C = delta*target +(1-delta)*sample
110
return(C)
111
}
112
113
114
#-----------------------------------------------------------
115
# Functions for the DCC estimation
116
#-----------------------------------------------------------
117
118
119
DCCestimation = function( mDevolR.centered , parN , uncR ){
120
#fitN <- try( nlminb(start=parN, objective=loglik.dcc2.DECO , lower=lowN, upper=upN,
121
# control=list(x.tol = 1e-8,trace=0)) )
122
# Ensure covariance stationarity
123
N = ncol( mDevolR.centered )
124
I = diag( rep(1,N) ) ; J = matrix( rep(1,N^2) , ncol=N )
125
rho = mean( lvech(uncR) )
126
fitN <- try( constrOptim( theta = parN , f = loglik.dcc2.DECO , ui=rbind(c(1,0),c(0,1),c(-1,0),c(0,-1),c(-1,-1) ),
127
ci=c(lowN,-upN,-1), grad=NULL, uncR= uncR , mDevolR.centered=mDevolR.centered ) )
128
# compare with constant correlation case
129
LLH_constant = 0;
130
invtarget = (1/(1-rho))*( I - rho/( 1+(N-1)*rho )*J );
131
for(t in 2:nrow(mDevolR.centered)){
132
st = matrix( mDevolR.centered[t,] , ncol = 1 );
133
LLH_constant = LLH_constant + log( det(uncR) ) + t(st)%*%invtarget%*%st
134
}
135
LLH_constant = - LLH_constant
136
if( !inherits(fitN, "try-error") ){ LLH_DCC = -fitN$value }else{ LLH_DCC = -LLH_constant }
137
# Likelihood ratio test statistic for the case of time-varying garch effects
138
# cases where garch volatility is probably not reliable or the volatility forecasts are so erratic that a constant garch works fine
139
if( LLH_DCC=="NaN" | (fitN$par[1]>= 0.1&fitN$par[2]<=0.7) | sum(fitN$par)>=0.999 ){
140
LLH_DCC = LLH_constant ;
141
useDCC = F;
142
} #volatility is too erratic
143
if( 2*(LLH_DCC-LLH_constant) <= qchisq(0.999,df=2) ){
144
Rt = uncR;
145
}else{
146
print( c("use DCC with parameters",fitN$par) )
147
Rt = Rforecast(fitN$par,mR=mDevolR.centered,uncR=C)
148
}
149
return(Rt)
150
}
151
152
Rforecast <- function(par,mR,uncR){
153
T = nrow(mR); N = ncol(mR)
154
alpha = par[1] ; beta = par[2];
155
omega = (1-par[1]-par[2])*uncR
156
Qt = diag( rep(1,N) )
157
k = 1
158
for( i in 2:N ){
159
for(j in 1:(i-1)){
160
e2 = mR[,i]*mR[,j];
161
e2[is.na(e2)] = mean( na.omit(e2 ) )
162
e2t <- omega[i,j] + alpha*c(mean(e2),e2[-length(e2)], tail(e2,1) )
163
Qt[i,j] = Qt[j,i] = tail(filter(e2t, beta, "recursive", init = uncR[i,j] ),1)
164
}
165
}
166
167
return( diag(diag(Qt)^(-0.5))%*%Qt%*%diag(diag(Qt)^(-0.5)) )
168
}
169
# test; uncR=diag(c(1,1)) ; Rforecast( c(0.05,0.4) , matrix(rnorm(400),ncol=2),uncR)
170
171
loglik.dcc2.DECO = function (param,uncR,mDevolR.centered)
172
{
173
require('ccgarch')
174
dvar = mDevolR.centered
175
nobs <- dim(dvar)[1]
176
ndim <- dim(dvar)[2]
177
out <- .Call("dcc_est", dvar, uncR, param[1], param[2])
178
DCC <- dcc.est(dvar, param)$DCC
179
lf <- numeric(ndim)
180
I = diag( rep(1,ndim) ) ; J = matrix( rep(1,ndim^2) , ncol=ndim )
181
for (i in 1:nobs) {
182
R <- matrix(DCC[i, ], ndim, ndim)
183
rho = mean( lvech(R) )
184
DECO = (1-rho)*I + rho*J
185
invDECO = (1/(1-rho))*( I - rho/( 1+(ndim-1)*rho )*J )
186
lf[i] <- log(det(DECO)) + sum(dvar[i, ] * crossprod(invDECO,
187
dvar[i, ]))
188
}
189
sum(lf)
190
}
191
192
193