백테스팅 구축 - (1) 일자 변수 처리 및 차트 데이터 조회
이전 포스팅에서는 백테스팅 전략에 대해 간단하게 서술했었고, 이번 포스팅에서는 백테스팅 전략에 대해 제작하고자 할 예정이다. 일단 백테스팅의 경우에는 크게 두 가지 방법이 있다.
- 종목코드를 입력하면 그 종목에 대해서만 거래 전략 테스트
- 일자를 입력하면 하루 하루 종목을 선정한 후에 거래 전략 테스트
이 중 후자의 방법이 보다 실질적인 거래와 가장 유사한 형태의 백테스팅 전략이라고 볼 수 있기 때문에 여기서는 후자의 방법대로 백테스팅을 하는 방법에 대해 다루어볼 예정이다.
일자 입력과 일자의 변수 처리
일단 기본적으로 일자를 기반으로 백테스팅을 구축하기 위해서는 시작 일자와 종료 일자를 입력하고 그를 하나의 변수로서 받아와야 한다. 이를 변수로 받아오기 위해서는 class를 생성한 후에, 그 아래에 def __init__(self, A, B, C, D)와 같은 방식으로 제작함으로써 변수를 받아올 수 있다. 그리고 해당 class는 if __name__ == "__main__": 문을 통해서 해당 파일이 실행될 경우 해당 클래스로 변수값을 전달하도록 해주면 된다.
class algorithm1():
def __init__(self, start_date, end_date, all_range):
print("시작일자:", start_date)
print("종료일자:", end_date)
print("전체범위:", all_range)
if __name__ == "__main__":
start_date = '20200101'
end_date = '20210101'
all_range = '20150101'
algorithm1(start_date, end_date, all_range)
시작일자: 20200101
종료일자: 20210101
전체범위: 20150101
물론 위의 방법 외에도 datetime의 timedelta 함수를 통해 특정 일자를 입력하면 그 일자를 바탕으로 일정 기간의 일자를 계산해서 그 범위 내에서만 백테스팅을 진행하도록 하는 방법도 있다.
데이터를 불러올 종목 코드 조회하기
기본적으로 데이터를 조회하기 위해서는 조회하고자 하는 종목 코드가 있어야 한다. 이 종목 코드는 Pandas 라이브러리 내에 있는 read_sql 함수를 이용해서 이전에 '차트 이어받기 구축'때 제작했던 데이터베이스를 불러오면, 현재 데이터가 저장되어 있는 종목 코드들을 불러올 수 있다. 그 때 제작했던 데이터베이스의 이름은 item_savepoint였다. 그렇다면 이제 그 데이터베이스를 불러옴으로써 저장되어 있는 종목코드를 조회하도록 하자. 아래의 함수를 class algorithm1 아래에 제작해주면 된다.
def load_code(self):
code_data = pd.read_sql("SELECT code FROM item_savepoint", engine_item)
return code_data
이제 다시 def __init__ 함수로 돌아와서, 아래와 같이 제작한 후 결과물을 출력해보면 코드 리스트라 올바르게 불러와지는 것을 확인할 수 있다.
class algorithm1():
def __init__(self, start_date, end_date, all_range):
print("시작일자:", start_date)
print("종료일자:", end_date)
print("전체범위:", all_range)
code_list = self.load_code()
print(code_list)
def load_code(self):
code_data = pd.read_sql("SELECT code FROM item_savepoint", engine_item)
return code_data
시작일자: 20200101
종료일자: 20210101
전체범위: 20150101
code
0 000020
1 000040
2 000050
3 000060
4 000070
... ...
4536 900120
4537 900250
4538 900070
4539 900100
4540
[4541 rows x 1 columns]
일자를 바탕으로 저장된 데이터 불러오기
앞전의 게시글에서 read_sql 또는 SELECT * FROM ~~ 문을 이용해 MySQL에 저장되어 있는 데이터들을 불러오는 방법에 대해 자세하게 서술했으니, 여기서는 간단하게 코드만 알아보도록 하겠다. 일단 앞에서 저장되어 있는 코드 리스트들을 불러왔으니, 그 코드 리스트를 바탕으로 데이터를 불러오도록 하자. 아래와 같이 차트 데이터를 불러오는 코드를 다시 class algorithm1 아래에 제작해주도록 하자.
def load_chart(self, start_date, end_date, all_range, code):
chart_data = pd.read_sql("SELECT * FROM " + code, engine_all)
이제 위 코드의 변수들을 보면 start_date, end_date, all_range, code라는 네 가지 변수가 있는데, 우리는 read_sql을 통해 불러온 데이터를 대상으로 해서 all_range를 적용해서 우리가 사용하고자 하는 기간에 해당하는 데이터만 불러올 예정이다. 이 all_range 변수를 사용하는 이유는 바로 1985년에 상장한 종목이 있다면 현재 chart_data 변수 안에는 1985년부터의 데이터가 포함되어 있을 것이고, 이렇게 많은 데이터를 불러오게 되면 데이터 처리가 느려질 수 있을 뿐만 아니라 굳이 그 때부터 백테스팅을 진행할 실익이 없기 때문이기도 하다. 그렇다면 일단 all_range 변수를 통해서 사용할 데이터의 기간을 지정해주도록 하자.
데이터프레임 형태의 자료형에 있어서 특정 조건을 충족시키는 부분만을 표현하는 방법은 기본적으로 아래와 같은 형태이다.
- DataFrame[(DataFrame['columns'] > condition)]
- DataFrame[(DataFrame['columns'] > condition_one) & (DataFrame['columns'] > condition_two)]
여기서의 DataFrame이란 우리가 def load_chart에서 제작했던 변수로는 chart_data 변수에 해당한다. 우리는 기본적으로 all_range라는 기간 이후의 데이터를 사용할 것이기 때문에, 아래와 같이 제작하면 된다.
def load_chart(self, all_range, code):
cd = pd.read_sql("SELECT * FROM s" + code + " WHERE date >= " + all_range, engine_all)
return cd
그리고 class algorithm1 아래에서는 code_list['code']라는 변수를 대상으로 for문을 돌리고, 각각의 코드를 load_chart에 대한 인자로 전달해준 후에 그 결과값을 출력하도록 하면 된다.
class algorithm1():
def __init__(self, start_date, end_date, all_range):
print("시작일자:", start_date)
print("종료일자:", end_date)
print("전체범위:", all_range)
code_list = self.load_code()
for i in code_list['code']:
chart_data = self.load_chart(all_range, i)
print(chart_data)
date open high low close volume trade_volume
0 20210702 15900 15950 15600 15750 266741 4212
1 20210701 15700 15900 15450 15800 268235 4206
2 20210630 15650 15800 15450 15650 153804 2401
3 20210629 15800 16100 15600 15650 413276 6545
4 20210628 15600 15800 15400 15750 404835 6312
... ... ... ... ... ... ... ...
1595 20150108 5550 5600 5400 5500 65098 357
1596 20150107 5470 5580 5400 5540 42517 234
1597 20150106 5480 5570 5450 5470 49260 271
1598 20150105 5430 5590 5400 5500 47278 259
1599 20150102 5450 5570 5450 5530 48783 269
[1600 rows x 7 columns]
date open high low close volume trade_volume
0 20210702 15900 15950 15600 15750 266741 4212
1 20210701 15700 15900 15450 15800 268235 4206
2 20210630 15650 15800 15450 15650 153804 2401
3 20210629 15800 16100 15600 15650 413276 6545
4 20210628 15600 15800 15400 15750 404835 6312
... ... ... ... ... ... ... ...
3195 20150108 6414 6414 6139 6231 93880 586
3196 20150107 6414 6445 6261 6292 88689 560
3197 20150106 6353 6536 6323 6384 84301 538
3198 20150105 6414 6445 6231 6445 58367 370
3199 20150102 6261 6567 6200 6384 164256 1053
[3200 rows x 7 columns]
이처럼 2015년 1월 1일 이후의 데이터를 요청했기 때문에 포스팅 일자 기준 최신 일자인 2021년 7월 2일까지의 데이터만 불러오고 있음을 확인할 수 있다.
from sqlalchemy import create_engine
import pandas as pd
engine_all = create_engine('mysql+mysqldb://root:a9985623@127.0.0.1:3306/day_data', echo=False)
connection_all = engine_all.connect()
engine_item = create_engine('mysql+mysqldb://root:a9985623@127.0.0.1:3306/item_savepoint', echo=False)
connection_item = engine_all.connect()
class algorithm1():
def __init__(self, start_date, end_date, all_range):
print("시작일자:", start_date)
print("종료일자:", end_date)
print("전체범위:", all_range)
code_list = self.load_code()
for i in code_list['code']:
self.load_chart(all_range, i)
def load_code(self):
code_data = pd.read_sql("SELECT code FROM item_savepoint", engine_item)
return code_data
def load_chart(self, all_range, code):
cd = pd.read_sql("SELECT * FROM s" + code + " WHERE date > " + all_range, engine_all)
return cd
if __name__ == "__main__":
start_date = '20200101'
end_date = '20210101'
all_range = '20150101'
algorithm1(start_date, end_date, all_range)
다음 포스팅에서는 이 차트 데이터를 바탕으로 어떤 방식으로 우리의 거래 전략을 수립하는지에 대해 살펴보도록 하겠다.
'AUTO TRADE > Back test' 카테고리의 다른 글
백테스팅 구축 (4) - 일자별 차트 데이터 불러오기 (0) | 2021.07.04 |
---|---|
백테스팅 구축 (3) - 일자 계산하기 (0) | 2021.07.04 |
키움증권 Open API - 차트 데이터 함수 수정 (0) | 2021.07.04 |
백테스팅 구축 - (2) 차트 데이터 가공하기 (0) | 2021.07.03 |
백테스팅 전략 수립 시 주의사항 (0) | 2021.06.16 |
소중한 공감 감사합니다