본문 바로가기
파이썬/가상화폐

Python으로 비트코인 승률 67% 전략, 역추세 전략 , RSI(2) 백테스팅 구현 - 1

by 행복론자 2020. 5. 17.

추세추종 전략은 비싸게 사서 더 비싸게 팔아 수익을 남기겠다는 전략입니다.

하지만 추세추종 전략의 단점으로는 횡보장에서 누적된 손실이고 승률이 상대적으로 낮다는 것입니다.

 

추세가 계속 상승할 줄 알았으나 쉽게 꺾여버리거나 잠깐 상승하는 척하는 경우에는 손실이 누적됩니다.

실제로 주식시장의 경우 상승하는 날이 떨어지는 날보다 더 적습니다. 미국증시도 마찬가지이나 계속해서 우상향해왔던 이유는 떨어지는 횟수가 잦더라도 상승할 때 폭이 더 커왔기 때문입니다.

 

아무튼 이렇게 상승 추세에 탄다는 것은 낮은 승률이지만 딸 때는 크게 따는 높은 손익비를 기대하고 있습니다. 

이와 다른 전략을 흔히 역추세 전략이라고 합니다.

 

역추세 전략은 계속해서 가치가 떨어지는 와중에 추세가 전환되어 갑자기 상승하여 수익을 기대하는 전략으로 생각하기 쉽지만 

 

조금 다르게 생각하면 장기적으로 보면 계속 상승하던중 단기간에 크게 하락하는 경우, 다시 장기 추세에 편승하여 반등하는 것 또한 역추세라고 볼 수 있습니다.

 

계속 하락하던 것을 사서 반등하기 기다린다는 생각에서 좀 더 확장하면

계속 상승하던 애가 잠깐 떨어지는 경우 다시 원래 추세대로 상승하기를 기대할 수도 있습니다.

 

물론 두번째 경우 다시 상승하다가도 꺾일 수 있지만 

RSI(14)를 활용한 시그널 중 이 수치가 30 밑으로 떨어지는 과매도 구간에는 일시적으로라도 반등하는 것을 노리고 매수하는 전략처럼 생각할 수 있습니다.

 

결론으로 이 포스팅에서 말하는 역추세의 전략의 원리는

장기적으로 상승하던 추세에서 잠깐 크게 떨어지는 경우에 매수하여 다시 반등을 할 것을 기대하겠다입니다.

 

 

그럼 매매조건은 

아래를 만족하는 경우 당일 종가 매수 
1. 당일 종가가 200일 이평선 위 (장기 상승 중)
2. 당일 종가가 5일 이평선 아래 (단기 하락 1)
3. RSI(2) < 5 (단기하락2)

아래를 만족하는 경우 그 다음날 시가에 매도 
1. 당일 종가가 5일 이평선 위 (다시 상승중)

 

RSI는 보통 14일치의 평균 상승, 하락을 사용하지만 2일치의 평균 상승, 하락을 사용하는 경우 

RSI(2)라고 표현하여 사용하겠습니다. 

 

이 전략을 비트코인 가격 데이터를 얻어와 사용해보겠습니다.

먼저 비트코인 가격을 얻어오고 RSI(2)를 구하는 방법입니다.

RSI 계산에 대해서는

2019/11/06 - [Python/Stock] - Python으로 RSI(Relative Strength Index) 구하기

 

위 글을 참조해주시길 바랍니다.

코드를 보면 이렇게 됩니다. 

import pybithumb
import pandas as pd
import numpy as np

# 비트코인 BTC
df = pybithumb.get_ohlcv("BTC")

period = 2
date_index = df.index.astype('str')

U = np.where(df.diff(1)['close'] > 0, df.diff(1)['close'],0)  # df.diff를 통해 (기준일 종가 - 기준일 전일 종가)를 계산하여 0보다 크면 증가분을 감소했으면 0을 넣어줌
D = np.where(df.diff(1)['close'] < 0, df.diff(1)['close'] * (-1),0)  # df.diff를 통해 (기준일 종가 - 기준일 전일 종가)를 계산하여 0보다 작으면 감소분을 증가했으면 0을 넣어줌
AU = pd.DataFrame(U, index=date_index).rolling(window=period).mean()  # AU, period=2일 동안의 U의 평균
AD = pd.DataFrame(D, index=date_index).rolling(window=period).mean()  # AD, period=2일 동안의 D의 평균
RSI = AU / (AD + AU) * 100  # 0부터 1로 표현되는 RSI에 100을 곱함
df['U'] = U
df['D'] = D
df['AU'] = AU
df['AD'] = AD
df['RSI2'] = RSI
df['ma5'] = df['close'].rolling(window=5, min_periods=1).mean()
df['ma200'] = df['close'].rolling(window=200, min_periods=1).mean()

 

 

2일 동안의 상승분(U), 하락분(D) 그리고 이에 대한 각각의 평균 AU, AD는 DataFrame에 넣어줄 필요는 없지만 그냥 제대로 했나 보기 위해 넣었습니다. 빼셔도 전혀 무방합니다.

이렇게 하면 DataFrame, df에는 RSI(2) 값 그리고 일봉(시가, 종가 등) 이평선(5일, 200일)이 들어가있습니다.

이를 바탕으로 반복문을 통해 매매 결과를 계산해보겠습니다.

 

bid_price = 0
ask_signal = False
accum_profit = 0
accum_loss = 0
win_count = 0
lose_count = 0

for i, row in df.iterrows():
    open, close, ma200, ma5, rsi2 = row['open'], row['close'], row['ma200'], row['ma5'], row['RSI2']

    # 청산시점 확인
    if ask_signal:
        print('3. sell at', i, end="\n \n")

        # 수익률 기록
        profit = (open - bid_price) / bid_price * 100
        df.at[i, 'profit'] = profit

        bid_price = 0
        ask_signal = False

        # 수익거래
        if profit > 0:
            win_count +=1
            accum_profit += profit
        # 손실거래
        else:
            lose_count +=1
            accum_loss += profit

    # 매수조건 확인
    elif not bid_price and ma200 < close < ma5 and rsi2 < 5:
        print('1. buy at', i)
        df.at[i, 'bid_price'] = close
        bid_price = close

    # 매도조건 확인
    elif bid_price and close > ma5:
        print('2. sell signal at', i)
        ask_signal = True

 

 

if의 분기가 세 개인 이유를 

코드말고 거래 처리 흐름 순서대로 보면 

1. 매수신호 확인

2. 매도신호 확인

3. 매도신호가 들어오면 다음날 청산 

 

이렇게 이루어짐을 생각해 구성했습니다. 

또한 매도신호가 들어와 다음날 청산하는 시점에는 다시 매수하지 않는다는 조건을 달았습니다. 

 

실행 결과를 콘솔에서 보면

1. buy at 2014-01-08 00:00:00
2. sell signal at 2014-01-11 00:00:00
3. sell at 2014-01-12 00:00:00
 
1. buy at 2014-01-13 00:00:00
2. sell signal at 2014-01-15 00:00:00
3. sell at 2014-01-16 00:00:00
 
1. buy at 2014-01-18 00:00:00
2. sell signal at 2014-01-20 00:00:00
3. sell at 2014-01-21 00:00:00

 

 

이런 식으로 나옵니다.

일봉이기에 날짜는 맞지만 시간은 무시하시면 될 것 같습니다.

 

이렇게 매매를 하고 전략 결과를 살펴보기 위해서 print를 해주면 전체 코드는 이렇습니다.

import pybithumb
import pandas as pd
import numpy as np

# 비트코인 BTC
df = pybithumb.get_ohlcv("BTC")

period = 2
date_index = df.index.astype('str')

U = np.where(df.diff(1)['close'] > 0, df.diff(1)['close'],0)  # df.diff를 통해 (기준일 종가 - 기준일 전일 종가)를 계산하여 0보다 크면 증가분을 감소했으면 0을 넣어줌
D = np.where(df.diff(1)['close'] < 0, df.diff(1)['close'] * (-1),0)  # df.diff를 통해 (기준일 종가 - 기준일 전일 종가)를 계산하여 0보다 작으면 감소분을 증가했으면 0을 넣어줌
AU = pd.DataFrame(U, index=date_index).rolling(window=period).mean()  # AU, period=2일 동안의 U의 평균
AD = pd.DataFrame(D, index=date_index).rolling(window=period).mean()  # AD, period=2일 동안의 D의 평균
RSI = AU / (AD + AU) * 100  # 0부터 1로 표현되는 RSI에 100을 곱함
df['U'] = U
df['D'] = D
df['AU'] = AU
df['AD'] = AD
df['RSI2'] = RSI
df['ma5'] = df['close'].rolling(window=5, min_periods=1).mean()
df['ma200'] = df['close'].rolling(window=200, min_periods=1).mean()

bid_price = 0
ask_signal = False
accum_profit = 0
accum_loss = 0
win_count = 0
lose_count = 0

for i, row in df.iterrows():
    open, close, ma200, ma5, rsi2 = row['open'], row['close'], row['ma200'], row['ma5'], row['RSI2']

    # 청산시점 확인
    if ask_signal:
        print('3. sell at', i, end="\n \n")

        # 수익률 기록
        profit = (open - bid_price) / bid_price * 100
        df.at[i, 'profit'] = profit

        bid_price = 0
        ask_signal = False

        # 수익거래
        if profit > 0:
            win_count +=1
            accum_profit += profit
        # 손실거래
        else:
            lose_count +=1
            accum_loss += profit

    # 매수조건 확인
    elif not bid_price and ma200 < close < ma5 and rsi2 < 5:
        print('1. buy at', i)
        df.at[i, 'bid_price'] = close
        bid_price = close

    # 매도조건 확인
    elif bid_price and close > ma5:
        print('2. sell signal at', i)
        ask_signal = True


df.to_csv('excel.csv')

trading_count = win_count + lose_count

print('1. 승리거래', win_count)
print('2. 패배거래', lose_count)
print('3. 매매승률', win_count / trading_count)
print('4. 수익총합', accum_profit)
print('5. 손실총합', accum_loss)
print('6. 전체합', accum_profit + accum_loss)
print('7. 수익평균', accum_profit / win_count)
print('8. 손실평균', accum_loss / lose_count)

 

 

아래는 수행 결과입니다.

(수수료, 슬리피지 없이 계산했으므로 수익,손실이 온전하지 못합니다.)

1. 승리거래 67
2. 패배거래 33
3. 매매승률 0.67
4. 수익총합 214.94842750310218
5. 손실총합 -246.4055744635239
6. 전체합 -31.45714696042171
7. 수익평균 3.208185485120928
8. 손실평균 -7.466835589803754

 

 

전체합이 -31으로 나오지만 그렇다고 이 말이 100만원 넣으면 70만원이 된다는게 아닙니다.

왜냐하면 반복되는 매매에서 발생하는 기하평균을 반영하진 않았으므로 실제로는 이것보다 돈을 엄청나게 잃습니다. 

(격달로 10%씩 잃고 따고를 반복하면 돈이 녹는 것과 같습니다.)

 

승률은 67%라고 하면 '오 뭐야 돈 잘벌겠네' 라고 생각하실 수 있습지만 손익비가 엉망이기에 돈을 엄청나게 잃었습니다.

엑셀로도 확인할 수 있는데 대충 살펴보면 O열에 수익이 나빠보이진 않습니다.

다만 비트코인은 변동성이 엄마무시하기 때문에 잃을 때 정말 크게 잃습니다. 

 

 

문제는 위 전략의 매도가 오로지 이평선(5일선)에 기반했기 때문이고 

너무 큰 손실이 생길 때는 손절하는 장치가 없어서 더욱 크게 잃습니다.

 

그럼에도 이 높은 승률(67%)을 보면

누군가가 단기적으로 크게 하락하면 다음에 상승한다! 라고 하면 무시할만한 소리는 아님을 알 수 있습니다.

70%에 육박하는 이 높은 승률에 기반하는 역추세 전략을 좀 더 보완할 수만 있다면 좋은 결과가 있을 것 같다는 생각이 듭니다. 

 

(다음에는 같은 전략으로 비트코인 말고 국내주식에 적용해보겠습니다, 미리 말하자면 비트코인과 다르게 엄청나게 좋은 결과가 있습니다.)

 

참고:

1.cafe.naver.com/invest79/2123

2.https://m.blog.naver.com/juun41/221335821964

 


같이 읽어보면 좋은 글

2022.12.27 - [파이썬/가상화폐] - [전자책] 바이낸스 코인선물자동매매 시스템 개발 방법을 담은 책이 출시되었습니다.

 

[전자책] 바이낸스 코인선물자동매매 시스템 개발 방법을 담은 책이 출시되었습니다.

🎁 바이낸스 자동매매 시스템 개발 방법을 담은 책이 출시되었습니다. "나 대신 일해주는 코인선물자동매매 프로그램 개발, 노하우 및 소스를 모두 공개합니다" ✔️ Q: 무슨 내용인가요? Python

jsp-dev.tistory.com

 

2022.11.05 - [파이썬/가상화폐] - [공지] 코인거래소별 프리미엄 체크봇 개발 가이드와 풀소스 전자책 | binance bybit | 업비트 김치프리미엄

 

[공지] 코인거래소별 프리미엄 체크봇 개발 가이드와 풀소스 전자책 | binance bybit | 업비트 김치프

https://kmong.com/gig/417785 거래소별 코인 프리미엄 알림봇 개발 가이드를 드립니다 | 36000원부터 시작 가능한 총 평점 5점의 3개 총 작업 개수 완료한 총 평점 5점인 JSDEV의 전자책, 투잡·재테크 전자

jsp-dev.tistory.com

 

2020/05/20 - [파이썬/가상화폐] - Python으로 비트코인 승률 67% 전략, 역추세 전략 , RSI(2) 백테스팅 구현 - 2

 

Python으로 비트코인 승률 67% 전략, 역추세 전략 , RSI(2) 백테스팅 구현 - 2

지난글에 이어 RSI(2)를 이용한 역추세 전략을 보완할 수 있는 일종의 장치를 조금 넣어보고 수정한 코드입니다. 무엇을 추가할까 생각할 때 제일 먼저 생각난게 1. 손절라인 지난 전략은 당일 종

jsp-dev.tistory.com

반응형
이 포스팅은 쿠팡파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

댓글