lyy9257.tistory.com
이번에는 지난 강의때 구축했던 주가 데이터베이스를 이용해
간단한 백테스트를 진행해 보도록 하겠습니다.
0. 백테스트의 과정
우리가 주식 거래를 하는 과정을 살펴보면
준비된 자금으로 주식 매수 → (특정 조건에 부합시) 매도 → 수익/손실 기록 의 과정으로 진행됨을 알 수 있습니다.
우리는 이번 강좌에서 파이썬으로 이 과정을 어떤식으로 구현할 수 있는지 간략하게 확인해 보겠습니다.
1. 필요 패키지 호출
import pandas as pd
import numpy as np
import sqlite3
import matplotlib.pyplot as plt
백테스트를 위해 필요한 패키지를 불러옵니다.
코드 설명
- numpy : pandas와 더불어 데이터 분석에 사용됩니다.
- matplotlib : 데이터를 시각화하기위해 사용되는 패키지입니다.
2. 필요한 데이터 호출
stock_code = 'A233740' ## 불러오고 싶은 종목의 종목코드
con = sqlite3.connect("price.db") ## 주가가 저장되어 있는 데이터베이스 연결
query = "SELECT * FROM %s" %stock_code ## 쿼리문 작성
price_df = pd.read_sql(query, con) ## 데이터베이스에서 불러옴
print(price_df) ## 확인
백테스트를 하기 위해 주가데이터를 불러옵니다.
여기서는 KODEX KOSDAQ150 레버리지 주가데이터를 이용하였습니다.
코드 설명
- stock_code : 주가데이터를 불러오기 위해 원하는 종목의 종목코드를 설정합니다.
이는 주가데이터 테이블의 이름을 종목코드로 설정하였기 때문입니다.
- con : 주가데이터가 저장되어있는 데이터베이스를 연결합니다.
- query : 주가데이터를 불러오기 위한 SQL 명령어를 설정합니다.
설명에 적혀져있는 쿼리문은 종목코드의 이름을 가지는 테이블의 모든 데이터를 선택하는 의미를 가지고 있습니다.
- pd.read_sql(qurey, con) : 쿼리문을 기반으로 연결한 데이터베이스에서 데이터를 가져와 DataFrame 형태로 변환합니다.
< 실행결과 >
date open high low close volume
0 20151217 10240 10405 9970 10330 946156
1 20151218 10230 10710 10165 10710 1841150
2 20151221 10695 10825 10670 10720 1274858
3 20151222 10740 10750 10450 10495 1374974
4 20151223 10535 10635 10415 10425 2532341
... ... ... ... ... ... ...
1055 20200408 6850 7065 6750 6840 54161712
1056 20200409 7005 7050 6855 6950 41679524
1057 20200410 6965 7000 6550 6860 49728027
1058 20200413 6800 6860 6575 6575 26054303
1059 20200414 6735 6990 6670 6920 37525422
[1060 rows x 6 columns]
다음과 같이 데이터프레임의 일부분이 출력됩니다.
3. 불러온 데이터의 시각화
plt.plot(price_df['close'])
plt.show()
불러온 주가데이터의 주가가 어떻게 흘러가는지 시각화하여 확인해봅시다.
코드 설명
plt.plot(데이터) : 입력된 데이터를 기반으로 그래프를 그립니다.
plt.show() : 그래프를 시현합니다.
< 실행결과 >
다음과 같이 불러온 종목의 종가기반의 실선 그래프가 그려지게 됩니다.
여기서는 KODEX KOSDAQ150 레버리지의 종가 그래프가 작도되었으며,
이 강의에서는 matplotlib 패키지가 그래프를 그리는데 사용된다는 것만 설명하고 넘어가겠습니다.
4. 백테스트
불러온 데이터를 이용해 백테스트를 진행해 보겠습니다.
여기서는 systrader79님이 소개했던 '래리 윌리엄스의 변동성 돌파' 전략을 테스트 해보겠습니다.
## 변동성 돌파
## 참고책 : 파이썬을 이용한 비트코인 자동매매(조대표 외 1명 지음)
## 1) Range값 및 매수 목표가 산출
price_df['range'] = (price_df['high'] - price_df['low']) * 0.5
price_df['target'] = price_df['open'] + price_df['range'].shift(1)
## 2) 매수 시뮬레이션
price_df['ror'] = np.where(price_df['high'] > price_df['target'], price_df['close'] / price_df['target'], 1)
## 3) 누적수익률 산출
price_df['total'] = price_df['ror'].cumprod()
## 4) 생성된 총 수익률 데이터 확인
print(price_df['total'])
순서는 range값 및 매수 목표가 산출 → 매수 시뮬레이션 → 누적수익률 산출 → 데이터 확인 순으로 진행이 됩니다.
코드 설명
- df.shift(숫자) : 입력된 값 만큼 데이터를 쉬프트 합니다.
코드에서는 1을 입력하였기 때문에 모든 데이터가 1칸씩 밀려나게 됩니다. (1번째 데이터는 2번째로, 2번째는 3번째로... 형식)
이는 D-1일 데이터를 D-day에 사용하기 위함입니다. (앞에 데이터가 한칸 밀려나면 현재로 오겠죠?)
- np.where(조건, Value1, Value2) : 조건식이 참이면 Value1, 거짓이면 Value2를 반환합니다.
코드에서는 목표가와 고가를 비교하여, 고가가 더 클 경우 종가/목표가를, 그렇지 않을 경우 1을 반환합니다.
df.cumprod() : 누적곱을 계산합니다.
Example) [2, 3, 4]를 cumprod하여 계산할 경우 누적곱인 [2, 6(=2*3), 24(=2*3*4)]가 반환됩니다.
< 실행결과 >
0 1.000000
1 1.025126
2 1.025126
3 1.025126
4 1.025126
...
1055 4.106948
1056 4.106948
1057 4.106948
1058 4.106948
1059 4.132328
Name: total, Length: 1060, dtype: float64
다음과 같은 데이터프레임의 'total' 칼럼의 데이터가 출력됩니다.
5. 성과 지표 계산
백테스트의 결과를 기반으로 CAGR와 MDD지표를 계산해봅시다.
### 계산용 지표 계산 (거래 년수, 총 수익)
trade_year = int(len(price_df.index)/252)
result = round((price_df['total'].iat[-1] / price_df['total'].iat[0] - 1) * 100, 3)
print(trade_year, result)
먼저 거래연수(거래일 / 1년의 영업일(약 252일)) 와 총 수익률(백분율, 소수 3자리까지)을 계산합니다.
< 실행결과 >
4 313.233
거래연수 4년, 누적 수익률 313.233%의 결과값이 출력됩니다.
이 값을 기반으로 CAGR와 MDD를 계산해봅시다.
## CAGR 계산
total_profit = (price_df['total'].iat[-1] / price_df['total'].iat[0])
cagr = round((total_profit ** (1/trade_year)-1) * 100, 2)
## MDD 계산
arr_v = np.array(price_df['total'])
peak_lower = np.argmax(np.maximum.accumulate(arr_v) - arr_v)
peak_upper = np.argmax(arr_v[:peak_lower])
mdd = round((arr_v[peak_lower] - arr_v[peak_upper]) / arr_v[peak_upper] * 100, 3)
print(cagr, mdd)
CAGR 계산식에 대한 설명은 생략하겠습니다.
MDD 계산의 과정은
최대 수익 산출 → 최대 수익 대비 하락폭 산출 → MDD가 발생한 때의 리스트 인덱스 추출
→ 그때의 값을 이용하여 MDD 계산 순으로 이루어 집니다.
코드 설명
np.argmax : 가장 큰 값의 인덱스를 반환합니다.
np.maximum : 입력된 값들을 비교하여 최대값을 반환합니다.
np.accumulate : 행의 갯수만큼 반복합니다. (모든 행에 적용)
< 실행결과 >
42.58 -22.355
CAGR와 MDD가 산출됩니다.
5. 수익률 그래프 시각화
주가 데이터를 시각화한 방법을 이용하여 수익률 데이터도 시각화 해보겠습니다.
plt.plot(price_df['total'])
plt.show()
< 실행결과 >
다음과 같은 수익률 그래프가 그려집니다.
이번 강의에서는 백테스트의 흐름을 개략적으로 알아보기 위해 간단히 백테스팅을 진행해 보았습니다.
수수료와 세금이 전혀 고려되지 않았기 때문에, 이 방법을 통해 얻은 백테스팅의 결과는 참고용으로만 쓸 수 있습니다.
다음 강의에서는 조금 더 정교하게 백테스트를 진행해 보도록 하겠습니다.
예제 파일은 아래에서 받아 보실 수 있습니다.
강의가 도움이 되셨다면, 좋아요와 구독을 눌러주세요.