ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • (파이썬 증권데이터 분석) 백트레이더를 활용한 백테스트
    computer_IT 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의 범위를 멋어나면 매수 또는 매도 지점이 표시된다.

    댓글

Designed by Tistory.