THE DIFFERENCE BETWEEN ETFs AND CLOSED-END FUNDS



트레이더들에게 있어서 exchange-traded funds (ETFs)와 closed-end funds(CEFs)의 차이를 이해하는 것은 매우 중요합니다. 이 장단점을 아는 것은 투자 결정을 하는 데 도움을 줄 것입니다.


CEF에 대해 보통 오해하는 것은 CEF가 전통적인 뮤츄얼 펀드나 ETF라고 생각하는 것입니다. closed-end fund는 전통적인 뮤츄얼 펀드처럼 트레이더들에게 closed되어 있지 않습니다. 심지어 CEF 주식은 ETFs가 아니지만 거래소에서 거래도 됩니다.


closed-end fund (CEF) 혹은 closed-ended fund 


CEF는 회수 할 수 없는 특정 수량의 주식 발행을 기반으로 결합된 투자 모델입니다. 즉, 투자자가 펀드에 투자 후 환매를 할 수가 없다는 것입니다. 또한 만기가 있고, 펀드 모집 후 펀드 만기 이전에 open-end funds와 달리, closed-end fund에서는 가입이 제한됩니다. 주식들은 open-end 뮤츄얼 펀드를 선행하지만 오히려 적극적으로 관리되는 투자와 유사하고, 뮤츄얼 펀드에 의해 원래 설계된 시장에서만 구매 및 판매 될 수 있습니다.


exchange-traded fund (ETF)


ETF는 주식 시장에서 거래되는 투자 펀드입니다. 하나의 ETF는 주식, 실물자산, 채권과 같은 자산들을 보유합니다. 일반적으로 편차가 발생할 수 있지만 일반적으로 순자산 가치에 가깝게 거래하도록 설계된 차익 거래 메커니즘을 통해 설계됩니다. 대부분 ETF는 주식 지수 혹은 채권 지수와 같은 지수를 추종합니다. 낮은 cost, 세금, 주식과 같은 특징을 갖는다는 것이 흥미로운 점입니다.


CEF와 ETF의 차이점들:



  • Transparency (투명성)

ETF는 완전히 투명합니다. ETF는 인덱스 및 액티브 펀드 여부에 상관없이 포트폴리오가 투명하게 운영되고 거래일 동안 일정한 주기로 가격이 형성됩니다. 투자자들은 손쉽게 기초자산, 채권, 원자재 등을 인식할 수 있습니다.

CEF는 보유 자산을 포함한 포르폴리오 세부 정보는 월별, 분기 별 또는 반기 별로만 제공됩니다.


  • Fee (수수료)


CEF의 비용은 ETF와 비교하여 높습니다. 왜냐하면 ETF는 indexed된 포트폴리오이고 이 포트폴리오는 actively manged되는 포트폴리오보다 제어하는데 비용이 덜 들기 때문입니다. 게다가 적극적으로 관리되는 포트폴리오의 내부 거래 비용은 ETF의 내부 거래 비용보다 높습니다. 포트폴리오의 회전율이 낮기 때문입니다. 그러므로 장기 투자를 계획하고 있는 투자자는 CEF에 비해 ETF에 투자하면 많은 것을 절약할 수 있습니다.

어떤 투자도 다른 것에 비해 더 좋거나 나쁘지 않습니다. 그것은 단지 다를 뿐이며 자유롭고 공정한 자본 시장에서는 여러 가지 투자 옵션을 얻는 것이 핵심 요소입니다.



  • Net Asset Value (NAV) 순자산 가치


ETF는 일반적으로 NAV에 가깝게 거래됩니다. ETF가 NAV에 비해 큰 프리미엄이나 할인으로 거래를 하는 것은 예외적인 일입니다. 역사적으로 기관들은 creation 단위를 만들거나 청산함으로써 차익거래 기회를 보았습니다. 그렇기 때문에 ETF 주식 가격은 기초자산 지수 또는 증권 바구니의 NAV에 가깝게 유지할 수 있습니다.


반면에, CEF는 NAV 대비 프리미엄을 붙이거나 할인을 할 가능성이 더 큽니다. 프리미엄은 펀드의 주식에 대해 더 많은 수요가 있다는 것을 나타내며, 할인은 수요가 적다는 것을 나타낼 수 있습니다. 여기서 순자산 가치(NAV)는 총자산에서 부채를 차감하고 총 주식 수로 나누어 계산합니다.











Correlated stocks and Pair Trading

Pair Trading


이전 포스팅에서 correlated stocks에 대해 알아보았습니다.
이제 이 상관관계를 이용하여 간단한 페어 트레이딩전략을 이용해보겠습니다. 페어 트레이딩은 수학적 분석에 기반한 전략입니다.


여기서는 삼성전자와 그 계열사인 삼성전기를 예로 들겠습니다. 만약 삼성전자와 삼성전기가 같은 경제적 기반을 가지고 있다는 가정에서 우리는 이 두 종목의 가격의 차이(spread)혹은 비율이 시간이 지나도 일정하게 유지될 것을 기대할 것입니다. 그러나 삼성전자에 대해 대규모 매매주문, 뉴스에 대한 반응 등으로 인해 수시로 일시적인 수요/공급 변화가 생긴다면, 이 시나리오에서 삼성전자는 위/아래로 움직이고 삼성전기은 서로 다른 움직임을 보일 수 있습니다. 이 발산이 시간이 지남에 따라 정상으로 되돌아 갈 것으로 예상된다면 이 때 페어 트레이딩을 할 수가 있습니다.


Cointegration

공적분은 correlation과 매우 유사합니다. 두 series 간의 비율이 평균을 중심으로 달라짐을 의미합니다. 두 series Y, X는 다음과 같습니다.


Y = ⍺ X + e

여기서 는 상수 비율이고, e는 white noise입니다. 두 시계열 간의 페어 트레이딩이 동작하기 위해서는,  시간 경과에 따른 비율의 기대 값이 평균에 수렴되어야 합니다. 즉, 그들은 공적분되어야 합니다. 아래와 같은 형태가 cointegrated된 형태입니다.




Pair Trading을 하는 방법

두 개의 cointegrated time series는 서로를 향하거나 서로에게더 떨어지기 때문에 spread가 높거나 낮은 때가 있을 것입니다. 우리는 어떤 종목을 buy하거나 다른 종목에 대해 sell함으로써 페어 트레이딩을 할 수가 있습니다. 이러한 방법으로, 만약 두 종목의 가격이 같이 하락하거나 상승한다면, 우리는 돈을 벌거나 잃지 않습니다. 우리는 market neutral한 것입니다.

다시 Y = ⍺ X + e 에서 본 X와 Y으로 돌아가면, Y/X와 같은 비율은 mean value ⍺ 에서 등락을 할 것입니다. 그렇기 때문에 우리는 X와 Y가 멀리 떨어질 때, 가 너무 높거나 낮을 때를 포착하면 됩니다.

  • Going Long the Ratio ⍺ 가 평소보다 작으며 증가할 것을 예측할 때, 우리는 Y를 사고 X를 파는 것에 배팅합니다.

  • Going Short the Ratio 가 평소보다 크고 감소할 것을 예측할 때의 경우입니다. 우리는 X를 사고 Y를 파는 것에 배팅합니다.

우리는 항상 "hedged postion"입니다. :  매도 포지션의 가치가 떨어지면 매수 포지션이 되고, 매수 포지션이 되면 매도 포지션으로 돈을 벌어 전체 시장 변동에 영향을 받지 않습니다. 종목 X와 Y가 서로 상대적으로 움직일 때만 수익을 얻거나 잃게 됩니다.

우리는 cointegrated할 것으로 생각되는 종목을 찾을 때 여러 비교 바이어스에 빠지게 됩니다.

  • 다중 비교 편향 은 단순히 많은 테스트를 실행할 때 p 값을 잘못 생성할 기회가 증가한다는 사실입니다. 이를 피하기 위해, 공적분이 될 것으로 의심되는 이유가 있는 소수의 쌍을 선택하고 개별적으로 선택해야합니다. 이전 포스팅에서 상관관계가 있는 주식을 찾은 것과 관계가 있습니다.

이제 우리는 실제 종목에 적용시켜 두 종목간의 비율을 비교해보도록 하겠습니다. cointegration을 확인하기 위해 통계 패키지인 statsmodels을 이용합니다.
 

Configuration
from statsmodels.tsa.stattools import coint


Data

데이터는 아래와 같이 date가 index이고 symbol이 column인 DataFrame을 이용할 것입니다.

Input : 
data.head(3)


Output:




이제 이 데이터들을 이용하여 conitegrated된 쌍을 찾을 것입니다. 아래와 같이 함수를 정의한 뒤 사용합니다.

Input : 
def find_cointegrated_pairs(data):
    n = data.shape[1]
    score_matrix = np.zeros((n, n))
    pvalue_matrix = np.ones((n, n))
    keys = data.keys()
    pairs = []
    for i in range(n):
        for j in range(i+1, n):
            S1 = data[keys[i]]
            S2 = data[keys[j]]
            result = coint(S1, S2)
            score = result[0]
            pvalue = result[1]
            score_matrix[i, j] = score
            pvalue_matrix[i, j] = pvalue
            if pvalue < 0.02:
                pairs.append((keys[i], keys[j]))
    return score_matrix, pvalue_matrix, pairs



# Heatmap to show the p-values of the cointegration test
# between each pair of stocks
scores, pvalues, pairs = find_cointegrated_pairs(data)
import seaborn
m = [0,0.2,0.4,0.6,0.8,1]
seaborn.heatmap(pvalues, xticklabels=instrumentIds, 
                yticklabels=instrumentIds, cmap=’RdYlGn_r’, 
                mask = (pvalues >= 0.98))
plt.show()
print(pairs)


Output:



[('000660', '071050'), ('016360', '066570'), ('016360', '005940'), ('016360', '012450'), ('066570', '005490'), ('066570', '005940'), ('006800', '003550'), ('006800', '012450'), ('003550', '004020'), ('003550', '086790'), ('003550', '024110'), ('003550', '003490'), ('003550', '042670'), ('005940', '012450'), ('005940', '042670'), ('055550', '024110'), ('086790', '051910'), ('086790', '028050'), ('086790', '012330'), ('086790', '096770'), ('000720', '042670')]

p-value가 0.02이하인 쌍만 추가한 결과, 위와 같은 결과가 나왔습니다. 삼성전자는 p-value가 0.02이하인 쌍이 없었으며 가장 p-value가 가장 낮은 쌍은 LG(003550)와 기업은행(024110) 이 나왔습니다. 이 두 종목으로 나머지 과정을 진행해보겠습니다.





결과로 나온 비율은 안정적으로 평균 주위에 맴도는 것처럼 보입니다. 하지만 통계적으로 절대 비율은 매우 유용하진 않습니다. 이 signal을 z-score로 normalize해보도록 하겠습니다.


Z Score (Value) = (Value — Mean) / Standard Deviation


주의


실제로 이것은 일반적으로 데이터에 scale을 하기위해 수행되지만 이것은 분포를 가정합니다. 대개 normal을 사용합니다. 그러나 많은 데이터가 normal distribution으로 되지 않으므로 이러한 분포를 사용할 때는 매우 조심해야 합니다. 비율의 실제 분포는 매우 극단적인 값으로 모델이 엉망이 되어 큰 손실을 초래할 수 있기 때문입니다.


Input :

def zscore(series):
    return (series - series.mean()) / np.std(series)

zscore(ratios).plot()
plt.axhline(zscore(ratios).mean())
plt.axhline(1.0, color=’red’)
plt.axhline(-1.0, color=’green’)
plt.show()



Output :



 위의 그림에서 알 수 있듯이 종종 평균에서 크게 발산하는 경우에 우리는 이익을 취할 수 있습니다.

우리는 이제 trading signal을 개발해보겠습니다. data techniques을 이용하여 trading singal을 개발하는 방법을 steps순으로 진행할 것입니다.


  • 신뢰할 수 있는 데이터 수집 및 데이터 정리
  • 거래 signal / logic을 식별하기 위해 데이터로부터 feature 생성
  • feature는 MA혹은 가격 데이터, correlation또는 복잡한 signal의 ratio일 수 있습니다. 이를 결합하여 새로운 기능을 만들 수 있습니다.
  • 이러한 기능을 사용하여 거래 signal을 생성합니다.

Step 1. 문제 설정

여기서 우리는 다음 순간이 매수 혹은 매도인지를 알려주는 신호를 만들겠습니다. 예측 변수 Y는

Y = Ratio is buy (1) or sell (-1)
Y(t)= Sign( Ratio(t+1) — Ratio(t) )

우리는 실제 주식 가격이나 비율의 실제 가치를 예측할 필요가 없다는 점에 유의하셔야 합니다.

Step 2. 신뢰할 수 있고 정확한 데이터 수집



거래하고자하는 주식과 사용할 데이터를 가져와 배당금과 액면 분할을 고려해줘야합니다.



Step 3. 데이터 분할



이전 포스팅에서 한 것처럼 training과 test셋을 각각 70%, 30%로 나눌 것입니다.



Step 4. Feature Engineering



우리는 ratio의 이동방향을 예측하려고 합니다. 우리는 두 주식이 공적분되면 비율이 평균으로 되돌아가는 경향이 있음을 보았습니다.

다음과 같은 기능을 사용합니다.

  • ratio의 60일 이동 평균 : 이동 평균 측정
  • ratio의 5일 이동 평균 : 평균의 현재가치 측정
  • 60일 표준 편차
  • z score : (5일 이동평균 - 60일 이동평균) / 60일 표준 편차


Input :

ratios_mavg5 = ratios.rolling(window=5,
                               center=False).mean()
ratios_mavg60 = ratios.rolling(window=60,
                               center=False).mean()
std_60 = ratios.rolling(window=60,
                        center=False).std()
zscore_60_5 = (ratios_mavg5 - ratios_mavg60)/std_60
plt.figure(figsize=(15,7))
plt.plot(train.index, train.values)
plt.plot(ratios_mavg5.index, ratios_mavg5.values)
plt.plot(ratios_mavg60.index, ratios_mavg60.values)
plt.legend(['Ratio','5d Ratio MA', '60d Ratio MA'])
plt.ylabel('Ratio')
plt.show()



Output :





이번엔 이동 평균의 z-score ratio를 확인해보도록 하겠습니다.

Input :

plt.figure(figsize=(15,7))
zscore_60_5.plot()
plt.axhline(0, color='black')
plt.axhline(1.0, color='red', linestyle='--')
plt.axhline(-1.0, color='green', linestyle='--')
plt.legend(['Rolling Ratio z-Score', 'Mean', '+1', '-1'])
plt.show()


Output :




이동 평균의 z-score는 평균으로 회귀하는 정도가 매우 강한 것을 확인할 수 있습니다.


Step 5. 모델 선택


아주 간단한 모델부터 시작해보겠습니다. 우리는 z-score feature가 매우 높아지거나 매우 낮아질 때마다 회귀하는 것을 알 수 있습니다. +1 / -1을 threshold로 설정하여 trading signal을 생성하는 모델을 사용하도록 하겠습니다.

  • Ratio는 z-score가 -1.0이하로 내려갈 때마다 buy (1) 신호를 생성합니다. 왜냐하면 z-score가 0으로 돌아가므로 ratio가 증가할 것이기 때문입니다.
  • z-score가 1.0을 넘을 때 z-score가 0으로 내려가므로 ratio가 감소할 것이기 때문에 sell (-1) 신호를 생성합니다.


Step 6. 훈련

마지막으로, 우리의 모델이 실제 데이터에 잘 작동하는지 확인햅시다. 실제 ratio와 trading signal을 확인해 보도록 하겠습니다.


Input :

# Plot the ratios and buy and sell signals from z score
plt.figure(figsize=(15,7))
train[60:].plot()
buy = train.copy()
sell = train.copy()
buy[zscore_60_5>-1] = 0
sell[zscore_60_5<1 0="" atio="" buy="" color="’r’," ell="" linestyle="’None’," marker="’^’)" plot="" plt.axis="" plt.legend="" plt.show="" pre="" ratios.max="" ratios.min="" sell="" signal="" uy="" x1="" x2="" y1="" y2="plt.axis()">


Output :




signal들은 합리적으로 보입니다. 우리는 ratio가 높을 때 sell signal, 낮을 때 buy signal을 표시하고 있습니다.

이번엔 실제 종목들의 가격 변화와 signal들을 보도록 하겠습니다.


Input :
# Plot the prices and buy and sell signals from z score
plt.figure(figsize=(18,9))
S1[60:].plot(color='b')
S2[60:].plot(color='c')

buyR = 0*S1.copy()
sellR = 0*S1.copy()

# When buying the ratio, buy S1 and sell S2
buyR[buy!=0] = S1[buy!=0]
sellR[buy!=0] = S2[buy!=0]

# When selling the ratio, sell S1 and buy S2 
buyR[sell!=0] = S2[sell!=0]
sellR[sell!=0] = S1[sell!=0]
buyR[60:].plot(color='g', linestyle='None', marker='^')
sellR[60:].plot(color='r', linestyle='None', marker='^')
x1,x2,y1,y2 = plt.axis()
plt.axis((x1,x2,min(S1.min(),S2.min()),max(S1.max(),S2.max())))
plt.legend(['LG','IBK', 'Buy Signal', 'Sell Signal'])
plt.show()


Output :




training data에 확인한 결과는 위와 같습니다. 이제 이 모델을 그대로 test data에 적용시켜 확인해보도록 하겠습니다.


Step 7. 테스트


z-score를 이용한 모델을 사용합니다. test data에서도 확인할 수 있듯이 ratio는 어떠한 상수를 기준으로 위아래로 등락하는 것을 확인할 수 있습니다. (여기서는 약 5.5), z-score가 1을 초과할 때 sell signal을 보내고, -1미만일 때 buy signal을 보내고 있습니다.




아래의 그림은 종목들의 주가와 같이 확인한 결과입니다. 오히려 전체적으로 가격이 상승하는 국면에서는 sell signal이 많이 발생하고, 하락하는 국면에서 buy signal이 발생하고 있습니다. 




이번 포스팅에서는 모델 validation과 backtest 과정은 생략하겠습니다. 전체적인 과정을 설명하기 위해 아주 단순한 방법으로 상관관계를 갖는 종목을 이용한 pair trading signal 발생을 해보았습니다. 여기서는 간단한 방식으로 5d-MA와 60d-MA만을 이용해 signal을 이용해보았지만, 본인의 trading 전략을 세운 뒤에 이용한다면 alpha를 찾아낼 수 있는 기회를 포착할 수 있을 것입니다. 어도비와 마이크로소프트와 같이 강력한 cointegration을 가지고 있는 종목들이 발견되지 않는다면, 선물, 옵션, ETF등과 같은 여러 방법을 이용하면 상관관계를 포착할 수 있을 것입니다.





Correlated assets

주식 시장이 움직이는 것을 정확히 예측하는 것은 매우 어려운 일입니다. 주식이 특정 방향으로 움직이는 것은 수백만 개의 이벤트와 사전 조건이 존재하기 때문입니다. 그래서 우리는 이러한 사전 조건들을 capture해야합니다. 그러기 위해서 우리는 아래와 같은 가정들이 필요합니다.


1) 시장은 100% random하지 않다.
2) 역사는 반복된다.
3) 시장은 사람들의 합리적인 행동에 따른다.
4) 시장은 'perfect'하다.



우리는 이러한 가정을 한 뒤, 삼성전자(005930) 의 주가 움직임을 예측해 볼 것입니다. 
우리는 삼성전자의 주가가 등락 여부에 어떤 것들이 영향을 주는 지를 이해해야 합니다. 그러므로, 우리는 가능한 많은 정보를 통합할 것입니다. (주식을 다양한 방면과 각도로 묘사하기 위해) 우리는 일별 데이터 (우리가 가지고 있는 데이터의 70%) 를 사용하여 다양한 알고리즘을 훈련시키고 나머지를 예측하는데 사용할 것입니다. 그리고 우리는 예측된 결과와 hold-out 데이터를 비교할 것입니다. .

이것들은 꼭 주식이 아니더라도 원자재, FX, 지수, 채권 등 아무 유형이 가능합니다.
삼성전자와 같은 큰 기업은 고립되어 있지 않습니다. 경쟁사를 포함하여 고객들, 글로벌 경제, 지정학적 현상, 재정 및 통화 정책, 자본 접근 등 외부요인이 있습니다.


Correlated stocks

이번 포스팅에서는 먼저 삼성전자와 유의미한 상관관계를 갖고 있는 기업들을 찾아볼 것입니다. 전체적으로는 상관관계가 있는 기업을 찾기 위해, 종가데이터를 이용하여 correlation을 구하는 것 방법의 문제점과 해결 방법에 대해 알아보도록 하겠습니다.

Environment
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split


Configuration


2008년 1월 2일부터 2019년 1월 25일의 데이터를 사용할 것입니다. (7년은 training 목적, 3년은 validation 목적)


Input:
train, test = train_test_split(samsung_df, test_size=0.3, shuffle=False)
print('There are {} number of days in the dataset.'.format(samsung_df.shape[0]))
print('train set : {}, test set : {}'.format(train.shape[0], test.shape[0]))
print('train period : {} ~ {}'.format(train.index[0], train.index[-1]))
print('test period : {} ~ {}'.format(test.index[0], test.index[-1]))

Output:
There are 2739 number of days in the dataset.
train set : 1917, test set : 822
train period : 2008-01-02 ~ 2015-09-16
test period : 2015-09-17 ~ 2019-01-25






먼저 전체 주가 데이터를 symbol을 column으로 하여 데이터프레임을 생성한 뒤 데이터를 입력합니다.

Input:
all_df.head(2)

Output:




이제 특정 기업과 나머지 모든 기업에 대한 correlation을 구합니다. 여기서 먼저 correlation을 구하기 위한 함수를 정의해줍니다. 종목들마다 종가데이터가 있는 정도가 다르기 때문에 nan값에 대한 처리를 해주는 것이 중요합니다.

def search_string(gr, column, strings_list):
    if isinstance(strings_list,str):
        strings_list = [strings_list]
    if isinstance(column, str):
        #### if column is not a list but a string, it means there is only one column to search
        return gr[gr[column].str.contains('|'.join(strings_list),na=False)]
    else:
        gr_df = pd.DataFrame()
        counter = 0
        for col in column:
            if counter == 0:
                gr_df =  gr[gr[col].str.contains('|'.join(strings_list),na=False)]
                counter += 1
            else:
                gr_df.append(gr[gr[col].str.contains('|'.join(strings_list),na=False)])
                counter += 1
        return gr_df

    
def top_correlation_to_name(stocks, column_name, searchstring, top=10, abs_corr=False):
    incl = [x for x in list(stocks) if x not in column_name]
    ### First drop all NA rows since they will mess up your correlations.
    stocks.dropna(inplace=True)
    ### Now find the highest correlated rows to the selected row ###
    try:
        index_val = search_string(stocks, column_name,searchstring).index[0]
    except:
        print('Not able to find the search string in the column.')
        return
    ### Bring that selected Row to the top of the Data Frame
    df = stocks[:]
    df["new"] = range(1, len(df)+1)
    df.loc[index_val,"new"] = 0
    stocks = df.sort_values("new").drop("new",axis=1)
    stocks.reset_index(inplace=True,drop=True)
    ##### Now calculate the correlation coefficients of other rows with the Top row
    try:
        if abs_corr == True:
            cordf = pd.DataFrame(stocks[incl].T.corr().abs().sort_values(0,ascending=False))
        else:
            cordf = pd.DataFrame(stocks[incl].T.corr().sort_values(0,ascending=False))
    except:
        print('Cannot calculate Correlations since Dataframe contains string values or objects.')
        return
    try:
        cordf = stocks[column_name].join(cordf)
    except:
        cordf = pd.concat((stocks[column_name],cordf),axis=1)
    #### Visualizing the top 5 or 10 or whatever cut-off they have given for Corr Coeff
    if top >= 1:
        top10index = cordf.sort_values(0,ascending=False).iloc[:top,:3].index
        top10names = cordf.sort_values(0,ascending=False).iloc[:top,:3][column_name]
        top10values = cordf.sort_values(0,ascending=False)[0].values[:top]
    else:
        top10index = cordf.sort_values(0,ascending=False)[
            cordf.sort_values(0,ascending=False)[0].values>=top].index
        top10names = cordf.sort_values(0,ascending=False)[
            cordf.sort_values(0,ascending=False)[0].values>=top][column_name]
        top10values = cordf.sort_values(0,ascending=False)[
            cordf.sort_values(0,ascending=False)[0].values>=top][0]
    #### Now plot the top rows that are highly correlated based on condition above
    stocksloc = stocks.iloc[top10index]
    #### Visualizing using Matplotlib ###
    stocksloc = stocksloc.T
    stocksloc = stocksloc.reset_index(drop=True)
    stocksloc.columns = stocksloc.iloc[0].values.tolist()
    stocksloc.drop(0).plot(subplots=True, figsize=(15,10),legend=False,
                         title="Top %s Correlations to %s" %(top,searchstring))
    [ax.legend(loc=1) for ax in plt.gcf().axes]
    plt.tight_layout()
    plt.show()
    
    return dict(zip(top10names, top10values))


그 후, 함수를 사용하기 위해 전처리를 해줍니다.

Input:
all_df_T = all_df.T
all_df_T.reset_index(drop=False, inplace=True)
all_df_T.head(1)

for col in incl:
    all_df_T[col] = all_df_T[col].map(lambda x: float(x))


Output:




Input:
top_correlated_companies = top_correlation_to_name(all_df_T, 'index', '005930', 5, abs_corr=True)


Output:




주가를 기반으로 유의미한 상관관계를 갖는 종목은 이와 같은 결과가 나왔습니다.


Input:
for key, value in top_correlated_companies.items():
    print('{} : {}'.format(company_list.loc[company_list.종목코드 == key, '회사명'].values[0], value))   


Output:

삼성전자 : 1.0
오리온홀딩스 : 0.9480981638541061
제일기획 : 0.9368736502664881
비에이치 : 0.9202494270558285
농우바이오 : 0.9143668553498088


위 목록에 대한 놀라운 사실은 오리온 홀딩스가 삼성그룹 계열사보다 삼성전자와 더 관련이 있다는 것입니다. 이것을 더 자세히 조사해 봅시다.

위와 같은 주식 차트처럼 "trendy"한 시계열 데이터에 대한 것 중 하나는 오해의 소지가 있는 결론으로 이어질 수 있습니다.

각 차트는 시간과 관련이 있기 때문에 한 주식 차트가 다른 차트에 대해 회귀 할 때 주가와 같은 "trendy"한 시계열 데이터가 까다로울 수 있습니다. 그들은 모두 시간과 상관 관계가 있기 때문에 강하지만, 종종 가짜 관계를 나타낼 것입니다.

따라서 주가와 같은 "trendy"한 시계열 데이터는 "nonstationary"로 간주됩니다.(즉, 시간에 따라 변화하는 평균 및 분산을 갖는 것)

그렇기 때문에 시계열 데이터를 처리 할 때 당신은 일반적으로 그들이 시간에 독립적으로 상관 관계가 있는지 알고 싶어할 것입니다. 한 series의 variations이 다른 것의 variations과 일치 하는지 여부를 알고 싶을 겁니다. 이 때, "Trend"의 존재는 당신을 혼동시킬 수 있으므로 피해야합니다.

따라서 데이터에서 "trend"을 제거하기 위해 다음의 작업을 수행했습니다.

먼저 전체 시계열을 1의 기간으로 차이를 두었습니다. 이것은 지난 기간동안 포트폴리오에서 모든 "일일 수익률"을 얻었음을 의미합니다. 우리는 이제 삼성전자의 일일 수익률과 가까운 correlation을 갖는 종목들로 비교할 것입니다.

우리의 데이터 프레임에 적용된 "diff (1)"함수로 pandas에서 이것을 쉽게 수행 할 수 있습니다. 우리는 기존의 주식 포트폴리오에서 differnce를 하도록 하겠습니다. .


Input:
all_df_diff = all_df.diff(1)
all_df_diff = all_df_diff.iloc[1:,:]
all_df_diff_T = all_df_diff.T
all_df_diff_T.reset_index(drop=False, inplace=True)

for col in incl:
    all_df_diff_T[col] = all_df_diff_T[col].map(lambda x: float(x))

top_correlated_companies = top_correlation_to_name(all_df_diff_T, 'index', '005930', 5, abs_corr=True)

for key, value in top_correlated_companies.items():
    print('{} : {}'.format(company_list.loc[company_list.종목코드 == key, '회사명'].values[0], value))   


Output:



삼성전자 : 1.0
삼성전기 : 0.4065839894458186
SK하이닉스 : 0.3751230260001406
LG디스플레이 : 0.36649793644842443
삼성증권 : 0.35648431858304086




새로운 차트의 흥미로운 점은 이전보다 삼성전자와의 상관관계가 훨씬 낮다는 것입니다. "trend"를 제거했음에도 불구하고 상관관계가 있는 종목들을 보면 기존의 결과와는 매우 다릅니다. 삼성의 계열사가 주를 이루고 관련되어 있는 종목들이 결과로 나오는 것을 확인할 수 있습니다. 이 간단한 tool을 통해서 우리는 상관관계가 있는 종목들을 도출해 낼 수 있습니다. 이처럼 시계열의 데이터에서 얻을 수 있는 "trend"가 있는 데이터는 분명히 차이를 둬야된다는 것은 매우 중요합니다.



다음 포스팅에서는 이 상관관계가 있는 종목 데이터를 이용하는 방법에 대해 알아보겠습니다.












Macroeconomic forecasting with Gaussian processes






정확한 거시경제 예측은 사업 결정, 금융 거래, 그리고 정치인과 경제학자들에 의한 정책 결정의 근거로서 필수적입니다. 전통적으로 시계열 데이터에 대한 선형 회귀 또는 밀접하게 관련된 방법을 통해 수행되었습니다. 
본 포스팅에서는 인기 있는 비선형적 방법인 가우스 프로세스 회귀 분석을 사용하여 여러 국가의 GDP를 예측하여 전통적인 기법보다 더 나은 결과를 얻을 수 있는지 여부를 확인하고자 합니다.

가장 중요한 거시경제변수는 아마도 국내총생산(GDP)일 것입니다. 그것은 한 지역에서 판매되는 모든 상품과 서비스의 가치를 측정하기 때문입니다. 따라서 우리는 GDP 예측에 초점을 맞출 것입니다.

전체적으로는 다음과 같이 구성됩니다.

1. 먼저 데이터를 로드하고 변환한 다음, 
2. simple baseline method 및 multivariate time-series regression을 평가하고 
3. 마지막으로 가우스 프로세스(GP) 회귀 분석과 비교합니다.

Environment

우리는 pandas, statsmodels, scikit-learn 패키지를 사용할 것입니다. 
콘솔이나 터미널에 아래와 같은 명령어로 설치합니다. 
    > pip3 install pandas
    > pip3 install statsmodels
    > pip3 install sklearn



Configuration

첫 째로, 우리는 configuration을 특정할 것입니다. 만약 다른 나라, 기간, indicators가 필요하다면 코드를 바꾸시면 됩니다.


Input:

# out-of-sample로 사용할 년도의 수 
#(실제 GDP와 비교하여 매년 국가별로 하나의 예측을 할 것입니다)
nyears = 10
# GP regression에 사용할 lag의 수
lags = 5
# Indicator labels과 the World Bank API에서의 이름
indicators  = {"gdp"        : "NY.GDP.MKTP.CD",
               "population" :    "SP.POP.TOTL",
               "inflation"  : "FP.CPI.TOTL.ZG"}
nindicators = len(indicators)
# 예측하기 위한 변수, indicator labels 중에 하나여야 함
target_variable = "gdp"
# Countries to include in the data, specified as ISO country codes
countries  = ['au','ca','de','es','fr','gb','jp','us']
ncountries = len(countries)
# 데이터 셋의 시작 연도와 마지막 연도
start_year = 1976
end_year   = 2018


Data

Loading

먼저 우리는 몇몇의 거시경제 지표들을 the World Bank HTTP API를 통하여 다운받을 것입니다. 여기서 Python의 requests 패키지를 사용하게 됩니다.

먼저 우리가 위에 configuration에서 설정했던 각각 다른 나라들, indicator로 채워질 template url을 특정합니다. 우리가 URL에 request할 때, 그 데이터들은 json 형식으로 fetched 될 것입니다. 우리는 그것들을 pandas dataframe에 넣을 것입니다.

import requests
import pandas as pd
template_url = "http://api.worldbank.org/v2/countries/{0}/indi"
template_url += "cators/{1}?date={2}:{3}&format=json&per_page=999"

# Countries는 세미 콜론으로 분리됩니다.
country_str = ';'.join(countries)
raw_data = pd.DataFrame()
for label, indicator in indicators.items():
    # template URL을 채웁니다.
    url = template_url.format(country_str, indicator, start_year, end_year)

    # 데이터를 request하고
    json_data = requests.get(url)

    # JSON String을 python object로 변경합니다.
    json_data = json_data.json()

    # 반환되는 데이터는 리스트이며, 첫 번째 element는 meta데이터,
    # 두 번째 element가 실제 데이터입니다.

    json_data = json_data[1]

    # 모든 데이터 포인트를 loop하며 value들을 dataframe으로 확장합니다.
    for data_point in json_data:
        country = data_point['country']['id']
        # 각각 나라, indicator로 variable을 만듬
        item = country + '_' + label

        year = data_point['date']

        value = data_point['value']

        # DataFrame으로 Append
        new_row = pd.DataFrame([[item, year, value]],
                               columns=['item', 'year', 'value'])
        raw_data = raw_data.append(new_row)
# 데이터를 피벗하여 columns을 따라 특정 연도를 얻고, rows를 따라 variable을 얻습니다.
raw_data = raw_data.pivot(index='year', columns='item', values='value')

# rows와 columns 출력 테스트
print('\n', raw_data.iloc[:10, :5], '\n')

Output:



Exploration

plots을 통해 데이터를 explore해보도록 하겠습니다.

Input:
import matplotlib.pyplot as plt
for lab in indicators.keys():
    
    indicator = raw_data[[x for x in raw_data.columns 
                              if x.split("_")[-1] == lab]]
    indicator.plot(title=lab)
    plt.show()

Output:




US의 GDP 성장율이 클수록 인구의 증가가 빠르다는 것을 부분적으로 설명할 수 있을 것입니다. 이것은 우리의 모델에 의해 captured 되어야 합니다.

Transformation

우리는 우리 모델의 데이터를 사용하기 전에, 적절한 모델로 transform해줘야 합니다.


Input:

import numpy as np

# 절대 값 대신에 우리는 상대적인 변화율을 이용할 것입니다.
# Nan값 때문에 오류가 발생할 수 있습니다.
data = np.log(raw_data).diff().iloc[1:,:]

# NaN을 0으로 채움.
data.fillna(0, inplace=True)

# 각 Series에서 평균값을 뺌
data = data - data.mean()

# index의 데이터 타입을 변경
data.index = pd.to_datetime(data.index, format='%Y')

# target variable 데이터만 뽑아서 target 변수에 넣음.
target = data[[x for x in data.columns if x.split("_")[-1] == target_variable]]


Evaluation

모든 모델들은 같은 방법으로 평가됩니다. 데이터의 마지막 연도를 예측하기 위해 우리는 각 나라의 이전 년도 데이터를 이용하여 모델을 훈련합니다. 각 예측에서 우리는 실제 값과 예측된 값의 차이를 제곱하여 error를 계산합니다. 그리고 mean을 구한 뒤, 제곱근을 취함으로써 우리는 root mean squared error (RMSE)를 구할 수 있습니다.



 ŷ𝒾 는 forecast 값,  𝘺𝒾 는 타겟 변수의 실제 값, 그리고 m은 우리가 예측할 년도의 개수입니다.

Baseline forecasts

우리는 먼저 simple baseline method 로 performance를 확인 해 본 뒤, subsequent methods와 비교해 볼 것입니다. baseline method는 간단하게 목표 변수의 이전 관측치와 동일한 변화율을 예측할 것입니다.

더 복잡한 방법은 naive baseline forecast보다 두드러지게 outperform하는 경우에만 사용하는 것이 좋습니다. the principle of Occam's Razor와 the KISS principle을 지키는 것이 좋습니다.

Input:

errors = target.iloc[-nyears:] - target.shift().iloc[-nyears:]
# Root mean squared error
rmse = errors.pow(2).sum().sum()/(nyears*ncountries)**.5
print('\n\t' + '-' * 18)
print("\t| Error: ", np.round(rmse, 4), '|')
print('\t' + '-' * 18 + '\n')


Output:






Multivariate time series


우리는 이제 multivariate time series regression의 performance를 조사해 볼 것입니다.
계량 경제학에서는 Vector Autoregression (VAR)이라고도 불립니다.


d는 독립 변수의 수, 𝜀는 lag의 수, εt 는 error term,  βi,jβi,j 는 추정된 파라미터입니다.
시계열 분석에 대한 자세한 내용을 알기 위해서는 Brockwell과 Davis의 "Time Series: Theory and Methods"와 Hamilton의 "Time Series Analysis"를 추천합니다.

모델을 fit하기 위해서 우리는 statsmodels 패키지를 사용합니다. 여기서 VAR 구현은 최소 제곱을 사용하여 매개 변수를 추정합니다. 하나의 lag를 이용하여 model을 훈련시킵니다. 즉, 독립 변수의 가장 최근 이전 값에서 대상 변수를 regression하지만, lag의 수를 설정을 지원하는 automatic methods도 있습니다. the Akaike Information Criterion (AIC) 나 Bayesian Information Criterion (BIC) 등이 있습니다.


Input:

from statsmodels.tsa.api import VAR
# Sum of squared errors
sse = 0
for t in range(nyears):
    
    # Create a VAR model
    model = VAR(target.iloc[t:-nyears+t], freq='AS')
    
    # Estimate the model parameters
    results = model.fit(maxlags=1)
    
    actual_values = target.values[-nyears+t+1]
    
    forecasts = results.forecast(target.values[:-nyears+t], 1)
    forecasts = forecasts[0,:ncountries]
sse += ((actual_values - forecasts)**2).sum()
# Root mean squared error
rmse = (sse / (nyears * ncountries))**.5
print('\n\t' + '-' * 18)
print("\t| Error: ", np.round(rmse, 4), '|')
print('\t' + '-' * 18 + '\n')

Output:



우리는 복잡한 VAR모델이 거시 경제 예측을 위해서 baseline model과 거의 동일하다는 것을 알 수 있습니다.


Gaussian process regression


우리는 이제 Gaussian process regression을 이용하여 GDP를 예측할 것입니다. 우리의 모델은 이전과 비슷합니다.
𝘺𝑡는 타겟 변수의 관측치입니다. 각 𝓍𝑡는 독립 변수의 관측된 벡터입니다.   𝑓(𝓍)는 regression 함수이고 noise term ε𝑡은 분산 α를 갖는 normal (Gaussian) distribution을 가지고 있습니다. 각 out-of-sample 예측에서 우리는 타겟 변수 y의 n년 간의 관측된 값을 column vector로 넣고 y로 나타낼 것입니다. 우리는 또한 각 관측치가 행렬에서 행을 차지하는 n년간 독립 변수의 관측치의 matrix를 X라고 할 것입니다. 여기서 각 관찰은 변수의 lagged values들을 포함할 것입니다.

회귀 함수 𝑓 (𝓍)가 임의의 매개 변수를 가진 선형 함수인 대신에, 함수는 이제 랜덤한 값을 가지므로 각 점 𝓍𝑡에서의 값은 정규 분포의 확률 변수이고 두 개의 확률 변수 𝑓(𝓍𝑡)와 𝑓(𝓍𝑠)는 소위 공분산 함수 (또는 커널) 𝑘(𝓍𝑡, 𝓍𝑠)에 의해 주어지며, 이것들은 지정되어야 합니다. 𝑓(𝓍) 함수는 '가우시안 프로세스'라 불립니다. error term이 정상적으로 분포되기 때문에 목표 값은 𝑡 = s이고 𝑘 (𝓍𝑡, 𝓍𝑠) 이면 𝑘 (𝓍𝑡, 𝓍𝑠) +𝑎 와 같은 공분산으로 정규 분포됩니다.

𝘺𝑡 𝓍𝑡 에 대해 nn 개의 데이터 포인트를 사용하여 모델을 추정하고, 우리가 𝑛+₁ 의 예측을 토대로 새로운 테스트 포인트 𝓍𝑛+₁을 가지고 있다고 가정합시다. 주어진 y, 𝑋 ,𝓍𝑛+₁ 에서 f(𝓍𝑛+₁의 조건부 분포는 또한 정규 분포를 가지며  ŷ𝑛+₁ 의 예측을 𝑓(𝓍𝑛+₁)의 조건부 기대 값으로 삼을 수 있습니다.  잘 알려진 공식인 multivariate Gaussian distribution은 아래와 같습니다.

K는 n X n 행렬 (행 t와 열 s에 대한 엔트리는  𝑘 (𝓍𝑠, 𝓍𝑡)로 주어지고, 𝐼는 항등 행렬이며, 𝐤는 𝑘(𝓍𝑡,𝓍𝑛+₁)에 의해 주어진 t를 갖는 길이 n의 열 벡터입니다.

classification에도 사용되는 Gaussian process methods를 더 읽기 위해서는, Rasmussen 과 Williams의 "Gaussian Processes in Machine Learning"을 보는 것을 추천합니다.

Gaussian process regression은 scikit-learn 패키지를 이용합니다. 각 예측 연도에 대해 과거 타겟 변수의 관측치들의 벡터 y와 독립 변수의 관측치들의 data matrix X를 생성합니다.
우리는 이것들을 GaussianProcessRegressor 클래스에 제공하여 모델을 estimate한 다음 다음 해에 대한 예측을 할 것입니다. 이전과 마찬가지로 RMSE를 사용하여 오류를 계산합니다.

우리는 아래와 같은 common Gaussian covariance function을 사용할 것입니다.

∥v∥   vector vv의 길이이고 , σσ 는 매개변수입니다.


Input:

from sklearn.gaussian_process import GaussianProcessRegressor
from sklearn.gaussian_process.kernels import RBF

# 우리는 covariance function의 매개변수를 일반적인 covariance function의
# heuristic인 데이터 포인트의 median으로 사용합니다.
# The 'alpha' 인수는 잡음 분산이며, 우리가 covariance 매개변수와 동일하게 설정합니다.

gpr = GaussianProcessRegressor(kernel=RBF(0.1), alpha=0.1)
# 각 예측의 estimation/fitting을 위한 데이터 포인트의 수
ndata = target.shape[0] - nyears - lags
print(ndata)
# Sum of squared errors
sse = 0
for t in range(nyears):

    # 타겟 변수의 관측치
    y = np.zeros((ndata, ncountries))
    # 독립 변수의 관측치
    X = np.zeros((ndata, lags * ncountries * nindicators))

    for i in range(ndata):
        y[i] = target.iloc[t + i + 1]
        X[i] = data.iloc[t + i + 2:t + i + 2 + lags].values.flatten()

    gpr.fit(X, y)

    x_test = np.expand_dims(data.iloc[t + 1:t + 1 + lags].values.flatten(), 0)
    forecast = gpr.predict(x_test)

    sse += ((target.iloc[t].values - forecast) ** 2).sum()

rmse = (sse / (nyears * ncountries)) ** .5
print('\n\t' + '-' * 18)
print("\t| Error: ", np.round(rmse, 4), '|')
print('\t' + '-' * 18 + '\n')


Output:

우리는 지금까지 얻은 결과를 정리해보면 Gaussian process regression을 사용하여 얻은 결과는 baseline과 linear regression models과 비교하여 약간의 성능 개선이 있다는 것을 확인할 수 있었습니다.


옵션 가격결정 & The "Greeks"





1. 옵션 가격결정

이번 포스팅은 옵션 가격 결정과 Greeks에 대해 알아보도록 하겠습니다.

the Greeks를 이해하는 것, 내재 변동성, time decay(감쇠) 등 옵션 가격에 영향을 주는 요소들을 고려해 주는 것은 이 산업에서 성공적인 비지니스를 이룰 수 있는지와 없는지를 구별해 줄만큼 매우 중요한 요소입니다.

하지만 시장 변화에 따라 단일 옵션 또는 복수의 옵션이 포함된 포지션의 가격에 어떤 일이 발생할지 예측하는 것은 어려울 수 있습니다. 옵션은 많은 다른 요소들이 포함되어 있기 때문입니다. 따라서 옵션가격이 항상 주식의 가격과 함께 움직이는 것처럼 보이지 않기 때문에, 어떤 요소들이 옵션의 가격에 기여하고 그들이 가지는 영향을 이해하는 것이 중요합니다.

옵션 트레이더들은 종종 옵션 포지션의 델타, 감마, 베가, 세타를 이용합니다. 이것들은 종합적으로 "Greeks"라고 불리며 수량화 할 수있는 팩터들에 대한 옵션 가격의 민감도를 측정할 수 있는 방법입니다.

여기서 사람들이 흔히들 착각을 합니다. 중요한 것은, Greeks는 가격을 결정하는 것이 아니라는 것입니다. Greeks는 단지 주가 변동, 내재 변동성, 시간 등에 대한 옵션가격 변동이 일어날 수 있는 것을 반영합니다. 즉, Greeks는 앞을 내다보는 용도이지, 가격 결정을 하는 것이 아니라는 것입니다. 이것은 아주 중요한 차이입니다.


 
옵션 가격은 크게는 두 개의 카테고리로 분류가 됩니다.
첫 번째는 Intrinsic Value(내재 가치), Time Value(시간 가치)입니다.


1.1. Intrinsic Value


내재 가치에 대해 먼저 알아보자면,
만약 당신이 50의 Strike Price(행사가격)를 가지고 있는 콜 옵션이 있고
현재 Spot Price(현물가격)가 55라면 당신은 옵션의 5의 내재 가치를 가지고 있는 것입니다.
왜냐하면 당신은 50에 산 뒤, 즉시 55에 팔 수 있기 때문이죠.
간단하게 행사가격과 현물가격의 차이라고 생각할 수 있습니다.


1.2. Time Value


두 번째로는 시간 가치입니다.
이것이 문제입니다. 사람들은 대부분 내재 가치는 쉽게 얻지만, 이 시간 가치가 기초 자산의 가격 변동과 더불어 옵션 가격 변동에 많은 관련이 있기 때문입니다.
내재 가치는 linear한 관계에 있다면 이 시간 가치는 약간 다릅니다.


1.2.1. Time to Maturity


먼저 Time to Maturity(기간)은 만기가 얼마나 남았는지 입니다.

만기가 긴 옵션은 더 고평가 됩니다. 왜냐하면 그 계약이 성사되기 까지 시간이 오래 걸리기 때문입니다.


1.2.2. Volatility


다음은 Volatility(변동성)입니다. 이것은 여기서 핵심 요소입니다.
변동성이 높다면 옵션 가격은 상승합니다. 콜, 풋 모든 쪽에서 상승하게 되는데, 기초자산의 변동성이 크면 클수록 기초자산의 가격이 행사가격을 넘어 In-the-Money상태로 갈 확률이 높아지게 됩니다. 하루에 0.1%씩 오르고 내리는 주식 보다는 상한가 하한가를 보이며 움직이는 주식이 더 높은 옵션프리미엄을 가진다는 이야기입니다.


1.2.3. Rate of Interest


마지막으로는 Rate of Interest(이자율)입니다.

이것은 rho입니다. 여기서는 rho에 대해서 자세하게 설명하지 않겠습니다. 이것은 Time to Maturity와 Volatility 같이 계약 만기가 더 길어질수록 이자율은 옵션 가치에 더 큰 영향을 미치게 됩니다. 60일 이내의 옵션의 경우에는 이것의 영향이 거의 존재하지 않습니다.
그렇기 때문에 main Greek으로 다루진 않겠지만 이러한 것이 있다는 것을 알아두면 좋게습니다.

이렇게 기본적인 옵션 가격결정에 대해 알아보았으며, 이제는 실제 Greek에 대해 알아 보도록 하겠습니다.




2. The Greeks


우리가 좀 전까지 다뤘던 Option Pricing을 Greeks으로 바꿔보면 그림과 같이 5가지의 Greeks이 있습니다. 기본적으로 4가지의 중요한 Greeks은 Delta, Gamma, Vega, Theta입니다. 그리고 Rho까지 총 5가지의 Greeks입니다. 여기서 Rho는 중요 요소가 아니지만 무시하지는 않을 것입니다.

2.1. Delta


델타(Delta) = 옵션가격변화 / 기초자산의 변화

델타는 기본적으로 내재 가치에 대한 관계를 보여주는 역할을 합니다. 기초 자산의 변화에 따른 옵션 가치의 변화로 표현합니다.
만약 콜옵션이 Deep OTM(깊은 외가격상태)에 있을 경우 콜옵션의 델타는 0에 가까울 것입니다. 만약 기초자산의 가격이 조금 오르더라도 콜옵션은 아직 OTM일 것이기 때문에 가격의 변화가 거의 없을 것이기 때문입니다.
그리고 콜옵션이 Deep ITM에 있는 경우 콜옵션의 델타는 거의 1에 가까울 것입니다.
기초 자산 가격변화와 거의 같은 비율로 콜옵션의 가격이 변하게 될 것이기 때문입니다.

2.2. Gamma


감마(Gamma) = 델타 가격변화 / 기초자산의 변화

감마는 맨 위 그림과 연결되진 않지만 델타와 관련이 있습니다. 감마는 기본적으로 변화율, 혹은 델타의 acceleration amount입니다.

2.3. Vega


Vega-Volatility. 
베가(Vega) = 옵션 가격변화 / 주가지수의 변화

외우기 쉽죠. 베가는 기초자산의 가격변동성의 변화에 따른 옵션가격의 변화 정도를 말합니다.
가격 변동성은 말씀 드렸다시피 시간가치를 결정하는 데에 가장 중요한 변수입니다. 변동성이 증가하면 시장의 불확실성이 높아져 시간가치가 증가하죠.
가격 변동성이 상승할 것을 예상한다면 등가격 옵션의 매수를 고려하고, 반대일 경우에는 매도를 고려합니다. 이는 등가격옵션의 베가가 가장 크기 때문입니다.

2.4. Theta


Theta-Time to Maturity.
세타(Theta) = 옵션 가격변화 / 시간의 변화

세타는 시간의 경과함에 따른 옵션가격의 변화 정도를 말합니다. 옵션은 만기일에 가까워질수록 시간가치가 줄어듭니다. 세타는 이러한 시간소멸효과를 측정한 것으로, 현재의 옵션시장가격과 익일의 이론가격과의 차이를 나타냅니다.
세타는 베가와 마찬가지로 등가격옵션일 때 가장 크고 내가격이나 외가격으로 갈수록 작아지게 됩니다.

2.5. Rho

Rho - Rate of Interest
로(Rho) = 옵션 가격변화 / 이자율의 변화

로는 이자율의 변화에 따른 옵션값의 변화를 뜻합니다. 일반적으로 콜옵션 매수자는 금리가 오르면 유리하고 반대로, 풋옵션 매수자는 금리가 내려가면 유리합니다.