204 lines
5.5 KiB
Python
204 lines
5.5 KiB
Python
#!/usr/bin/env python3
|
|
|
|
import argparse
|
|
from collections import deque
|
|
from enum import Enum
|
|
import time
|
|
import socket
|
|
import json
|
|
from state import StateManager
|
|
from order import OrderManager
|
|
|
|
team_name = "HanyangFloorFunction"
|
|
|
|
MAX_ARBS = 5
|
|
XLF_SIZE = 50
|
|
VALE_SIZE = 50
|
|
|
|
|
|
def main():
|
|
args = parse_arguments()
|
|
exchange = ExchangeConnection(args=args)
|
|
|
|
hello_message = exchange.read_message()
|
|
print("First message:", hello_message)
|
|
|
|
state = StateManager()
|
|
om = OrderManager(exchange)
|
|
|
|
market_open = False
|
|
xlf_pending = {}
|
|
|
|
def next_id():
|
|
return om.next_order()
|
|
|
|
# ---------------- BOND ----------------
|
|
def place_bond_orders():
|
|
if not market_open:
|
|
return
|
|
|
|
bid = state.bid_prices["BOND"]
|
|
ask = state.ask_prices["BOND"]
|
|
|
|
if bid is None or ask is None:
|
|
return
|
|
|
|
buy_price = bid + 1
|
|
sell_price = ask - 1
|
|
|
|
size = 100
|
|
|
|
exchange.send_add_message(next_id(), "BOND", Dir.BUY, buy_price, size)
|
|
exchange.send_add_message(next_id(), "BOND", Dir.SELL, sell_price, size)
|
|
|
|
# ---------------- XLF ----------------
|
|
def try_xlf_arb():
|
|
if not market_open:
|
|
return
|
|
|
|
if len(xlf_pending) >= MAX_ARBS:
|
|
return
|
|
|
|
bond_ask = state.ask_prices["BOND"]
|
|
gs_ask = state.ask_prices["GS"]
|
|
ms_ask = state.ask_prices["MS"]
|
|
wfc_ask = state.ask_prices["WFC"]
|
|
xlf_bid = state.bid_prices["XLF"]
|
|
|
|
bond_bid = state.bid_prices["BOND"]
|
|
gs_bid = state.bid_prices["GS"]
|
|
ms_bid = state.bid_prices["MS"]
|
|
wfc_bid = state.bid_prices["WFC"]
|
|
xlf_ask = state.ask_prices["XLF"]
|
|
|
|
if None in [bond_ask, gs_ask, ms_ask, wfc_ask, xlf_bid,
|
|
bond_bid, gs_bid, ms_bid, wfc_bid, xlf_ask]:
|
|
return
|
|
|
|
basket_ask = bond_ask*3 + gs_ask*2 + ms_ask*3 + wfc_ask*2
|
|
basket_bid = bond_bid*3 + gs_bid*2 + ms_bid*3 + wfc_bid*2
|
|
|
|
profit1 = xlf_bid * 10 - basket_ask - 100
|
|
profit2 = basket_bid - xlf_ask * 10 - 100
|
|
|
|
# 🔥 공격 (손해도 감수)
|
|
if profit1 > -50:
|
|
for sym, qty in [("BOND",3),("GS",2),("MS",3),("WFC",2)]:
|
|
oid = next_id()
|
|
exchange.send_add_message(oid, sym, Dir.BUY, state.ask_prices[sym], qty)
|
|
xlf_pending[oid] = qty
|
|
|
|
elif profit2 > -50:
|
|
oid = next_id()
|
|
exchange.send_add_message(oid, "XLF", Dir.BUY, xlf_ask, XLF_SIZE)
|
|
xlf_pending[oid] = XLF_SIZE
|
|
|
|
# ---------------- VALE ----------------
|
|
def try_vale_arb():
|
|
if not market_open:
|
|
return
|
|
|
|
vale_bid = state.bid_prices["VALE"]
|
|
vale_ask = state.ask_prices["VALE"]
|
|
valbz_bid = state.bid_prices["VALBZ"]
|
|
valbz_ask = state.ask_prices["VALBZ"]
|
|
|
|
if None in [vale_bid, vale_ask, valbz_bid, valbz_ask]:
|
|
return
|
|
|
|
profit1 = vale_bid - valbz_ask - 10
|
|
profit2 = valbz_bid - vale_ask - 10
|
|
|
|
if profit1 > -5:
|
|
exchange.send_add_message(next_id(), "VALBZ", Dir.BUY, valbz_ask, VALE_SIZE)
|
|
|
|
elif profit2 > -5:
|
|
exchange.send_add_message(next_id(), "VALE", Dir.BUY, vale_ask, VALE_SIZE)
|
|
|
|
# ---------------- MAIN LOOP ----------------
|
|
while True:
|
|
message = exchange.read_message()
|
|
|
|
if message["type"] == "close":
|
|
print("Round ended")
|
|
break
|
|
|
|
elif message["type"] == "open":
|
|
print("Market opened")
|
|
market_open = True
|
|
place_bond_orders()
|
|
|
|
elif message["type"] == "fill":
|
|
sym = message["symbol"]
|
|
qty = message["size"]
|
|
dir_ = message["dir"]
|
|
|
|
if dir_ == Dir.BUY:
|
|
om.update_position(sym, message["order_id"], qty)
|
|
else:
|
|
om.update_position(sym, message["order_id"], -qty)
|
|
|
|
print("Position:", om.positions)
|
|
|
|
elif message["type"] == "book":
|
|
sym = message["symbol"]
|
|
|
|
state.update_bid_ask_price(
|
|
sym,
|
|
message["buy"][0][0] if message["buy"] else None,
|
|
message["sell"][0][0] if message["sell"] else None
|
|
)
|
|
|
|
# 핵심 실행
|
|
try_xlf_arb()
|
|
try_vale_arb()
|
|
place_bond_orders()
|
|
|
|
|
|
class Dir(str, Enum):
|
|
BUY = "BUY"
|
|
SELL = "SELL"
|
|
|
|
|
|
class ExchangeConnection:
|
|
def __init__(self, args):
|
|
self.exchange_hostname = args.exchange_hostname
|
|
self.port = args.port
|
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
sock.connect((self.exchange_hostname, self.port))
|
|
self.reader = sock.makefile("r", 1)
|
|
self.writer = sock
|
|
self._write({"type": "hello", "team": team_name})
|
|
|
|
def read_message(self):
|
|
msg = json.loads(self.reader.readline())
|
|
if "dir" in msg:
|
|
msg["dir"] = Dir(msg["dir"])
|
|
return msg
|
|
|
|
def send_add_message(self, order_id, symbol, dir, price, size):
|
|
self._write({
|
|
"type": "add",
|
|
"order_id": order_id,
|
|
"symbol": symbol,
|
|
"dir": dir,
|
|
"price": price,
|
|
"size": size,
|
|
"tif": "DAY"
|
|
})
|
|
|
|
def _write(self, msg):
|
|
self.writer.send((json.dumps(msg) + "\n").encode())
|
|
|
|
|
|
def parse_arguments():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--test", required=True)
|
|
args = parser.parse_args()
|
|
args.exchange_hostname = "test-exch-" + team_name
|
|
args.port = 22000
|
|
return args
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |