Programming

업비트 마켓 메이킹 파이썬 봇

steloflute 2022. 5. 5. 01:01

https://blog.naver.com/opop4615/222313500451

 

 

[COIN X QUANT] 맛보기 # 암호화폐 마켓메이킹

안녕하세요 WILLBE입니다. 블로그에서 오랜만에 인사드리네요 😁 취업이후 블로그에 많이 소홀했던...

blog.naver.com

에 개념적으로 간단하게 잘 되어 있는 마켓 메이킹 봇 소스 코드가 있다.

그런데 거기에 나와 있는 소스 코드는 작동하지 않는다. API 명세가 바뀌어서인지...

 

그래서, 작동하도록 소스 코드를 변경하였다. 로직도 일부 변경했다. 고정된 몇 틱 호가가 아니라 위 아래로 몇 % 구간에 주문을 넣는다.

 

매수, 매도 호가에 1쌍의 주문을 계속 대기시키는 로직이다.

시장의 잡음(noise)를 수익화하는 로직이다. 그런데 요즘 장은 노이즈가 별로 없는 듯 하다.

미체결 주문이 현재 가격에서 너무 멀어지면 취소시키고 다시 주문한다.

 

업비트 API 매매는 직접 API 명세를 보고 프로그래밍해도 되지만, 미리 만들어진 API wrapper인 pyupbit을 사용하는 것이 편리하다.

 

# api_key.py:

#access_key = "업비트에서 발급받은 api access key"
#secret_key = "업비트에서 발급받은 api secret key"

access_key = ""
secret_key = ""
이 파일은 노출되지 않게 잘 관리해야 한다.
 

# upbitmm.py:

# 참고: [COIN X QUANT] 맛보기 # 암호화폐 마켓메이킹|작성자 WILLBE https://blog.naver.com/opop4615/222313500451
# https://github.com/sharebook-kr/pyupbit

import api_key

import pyupbit
import time
import traceback

upbit = pyupbit.Upbit(api_key.access_key, api_key.secret_key)

# 시장 상수
# 최소 주문 금액
min_KRW_quantity = 5000

# 수수료율
fee_rate = 0.05 / 100

# Setting
tickers = ['KRW-BTC', 'KRW-XRP', 'KRW-SOL', 'KRW-ETH', 'KRW-BCH', 'KRW-BSV', 'KRW-ADA', 'KRW-DOT', 'KRW-DOGE']
KRW_quantity = 5500

# 목표 스프레드
spread = 1 / 100
spread = max(spread, fee_rate * 2) # 수수료 이상이 되게

# order interval (in seconds)
order_interval = 1

#tickers_all = pyupbit.get_tickers()
#print('All Tickers:', tickers_all)
tickers_krw = pyupbit.get_tickers(fiat = 'KRW')
print('KRW Tickers:', tickers_krw)

#tickers = tickers_krw
print('My Tickers ', tickers)
print('KRW Quantity: ', KRW_quantity)

def get_order_new(ticker, order_type):
    """
    bid/ask 미체결 주문 현황

    미체결주문 존재시 주문 ID, 미존재시 None 반환
    """
    order = upbit.get_order(ticker)
    if not order:
        return None

    for x in order:
        if x['side'] == order_type:
            return x['uuid']
    return None

def cancel_all():
    for ticker in tickers:
        orders = upbit.get_order(ticker)
        for x in orders:
            print('Cancel: ', x)
            upbit.cancel_order(x['uuid'])

def make_market(ticker):
    orderbook = pyupbit.get_orderbook(ticker = ticker)
    ask_target_price = orderbook['orderbook_units'][0]['ask_price']
    bid_target_price = orderbook['orderbook_units'][0]['bid_price']
    ask_target_price_delta = orderbook['orderbook_units'][1]['ask_price'] - ask_target_price
    bid_target_price_delta = bid_target_price - orderbook['orderbook_units'][1]['bid_price']
    price_delta = max(ask_target_price_delta, bid_target_price_delta)

    # 스프레드 도달할 때까지 호가 위치를 벌린다.
    while ask_target_price / bid_target_price - 1 < spread:
        ask_target_price += price_delta
        bid_target_price -= price_delta

    # .9999 방지
    ask_target_price = round(ask_target_price, 4)
    bid_target_price = round(bid_target_price, 4)
    print('target price:', ask_target_price, bid_target_price)

    # https://docs.upbit.com/reference/%ED%98%B8%EA%B0%80-%EC%A0%95%EB%B3%B4-%EC%A1%B0%ED%9A%8C
    # orderbook_unit 리스트에는 15호가 정보가 들어가며 차례대로 1호가, 2호가 ... 15호가의 정보를 담고 있습니다.

    # ask 주문 (매도)
    balance = upbit.get_balance(ticker)
    if balance * ask_target_price >= min_KRW_quantity:
        ask_order = get_order_new(ticker, 'ask')
        if ask_order == None: # 미체결 주문이 없으면
            # print('orderbook: ', orderbook)
            quantity = round(KRW_quantity / bid_target_price, 8) # 매수 수량으로 팔아야 수량이 쌓이지 않는다.
            if balance < quantity * 2:
                quantity = balance
            upbit.sell_limit_order(ticker, ask_target_price, quantity)
            print(ticker, 'new ask order. price:', ask_target_price)
        else: # 미체결 주문이 있으면
            old_ask_price = float(upbit.get_order(ask_order)['price'])
            print('old ask price: ', old_ask_price)
            if old_ask_price > ask_target_price * (1 + spread / 2):
                upbit.cancel_order(ask_order)
                print('ask order cancel', old_ask_price)

    # bid 주문 (매수)
    balance = upbit.get_balance('KRW')
    if balance >= KRW_quantity:
        bid_order = get_order_new(ticker, 'bid')
        if bid_order == None: # 미체결 주문이 없으면
            quantity = round(KRW_quantity / bid_target_price, 8)
            upbit.buy_limit_order(ticker, bid_target_price, quantity)
            print(ticker, 'new bid order. price:', bid_target_price)
        else: # 미체결 주문이 있으면
            old_bid_price = float(upbit.get_order(bid_order)['price'])
            print('old bid price: ', old_bid_price)
            if old_bid_price < bid_target_price / (1 + spread / 2):
                upbit.cancel_order(bid_order)
                print('bid order cancel', old_bid_price)

def loop_make():
    cancel_all()
    while True:
        print()
        print('upbitmm')
        t = time.localtime()
        print(time.strftime("%H:%M:%S", t))

        for ticker in tickers:
            print('*', ticker, pyupbit.get_current_price(ticker))
            #make_market(ticker)
            try:
                make_market(ticker)
            except Exception as e:
                #print(e)
                print(traceback.format_exc())
                time.sleep(1)
            time.sleep(1 / 8 * 2) # 주문은 초당 8회, 분당 200회 / 주문 외 요청은 초당 30회, 분당 900회 사용 가능합니다.
        time.sleep(order_interval)

loop_make()

흔한 마켓 메이킹 알고리즘이다.

 

참고: 33. 단순 마켓메이킹 (Market Making) 전략 : 네이버 블로그 (naver.com)

 

33. 단순 마켓메이킹 (Market Making) 전략

알고리즘 트레이딩 (Algorithmic Trading) - 전략 (33) 단순 마켓메이킹 (Market Making) 전략 상대호...

blog.naver.com