파이썬으로 VAA 전략 리밸런싱을 해보자 (동적자산배분)

1. 들어가며

 최근에 주식에 다시 관심을 가지고 이것저것 공부하고 있다. 지금은 불확실성이 커서 위험한 시기라고 한다. 여러 불안 요소들이 해소가 되는 듯 하면 들어가려고 하는데, 앞으로는 웬만하면 개별주에 투자하지 않고 동적자산배분을 바탕으로 ETF에 투자를 하려고 한다.

 

 지금 계획은 올웨더50%, VAA50%이나, 현재의 불확실성이나 높은 환율을 생각하면 올웨더는 우리나라 ETF에 투자하거나 아니면 현금으로 보유하고 있을까 싶다. 내년쯤 물가 안정이나 경기침체에 대한 우려가 해소되어서 상승장이 되면 그때 들어가는 것이 낫지 않을까 싶다.

 

 

이틀 전 뉴스 : S&P 500이 2.76% 오른날
어제 뉴스 : S&P 500이 0.84% 떨어진 날

 

 

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. 기타

 오는 말일에 시도해 볼 예정! 환율이 너무 높아서 걱정이긴 하지만, 연습하는 마음으로 해보려고 한다. 

댓글

Designed by JB FACTORY