#!/usr/bin/env python # coding: utf-8 # # **트레이딩 전략과 구현 6장 | 볼린저 밴드 매매1 | 추세추종 기법** # **[파이썬 증권 데이터 분석 6장 | nbviewer](https://nbviewer.jupyter.org/github/INVESTAR/StockAnalysisInPython/tree/master/06_Trading_Strategy/)** # - **변동성 돌파, 추세추종, 반전** 3가지 매매기법 존재 # - **추세추종, 반전 매매기법** 2가지를 확인해 본다 # - **변동성 돌파 :** 주가가 상단 밴드를 돌파할 때 매수하고, 하단 밴드를 하양 이탈할 때 공매도 하는 기법 # | 범주 | 기술적 지표 | # |:-------:|:---------------------------:| # |추세 | **선형회귀, 이동평균선 (MACD)** | # |모멘텀 | **변화율, 스토캐스틱 (%k, %d)** | # |거래량 | **일중강도(II), 매집/분산(A/D), 현금흐름지표(MFI), 거래량가중(MACD)** | # |과매수/과매도 | **CCI, RSI** | # |심리 | **여론조사선, 풋/콜옵션 비율** | # # **1 추세추종 매매기법** # **볼린저 밴드 지표 (%b)** 이외에, **현금흐름지표(MFI : Money Flow Index), 일중강도(II)** 와 같은 거래량 지표를 함께 확인한다 # # ## **01 데이터 불러오기 + 볼린저 밴드 추가** # loading the Naver Stock Price Table # In[1]: DATA_FILENAME = 'data/stock-naver.pkl' import pandas as pd import FinanceDataReader as fdr try: data_raw = pd.read_pickle(DATA_FILENAME) except FileNotFoundError: data_raw = fdr.DataReader("035420", "2019-01-01") data_raw.columns = [_.lower() for _ in data_raw.columns] data_raw.to_pickle(DATA_FILENAME) data_df = data_raw.copy() data_df.tail(3) # In[2]: # 볼린저 밴드 데이터 추가 data_df['MA20'] = data_df['close'].rolling(window=20).mean() data_df['stddev'] = data_df['close'].rolling(window=20).std() data_df['upper'] = data_df['MA20'] + (data_df['stddev'] * 2) data_df['lower'] = data_df['MA20'] - (data_df['stddev'] * 2) data_df['PB'] = (data_df['close'] - data_df['lower']) / (data_df['upper'] - data_df['lower']) data_df.tail(3) # ## **02 현금흐름지표 (MFI : Money Flow Index | $ 중심가격 \times 거래량 $ )** # - **중심 가격 (Typical Price)** 은 **일정기간의 고가, 저가, 종가** 의 3평균 # - **트레이딩이 집중적 발생하는 주가지점** 을 확인하는 지표로 활용 # # $$ MFI = 100 - (100 \div (1+{(긍정적 현금 흐름) \over (부정적 현금 흐름)})) $$ # # - 긍정적 현금 흐름 PMF (Positive Money Flow) : **중심 가격 (Typical Price)** 이 **전일보다 상승** 한 기간의 **현금흐름 합** # - 부정적 현금 흐름 NMF (Nagative Money Flow) : **중심 가격 (Typical Price)** 이 **전일보다 하락** 한 기간의 **현금흐름 합** # In[3]: # 중심가격 (Typical Price) 의 계산 : (일정기간 고가/ 저가/ 종가) 의 3평균 data_df['TP'] = (data_df['high'] + data_df['low'] + data_df['close']) / 3 # PMF (Positive Money Flow) data_df['PMF'], data_df['NMF'] = 0, 0 # 현금흐름값 : (i+1 일차 중심가격) X (i+1 일차 거래량) for i in range(len(data_df.close)-1): # 익일 중심가격이 높아진 경우 (중심가격 X 거래량) : PMF 현금흐름값 저장, NMF 는 0 저장 if data_df.TP.values[i] < data_df.TP.values[i+1]: data_df.PMF.values[i+1] = data_df.TP.values[i+1] * data_df.volume.values[i+1] data_df.NMF.values[i+1] = 0 # 익일 중심가격이 높아진 경우 : PMF 0 저장, NMF 는 현금흐름값 저장 else: data_df.NMF.values[i+1] = data_df.TP.values[i+1] * data_df.volume.values[i+1] data_df.PMF.values[i+1] = 0 # In[4]: # 현금흐름비율 (MFR : Money Flow raito) # : 10일 간의 긍정적 현금흐름의 합을 10일간 부정적 현금흐름의 합으로 나는 결과 data_df['MFR'] = (data_df.PMF.rolling(window=10).sum() / data_df.NMF.rolling(window=10).sum()) # 10일 간의 현금흐름지표 계산결과 저장 data_df['MFI10'] = 100 - 100 / (1 + data_df['MFR']) data_df = data_df[19:] data_df.tail(3) # ## **03 Visualization** # In[5]: get_ipython().run_line_magic('matplotlib', 'inline') get_ipython().run_line_magic('config', "InlineBackend.figure_format = 'retina'") # Loading ... Visualization Modules import matplotlib.pyplot as plt import warnings plt.style.use('seaborn') warnings.simplefilter(action='ignore', category=FutureWarning) from matplotlib.font_manager import fontManager as fm # 한글폰트 확인 및 추가 font_list_check = ['D2Coding', 'NanumGothicCoding', 'NanumGothic'] for _ in font_list_check: font_counts = [f for f in font_list_check if _ in [_.name for _ in fm.ttflist]] if len(font_counts) > 1: print(f"found : {_}"); plt.rc('font', family=_); break # In[6]: plt.rcParams['figure.dpi'] = 300 plt.rcParams['figure.figsize'] = (20.0, 8.0) # plt.figure(figsize=(15, 8)) plt.subplot(2,1,1, ylabel='BBand(20 day, 2 std)') plt.plot(data_df.index, data_df['close'], label='Close', color='purple') plt.plot(data_df.index, data_df['upper'], '--', label ='Upper band', color='orange') plt.plot(data_df.index, data_df['MA20'], 'k--', label='Moving average 20') plt.plot(data_df.index, data_df['lower'], 'c--', label ='Lower band') plt.fill_between(data_df.index, data_df['upper'], data_df['lower'], color='0.9') plt.subplot(2,1,2) plt.plot(data_df.index, data_df['PB'] * 100, label='%B x 100', color='orange') plt.plot(data_df.index, data_df['MFI10'], 'g--', label='MFI(10 day)') plt.axhline(y=(1*100), color ='black', linewidth=.5, linestyle="--") # 볼린저 밴드 상단 plt.axhline(y=(.5*100), color ='red', linewidth=1.5, linestyle="--") # 볼린저 밴드 중심 plt.axhline(y=(0*100), color ='black', linewidth=.5, linestyle="--") # 볼린저 밴드 하단 plt.yticks([-20, 0, 20, 40, 60, 80, 100, 120]) plt.grid(True); plt.legend(loc='best'); plt.show(); # ## **03 볼린저 밴드 추세추종을 활용한 매매시점** # - 매수 : %b > **0.8**, MFI > **80** (상단밴드 접근, 지표 강세일 떄) # - 매도 : %b < **0.2**, MFI < **20** (하단밴드 접근, 지표 약세 확증시) # In[7]: get_ipython().run_line_magic('matplotlib', 'inline') get_ipython().run_line_magic('config', "InlineBackend.figure_format = 'retina'") # Loading ... Visualization Modules import matplotlib.pyplot as plt import warnings plt.style.use('seaborn') warnings.simplefilter(action='ignore', category=FutureWarning) from matplotlib.font_manager import fontManager as fm # 한글폰트 확인 및 추가 font_list_check = ['D2Coding', 'NanumGothicCoding', 'NanumGothic'] for _ in font_list_check: font_counts = [f for f in font_list_check if _ in [_.name for _ in fm.ttflist]] if len(font_counts) > 1: print(f"found : {_}"); plt.rc('font', family=_); break # In[8]: plt.rcParams['figure.dpi'] = 300 plt.rcParams['figure.figsize'] = (20.0, 6.0) # plt.figure(figsize=(15, 8)) plt.subplot(2, 1, 1, title='NAVER Bollinger Band(20 day, 2 std) - Trend Following') plt.plot(data_df.index, data_df['close'], label='Close', color='purple') plt.plot(data_df.index, data_df['upper'], '--', label ='Upper band', color='orange') plt.plot(data_df.index, data_df['MA20'], 'k--', label='Moving average 20') plt.plot(data_df.index, data_df['lower'], 'c--', label ='Lower band') plt.fill_between(data_df.index, data_df['upper'], data_df['lower'], color='0.9') for i in range(len(data_df.close)): if data_df.PB.values[i] > 0.8 and data_df.MFI10.values[i] > 80: plt.plot(data_df.index.values[i], data_df.close.values[i], 'r^') elif data_df.PB.values[i] < 0.2 and data_df.MFI10.values[i] < 20: plt.plot(data_df.index.values[i], data_df.close.values[i], 'bv') plt.legend(loc='best') plt.subplot(2, 1, 2) plt.plot(data_df.index, data_df['PB'] * 100, label='%B x 100', color='orange') plt.plot(data_df.index, data_df['MFI10'], 'g--', label='MFI(10 day)') plt.axhline(y=(1*100), color ='black', linewidth=.5, linestyle="--") # 볼린저 밴드 상단 plt.axhline(y=(.5*100), color ='red', linewidth=1.5, linestyle="--") # 볼린저 밴드 중심 plt.axhline(y=(0*100), color ='black', linewidth=.5, linestyle="--") # 볼린저 밴드 하단 plt.yticks([-20, 0, 20, 40, 60, 80, 100, 120]) for i in range(len(data_df.close)): if data_df.PB.values[i] > 0.8 and data_df.MFI10.values[i] > 80: # 매수시점 plt.plot(data_df.index.values[i], 0, 'r^') elif data_df.PB.values[i] < 0.2 and data_df.MFI10.values[i] < 20: # 매도시점 plt.plot(data_df.index.values[i], 0, 'bv') plt.grid(True); plt.legend(loc='best'); plt.show()