파이썬을 이용한 비트코인 자동매매 (개정판) (https://wikidocs.net/book/1665) 등을 참고하여 변동성 돌파 전략에 대한 백테스트 로직을 짜고 테스트 해보았다. 비트코인에 대하여 변동성 돌파 전략을 적용한 자료가 정말 많아, 시스템 트레이딩 입문자이자 파이썬 초보자인 입장에서 충분히 도전해볼 만하다고 생각하여 변동성 돌파 전략 백테스팅에 도전하였다.
* 주의: 파이썬 초보이기에 코드가 난잡할 수 있으며 틀릴 수도 있습니다!
1. 데이터 가져오기
이전의 포스팅에서 다룬 방법으로 저장한 데이터를 읽어와서 테스트를 진행할 것이다.
먼저 백테스트를 위한 기본 세팅값을 준다. symbol은 티커를, interval은 타임프레임을, year은 백테스트 데이터의 기간을 뜻한다. year의 경우 All 이면 2017~2022년까지의 모든 데이터를 의미하고, 2017, 2018 등 특정 연도를 입력하면 해당 연도의 1월 1일부터 12월 31일까지의 데이터를 갖고온다. (이 데이터는 이전 포스팅에서 말한 위치에 저장되어 있는 데이터다.)
# 백테스트 기본 셋팅
symbol = "BTCUSDT" # 다른 티커도 가능
interval = '1d' # 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, 1M
year = 'All' # 2017~2022 중 선택 가능.
# 데이터 읽어오기: 전체 데이터
df = pd.read_csv (f'C:.\\Data\\{symbol[:-4]}-USDT_Data\\{symbol[:-4]}-USDT_Data_{interval}\\{symbol[:-4].upper()}_USDT_{interval}_{year}.csv')
# 전체: _All
# 기간: 연도 불러오면 됨
df = pd.DataFrame(df)
df = df.dropna(how='any')
2. 로직 설정
변동성 돌파 전략의 로직은 비교적 간단하다. 실력이 있으신 여러 시스템 트레이더들이 이미 자세히 설명하시고 계시므로 여기서는 간단하게 설명하겠다. (자세한 원리 및 로직 설명: https://stock79.tistory.com/entry/%EC%8B%A4%EC%A0%84-%ED%88%AC%EC%9E%90-%EC%A0%84%EB%9E%B5-48-%EB%B3%80%EB%8F%99%EC%84%B1-%EB%8F%8C%ED%8C%8C-%EC%A0%84%EB%9E%B5%EC%9D%98-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-1)
1) 전일의 고저 변동폭 계산
2) 1)을 바탕으로 당일의 목표가 계산
3) 당일에 목표가를 상향돌파할 경우 진입
4) 익일 시가에 청산
이를 반영하여 다음과 같이 코드로 구현해보았다.
def VBS(df, k):
# 목표가 구하기
df['range'] = df['High'] - df['Low'] # 고저 변동폭
df['target'] = df['Open'] + df['range'].shift(1) * k
# 목표가 한칸 내려주고 (shift), 이후 k값을 곱한 목표가 계산
# 매수 시뮬레이션
df['ror'] = np.where(df['High'] > df['target'], df['Close'] / df['target'],
1) # high > target인 지점에서 close / target
# 최종 누적 산출
df['total'] = df['ror'].cumprod()
final_cum_ror = (df['total'].iloc[-1].astype(float)) * 100 -100
# 연간 수익률 (기간 수익률)
N = ((df.index[-1] - df.index[0])) / 365
CAGR = (final_cum_ror ** (1 / N))
# dd값 기록 및 mdd 계산
array_v = np.array(df['total'])
dd_list = -(np.maximum.accumulate(array_v) - array_v) / np.maximum.accumulate(array_v)
peak_lower = np.argmax(np.maximum.accumulate(array_v) - array_v)
peak_upper = np.argmax(array_v[:peak_lower])
mdd = round((array_v[peak_lower] - array_v[peak_upper]) / array_v[peak_upper] * 100, 3)
return final_cum_ror, CAGR, mdd, dd_list,df['total']
# 최종 수익률, 연간 수익률, 최대손실폭 (mdd), 손실 목록, 누적 이익 목록
df['range']: 변동폭
df['target']: 변동폭
df['ror']: 일일 수익률
df['total']: 누적 수익률
- 1. df ['range'] 계산
- 전일 고저 변동폭을 계산하여 df['range']에 저장한다.
- 2. df ['target'] 계산
- 1.을 통해 구한 df ['range'] 값을 shift(1)을 통해 한칸 내려주고, 여기에 가중치 k 값을 곱한다.
- 이 값을 당일 시가 df['Open']에 더하여 목표값을 산출하여, df['target']으로 저장한다.
- 3. 변동성 돌파전략이 실행된 날 및 및 일일 수익률 기록 (df ['ror'])
- 당일의 고가 df['High']가 df['target']값보다 클 경우, 이는 목표가를 상향돌파했다는 것이므로 이때는 df ['ror']에 df ['Close'] / df['Target']을 추가한다.
- 만약 df['High']가 df['target']보다 낮을 경우, 당일에 목표가를 돌파한 적이 없다는 것이므로 df['ror']에 1을 추가한다.
* np.where (조건, 조건이 True일때 값, 조건이 False일때 값)
- 4. 누적 수익률 (df ['total']) 기록 및 최종 누적 수익률 (final_cum_ror), 연간 수익률 (CAGR) 도출
- df['ror'] 값을 누적곱(cumprod 함수 활용) 하여 도출한다.
- 맨 마지막 값이 전략의 최종 누적 수익률 (final_cum_ror) 이므로 따로 뽑아낸다.
. 최종 누적 수익률을 통해 연간 누적수익률 (CAGR) 을 계산한다.
- 5. MDD 도출
- Drawdown (DD) 를 list에 저장하고, 여기서 제일 큰 값을 MDD로 산출한다.
- 1) 누적 수익률을 numpy의 array 형식 (array_v) 으로 저장한다.
- 2) array_v를 순차적으로 돌며, array_v[i]값이 아직까지 나온 값중 최대값이면 해당 값을 기록하고, array_v[i]가 그 이전에 나온 최대값보다 작으면 해당 값을 최대값으로 대체하는 array를 만든다.
* (np.maximum.accumulate(array_v))
- 3) 2)번에서 구한 array 에서 array_v를 빼고, 이를 array_v로 나눠준다. 이를 통해 손실율 리스트 (dd list) 를 구한다.
- 4) 손실율 list에서 절대값이 가장 큰 값이 MDD 이다.
- 6. Return 값
- 1) 최종 누적 수익률
- 2) 연간 수익률 (CAGR)
- 3) 최대손실폭 (MDD)
- 4) 손실율 목록 (dd_list)
- 5) 누적 이익 목록 (df['total']) 을 return 한다.
3. 결과 출력
밑의 코드를 통해 결과를 출력할 수 있으며, 그 결과는 다음과 같다.
print("최종 누적 수익률: ", final_result[0] ,"%") # 최종 누적 수익률 도출
print("MDD: ", final_result[2], "%") # mdd 도출
다음 포스팅에서는 변수를 최적화해보고, 시각화에 도전해보도록 하겠다.
### 전체 코드
import pandas as pd
import numpy as np
import random as rand
from bayes_opt import BayesianOptimization
import matplotlib.pyplot as plt
import seaborn as sns
################ 백테스트 ################
# 백테스트 기본 셋팅
symbol = "BTCUSDT" # 다른 티커도 가능
interval = '1d' # 1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, 1M
year = 'All' # 2017~2022 중 선택 가능.
# 데이터 읽어오기: 전체 데이터
df = pd.read_csv (f'C:.\\Data\\{symbol[:-4]}-USDT_Data\\{symbol[:-4]}-USDT_Data_{interval}\\{symbol[:-4].upper()}_USDT_{interval}_{year}.csv')
# 전체: _All
# 기간: 연도 불러오면 됨
df = pd.DataFrame(df)
df = df.dropna(how='any')
# 변동성 돌파 전략 위한 로직 설정
def VBS(df, k):
# 목표가 구하기
df['range'] = df['High'] - df['Low'] # 고저 변동폭
df['target'] = df['Open'] + df['range'].shift(1) * k
# 목표가 한칸 내려주고 (shift), 이후 k값을 곱한 목표가 계산
# 매수 시뮬레이션
df['ror'] = np.where(df['High'] > df['target'], df['Close'] / df['target'],
1) # high > target인 지점에서 close / target
# 최종 누적 산출
df['total'] = df['ror'].cumprod()
final_cum_ror = (df['total'].iloc[-1].astype(float)) * 100 -100
# 연간 수익률 (기간 수익률)
N = ((df.index[-1] - df.index[0])) / 365
CAGR = (final_cum_ror ** (1 / N))
# dd값 기록 및 mdd 계산
array_v = np.array(df['total'])
dd_list = -(np.maximum.accumulate(array_v) - array_v) / np.maximum.accumulate(array_v)
peak_lower = np.argmax(np.maximum.accumulate(array_v) - array_v)
peak_upper = np.argmax(array_v[:peak_lower])
mdd = round((array_v[peak_lower] - array_v[peak_upper]) / array_v[peak_upper] * 100, 3)
return final_cum_ror, CAGR, mdd, dd_list,df['total']
# 최종 수익률, 연간 수익률, 최대손실폭 (mdd), 손실 목록, 누적 이익 목록
# 값 추출
final_result = VBS(df, 0.5)
print("최종 누적 수익률: ", final_result[0] ,"%") # 최종 누적 수익률 도출
print("MDD: ", final_result[2], "%") # mdd 도출
'프로그래밍 공부 > 파이썬 구현' 카테고리의 다른 글
[변동성 돌파 전략 4] 변동성 돌파 전략 성과 시각화 (0) | 2022.01.24 |
---|---|
[변동성 돌파 전략 3] 변동성 돌파 전략 백테스트 k 최적화 (베이지안 최적화) (0) | 2022.01.24 |
[변동성 돌파 전략 2] 변동성 돌파 전략 백테스트 k 최적화 (그리드 서치) (0) | 2022.01.24 |
(따라해보기) Shooting Star 구현해보기 (0) | 2022.01.21 |
[데이터 수집] 바이낸스 과거 데이터 저장하기 (0) | 2022.01.15 |
댓글