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


1. 개요

2. 노이즈 계산

3. 평균 노이즈 계산

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

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

6. 변동성 돌파 전략과 분석 - (2)


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


이전 포스트에서 노이즈 특정 범위에 따른 변동성 돌파 매매를 백테스팅해봤다. 모든 경우의 수를 백테스팅해보지 않았지만 약 연 80%의 수익율이 나왔다. 모든 경우에 대한 백테스팅 결과는 다음에 차차 포스팅할 예정이다. 


이번 포스트는 이전 포스트에서 보았던 변동성 돌파 전략 매수/매도 알고리즘에 특정 조건을 추가할 것이다. 이전 포스트에서 사용했던 매수/매도 알고리즘은 아래와 같다.


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

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

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

매도 :  다음 날 시초가


위 알고리즘에 합집합 또는 교집합 개념을 도입할 것이다. 이 개념은 이동평균선의 정배열 개념에서 도출했다. 정배열은 단기 이동 평균선부터 중/장기 이동평균선 순으로 차례로 나열되어 있는 상태이다. 그렇다면 노이즈 값에도 이를 도입할 수 있지 않을까? 예로 사용자가 설정한 노이즈 값 범위가 40일 평균 노이즈와 60일 평균 노이즈 둘 다 속할 때 매수하는 것이다. 이는 40일 평균 노이즈와 60일 평균 노이즈 집합의 교집합과 같다. 또는 40일 평균 노이즈에 속하거나 60일 평균 노이즈에 속하면 매수 하는 것이다. 이는 합집합과 같다. 이 조건을 추가한다. 


해당 조건을 추가한 매수/매도 알고리즘이다.  


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

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

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

매도 :  다음 날 시초가


코드를 살펴보자. DB 관련 코드는 이전 포스트에서 봤던 StockDB.py를 사용하면 된다. 여기서 'Code' 데이터를 추가로 불러오는 이유를 설명한다. 만일 40일 평균 노이즈와 60일 평균 노이즈를 사용하고 이들의 교집합에 대해 매수/매도를 한다고 하자. 두 집합의 교집합을 구하기 위해서는 'Date'와 "Code" 값이 필요하다. 이 두 값이 각각의 노이즈를 구분해주기 때문이다. 그래서 두 집합에 동일하게 포함된 ('Date', 'Code') 값을 찾으면 교집합을 구할 수 있다. 합집합도 마찬가지다. 합집합을 구할 때는 두 집합을 더한 다음 그에 대한 교집합을 빼야한다. 따라서 'Code'가 추가로 필요하다.


나머지 DB 관련 코드는 이전 포스트에서 설명했으니 생략한다. 다음은 사용자가 입력한 평균 노이즈들 중 하나에 속할 때(합집합) 매수하여 누적 수익율을 계산하는 코드이다.

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_type1 = "120" noise_type2 = "50" dB = db.StockDB("qhdks12#$") data1 = dB.select_noise_profit_data(market, profit_type, noise_type1) data2 = dB.select_noise_profit_data(market, profit_type, noise_type2) data1['Flag'] = pd.cut(data1['Noise'], bins=[0.3,0.4], include_lowest=True) data1 = data1.dropna() data2['Flag'] = pd.cut(data2['Noise'], bins=[0.3,0.4], include_lowest=True) data2= data2.dropna() data = data1.append(data2) data_group_code=data.groupby([data['Date'],data['Code']]).mean().reset_index() profit_by_date = pd.DataFrame(data_group_code.groupby(data_group_code['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()

먼저 두 개의 평균 노이즈 데이터를 불러온다. 위 예에서는 120일 평균 노이즈와 50일 평균 노이즈를 사용한다. 각 평균 노이즈 데이터를 사용자가 입력한 범위로 자른다. 여기까지는 지난 포스트와 똑같다. 그리고 합집합을 구한다. 방법은 간단하다. "append()" 메서드를 이용해 두 개의 평균 노이즈 집합을 이어준다. 그리고 'Date와 'Code' 값으로 그룹핑해 평균을 구한다. 평균을 구하는 이유는 교집합을 없애기 위해서다. append()를 적용하면 두 개의 집합을 합치기 때문에 두 집합 사이에 중복된 데이터가 존재하게 된다. 이를 하나로 합치기 위해서 먼저 'Date'와 'Code'로 그룹핑한다. 그러면 각 집합의 중복된 데이터가 하나로 묶이게 되고 이에 mean(), 평균을 적용한다. 평균을 적용하면 중복된 데이터가 가지고 있는 값이 되고 중복은 사라진다. n이 m개 있을 경우 이에 대한 평균은 n이다. 이를 이용했다. 

이 과정을 거치면 최종적으로 두 평균 노이즈 집합의 합집합이 도출된다. 이에 대해 이전 포스트에서 설명한 것처럼 'Date'로 그룹핑해 누적 수익율을 구한다. 슬리피지 값은 0.4퍼로 했다.


아래 차트는 위 코드에 대한 최종 결과이다. 아래에서 상위 두 차트는 합집합이 아닌 개별적으로 적용한 차트이다. 하위 차트가 50일 평균 노이즈와 120일 평균 노이즈의 합집합을 적용했다.


합집합을 적용하니 수익율이 많이 증가한 걸 알 수 있다. 약 400배에서 650배로 증가했다. 



다음은 사용자가 입력한 평균 노이즈들 모두에 속할 때(교집합) 매수하여 누적 수익율을 계산하는 코드이다.

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_type1 = "120" noise_type2 = "50" dB = db.StockDB("qhdks12#$") data1 = dB.select_noise_profit_data(market, profit_type, noise_type1) data2 = dB.select_noise_profit_data(market, profit_type, noise_type2) data1['Flag'] = pd.cut(data1['Noise'], bins=[0.3,0.4], include_lowest=True) data1 = data1.dropna() data2['Flag'] = pd.cut(data2['Noise'], bins=[0.3,0.4], include_lowest=True) data2= data2.dropna() data = data1.merge(data2, how='inner', on=['Date','Code']) profit_by_date = pd.DataFrame(data.groupby(data['Date'])['Profit_x'].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()

중간 부분까지는 합집합 구하는 코드와 똑같다. 교집합 구하는 방식은 쉽다. 'Date'와 'Code'를 기준으로 내부조인을 하면 된다. 내부 조인은 조인하는 두 집합의 공통 부분만 합친다.


아래 차트는 위 코드에 대한 최종 결과이다. 아래에서 상위 두 차트는 교집합이 아닌 개별적으로 적용한 차트이다. 하위 차트가 50일 평균 노이즈와 120일 평균 노이즈의 교집합을 적용했다.

교집합인 만큼 수익율은 더 적어진다. 하지만 더 안정적이게 된다.

50일 평균 노이즈 집합과 120일 평균 노이즈 집합 사이의 시간 간격 때문에 별 다른 효과가 없어보이지만 다른 데이터를 적용하면 결과가 또 달라진다.


지금까지 노이즈를 토대로 다양한 방식을 사용해 관계를 파악하고 여러 개의 조건을 만들었다. 

다음 포스트에서는 지금까지 포스팅한 분석 로직을 토대로 노이즈와 변동성 돌파 전략의 관계에 따른 수익율을 분석해볼 예정이다. 

+ Recent posts