MFI(Money Flow Index, 현금흐름지표)¶
- 볼린저 밴드를 이용하여 추세 추종 매매를 할 때 사용할 수 있는 지표. 주가와 거래량을 동시에 고려할 수 있어 주가만 고려하거나 거래량만 고려하는 지표들보다 많은 정보를 담고 있음
- 현금흐름(Money Flow) = 중심가격 x 거래량
- 중심가격(Typical Price) = $\frac{저가+고가+종가}{3}$
- MFI는 거래량 데이터에 RSI(Relative Strength Index, 상대강도지수)의 개념을 적용한 것으로 볼 수 있음. RSI가 n일 동안의 상승일의 상승폭과 하락일의 하락폭 합계를 이용하는 것처럼 MFI는 상승일 동안의 현금흐름의 합(긍정적 현금흐름)과 하락일 동안의 현금흐름의 합(부정적 현금흐름)을 이용
- 긍정적 현금흐름: 중심가격이 전일보다 상승한 날들의 현금흐름의 합
- 부정적 현금흐름: 중심가격이 전일보다 상승한 날들의 현금흐름의 합
In [1]:
from pykrx import stock
import pandas as pd
from datetime import datetime # 오늘날짜 가져올때 사용
import matplotlib.pyplot as plt
import matplotlib.colors as mcolors # 색상표
# 한글폰트 설정, 그래프 마이너스 표시 설정
import matplotlib
from matplotlib import font_manager, rc
import platform
if platform.system() == 'Windows':
# 윈도우인 경우
font_name = font_manager.FontProperties(fname="c:/Windows/Fonts/malgun.ttf").get_name()
rc('font', family=font_name)
else:
# Mac 인 경우
rc('font', family='AppleGothic')
matplotlib.rcParams['axes.unicode_minus'] = False
In [3]:
stock_list = pd.DataFrame({'종목코드':stock.get_market_ticker_list(market="ALL")})
stock_list['종목명'] = stock_list['종목코드'].map(lambda x: stock.get_market_ticker_name(x))
# 두산중공업의 2020년 이후 주가 데이터 가져오기
stock_nm = '한화솔루션'
ticker = stock_list.loc[stock_list['종목명']==stock_nm, '종목코드']
today = datetime.today().strftime("%Y%m%d")
df = stock.get_market_ohlcv_by_date(fromdate="20200101", todate=today, ticker=ticker)
df
Out[3]:
In [4]:
# 10일(거래일 기준으로 2주 동안) 기준의 현금흐름지표를 구하는 코드
df['TP'] = (df['고가']+df['저가']+df['종가'])/3
df['PMF'] = 0
df['NMF'] = 0
for i in range(len(df['종가'])-1):
# 당일의 중심가격이 전일의 중심가격보다 크면 긍정적 현금흐름
if df['TP'].values[i] < df['TP'].values[i+1]:
df['PMF'].values[i+1] = df['TP'].values[i+1]*df['거래량'].values[i+1]
df['NMF'].values[i+1] = 0
# 당일의 중심가격이 전일의 중심가격보다 작거나 같으면 부정적 현금흐름
else:
df['NMF'].values[i+1] = df['TP'].values[i+1]*df['거래량'].values[i+1]
df['PMF'].values[i+1] = 0
df['MFR'] = df['PMF'].rolling(window=10).sum()/df['NMF'].rolling(window=10).sum()
df['MFI10'] = 100 - 100/(1+df['MFR'])
In [5]:
df
Out[5]:
In [15]:
# 볼린저밴드를 그리기
df = df.assign(이동평균=df['종가'].rolling(window=20).mean(),
표준편차=df['종가'].rolling(window=20).std())
df = df.assign(상단밴드=df['이동평균'] + df['표준편차']*2,
하단밴드=df['이동평균'] - df['표준편차']*2)
df = df.assign(PB=(df['종가']-df['하단밴드']) / (df['상단밴드']-df['하단밴드']),
밴드폭=(df['상단밴드']-df['하단밴드'])/df['이동평균'])
df = df[19:]
In [20]:
tab_cols = mcolors.TABLEAU_COLORS
plt.figure(figsize=(10, 5))
plt.plot(df.index, df['종가'], color=tab_cols['tab:gray'], linewidth=1, label='종가')
plt.plot(df.index, df['상단밴드'], color=tab_cols['tab:red'], linestyle='dashed', linewidth=1, label='상단밴드')
plt.plot(df.index, df['이동평균'], color=tab_cols['tab:green'], linestyle='dashed', linewidth=1, label='20일 이동평균')
plt.plot(df.index, df['하단밴드'], color=tab_cols['tab:blue'], linestyle='dashed', linewidth=1, label='하단밴드')
plt.title(f'{stock_nm}({int(ticker.values)})의 볼린저 밴드(20일, 2 표준편차)')
for i in range(df.shape[0]):
if df['PB'].values[i] > 0.8 and df['MFI10'].values[i] > 80:
plt.plot(df.index.values[i], df['종가'].values[i], 'r^')
elif df['PB'].values[i] < 0.2 and df['MFI10'].values[i] < 20:
plt.plot(df.index.values[i], df['종가'].values[i], 'bv')
plt.legend(loc='best');
%b 값이 0.8보다 크고, MFI 값이 80보다 크면 매수, %b값이 0.2보다 작고, MFI 값이 20보다 작으면 매도하는 전략
빨간색 화살표가 매수지점을 표시한 것이고, 파란색 화살표가 매도지점을 표시한 것
2020년에는 추세추종 매매가 효과가 있었지만, 2021년에는 추세추종 매매를 했으면 큰 손해를 보았을 것임