python 패키지 중 백테스트를 할 수 있는 bt라는 패키지가 있다.
https://pmorissette.github.io/bt/#
그동안 동적/정적 자산배분 을 백테스트하기 위해 직접 구현했었는데,
bt를 이용하니 너무나도 간단하게 된다!
전략 구현은 직접 하면 되고,,
데이터 가공하거나 수익률 구하는 것 등 왠만한 건 알아서 해준다.
bt를 이용해서 레이달리오의 사계절 포트폴리오를 구현해 보자.
이 글은 본인의 네이버 블로그 글을 옮겨 일부 수정한 글이다. 패키지 사용 및 백테스트 기간은 현시점(2023년 2월)에 맞게 업데이트하였다. 원글: https://blog.naver.com/inthecar4345/222789686795 |
사계절 포트폴리오
사계절 포트폴리오는 레이달리오가 만든 전략으로, 여러 자산군을 적당한 비율(?!)로 나누어 연 리밸런싱을 하는 것이다.
https://portfoliocharts.com/portfolio/all-seasons-portfolio/
자산 | 자산 성격 | 비율 |
---|---|---|
SPY | Total Stock Market | 30% |
IEF | Intermediate Bonds | 15% |
TLT | Long Term Bonds | 40% |
GLD | Gold | 7.5% |
DBC | Commodities | 7.5% |
테스트 환경 및 참고자료
bt의 활용법은 희망고원님의 블로그를 참조했다.
bt를 활용한 다양한 전략들을 직접 구현하시고, 공개해 놓으셨다. (최고!)
https://blog.naver.com/hermian71/222082051169
툴은 google colab을 사용했다.
https://colab.research.google.com/
패키지 설치 및 import
필요한 패키지는 간단하다.
- bt
- 백테스트를 위한 기능 모음
- finterstellar
- 미국 주식 데이터 가져오기
- quantstats
- 결과 데이터를 여러가지 형태로 보기 쉽게 정리해 준다.
pip install부터 시작하자.
!pip install bt
!pip install finance-datareader
!pip install quantstats
그리고 import.
- %matplotlib inline: 이걸 해주어야 colab에서 matplot 그래프가 제대로 보인다.
import bt
import FinanceDataReader as fdr
import quantstats as qs
import pandas as pd
%matplotlib inline
초기 설정
사계절 포트폴리오에 사용되는 자산 및 초기 자본 설정.
초기 자본은 10만 달러로 했다.
U = ['SPY','IEF','TLT','GLD','DBC']
initial_capital = 100000.0
주가 데이터 가져오기
주가 데이터는 최대한 많이 가져오고, n/a인 데이터는 dropna로 잘라냈다.
df = pd.DataFrame()
for ticker in U:
df[ticker] = fdr.DataReader(ticker)['Adj Close']
df = df.dropna()
가져온 dataframe을 보면, 2006-02-06 부터 유효한 데이터를 가져온다.
사계절 포트폴리오 전략 구현
bt는 백테스트를 위한 api가 잘 구현되어 있어서,
정적 자산배분 정도의 간단한 전략은 아아아주 쉽게 구현이 가능하다. :)
s = bt.Strategy('all_season',
[bt.algos.RunYearly(run_on_first_date=False,
run_on_end_of_period=True,
run_on_last_date=False),
bt.algos.SelectAll(),
bt.algos.WeighSpecified(SPY=0.3,IEF=0.15,TLT=0.4,GLD=0.075,DBC=0.075),
bt.algos.Rebalance(),
])
bt1 = bt.Backtest(s, df, initial_capital=initial_capital)
- bt.algos.RunYearly()
- 연단위 리밸런싱
- run_on_first_date=False
- 전략 첫째날 리밸런싱 안함
- run_on_end_of_period=True
- 주기의 마지막날에 리밸런싱
- False로 하면 주기의 첫째날에 리밸런싱한다.
- run_on_last_date=False
- 전략 마지막날 리밸런싱 안함
- bt.algos.SelectAll()
- argument로 넘어온 dataframe의 전체를 사용
- bt.algos.WeighSpecified()
- 자산별 비중 결정
- bt.algos.Rebalnce()
- 리밸런싱
벤치마크를 위한 전략 (buy and hold) 구현
SPY를 벤치마크로 했다.
def buy_and_hold(data, name='buy_and_hold'):
s = bt.Strategy(name, [bt.algos.RunOnce(),
bt.algos.SelectAll(),
bt.algos.WeighEqually(),
bt.algos.Rebalance()])
return bt.Backtest(s, data, initial_capital=initial_capital)
SPY = buy_and_hold(df['SPY'].to_frame(), name='SPY')
전략 실행
만들어진 전략 수행은 bt.run() 함수로 해준다.
argument를 추가하면, 여러 전략을 동시에 테스트할 수 있다.
아래처럼 bt1(사계절)과 SPY를 동시에 테스트한다.
res = bt.run(bt1, SPY)
결과 확인
차트 찍어보기
res.plot()
SPY에 비해 곡선의 기울기가 완만하다.
적게 오르긴 했지만 낙폭도 적다.
2022년은 공통적으로 박살이 났다가 올 1월에 상당히 상승을 했다.
수치로 보기
res.display()
CAGR은 SPY에 비해 2/3 수준으로 낮지만, MDD가 1/2 수준이다.
MDD 떨어진 것에 비해 수익률이 적게 떨어졌다.
월간 수익률
res.display_monthly_returns()
2022년 한해는 정말 박살박살이다... 최종 YTD -18.8이다.
백테 기간 중 최악의 하락이다.
작년은 많은 전략들의 MDD가 갱신되었다.
강환국 작가 얘기로는, MDD가 갱신된 후가 상승률이 높다고 하던데 올해는 어떻게 될 지 모르겠다.
quantstats를 활용한 결과값
다양한 결과값을 한번에 얻을 수 있다.
qs.reports.full(res.prices['all_season'].to_returns().dropna(), res.prices['SPY'].to_returns().dropna())
Full Report
전체 소스코드
colab에서 .py로 추출
!pip install bt
!pip install finance-datareader
!pip install quantstats
import bt
import FinanceDataReader as fdr
import quantstats as qs
import pandas as pd
%matplotlib inline
U = ['SPY','IEF','TLT','GLD','DBC']
initial_capital = 100000.0
df = pd.DataFrame()
for ticker in U:
df[ticker] = fdr.DataReader(ticker)['Adj Close']
df = df.dropna()
s = bt.Strategy('all_season',
[bt.algos.RunYearly(run_on_first_date=False,
run_on_end_of_period=True,
run_on_last_date=False),
bt.algos.SelectAll(),
bt.algos.WeighSpecified(SPY=0.3,IEF=0.15,TLT=0.4,GLD=0.075,DBC=0.075),
bt.algos.Rebalance(),
])
bt1 = bt.Backtest(s, df, initial_capital=initial_capital)
def buy_and_hold(data, name='buy_and_hold'):
s = bt.Strategy(name, [bt.algos.RunOnce(),
bt.algos.SelectAll(),
bt.algos.WeighEqually(),
bt.algos.Rebalance()])
return bt.Backtest(s, data, initial_capital=initial_capital)
SPY = buy_and_hold(df['SPY'].to_frame(), name='SPY')
res = bt.run(bt1, SPY)
res.plot()
res.display()
res.display_monthly_returns()
qs.reports.full(res.prices['all_season'].to_returns().dropna(), res.prices['SPY'].to_returns().dropna())
'주식_퀀트_파이썬 > 전략 테스트' 카테고리의 다른 글
사계절 포트폴리오 2 - 월간 리밸런싱 (0) | 2023.02.08 |
---|
댓글