글을 쓰기에 앞서 우리는 백테스팅을 통해 최적의 K 값을 찾았다고 가정하고 1시간봉을 기준으로 거래한다고 가정한다.

변동성돌파전략의 핵심은 목표가의 지정과 해당 가격을 초과할 때 기계적 매수 그리고 단위시간이 끝날 때 기계적 매도이다.
여기서 그 알고리즘을 조금 더 상세하게 분리하자면 다음과 같다.

1. 거래시작 전의 저가와 고가를 파악하여 목표가를 지정한다.
2. 목표가를 넘을때까지 계속해서 현재가를 확인한다. 만약 단위시간이 넘어간다면 다시 1 로 돌아간다
3. 만약 목표가를 넘었다면 현재 시장가로 전량매수한다.
4. 단위시간이 끝나기 직전에 보유량 전량 매도한다.
5. 거래를 끝낼 때 까지 1부터 4 까지를 반복한다.

그렇다면 해당 알고리즘을 수행하기 위해선  [1] { 목표가를 계산하고 } , [2] { 매 초 마다 현재가를 확인하고 },  [3] { 목표가를 넘었다면 시장가로 전량 매수하고 }, [4] { 단위시간이 끝나기 직전에 전량 매도하는 } 4가지 기능을 구현해야만 한다.


[1] 목표가 계산 코드
목표가 계산을 위해 쓰일 코드는 pyupbit 라이브러리 내의 get_ohlcv() 함수이다.

import pyupbit

df = pyupbit.get_ohlcv('KRW-'+COINTICKER,'minute60')
print(df)

#                          open        high         low       close  
#2021-02-19 09:00:00  57852000.0  63680000.0  57038000.0  63649000.0   
#2021-02-20 09:00:00  63649000.0  65985000.0  62399000.0  64251000.0   
#2021-02-21 09:00:00  64260000.0  65846000.0  63381000.0  65417000.0   
#2021-02-22 09:00:00  65416000.0  65488000.0  56562000.0  61744000.0   
#2021-02-23 09:00:00  61688000.0  61760000.0  50900000.0  55105000.0
#...                         ...         ...         ...         ...   
#2021-09-02 09:00:00  56445000.0  58369000.0  56232000.0  57155000.0   
#2021-09-03 09:00:00  57155000.0  59110000.0  56500000.0  57783000.0   
#2021-09-04 09:00:00  57717000.0  58500000.0  57184000.0  57827000.0   
#2021-09-05 09:00:00  57836000.0  59650000.0  57217000.0  59212000.0   
#2021-09-06 09:00:00  59212000.0  59960000.0  58810000.0  59212000.0

get_ohlcv 함수에는 'KRW-BTC' 와 같이 알고싶은 코인의 정보와 'minute60' 혹은 'day' 와 같이 단위시간이 변수로 들어가고, DataFrame 형태로 반환된다. 밑에 주석으로 달아놓은 부분이 'KRW-BTC','day' 로 설정하여 반환되는 데이터프레임이다.
간단히 확인할 수 있듯이 데이터프레임의 0번 인덱스가 가장 오래된 데이터고 가장 마지막 인덱스가 가장 최신인 현재의 데이터이다.
우리가 목표가 계산을 위해 필요한 값은 [ 직전 고가, 직전 저가, 현재 시가 ] 일 것이다.  따라서  데이터프레임 라이브러리인 Pandas 의 iloc() 함수를 이용하여 해당 두 줄의 행을 가져와 데이터를 사용 할 것이다.

def cal_target():
  df =  pyupbit.get_ohlcv('KRW-'+COINTICKER,'minute60')
  yesterday = df.iloc[-2]
  today = df.iloc[-1]

  yesterday_high = float(yesterday['high'])
  yesterday_low = float(yesterday['low'])
  range = yesterday_high - yesterday_low
  today_open = float(today['open'])

  target = today_open + (range*K) # 여기서의 K 는 변동성상수 K
  
  return target

위의 프로세스를 통해 목표가를 구할 수 있다. 이 목표가 계산은 앞으로 계속 써야하므로, 함수형태로 만들어주었다.


[2] 매 초 현재가 확인 //  그리고  [3][4] 매수와 매도

사실상 알고리즘 매매의 꽃이라고 할 수 있다. 우리가 매매를 알고리즘에 맡기는 이유가 어지럽게 움직이는 캔들을 하루종일 쳐다보고 있을 여유도, 이유도 찾지 못하기 때문이다. 하지만 이 단계 또한 그 중요성에 비해 그다지 복잡하지 않다.
이 단계에서 새롭게 사용 될 라이브러리는 시간 확인을 위해 datetime 라이브러리 이다. 정말 단순하게 시간 확인을 위한 라이브러리이므로 다른 라이브러리를 사용하더라도 상관없고 시간 체크를 위해 아예 다른 방법을 사용하더라도 상관은 없다.

operate = False #프로그램을 실행하자마자 구매하는것을 방지하기 위함
hold = False #매수를 기다리는중인지 매도를 기다리는중인지 확인하기 위함
COINTICKER = 'BTC'  #COINTICKER 에 원하는 티커 입력


While True:
	now = datetime.datetime.now()
    
    #목표가 갱신 프로세스
    if now.minute == 0 and 10 <= now.second <= 20:
    	target = cal_target()
        print('목표가 갱신') #생략해도 상관없다. 제대로 작동하는지 확인하기 위함
        operate = True
    
    price = pyupbit.get_current_price('KRW-'+COINTICKER)
    
    if operate and price is not None and hold is False and (price > target):
    	#operate가 True이고, price가 제대로 구해졌으며, 현재 구매상태가 아니고
        #마지막으로 현재가가 목표가를 넘어섰다면? 매수신호!
        
        balance =  upbit.get_balance('KRW')
        upbit.buy_market_order('KRW-'+COINTICKER,balance*0.9995)
        #0.9995 는 거래수수료 제한 금액
        print('===매수===')
        hold = True
        
        
    if now.minute == 59 and 45<=now.second<=55 and hold:
    	coin_balance = upbit.get_balance('KRW-'+COINTICKER)
        upbit.sell_market_order('KRW-'+COINTICKER,coin_balance)
        print('===매도===')
        hold = False
        operate = False
   	
    time.sleep(10) #10초마다 이 반복문을 실행한다

설명을 위해 COINTICKER 를 우선 BTC 로 설정하고 코드를 작성했다.  따로 탈출조건을 만들지 않은 While 문이므로, 만약 실제로 실행한다면 터미널에서 컨트롤+C 로 강제종료 시켜야 한다.
업비트 api는 만약 제대로 실행되지 않는다면 None 을 반환한다. 따라서  매수신호 감지에서의 price is not None 조건문으로 price를 제대로 구하지 못했을 경우를 필터링해주었다. 그리고 0.05%의 거래수수료를 떼는 업비트에서 0.005를 제하지 않은 내 KRW 잔고를 전부 시장가로 매수신호를 보낼 경우 자신의 잔고 이상으로 매수신호를 보내는것으로 매수가 진행되지 않는다

또한 정각이 되기 직전에 파는 이유는 생각보다 해당 알고리즘을 사용하는경우가 적지 않아서인지 정각이 되는 시간에 가격에 변동이 생긴다. 따라서 그 매물들이 시장에 풀리기 직전에 우리가 먼저 판매하는 전략이기도 하다.



[[ 마무리 ]]

위의 코드만으로도 자동매매는 "어쨌든 구동은 된다" 하지만 나는 여기에서 더 나아가서 GUI화 시키고, 또 동시에 이런 변동성돌파 자동매매프로그램을 구현하고싶어하는 가장 큰 이유 "급등종목" 의 감시가 주 목적인 만큼 단 한개의 종목이 아닌 여러개의 종목을 동시에 감시할 수 있는 쓰레딩또한 다룰 것이다. GUI화를 위해 tkinter 라이브러리를  사용 할 것이고, 쓰레딩을 위해 threding 라이브러리또한 사용 할 것이다.
단순히 한 종목만을 계속해서 매매하고싶다면 오늘까지의 내용만으로도 충분히 구동시킬 수 있을것이다.
만약 더욱 사용하기 편하게, 또 동시에 많은 종목을 감시하고 싶은 프로그램을 작성하고싶다면, 뒤 이을 GUI와 쓰레딩 게시글들을 확인해주면 감사하겠다.

P.S. 저는 절대 자동매매를 추천드리지 않습니다. 자동매매가 돈이 됐으면 저도 이렇게 취업준비를 하고 있지 않겠지요? 재미로만 만들고 구동해보시길 추천드립니다.

 

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기