앞서 우리는 ETF 2종목을 6:4로 구성하는 아주 간단한 포트폴리오를 구성해 보았다.
수익률을 CAGR로 산출하였고, 전략 평가방법 역시 -CAGR/MDD 로 산출하여 점수와 수익률 모두 표준화 하였다.
위 표를 토대로 우리는 우리 포트폴리오는 연평균 수익률이 11.1% 정도 나오며 해당 포트폴리오 전략의 점수는 대략 0.215점 정도 된다고 평가 할 수 있다.
하지만 전략점수가 높게나온다고 해도 결국 SPY 몰빵 전략이 수익률이 조금 더 높다. 하지만 6:4 전략을 유지하면서도 수익률도 몰빵전략보다 더욱 높이는 방법이 있다. 바로 리벨런싱이다.
복습겸 SPY, KODEX200 지표와 우리의 6:4 투자 후 존버 전략을 정리해보자.
import pandas as pd
# sql = """
# SELECT
# A.TICKER
# ,A.DATE
# ,A.ADJ_CLOSE PRICE
# FROM
# DAILY_CHART A
# WHERE
# A.TICKER IN ('SPY', 'KRX.069500')
# AND A.DATE BETWEEN '20020101' AND '20220131'
# """
# cur.execute(sql)
# data = cur.fetchall()
# pd.DataFrame(data).set_index(['TICKER', 'DATE']).to_csv('04_pf_01.csv')
df = pd.read_csv('04_pf_01.csv').set_index(['TICKER', 'DATE'])
data = {
'SPY': df.loc['SPY', :]['PRICE'],
'KODEX200': df.loc['KRX.069500', :]['PRICE']
}
chart = pd.DataFrame(data)
# 빈값은 앞의 값으로 채운다.(특정 나라에만 공휴일로 휴장일 경우), 앞의값이 없는경우 해당날짜 제외
chart = chart.fillna(method='ffill').loc[
chart['SPY'].notnull() &
chart['KODEX200'].notnull()
]
chart = chart / chart.iloc[0] # 기준가 1로 동일화
chart['Benchmark'] = chart['SPY'] * 0.6 + chart['KODEX200'] * 0.4
chart.plot(rot=45)
cagr = (chart.iloc[-1]/chart.iloc[0]).pow(1/(2021 - 2002)) - 1
mdd = ((chart - chart.cummax()) / chart.cummax()).min()
sp = -cagr/mdd
print('단위(%)')
table = pd.DataFrame.from_dict(cagr.to_dict(), orient='index', columns=['CAGR']) * 100
table['MDD'] = mdd * 100
table['SP'] = sp * 100
table
단위(%)
벤치마크는 전략의 기반이 되는 지수를 말한다. 예를들어 우리의 6:4 전략에서의 기초가 되는 지수(비교군)는 SPY와 KODEX200의 6:4 투자 수익률이 되며 이를 벤치마크라 정한다. 해당 지표를 기반으로 추가적인 전략을 사용하여 투자했을때 기존(벤치마크)대비 얼마만큼의 초과수익(알파)을 창출했는지 쉽게 파악할 수 있다.
idxs = chart.index
acc = {'CASH': 1, 'SPY': 0, 'KODEX200': 0}
hist = []
info = {'LAST_RB_YYMM': '0000-00'}
for i, (date, row) in zip(range(len(chart)), chart.iterrows()):
# 최초셋팅
if i == 0:
acc['SPY'] = acc['CASH'] * 0.6 / row['SPY']
acc['KODEX200'] = acc['CASH'] * 0.4 / row['KODEX200']
acc['CASH'] -= acc['SPY'] + acc['KODEX200']
print(acc)
month = date.split('-')[1]
yymm = "{}-{}".format(date[0], date[1])
spy_eval_amt = acc['SPY'] * row['SPY']
kodex200_eval_amt = acc['KODEX200'] * row['KODEX200']
eval_amt = spy_eval_amt + kodex200_eval_amt + acc['CASH']
# 리벨런싱
if month in ['05','11']:
if info['LAST_RB_YYMM'] != yymm:
target_spy_amt = eval_amt * 0.6
target_kodex200_amt = eval_amt * 0.4
diff_spy_amt = target_spy_amt - spy_eval_amt
diff_kodex200_amt = target_kodex200_amt - kodex200_eval_amt
diff_spy_qty = diff_spy_amt / row['SPY']
diff_kodex200_qty = diff_kodex200_amt / row['KODEX200']
acc['SPY'] += diff_spy_qty
acc['KODEX200'] += diff_kodex200_qty
# 평가금 기록
hist.append({'DATE': date, 'PF1': eval_amt})
pf1 = pd.DataFrame(hist).set_index('DATE')
print(acc)
# print(hist)
chart['PF1'] = pf1
chart.plot(rot=45)
{'CASH': 0.0, 'SPY': 0.6, 'KODEX200': 0.4}
{'CASH': 0.0, 'SPY': 0.6055940024862003, 'KODEX200': 0.46178392003736474}
단순 리벨런싱만 했을뿐인데 모든부분에서 PF1이 좋아보인다. 왜 이런 현상이 일어나는 걸까? 바로 리벨런싱을 할때 6:4 비중을 맞추기위해 상대적으로 많이 오른자산을 팔아 많이 내린 자산을 사기 때문이다. 이는 지속적인 고가매도와 저가매수를 의미한다.
투자 자산이 모두 우상향을 하고 서로의 오르고 내리는 타이밍과 폭이 다를 수록 리벨런싱을 지속적으로 하게되면 수익이 극대화 된다.
그러면 어떤 자산 혹은 종목을 골라야 수익을 극대화 할 수 있을까?