미국 ETF 평균모멘텀스코어로 비중 조절 백테스트(ETF 포트폴리오 투자)
본문 바로가기
파이썬(Python)/파이썬으로 투자실험

미국 ETF 평균모멘텀스코어로 비중 조절 백테스트(ETF 포트폴리오 투자)

by 대충살아볼까 2024. 3. 4.

"주식투자 ETF로 시작하라" 라는 책을 읽었습니다.

 

 

 

이 책에서 ETF를 투자할 때 평균모멘텀스코어라는 전략으로 투자비중을 조정하면서 장기간 투자하면 단일종목만 투자할 때 보다 변동성은 줄여주고, 수익을 올려준다는 내용이 있습니다.

 

미국ETF를 투자하고 있는 입장에서 사실인지 여부를 너무나 확인해보고 싶어서 백테스트를 해 보았습니다.

 

 

전략

전략은 간단합니다. 추세추종전략으로 모멘텀이 상승하면 주식(ETF)비중을 늘리고, 반대인 경우는 주식 비중을 줄이는 대신 현금비중을 늘리는 방법입니다.

 

예를들어 이번달에 주식이 1000원인데 지난달이 800원이었으면 올랐기 때문에 1을 부여합니다. 2달전에 1100원이었으면 떨어졌기 때문에 0을 부여합니다. 이렇게 1과 0을 지난 1년치를 대상으로 월별로 부여한 다음 12로 나눠줍니다.

 

그럼 0% ~ 100%까지 다양하게 비중이 나오겠죠? 그 비중에 따라서 ETF를 투자하고, 현금은 국내 RP가 3%이기 때문에 매월 3/12%이자로 늘어난다고 가정했습니다.

 

 

 

미국 ETF 데이터 가져오기

import pandas as pd
from pandas_datareader import data as pdr
import yfinance as yf
yf.pdr_override()
from datetime import datetime
import matplotlib.pyplot as plt

pd.options.display.float_format = '{:,.2f}'.format

ticker = 'voo'

df = pdr.get_data_yahoo(ticker)
df

 

 

데이터를 가져왔습니다. 저는 월별로 투자를 한다고 가정하고 백테스트를 진행할 에정이기 때문에 월별 마지막날을 가져와 보도록 하겠습니다.

 

 

매월말 데이터만 추출해서 데이터프레임 만들기

df['Odate'] = df.index
df

 

index를 복사해서 'Odate'라는 컬럼을 만들었습니다.

 

df_m = df.groupby(by=[df.index.year, df.index.month], as_index=False).last()
df_m

월별 말일만 따로 뽑아서 데이터를 재정리 했습니다.

 

이제 날짜를 다시 index로 지정하겠습니다.

df_m.set_index('Odate', inplace=True)
df_m

 

 

'df_m'이라는 변수가 사용하기 귀찮아서 'df'로 변경하겠습니다.

df = df_m
df

 

 

 

모멘텀스코어 구하기

평균모멘텀은 12개월 중 지정월(이번달)과 비교해서  n 개월 이전 주가가 오르면 '1', 떨어지면 '0'을 부여해서 합산한 다음 12로 나눠주는 과정입니다.

li_score = []

for i in range(len(df)):
    if i<11:
        li_score.append(0)
    else:
        val = 0
        for m in range(1, 13):
            if df['Close'].iloc[i] - df['Close'].iloc[i-m] > 0:
                val += 1
        li_score.append(val/12)     
    
df['평균모멘텀스코어'] = li_score
df

 

책에는 코드가 이상하게 나와 있어서 제가 무식하게 만들었습니다. 제가 이해를 못하는 건지 책이 이상한건지 잘 모르겠네요. 몇 번씩 읽어보니깐 오타도 많고... 그래도 똑똑하신 분이 만들었으니 감사하게 생각하며 활용하고 있습니다.

 

df['평균모멘텀스코어'].describe()

 

생각보다 주식 투자 비중이 높은 달이 많은 것 같습니다. 

 

평균값이 72%이니, 대부분 전체 포트폴리오에서 ETF 비중이 72%를 유지하고 있다고 생각이 됩니다.

 

 

 

ETF와 현금의 비중을 구해서 백테스트 하기

주식 = []
현금 = []
합계 = []
for i in range(len(df)):
    if i == 0:
        주식.append(0)
        현금.append(1000)
        합계.append(1000)
    else:
        합계.append(주식[i-1]*df['Close'].iloc[i]/df['Close'].iloc[i-1] + 현금[i-1]*(1 + 0.03/12))
        주식.append(합계[i]*df['평균모멘텀스코어'].iloc[i])
        현금.append(합계[i]-주식[i])

df['주식'] = 주식
df['현금'] = 현금
df['합계'] = 합계

df

 

pandas를 능숙하게 다루지 못해서 무식한 방법으로 만들었습니다.

 

합계를 우선 구한 다음 주식과 현금비중을 나누는 방법으로 리밸런싱하는 백테스트를 해 보았습니다.

 

현금은 매월 3/12%로 계산했습니다.(RP가 3%정도 되더라구요.)

 

df['주가백분율'] = df['Close']/df['Close'].iloc[0]
df['전략백분율'] = df['합계']/df['합계'].iloc[0]
df

 

그래프를 그리기 위해서 주가(ETF)와 전략(모멘트스코어)의 최초 금액 대비 백분율 컬럼을 추가했습니다.

 

 

그래프 그리기

plt.rcParams['figure.figsize'] = (16, 9)

plt.plot(df.index, df['주가백분율'], color='blue', label=ticker)
plt.plot(df.index, df['전략백분율'], color='red', label='Ave_momentum')
plt.grid(True)
plt.legend(loc='best')

plt.title(f'{ticker} vs Average_Momentum')

plt.show()

 

cagr_etf = (df['주가백분율'].iloc[-1]/df['주가백분율'].iloc[0]) ** (1/(len(df)/12)) -1
cagr_전략 = (df['전략백분율'].iloc[-1]/df['전략백분율'].iloc[0]) ** (1/(len(df)/12)) -1
print(cagr_etf, cagr_전략)

 

 

VOO 즉 S&P500 ETF는 CAGR이 11.7%인데 반해 평균모멘텀스코어 비중조절 전략은  7.8% 정도 되네요.

 

아마도 현금의 수익률이 적어서 그런것 같습니다. 현금대신 채권으로 하면 올라갈까요? VOO 대신 다른 ETF는 수익률이 어떻게 될까요?

 

너무나 궁금하지만 피곤해서 다음에 테스트하고 포스트 하도록 하겠습니다.

728x90

댓글