본문 바로가기

Project

01-5. 비트코인 자동 매매 트레이딩 봇: 샘플 코드 수정!! 나만의 전략 코드 짜기!

반응형

01-5. 비트코인 자동 매매 트레이딩 봇 만들기

 

 

 

지난 포스팅 #01-4. 비트코인 자동 매매 트레이딩 봇: 샘플 코드 분석을 해보아요! 에서
조코딩님의 비트코인 자동 매매 샘플 코드 분석을 통해 전체적인 자동 매매 프로그램의 구성과 흐름을 알아보았습니다.

 

01-4. 비트코인 자동 매매 트레이딩 봇: 샘플 코드 분석을 해보아요!

자동 매매 샘플 코드 분석하기 비트코인 자동매매 트레이딩 봇 시리즈의 4번째 포스팅입니다! 이번에는 실제 매매에 사용할 샘플 코드를 자세히 살펴보고, 내가 원하는 조건으로 어떻게 수정하

zero-coding.tistory.com

 

이를 바탕으로 저만의 전략을 구성하고 적용하기 위해 실전 테스트와 코드 수정을 반복하였습니다.

뼈대가 될 샘플 코드 테스트를 위해, 코인 자동 매매에 적용할 코인 A를 선정하고
백테스트(BackTest)를 통해 k 값을 정의한 후  샘플 코드 테스트 진행한 결과 몇 가지 수정 사항을 발견하였습니다.

 

이번 포스팅에서는 백테스트로 알아본 k값샘플 코드 테스트에서 보인 문제점에 대해 이야기해 보도록 하겠습니다.
마지막으로 원하는 방법으로 자동 매매를 하기 위해 수정한 코드를 공유하고자 합니다.

 

 

# 포스팅 내용

  • 변동성 돌파 전략의 K값 정하기
  • 샘플 코드 문제점
  • 자동 매매 전략 및 코드 수정
  • 자동 매매 테스트 후기
  • 비트코인 자동 매매 코드 공유

 

 


 

 

Step 1. K값 정의

변동성 돌파 전략의 K값을 정의하기 위해, 코인 A 가격 데이터를 이용하여 백테스트를 진행했습니다.
1일 기준으로 7일, 14일, 30일, 90일 동안의 백테스트 결과는 다음 그래프와 같습니다.

# 백테스트 코드는 조코딩님의 github 자료를 이용했습니다.

K값이 0.1~0.15 및 0.2 부근에서, 그리고 2달 이상 장기 투자를 진행하였을 때 가장 좋은 수익률이 나타납니다.
K값이 약 0.5 일 때는 오히려 마이너스가 되기도 하며, 0.5 이상의 높은 K 값에서는
투자 기간에 따라 플러스와 마이너스 수익을 기록합니다.

 

위 결과는 5월 초, 비트코인의 상승장에서 테스트하였기 때문에
낮은 K값에서 더 좋은 수익률을 보인 것으로 판단됩니다.

테스트 당시 비트코인이 상승장이었고, 자동 매매 코드가 생각한 것처럼 작동하는지
그리고 수정해야 할 부분은 어디 인지 알아보기 위한 테스트 목적이었으므로
0.12의 낮은 K값을 선택했습니다.

 

 

 

Step 2. 샘플 코드 문제점 파악

샘플 코드에 특별한 수정 없이, 최소한의 정보(API key, Ticker, K 값)만 변경한 뒤
실행 해 본 결과 개인의 상황과 맞지 않는 몇 가지 문제점이 발견되었습니다.

 

# 샘플 코드의 전체 진행과 함수에 대한 설명은 비트코인 자동 매매 트레이딩 봇: 샘플 코드 분석을 해보아요! 의 Step 2~4. 를 참고해주세요.

 

01-4. 비트코인 자동 매매 트레이딩 봇: 샘플 코드 분석을 해보아요!

자동 매매 샘플 코드 분석하기 비트코인 자동매매 트레이딩 봇 시리즈의 4번째 포스팅입니다! 이번에는 실제 매매에 사용할 샘플 코드를 자세히 살펴보고, 내가 원하는 조건으로 어떻게 수정하

zero-coding.tistory.com

 

 

문제점 1) 조건 만족 시 잔고에 남아 있는 원화를 전량 매수한다.

  • 원화 보유가 안됨
  • 다른 코인에 대한 대응이 안됨
  • 원치 않는 불타기 발생
if target_price < current_price:
	krw = get_balance("KRW")
	if krw > 5000:
		upbit.buy_market_order("KRW-BTC", krw*0.9995)

 

매수를 위해 가져오는 원화(krw)는 get_balance 함수를 통해 개인 잔고에 있는 원화("KRW")의 총액입니다.
매수 금액의 제한이 없기 때문에 1일 동안 매수 조건 만족 시, 잔고에 남아있는 원화 전액을 매수합니다.
만약, 투자를 진행하고 있는 코인이 1개라면 1일 중 첫 번째 매수에서 모든 원화를 소진했으므로 문제 되지 않습니다.

 

하지만, 2개 이상의 코인을 투자 중인 상태에서 기존의 다른 코인 매도하면 원화가 잔고에 충전되고,
이때 자동 매매의 모든 조건이 충족되는 순간 다시 한번 모든 원화로 코인을 매수합니다.
즉, 잔여 현금이 0인 상태가 발생하게 되어 다른 코인에 대해 대응할 수 없는 상황이 발생할 수 있습니다.
특히, target_price < current_price 조건이 참인 상황에는 아무리 코인을 매도하더라고
곧바로 다시 모든 금액을 매수해버립니다. 따라서 현금 보유를 위해서는 프로그램을 꺼야 하는 경우가 발생하게 됩니다.

 

이렇게 되면, 보유하고 있는 원화가 없으므로 투자를 진행 중인 코인에 대한 개별적 대응이 불가능합니다.
또한 target_price < current_price 조건에 의해 현재가가 목표가 이상이면
무조건 매수를 진행하게 되어 원치 않는 불타기가 발생합니다.

 

 

문제점 2) 평균 매수가 이하로 하락 시 아무것도 하지 않는다.

샘플 코드 상에서의 매매 전략은 '변동성 돌파 전략' 1개 만을 수행하도록 만들어져 있습니다.
목표 매수가 도달 시 원화 전량 매수 이후, 매도 전(다음날 오전 8시 59분 50초)까지는 아무것도 하지 않습니다.

 

'변동성 돌파 전략'은 확실한 상승세에 매수/매도하여 수익을 얻는 방법이므로,

사실상 상대적으로 높은 가격에 매수가 이루어집니다.

하지만 변동성이 높은 암호화폐 시장에서 1일 중 ±5~10%는 충분히 오르락내리락 가능함을 감안할 때,
변동성 돌파 전략에 따라 상승세로 판단하였더라도 장중에 현재가가 평균 매수가 이하로 낮아질 가능성이 높습니다.

 

초기 매수 이후 매도 전까지 가격 하락이 발생할 때, 추가 매수하여 평균 단가를 낮춘다면,

다시 수익권에 도달하는 시간을 줄일 수 있습니다. 이 경우, 결과적으로 3가지 시나리오가 예상됩니다.

  • 첫째, 마이너스 발생 → 추가 매수 → 원금 회복 → 수익 → 매도
  • 둘째, 마이너스 발생 → 추가 매수 → 원금 회복 → 매도
  • 셋째, 마이너스 발생 → 추가 매수 → 매도

 

첫 번째 경우, 추가 매수로 인해 낮아진 단가와 늘어난 시드로 인해 기존 방법보다 높은 수익률을 얻을 수 있습니다.
두 번째 경우, 추가 매수를 하지 않았을 경우 마이너스 상태에서 매도가 발생하여 손해를 보았을 것이지만,
추가 매수를 함으로 인해 원금 보호가 가능합니다.
세 번째는 첫 번째와 유사한 상황이며, 늘어난 시드로 인해 큰 손해가 발생할 수 있지만
최소한 손실률(%)이 낮아질 수는 있습니다.

 

 

문제점 3) 조건 변경 시 코드 전체의 파라미터를 수정해야 한다.

샘플 코드에는 따로 변수로 지정되어 있는 조건이 없습니다.
따라서 시장 상황 및 개인 상황에 따라 매매 기준 시간, 코인 종류, K값 등을 수정하기 위해서는
전체 코드에 있는 모든 파라미터를 정확히 변경해 주어야 합니다.

 

사실.. 아주 복잡한 코드가 아니므로 수정하는데 오랜 시간이 걸리거나 아주 어려운 사항은 아니지만,
역시나 굳이 필요 없는 작업을 여러 번 하는 것은 너무나 귀찮습니다. 하하항

 

자동 매매의 기본적인 조건들 (매매 시간 간격, 코인 종류(ticker), K 값 등)을 while 함수 이전에 변수로 지정하고,
while 내부에서는 지정한 변수를 이용함으로써 상위 변수만 한번 바꾸어 주면 모든 수정이 끝나도록 만들면 좋겠습니다.

 

 

 

Step 3. 코드 수정!

위에서 정리한 문제점을 바탕으로 코드를 수정하였고,
수정한 코드의 기본 구성은 "로그인 → 변수 설정 → 1, 2, 3차 분할 매수 실행→ 매도 실행"으로 만들었습니다.

 

변수 설정

변수에는 매수에 사용할 총 원화 금액분할 매수를 위한 비율을 적어줍니다.

시간 간격은 매매 시작 ~ 매도까지 1세트의 시간 간격을 의미하며,

1일 단위는 "day", 분단위는 "minute240, minute60, minute 30"등을 지정할 수 있습니다.

ticker와 currency는 본인이 원하는 코인의 이름을 입력하고, k는 백테스팅 결과 가장 적절한 값으로 지정합니다.

 

# interval 변수의 자세한 설정은 01-4 포스팅의 매수 가격 설정하기 표를 참고해주세요.

# ticker, currnecy 찾는 법은 01-3 포스팅의 Step 2, 3을 참고해주세요.

 

# 총 매수 할 원, 분할 매수 비율
total = 1000000
rate30 = 0.3
rate40 = 0.4
rate_minus = 0.95

# 시간 간격
interval = "day"
# interval = "minute240"

# ticker, k, currency
ticker = "KRW-LTC"
currency = "LTC"
k = 0.12

 

 

시간 설정

interval 설정이 바뀔 수 있음에 따라, get_start_time함수에 interval 파라미터를 추가하여 수정합니다.

위에서 지정한 변수 ticker와 interval에 따라 start_time을 정의하고

end_time은 start_time에서 interval 만큼의 시간을 더하고 5초를 빼주었습니다.

start_time부터 end_time까지 매수를 진행하는 시간이며, end_time 이후 5초 동안 매도를 진행합니다.

 

def get_start_time(ticker, interval):             # 시작 시간 조회
    df = pyupbit.get_ohlcv(ticker, interval=interval, count=1)
    start_time = df.index[0]
    return start_time

 

# 시간 간격
interval = "day"

# 현제 및 매수 시작/종료 시간
start_time = get_start_time(ticker, interval)
now = datetime.datetime.now()
end_time = start_time + datetime.timedelta(days=1) - datetime.timedelta(seconds=5)

print(start_time)
print(now)
print(end_time)

 

 

만약 intertval을 4시간 간격(minute240)으로 변경하면,

start_time은 "09:00:00, 13:00:00, 17:00:00, 21:00:00, 01:00:00, 05:00:00"가 되고

end_time은 "08:59:55, 12:59:55, 16:59:55, 20:59:55, 12:59:55, 04:59:55"로 설정됩니다.

# 시간 간격
interval = "minute240"

# 현제 및 매수 시작/종료 시간
start_time = get_start_time(ticker, interval)
now = datetime.datetime.now()
end_time = start_time + datetime.timedelta(minutes=240) - datetime.timedelta(seconds=5)

print(start_time)
print(now)
print(end_time)

 

 

매매 시작

전체 매매가 자동으로 이루어 지기 위해 while True: 로 시작하여 무한 루프를 만들어주고,

매매 시작/종료 그리고 현재 시간을 설정합니다. 시간 설정이 끝나면, 본격적으로 코인 자동매매를 시작합니다.

 

def get_target_price(ticker, interval, k):        
    df = pyupbit.get_ohlcv(ticker, interval=interval, count=2)     
    target_price = df.iloc[0]['close'] + (df.iloc[0]['high'] - df.iloc[0]['low']) * k
    return target_price

 

while True:
  # 현제 및 매수 시작/종료 시간
  start_time = get_start_time(ticker, interval)
  now = datetime.datetime.now()
  end_time = start_time + datetime.timedelta(days=1) - datetime.timedelta(seconds=5)


    # 매매 시작
    if start_time < now < end_time:
        target_price = get_target_price(ticker, interval, k)
        print("Start: %s" % (start_time))
        print("End: %s" % (end_time))
        print("Target price: %d" % (target_price))

 

  • 현재 시간이 start_time과 end_time 사이에 있을 때 매매를 시작합니다.
  • get_target_price( ) 함수를 이용하여 코인 매수를 위한 목표 가격을 설정합니다.
    • interval 설정이 바뀔 수 있음으로, get_target_price함수에 interval 파라미터를 추가, 수정합니다.
  • 이때, ticker, interval, k는 while문 시작 이전에 지정한 변수를 사용합니다.
  • 진행 상황 모니터링을 위해 print( )로 시작/종료 시간과 목표 매수 가격을 알려줍니다. 

 

 

분할 매수

매매 시작 이후 3회 분할 매수를 할 수 있도록 코드를 작성하였습니다.

1차와 2차총 매수 금액의 30%, 3차 매수는 총 매수 금액의 40%를 매수하도록 설정했으며,

매수 평균가에서 5% 하락마다 추가 매수 진행합니다. 이때, "평균 매수가"를 조회하고 가져와야 하므로

이를 실행할 get_buy_average( ) 함수를 만들어 주었습니다. 

 

총 매수 금액과 분할 매수의 비율을 변경하고 싶으면 가장 상위의 "변수 설정" 부분에서 필요한 변수만 수정하시면 됩니다.

 

초기 1차 매수 시, 현재 시장 가격(current_price)이 급하게 올라가더라도

매수 목표가(target_price)를 크게 벗어나지 않게 하기 위해 가격 범위를 지정해줍니다.

단순히 "target_price < current_price"로 조건을 설정하면, 현재 가격(current_price)이 순간적으로 빠르게 상승할 때

매수 목표가 보다 약 500~1000원 이상까지 비싼 가격에 매수가 체결되는 현상이 발생하여 이를 방지하기 위함입니다. 

 

def get_buy_average(currency):                # 평균매수가
    balances = upbit.get_balances()
    for b in balances:
        if b['currency'] == currency:
            if b['avg_buy_price'] is not None:
                return float(b['avg_buy_price'])
            else:
                return 0

 

	i = 0 
        while i < 3:
            now = datetime.datetime.now()
            current_price = get_current_price(ticker)
            time.sleep(0.5)

            # 매수 1차
            if i==0 and (target_price-50) <= current_price < (target_price+100):
                upbit.buy_market_order(ticker, total*rate30)
                time.sleep(1)
                buy_average = get_buy_average(currency)
                i += 1                
                print("%dst Buy OK" % (i))              

            # 매수 2차
            if i==1 and current_price < buy_average*rate_minus:
                upbit.buy_market_order(ticker, total*rate30)
                time.sleep(1)
                buy_average = get_buy_average(currency)
                i += 1
                print("%dnd Buy OK" % (i))

            # 매수 3차
            if i==2 and current_price < buy_average*rate_minus:
                upbit.buy_market_order(ticker, total*rate40)
                time.sleep(1)
                buy_average = get_buy_average(currency)
                i += 1
                print("%drd Buy OK" % (i))

            if now > end_time:
                break

 

  • 매수 진행 횟수 카운트를 위한 i를 설정하고, 총 3회 분할 매수를 할 수 있도록 while i < 3: 으로 시작합니다.
    • 이때, 3번의 분할 매수 횟수를 채우지 못하더라도 매매 종료 시간이 되면 while 반복문을 종료해야 합니다.
    • 따라서 break를 사용해서 현재 시간이 종료 시간을 벗어나면 while문을 빠져나올 수 있도록 합니다.
  • if문으로 1~3차 매수에 대한 조건을 설정하고, 각 단계에 맞는 금액 비율로 매수하도록 지정합니다.
    • upbit.buy_market_order(ticker, total*rate30)
    • upbit.buy_market_order(ticker, total*rate40)
  • 각 단계마다 매수 실행 이후 평균 매수가를 가져옵니다.
    • buy_average = get_buy_average(currency)
  • 중간에 time.sleep(1)을 주어 업비트의 API 통신이 원활하게 이루어질 수 있도록 합니다.
    • time.sleep 없으면 자꾸 매수 평균가(buy_average)를 "None"으로 가져와서 에러가 발생합니다.
  • 분할 매수 카운트 진행을 알려주는 i에 +1을 하고, 매수 단계 모니터링을 할 수 있도록 print( )로 문구를 출력합니다.
  • 분할 매수 while 반복문은 매수 횟수 i가 3이 되거나, 현재 시간이 end_time 시간을 넘어가면 종료합니다.

 

 

매도

분할 매수 while문이 종료되면 end_time 이후 5초간 전량 매도를 진행합니다.

분할 매수의 while 반복을 종료하는 조건은 2가지이고 매도 조건은 오직 '시간'이므로

else가 아닌 elif를 사용합니다.

 

elif now > end_time:
    coin = get_balance(currency)
    upbit.sell_market_order(ticker, coin)
    time.sleep(1)
    print("Sell OK")

 

  • 현재 시간(now)매매 종료 시간(end_time)을 넘어가면 elif 코드가 실행됩니다.
  • get_balance( ) 함수를 이용해서 매매 종료 시간 직전까지 매수했던 코인을 가져옵니다.
  • 그리고 모든 코인을 5초 동안 현재 시장 가격으로 전량 매도합니다.
    • 매도 시간을 조절하기 위해서는 상위의 "시간 설정" 부분에서 수정 가능합니다.
  • 매도 완료 후, 다시 처음으로 돌아가 while True: 부터 새로 시작합니다.
    • 시간 설정 ~ 매도까지 무한히 반복 진행하며, 가장 상위(while True: 이전)에 지정한 변수를 그대로 사용합니다.

 

 

 

Step 4. 비트코인 자동 매매 트레이딩 봇 테스트 후기

4시간 간격으로 약 7일 테스트해본 결과, 설정한 조건들에 맞게 분할 매수부터 원하는 시점에 매도까지

문제없이 잘 실행됩니다. 최대 매수 금액과 분할 매수 금액을 지정 해 놓으니 투자 중인 다른 코인들과

자동 매매를 하는 코인을 구분할 수 있어 효과적입니다. 또한 분할 매수를 함으로써 리스크 관리가 가능하고,

변수들을(k값과 시간 간격 그리고 매수 비율) 시장 상황에 따라 수정하며 실행함으로써 안정적 매매할 수 있었습니다.  

 

작성한 코드로 자동 매매 진행 중, 상황에 따라 급히 수동으로 매수/매도를 하더라도

if문에서 설정한 조건들로 인해 원치 않는 시점에 매수는 발생하지 않았습니다.

직접 작성한 코드로 계획했던 데로 동작하고 실제로 수익까지 발생하니 그저 신기하네요^^

 

현재 작성한 코드는 매수와 매도 시점이 기본적으로 "시간"이지만, 꼭 시간이 기준이 되어야 하는 것은 아닙니다.

추후에는 매수가 기준으로 x% 수익이면 무조건 매도하도록 코드를 수정하여

리스크를 더욱 줄일 수 있지 않을까 생각합니다:) 

그리고 개인 노트북으로 프로그램을 실행하면 노트북을 너무 오래 켜 두어야 하는 문제가 있으나

이는 추후 클라우드 서비스를 이용해서 해결할 예정입니다.

 

 


 

 

비트코인 자동 매매 트레이딩 봇 프로그램 만들기! 완성입니다~!!!

업비트 API Key 발급, 데이터 호출 및 분석 그리고 직접 원하는 방식으로 자동 매매 코드까지 작성해보았습니다!

 

작성한 코드는 제 개인 깃허브에 올려놓았습니다!

# zions 깃허브: 비트코인 자동 매매 트레이딩 봇 코드 공유

 

zion08/Crypto-Autotrade

Contribute to zion08/Crypto-Autotrade development by creating an account on GitHub.

github.com

필요하신 분은 얼마든지 참고하시고, 혹시 피드백 또는 질문 사항 있으시면 댓글로 알려주세요.

 

파이썬 기본 문법을 이용한 프로그램이지만 저와 같이 처음 코딩을 접하는 분들에게는 정말 많은 연습이 되기도 하고,

직접 만든 프로그램으로 실제 사용까지 해보니 파이썬과 코딩에 더 흥미가 생기네요!

앞으로 비트코인 자동 매매 트레이딩 프로그램 만들기 관련해서는 업데이트 내용 있을 시

추가적으로 포스팅하도록 하겠습니다.

감사합니다!!

 

 

 

✋ 자동 매매 프로그램이 무조건적인 수익을 보장하지 않습니다.

✋ 모든 투자의 책임은 투자자 본인에게 있습니다.

 

 

 

참고 자료

더보기

https://www.youtube.com/playlist?list=PLU9-uwewPMe3KKFMiIm41D5Nzx_fx2PUJ

반응형