8. .ARIMA + GARCH를 이용한 시계열 예측

   ARIMA(p, d, q) 모형은 시계열을 d번 차분하여 고정된 시계열(stationary time series)를 얻을 수 있다. 하지만 시계열을 구성하는 분산을 고정해야하는 단점이 있다. 이렇게 분산을 고정할 경우 주기 시계열처럼 변동성 군집(volatility clustering) 현상이 있는 시계열 분석이 어렵다는 단점이 있다.
   이러한 단점을 해결하는 방법이 GARCH(r, s)와 같은 이분산 모형을 이용하여 시계열의 분산 자체를 모형화 하는 방법이다. 하지만 이 경우 시계열의 전체적인 방향성을 이해하는데는 문제가 있다.

   최근 알고리즘 트레이딩 분야에서 나름 주목을 받는 방법이 앞의 두 모형을 섞어 사용하는 것이다. 전체적인 방향성은 ARIMA 모형으로 찾고, 시계열의 분산을 GARCH로 분석하여 예측하는 방식이다.
   다음의 ARIMA(p, d, q)를 보자.
$$
\theta_p(\mathbf{B})(1-\mathbf{B})^d x_t = \phi_q(\mathbf{B})\epsilon_t
$$
   여기서 $d=0$일 경우 ARMA(p, q)와 동일하므로 다음의 식으로 나타낼 수 있다.
$$
x_t = \sum^{p}_{i=1} \alpha_i x_{t-i} + \sum^{q}_{j=1} \beta_j \epsilon_{t-j} + \epsilon_t
$$
   ARMA는$\epsilon_t$로 표현하는 충격 또는 오류항이 동일한 분산을 갖는다고 정의한다. 이 부분에 GARCH(r, s)를 적용하여 $\epsilon_t$를 다음과 같이 정의한다.
$$
\epsilon_t = \sigma_t \omega_t \\
\sigma^2_t = \alpha_0 + \sum_{i=1}^r \alpha_i \epsilon_{t-i}^2 + \sum_{j=1}^s \beta_j \epsilon_{t-j}^2
$$
   이렇게 정의한 후 시계열에 적용하면, 시계열의 방향성을 찾으면서 이분산 특정도 잡아낼 수 있다.

   이 책에서 예제로 제시한 것은 S&P500 지수에 대한 예측과 이에 따른 전략이었다. 하지만 구글 파이낸스가 지수 정보는 제공하지 않는 관계로 구글의 주가를 가지고 전략을 테스트 해보았다. ARIMA+GARCH를 이용하여 다음날의 주가 방향을 예측하고 상승이면 long, 하락이면 short 포지션을 취한다.
   그 결과는 다음의 그래프이다.
   그래프의 붉은 선이 전략에 의한 수익이고, 푸른색 선이 주식을 사고 버텼을 경우의 수익이다. 2008년에서 2010년 사이 금융위기 당시 하락 추세에서 short 포지션을 잘 취하여 높은 수익을 낸다. 하지만 2012년 경 시장이 혼조세를 겪으면서 예측이 틀리고 큰 손실이 발생하는 것을 볼 수 있다. 이 부분에서 어떻게 예측력이 떨어진것인지 연구해 볼 가치가 있다고 생각한다.
   ARIMA+GARCH를 이용하여 시계열을 맞추는 코드는 다음과 같으며, R을 이용한 코드이다.

 
library(quantmod)
library(lattice)
library(timeSeries)
library(rugarch)

# S&P 500 주가를 받고 NA는 없앰
getSymbols("GOOG", from="1990-01-01", src = "google")
gg_returns = diff(log(Cl(GOOG)))
gg_returns[as.character(head(index(Cl(GOOG)), 1))] = 0

# foreacst vector를 만들어 예측치 저장
window_len = 500
fore_len = length(gg_returns) - window_len
forecasts <- vector(mode="character", length=fore_len)

for(d in 0:fore_len)
{
    # rolling window를 구함
    gg_returns_offset = gg_returns[(1+d):(window_len + d)]
    
    # fitting ARIMA model
    final.aic <- Inf
    final.order <- c(0, 0, 0)
    for(p in 0:5)
    {
        for(q in 0:5)
        {
            if(p == 0 && q==0)
            {
                next
            }
            
            arima_fit = tryCatch(arima(gg_returns_offset, order = c(p, 0, q)), 
                                 error = function(err) FALSE, 
                                 warning = function(err) FALSE)
            
            if(!is.logical(arima_fit))
            {
                current.aic <- AIC(arima_fit)
                if(current.aic < final.aic)
                {
                    final.aic <- current.aic
                    final.order <- c(p, 0, q)
                    final.arima <- arima(gg_returns_offset, order = final.order)
                }
            }
            else
            {
                next
            }
        }
    }
    
    # fitting GARCH model
    spec = ugarchspec(
        variance.model = list(garchOrder=c(1,1)),
        mean.model = list(armaOrder=c(final.order[1], final.order[3]), include.mean=T),
        distribution.model="sged"
    )
    fit = tryCatch(
        ugarchfit(
            spec, gg_returns_offset, solver = 'hybrid'
        ), error=function(e) e, warning=function(w) w
    )
    
    # GARCH 모형이 수렴하지 않으면 방향을 "long"으로 선택
    # 그렇지 않으면 수익률 예측에 따라 맞는 방향을 찾아줌
    if(is(fit, "warning"))
    {
        forecasts[d + 1] = paste(
            index(gg_returns_offset[window_len]), 1, sep=","
        )
        print(
            paste(
                index(gg_returns_offset[window_len]), 1, sep=","
            )
        )
    }
    else
    {
        fore = ugarchforecast(fit, n.ahead = 1)
        ind = fore@forecast$seriesFor
        forecasts[d + 1] = paste(
            colnames(ind), ifelse(ind[1] < 0, -1, 1), sep=","
        )
        print(
            paste(
                colnames(ind), ifelse(ind[1] < 0, -1, 1), sep=","
            )
        )
    }
}

# forecast 결과를 csv에 씀
write.csv(forecasts, file="E:/devel/R_src/AdvAlgoTrading/forecasts.csv", row.names=FALSE)


인생논어 - 1

  0. 조형권님이 쓴 <<인생논어>> 를 읽고 필사한다는 생각으로 구문들을 옮겨 적으려 한다.  1. 나만의 속도를 유지하라.   子曰, 射不主皮 爲力不同科 古之道也 (자왈, 사부주피 위력부동과 고지도야)  해석: 활을 쏠 때 ...