#!/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()