< 6. 변동성 돌파 전략과 노이즈 분석 - (2) >


1. 개요

2. 노이즈 계산

3. 평균 노이즈 계산

4. 변동성 돌파 전략과 노이즈 상관 분석

5. 변동성 돌파 전략과 분석 - (1)


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


이전 포스트에서 노이즈 값의 특정 범위에 따라 변동성 돌파 매매가 수익이 있을 확률을 계산해 봤다. 그리고 뚜렷하진 않지만 약간의 경향성을 확인했다. 이번에는 이 경향성을 이용해 변동성 돌파 전략에 따라 매수/매도를 해 백테스팅할 것이다. 


백테스팅할 매수/매도 알고리즘은 아래와 같다.(빨간색으로 된 부분이 기존에서 추가됬다.)


매수 : ( 전일 고가 - 전일 저가 ) * Scope + 시초가 <= 현재가   [ Scope : 0.2 ~ 1.4 (0.1 간격) ]

* ( 전일 고가 - 전일 저가 )가 0 이상이어야 함.

* 당일 평균 노이즈 값이 사용자가 입력한 특정 노이즈 값 범위에 있어야 함.

매도 :  다음 날 시초가


당일 평균 노이즈 값은 이전 포스트에서 계산했던 수익이 날 확률이 높은 범위로 할 것이다. 참고로 슬리피지 값은 0.4%로 한다. 


코드를 살펴보자.

다음은 DB에 접근하는 코드이다. 지난 포스트에서 보았던 코드와 거의 똑같다. 추가 된 것은 'Noise', 'Profit' 외에 'Code'와 'Date'를 불러온다. 'Date'를 불러온 이유는 시간에 의한 누적 수익율을 구해야 하기 때문에 시간별로 그룹핑하기 위해서다. 'Code'는 지금 필요 없지만 다음에 소개할 다른 매수/매도 알고리즘에 사용될 예정이다.

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_noise_profit_data(self, market, profit_type, noise_type):
        log.info("Selecting market all data....")

        sql = "select pft.Date , pft.Code, pft.Profit, Nos.Noise from " \
              "(select Code, Date, Profit from "+market+"_profit_"+profit_type+") as pft " \
              "join (select * from "+market+"_noise_"+noise_type+") as Nos on pft.Code=Nos.Code and pft.Date=Nos.Date;"

        try:
            data = pd.read_sql(sql, self.conn)
        except Exception as e:
            log.info("Selecting market all data Error : {}".format(repr(e)))

        return data

다음은 시간에 따른 누적 수익율을 계산하고 차트로 보여주는 코드이다. "select_noise_profit_data()" 메서드로 일자, 일자에 해당하는 수익율과 노이즈 데이터를 불러온다. 데이터를 사용자가 입력한 특정 노이즈 범위에 따라 나눈다. "bins" 변수에 범위를 설정한다. "pd.cut" 메서드를 이용해 나눈다. 나누면 아래 코드에서 노이즈가 0.3 미만이고 0.4 이상인 데이터는 NA 값이 들어간다. 따라서 "dropna()"로 0.3에서 0.4 범위에 없는 데이터를 지운다. 결과적으로 노이즈가 0.3~0.4인 데이터만 추출된다.
추출된 데이터를 'Date'를 기준으로 그룹핑해 수익율의 평균값을 구한다. 그러면 특정 일에 매수한 종목의 평균 수익율이 계산된다. 이는 하루에 매수한 종목들을 동일한 비중으로 샀다는 것을 의미한다. 그리고 0.4% 슬리피지를 적용한 누적 수익율을 구하고 차트로 나타낸다.

import logging as log import pandas as pd import StockDB as db import sys from mpldatacursor import datacursor from matplotlib.dates import DateFormatter import matplotlib.pyplot as plt log.basicConfig(stream=sys.stdout, level=log.DEBUG) market = "kosdaq" profit_type = "6" noise_type = "50" bins = [0.3,0.4] dB = db.StockDB("qhdks12#$") data = dB.select_noise_profit_data(market, profit_type, noise_type) data['Flag'] = pd.cut(data['Noise'], bins=[0.3,0.4], include_lowest=True) data = data.dropna() profit_by_date = pd.DataFrame(data.groupby(data['Date'])['Profit'].mean()) cul_profit = (profit_by_date + 1 - 0.004).cumprod() axes = cul_profit.plot(grid=True) lines = axes.get_lines() fmt = DateFormatter('%Y-%m-%d') datacursor(lines, formatter=lambda **kwargs: 'Return : {y:.4f}'.format(**kwargs) + '\ndate: ' + fmt(kwargs.get('x'))) plt.show()


아래 차트는 위 코드에 대한 결과이다. 코스닥 종목에 50일 평균 노이즈를 적용했고 노이즈 범위는 0.3에서 0.4로 했다. 

그 결과 괜찮다. 등락폭이 크긴 하지만 거의 10년 사이에 400배가 된다. 약 연간 80 퍼센트의 수익율을 보인다. 실제 주식시장에 사용해도 될 것 같다. 


그렇다면 위 차트에 적용한 설정이 아닌 다른 값으로 하면 어떤 수익율을 보일까? 더 많은 수익율을 낼 수 있지 않을 까? 이에 대한 분석은 나중에 차차 설명하겠다. 


다음 포스트에서는 위에서 언급한 변동성 돌파 매매 전략 알고리즘에 조건을 추가해볼 예정이다. 해당 조건은 이동 평균선의 정배열 개념에서 떠올랐다. 이에 대한 자세한 내용은 다음 포스트에서 소개하겠다. 과연 이 조건을 추가했을 때 더 수익율이 날 지 궁금하다. 




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



+ Recent posts