[알고리즘 트레이딩] Upbit 데이터를 활용한 Backtrader 백테스트

 

Upbit 1분봉 데이터를 활용한 Backtrader 백테스트

1. 개요

Backtrader는 강력한 백테스팅 프레임워크로, Python을 이용해 다양한 트레이딩 전략을 검증할 수 있습니다. 이번 글에서는 Upbit에서 1분봉 데이터를 가져와 Backtrader에서 활용하는 방법을 소개합니다.

2. 백테스트 과정

1️⃣ Upbit에서 1분봉 데이터 가져오기

Backtrader에서 데이터를 사용하려면 Pandas DataFrame 형태로 변환해야 합니다. Upbit API를 이용해 1분봉 데이터를 가져오는 코드를 작성합니다.

import requests
import pandas as pd

def get_upbit_ohlcv(market="KRW-BTC", count=200):
    url = "https://api.upbit.com/v1/candles/minutes/1"  # 1분봉 데이터
    params = {"market": market, "count": count}
    response = requests.get(url, params=params)
    data = response.json()

    df = pd.DataFrame(data)
    df["datetime"] = pd.to_datetime(df["candle_date_time_kst"])
    df = df[["datetime", "opening_price", "high_price", "low_price", "trade_price", "candle_acc_trade_volume"]]
    df.columns = ["datetime", "open", "high", "low", "close", "volume"]
    df.set_index("datetime", inplace=True)

    return df

df = get_upbit_ohlcv()
print(df.head())  # Upbit에서 가져온 데이터 확인

2️⃣ Backtrader에서 데이터 로딩

Backtrader는 Pandas DataFrame을 데이터 피드로 사용할 수 있습니다. 위에서 가져온 데이터를 변환하여 적용합니다.

import backtrader as bt

data = bt.feeds.PandasData(dataname=df)

3️⃣ 이동평균 크로스 전략 구현

단순한 SMA 20/60 크로스 전략을 구현합니다. (SMA20이 SMA60을 상향 돌파하면 매수, 하향 돌파하면 매도)

class SmaCross(bt.Strategy):
    params = (("sma1", 20), ("sma2", 60),)

    def __init__(self):
        self.sma1 = bt.indicators.SimpleMovingAverage(self.data.close, period=self.params.sma1)
        self.sma2 = bt.indicators.SimpleMovingAverage(self.data.close, period=self.params.sma2)
        self.order = None  # 현재 주문 상태 추적
        self.trade_count = 0  # 거래 횟수 추적

    def next(self):
        if self.order:  # 기존 주문이 있으면 대기
            return
        
        if self.sma1[0] > self.sma2[0] and self.sma1[-1] <= self.sma2[-1]:  # 골든크로스
            self.order = self.buy()
            self.trade_count += 1  # 거래 횟수 증가
        elif self.sma1[0] < self.sma2[0] and self.sma1[-1] >= self.sma2[-1]:  # 데드크로스
            self.order = self.sell()
            self.trade_count += 1  # 거래 횟수 증가

    def stop(self):
        final_value = self.broker.getvalue()  # 최종 포트폴리오 가치
        print(f"최종 자본: {final_value:.2f} KRW")
        print(f"총 거래 횟수: {self.trade_count}")
        print(f"수익률: {((final_value / 1000000) - 1) * 100:.2f}%")  # 초기 자본 100만 기준

4️⃣ 백테스트 실행 및 성능 평가

Backtrader 엔진을 실행하여 전략을 검증하고, 성능 평가를 추가합니다.

cerebro = bt.Cerebro()
cerebro.addstrategy(SmaCross)
cerebro.adddata(data)
cerebro.run()
cerebro.plot()

5️⃣ Sharpe Ratio 등 성능 지표 추가

Backtrader는 Sharpe Ratio(위험 대비 수익률) 같은 성능 지표를 추가할 수도 있습니다.

class SharpeRatio(bt.Analyzer):
    def __init__(self):
        self.returns = []

    def next(self):
        self.returns.append(self.strategy.broker.getvalue())

    def get_analysis(self):
        returns = pd.Series(self.returns).pct_change().dropna()
        sharpe_ratio = returns.mean() / returns.std() * (252 ** 0.5)  # 연간 Sharpe Ratio 계산
        return {"sharpe_ratio": sharpe_ratio}

cerebro.addanalyzer(SharpeRatio, _name="sharpe")
results = cerebro.run()
sharpe = results[0].analyzers.sharpe.get_analysis()
print(f"Sharpe Ratio: {sharpe['sharpe_ratio']:.2f}")

3. 결론

이 과정에서 Upbit에서 1분봉 데이터를 가져와 Backtrader에 적용하고 간단한 전략을 테스트하는 방법을 배웠습니다. 추가로 최종 자본, 거래 횟수, Sharpe Ratio 등을 활용해 성능을 평가하는 방법도 적용했습니다. 이를 기반으로 다양한 트레이딩 전략을 테스트하고 개선해볼 수 있습니다.

댓글

이 블로그의 인기 게시물

공압 속도 제어: 미터인 vs 미터아웃

NPN, PNP 트랜지스터 차이점

[PLC] 센서 NPN, PNP 출력 타입별 결선방법 (OMRON E2E-X 시리즈 3선식 배선)

[주식] 한국거래소(KRX) 데이터 API 입문 가이드

[PLC] PLC 아날로그 입출력 기본

[투자] ETF 투자 가이드 : 카테고리별 ETF 선택 전략

[PLC] 릴레이와 전자 접촉기 (MC)

[아두이노] 가변저항(Potential Divider)과 전압분배(Voltage Divider)

[농사] 천연 식물성 살충제 종류 및 제조법

[PLC] 릴레이 자기유지 (Realy Latch or Sealing)