유자차의 재테크 공부방

[동적자산배분] HAA - 파이썬으로 직접 백테스트하기 (1) 본문

자산배분

[동적자산배분] HAA - 파이썬으로 직접 백테스트하기 (1)

유자차H 2023. 3. 19. 19:20
반응형

HAA 이론

 

import pandas as pd
import yfinance as yf

# yahoo finance에서 필요 종목들의 공통 시작일부터 종가 데이터 받기
def get_yahoo_data(tickers, get_type="Adj Close"):
    df = yf.download(tickers)
    df = df[get_type]
    df.dropna(inplace=True)
    return df

# 리밸런싱 하는 날의 데이터만 뽑기(월말 데이터만 추출)  
def get_rebal_date(df, rebal="month"):
    res_df = pd.DataFrame()
    df["year"] = df.index.year
    df["month"] = df.index.month
    df["day"] = df.index.day
    days_df = df.groupby(["year","month"])["day"].max()
    for i in range(len(days_df)):
        if days_df.iloc[i] >= 25:
            day = "{}-{}-{}".format(days_df.index[i][0], days_df.index[i][1], days_df.iloc[i])
            res_df = pd.concat([res_df,df[df.index==day]])
    return res_df

agg_tickers = ["SPY","IWM","VEA","VWO","TLT","IEF","PDBC","VNQ"]
safe_tickers = ["IEF","BIL"]

all_tickers = list(set(agg_tickers+safe_tickers+["TIP"]))
data = get_yahoo_data(all_tickers)
month_data = get_rebal_date(data)

safe_num = 0
agg_num = 0
buy_history = []
# logic
# TLT 1-3-6-12 모멘텀 점수 구하기
for i in range(12, month_data.shape[0]):
  m1 = (month_data["TIP"].iloc[i]-month_data["TIP"].iloc[i-1])/month_data["TIP"].iloc[i-1]
  m3 = (month_data["TIP"].iloc[i]-month_data["TIP"].iloc[i-3])/month_data["TIP"].iloc[i-3]
  m6 = (month_data["TIP"].iloc[i]-month_data["TIP"].iloc[i-6])/month_data["TIP"].iloc[i-6]
  m12 = (month_data["TIP"].iloc[i]-month_data["TIP"].iloc[i-12])/month_data["TIP"].iloc[i-12]
  score = m1 + m3 + m6 + m12
  # print("TLT 모멘텀 스코어 : {}".format(score))

  if score > 0:
    # print("상승장")
    agg_num+=1
    asset_type = agg_tickers
    m1 = (month_data[asset_type].iloc[i]-month_data[asset_type].iloc[i-1])/month_data[asset_type].iloc[i-1]
    m3 = (month_data[asset_type].iloc[i]-month_data[asset_type].iloc[i-3])/month_data[asset_type].iloc[i-3]
    m6 = (month_data[asset_type].iloc[i]-month_data[asset_type].iloc[i-6])/month_data[asset_type].iloc[i-6]
    m12 = (month_data[asset_type].iloc[i]-month_data[asset_type].iloc[i-12])/month_data[asset_type].iloc[i-12]
    score = m1 + m3 + m6 + m12
    # print("공격자산 모멘텀 스코어 : {}".format(score))
    top4 = score.nlargest(4)
    buy=[]
    for name, value in zip(top4.index, top4.values):
      if value <= 0:
        buy.append("BIL")
      else:
        buy.append(name)
    
  else:
    # print("하락장")
    safe_num+=1
    asset_type = safe_tickers
    m1 = (month_data[asset_type].iloc[i]-month_data[asset_type].iloc[i-1])/month_data[asset_type].iloc[i-1]
    m3 = (month_data[asset_type].iloc[i]-month_data[asset_type].iloc[i-3])/month_data[asset_type].iloc[i-3]
    m6 = (month_data[asset_type].iloc[i]-month_data[asset_type].iloc[i-6])/month_data[asset_type].iloc[i-6]
    m12 = (month_data[asset_type].iloc[i]-month_data[asset_type].iloc[i-12])/month_data[asset_type].iloc[i-12]
    score = m1 + m3 + m6 + m12
    # print("안전자산 모멘텀 스코어 : {}".format(score))
    buy = list(score.nlargest(1).index)
  buy_history.append(buy)

df_buy = pd.DataFrame(buy_history)
df_buy["Date"] = month_data.index[12:]
df_buy.set_index("Date", drop=True, inplace=True)
df_buy.fillna("", inplace=True)
print("상승장 : 하락장 비율  = {:.1f}% : {:.1f}%".format(agg_num/(agg_num+safe_num)*100, safe_num/(agg_num+safe_num)*100))

상승장은 71.6% 하락장은 38.4%으로 나왔다. 상승장이 하락장의 2배 이상!!

강환국님의 영상에서 상승장은 86% 하락장은 14%정도였는데, 기간에 달라서일 듯( 1971-2023.01)

 

2015년 12월부터 2023년 3월까지 안전자산인 경우가 25번인데

이 중 IEF는 4번밖에 안나왔다. 안전자산으로 가라 = 현금으로!! 인듯

반응형
Comments