5-2. [트레이딩 전략 구현] 심리투자 법칙 : 삼중창매매시스템

2021. 6. 19. 22:10Financial Analysis

삼중창 매매 시스템(Triple Screen Trading System)은 추세 추종과 역추세 매매법을 함께 사용하여

세 단계의 창을 참조하여 정확한 매수/매도 타이밍을 찾도록 구성되어 있다.

첫번째 창 - 시장 조류


삼중창 매매 시스템에서의 첫 번째 창에서는 추세지표를 통해 시장 조류를 분석한다.

삼중창 매매기법의 코드를 단계적으로 구현해보겠다.

import pandas as pd
import matplotlib.pyplot as plt
from mpl_finance import candlestick_ohlc
import matplotlib.dates as mdates
from Investar.MarketDB import MarketDB

class TripleScreen():

    def __init__(self, company, start_date):
        mk = MarketDB()
        self.df = mk.get_daily_price(company, start_date)
        self.company = company
        self.ohlc = pd.DataFrame()

TripeScreen 클래스에서는 <사명> 과 <시작일>을 인수로 전달받는다.

MarketDB 클래스를 통해 DB에서 해당 시작일부터의 데이터를 데이터프레임의 형태로 저장한다.

     def get_market_tide(self):
        df = self.df
        ema60 = df.close.ewm(span=60).mean()
        ema130 = df.close.ewm(span=130).mean()
        macd = ema60 - ema130
        signal = macd.ewm(span=45).mean()
        macdhist = macd - signal

        df = df.assign(ema130=ema130, ema60 = ema60, macd = macd,
                           signal = signal, macdhist=macdhist).dropna()
        df['number'] = df.index.map(mdates.date2num)
        ohlc = df[['number', 'open', 'high', 'low', 'close']]
        ohlc.index = pd.to_datetime(ohlc.index)
        self.ohlc = ohlc
        self.df = df
        return

시장 조류를 분석하는 코드이다.

먼저 클래스 멤버 변수인 df를 가져와서 복사한뒤, 판다스의 ewm 함수를 이용하여 종가의 12주(60일), 26주(130일)의

EMA를 구한다. 일간 차트 기준으로 매매를 하기 때문에 EMA를 구할 때 주간 단위를 이용한다.

MACD선과 시그널선도 구해준다. 앞에서 구한 값을 데이터프레임의 컬럼에 추가한다.

만들어진 ohlc와 df를 각각 대응하는 멤버 변수에 저장해준다.

    def show_candle_chart(self,subplot):
        df = self.df
        plt.title('Candle & MACD Chart')
        plt.grid(linestyle = "dotted")
        candlestick_ohlc(subplot, self.ohlc.values, width=.6, colorup='red', colordown='blue')
        subplot.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))
        plt.plot(df.number, df['ema130'], color='c', label = 'EMA130')
        plt.legend(loc='best')

    def show_macd_chart(self, subplot):
        df = self.df
        subplot.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))
        plt.bar(df.number, df['macdhist'], color='m', label='MACD-hist')
        plt.plot(df.number, df['macd'], color='b', label='MACD')
        plt.plot(df.number, df['signal'], 'g--', label='MACD-signal')
        plt.legend(loc='best')

각각 ohlc 캔들차트와 EMA선을 그리는 함수, 그리고 macd히스토그램과 MACD선, 시그널선을 그리는 함수이다.

### main함수 
	tw = TripleScreen('대한항공', '2019-03-06') 
	tw.get_market_tide() 
	p1 = plt.subplot(2,1,1) 
	tw.show_candle_chart(p1) 
	p2 = plt.subplot(2,1,2) 
	tw.show_macd_chart(p2) plt.show()

다음의 결과가 출력된다.

 

두번째 창 - 시장파도


삼중창 매매 기법의 두번째 창은 오실레이터를 이용하여 시장 파도를 분석하는 것이다.

스토캐스틱 30 이하에서 매수하고, 70 이상에서 매도하는 조건으로 코드를 구현해보자.

    def get_market_wave(self):
        df = self.df
        ndays_high = df.high.rolling(window=14, min_periods=1).max()
        ndays_low = df.low.rolling(window=14, min_periods=1).min()
        fast_k = (df.close - ndays_low) / (ndays_high - ndays_low) * 100
        slow_d = fast_k.rolling(window=3).mean()
        df = df.assign(fast_k=fast_k, slow_d=slow_d).dropna()
        self.df = df
        return

14일 간의 최고가와 최저가를 각각 구하고, 빠른 %K와 이의 3일 동안의 평균인 느린 %D를 구한 뒤

데이터프레임에 추가해준다.

    def show_stochastic_chart(self, subplot):
        df = self.df
        subplot.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m'))
        plt.plot(df.number, df['fast_k'], color ='c', label='%K')
        plt.plot(df.number, df['slow_d'], color = 'k', label='%D')
        plt.yticks([0, 20, 80, 100])
        plt.legend(loc='best')
### main함수 
	tw = TripleScreen('대한항공', '2019-03-06') 
	tw.get_market_tide() p1 = plt.subplot(3,1,1) 
	tw.show_candle_chart(p1)
	p2 = plt.subplot(3,1,2) 
	tw.show_macd_chart(p2) 
	tw.get_market_wave() 
	p3 = plt.subplot(3,1,3) 
	tw.show_stochastic_chart(p3) 
	plt.show()

한 가지 지표로만 매매 기준을 삼지 말고 지수 이동 평균, MACD 지표, 스토캐스틱과 같이

서로 상충하는 지표들 간의 비교를 통해 더 정확한 매매 시그널을 캐치할 수 있다.

가상 매매 구현


위 지표들을 토대로 가상으로 매매하는 코드를 구현해보자.

    def sim_trade(self):
        account = 1000000
        stocks = 0
        profit = 0

        df = self.df
        for i in range(len(df.close)):
            if df.ema130.values[i-1] < df.ema130.values[i] and \
                df.slow_d.values[i-1] >= 20 and df.slow_d.values[i] < 20:
                account -= df.close.values[i]
                stocks += 1
                print(f"[{df.index.values[i]}] 매수 체결 - 매수가 : {df.close.values[i]} | "
                      f"체결 수량 : 1 | 현재 총 {stocks} 주")
            elif df.ema130.values[i-1] > df.ema130.values[i] and \
                df.slow_d.values[i-1] <= 80 and df.slow_d.values[i] > 80:
                if stocks == 0:
                    continue
                print(f"[{df.index.values[i]}] 매도 체결 - 매도가 : {df.close.values[i]} |"
                      f"체결 수량 : {stocks} | 현재 총 0 주")
                account += stocks * df.close.values[i]
                stocks = 0

        profit = account + df.close.values[len(df.close)-1] * stocks - 1000000
        print(f"삼중창 매매법 총 수익 : {profit} (원)")

26주 EMA가 상승하면서 %D선이 20 이상을 돌파 하며 추락하면 매수 시그널로,

26주 EMA가 하락하면서 %D선이 80 이하로 돌파 상승하면 매도 시그널로 인식한다.

매수 시그널에서는 한 주씩 적립 매입하고, 매도 시그널이 나오면 전량 매도를, 마지막으로 총 수익은

현재 매입한 주식의 총 가치 + 실현손익으로 계산하였다.

>>> tw.sim_trade()
[2019-10-04] 매수 체결 - 매수가 : 247000 | 체결 수량 : 1 | 현재 총 1 주 
[2019-12-26] 매수 체결 - 매수가 : 277500 | 체결 수량 : 1 | 현재 총 2 주 
[2020-01-29] 매수 체결 - 매수가 : 278500 | 체결 수량 : 1 | 현재 총 3 주 
[2020-04-20] 매도 체결 - 매도가 : 255000 | 체결 수량 : 3 | 현재 총 0 주 
[2020-12-23] 매수 체결 - 매수가 : 231500 | 체결 수량 : 1 | 현재 총 1 주 
[2021-01-29] 매수 체결 - 매수가 : 233500 | 체결 수량 : 1 | 현재 총 2 주 
[2021-03-23] 매수 체결 - 매수가 : 275000 | 체결 수량 : 1 | 현재 총 3 주 
[2021-04-23] 매수 체결 - 매수가 : 275000 | 체결 수량 : 1 | 현재 총 4 주 
[2021-05-25] 매수 체결 - 매수가 : 305500 | 체결 수량 : 1 | 현재 총 5 주 
[2021-06-11] 매수 체결 - 매수가 : 299500 | 체결 수량 : 1 | 현재 총 6 주 
삼중창 매매법 총 수익 : 19000 (원) Process finished with exit code 0 


실험 결과, 변동성이 크지 않은 상승장에서는

  1. 추세 추종 매매법
  2. 삼중창 매매법
  3. 반전 매매법

변동성이 큰 박스권 종목에서는

  1. 삼중창 매매법
  2. 추세 추종 매매법
  3. 반전 매매법

변동성이 큰 하락장에서는

  1. 반전 매매법
  2. 삼중창 매매법
  3. 추세 추종 매매법  

모든 종목에 대해서는 아니지만, 각 매매기법은 대략적으로 이러한 양상을 보였다.

 

이처럼 시장 움직임에 따라서 적합한 매매 기법이 존재하므로 

 

전략에 맞는 알고리즘을 선택하는 것이 중요하다.