파이썬 바이낸스 API로 비트코인 투자 백테스팅 : 일중 강도(II) 매매 전략
일중 강도(Intrday Intensity, II)를 이용하여 비트코인 투자 연습도 하고 파이썬 판다스도 익혀보겠습니다. 지금까지 변동성 돌파전략, 이동평균선, MACD, RSI 매매 전략, 그리고 MFI 매매 전략까지 백테스팅 해 보았습니다. 여기에 더해 이번 포스팅에서는 파이썬 바이낸스 API로 비트코인 캔들 데이터를 가져온 후, 파이썬 판다스로 일중 강도(II) 매매 전략을 백 테스팅 해보겠습니다.
글의 순서
백테스팅 (back testing)
추세추종 기법 중 일중 강도 II%를 이용한 반전 매매기법
일중 강도(II) 매매 전략 백 테스팅 과정 : 바이낸스 비트코인 시계열 데이터
파이썬 코드 : 바이낸스 API, 판다스로 MFI 매매 전략 백 테스팅
백테스팅 (back testing)
백테스팅은 과거의 가격정보로 지금 적용하고자 하는 매매 전략이 얼마나 효과적인지를 테스트 해보는 과정입니다. 지금까지 변동성 돌파전략, 단순이동평균, 지수이동평균, MACD 매매 전략, RSI, MFI 매매전략을 적용했을 때 얼마나 많은 수익을 얻을 수 있을지 알아보았습니다. 이번에는 일중 강도 매매 전략 차례입니다.
파바이낸스 비트코인 변동성 돌파전략 백 테스팅 결과,
파이썬 바이낸스 비트코인 투자 백테스팅 : 이동평균선 매매 기법,
파이썬 바이낸스 비트코인 투자 백테스팅 : 지수 이동평균선 매매 기법,
파이썬 바이낸스 API로 비트코인 투자 백테스팅 : MACD 매매 전략,
파이썬 바이낸스 API로 비트코인 투자 백테스팅 : RSI 매매 전략,
파이썬 바이낸스 API로 비트코인 투자 백테스팅 : MFI 매매 전략,
추세추종 기법 중 일중 강도 II%를 이용한 반전 매매기법
볼린저 밴드와 함께 일중 강도를 활용하는 매매기법을 반전 매매기법이라고 합니다. 반전 매매기법은 주가가 반전하는 지점을 찾아내서 매수 또는 매도하는 기법입니다. 볼린저 밴드 상 상승인데, 약세 지표가 뜬다면 매도하고, 볼린저 밴드 상 하락인데, 강세 지표가 뜨면 매수합니다. 구체적으로는 아래의 과정을 따릅니다. 참고로, 현재 가격을 볼린저 밴드상 위치로 나타내 주는 지표가 %b입니다.
▶매수 : %b가 0.05보다 작고, II%가 0보다 클 때 → 볼린저 밴드 하단에 있는데, 강세지표가 발생한 경우,
▶매도 : %b가 0.95보다 크고, II%가 0보다 작을 때 → 볼린저 밴드 상단에 있는데, 약세지표가 발생한 경우
일중 강도(II) 매매 전략 백 테스팅 과정 : 바이낸스 비트코인 시계열 데이터
지난 포스팅의 이동평균선, MACD 매매 전략, RSI, MFI 매매 전략과 비교하기 위하여 일중 강도를 사용한다는 것 외에 다른 것들은 모두 동일하게 유지하고 백테스팅합니다. 파이썬 바이낸스 API로 추출한 3개월(2022년 12월 ~ 2023년 2월) 동안의 비트코인 시계열 데이터로 수행한 백 테스팅 과정을 정리해 보겠습니다.
(1) 파이썬 바이낸스 API로 비트코인 시계열 데이터 가져오기
파이썬 바이낸스 API의 get_historical_klines() 함수로 비트코인 가격을 시계열 데이터로 가져옵니다. 전체 구간이 3개월이고, II%를 구할 때의 기준 구간이 21임을 감안하여, 시간간격을 4시간(4h)로 하였습니다.
※ 참고로 2022년 12월 부터 2023년 2월까지의 구간에서 시간간격을 1일(1d)로 했을 때, 일중강도 매매 전략으로는 매수 또는 매도 조건이 한 번도 발생하지 않았습니다.
(2) 볼린저 밴드 지표 %b 구하기
%b =(종가 – 하단 볼린저 밴드)/(상단 볼린저 밴드 – 하단 볼린저 밴드)
(3) 일중 강도 II, 일중강도율 II% 구하기
일중 강도 II = (2 × 종가 – 고가 – 저가)/(고가 – 저가) × 거래량
일중 강도율 = (21일 동안의 일중 강도의 합)/(거래량의 21일 합) * 100
(4) 매수, 매도 위치 찾아내기
매수 조건인 %b가 0.05보다 작고, II%가 0보다 클 때와 매도 조건인 %b가 0.95보다 크고, II%가 0보다 작을 때를 찾아냅니다. 여기서는 교차가 발생한 날의 종료가로 매수 또는 매도했다고 가정하였습니다.
(5) 이익 계산 : 이익(profit) = 매도가 – 매수가
매도 가격에서 매수 가격을 빼면 전체 구간에서의 이익이 됩니다. 2022년 12월 부터 2023년 2월까지의 구간에서 시간간격을 1일(1d)로 했을 때, 매수 또는 매도 조건이 한 번도 발생하지 않았습니다. 시간간격을 4시간(4h)로 조절했을 때, 매수 조건이 7회, 매도 조건이 4회 발생했습니다.
아래 그림에서 손실과 수익 구간을 확인할 수 있는데요. 첫 번째 사고팔았던 구간에서 18.67 USDT 손실, 두 번째 사고 팔았던 구간에서 6846.11 USDT 이익을 봐서, 총 6827.44 USDT의 이익을 얻었습니다.
▶첫 번째 사고, 팔았던 구간 : 18.67 USDT 손실
▶두 번째 사고, 팔았던 구간 : 6846.11 USDT 이익
※ 참고로, 이 포스팅에서는 거래 수수료를 0으로 가정하고 계산하였습니다.
파이썬 코드 : 바이낸스 API, 판다스로 일중 강도 II 매매 전략 백 테스팅
지금까지의 과정을 ‘판다스 일중 강도 II 매매 전략 백 테스팅’ 파이썬 코드에 나타내었습니다. 앞에서 설명한 %b 와 II 조건을 함께 만족하는 교차 지점을 찾아내는 것이 코드의 핵심부분이라고 할 수 있습니다. 코드의 #07) 부분을 유심히 봐 주시기 바랍니다. 시계열 데이터와 매수, 매도 지점을 표시한 차트는 C:/_python/pandas/backtesting/ 라는 폴더에 IIp.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 114 115 116 |
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.))) # ====== 판다스로 Intraday Intensity(II) 매매 전략 구현 ====== #07) 볼린저밴드 #07-1) 시간 간격 개수 설정 : window 만큼 window = 20 #07-2) window 만큼의 시간 간격 기준 이동평균선 df['sma'] = df['close'].rolling(window).mean() #07-3) window 만큼의 시간 간격 기준 표준편차 df['stddev'] = df['close'].rolling(window).std() #07-4) 볼린저 밴드 : 상단(upper) ~ 하단(lower) df['upper'] = df['sma'] + ( 2.0 * df['stddev']) df['lower'] = df['sma'] - ( 2.0 * df['stddev']) #07-5) 볼린저 밴드 지표 : %b df['pb'] = (df['close']-df['lower'])/(df['upper']-df['lower']) #07-6) 기술적 분석 지표, 일중 강도 (Intraday Intensity) df['II'] = (2*df['close']-df['high']-df['low'])/(df['high']-df['low']) * df['volume'] df['IIp'] = df['II'].rolling(window=21).sum()/df['volume'].rolling(window=21).sum()*100 #07-7) %b, II의 매수, 매도 조건 df['mark_buy'] = np.where((df['pb'] < 0.05) & (df['IIp'] > 0), 1, 0) df['mark_sell'] = np.where((df['pb'] > 0.95) & (df['IIp'] < 0), 1, 0) df['time_mark_buy'] = df['mark_buy'].diff() df['time_mark_sell'] = df['mark_sell'].diff() #07-8) 매수, 매도지점 표시 df['cross_buy'] = np.where(df['time_mark_buy']==-1, df['close'], np.NaN) df['cross_sell'] = np.where(df['time_mark_sell']==-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 II(Intraday Intensity)') axs[0].set_xlim(np.datetime64(tstt_utc), np.datetime64(tend_utc)) axs[0].set_ylabel('Price (USDT)') axs[0].legend(loc='best') axs[0].tick_params(axis='x', rotation=15) axs[0].grid(True) # %b, II% axs[1].plot(df['time_open'],df['pb']*100, label='%b*100') axs[1].plot(df['time_open'],df['IIp'], label='II%') axs[1].set_xlim(np.datetime64(tstt_utc), np.datetime64(tend_utc)) major_yticks = [0, 5, 95] axs[1].set_yticks(major_yticks) axs[1].tick_params(axis='x', rotation=15) axs[1].legend(loc='best') axs[1].grid(True) #09) 차트를 그림파일로 저장 file_path = 'C:/_python/pandas/backtesting/' plt.savefig(file_path +'IIp.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}') #10-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 30 31 32 33 34 35 36 |
[ BINANCE ACCOUNT ACCESSED ] time_open open high low close ... mark_sell time_mark_buy time_mark_sell cross_buy cross_sell 536 2023-02-28 17:00:00 23235.63 23421.98 23200.00 23392.69 ... 0 0.0 0.0 NaN NaN 537 2023-02-28 21:00:00 23391.96 23579.12 23315.42 23518.30 ... 0 0.0 0.0 NaN NaN 538 2023-03-01 01:00:00 23519.08 23600.00 23205.06 23264.36 ... 0 0.0 0.0 NaN NaN 539 2023-03-01 05:00:00 23263.38 23343.55 23020.97 23141.57 ... 0 0.0 0.0 NaN NaN 540 2023-03-01 09:00:00 23141.57 23498.00 23020.03 23441.14 ... 0 0.0 0.0 NaN NaN 541 2023-03-01 13:00:00 23440.37 23847.00 23425.44 23716.06 ... 0 0.0 0.0 NaN NaN 542 2023-03-01 17:00:00 23716.06 24000.00 23673.44 23739.17 ... 0 0.0 0.0 NaN NaN 543 2023-03-01 21:00:00 23739.87 23888.00 23550.80 23711.09 ... 0 0.0 0.0 NaN NaN 544 2023-03-02 01:00:00 23711.09 23746.24 23328.16 23355.14 ... 0 0.0 0.0 NaN NaN 545 2023-03-02 05:00:00 23354.03 23674.60 23300.00 23628.97 ... 0 0.0 0.0 NaN NaN [10 rows x 19 columns] #10) --- * Number of buying : 7 Number of selling : 4 # Buying Info. time_open cross_buy 66 2022-12-12 09:00:00 16918.97 95 2022-12-17 05:00:00 16632.12 164 2022-12-28 17:00:00 16678.98 166 2022-12-29 01:00:00 16595.92 168 2022-12-29 09:00:00 16558.33 500 2023-02-22 17:00:00 24160.87 503 2023-02-23 05:00:00 24182.21 # Selling Info. time_open cross_sell 24 2022-12-05 09:00:00 17196.88 27 2022-12-05 21:00:00 17083.92 118 2022-12-21 01:00:00 16900.30 357 2023-01-29 21:00:00 23525.09 |
마치며 …
이번 포스팅에서도 바이낸스 비트코인 투자 연습을 하면서 판다스 데이터프레임을 익혀보았습니다. 파이썬 바이낸스 API로 비트코인 시계열 데이터를 가지고 온 후, 파이썬 판다스로 일중 강도 II 매매 전략을 백 테스팅 하였습니다.
데이터 분석에 유용하게 쓸 수 있는 판다스 데이터프레임의 열 계산 방법과 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. 파이썬 바이낸스 API로 시계열 데이터 분석. 판다스, 볼린저 밴드 (Bollinger Band)
9. 시계열 데이터 기술적 분석 : 일중 강도 (Intraday Intensity, II)
10. 시계열 데이터 분석 : 추세분석 지표 6가지
11. 시계열 데이터 분석 : 과매수, 과매도, 강세, 약세
12. 파이썬 프로그래밍 시작
참고자료
[1] python-binance Docs >> get_historical_klines
[2] 김황후(2020), 파이썬 증권 데이터 분석, 한빛미디어
쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.