반응형
앞선 글에서 간단한 전략(볼린저 밴드 하단 + RSI < 30 진입, 중심선 청산)을 적용해
과거 데이터를 기반으로 수익률과 승률 등을 확인해봤다.
이번 글에서는 그 결과를 그래프로 시각화해보자.
숫자로 보는 수익률도 중요하지만, 시각화된 수익곡선은 전략의 성향을 훨씬 직관적으로 보여준다.
1. 백테스트 전략 코드 (요약 포함)
먼저 [6편]에서 만들었던 전략 백테스트 코드를 그대로 쓰되,
수익률 기록뿐만 아니라 각 트레이드의 순서에 따라 누적 수익률을 계산하도록 정리해보자.
import ccxt
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# 데이터 수집
binance = ccxt.binance({'enableRateLimit': True})
symbol = 'BTC/USDT'
ohlcv = binance.fetch_ohlcv(symbol, timeframe='5m', limit=5000)
df = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
# RSI 계산
def calculate_rsi(series, period=14):
delta = series.diff()
gain = delta.where(delta > 0, 0)
loss = -delta.where(delta < 0, 0)
avg_gain = gain.rolling(window=period).mean()
avg_loss = loss.rolling(window=period).mean()
rs = avg_gain / avg_loss
return 100 - (100 / (1 + rs))
df['rsi14'] = calculate_rsi(df['close'])
# 볼린저 밴드
period = 20
df['ma20'] = df['close'].rolling(window=period).mean()
std = df['close'].rolling(window=period).std()
df['bb_upper'] = df['ma20'] + 2 * std
df['bb_lower'] = df['ma20'] - 2 * std
# 전략 백테스트
position = None
entry_price = 0
returns = []
entry_times = []
for i in range(1, len(df)):
row = df.iloc[i]
prev = df.iloc[i - 1]
# 진입 조건
if position is None:
if row['close'] < row['bb_lower'] and row['rsi14'] < 30:
position = 'long'
entry_price = row['close']
entry_times.append(row['timestamp'])
# 청산 조건
elif position == 'long':
if row['close'] > row['ma20']:
exit_price = row['close']
ret = (exit_price - entry_price) / entry_price
returns.append(ret)
position = None
2. 수익곡선 계산
returns 리스트를 누적해서 수익곡선을 만들자.
각 수익률은 개별 트레이드의 수익이고, 이를 누적해서 곡선을 만들면 된다.
# 누적 수익률 시리즈 생성
cumulative_returns = pd.Series([1 + r for r in returns]).cumprod() - 1
3. 수익곡선 시각화
plt.figure(figsize=(10, 5))
plt.plot(cumulative_returns, marker='o')
plt.title('백테스트 누적 수익률 곡선')
plt.xlabel('트레이드 순번')
plt.ylabel('누적 수익률')
plt.grid(True)
plt.tight_layout()
plt.show()
이렇게 하면 전략이 수익을 얼마나 쌓았는지 한눈에 확인할 수 있다.
4. 최대 낙폭(Drawdown) 시각화
낙폭은 고점 대비 얼마나 손실이 컸는지를 보여주는 지표다.
수익률만 보면 좋아 보여도, 큰 낙폭이 있으면 위험한 전략일 수 있다.
equity_curve = pd.Series([1 + r for r in returns]).cumprod()
running_max = equity_curve.cummax()
drawdown = (equity_curve - running_max) / running_max
plt.figure(figsize=(10, 4))
plt.plot(drawdown, color='red')
plt.title('최대 낙폭 (Drawdown)')
plt.xlabel('트레이드 순번')
plt.ylabel('낙폭 비율')
plt.grid(True)
plt.tight_layout()
plt.show()
5. 수익률 요약 지표 출력
if returns:
total_return = cumulative_returns.iloc[-1]
win_rate = sum(1 for r in returns if r > 0) / len(returns)
avg_return = np.mean(returns)
print(f"총 거래 횟수: {len(returns)}")
print(f"승률: {win_rate * 100:.2f}%")
print(f"평균 수익률: {avg_return * 100:.2f}%")
print(f"누적 수익률: {total_return * 100:.2f}%")
else:
print("조건에 맞는 거래가 발생하지 않았습니다.")
6. 출력 결과
총 거래 횟수: 7
승률: 85.71%
평균 수익률: 0.17%
누적 수익률: 1.22%
마무리하며
이번 글에서는 앞서 구현한 전략의 결과를 수익곡선과 낙폭 그래프로 시각화해보았다.
단순한 숫자보다는 이렇게 흐름을 그래프로 보는 것이 훨씬 전략의 안정성과 특징을 잘 보여준다.
이제 이 전략이 꾸준한 수익을 내는지, 손실이 얼마나 큰지를 눈으로 직접 확인할 수 있게 되었다.
사실 전략이라기엔 너무 초라한 내용이지만 어쨌거나 틀을 잡았으니 이제 전략을 조금 구체화 하면 될 것 같다.
반응형
'코인' 카테고리의 다른 글
[자동매매로봇 만들기] [8편] 전략 고도화 – 백테스트 구조화 & 볼린저 밴드 전략 모듈화 (0) | 2025.06.12 |
---|---|
[자동매매봇 만들기][6편] 백테스트로 전략 검증하기 – 과거 데이터로 수익률 확인하기 (0) | 2025.06.06 |
[자동매매봇 만들기][5편] 텔레그램 봇 연동 – 매매 시그널 알림 보내기 (0) | 2025.05.17 |
[자동매매봇 만들기][4편] 기술적 지표와 단순 매매 조건 구현하기 (0) | 2025.05.16 |
[자동매매봇 만들기][3편] 바이낸스에서 실시간 시세와 캔들 데이터 가져오기 (API 키 없이) (2) | 2025.05.14 |