(파이썬 증권데이터 분석) 백트레이더를 활용한 백테스트
2022.07.24 - [computer_IT] - (파이썬 증권데이터 분석) 슬랙으로 알림메시지 보내기
(파이썬 증권데이터 분석) 슬랙으로 알림메시지 보내기
2022.07.24 - [computer_IT] - (파이썬 증권데이터 분석) 장고 웹서버 구축 및 자동화 (파이썬 증권데이터 분석) 장고 웹서버 구축 및 자동화 2022.07.24 - [computer_IT] - (파이썬 증권데이터 분석) 삼중창 매매.
lifenlight.tistory.com
백테스트는 과거 데이터를 기반으로 테스트를 진행하기 때문에 백테스트에서 좋은 결과가 나온다 해도 미래에 동일한 결과를 보장할 수 없다. 조금이라도 신뢰할 수 있는 결과를 얻으려면 최대한 긴 기간동안 수집된 다량의 데이터를 이용하여 검증해야 한다. 백테스트 파이썬 라이브러리로 Zipline, PyAlgoTrade, TradingWithPython, PyBacktest 등이 있다. 책에서는 Backtrader를 사용하였다. 문서화가 잘 되어 있고 직관적이어서 사용하기 쉽다고 한다.
pip install backtrader로 라이브러리를 설치한다. 현재 YahooFinanceData() 함수 에러가 발생한다. (FileNotFoundError: [Errno 2] No such file or directory:) pip 로 설치하지 말고 https://github.com/mementum/backtrader 여기서 zip파일을 다운받아 가상환경 lib>python3.x>site-packages 폴더 안에 backtrader 폴더를 복사한다.
백트레이더 홈페이지 주소는 https://backtrader.com/ 이다.
RSI를 이용한 단순 백테스트
천 만원의 투자 금액으로 RSI지표에 따라 매매했을 때 백테스틑 결과를 출력하는 예제이다.
from datetime import datetime
import backtrader as bt
class MyStrategy(bt.Strategy): # ① bt.Strategy 클래스 상속받음
def __init__(self):
self.rsi = bt.indicators.RSI(self.data.close) # ② 사용할 변수 지정
def next(self): # ③ next()메서드는 조건을 만족하는 최소 주기마다 자동으로 호출된다.
if not self.position:
if self.rsi < 30: # RSI가 30 미만일 때 매수
self.order = self.buy()
else:
if self.rsi > 70: # RSI가 70 초과일 때 매도
self.order = self.sell()
cerebro = bt.Cerebro() # ④ Cerebro는 데이터 취합 및 백테스트 출력기능 담당
cerebro.addstrategy(MyStrategy)
data = bt.feeds.YahooFinanceData(dataname='036570.KS', # ⑤
fromdate=datetime(2017, 1, 1), todate=datetime(2019, 12, 1))
cerebro.adddata(data)
cerebro.broker.setcash(10000000) # ⑥ 초기 투자금액
cerebro.addsizer(bt.sizers.SizerFix, stake=30) # ⑦매매 단위는 30주
print(f'Initial Portfolio Value : {cerebro.broker.getvalue():,.0f} KRW')
cerebro.run() # ⑧ 백테스트 실행
print(f'Final Portfolio Value : {cerebro.broker.getvalue():,.0f} KRW')
cerebro.plot() # ⑨ 차트로 출력
결과 화면은 다음과 같다.
천 만원의 투자금액이 1292만원으로 늘어났다.
RSI_SMA를 이용한 백테스트
RSI 지표 대신 21일 단순 이동 평균에 대한 RSI_SMA 지표로 사용한다.
import backtrader as bt
from datetime import datetime
class MyStrategy(bt.Strategy):
def __init__(self):
self.dataclose = self.datas[0].close
self.order = None
self.buyprice = None
self.buycomm = None
# 21일 단순 이동평균에 대한 RSI_SMA
self.rsi = bt.indicators.RSI_SMA(self.data.close, period=21)
def notify_order(self, order): # ① 주문상태 변화가 있을 때마다 자동으로 실행
if order.status in [order.Submitted, order.Accepted]:
return
if order.status in [order.Completed]: # ② 주문상태가 완료이면 상세주문정보 출력
if order.isbuy():
self.log(f'BUY : 주가 {order.executed.price:,.0f}, '
f'수량 {order.executed.size:,.0f}, '
f'수수료 {order.executed.comm:,.0f}, '
f'자산 {cerebro.broker.getvalue():,.0f}')
self.buyprice = order.executed.price
self.buycomm = order.executed.comm
else:
self.log(f'SELL : 주가 {order.executed.price:,.0f}, '
f'수량 {order.executed.size:,.0f}, '
f'수수료 {order.executed.comm:,.0f}, '
f'자산 {cerebro.broker.getvalue():,.0f}')
self.bar_executed = len(self)
elif order.status in [order.Canceled]:
self.log('ORDER CANCELD')
elif order.status in [order.Margin]:
self.log('ORDER MARGIN')
elif order.status in [order.Rejected]:
self.log('ORDER REJECTED')
self.order = None
def next(self):
if not self.position:
if self.rsi < 30:
self.order = self.buy()
else:
if self.rsi > 70:
self.order = self.sell()
def log(self, txt, dt=None): # ③
dt = self.datas[0].datetime.date(0)
print(f'[{dt.isoformat()}] {txt}')
cerebro = bt.Cerebro()
cerebro.addstrategy(MyStrategy)
data = bt.feeds.YahooFinanceData(dataname='036570.KS',
fromdate=datetime(2017, 1, 1), todate=datetime(2021, 12, 1))
cerebro.adddata(data)
cerebro.broker.setcash(10000000)
cerebro.broker.setcommission(commission=0.0014) # ④ 수수료 차감
cerebro.addsizer(bt.sizers.PercentSizer, percents=90) # ⑤ 매매 주문 적용 주식수
print(f'Initial Portfolio Value : {cerebro.broker.getvalue():,.0f} KRW')
cerebro.run()
print(f'Final Portfolio Value : {cerebro.broker.getvalue():,.0f} KRW')
cerebro.plot(style='candlestick') # ⑥ 캔들스틱 차트로 표시
위 그래프에서 빨간 원은 손실을 나타낸다. 맨 밑의 그래프에는 RSI_SMA 를 보여준다. 기준선인 30과 70의 범위를 멋어나면 매수 또는 매도 지점이 표시된다.