파이썬으로 VAA 전략 리밸런싱을 해보자 (동적자산배분)
- 직장빼고생활/블로그
- 2022. 7. 21.
1. 들어가며
최근에 주식에 다시 관심을 가지고 이것저것 공부하고 있다. 지금은 불확실성이 커서 위험한 시기라고 한다. 여러 불안 요소들이 해소가 되는 듯 하면 들어가려고 하는데, 앞으로는 웬만하면 개별주에 투자하지 않고 동적자산배분을 바탕으로 ETF에 투자를 하려고 한다.
지금 계획은 올웨더50%, VAA50%이나, 현재의 불확실성이나 높은 환율을 생각하면 올웨더는 우리나라 ETF에 투자하거나 아니면 현금으로 보유하고 있을까 싶다. 내년쯤 물가 안정이나 경기침체에 대한 우려가 해소되어서 상승장이 되면 그때 들어가는 것이 낫지 않을까 싶다.
2. 전략 설명
VAA (Vigilant Asset Allocation)
참고할 게시물
https://allocatesmartly.com/vigilant-asset-allocation-dr-wouter-keller-jw-keuning/
https://youtu.be/eQeu8v_-Y98 (할 수 있다! 알고투자 - 강환국 작가님 유튜브)
1) 아래와 같이 자산을 두 종류로 분류
- 공격 자산 : SPY(미국 주식), VEA(선진국 주식), VWO(개발도상국 주식), AGG(미국 잡채권)
- 수비 자산 : SHY(미국 단기국채), IEF (미국 중기국채), lQD (미국 회사채)
2) 각 자산에 대하여 momentum score를 계산한다.
Momentum Score : (12 * (p0 / p1 – 1)) + (4 * (p0 / p3 – 1)) + (2 * (p0 / p6 – 1)) + (p0 / p12 – 1)
= 12*(최근 1개월 수익) + 4*(최근 3개월 수익) + 2*(최근 6개월 수익) + 1*(최근 12개월 수익)
3) 아래 방법으로 자산을한 개의 자산에 100% 투자한다.
- 만약 4개의 공격 자산의 Momentum Score가 모두 플러스(Positive)라면, 공격 자산 중 가장 높은 점수의 자산을 구매한다.
- 만약 4개의 공격 자산 중 1개라도 마이너스(Negative)가 있다면, 수비 자산 중 가장 높은 점수의 자산을 구매한다.
4) 매월 말일에 리밸런싱을 한다.
3. 파이썬으로 리밸런싱을 위한 계산하기
전체 코드 -> 매월 말일자 데이터로 계산
과거 데이터를 말일로 계산하지 않으면 영업일/공휴일 등이 끼어 코드가 까다롭게 된다. 어차피 말일에 리밸런싱을 할 것이니 매월 말일 수정 종가를 기준으로 작성하도록 코드를 짬
import pandas_datareader as pdr
import pandas as pd
from datetime import datetime, timedelta
pd.options.display.float_format = '{:.2f}'.format
# today = datetime(2022,6,30) # Manual 입력시
today = datetime.today()
start_date = today - timedelta(days=366)
end_date = today
# Momentum Score 계산
def cal_momentum(price):
month_1 = (price[-1] - price[-1-1]) / price[-1-1]
month_3 = (price[-1] - price[-1-3]) / price[-1-3]
month_6 = (price[-1] - price[-1-6]) / price[-1-6]
month_12 = (price[-1] - price[-1-12]) / price[-1-12]
result = 12*month_1 + 4*month_3 + 2*month_6 + 1*month_12
return [price[-1], month_1, month_3, month_6, month_12, result]
asset_list = ['SPY', 'VEA', 'EEM', 'AGG', 'LQD', 'SHY','IEF']
result_df = pd.DataFrame(index = ['price','month1','month2','month6','month12','result'])
for item in asset_list:
# yahoo에서 주가 데이터를 가져온다.
raw_data = pdr.get_data_yahoo(item, start_date, end_date)['Adj Close']
# 매월 말일 데이터만 남기도록 정리
df = raw_data.to_frame()
df['STD_YM'] = df.index.to_series().apply(lambda x : x.strftime('%Y-%m'))
month_list = df['STD_YM'].unique()
month_last_df = pd.DataFrame()
for m in month_list:
month_last_df = month_last_df.append(df.loc[df[df['STD_YM']==m].index[-1],:])
# Momentum Score 계산
data = cal_momentum(month_last_df['Adj Close'])
result_df[item] = data
print(result_df)
현재 기준 실행 결과 :
공격 자산 중 마이너스가 있으므로 수비 자산을 구매. 가장 점수가 높은 SHY (-0.14 포인트)를 전량 구매한다.
다만 위의 결과는 오늘 날짜(한국시간 2022년 7월 20일 00시 01분 기준)의 가격과 과거 월 말일자의 가격을 계산하여 산출한 것이므로, 정확한 결과를 얻기 위하여서는 매월 말일에 실행하거나 시작 날짜를 말일로 지정하고 실행하여야 한다.
4. 코드 간단히 설명
1) 주가 데이터 가져오기
raw_data = pdr.get_data_yahoo(item, start_date, end_date)['Adj Close']
아래와 같이 특정 기간동안 모든 날짜의 종가 데이터를 가져온다.
2) 매월 종가 데이터 가져오기
위 데이터에 어떤 달의 값이 있는지 확인하기 위하여 '년-월' 데이터를 리스트로 뽑아냅니다.
df = raw_data.to_frame()
df['STD_YM'] = df.index.to_series().apply(lambda x : x.strftime('%Y-%m'))
month_list = df['STD_YM'].unique()
결과
raw data에서 매월 종가 데이터를 가져옵니다.
'년-월' 값으로 필터 후 가장 마지막 인덱스의 값이 그 달의 마지막 종가이므로 해당 데이터를 가져옵니다.
month_last_df = pd.DataFrame()
for m in month_list:
month_last_df = month_last_df.append(df.loc[df[df['STD_YM']==m].index[-1],:])
print(month_last_df)
결과
3) 마지막 계산
미리 정의해놓은 함수로 Momentum Score를 계산합니다.
data = cal_momentum(month_last_df['Adj Close'])
5. 기타
오는 말일에 시도해 볼 예정! 환율이 너무 높아서 걱정이긴 하지만, 연습하는 마음으로 해보려고 한다.