본문 바로가기
Python

SMA와 MACD 이용 Python 가상화폐 자동매매(2/2)-backtesting

by 아짱이아빠 2021. 9. 1. 22:28
반응형

지난번에 알아본 자동매매 프로그램을 backtesting 하는 방법과 그 결과에 대한 분석을 해보겠다. 

 

먼저 backtesting 코드를 알아본 후 dp이다(ADA)와 이더리움클래식(ETC)에 대해 자동매매 프로그램의 누적 수익률을 알아보겠다.

또한, 10분봉과 15 분봉 간의 수익률 차이와 지난번 알아본 프로그램의 몇 가지 조건을 바꿨을 때에 수익률이 어떻게 바뀌는지도 알아보겠다.

 

[Backtesting 코드 분석]

Backtesting은 프로그램을 오프라인 상태에서 지난 데이터를 통해 테스트를 해보는 것이다.

Backtesting 코드의 구조는 자동매매 프로그램 구조와 거의 동일하다.

import pyupbit
import numpy as np
import pandas as pd

coin = input("코인 :")

new_df = pyupbit.get_ohlcv(coin,interval="minutes10", count=200)

 

위의 코드는 필요한 모듈을 불러온 후 upbit 거래소에서 10분봉 데이터를 200개 가져온다.

즉, 코드를 실행시키는 시간부터 200분 전까지의 10분간격의 데이터를 불러와 new_df 변수에 저장한다.

 

1분 봉이나 3분, 5분 또는 15분 봉 데이터는 “minutes1”, “minutes3”, “minutes5”, “minutes15” 와 같이 바꿔주면 된다.

참고로 한번에 불러오는 데이터는 최대 200개이다.

그러므로 1분봉의 경우는 현재시간부터 200분 이전까지만 불러오게 된다.

 

ShortEMA = new_df.close.ewm(span=12, adjust=False).mean()
LongEMA = new_df.close.ewm(span=26, adjust=False).mean()
MACD = ShortEMA-LongEMA
Signal = MACD.ewm(span=9, adjust=False).mean()

new_df['MACD'] = MACD
new_df['Signal'] = Signal

SMA01 = new_df.close.rolling(window=3).mean()
SMA02 = new_df.close.rolling(window=10).mean()
SMA03 = new_df.close.rolling(window=50).mean()

new_df['SMA01'] = SMA01
new_df['SMA02'] = SMA02
new_df['SMA03'] = SMA03

new_df01 = new_df.tail(len(new_df)-50)

 

위는 3가지 종류의 SMA와 MACD를 계산하는 코드이며 이전 자동매매 프로그램에서 알아본 내용과 동일하므로 설명은 생략하도록 하겠다.

단, 마지막 줄은 계산된 데이터의 시작 시간부터 50개의 데이터 즉, 500분에 해당하는 데이터를 삭제하는 부분이다.

이것이 필요한 이유는 SMA03이 50개 데이터를 이동 평균하므로 SMA03은 첫 데이터부터 50개까지 NaN이 되어 전체적인 계산에 영향을 주기 때문이다.

SMA03 뿐만 아니고 MACD나 SMA01등도 모두 평균을 하므로 첫 데이터부터 일정 데이터 까지는 버려야 하는데 가장 많이 버려야 하는 SMA03 개수만큼 버리면 그때부터는 모두 유효한 데이터가 된다.

평균계산으로 인해 첫 데이터부터 일정 기간 데이터는 버려야 함
(평균계산으로 인해 첫 데이터부터 일정 기간 데이터는 버려야 함)

 

buy_price=[]
sell_price=[]

for i in range(len(new_df01)):
  if (new_df01.SMA03[i] < new_df01.SMA02[i]) and (new_df01.SMA03[i] < new_df01.SMA01[i]) and ((new_df01.SMA01[i-1] < new_df01.SMA02[i-1]) and (new_df01.SMA01[i] > new_df01.SMA02[i])) and (new_df01.MACD[i] > new_df01.Signal[i]):
    buy_price.append(new_df01['close'][i])
    buy_price_=new_df01['close'][i]
    buy_date = new_df01.index[i]
    print('buy date :', buy_date)
    print('buy price :', buy_price_)
    
  if new_df01.SMA01[i] < new_df01.SMA02[i] and flag==0 :
    sell_price.append(new_df01['close'][i])
    sell_price_=new_df01['close'][i]
    sell_date = new_df01.index[i]
    print('sell date :', sell_date)
    print('sell price :', sell_price_)
    
buy_price.pop()

 

Backtesting의 실질적인 대상인 위의 코드도 이전에 설명했으므로 자세한 설명은 생략하도록 하겠다.

맨 마지막 코드는 다음에 수행할 누적 수익률 계산을 할 때에 필요한 경우도 있고 필요 없는 경우도 있는 코드이다.

마지막 매수를 한 데이터를 지우는 내용의 코드인데 수익률을 계산할 때에 마지막에는 매도를 한 상태여야 계산 에러가 발생하지 않는다.

그러나 다운받은 이전 가상화폐 데이터를 통해 가상 매매를 했는데 마지막 이벤트가 매수를 한 것이면 이 부분은 수익이 발행한 것인지 아닌지 확인이 불가하기 때문이다.

그래서 backtesting을 할 때에 에러가 발생하면 마지막 매수 이벤트 한 개를 지워줌으로써 그 이벤트에 대한 수익률은 계산하지 않고 에러를 피한다. 

 

data = pd.DataFrame()
data['buy_price'] = buy_price
data['sell_price'] = sell_price
profit = []

for i in range(len(data)):
  profit.append(data['sell_price'][i]/data['buy_price'][i])  

data['profit'] = profit
data['hpr'] = data['profit'].cumprod()
data_=data['hpr']

 

 

 

“data”라는 빈 데이터 프레임을 만들어 여기에 매수와 매도했던 데이터를 넣어준다.

그리고 각 매매 이벤트의 매도 가격을 매수 가격으로 나누어 수익률을 계산하고 “. comprod()” 함수를 통해 각 수익률에서 누적 수익률을 구한다.

 

여기까지 backtesting을 위한 코드를 알아봤고 다음은 실제로 ADA와 ETC에 여러 인자들을 바꿨을 때의 결과를 알아보겠다.

 

[기본 자동매매 조건에서의 수익률 비교]

Backtesting의 기간은 8월 28일 17:10부터 29일 18:00까지이며 에이다(ADA)와 이더리움클래식(BTC)의 두 가상 화폐에 대해 자동매매 시의 누적수익률과 실제 이 기간 수익률을 알아보면 아래와 같다.

 

자동 매매 누적수익율과 실제 수익율 비교
(자동 매매 누적수익율과 실제 수익율 비교)

 

위의 결과에서 보듯이 ADA의 경우는 실제로는 손해지만 자동매매를 통해서는 이득을 볼 수 있었고 ETC의 경우는 자동매매는 손해이나 실제로는 7%의 수익이 있었다.

ADA의 경우 자동매매가 유리했다는 결과지만 실제로 그 차이는 크지 않으며 게다가 여기에는 수수료가 고려되어 있지 않은데 자동매매에서 한 번 더 거래가 있었으므로 수수료를 고려하면 더욱 차이는 없다고 볼 수 있다.

 

반응형

 

[분봉에 따른 수익률 변화 분석]

다음은 분봉에 따른 수익률을 비교해본 것이다.

 

분봉에 따른 자동매매 수익율 비교
(분봉에 따른 자동매매 수익율 비교)

 

15분 봉의 경우는 앞의 10분봉과 같은 기간이므로 비교가 가능한데 5분봉과 3분봉은 기간이 서로 다르다. 이는 upbit API에서 한번에 제공하는 데이터의 개수가 200개로 한정되어 있기 때문이다.

그러므로 결과는 참고만 한다.

 

앞에서의 10분봉과 기준이 같은 15분봉 기준의 결과를 보면 서로 비슷하다.

기간이 서로 달라 비교는 안 되겠지만 5분 봉과 3분 봉에서는 짧은 기간에도 거래가 많아진다.

그러나 결과는 손해이다.

전체적으로 여기서 알 수 있는 것은 자동매매 거래가 많을수록 손해를 본다는 것이며 이는 자동매매 로직에 문제가 있다고 볼 수 있다.

그래서 다음은 자동매매 로직을 변경했을 때의 결과를 알아보겠다.

 

[자동매매 로직 변경에 따른 수익률 비교]

(1) 매도 로직 변경

이전까지의 자동매매 매도시점의 판단은 3일 단순 이동평균 SMA가 10일 SMA 보다 아래로 내려가는 순간에 전액 매도를 하는 로직이었다. (이전 글 참고)

이 로직이 대체적으로 가격이 어느 정도 내려온 시점에 매도가 이루어져 이익이 적거나 손해를 보는 거래를 하는 상황이 발생한다. 

그렇기 때문에 가격이 하락을 할 때에 조금 더 일찍 매도를 하여 이익을 더 남기기 위해 현재 가격이 10일 SMA 값보다 아래일 때에 매도하는 로직으로 바꾸어 테스트해보았으며 결과는 아래와 같다.

매도 로직 변경에 따른 결과
(매도 로직 변경에 따른 결과)

 

Backtesting 기간이나 기타 다른 조건은 맨 처음의 조건과 동일하다.

결과는 큰 차이가 없었고 ADA는 오히려 더 좋지 않은 결과이다.

바꾼 로직이 반드시 이익이 나는 방향으로만 거래를 하지 않는다는 것을 알 수 있다.

 

(2) 매수 로직 변경

이번에는 다른 조건을 모두 동일하게 하고 매수 로직을 변경하였다.

기존은 3일 SMA나 10일 SMA가 50일 SMA보다 모두 위쪽에 있어야 매수의 기본 조건이 되었는데 이렇다 보니 거래 자체가 많이 발생하지 않고 게다가 충분히 이익을 볼 수 있는 거래도 건너뛰는 경우가 생겼다.

그래서 50일 SMA 조건을 제거하였다.

그 결과는 다음과 같다.

 

매수 로직 변경에 따른 결과
(매수 로직 변경에 따른 결과)

 

50일 SMA에 대한 기준이 없어지니 거래가 많아졌다.

ADA는 여전히 크게 변화가 없이 손해를 보는 결과이나 ETC의 경우는 약 4%의 이익이 발생했고 이제까지의 결과 중 가장 높다.

 

 

[결 론]

아직은 계속 테스트를 해보는 과정에 있고 backtesting의 기간도 너무 짧은 경향이 있어서 자동매매에 대한 어떤 결론을 내리기에는 이르다고 생각된다.

그러나 지금까지의 테스트와 실제 자동매매로 거래를 해본 봐로는 자동매매를 통해 수익을 내는 것은 쉽지 않다는 것이다.

그 이유는 다음과 같다.

첫 째로는 지난 포스트에도 얘기했었던 프로그램이 거래하려는 시점과 분봉의 종료되는 시점을 정확히 일치시킬 수 없다.

그렇기 때문에 실제로는 매수나 매도 조건이 되지 않았지만 프로그램 상으로는 매수나 매도가 일어나 손해를 보게 된다. 

이는 backtesting의 결과에서도 고려되어야 한다.

Backtesting은 이미 지난 과거의 데이터를 가지고 자동매매 로직을 테스트하는 것이므로 위에서의 시점이 일치하지 않아 잘못된 거래가 발생하는 것을 반영하지 못한다.

그러므로 자동매매의 결과는 backtesting 결과보다 더 안 좋을 수 있음을 알아야 한다.

 

두 번째는 자동매매가 보조지표를 가지고 매수와 매도를 하는데 보조지표 데로 실제 코인의 가격은 움직이지 않는다는 것이다.

더욱이 코인은 주식보다 변동성이 더욱 크다.

실제로 갑자기 급등하는 종목은 프로그램이 높은 가격에서 매수를 하는 경우가 발생하고 결국 큰 손해를 볼 수 있다.

 

그러나 앞에서의 backtesting 결과로 알 수 있는 것이 한 가지 있는데 그것은 코인이 상승장이면 자동매매도 수익을 낼 확률이 높다는 것이다.

상승장이니 수익을 내는 것은 당연한 얘기겠지만 24시간 열려있는 장에서 밤새 이것을 보고 있을 수는 없다. 

밤사이라도 걸어두면 상승장에서 어느 정도 수익을 보장할 수 있는 자동매매 프로그램을 만들 수 있지 않을까 생각된다. 

 

이제까지 SMA와 MACD의 두 보조지표를 통해 자동매매 프로그램을 구성했는데 앞으로 Bollinger Band나 RSI등 더 많은 보조지표를 조합하여 시험을 해 볼 생각이다.

그러다 보면 언젠가는 횡보하는 장이나 하락장에서도 사용할 만한 프로그램이 만들어지지 않을까 기대해 본다.

좋은 수익을 내는 프로그램이 완성되면 그 때 다시 정리하도록 하겠다.

 

반응형

댓글