본문 바로가기
주식_퀀트_파이썬/전략 테스트

사계절 포트폴리오 1 - 전략 설명 / 연간 리밸런싱 백테스트

by 인더카 2023. 2. 5.
반응형

python 패키지 중 백테스트를 할 수 있는 bt라는 패키지가 있다.

https://pmorissette.github.io/bt/#

 

bt - Flexible Backtesting for Python — bt 0.2.10 documentation

What is bt? bt is a flexible backtesting framework for Python used to test quantitative trading strategies. Backtesting is the process of testing a strategy over a given data set. This framework allows you to easily create strategies that mix and match dif

pmorissette.github.io

그동안 동적/정적 자산배분 을 백테스트하기 위해 직접 구현했었는데,
bt를 이용하니 너무나도 간단하게 된다!

 

전략 구현은 직접 하면 되고,,
데이터 가공하거나 수익률 구하는 것 등 왠만한 건 알아서 해준다.

 

bt를 이용해서 레이달리오의 사계절 포트폴리오를 구현해 보자.

 

  이 글은 본인의 네이버 블로그 글을 옮겨 일부 수정한 글이다.
  패키지 사용 및 백테스트 기간은 현시점(2023년 2월)에 맞게 업데이트하였다.

  원글: https://blog.naver.com/inthecar4345/222789686795

 

사계절 포트폴리오

사계절 포트폴리오는 레이달리오가 만든 전략으로, 여러 자산군을 적당한 비율(?!)로 나누어 연 리밸런싱을 하는 것이다.
https://portfoliocharts.com/portfolio/all-seasons-portfolio/

 

All Seasons Portfolio – Portfolio Charts

Asset allocation. investing theory, and historical data for the All Seasons Portfolio by Ray Dalio, via Tony Robbins

portfoliocharts.com

자산 자산 성격 비율
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

 

한국 주식:채권 = 1:1 "Nifty Fifty Portfolio" python 백테스팅

#bt #ffn #python #backtesting backtrader나 bactesting.py의 경우 기술적 분석에 대한 백테스팅은 편한듯...

blog.naver.com

툴은 google colab을 사용했다.

https://colab.research.google.com/

 

Google Colaboratory

 

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())

 

반응형

댓글