GARCH-in-Mean in R (rugarch)¶
The R corner of the GARCH-M trio (from-scratch → PyMC → R)¶
rugarch fits GARCH-in-mean directly: set archm=TRUE in the mean model, with archpow=1 to put the conditional standard deviation in the mean (the same $\lambda\sqrt{h_t}$ term as the from-scratch notebook; archpow=2 would use the variance). The in-mean coefficient is reported as archm — this is $\lambda$, the price of risk. We fit the same three specifications on the same S&P 500 data and confirm the from-scratch estimates.
suppressMessages(library(rugarch))
r <- read.csv('sp500ret.csv')$ret
gm <- function(model, dist, x){
spec <- ugarchspec(variance.model=list(model=model, garchOrder=c(1,1)),
mean.model=list(armaOrder=c(0,0), include.mean=TRUE, archm=TRUE, archpow=1),
distribution.model=dist)
ugarchfit(spec, x, solver='hybrid')
}
cat('rugarch GARCH-in-mean (archm = in-mean coefficient on conditional SD), S&P 500 daily:\n')
for (nm in c('GARCH-M-N','GARCH-M-t','GJR-M-t')){
mo <- if (grepl('GJR', nm)) 'gjrGARCH' else 'sGARCH'
di <- if (grepl('-t', nm)) 'std' else 'norm'
mc <- gm(mo, di, r)@fit$matcoef
cat(sprintf(' %-11s archm(lambda) %7.4f se %.4f t %5.2f p %.3f\n',
nm, mc['archm',1], mc['archm',2], mc['archm',3], mc['archm',4]))
}
cat('\nGARCH-M-t full coefficients (cross-check vs the from-scratch module):\n')
print(round(gm('sGARCH','std', r)@fit$matcoef, 4))
rugarch GARCH-in-mean (archm = in-mean coefficient on conditional SD), S&P 500 daily:
GARCH-M-N archm(lambda) 0.0582 se 0.0398 t 1.46 p 0.144 GARCH-M-t archm(lambda) 0.0218 se 0.0363 t 0.60 p 0.547 GJR-M-t archm(lambda) 0.0359 se 0.0360 t 1.00 p 0.320
GARCH-M-t full coefficients (cross-check vs the from-scratch module):
Estimate Std. Error t value Pr(>|t|) mu 0.0427 0.0295 1.4448 0.1485 archm 0.0218 0.0363 0.6023 0.5470 omega 0.0062 0.0020 3.0971 0.0020 alpha1 0.0630 0.0087 7.2071 0.0000 beta1 0.9339 0.0091 102.6613 0.0000 shape 6.1499 0.4996 12.3105 0.0000
The same puzzle, and the same frequency effect¶
rugarch reproduces the from-scratch fit to the decimal, so the story carries over: $\hat\lambda$ is positive but its $t$-statistic is well under 2 in every specification — the risk-return tradeoff has the right sign but is not statistically resolved at daily frequency. As the from-scratch notebook showed, the premium is larger at monthly frequency; the monthly point estimate here confirms that (the sharper inference is quantified in the Python notebook via $P(\lambda>0)$).
options(repr.plot.width=7.5, repr.plot.height=4.3)
rm <- read.csv('spx_monthly.csv')$ret
lam_d <- gm('sGARCH','std', r )@fit$matcoef['archm',1]
lam_m <- gm('sGARCH','std', rm)@fit$matcoef['archm',1]
cat(sprintf('GARCH-M-t risk premium: daily %.4f monthly %.4f (monthly ~%.0fx larger)\n',
lam_d, lam_m, lam_m/lam_d))
bp <- barplot(c(daily=lam_d, monthly=lam_m), col=c('steelblue','firebrick'),
ylim=c(0, 1.15*lam_m), ylab=expression(lambda~' (risk premium)'),
main='GARCH-M-t risk premium by frequency (rugarch)')
text(bp, c(lam_d, lam_m), labels=sprintf('%.3f', c(lam_d, lam_m)), pos=3)
GARCH-M-t risk premium: daily 0.0218 monthly 0.2075 (monthly ~9x larger)
Results¶
rugarch= from-scratch. The in-mean coefficientarchmmatches the hand-written MLE to four decimals in all three specifications ($\lambda=0.058$ Normal, $0.022$ Student-$t$, $0.036$ GJR-$t$), as do $\omega,\alpha,\beta,\nu$ — an independent check that the forward-recursion likelihood is coded correctly.- The risk-return puzzle, confirmed by a second engine. $\hat\lambda>0$ everywhere but $|t|<1.5$ throughout; the tradeoff is directionally right, statistically weak at daily frequency.
- Frequency helps here too. Refitting GARCH-M-$t$ to the monthly series,
rugarchreturns a ~9×-larger $\lambda$ — the same signal-to-noise effect the Python notebook sharpens via the posterior $P(\lambda>0)$ (0.79 → 0.94).
Because bayesGARCH does not support an in-mean term, the Bayesian GARCH-M lives in the Python notebooks (garchm_python Metropolis, garchm_pymc NUTS); here R contributes the frequentist rugarch fit and the cross-engine validation.
Reference¶
- Engle, R. F., Lilien, D. M. & Robins, R. P. (1987). Estimating time varying risk premia in the term structure: the ARCH-M model. Econometrica 55, 391–407.