AUTO TRADE/Back test

백테스팅 구축 - (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]

 

 


728x90

 

 

일자를 바탕으로 저장된 데이터 불러오기

앞전의 게시글에서 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)

 

다음 포스팅에서는 이 차트 데이터를 바탕으로 어떤 방식으로 우리의 거래 전략을 수립하는지에 대해 살펴보도록 하겠다.

 

 


728x90
반응형
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.