computer_IT

(파이썬 증권데이터 분석) 백트레이더를 활용한 백테스트

LifenLight 2022. 7. 24. 18:31
반응형

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()  # ⑨ 차트로 출력

결과 화면은 다음과 같다.

backtrader 백테스트 결과(엔씨소프트)

천 만원의 투자금액이 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를 이용한 백테스트(엔씨소프트)

위 그래프에서 빨간 원은 손실을 나타낸다. 맨 밑의 그래프에는 RSI_SMA 를 보여준다. 기준선인 30과 70의 범위를 멋어나면 매수 또는 매도 지점이 표시된다.

반응형