본문 바로가기

파이썬으로 퀀트 프로그램 만들기 project/백테스팅

[백테스팅]MACD 와 MACD signal을 이용하여 매매하기

728x90

차트 보조지표 중 하나인 macd, macd signal, 그리고 rsi을 추가적으로 이용하여 매매 백테스팅을 진행해 보겠습니다.

구체적인 매매 아이디어는 다음과 같습니다.

 

매수조건

1. macd 선이 macd singnal 상향돌파 (골든 크로스) 발생

2. rsi가 35 이하로 과매도

 

손익비는 1퍼센트로 하겠습니다.

한국 비트코인 5분봉 2만개 차트에서 백테스팅을 진행해보겠습니다.

 

#코드

본격적인 코드를 소개해드리겠습니다.

import pyupbit

access = "123abc"          # 본인 값으로 변경
secret = "123abc"         # 본인 값으로 변경
upbit = pyupbit.Upbit(access, secret)

print(upbit.get_balance("KRW-BTC"))     # KRW-BTC 조회
print(upbit.get_balance("KRW"))         # 보유 현금 조회

pyupbit 라이브러리를 이용하기 위한 access 값과 secret값을 입력해 줍니다. 

get_balance를 통해 잘 로그인 되었는지 확인합니다.

 

import talib

count = 20000
df = pyupbit.get_ohlcv("KRW-BTC", interval='minute5',count = count)

df = df[["open","high","low","close"]]

df['RSI'] = talib.RSI(df['close'], timeperiod=14)
df['macd'],df['macd_signal'], macd_hist = talib.MACD(df["close"], fastperiod=12, slowperiod=26, signalperiod=9)

tf = 0.0005 #trading fee
df['buy_condition'] = False
df['hpr'] = 1 # 누적 수익률
df['ror'] = 1 
df['buy_price'] = 0 # 평단가
df['dr'] = 1 # 금일 수익률
df["trading_number"] = 0
df["win"] = 0
df["lose"] = 0

비트코인 5분봉 데이터 2만개를 받아줍니다.

그리고 talib 라이브러리를 통해 rsi, macd, macd_signal 열들을 만들어줍니다.

그리고 매매 수수료를 0.05%로 설정해주고, 필요한 열들을 추가해줍니다.

 

 

 

golden_cross = False

#손익비
stop_profit = 0.01
stop_loss = 0.01

#과매도
over_sell = 35

for i in range(1,count):
    if df.iloc[i-1,7] == False:      
        # macd 골든 크로스 발생
        if df.iloc[i-1,5] < df.iloc[i-1,6] and df.iloc[i,5] > df.iloc[i,6]:
            golden_cross = True
        elif df.iloc[i-1,5] > df.iloc[i-1,6] and df.iloc[i,5] < df.iloc[i,6]:
            golden_cross = False

        # macd 골든 크로스, 과매도 -> 매수
        if golden_cross == True and (df.iloc[i,4] < over_sell or df.iloc[i-1,4] < over_sell or df.iloc[i-2,4] < over_sell or df.iloc[i-3,4] < over_sell or df.iloc[i-2,4] < over_sell):   
            df.iloc[i,7] = True # buy condition
            df.iloc[i,11] = 1 # dr
            df.iloc[i,9] = 1 # ror
            df.iloc[i,10] = df.iloc[i,3] # buy price
            df.iloc[i,12] = df.iloc[i-1,12] + 1 # trading_number + 1
            golden_cross = False
            
        else:
            df.iloc[i,12] = df.iloc[i-1,12] # trading_number

    else: #df.iloc[i-1,7] == True
        #익절
        if df.iloc[i,1] >= df.iloc[i-1,10]*(1+stop_profit):
            df.iloc[i,7] = False # buy condition
            df.iloc[i,11] = df.iloc[i-1,10]*(1+stop_profit)/df.iloc[i-1,3]#dr
            df.iloc[i,9] = df.iloc[i-1,9]*df.iloc[i,11] # ror

        #손절
        elif df.iloc[i,2] <= df.iloc[i-1,10]*(1-stop_loss):
            df.iloc[i,7] = False # buy condition
            df.iloc[i,11] = df.iloc[i-1,10]*(1-stop_loss)/df.iloc[i-1,3]# dr
            df.iloc[i,9] = df.iloc[i-1,9]*df.iloc[i,11]# ror

        else:
            df.iloc[i,7] = df.iloc[i-1,7]
            df.iloc[i,10] = df.iloc[i-1,10]
            df.iloc[i,11] = df.iloc[i,3]/df.iloc[i-1,3]# dr
            df.iloc[i,9] = df.iloc[i-1,9]*df.iloc[i,11]# ror

        df.iloc[i,12] = df.iloc[i-1,12]


df['hpr'] = df['dr'].cumprod()   

for i in range(1,count):
    if df.iloc[i-1,7] == True and df.iloc[i,7] == False: # 매도했을때
        if df.iloc[i,9] > 1: # 이기면
            df.iloc[i,13] = df.iloc[i-1,13] + 1
            df.iloc[i,14] = df.iloc[i-1,14]
        elif df.iloc[i,9] <= 1: # 지면
            df.iloc[i,14] = df.iloc[i-1,14] + 1
            df.iloc[i,13] = df.iloc[i-1,13]
    else:
        df.iloc[i,13] = df.iloc[i-1,13]
        df.iloc[i,14] = df.iloc[i-1,14]

본격적인 백테스트 코드입니다. 

위에서 설명드린 매매 조건을 가지고 매매를 진행합니다.

 

결과를 띄워봅시다.

import matplotlib.pyplot as plt
from matplotlib import gridspec

fig = plt.subplots(figsize=(18,15), sharex = True)#sharex를 통해 두그림의 x축을 공유함
gs = gridspec.GridSpec(nrows=3, ncols=1, height_ratios=[3,1,1])#gridspec을 통해 여러 축들을 원하는 대로 배치 가능

#주가, 수익률 나타내기
ax1 = plt.subplot(gs[0])
ax1.plot(df.index, df['hpr']*df.iloc[100,0], color='black', label="trading") # 수익률
ax1 = df['close'].plot(label="index", alpha = 0.5) # 주가

plt.legend()

#RSI 나타내기
ax2 = plt.subplot(gs[1])
ax2 = df['RSI'].plot(color='brown')
ax2.hlines(70,df.index[0],df.index[-1], color= 'black')
ax2.hlines(35,df.index[0],df.index[-1], color= 'black')


#MACD
ax3 = plt.subplot(gs[2])
ax3 = df['macd'].plot(color='red')
ax3 = df['macd_signal'].plot(color='blue')
plt.grid(True)
plt.subplots_adjust(wspace=0, hspace=0)

 

 

맨윗칸에서 하늘색 그래프는 비트코인 차트이고, 검은 색 선은 누적 수익률입니다. 결과가 좋지 못하네요

두번째 칸은 rsi를 뜻하고, 세번째 칸은 macd와 macd signal을 보여줍니다.

 

구체적인 승률을 확인하고 buy&hold 와 누적수익률을 비교해봅시다.

win_ratio=df.iloc[-1,13]/df.iloc[-1,12]
buy_and_hold = df.iloc[-1,3]/df.iloc[0,0]
hpr = df.iloc[-1,8]

print("win: ",df.iloc[-1,13]," / lose: ", df.iloc[-1,14], sep="")
print("승률: ",win_ratio)
print("buy and hold: ", buy_and_hold)
print("hpr: ",hpr)

win: 38 / lose: 40
승률:  0.48717948717948717
buy and hold:  1.1675775951488072
hpr:  0.9763825018421127

 

확실히 결과가 아쉽게 나왔네요. 

 

 

#소감

백테스팅 코드에서 macd골든크로스를 체크하는 방법이 아쉬웠던것같아요

한번 골든 크로스 되면 며칠이 지나도 계속 골든크로스가 되어있다고 체크되어 있어서 좋은 알고리즘이 되지 못한것 같네요

승률은 반반이었고 수익률은 buy and hold에 못미치는게 아쉬울 따름입니다.