[알고리즘 트레이딩] 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 등을 활용해 성능을 평가하는 방법도 적용했습니다. 이를 기반으로 다양한 트레이딩 전략을 테스트하고 개선해볼 수 있습니다.

댓글

이 블로그의 인기 게시물

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

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

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

전력(kW) 계산하기 (직류, 교류 단상, 교류 삼상)

커패시터에 저장된 에너지 계산

제너 다이오드에 저항을 연결하는 이유

[자동화] 안쓰는 안드로이드폰을 활용한 식물 성장 타임랩스 촬영

3선 결선식 센서의 타입 PNP, NPN

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

[스마트팜] 아쿠아포닉스에서 pH 제어를 자동화해보자! (Python 활용)