APARCH model

Discussions of ARCH, GARCH, and related models
ac_1
Posts: 467
Joined: Thu Apr 15, 2010 6:30 am

APARCH model

Unread post by ac_1 »

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
TomDoan
Posts: 7777
Joined: Wed Nov 01, 2006 4:36 pm

Re: APARCH model

Unread post by TomDoan »

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.
ac_1
Posts: 467
Joined: Thu Apr 15, 2010 6:30 am

Re: APARCH model

Unread post by ac_1 »

TomDoan wrote: Mon Sep 15, 2025 6:39 am 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.
So it's not possible with DAILY financial returns, long history, using (b)?
TomDoan
Posts: 7777
Joined: Wed Nov 01, 2006 4:36 pm

Re: APARCH model

Unread post by TomDoan »

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).
ac_1
Posts: 467
Joined: Thu Apr 15, 2010 6:30 am

Re: APARCH model

Unread post by ac_1 »

TomDoan wrote: Mon Sep 15, 2025 7:02 am 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).
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)
TomDoan
Posts: 7777
Joined: Wed Nov 01, 2006 4:36 pm

Re: APARCH model

Unread post by TomDoan »

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.
ac_1
Posts: 467
Joined: Thu Apr 15, 2010 6:30 am

Re: APARCH model

Unread post by ac_1 »

TomDoan wrote: Mon Sep 15, 2025 11:15 am 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.
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)
TomDoan
Posts: 7777
Joined: Wed Nov 01, 2006 4:36 pm

Re: APARCH model

Unread post by TomDoan »

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.
ac_1
Posts: 467
Joined: Thu Apr 15, 2010 6:30 am

Re: APARCH model

Unread post by ac_1 »

TomDoan wrote: Tue Sep 16, 2025 5:32 pm 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.
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
Generating 10 days ahead forecasts, at the moment I have

*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
APARCH is an extremely useful supermodel as it nests other models - but only if it can be estimated and thereafter generate the bootstrap forecasts in a reasonable amount of time. And, thus far the model's using the GARCH Instruction: analytical and simulations have produced excellent/stable results via exceedence plots!
TomDoan
Posts: 7777
Joined: Wed Nov 01, 2006 4:36 pm

Re: APARCH model

Unread post by TomDoan »

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
ac_1
Posts: 467
Joined: Thu Apr 15, 2010 6:30 am

Re: APARCH model

Unread post by ac_1 »

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?
TomDoan
Posts: 7777
Joined: Wed Nov 01, 2006 4:36 pm

Re: APARCH model

Unread post by TomDoan »

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 *
...
ac_1
Posts: 467
Joined: Thu Apr 15, 2010 6:30 am

Re: APARCH model

Unread post by ac_1 »

TomDoan wrote: Sun Sep 21, 2025 4:57 pm I'm not sure why you would do any flavor of ARCH.
Just to see if I can get near-exact results vis-a-vis 'proper' estimation.
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 *
...
Can these be estimated from APARCH?

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?
TomDoan
Posts: 7777
Joined: Wed Nov 01, 2006 4:36 pm

Re: APARCH model

Unread post by TomDoan »

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.
ac_1
Posts: 467
Joined: Thu Apr 15, 2010 6:30 am

Re: APARCH model

Unread post by ac_1 »

TomDoan wrote: Mon Sep 22, 2025 12:22 pm 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.
Yes - because it's too simple.

Here's an interesting paper: https://public.econ.duke.edu/~boller/Pa ... usings.pdf.
Post Reply