https://blog.naver.com/opop4615/222313500451
에 개념적으로 간단하게 잘 되어 있는 마켓 메이킹 봇 소스 코드가 있다.
그런데 거기에 나와 있는 소스 코드는 작동하지 않는다. 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)
'Programming' 카테고리의 다른 글
The history of C# (0) | 2022.06.28 |
---|---|
No module named 'pip' 에러와 함께 pip가 갑자기 안되는 경우 · Tonic (jwgo.kr) (0) | 2022.05.08 |
Visual Studio 2022 Community (0) | 2022.04.27 |
Pandas Tutorial (w3schools.com) (0) | 2022.04.24 |
Pattern-defeating Quicksort (0) | 2022.04.22 |