< 2. 변동성 돌파 전략과 노이즈 상관 분석 - 노이즈 계산 >


1. 개요


해당 포스트를 읽기 전에 위 포스트를 읽길 추천한다.


이번 포스트에서는 2007년 1월 1일부터 2018년 1월 10일까지의 주식 일봉 데이터를 가지고 노이즈를 계산한 후 데이터 베이스에 저장한다. 일봉 데이터는 "kospi_market"과 "kosdaq_market" 테이블에 있다.(개요를 보면 알 수 있다.) DB에서 해당 테이블에 있는 모든 일봉 데이터를 가져온 후 노이즈 계산을 하고 노이즈 데이터를 저장할 테이블에 저장한다. 


노이즈 테이블에 저장할 테이블 이름은 "kospi_noise", "kosdaq_noise"라고 한다. 테이블 구조는 아래와 같다. 




코드를 살펴보자. 다음은 DB에 액세스하는 클래스 코드이다.

from sqlalchemy import create_engine
import pymysql
pymysql.install_as_MySQLdb()
import pandas as pd
import logging as log

class StockDB(object):
    # 싱글톤 패턴
    _instance = None

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = object.__new__(cls)
            return cls._instance
        return cls._instance


    def __init__(self, password):
        log.info("Connecting database.....")

        try:
            self.engine = create_engine("mysql+mysqldb://root:"+password+"@localhost/stock", encoding='utf-8')
            self.conn = pymysql.connect(host='localhost', user='root', password=password, db='stock', charset='utf8')
            self.cursor = self.conn.cursor()
        except Exception as e:
            log.warning("Connecting database Error : {}".format(repr(e)))

    def select_market_all_data(self, market):
        log.info("Selecting market all data....")

        try:
            data = pd.read_sql('select Date, Code, Open, High, Low, Close from '+market+'_market', self.conn, index_col='Date')
        except Exception as e:
            log.info("Selecting market all data Error : {}".format(repr(e)))

        return data

    def insert_noise_data(self,market, data):
        log.info("Inserting into data in {} noise".format(market))

        try:
            data.to_sql(name=market+"_noise", con=self.engine, if_exists='append')
            self.conn.commit()
        except Exception as e:
            log.info("Inserting into data in {} noise Error : {}".format(market, repr(e)))

메서드 하나씩 알아보자. "select_market_all_data"는 코스피/코스닥 시장에 있는 모든 종목의 2007년 이후부터 일자, 종목 코드, 시가, 고가, 저가, 종가 데이터를 불러온다. 함수 매개변수 market 값은 "kospi" 아니면 "kosdaq" 이 들어간다. "insert_noise_data()" 메서드는 계산한 일자별 모든 노이즈 값을 "kospi_noise" 또는 "kosdaq_noise" 테이블에 저장한다. 

다음은 실제 노이즈 값을 계산하는 코드이다. 
import StockDB as dB
import pandas as pd
import logging as log
import sys

log.basicConfig(stream=sys.stdout, level=log.DEBUG)


def cal_noise(data):
    log.info("Calculating noise")

    noise_data = pd.DataFrame()

    try:
        noise_data['Code'] = data['Code']
        noise_data['Noise'] = (1- abs(data['Open']-data['Close'])/(data['High']-data['Low']).replace(0,sys.maxsize)).astype(float)
        noise_data.set_index(data.index)
    except Exception as e:
        log.warning("Calculating noise Error {} : ".format(repr(e)))

    return noise_data



db = dB.StockDB("qhdks12#$")

data = db.select_market_all_data("kospi")
noise_data = cal_noise(data)
db.insert_noise_data("kospi",noise_data)


data = db.select_market_all_data("kosdaq")
noise_data = cal_noise(data)
db.insert_noise_data("kosdaq",noise_data)


noise 값 계산은 매우 간단하다. 전체적인 부분을 보면 db 객체를 초기화한 후 "db.select_market_all_data("kospi")"로 DB에 저장되어 있는 코스피 종목 모든 일자 데이터를 가져온다. "cal_noise()" 메서드는 인자로 받은 데이터를 토대로 노이즈 값을 계산하고 반환한다. 마지막으로 "insert_noise_data()" 메서드에 계산한 값을 전달해 실제 "kospi_noise" 테이블에 저장한다. 코스닥 종목에 대해서도 똑같이 한다.


"cal_noise" 메서드는 종목의 일봉 데이터를 토대로 노이즈를 계산한다. 노이즈 계산 공식은 아래와 같다.


Noise = 1 - | 종가 - 시가 | / ( 고가 - 저가 )


"cal_noise" 메서드는 위 공식을 그대로 코드로 표현했다. 다만 예외 사항이 한 가지 있다. ( 고가 - 저가 ) 가 0이 될 경우다. 이 경우가 의외로 많다. 거래가 몇 일간 정지됬거나 점 상한가 등의 경우가 이에 해당한다. ( 고가 - 저가 ) 가 0이 되면 0으로 나누려고 했기에 예외가 발생한다. 따라서 이를 처리해야 한다. ( 고가 - 저가 ) 가 0일 때는 0을 sys.maxsize로 int형 최댓값으로 바꿔 Noise를 1에 아주 가깝게 만든다. 그 이유는 점 상한가나 거래 정지가 안정성을 추구하는 거래라고 보지 않기 때문이다. 

나머지 코드는 쉽게 이해 가능할 거라 생각한다.


"cal_noise" 메서드 결과로 데이터 프레임이 반환된다. 인덱스 값은 Date가 되고 칼럼으로 Code와 Noise가 있다. 이를 그대로 insert_noise_data()에 전달하면 노이즈 값이 계산되 DB에 저장된다.     


이번 포스트에서는 변동성 돌파 전략과 노이즈 상관 분석을 위해서 노이즈 값을 계산해 DB에 저장했다. 다음 포스트에서는 5/10/20/40/60/120 평균 노이즈 값을 계산할 것이다.




참고로 필자는 컴퓨터 공학과를 재학 중인 대학생입니다. 따라서 코드가 완벽할 수 없습니다. 알고리즘이나 코드가 비효율적이거나 오류가 있다면 댓글 달아주세요..

+ Recent posts