upbit에서 주는 실시간 데이터를 받는 방법은 아래 글에 기술해 놓았습니다. 여기에 나오는 함수를 사용할 예정입니다.

https://money-expert.tistory.com/32?category=757693 

 

실시간 거래를 위하여 기존 시뮬레이터를 다시 refactoring해봅니다. 프로그램 내용을 최대한 간단하게 만들기 위하여 로그관련된 부분은 과감하게 삭제하고, 매매 로직에서도 클래스 하나로 구현해보았습니다.

 

최대한 간단한 구조로 만들었으며, 로직도 래리윌리암스가 아닌 아래와 같이 아주 간단한 로직으로 개발하였습니다.

 

매매로직 :

매수 :

   기준가 대비 x% 오르면 매수

매도 :

    1) 익절 : 매수가 대비 y% 오르면 매도

    2) 손절 : 매수가 대비 z% 내리면 매도 

 

 

우선 Trader()라는 class를 하나 추가했습니다.

Trader 클래스에서는 실제 매매를 담당합니다.

Trader의 간단한 동작 방식은 아래와 같습니다.

 

 

실시간 거래 정보가 들어온다.

if 매수 대기 중이면 :

   if 현재 가격이 매수 조건이면 :

        매수주문

else 매도 대기 중이면 :

   if 현재 가격이 매도 조건이면 :

        매도주문

        매수 대기중으로 변경

  

코딩할 내용은 단순하지만 이런 저런 조건문이 많이 붙기 때문에 실제 코드는 약간 복잡합니다. 예를들어 매수할 수량을 정하는 부분에서도 암호화폐의 특성상 소숫점 이하까지 주문을 할 수 있습니다. 그렇다고 소숫점 10자리까지 주문을 할 수 없으니 매수할 수량에 따라서 적절한 수량을 계산해야합니다. 아래와 같은 방식으로요. 이런식으로 매매 흐름과는 관계없이 세세하게 코딩하여야 하는 부분이 나오면 생각외로 시간이 많이 걸리게 됩니다.

 

                # 살 수량 결정
                buying_vol = amount / buy_price    # 매수 주수
                if buying_vol > 10 :    #10개 보다 크면 소숫점 0
                    buying_vol = int(buying_vol)
                elif buying_vol > 0 :   #0개 보다 크면 소숫점 2
                    buying_vol = float(format(buying_vol,'.2f'))
                else :                  #0개 적으면 크면 소숫점 4
                    buying_vol = float(format(buying_vol,'.4f'))

 다음은 프로그램을 시작하는 부분입니다.

우선 거래소를 생성합니다. 여기에서는 upbit 거래소를 사용합니다. 이때 본인의 키로 변경하셔야 합니다.

사용할 로직도 생성합니다. 일반적으로 candle 정보를 사용하기 때문에 인자로 넘겨주지만 본 예제에서는 candle은 사용하지 않습니다. 대신에 로직에서 사용할 매수기준, 매도기준, 손절기준을 %를 logic에 설정을 합니다.

 

다음으로는 로직에서 사용할 시작가격을 설정합니다. 일반적으로는 candle 정보를 읽어서 적절한 값을 설정하거나, 아니면 일정 기간 돌리면서 candle 정보를 쌓아나가야 합니다. 이 부분도 일단은 간단하게 입력하도록 하였습니다.

 

이렇게 필요한 class를 만들고 변수 값을 설정한 후 Trader를 생성하면 됩니다. 

    access = 'my acess'  # 본인의 access 키값
    secret = 'my secret' # 본인의 secret 키값
    
    upbit = MyUpbit(access, secret)
    # 상승 따라가기
    tr_logic = TR_FOLLOW_TREND('min', 1) # candle정보는 무시

    ticker = 'KRW-LBC'
    seed = 1000
    buy_perc = 0.03  # 시작가 대비 3% 오르면 매수
    sell_perc = 0.01 # 매수가 대비 10% 오르면 매도(익절)
    losscut = 0.03   # 매수가 대비 losscut 내리면 매도(손절)
    tr_logic.init_set(buy_perc, sell_perc, losscut)

    start_price = 102 # 시작가, 로직에 따라 시초가일 수도 있고, 이전 30분 candle의 open 가격일 수 있음.
    tr_logic.set_start_price(start_price)

    trader = Trader(upbit, ticker, tr_logic, seed)

 

다음에는 websocket를 설정하는 부분입니다. myconnect() 함수에 앞에서 만든 trader와 관련 정보를 설정하면 됩니다. 만약 받은 실시간 정보를 출력하고 싶으면 display_web_socket_recv 값을 1로 하면 됩니다. 체결 정보가 너무 많으면 시스템이 느려질 수 있으므로 정상적으로 동작하는지 확인할 때는 1로 설정하고, 그 후에는 0으로 하는 것을 권합니다. 막상 돌려보니 연결이 끊어지는 경우가 빈번하더군요. 따라서 접속이 끝어지면 잠시 쉬었다가 다시 연결하는 방식으로 코딩을 했습니다.

 

    display_web_socket_recv = 0
    while(1) :
        try :
            asyncio.get_event_loop().run_until_complete(my_connect(trader, ticker, display_web_socket_recv))
        except Exception as x: 
            print('websocket error : ', x)

        time.sleep(10)

 


이제 체결 정보를 실시간으로 받을 수 있습니다. upbit에서 넘겨주는 체결정보에는 당양한 정보가 있는데요. 이걸 제가 필요한 내용만 추려서 dict 형태 정보로 변경을 합니다. 이렇게 하는 이유는 향후 다른 거래소에서 거래를 할 때 거래소 의존적인 부분을 최소화하기 위함입니다. 실거래 데이터가 왔으니 이제는 거래를 한는 trader에게 이 정보를 넘겨줍니다.

 

            data_rev = await websocket.recv()
            my_json = data_rev.decode('utf8').replace("'", '"')
            data = json.loads(my_json)
            if show :
                print(data['code'], data['trade_time'], data['ask_bid'], data['trade_price'], data['trade_volume'])
            if 'type' in  data :
                if data['type'] == 'trade' :
                    info = make_info_from_upbit_real(data)
                    real.do_trading(info)

 

거래를 하는 방식은 앞에서 설명한대로입니다. 매수 조건이 되면 매수, 매수되었다면 매도 조건이면 매도. 간단하죠.

그런데 실제로는 좀더 작업을 해야합니다. 예를들어 매수 주문을 했다고 매수가 된 것이 아닙니다. 시장가 주문을 하면 되겠지만 이런 경우에는 수익률이 떨어질 수 있습니다. 만약 지정가 매수를 하게되면 매수가 되었는지 확인하는 코드를 꼭 추가하여야 합니다. 이번 소스에서는 빠졌지만 실제 매매를 하기 위해서는 꼭 추가하여야 합니다. 

 

    def do_trading(self, info) :
        if self.buying_order_info == {} : # 매수 대기 중
            buy_price = self.tr_logic.is_enter_condition(info) 
            if buy_price > 0 : # 매수조건임
                amount = min(self.balance, self.init_seed)
                # 살 수량 결정
                buying_vol = amount / buy_price    # 매수 주수
                self.do_new_order('buy', buy_price, buying_vol)

        else : # 이미 매수함
            sell_price, losscut = self.tr_logic.is_exit_condition(info)  #
            if sell_price > 0 : # 매도 조건
                # 매도 주문 
                # 매도 가격 : tr_logic에서 결정한 값, 
                # 매도 수량 : 매수 수량
                self.do_new_order('sell', sell_price, self.buying_order_info['org_qty'])

 

로직은 앞에서 설명한 것과 같이 일정 % 오르면 매수하고, 매수한 후 일정 % 이상 오르면 매도, 일정 %이하 내리면 손절입니다. 필요한 초기값들 설정하는 부분도 추가를 해야합니다. 주 부분은 매수조건, 매도저건입니다. 예로 만든 로직은 아주 간단합니다. 매수는 현재가가 기준가 대비하여 올랐으면 현재가로 매수 가격으로 돌려줍니다. 매도는 익절/손절 조건을 만족하면 현재가를 매도 가격으로 돌려줍니다.   

 

class TR_FOLLOW_TREND() 

    def is_enter_condition(self, info) :
        # buy_price는 시작가 * 상승률
        buy_price = self.open * (1+self.buy_percent) 
        if info['close'] >= buy_price :
            self.bought_price = info['close']  # 매수 가격 저장
            return info['close']
        return 0

    # 조건 조사
    # cut : 익절(1) 혹은 손절 (2)
    def is_exit_condition(self, info) :
        sell_price = self.bought_price * (1+self.sell_percent)  # 매수 가격 대비 올랐으면
        if info['close'] >= sell_price :
            self.bought_price = 0
            return info['close'], 1    # 1: 익절

        sell_price = self.bought_price * (1-self.losscut)  # 매수 가격 대비 내렸으면
        if info['close'] <= sell_price :
            self.bought_price = 0
            return info['close'], 2    # 2: 손절

        return 0, 0

 

upbit websocket으로 실시간 체결 데이터를 받아서 정의한 로직에 맞게 매매를 하는 프로그램이 완성되었습니다.

물론 매수/매도 주문 후 실제 체결이 되었는지 확인하는 부분을 추가하여야 완벽한 실전 매매가 됩니다. 

 

이 부분은 좀 복잡하기 때문에 일전에 소개해드린 전략매매 흐름도를 바탕으로 trader class를 변경하면 향후 기능 변경시에 적응하기 좋습니다.

 

money-expert.tistory.com/12

 

다음에는 업비트에서 전종목 시세를 받아서 (open 가격 자동 설정) 돌아가는 방식을 설명하도록 하겠습니다. 

현재 개인적으로 upbit에서 실시간 시세를 받아서 래리윌리엄스 로직을 돌리고 있는데요. 생각만큼 수익이 나오지는 않습니다. 시뮬레이션에서는 수익이 좋았는데, 실제 적용해보니 생각만큼 수익이 안나는군요. 세상에 쉬운 일이 없군요. 

 

관련 코드는 아래 깃허브에 있습니다. pyupbit 수정한 버전도 함께 올려 놓았습니다.

 

github.com/multizone-quant/system-trading-crypto

반응형

설정

트랙백

댓글