diff --git a/new_prac.py b/new_prac.py index 754958c..8915969 100644 --- a/new_prac.py +++ b/new_prac.py @@ -5,18 +5,18 @@ from state import StateManager team_name = "HanyangFloorFunction" -# 🔥 핵심 파라미터 -ORDER_SIZE = 5 -MAX_POS = 50 -KILL_POS = 70 -ARB_THRESHOLD = 6 -REFRESH = 0.5 +# ===== 튜닝 ===== +ORDER_SIZE = 3 +MAX_POS = 30 +KILL_POS = 40 +REFRESH = 0.4 +ARB_THRESHOLD = 15 class Dir(str, Enum): BUY = "BUY" SELL = "SELL" -# ===================== +# ====================== class ExchangeConnection: def __init__(self, args): s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) @@ -26,41 +26,51 @@ class ExchangeConnection: self._write({"type": "hello", "team": team_name.upper()}) def read(self): - m = json.loads(self.reader.readline()) - if "dir" in m: - m["dir"] = Dir(m["dir"]) - return m - - def send(self, m): - self.writer.send((json.dumps(m)+"\n").encode()) + msg = json.loads(self.reader.readline()) + if "dir" in msg: + msg["dir"] = Dir(msg["dir"]) + return msg def add(self, oid, sym, d, px, sz, tif="DAY"): - self.send({"type":"add","order_id":oid,"symbol":sym,"dir":d,"price":px,"size":sz,"tif":tif}) + self._write({ + "type":"add","order_id":oid, + "symbol":sym,"dir":d,"price":px,"size":sz,"tif":tif + }) def ioc(self, oid, sym, d, px, sz): self.add(oid, sym, d, px, sz, "IOC") def cancel(self, oid): - self.send({"type":"cancel","order_id":oid}) + self._write({"type":"cancel","order_id":oid}) def convert(self, oid, sym, d, sz): - self.send({"type":"convert","order_id":oid,"symbol":sym,"dir":d,"size":sz}) + self._write({ + "type":"convert","order_id":oid, + "symbol":sym,"dir":d,"size":sz + }) -# ===================== + def _write(self, msg): + self.writer.send((json.dumps(msg)+"\n").encode()) + +# ====================== def parse_arguments(): - p = argparse.ArgumentParser() - g = p.add_mutually_exclusive_group(required=True) - g.add_argument("--production", action="store_true") - g.add_argument("--test", type=str, default="prod-like") - a = p.parse_args() + parser = argparse.ArgumentParser() + group = parser.add_mutually_exclusive_group(required=True) + group.add_argument("--production", action="store_true") + group.add_argument("--test", type=str, default="prod-like") - if a.production: - a.exchange_hostname, a.port = "production", 25000 + args = parser.parse_args() + + if args.production: + args.exchange_hostname = "production" + args.port = 25000 else: - a.exchange_hostname, a.port = "test-exch-"+team_name, 22000 - return a + args.exchange_hostname = "test-exch-" + team_name + args.port = 22000 -# ===================== + return args + +# ====================== def main(): args = parse_arguments() ex = ExchangeConnection(args) @@ -71,50 +81,30 @@ def main(): oid = 0 def nid(): - nonlocal oid; oid += 1; return oid + nonlocal oid + oid += 1 + return oid active = {} last_refresh = 0 - # 🔥 imbalance 계산 - def imbalance(sym): - bid = st.bid_depths.get(sym, 0) - ask = st.ask_depths.get(sym, 0) - return bid - ask - - # 🔥 alpha 방향 결정 - def alpha(sym): - imb = imbalance(sym) - if imb > 0: - return 1 # 상승 - elif imb < 0: - return -1 # 하락 - return 0 - - # 🔥 Adaptive MM + # ===== Market Making ===== def market_make(sym): - b = st.bid_prices.get(sym) - a = st.ask_prices.get(sym) - if b is None or a is None: + bid = st.bid_prices.get(sym) + ask = st.ask_prices.get(sym) + + if bid is None or ask is None: + return + + if ask - bid < 2: return p = pos.get(sym, 0) if abs(p) > MAX_POS: return - spread = a - b - direction = alpha(sym) - - # 🔥 방향 반영 - if direction > 0: - buy_px = b + 2 - sell_px = a - 1 - elif direction < 0: - buy_px = b + 1 - sell_px = a - 2 - else: - buy_px = b + 1 - sell_px = a - 1 + buy_px = bid + 1 + sell_px = ask - 1 if buy_px >= sell_px: return @@ -122,15 +112,16 @@ def main(): buy_sz = ORDER_SIZE sell_sz = ORDER_SIZE + # 포지션 조절 if p > 0: sell_sz += 2 elif p < 0: buy_sz += 2 - o = nid(); ex.add(o, sym, Dir.BUY, buy_px, buy_sz); active[o]=sym - o = nid(); ex.add(o, sym, Dir.SELL, sell_px, sell_sz); active[o]=sym + o = nid(); ex.add(o, sym, Dir.BUY, buy_px, buy_sz); active[o] = sym + o = nid(); ex.add(o, sym, Dir.SELL, sell_px, sell_sz); active[o] = sym - # 🔥 XLF arb (유지) + # ===== XLF Arb ===== def xlf_arb(): bond_ask = st.ask_prices.get("BOND") gs_ask = st.ask_prices.get("GS") @@ -138,13 +129,21 @@ def main(): wfc_ask = st.ask_prices.get("WFC") xlf_bid = st.bid_prices.get("XLF") - if None in [bond_ask, gs_ask, ms_ask, wfc_ask, xlf_bid]: + bond_bid = st.bid_prices.get("BOND") + gs_bid = st.bid_prices.get("GS") + ms_bid = st.bid_prices.get("MS") + wfc_bid = st.bid_prices.get("WFC") + xlf_ask = st.ask_prices.get("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 + # 케이스 1 cost = bond_ask*3 + gs_ask*2 + ms_ask*3 + wfc_ask*2 - profit = xlf_bid*10 - cost + profit1 = xlf_bid*10 - cost - if profit > ARB_THRESHOLD: + if profit1 > ARB_THRESHOLD: ex.ioc(nid(),"BOND",Dir.BUY,bond_ask,3) ex.ioc(nid(),"GS",Dir.BUY,gs_ask,2) ex.ioc(nid(),"MS",Dir.BUY,ms_ask,3) @@ -152,39 +151,50 @@ def main(): ex.convert(nid(),"XLF",Dir.BUY,10) ex.ioc(nid(),"XLF",Dir.SELL,xlf_bid,10) - # 🔥 리스크 컷 + # 케이스 2 + revenue = bond_bid*3 + gs_bid*2 + ms_bid*3 + wfc_bid*2 + profit2 = revenue - xlf_ask*10 + + if profit2 > ARB_THRESHOLD: + ex.ioc(nid(),"XLF",Dir.BUY,xlf_ask,10) + ex.convert(nid(),"XLF",Dir.SELL,10) + ex.ioc(nid(),"BOND",Dir.SELL,bond_bid,3) + ex.ioc(nid(),"GS",Dir.SELL,gs_bid,2) + ex.ioc(nid(),"MS",Dir.SELL,ms_bid,3) + ex.ioc(nid(),"WFC",Dir.SELL,wfc_bid,2) + + # ===== Risk ===== def risk(): - for s, p in pos.items(): + for sym, p in pos.items(): if abs(p) > KILL_POS: - if p > 0: - ex.ioc(nid(), s, Dir.SELL, st.bid_prices.get(s,1), abs(p)) - else: - ex.ioc(nid(), s, Dir.BUY, st.ask_prices.get(s,99999), abs(p)) + bid = st.bid_prices.get(sym) + ask = st.ask_prices.get(sym) - # ================= LOOP ================= + if p > 0 and bid: + ex.ioc(nid(), sym, Dir.SELL, bid, abs(p)) + elif p < 0 and ask: + ex.ioc(nid(), sym, Dir.BUY, ask, abs(p)) + + # ===== LOOP ===== while True: - m = ex.read() + msg = ex.read() - if m["type"] == "close": + if msg["type"] == "close": break - elif m["type"] == "book": - sym = m["symbol"] + elif msg["type"] == "book": + sym = msg["symbol"] - b = m["buy"][0][0] if m["buy"] else None - a = m["sell"][0][0] if m["sell"] else None + bid = msg["buy"][0][0] if msg["buy"] else None + ask = msg["sell"][0][0] if msg["sell"] else None - st.update_bid_ask_price(sym, b, a) - st.update_depth(sym, - m["buy"][0][1] if m["buy"] else 0, - m["sell"][0][1] if m["sell"] else 0 - ) + st.update_bid_ask_price(sym, bid, ask) now = time.time() if now - last_refresh > REFRESH: last_refresh = now - # 전체 cancel + # 모든 주문 취소 for o in list(active.keys()): ex.cancel(o) active.pop(o, None) @@ -195,13 +205,19 @@ def main(): xlf_arb() risk() - elif m["type"] == "fill": - s, q, d = m["symbol"], m["size"], m["dir"] - pos[s] += q if d == Dir.BUY else -q + elif msg["type"] == "fill": + sym = msg["symbol"] + qty = msg["size"] - # 🔥 초고속 재주문 - if s in ["GS","MS","WFC"]: - market_make(s) + if msg["dir"] == Dir.BUY: + pos[sym] += qty + else: + pos[sym] -= qty + # 체결 즉시 재주문 + if sym in ["GS","MS","WFC"]: + market_make(sym) + +# ====================== if __name__ == "__main__": main() \ No newline at end of file