APARCH model
APARCH model
Hi Tom,
I'd like to try the APARCH model (as it is a 'general' model) https://estima.com/webhelp/topics/garchuvmaxrpf.html
Aim: backtest and generate multistep ahead VaR and ES forecasts as viewtopic.php?t=3645, for financial returns.
So two approaches:
(a) analytical: the analytical formulae are complicated!
(b) simulate/bootstrap: a better approach maybe simulate/bootstrap, if it is based on something like https://estima.com/webhelp/topics/garchbootrpf.html
Views/suggestions?
Amarjit
I'd like to try the APARCH model (as it is a 'general' model) https://estima.com/webhelp/topics/garchuvmaxrpf.html
Aim: backtest and generate multistep ahead VaR and ES forecasts as viewtopic.php?t=3645, for financial returns.
So two approaches:
(a) analytical: the analytical formulae are complicated!
(b) simulate/bootstrap: a better approach maybe simulate/bootstrap, if it is based on something like https://estima.com/webhelp/topics/garchbootrpf.html
Views/suggestions?
Amarjit
Re: APARCH model
Is there an analytical formula? If there is, it will be much more efficient. You need a very large number of simulations to properly estimate tail events.
Re: APARCH model
It's always possible to do simulations. It just takes a lot of them to do an accurate calculation involving tail events. (Like maybe 10^6).
Re: APARCH model
Here's an attempt at a rolling bootstrap based on those links. I think it's correct, however please check.
Code: Select all
do jj = 0, %allocend()-WE-1
*===============================
*
* Parameter sets
*
linreg dlp tstart+1+jj tend+1+jj
# constant; * removed ar(1) term for consistency
frml(lastreg,vector=beta) meanf
nonlin(parmset=meanparms) beta
*
*===============================
*
* APARCH (asymmetric power GARCH)
*
set uu = %seesq
set h = %seesq
set u = 0.0
nonlin(parmset=APARCHparms) c a b
nonlin(parmset=powerparms) lambda
nonlin(parmset=asymmparms) d
compute a=0.0
compute b=0.0
compute c=%seesq
compute lambda=2.0; * baseline
compute d=0.0
frml varf = uupower=uu{1}^(.5*lambda),$
(c+a*uupower+d*%if(u{1}<0,uupower,0.0)+b*h{1}^(.5*lambda))^(2.0/lambda)
frml logl = (h(t)=varf(t)),$
(u=dlp-meanf),$
(uu(t)=u^2),$
%logdensity(h,u)
maximize(parmset=meanparms+APARCHparms+asymmparms+powerparms,title="APARCH (asymmetric power GARCH)") logl tstart+1+jj tend+1+jj
compute gstart=%regstart(),gend=%regend()
compute b0=%beta(1); * b0=0.0
*
* Standardize the historical residuals
*
set ustandard gstart gend = u/sqrt(h)
dofor kk = 1 2 3
* kk-STEPS
* ========
*
* span is the number of periods over which returns are to be computed.
* ndraws is the number of bootstrapping draws
*
compute span=kk
compute ndraws=ndraws
*
* Extend out the h series (values aren't important--this is just to get
* the extra space).
*
set h gend+1 gend+span = h(gend)
*
dec vect returns(ndraws)
do draw=1,ndraws
*
* This draws standardized u's from the ustandard series
*
boot entries gend+1 gend+span gstart gend
*
* Simulate the APARCH model out of sample, scaling up the standardized
* residuals by the square root of the current h.
*
set udraw gend+1 gend+span = ustandard(entries)
set u gend+1 gend+span = (h(t)=varf(t)),udraw(t)*sqrt(h(t))
*
* Figure out the cumulative return over the span. As written, this
* allows for the continuation of the sample mean return. If you want
* to look at zero mean returns, take the b0 out.
*
sstats gend+1 gend+span meanf(t)+u>>returns(draw)
if jj==%allocend()-WE-1; set mybootseries(kk) 1 ndraws = returns(t); * TOOS returns 1 Day to 5 Day
end do draw
*
* Compute desired fractiles of the returns
*
compute [vect] VaR=%fractiles(returns,.01)
report(action=define,hlabels=||"VaR/100 sp500","ES/100 sp500"||)
do i=1,1
sstats(mean) 1 ndraws %if(returns(t)<=VaR(i),returns(t),%na)>>es
report(atrow=i,atcol=1) -VaR(i) -es
end do i
report(action=format,picture="*.###")
report(action=show)
comp [rect] mVaR(jj+1,kk) = %scalar(%fractiles(returns,.01))
comp [rect] mES(jj+1,kk) = %scalar(-es)
end dofor kk
INFOBOX(CURRENT=jj)
end do jj
*
infobox(action=remove)Re: APARCH model
You can check by pegging lambda to 2.0 (take the APARCHPARMS out of the PARMSET=....) which should give you the same results (subject to randomization) as a GJR GARCH model.
Re: APARCH model
There's something(s) not correct.
If I run with just 10,000 draws I get 'flat' forecasts! Via 'common-sense = more uncertainty' & even if I was to use sqrt-of-time-rule, regardless of methodology they should be increasing with horizon (as with all other previous estimations/forecasts which have been run using the GARCH instruction). With 100,000 draws the code takes far too long to run for 1 estimation, here I have METHOD=SIMPLEX and reduced CVCRIT.
Also, in above it should be:
comp [rect] mES(jj+1,kk) = %scalar(es)
Re: APARCH model
You have made a complete mess of the loop nesting. All the set up of the model can be done outside the loop over time. Plus you never use the mybootseries(kk) which are the actual multiperiod returns.
Re: APARCH model
Sorry, I don't understand. I have followed GARCHBOOT.RPF, what do I exactly change in the loop nesting?
Using RATS garch.asc data (as an example), this is APARCH backtest bootstrap code with results.
Code: Select all
*===============================
clear(all)
disp %dateandtime()
comp starttime = %cputime()
disp starttime
*===============================
open data garch.asc
data(format=free,org=columns) 1 1867 bp cd dm jy sf
set dlogjy = 100*log(jy/jy{1})
set dlp = dlogjy
prin /
*===============================
*
* MULTI-STEP APARCH (asymmetric power GARCH)
*
seed 100
*seed %today()
comp WIN = 1000
comp ndraws = 10000
compute tstart= 1
compute tend = WIN
*===============================
nonlin(parmset=APARCHparms) c a b
nonlin(parmset=powerparms) lambda
nonlin(parmset=asymmparms) d
*===============================
dec rect[real] mVaR(%allocend()-WIN,10)
dec rect[real] mES(%allocend()-WIN,10)
dec vector[series] mybootseries(10)
*===============================
infobox(action=define,lower=0,upper=%allocend()-WIN-1,progress) "APARCH (asymmetric power GARCH)-bootstrapped Model Backtest"
infobox(action=modify) "LONG"
*
*do jj = 0, %allocend()-WIN-1
do jj = %allocend()-WIN-1, %allocend()-WIN-1
*===============================
*
* Parameter sets
*
linreg dlp tstart+1+jj tend+1+jj
# constant; * removed ar(1) term for consistency
frml(lastreg,vector=beta) meanf
nonlin(parmset=meanparms) beta
*
*===============================
*
* APARCH (asymmetric power GARCH)
*
set uu = %seesq
set h = %seesq
set u = 0.0
compute a=0.0
compute b=0.0
compute c=%seesq
compute lambda=2.0; * baseline
compute d=0.0
frml varf = uupower=uu{1}^(.5*lambda),$
(c+a*uupower+d*%if(u{1}<0,uupower,0.0)+b*h{1}^(.5*lambda))^(2.0/lambda)
frml logl = (h(t)=varf(t)),$
(u=dlp-meanf),$
(uu(t)=u^2),$
%logdensity(h,u)
* APARCH: full model
maximize(parmset=meanparms+APARCHparms+asymmparms+powerparms,title="APARCH (asymmetric power GARCH)",METHOD=SIMPLEX,ITERS=5000,CVCRIT=0.001) logl tstart+1+jj tend+1+jj
* GJR-GARCH MODEL: equivalent
*maximize(parmset=meanparms+asymmparms+powerparms,title="GJR-GARCH MODEL: equivalent",METHOD=SIMPLEX,ITERS=5000,CVCRIT=0.001) logl tstart+1+jj tend+1+jj
compute gstart=%regstart(),gend=%regend()
compute b0=%beta(1); * b0=0.0
*
* Standardize the historical residuals
*
set ustandard gstart gend = u/sqrt(h)
dofor kk = 1 2 3 4 5 6 7 8 9 10
* kk-STEPS
* ========
*
* span is the number of periods over which returns are to be computed.
* ndraws is the number of bootstrapping draws
*
compute span=kk
compute ndraws=ndraws
*
* Extend out the h series (values aren't important--this is just to get
* the extra space).
*
set h gend+1 gend+span = h(gend)
*
dec vect returns(ndraws)
do draw=1,ndraws
*
* This draws standardized u's from the ustandard series
*
boot entries gend+1 gend+span gstart gend
*
* Simulate the APARCH model out of sample, scaling up the standardized
* residuals by the square root of the current h.
*
set udraw gend+1 gend+span = ustandard(entries)
set u gend+1 gend+span = (h(t)=varf(t)),udraw(t)*sqrt(h(t))
*
* Figure out the cumulative return over the span. As written, this
* allows for the continuation of the sample mean return. If you want
* to look at zero mean returns, take the b0 out.
*
sstats gend+1 gend+span meanf(t)+u>>returns(draw)
if jj==%allocend()-WIN-1; set mybootseries(kk) 1 ndraws = returns(t); * TOOS returns 1 Day to 10 Day
end do draw
*
* Compute desired fractiles of the returns
*
compute [vect] VaR=%fractiles(returns,.01)
report(action=define,hlabels=||"VaR/100 p","ES/100 p"||)
do i=1,1
sstats(mean) 1 ndraws %if(returns(t)<=VaR(i),returns(t),%na)>>es
report(atrow=i,atcol=1) -VaR(i) -es
end do i
report(action=format,picture="*.###")
report(action=show)
comp [rect] mVaR(jj+1,kk) = %scalar(%fractiles(returns,.01))
comp [rect] mES(jj+1,kk) = %scalar(es)
end dofor kk
INFOBOX(CURRENT=jj)
end do jj
*
infobox(action=remove)
*===============================*===============================
* ALL OOS
* =======
grparm(bold) header 18
* sVaR SERIES
* -----------
set sVAR_1 WIN+1+1 %allocend()+1 = -mVaR(t-WIN-1,1)
set sVaR_2 WIN+1+2 %allocend()+2 = -mVaR(t-WIN-2,2)
set sVaR_3 WIN+1+3 %allocend()+3 = -mVaR(t-WIN-3,3)
set sVAR_4 WIN+1+4 %allocend()+4 = -mVaR(t-WIN-4,4)
set sVaR_5 WIN+1+5 %allocend()+5 = -mVaR(t-WIN-5,5)
set sVaR_6 WIN+1+6 %allocend()+6 = -mVaR(t-WIN-6,6)
set sVAR_7 WIN+1+7 %allocend()+7 = -mVaR(t-WIN-7,7)
set sVaR_8 WIN+1+8 %allocend()+8 = -mVaR(t-WIN-8,8)
set sVaR_9 WIN+1+9 %allocend()+9 = -mVaR(t-WIN-9,9)
set sVAR_10 WIN+1+10 %allocend()+10 = -mVaR(t-WIN-10,10)
prin / sVaR_1 sVaR_2 sVaR_3 sVaR_4 sVaR_5 sVaR_6 sVaR_7 sVaR_8 sVaR_9 sVaR_10
*===============================
* Density Plots
* -------------
grparm(nobold) footer 18
density(smoothing=2.0) mybootseries(1) 1 ndraws g1Day f1Day
density(smoothing=2.0) mybootseries(2) 1 ndraws g2Day f2Day
density(smoothing=2.0) mybootseries(3) 1 ndraws g3Day f3Day
density(smoothing=2.0) mybootseries(4) 1 ndraws g4Day f4Day
density(smoothing=2.0) mybootseries(5) 1 ndraws g5Day f5Day
density(smoothing=2.0) mybootseries(6) 1 ndraws g6Day f6Day
density(smoothing=2.0) mybootseries(7) 1 ndraws g7Day f7Day
density(smoothing=2.0) mybootseries(8) 1 ndraws g8Day f8Day
density(smoothing=2.0) mybootseries(9) 1 ndraws g9Day f9Day
density(smoothing=2.0) mybootseries(10) 1 ndraws g10Day f10Day
spgraph(hea="p\\(forecast returns APARCH-bootstrapped 1 Day to 10 Day)\\LONG",vfi=1,hfi=1)
scatter(key=upleft,head="",footer="Conditional PDFs",style=lines) 10
# g1Day f1Day 1 ndraws 2
# g2Day f2Day 1 ndraws 3
# g3Day f3Day 1 ndraws 5
# g4Day f4Day 1 ndraws 6
# g5Day f5Day 1 ndraws 7
# g6Day f6Day 1 ndraws 8
# g7Day f7Day 1 ndraws 9
# g8Day f8Day 1 ndraws 10
# g9Day f9Day 1 ndraws 11
# g10Day f10Day 1 ndraws 12
spgraph(done)
*===============================
disp %dateandtime()
comp endtime = %cputime()
disp endtime
comp endtime_starttime = endtime - starttime
disp endtime_starttime
*do jj = 0, %allocend()-WIN-1; * backtest loop
do jj = %allocend()-WIN-1, %allocend()-WIN-1; * TOOS loop
mybootseries(kk) is used for the hth day TOOS density plots.
TOOS results with length of time
ndraws = 10000
Code: Select all
VaR/100 p ES/100 p
1.174 1.516
VaR/100 p ES/100 p
1.135 1.533
VaR/100 p ES/100 p
1.174 1.557
VaR/100 p ES/100 p
1.135 1.510
VaR/100 p ES/100 p
1.147 1.567
VaR/100 p ES/100 p
1.147 1.488
VaR/100 p ES/100 p
1.147 1.566
VaR/100 p ES/100 p
1.180 1.611
VaR/100 p ES/100 p
1.180 1.614
VaR/100 p ES/100 p
1.135 1.453
09/17/2025 08:16
1758093362
37 = approx. 0.5mins
ndraws = 50000
Code: Select all
VaR/100 p ES/100 p
1.147 1.525
VaR/100 p ES/100 p
1.174 1.568
VaR/100 p ES/100 p
1.174 1.589
VaR/100 p ES/100 p
1.147 1.493
VaR/100 p ES/100 p
1.174 1.549
VaR/100 p ES/100 p
1.174 1.560
VaR/100 p ES/100 p
1.147 1.551
VaR/100 p ES/100 p
1.147 1.510
VaR/100 p ES/100 p
1.174 1.568
VaR/100 p ES/100 p
1.147 1.566
09/17/2025 08:48
1758095296
874 = approx. 14.57mins
Re: APARCH model
The definition of the FRML's can be moved outside. (You can do a LINREG over the full data range to give you the form for the mean model).
What's missing is the definition for the UU in generating the bootstrapped values (which is done in the calculation of LOGL in doing the estimation).
set udraw gend+1 gend+span = ustandard(entries)
set uu gend+1 gend+span = (h(t)=varf(t)),(u=udraw(t)*sqrt(h(t))),u^2
What's missing is the definition for the UU in generating the bootstrapped values (which is done in the calculation of LOGL in doing the estimation).
set udraw gend+1 gend+span = ustandard(entries)
set uu gend+1 gend+span = (h(t)=varf(t)),(u=udraw(t)*sqrt(h(t))),u^2
Re: APARCH model
To confirm there are 6 models in total: General APARCH(1,1) + 5 nested:
1. General APARCH(1,1)
2. Vanilla-GARCH(1,1)
3. GJR-GARCH
4. TARCH: (Threshold ARCH, Zakoian, 1994)
5. AbsModel: absolute value model
6. ARCH(1)
which can be achieved via "switching"/"changing" the models by fixing lambda, d, b (and sometimes removing them from PARAMSET). Any others?
I have these in seperate files - if I use IF or SWITCH statements the code could get messy and confusing as there are graphs/tables and the headers/labels require changing, model dependent. Any recommendations for ease in code?
1. General APARCH(1,1)
2. Vanilla-GARCH(1,1)
3. GJR-GARCH
4. TARCH: (Threshold ARCH, Zakoian, 1994)
5. AbsModel: absolute value model
6. ARCH(1)
which can be achieved via "switching"/"changing" the models by fixing lambda, d, b (and sometimes removing them from PARAMSET). Any others?
I have these in seperate files - if I use IF or SWITCH statements the code could get messy and confusing as there are graphs/tables and the headers/labels require changing, model dependent. Any recommendations for ease in code?
Re: APARCH model
I'm not sure why you would do any flavor of ARCH.
Can't you do any of those by proper use of PARMSETS?
nonlin(parmset=apgarch)
nonlin(parmset=standardgarch) lambda=2.0 d=0.0
nonlin(parmset=gjrgarch) lambda=2.0
maximize(parmset=meanparms+garchparms+asymmparms+powerparms+apgarch,title="APGARCH") logl 3 *
maximize(parmset=meanparms+garchparms+asymmparms+powerparms+standardgarch,title="GARCH") logl 3 *
maximize(parmset=meanparms+garchparms+asymmparms+powerparms+gjrgarch,title="GRJ-GARCH") logl 3 *
...
Can't you do any of those by proper use of PARMSETS?
nonlin(parmset=apgarch)
nonlin(parmset=standardgarch) lambda=2.0 d=0.0
nonlin(parmset=gjrgarch) lambda=2.0
maximize(parmset=meanparms+garchparms+asymmparms+powerparms+apgarch,title="APGARCH") logl 3 *
maximize(parmset=meanparms+garchparms+asymmparms+powerparms+standardgarch,title="GARCH") logl 3 *
maximize(parmset=meanparms+garchparms+asymmparms+powerparms+gjrgarch,title="GRJ-GARCH") logl 3 *
...
Re: APARCH model
Just to see if I can get near-exact results vis-a-vis 'proper' estimation.
Can these be estimated from APARCH?TomDoan wrote: ↑Sun Sep 21, 2025 4:57 pm Can't you do any of those by proper use of PARMSETS?
nonlin(parmset=apgarch)
nonlin(parmset=standardgarch) lambda=2.0 d=0.0
nonlin(parmset=gjrgarch) lambda=2.0
maximize(parmset=meanparms+garchparms+asymmparms+powerparms+apgarch,title="APGARCH") logl 3 *
maximize(parmset=meanparms+garchparms+asymmparms+powerparms+standardgarch,title="GARCH") logl 3 *
maximize(parmset=meanparms+garchparms+asymmparms+powerparms+gjrgarch,title="GRJ-GARCH") logl 3 *
...
TARCH: compute lambda=1.0; and parmset = meanparms + APARCHparms + asymmparms
AbsModel: compute lambda=1.0; compute d=0.0; and parmset = meanparms + APARCHparms
ARCH(1): compute lambda=2.0; compute d=0.0; compute b=0.0; and parmset = meanparms + (c,a)
Any others?
Re: APARCH model
The whole point (I assume) is that you wanted to look at special cases of APARCH. You can do all of those with a PARMSET option of
meanparms+garchparms+asymmparms+powerparms+a parmset with restrictions
where "a parmset with restrictions" is something like I showed in the examples.
I also assumed that you were interested in models that might give reasonable results for the VaR and ES calculation. An ARCH(1) will not and no one familiar with the ARCH/GARCH literature would expect it to.
meanparms+garchparms+asymmparms+powerparms+a parmset with restrictions
where "a parmset with restrictions" is something like I showed in the examples.
I also assumed that you were interested in models that might give reasonable results for the VaR and ES calculation. An ARCH(1) will not and no one familiar with the ARCH/GARCH literature would expect it to.
Re: APARCH model
Yes - because it's too simple.
Here's an interesting paper: https://public.econ.duke.edu/~boller/Pa ... usings.pdf.