__Data Analysis/교육
[금융경제] 볼린저밴드(Bollinger Bands) 투자 기법
KL_
2021. 6. 8. 23:13
볼린저밴드 관련 지표
- 20일 이동평균선
- %b
- 밴드폭(bandwidth)
- MFI(+RSI)
[ 코드 구현 ]
라이브러리 불러오기¶
import pandas as pd
import numpy as np
import pandas_datareader as pdr
import FinanceDataReader as fdr
from matplotlib import dates as mdates
%matplotlib inline
from pykrx import stock
from xml.etree import ElementTree
import warnings
warnings.filterwarnings(action='ignore')
# pd.set_option('display.float_format', '${:.6g}'.format)
# pd.options.display.float_format = '{:.6f}'.format
import seaborn as sns
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'Malgun Gothic'
함수 정의 ¶
def myplot(df, nrows=5, kind='line', title='제목', labels=False):
if nrows > 0:
print(df.head(nrows))
else:
print(df.tail(nrows))
if labels:
cols = df.columns
for i, col in enumerate(cols):
df[col].plot(label=labels[i], kind=kind)
else :
df.plot(kind=kind)
plt.title(title)
plt.legend()
plt.show()
파라미터 정의 ¶
- 100개 데이터를 확인하고자 함
df = pd.DataFrame()
df = my_krx('20181203', '20210427', '005930')
df.head()
>out
success:1, failed:0
date | code | open | high | low | close | volume | |
---|---|---|---|---|---|---|---|
0 | 2018-12-03 | 005930 | 42750 | 43400 | 42400 | 43250 | 12110702 |
1 | 2018-12-04 | 005930 | 42650 | 42900 | 41900 | 42150 | 14347746 |
2 | 2018-12-05 | 005930 | 40900 | 41750 | 40850 | 41450 | 12631983 |
3 | 2018-12-06 | 005930 | 40600 | 41100 | 40450 | 40500 | 14251826 |
4 | 2018-12-07 | 005930 | 40900 | 41400 | 40850 | 40950 | 11433083 |
- 지표 : 20일 이동평균선
df['m20']= df['close'].rolling(20).mean()
df['m20_std']= df['close'].rolling(20).std()
df['upper']= df['m20'] + df['m20_std']*2
df['lower']= df['m20'] - df['m20_std']*2
- rolling 후 생겨난 null값 행 삭제
df.dropna(axis=0, inplace=True)
- 날짜데이터 datetime 타입으로 변형, index 설정
df['date']= pd.to_datetime(df['date'])
df.set_index('date',inplace=True)
df.head()
Out>
code | open | high | low | close | volume | m20 | m20_std | upper | lower | |
---|---|---|---|---|---|---|---|---|---|---|
date | ||||||||||
2019-01-02 | 005930 | 39400 | 39400 | 38550 | 38750 | 7847664 | 39772.5 | 1370.312584 | 42513.125169 | 37031.874831 |
2019-01-03 | 005930 | 38300 | 38550 | 37450 | 37600 | 12471493 | 39490.0 | 1185.615541 | 41861.231082 | 37118.768918 |
2019-01-04 | 005930 | 37450 | 37600 | 36850 | 37450 | 14108958 | 39255.0 | 1092.787358 | 41440.574717 | 37069.425283 |
2019-01-07 | 005930 | 38000 | 38900 | 37800 | 38750 | 12748997 | 39120.0 | 966.872331 | 41053.744663 | 37186.255337 |
2019-01-08 | 005930 | 38000 | 39200 | 37950 | 38100 | 12756554 | 39000.0 | 934.992260 | 40869.984520 | 37130.015480 |
- 볼린저밴드 차트 확인
plt.plot(df['close'].iloc[:SIZE_],label='close')
plt.plot(df['m20'].iloc[:SIZE_],label='m20')
plt.plot(df['upper'].iloc[:SIZE_],label='upper')
plt.plot(df['lower'].iloc[:SIZE_],label='lower')
plt.legend()
plt.fill_between(df.iloc[:SIZE_].index, df['upper'].iloc[:SIZE_], df['lower'].iloc[:SIZE_],alpha=0.2)
plt.show()
df['%b']= (df['close']-df['lower'])/(df['upper']-df['lower'])
plt.plot(df['close'].iloc[:SIZE_],label='close')
plt.plot(df['%b'].iloc[:SIZE_],label='%b')
plt.plot(df['m20'].iloc[:SIZE_],label='m20')
plt.plot(df['upper'].iloc[:SIZE_],label='upper')
plt.plot(df['lower'].iloc[:SIZE_],label='lower')
plt.legend()
plt.fill_between(df.iloc[:SIZE_].index, df['upper'].iloc[:SIZE_], df['lower'].iloc[:SIZE_],alpha=0.2)
plt.show()
- 볼린저밴드, 주가 데이터가 %b와 지수가 달라 차트에서 비교 불가
- 이중 차트를 그려 해결
=>>
plt.plot(df['close'].iloc[:SIZE_], label = 'close')
plt.plot(df['m20'].iloc[:SIZE_], label= 'm20')
plt.plot(df['upper'].iloc[:SIZE_], label='upper')
plt.plot(df['lower'].iloc[:SIZE_], label= 'lower')
plt.fill_between(df.iloc[:SIZE_].index, df['upper'].iloc[:SIZE_], df['lower'].iloc[:SIZE_], alpha =0.2)
plt.legend()
plt.twinx()
plt.plot(df['%b'].iloc[:SIZE_],label = '%b' , color = 'yellow')
plt.legend()
plt.show()
- %b와 종가는 유사하게 움직인다. 즉, %b는 주가의 흐름을 따른다
- 지표: 밴드폭(bandwidth)¶
- 스퀴즈 파악에 유용
- 주가가 극도로 떨어져 이제 곧 반등세(상승세)를 보일 것으로 예상되는 상황
- 밴드폭= (상한-하한)/중간 (option *100(비율))
df['bwith']= (df['upper']-df['lower'])/df['m20']
plt.figure(figsize=(10,5))
plt.plot(df['close'].iloc[:SIZE_], label = 'close')
plt.plot(df['m20'].iloc[:SIZE_], label= 'm20')
plt.fill_between(df.iloc[:SIZE_].index, df['upper'].iloc[:SIZE_], df['lower'].iloc[:SIZE_], alpha =0.2)
plt.legend()
plt.twinx()
plt.plot(df['%b'].iloc[:SIZE_],label = '%b' , color = 'purple')
plt.plot(df['bwith'].iloc[:SIZE_],label = 'bwith' , color = 'yellow')
plt.legend()
plt.show()
- 변동성이 크다 = 밴드폭이 크다
- 밴드폭 최상 = lower 최저
RSI(상대강도지수), MFI(현금흐름지표)¶
- 일중강도지수는 II
볼린저밴드 매매 전략¶
- 변동성 돌파
- 추세 추종 >> 추세가 상승세에 매수, 하락세에 매도
- 반전(반등세) >> 꺾이는 지점, 주가가 반등세인 구간을 찾아내 매수, 매도
현금흐름지수 계산
- 추세추종: 현금흐름지수(MFI)를 따른다
- MF => 평균가 (고가,저가,종가)/3 * 거래량
- MFI= 100 - (100/ (1+긍정현금흐름/부정현금흐름) )
- 긍정현금흐름: 중심가가 전날보다 상승한 날들의 일수 합
- 부정현금흐름: 중심가가 전날보다 하락한 날들의 일수 합
- MF => 평균가 (고가,저가,종가)/3 * 거래량
- MFI= 100 - (100/ (1+긍정현금흐름/부정현금흐름) )
- 긍정현금흐름: 중심가가 전날보다 상승한 날들의 일수 합
- 부정현금흐름: 중심가가 전날보다 하락한 날들의 일수 합
df.head()
Out>
code | open | high | low | close | volume | m20 | m20_std | upper | lower | %b | bwith | |
---|---|---|---|---|---|---|---|---|---|---|---|---|
date | ||||||||||||
2019-01-02 | 005930 | 39400 | 39400 | 38550 | 38750 | 7847664 | 39772.5 | 1370.312584 | 42513.125169 | 37031.874831 | 0.313455 | 0.137815 |
2019-01-03 | 005930 | 38300 | 38550 | 37450 | 37600 | 12471493 | 39490.0 | 1185.615541 | 41861.231082 | 37118.768918 | 0.101473 | 0.120093 |
2019-01-04 | 005930 | 37450 | 37600 | 36850 | 37450 | 14108958 | 39255.0 | 1092.787358 | 41440.574717 | 37069.425283 | 0.087065 | 0.111353 |
2019-01-07 | 005930 | 38000 | 38900 | 37800 | 38750 | 12748997 | 39120.0 | 966.872331 | 41053.744663 | 37186.255337 | 0.404331 | 0.098862 |
2019-01-08 | 005930 | 38000 | 39200 | 37950 | 38100 | 12756554 | 39000.0 | 934.992260 | 40869.984520 | 37130.015480 | 0.259356 | 0.095897 |
- 지표: MFI ¶
# MFI
df['medium'] =(df['high']+ df['low']+ df['close'])/3 # 평균가
df['m_shift']= df['medium'].shift(1) # 전일가
# 현금흐름 분류
df['positive'] = (df['medium'] > df['m_shift']).apply(lambda x:1 if x==True else 0)
df['negative'] = (df['medium'] <= df['m_shift']).apply(lambda x:1 if x==True else 0)
# MF = 전일보다 올랐을 때의 MF 합, 전일보다 내렸을 때의 MF 합
df['positive']*= df['medium']* df['volume'] # 긍정현금흐름
df['negative']*= df['medium']* df['volume'] # 부정현금흐름
df['MFI'] = 100 - (100 / (1 + (df['positive'].sum() / df['negative'].sum())) )
df['MFI10'] = 100 - (100 / (1 + (df['positive'].rolling(10).sum() / df['negative'].rolling(10).sum())) )
- MFI 결과값 확인
df.tail()
Out[20]:
code | open | high | low | close | volume | m20 | m20_std | upper | lower | %b | bwith | medium | m_shift | positive | negative | MFI | MFI10 | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
date | ||||||||||||||||||
2021-04-21 | 005930 | 83300 | 83500 | 82500 | 82600 | 21636079 | 83495.0 | 1430.669700 | 86356.339399 | 80633.660601 | 0.343605 | 0.068539 | 82866.666667 | 83666.666667 | 0.000000e+00 | 1.792910e+12 | 54.91464 | 46.708272 |
2021-04-22 | 005930 | 82900 | 83000 | 82400 | 82400 | 13934746 | 83555.0 | 1352.376077 | 86259.752153 | 80850.247847 | 0.286487 | 0.064742 | 82600.000000 | 82866.666667 | 0.000000e+00 | 1.151010e+12 | 54.91464 | 48.408114 |
2021-04-23 | 005930 | 81900 | 82900 | 81600 | 82800 | 17805080 | 83620.0 | 1277.579949 | 86175.159898 | 81064.840102 | 0.339540 | 0.061114 | 82433.333333 | 82600.000000 | 0.000000e+00 | 1.467732e+12 | 54.91464 | 48.628373 |
2021-04-26 | 005930 | 82900 | 83500 | 82600 | 83500 | 15489938 | 83715.0 | 1186.891118 | 86088.782236 | 81341.217764 | 0.454714 | 0.056711 | 83200.000000 | 82433.333333 | 1.288763e+12 | 0.000000e+00 | 54.91464 | 57.492564 |
2021-04-27 | 005930 | 83200 | 83300 | 82500 | 82900 | 12941533 | 83750.0 | 1149.599473 | 86049.198945 | 81450.801055 | 0.315153 | 0.054906 | 82900.000000 | 83200.000000 | 0.000000e+00 | 1.072853e+12 | 54.91464 | 48.695328 |
- 차트 확인
plt.subplots(figsize=(10, 6))
ax1,ax2= plt.gca(),plt.gca().twinx()
plt.subplot(2,1,1)
plt.plot(df['close'].iloc[:SIZE_], label = 'close')
plt.plot(df['m20'].iloc[:SIZE_], label= 'm20')
plt.fill_between(df.iloc[:SIZE_].index, df['upper'].iloc[:SIZE_], df['lower'].iloc[:SIZE_], alpha =0.2)
plt.twinx()
plt.plot(df['bwith'].iloc[:SIZE_],label = 'bwith' , color = 'yellow')
plt.legend()
plt.grid()
#======================================================
plt.subplots(figsize=(10, 6))
plt.subplot(2,1,2)
plt.plot(df['%b'].iloc[:SIZE_] , label = '%b' , color = 'purple')
plt.twinx()
plt.plot(df['MFI10'].iloc[:SIZE_], label = 'MFI10' , color = 'pink')
plt.legend()
plt.grid()
plt.show()

- 수정 필요사항: 반등지점 표시할 지표를 추가해야한다.
- 내용 추가중입니다. -
728x90