파이썬 바이낸스 API로 비트코인 투자 백테스팅 : MFI 매매 전략
현금흐름지수(MFI)를 이용하여 비트코인 투자 연습도 하고 파이썬 판다스도 익혀보겠습니다. 지금까지 변동성 돌파전략, 이동평균선 매매 기법, MACD 매매 전략, 그리고 RSI 매매 전략까지 백테스팅 해 보았는데요. 이번 포스팅에서는 파이썬 바이낸스 API로 비트코인 캔들 데이터를 가져온 후, 파이썬 판다스로 MFI 매매 기법을 백 테스팅 해보겠습니다.
글의 순서
백테스팅 (back testing)
현금흐름지수(MFI, Money Flow Index)
MFI 매매 전략 : 골든크로스 vs. 데드크로스
MFI 매매 전략 백 테스팅 과정 : 바이낸스 비트코인 시계열 데이터
파이썬 코드 : 바이낸스 API, 판다스로 MFI 매매 전략 백 테스팅
백테스팅 (back testing)
백테스팅은 과거의 가격정보(시계열 데이터)로 지금 적용하고자 하는 매매 전략이 얼마나 효과적인지를 미리 테스트 해보는 과정을 의미합니다. 아래에 링크한 지난 포스팅에서 다양한 매매 기법을 적용했을 때 어떤 효과가 있을지 확인해 보았습니다. 변동성 돌파전략, 단순이동평균, 지수이동평균, MACD 매매 전략, RSI 매매전략을 적용했을 때와 이번 포스팅의 MFI 매매 전략을 비교해 보시기 바랍니다.
파바이낸스 비트코인 변동성 돌파전략 백 테스팅 결과,
파이썬 바이낸스 비트코인 투자 백테스팅 : 이동평균선 매매 기법,
파이썬 바이낸스 비트코인 투자 백테스팅 : 지수 이동평균선 매매 기법,
파이썬 바이낸스 API로 비트코인 투자 백테스팅 : MACD 매매 전략,
파이썬 바이낸스 API로 비트코인 투자 백테스팅 : RSI 매매 전략,
현금흐름지수(MFI, Money Flow Index)
MFI(Money Flow Index)는 거래량 데이터에 상대강도지수 개념을 도입한 지표라고 할 수 있습니다. 일정 기간 동안 주가가 전일에 비해 상승했을 때 현금 흐름의 합과 하락했을 때 현금 흐름의 합을 이용합니다. 구체적인 계산방법을 정리해보겠습니다.
우리가 정한 기간에서 가격이 상승한 날의 상승분을 Up, 가격이 하락한 날의 하락분을 Down이라고 설정합니다. 상승분 Up 값의 n일 동안의 평균을 AU, 하락분 Down 값의 n일 동안의 평균을 AD하고 하면, AU와 AD의 비율을 상대강도라고 정의합니다. 상대강도가 크다는 것은 상승폭이 크다는 것을 의미합니다.
MFI 매매 전략 : 골든크로스 vs. 데드크로스
MFI 값은 0~100 사이에 있습니다. MFI가 80 이상이면 아주 강력한 매수 신호를 나타내고, 20 이하이면 강력한 매도 신호를 나타냅니다. 80 이하였다가 80 위로 올라가는 순간과 20 이상이었다가 20 아래로 내려가는 시점을 포착하는 것이 중요합니다.
MFI 매매 전략 백 테스팅 과정 : 바이낸스 비트코인 시계열 데이터
지난 포스팅의 이동평균선, MACD 매매 전략, RSI 매매 전략과 비교하기 위하여 MFI를 사용한다는 것 외에 다른 것들은 모두 동일하게 유지하고 백테스팅합니다. 파이썬 바이낸스 API로 추출한 3개월(2022년 12월 ~ 2023년 2월) 동안의 비트코인 시계열 데이터로 수행한 백 테스팅 과정을 정리해 보겠습니다.
(1) 파이썬 바이낸스 API로 비트코인 시계열 데이터 가져오기
파이썬 바이낸스 API의 get_historical_klines() 함수로 비트코인 가격을 시계열 데이터로 가져옵니다.
(2) 현금흐름지수 MFI 구하기
step1) 기간 선정 : n일, 이 포스팅에서는 9일로 설정했습니다.
step2) 상승한 날들의 현금 흐름의 합 SMF_P 구하기 (SMF_P : Sum of Positive Money Flow)
step3) 하락한 날들의 현금 흐름의 합 SMF_N 구하기 (SMF_N : Sum of Negative Money Flow)
step4) 현금흐름비율 MFR = SMF_P/SMF_N 구하기
step5) MFI = 100 – (100 / (1+MFR))
(3) MFI 80, 20 교차지점 탐색
MFI가 80 이하였다가 80을 교차해서 올라갈때와, 20이상이었다가 20을 교차해서 내려갈 때를 찾아냅니다. 여기서는 교차가 발생한 날의 종료가로 매수 또는 매도했다고 가정하였습니다.
(4) 이익 계산 : 이익(profit) = 매도가 – 매수가
매도 가격에서 매수 가격을 빼면 전체 구간에서의 이익이 됩니다. 2022년 12월 부터 2023년 2월까지의 구간에서는 매수에 해당하는 MFI 교차가 1회, 매도에 해당하는 MFI 교차가 3회 발생했습니다.
아래 그림에서 손실과 수익 구간을 확인할 수 있는데요. 첫 번째 사고팔았던 구간에서 총 4446.93 USDT 이익을 얻었습니다.
▶첫 번째 사고, 팔았던 구간 : 4446.93 USDT 이익
※ 참고로, 이 포스팅에서는 거래 수수료를 0으로 가정하고 계산하였습니다.
파이썬 코드 : 바이낸스 API, 판다스로 MFI 매매 전략 백 테스팅
지금까지의 과정을 ‘판다스 MFI 매매 전략 백 테스팅’ 파이썬 코드에 나타내었습니다. 앞에서 설명한 MFI와 MFI 80과 20 교차 지점을 찾아내는 것이 코드의 핵심부분이라고 할 수 있습니다. 코드의 #07) 부분을 유심히 봐 주시기 바랍니다. 시계열 데이터와 매수, 매도 지점을 표시한 차트는 C:/_python/pandas/backtesting/ 라는 폴더에 MFI.png 라는 이름의 그림파일로 저장됩니다.
판다스 데이터프레임에서 유용하게 쓰이는 함수인 np.where(), rolling(window).mean(), rolling(window).sum(), diff() 함수, count() 함수의 활용법을 확인해 주시기 바랍니다. 또한, 종이 한 장에 그래프 두 개를 나란히 넣기 위해 fig, axs를 지정하는 부분과 x축의 날짜 범위를 맞추기 위해 numpy를 사용한 부분은 시계열 데이터 분석에서 자주 활용되는 중요한 부분입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
import os import time import pandas as pd import numpy as np from binance.client import Client import datetime from datetime import datetime, timezone, timedelta import matplotlib.pyplot as plt #01) 바이낸스 계정 접속 api_key = os.getenv('Binan_API_KEY') api_secret = os.getenv('Binan_SECRET_KEY') client = Client(api_key, api_secret) print('\n','[ BINANCE ACCOUNT ACCESSED ]') #02) 입력 : 시계열 데이터 수집 구간(tstt~tend), 시간 간격(t_interval) tstt_utc = '2022-12-01 00:00:00' tend_utc = '2023-02-28 23:59:59' t_interval = '1d' bars = client.get_historical_klines('BTCUSDT', t_interval, tstt_utc, tend_utc, limit=1000) #03) ohlcv 데이터만 추출 for i in bars: del i[6:] #04) 데이터프레임 열 이름 붙여주기 df = pd.DataFrame(bars, columns=['time_open','open','high','low','close','volume']) #05) 데이터프레임 열 type을 실수형으로 변환 df = df.astype({'open' : 'float', 'high' : 'float', 'low' : 'float', 'close' : 'float', 'volume' : 'float'}) #06) Date 열의 형태를 epoch에서 Pandas.Timestamp로 변경 df['time_open'] = df['time_open'].apply(lambda date: pd.Timestamp(time.ctime(date/1000.))) # ====== 판다스로 MFI 매매 전략 구현 ====== #07) 현금흐름지수(MFI, Money Flow Index) # MFI를 구하기 위한 시간 구간 설정 n_mfi = 9 #07-1) 중심가격 : Typical Price df['tp']=(df['high'] + df['low'] + df['close'])/3.0 #07-2) 상승, 하락 구분을 위한 기준값 df['close_bef'] = df['close'].shift(1) df['updown'] = df['close'] - df['close_bef'] #07-3) 상승, 하락 구분 :: Sum of Positive Money Flow, Sum of Negative Money Flow df['SMF_P'] = np.where(df['updown'] > 0.0, df['tp']*df['volume'], 0) df['SMF_N'] = np.where(df['updown'] > 0.0, 0, df['tp']*df['volume']) #07-4) 현금 흐름 비율 : MFR(Money Flow Ratio) df['MFR'] = df['SMF_P'].rolling(n_mfi).sum() / df['SMF_N'].rolling(n_mfi).sum() #07-5) 현금 흐름 지수 : MFI (Money Flow Index) df['MFI'] = 100 - 100/(1+df['MFR']) #07-6) MFI 20, 80 교차점 df['crs80'] = np.where(df['MFI'] < 80, 1, 0) df['crs20'] = np.where(df['MFI'] > 20, 1, 0) df['time_crs80'] = df['crs80'].diff() df['time_crs20'] = df['crs20'].diff() #07-7) 매수, 매도지점 표시 df['cross_buy'] = np.where(df['time_crs80']==-1, df['close'], np.NaN) df['cross_sell'] = np.where(df['time_crs20']==-1, df['close'], np.NaN) print(df.tail(10)) #08) 시계열 데이터 가시화, 차트에 매수지점(^), 매도지점(v) 표시 fig, axs = plt.subplots(2,1,figsize=(10,9)) axs[0].plot(df['time_open'],df['close'], label='close') axs[0].scatter(df['time_open'], df['cross_buy'], marker='^', color='red', label='buy') axs[0].scatter(df['time_open'], df['cross_sell'], marker='v', color='blue', label='sell') axs[0].set_title('BTC trading based on MFI(Money Flow Index)') axs[0].set_xlim(np.datetime64('2022-12-01'), np.datetime64('2023-03-01')) axs[0].set_ylabel('Price (USDT)') axs[0].legend(loc='best') axs[0].tick_params(axis='x', rotation=15) axs[0].grid(True) axs[1].plot(df['time_open'],df['MFI'], 'm', label='MFI') axs[1].set_xlim(np.datetime64('2022-12-01'), np.datetime64('2023-03-01')) major_yticks = [20, 80] axs[1].set_yticks(major_yticks) axs[1].legend(loc='best') axs[1].tick_params(axis='x', rotation=15) axs[1].grid(True) #09) 차트를 그림파일로 저장 file_path = 'C:/_python/pandas/backtesting/' plt.savefig(file_path +'MFI.png', dpi=200) plt.show() #10) 이익 계산, 계산결과 출력 no_buy = df['cross_buy'].count() no_sell = df['cross_sell'].count() print('\n','#10) ---') print(f'* Number of buying : {no_buy}', '\n', f' Number of selling : {no_sell}') #11-1) 매수일/매수가(df_buy), 매도일/매도가(df_sell) 저장 df_buy = df[['time_open', 'cross_buy']].dropna() df_sell= df[['time_open', 'cross_sell']].dropna() print('\n','# Buying Info.') print(df_buy) print('\n','# Selling Info.') print(df_sell) |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
[ BINANCE ACCOUNT ACCESSED ] time_open open high low close volume ... crs80 crs20 time_crs80 time_crs20 cross_buy cross_sell 80 2023-02-19 09:00:00 24632.05 25192.00 24192.57 24271.76 300395.99542 ... 1 1 0.0 0.0 NaN NaN 81 2023-02-20 09:00:00 24272.51 25121.23 23840.83 24842.20 346938.56997 ... 1 1 0.0 0.0 NaN NaN 82 2023-02-21 09:00:00 24843.89 25250.00 24148.34 24452.16 376000.82868 ... 1 1 0.0 0.0 NaN NaN 83 2023-02-22 09:00:00 24450.67 24476.05 23574.69 24182.21 379425.75365 ... 1 1 0.0 0.0 NaN NaN 84 2023-02-23 09:00:00 24182.21 24599.59 23608.00 23940.20 398400.45437 ... 1 1 0.0 0.0 NaN NaN 85 2023-02-24 09:00:00 23940.20 24132.35 22841.19 23185.29 343582.57453 ... 1 1 0.0 0.0 NaN NaN 86 2023-02-25 09:00:00 23184.04 23219.13 22722.00 23157.07 191311.81010 ... 1 1 0.0 0.0 NaN NaN 87 2023-02-26 09:00:00 23157.07 23689.99 23059.18 23554.85 202323.73623 ... 1 1 0.0 0.0 NaN NaN 88 2023-02-27 09:00:00 23554.85 23897.99 23106.77 23492.09 283706.08590 ... 1 0 0.0 -1.0 NaN 23492.09 89 2023-02-28 09:00:00 23492.09 23600.00 23020.97 23141.57 264140.99894 ... 1 0 0.0 0.0 NaN NaN [10 rows x 19 columns] #10) --- * Number of buying : 1 Number of selling : 3 # Buying Info. time_open cross_buy 39 2023-01-09 09:00:00 17178.26 # Selling Info. time_open cross_sell 71 2023-02-10 09:00:00 21625.19 74 2023-02-13 09:00:00 21773.97 88 2023-02-27 09:00:00 23492.09 |
마치며 …
이번 포스팅에서도 바이낸스 비트코인 투자 연습을 하면서 판다스 데이터프레임을 익혀보았습니다. 파이썬 바이낸스 API로 비트코인 시계열 데이터를 가지고 온 후, 파이썬 판다스로 MFI 매매 전략을 백 테스팅 하였습니다.
데이터 분석에 유용하게 쓸 수 있는 판다스 데이터프레임의 열 계산 방법과 np.where(), rolling(window).mean(), rolling(window).sum(), diff() 함수, count() 함수를 유심히 봐 주시기 바랍니다.
함께 참고하면 더 좋은 글 :
1. 바이낸스 코인거래소 API Key로 계좌에 접속하는 파이썬 프로그래밍
2. 파이썬 바이낸스 API로 시계열 데이터를 가져오는 파이썬 프로그래밍
3. 바이낸스 API 보안을 위한 환경 변수 설정 : 윈도우 10
4. 파이썬 바이낸스 API 시계열 데이터분석. 판다스 시간 처리
5. 파이썬 바이낸스 API로 차트 분석 : 판다스 이동평균선
6. 시계열 데이터 분석 : 지수 이동평균 (EMA)
7. 파이썬 바이낸스 API로 비트코인 시계열 데이터 분석 : 이동평균 수렴확산 (MACD)
8. 파이썬 바이낸스 비트코인 투자 백테스팅 : 지수 이동평균선 매매 기법
9. 파이썬 바이낸스 API로 비트코인 투자 백테스팅 : MACD 매매 전략
10. 바이낸스 비트코인 투자 백 테스팅. 파이썬 코인 투자 연습
11. 파이썬 바이낸스 API로 비트코인 투자 백테스팅 : RSI 매매 전략
12. 파이썬 프로그래밍 시작
참고자료
[1] python-binance Docs >> get_historical_klines
[2] 김황후(2020), 파이썬 증권 데이터 분석, 한빛미디어
쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.