돈벌고싶다

파이썬을 이용한 매우 간단한 백테스팅 본문

코인과코딩, 그리고 인공지능

파이썬을 이용한 매우 간단한 백테스팅

coinwithpython 2022. 4. 27. 17:43
728x90
반응형

백테스팅, 쉬울 것 같지만 은근히 머리가 아픕니다. 내가 예상치 못한 변수가 존재할 수도 있는데, 이걸 막기 위해 테스트 코드를 10개씩 짜자니 배보다 배꼽이 더 큰 느낌도 들죠.

 

하지만 전략이 매우 단순하다면, 백테스팅 역시 단 몇줄로 끝낼수도 있습니다. 오늘은 전날과 전전날 종가를 보고 당일 코인가격이 올라갈지 내려갈지 정하는 전략을 백테스팅 해보겠습니다.

 

해당 전략은 우연히 유튜브를 통해 접했었는데, 링크를 남기고 싶으나 아쉽게도 영상을 찾을 수가 없습니다. 추후 혹시나 다시 접하게 된다면 수정하겠습니다. 전략은 매우 단순합니다. 전전날 종가와 전날 종가보다 현재가가 높다면 매수하여 장이 끝날때까지 들고있다가 마지막에 파는 전략입니다. 코인의 경우 24시간 장이 열려있기 때문에 23시 59분에 판다고 가정하겠습니다.


1. 라이브러리 호출

 

import numpy as np
import pandas as pd
import datetime
import ccxt

 

필요한 라이브러리를 호출해줍니다.

 


 

2. 데이터 불러오기

 

def get_binance_data(symbol, interval):
    btc_ohlcv = binance.fetch_ohlcv(symbol, interval, limit=1000)
    df = pd.DataFrame(btc_ohlcv, columns=['datetime', 'open', 'high', 'low', 'close', 'volume'])
    df['datetime'] = pd.to_datetime(df['datetime'], unit='ms')
    df.set_index('datetime', inplace=True)
    return df
binance = ccxt.binance()
df = get_binance_data('BTCUSDT', '1d')

 

비트코인을 일단위로 최근 1000일치 데이터를 불러왔습니다. 다른 코인으로 불러와도 무방합니다.

 


 

3. 전략 구현을 위한 feature 생성

 

df['one_day_ago'] = df['close'].shift(1)
df['two_days_ago'] = df['close'].shift(2)

 

이 전략에서는 전날 종가와 전전날 종가만 알면 구현할 수 있기 때문에, 이 둘에 대한 feature를 생성해주었습니다.

 


 

4. 백테스팅

 

leverage = 1
fees = 0.048

df['long'] = df.apply(lambda x: (min(x['close']/x['open'], x['close']/x['one_day_ago'], x['close']/x['two_days_ago'])-(fees/100)*2-1)*leverage+1 if (x['high'] > x['two_days_ago']) & (x['high'] > x['one_day_ago']) else 1, axis=1)
df['short'] = df.apply(lambda x: (min(x['open']/x['close'], x['one_day_ago']/x['close'], x['two_days_ago']/x['close'])-(fees/100)*2-1)*leverage+1 if (x['low'] < x['two_days_ago']) & (x['low'] < x['one_day_ago']) else 1, axis=1)

 

전날 종가와 전전날 종가보다 오늘의 최고가가 더 높을 경우, 매매가 이루어진 날이라고 볼 수 있습니다. 따라서 해당 조건이 만족할 때, 시가, 전날 종가, 전전날 종가 중 가장 높은 가격에서 매수가 이루어지고 당일 종가에 매도가 이루어 지는 것으로 매일의 수익률을 계산하였습니다. 또한 long 뿐만이 아닌 short도 고려해보았습니다.

 

df['long'].cumprod()[-2], df['short'].cumprod()[-2]

 

가장 중요한 수익률은 어떻게 되었을까요? 위 코드를 돌려보면 아시겠지만, 2022년 4월 27일 기준 long은 3년간 15%를, short은 -93%를 달성했습니다. 3년 동안의 수익률이 고작 15%라니... 정말 실망스럽네요. 여기서 멈출 순 없기 때문에, 이번엔 5일 이동평균선보다 높을 경우 산다는 조건을 추가해보겠습니다.

 

df['low_ma5'] = df['low'].rolling(window=5).mean().shift(1)
df['high_ma5'] = df['high'].rolling(window=5).mean().shift(1)

df['long'] = df.apply(lambda x: (min(x['close']/x['open'], x['close']/x['one_day_ago'], x['close']/x['two_days_ago'], x['close']/x['high_ma5'])-(fees/100)*2-1)*leverage+1 if (x['high'] > x['two_days_ago']) & (x['high'] > x['one_day_ago']) else 1, axis=1)
df['long'] = df.apply(lambda x: x['long'] if x['high'] > x['high_ma5'] else 1, axis=1)

df['short'] = df.apply(lambda x: (min(x['open']/x['close'], x['one_day_ago']/x['close'], x['two_days_ago']/x['close'], x['low_ma5']/x['close'])-(fees/100)*2-1)*leverage+1 if (x['low'] < x['two_days_ago']) & (x['low'] < x['one_day_ago']) else 1, axis=1)
df['short'] = df.apply(lambda x: x['short'] if x['low'] < x['low_ma5'] else 1, axis=1)

df['long'].cumprod()[-2], df['short'].cumprod()[-2]

 

이동평균선 feature를 추가하고, 이동평균선에 대한 조건도 추가해봤습니다. 다시 한 번 코드를 실행해봤더니, 이번에는 3년간의 long 수익률이 113%, short 수익률이 -53%를 달성했군요. 3년동안 100프로 수익률이라면 만족스러울까요?

 


 

5. 마무리

 

정말 간단한 전략에 대해 정말 간단한 백테스팅을 진행해봤습니다. 도움이 되었을까요? 사실 전 많은 기법들에 대해 백테스팅을 하면서 알게 된 것이 있다면, 기법, 전략에 정도(正道)는 없다는 것입니다. 상승장, 하락장, 횡보장 각각에 다른 전략을 사용해야 수익을 볼 수 있으며, 오늘의 장은 1년 전의 장과 달라 1년 전 성공했던 기법이 오늘 성공한다는 보장은 그 어디에도 없습니다.

728x90
반응형
Comments