본문 바로가기
금융공학

기초자산 변동성: 역사적 변동성#2

by hustler78 2022. 12. 1.
728x90
반응형

이번 글은 역사적 변동성의 두 번째 글로서

2022.11.30 - [금융공학] - 기초자산 변동성: 역사적 변동성#1

 

기초자산 변동성: 역사적 변동성#1

기초자산의 GBM 모델은 위험 중립 측도(risk neutral measure) 하에서 다음과 같이 주어집니다. 기초자산 프로세스를 $S_t$라 하면 $$ dS_t/S_t = (r-q)dt + \sigma dW_t$$ 로 주어집니다. 여기서 ○ $r$ : 무위험 이

sine-qua-none.tistory.com

에서 이어집니다.

 

저번 글에서는 주식이나 지수의 일일 등락률의 표준편차나 일일 등락률의 제곱합을 계산하여 역사적 변동성을 추출하는 방법을 알아보았습니다.

샘플의 개수에 따라 그 값은 달라지는데요. 보통 많이 쓰이는 것이 180일 변동성, 250일 변동성 등입니다. 일반적으로 샘플이 $N$개 일 때, 이 샘플에서 추출한 역사적 변동성을

 

$N$일 역사적 변동성

이라 부릅니다. $N$을 바꿔 가며 역사적 변동성의 움직임을 보실까요?

 

 

Python Codes

import yfinance as yf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates

year_scaler = np.sqrt(252)	#연변동성으로 바꾸기 위한 팩터
index_name = '^KS11'	# 대상: KOSPI 지수

#저번 글 참조
df_index = yf.download(index_name, start="2000-01-01", end="2022-11-01")
df = df_index[['Close']].copy()
df['rate'] = (df.Close - df.Close.shift(1)) / df.Close.shift(1)

vol_days = [60, 90, 180, 250, 500]	#sample을 60에서 500까지 5가지 숫자에 대해서 변동성 구함
vol_name_column=[]
for vd in vol_days:
    col_name = 'vol_'+ str(vd)	#dataframe에 새롭게 삽입할 column이른 설정. ex)60 -> vol_60
    vol_name_column.append(col_name)	#새롭게 만든 column 리스트
    df[col_name] = year_scaler * df['rate'].rolling(window=vd).std()
    # 일반 일일등락률을 rolling method를 이용하여 표준편차 구하고, 연변동성으로 변환
df = df.dropna()	#NA값이 포함된 행 drop

fig, ax = plt.subplots()
ax.plot(df.index, df[vol_name_column])	#df.index를 x축으로 하는 5종의 그래프를 plotting
ax.xaxis.set_major_locator(mdates.YearLocator(1))
# x축의 표시형식을 연단위로 함 YearLocator(n)이면, n년 간격으로 label을 표시해줌
ax.legend(vol_name_column)

plt.show()

간략한 설명은 주석을 참고하시면 됩니다. 한 가지 알아둘 용법은 Axes.xaxis.set_major_locatormatplolib.dates.YearLocator() 입니다. $x$축의 눈금(tick) 간격을 조절할 때 쓰이는 용법으로, 용법의 사용 예는 위의 code를 참고하시면 됩니다.

 

 

결과는 아래와 같습니다.

 

 

어지러워 보이죠. 색깔별 그래프 하나하나가 변동성으로 쓰일 수 있습니다만, 다음의 특징이 있죠.

 

샘플의 개수가 많아질수록 변동성 그래프는 변화가 완만해진다(smoothing)

아무래도 일일등락률을 많이 모아 평균을 내고 분산을 구하면, 그 값은 모평균, 모분산에 가까워지게 되므로, 완만해질 수밖에 없습니다. 따라서

주가의 역동성을 중요시 바라보는 트레이더들은 많지 않은 샘플(180개 이하)로 구한 변동성을 감내할 수 있는 것이고, 변동성에 큰 영향을 받지 않는 포트폴리오를 구축하고자 하면, 샘플의 개수를 늘려나가면 됩니다.

 

위의 그림에서는 변동성 피크를 보이는 구간이 3군데가 있는데, 각각 2008년 말 리먼사태, 2011년 말 미국 신용등급 강등,  2020년 COVID19가 원인이라 볼 수 있겠죠.

 

피크를 쳤다가 일정 기간 뒤 그래프가 급속도로 꺼지는 원인은, 시간이 지나며 시장의 크래쉬 순간의 등락률이 샘플 대상에서 빠지게 돼서 표준편차가 작아지는 것입니다.

 

 

 

조금 더 스무스한 변동성을 원한다면?

 

위에서 보았듯이 역사적 변동성을 구하면, 시장의 폭락/폭등 상황을 적시적으로 반영하기 때문에, 마치 톱니바퀴처럼 피크가 나타나기 마련입니다. 이를 보완하기 위해, 몇몇 트레이더들은 역사적 변동성의 평균을 변동성으로 차용하는 경우가 있습니다. 

 

예컨대, 250일 역사적 변동성의 250일 평균 변동성 코드는 아래와 같아요.

 

import yfinance as yf
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.dates as mdates

year_scaler = np.sqrt(252)
index_name = '^KS11'
df_index = yf.download(index_name, start="2000-01-01", end="2022-11-01")
df = df_index[['Close']].copy()
df['rate'] = (df.Close - df.Close.shift(1)) / df.Close.shift(1)

vol_days = [60, 90, 180, 250, 500]
vol_name_column = []
for vd in vol_days:
    col_name = 'vol_' + str(vd)
    vol_name_column.append(col_name)
    df[col_name] = year_scaler * df['rate'].rolling(window=vd).std()

df['avr_vol_250'] = df['vol_250'].rolling(window=250).mean()
# 250 변동성의 250일 평균을 rolling method로 산출함. mean()은 평균을 뜻함

df = df.dropna()

fig, ax = plt.subplots()
ax.plot(df.index, df.vol_250, label='250 Vol')	# 250일 역사적 변동성과
ax.plot(df.index, df.avr_vol_250, label='250 Vol Average')	#250일 역사적 변동성이 250개 평균을 그림
ax.xaxis.set_major_locator(mdates.YearLocator(1))
ax.legend()
plt.show()

 

결과는 아래와 같습니다.

 

 

주황색 그래프가 250일 역사적 변동성의 평균인데요. 기존 변동성에 비해 부드럽고 완만한 변화를 보임을 알 수 있죠.

하지만, 피크가 나는 순간을 적시적으로 반영을 하지 못합니다. 평균을 취하기 때문에 늦게 늦게 반영되는 거죠. 따라서 주황색 그래프 자체가 파란색 변동성 곡선과 비교하여 우측으로 밀려나 있는 것처럼 보입니다.

 

 

하지만, 태생적으로 역사적 변동성은 과거의 상황으로 미래를 설명한다는 한계점이 있습니다. 과거의 움직임이 미래를 재현해 주진 않죠. 따라서 역사적 변동성의 평균을 취하는 것도, 좀 더 부드러운 변동성 정책을 쓰고자 하는 트레이딩 하우스에게는 좋은 방법이 될 것입니다.

 

다음 글에서는 또 따른 변동성 산출법을 알아보겠습니다.

 

728x90
반응형

댓글