From 5f7e000de3697026c80317a9a355568006f35576 Mon Sep 17 00:00:00 2001 From: perror_MacBookPro Date: Sun, 10 May 2026 16:08:46 +0900 Subject: [PATCH] last --- .DS_Store | Bin 0 -> 8196 bytes bot split/__pycache__/ETC.cpython-313.pyc | Bin 0 -> 6558 bytes .../__pycache__/order_new.cpython-313.pyc | Bin 0 -> 3403 bytes .../__pycache__/position.cpython-313.pyc | Bin 0 -> 1199 bytes bot split/__pycache__/value.cpython-313.pyc | Bin 0 -> 1744 bytes bot split/bot split.py | 10 + prac copy.py | 228 ++++++++++++++++++ 7 files changed, 238 insertions(+) create mode 100644 .DS_Store create mode 100644 bot split/__pycache__/ETC.cpython-313.pyc create mode 100644 bot split/__pycache__/order_new.cpython-313.pyc create mode 100644 bot split/__pycache__/position.cpython-313.pyc create mode 100644 bot split/__pycache__/value.cpython-313.pyc create mode 100644 prac copy.py diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..188f8278b7ffeb61dbf36f1b4e645db9784dbff9 GIT binary patch literal 8196 zcmeHMTWl3Y7@mJy=&T#)w1VAUz@tYHNP$y8pj;29ty~JW>1pYOOWAXFfeqW;dUnq# z*fdrj0e#dMHE7~3G2#m%(Rg{#1RwMPPf+xQL|;sN@t$Zj{xh?u=?&gApgYOVKRf?r z=Ks(4&-C9CLLikln+VYfArv1@nTFjgjq~|4qbcD`IZ{Ahal8U1PJ5d54H$Jk2ulo*>d23AaiqzRj!P=l2}pGU;mQzJC?Hlxy_gUu zkd!p)qXB_{J}Su&j|7-;lj?VWIOBL3uzC9!ekg zM$&;1?2<>g(|7rJT5 zpej`dnLawYp?Q5{tf?t6))*UYUXy5yty{Z(Y)qvKarXounShJ5m^2ptMt*)-C57= z%vl9=us7>D`5_lMRawKy=26(%;W%mg5hprjQw!l4o-<# zZLtY{I^A^2LAMlSGIjds?QAXKisj&;^#qWh2uGD7QftSPmaizUzuAiIRVVV<` zI`uBpV76PZ5!V=M32(}-P#Q0RE1p~-hw%?jB*jR?G@eYz=>?KZ^!#31L=q%L_K?H) zb?g*5L!Kh%$OZBixkx@HpOI_i8}c3bf&5B-BfpbBpd98v1yHDhI;e+5uo&Xd2+gn= zw!l_+5V{}@-EasF!x1pxD0q;E0-S_X@Hm`?Gw=jF2~Wcd@FKhfFT;6w58j6l;4*v; zMYsxIz;*Z$euAIjPo+YkimFsAOO&O`GG)24LRqV9QQDL}N?Pt;DdpCI34g>uF_Fx2 zYG7`Kr-t(8?77vjbJy-Y?R#(8+`2YjWYdC$ch$s}V2W+rnwmhPgl`G4lTj}+WlDkw z;0t6-Lv2y7t*dX)7T;Y;$?2)ugBfF;q#XLJB9xBbM=@*IobYwoa(r!PbLDHp%2kxI zbF8dbUstOqnlz08X0KY*>uT$@l?@wI$`rwC-lR3Ka!gAqG&L=`L*<77BPC01Xz3pV z`zPcI`I1~G-y_)nf-;174a8s>tbvWN4YorPTA&Rcf)40JkV}XUBE+-cz!11F3^^Eu zF?bZl;V}XAvjXbRz_aiiJP)tHtMD4U4sXCkcpEOkJMb=i1fL@4zlLw80eat5K*KMy z1G*?NB94vGWb7y G|Njl>Ol2Mb literal 0 HcmV?d00001 diff --git a/bot split/__pycache__/ETC.cpython-313.pyc b/bot split/__pycache__/ETC.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6956715117e77572b6b5a983375ed352c334b817 GIT binary patch literal 6558 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 literal 0 HcmV?d00001 diff --git a/bot split/__pycache__/order_new.cpython-313.pyc b/bot split/__pycache__/order_new.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d2e5b1b3cda3c83eb656516e5e962e5dac2efbd9 GIT binary patch literal 3403 zcmcH+OKcn0@$D`@D}GE`ABVN2YGqS)*097_mR-nbZN#=zN3NAtYbHdjc1w|KcI)Mm zdAp3Q9*Pt-0yQe&T!gZK3#e#XSU?UekODsB5agsIX{C^`MbH4v#ia}ok&4`k&b;ME z64dt6K7cdt&CHvf&zpIV+u?A4z_?ibr#>MP@;6+xhNn5%z7CURq7a3LzwnZ&$O3%+1hi%H|?i>iNwfpqIi!I#dn@}HBm9g$^K`!n2|Zho7LVdX)^D0 zPu|b`C~fAns|C~4GPYhY9pRczK_>Fuf~6zjX4*{WG@5ZWxiHjRZ2ti!%VdsFP9c<6 zI4UUooJSGnyyG6lbCmqpLw#rp^(($PQSrl1oa<7$<^oCpe!;omct{B`xzK*@xTu5~ zCwu_s5aS$bb3og;Pl+&UM2W(RR}QmPROzONb3Jme6MB_qHQMy&nGZ~NM6DSBCs^$G zn-QA+A;M(fdV31MGD$@Z!0u4EBr&+w>bAEvQ+P#~KweuIiI{TqzgH3$H_5UpF&qidh z78$IHgS3z7OtbP)?S-P|_^gHee8F&ptWF(ok?I)@QU&RBd{nbb)Xd=NYYhw^i@>{J z<1)G3q95qradN)NH+{Ep7aI_Z_W5ej2sz)3v%+0W5t5D(lKSC6ate<}cLWZf=}-C< z;UYvS4SRE*B&T@U-eUwZGrQaB=4WQRI^S!}QYTWAif_Urkyl>^4gUY40nhTju}gyl z8bqey=)biAPR9Px(Qt5VW--0{M$*@cm_%}2a-g&T0)egHeN_M8iL|xyVC$XVZvEzg zw6*l8{_w%`<<0uOi zf1B9r5?y6&sxMtELNAg3J zZO+lXRk)ki1ADDM0eGA21W2Ukq5iJEbazqsB6w)g-iX9&k@$LW_;JsA@XY3suWj_7 zt@WR+4AuI_Ye&Wxzr7hbQtn;)>E;Xl4Ic@;P##_n4sM2`4{!eB=0@mrEp)naa;>i# zI{h^C#%4HHzP=ugx7j1L&`9OAwaIE|xnF?^HoVzpnZmL?@M@WDmv@`oF8)+^YFyzb zd~vcW%+MhakiCxRc5OX-P)1gHdIrQObOEyJb+dQCF|yFqU3tPA#&8brNe_}vgV^>- z0MH$=84lGVLo36T_{P|k+Srx#v1@CuRkM0EGE|L}s$%K?9tN5KTj*H?V*vKMAcUeY^s%S8mnK7B>D-re* zg6U^|<9+@gPA3O`@vdJe370Jz00gbJoANu;T8^>NWXyq6G@pXeX0r%GF#7JH>3J| z$<{1YU3Jfsn=w2{6ajw7`UJo`q`~{Vr>aBe8U*mii5)~=MtQH)5c|Bnk9!&fP$k3A z#{xrZR~f3l{)UUy%nk}QMmg_WTp2VWUQt|J0S&l*a&?E{hL1^|Xi9-9TvtFdlRDRt z%5&umQuEwn#?5mT#?5o6<8s;h3YeGOvx82_T{I5J31$k0;r@fL+&8NL4@x(}ESh5L zeeDLEMP(9px~kZ-O#G&sxJ&dEU|>_UuofBu$8mol!OzIRU&*P@Nc=0$D0lfw0)TD) E7Yr2f@&Et; literal 0 HcmV?d00001 diff --git a/bot split/__pycache__/position.cpython-313.pyc b/bot split/__pycache__/position.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..aa04842bcb540d9b3f0a1afdc01fc3f968390cd2 GIT binary patch literal 1199 zcmZ`(%}*0S6rcTQyEN2lKcIYtjRAE@qz2K05hEa&A{63KG=^ldl%-iM+d4Ci;Xpz> z7&#ccH1Wu_H~$og9GW?qcnj z!}_{^Qpdi2^jfC@X_-{9zo8j8K)Z5=)g{6!1?F(q#s4X*_)l zP=>s)3R7uKZ9I@cdGIs`*8iDJ?|HNwvV7^Jk>dwduu~ zS3(CdC$tyyvqF2hIA4>YE2_A%vW!!!spT|TOf98Wg;8v!ZYe@%PJWBYi%jt>nPCoP z$)ZDPfhOM-=o?nFvrckubvC(Rdk*H*akvSpIdNy=esTdz&qjfpteAIsvK@E4xFZZg zT+ii%h(t%F#@im*3^on0hknF*tC5&o@kAAPv{x^%#oxR3lNjfW+d} zXbcu?=z|TPLZ=V}2|wG}-YDdS@wQ}p+~qr2S^oBrw>8=^0i=vF=y}_7NoJHObxQSt zC8ORBL3$cfZ-SOX6(wC!Xau;W(I^NiKRen7z+_m{G-(W^2$zbRHg`z77-G2d{T&-* z9M%J{hpI;RL1;hpdF#6|beK3YtYc${_JS+h`lNv(BzfZ{CXoNXM80AK(E$*25WrF| z@@6tdJLB%0!!Obu>`eEvR|aF(03g?J^k8>?_siN*c;uTg(nynD1y|Y%%I1b_3u8I#DCOVEvZj8#~O_5s0t&w-j~1;u}4@dj@>88A2XP qTkt0!qgWDT(VP7=9yarTM907;e<>^sP}dYiIrH}^qbCTUao{hrpcOO# literal 0 HcmV?d00001 diff --git a/bot split/__pycache__/value.cpython-313.pyc b/bot split/__pycache__/value.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7b5c95f3fed5b99c8e3f43104ee858c5d2deda0b GIT binary patch literal 1744 zcmcIl&2JM&6o30+d$TyW`LIb%k=Br;+DlxeA*Twdq@)Oekr*7JD$;0UHr5u$HZz+d zIB}|)Lls{v<;aoT+W(|fAceVd;^tx`Zix5B-jEm$J+$xe-tWCPJM)`2Z)W@B<1V25 z`SN{aTL7=fNyHw4{tSXH%)ohIPy}XNGzS?0b z`|{1o56b+JDf0$XskQH~U;atiXs#&h&gzP?)~~M~7%KG(aq|sj%doK}iI=CYma8%p zvfK`ZXo>QJmbfR|K`ks_xxG@p7BoW^i!h8mbiKuI7MIJ{7-cqFu_xP&C@$+s7upY% z!+F$lgd_m`?^PT&h<->vb zXJV}2{$~H~_HhPKY58z_v(-@6W^`9sfxK5sx`on&b(yas=t3249X|vbfwDfC^pQs+ zX#9w*PkkIwhXbSHn<^v2nA4&f;KIHwzQFH9o>YO<8B~%ecqn25ff}Q)bfr|`L~)Md zr|F|2s>g8XWcRYW+0NQ?r*wp0I3+QS>DqCgg!Mi>1YKD7ZlN8Os_`|3>L9*EBWNAp z8lfy{l7y@v7Hawvnz-pn%=BpnBzex;b9dd&^50JJ{~@N!c!Jp3&lAH#(8c#KJ)kmt zAJ7LNtZOunK=%SgN2F?`Fv7H+1>dX)dPsD!4$P0mk~CRzrkVP%6HbPwjxE z%1!M(+I_S?|14K}QhJt~{mYsC&v;UwX`W&h(WeBlI3s6C1Tjj*6x11-ik_l^4;bF! zX0RRNEp|EIZr$B!5YBRbe_vScij6*Xh=70pUrB=jP4 zgnSy3=Um1?9MyOb$0FL?i9^Zx!H@#o6hTL&72R0LQT+;UOgH8BX3W(2Csq&8JiVaJ zA1iOk>p4cMv|sB1ny1!VGQIR?Lv#BzO3zUm@jJqU?bEUqAO8}x{30p3Y=g_|d^f1W aCGjoBG_M?jo@E%uJM*kD_Xbeu4?Y0xi(qX4 literal 0 HcmV?d00001 diff --git a/bot split/bot split.py b/bot split/bot split.py index 13f5b74..d4b62f0 100644 --- a/bot split/bot split.py +++ b/bot split/bot split.py @@ -106,7 +106,17 @@ def on_book(message, man: Manager): man.orderMan.buy(message["symbol"], man.valueMan.get_bid(message["symbol"])-1, 10) else: man.orderMan.sell(message["symbol"], man.valueMan.get_ask(message["symbol"])+1, 10) + elif message["symbol"] == "WLF": + now = time.time() + + if now >= last_print_time+1: + last_print_time = now + if (man.positionMan.get_position("BOND") > 3 and + man.positionMan.get_position("GS") > 2 and + man.positionMan.get_position("MS") > 3 and + man.positionMan.get_position("WFC") > 2): + diff --git a/prac copy.py b/prac copy.py new file mode 100644 index 0000000..f35e029 --- /dev/null +++ b/prac copy.py @@ -0,0 +1,228 @@ +#!/usr/bin/env python3 + +import argparse +from enum import Enum +import socket +import json +from state import StateManager + +team_name = "HanyangFloorFunction" + +# ==================== 설정 ==================== +ORDER_SIZE = 2 +MAX_POS = 20 +ARB_THRESHOLD = 40 + +# ==================== +class Dir(str, Enum): + BUY = "BUY" + SELL = "SELL" + +# ==================== +def main(): + args = parse_arguments() + exchange = ExchangeConnection(args) + + state = StateManager() + hello = exchange.read_message() + + # 포지션 직접 관리 + positions = {} + for sym in hello["symbols"]: + positions[sym["symbol"]] = sym["position"] + + order_id = 0 + def next_id(): + nonlocal order_id + order_id += 1 + return order_id + + active_orders = {} + + # ==================== MARKET MAKING ==================== + def market_make(sym): + bid = state.bid_prices.get(sym) + ask = state.ask_prices.get(sym) + + if bid is None or ask is None: + return + + if ask - bid <= 2: + return + + pos = positions.get(sym, 0) + + if abs(pos) > MAX_POS: + return + + buy_price = bid + 1 + sell_price = ask - 1 + + if buy_price >= sell_price: + return + + # 포지션 조절 + if pos > 0: + buy_size = 1 + sell_size = ORDER_SIZE + 1 + elif pos < 0: + buy_size = ORDER_SIZE + 1 + sell_size = 1 + else: + buy_size = sell_size = ORDER_SIZE + + oid = next_id() + exchange.send_add_message(oid, sym, Dir.BUY, buy_price, buy_size) + active_orders[oid] = sym + + oid = next_id() + exchange.send_add_message(oid, sym, Dir.SELL, sell_price, sell_size) + active_orders[oid] = sym + + # ==================== BOND 안전 수익 ==================== + def bond_arb(): + bid = state.bid_prices.get("BOND") + ask = state.ask_prices.get("BOND") + + if ask and ask < 999: + exchange.send_add_message_ioc(next_id(), "BOND", Dir.BUY, ask, 3) + + if bid and bid > 1001: + exchange.send_add_message_ioc(next_id(), "BOND", Dir.SELL, bid, 3) + + # ==================== XLF 차익거래 (초안전 버전) ==================== + def xlf_arb(): + bond_ask = state.ask_prices.get("BOND") + gs_ask = state.ask_prices.get("GS") + ms_ask = state.ask_prices.get("MS") + wfc_ask = state.ask_prices.get("WFC") + xlf_bid = state.bid_prices.get("XLF") + + bond_bid = state.bid_prices.get("BOND") + gs_bid = state.bid_prices.get("GS") + ms_bid = state.bid_prices.get("MS") + wfc_bid = state.bid_prices.get("WFC") + xlf_ask = state.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 + + 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 + + pos = positions.get("XLF", 0) + + if abs(pos) > 10: + return + + profit1 = xlf_bid * 10 - basket_ask + if profit1 > ARB_THRESHOLD: + exchange.send_add_message_ioc(next_id(), "XLF", Dir.SELL, xlf_bid, 10) + + profit2 = basket_bid - xlf_ask * 10 + if profit2 > ARB_THRESHOLD: + exchange.send_add_message_ioc(next_id(), "XLF", Dir.BUY, xlf_ask, 10) + + # ==================== 리스크 관리 ==================== + def risk(): + for sym in ["GS", "MS", "WFC", "XLF"]: + pos = positions.get(sym, 0) + + if abs(pos) > MAX_POS: + if pos > 0: + exchange.send_add_message_ioc( + next_id(), sym, Dir.SELL, + state.bid_prices.get(sym, 1), abs(pos) + ) + else: + exchange.send_add_message_ioc( + next_id(), sym, Dir.BUY, + state.ask_prices.get(sym, 99999), abs(pos) + ) + + # ==================== LOOP ==================== + while True: + msg = exchange.read_message() + + if msg["type"] == "close": + break + + elif msg["type"] == "book": + sym = msg["symbol"] + + bid = msg["buy"][0][0] if msg["buy"] else None + ask = msg["sell"][0][0] if msg["sell"] else None + + state.update_bid_ask_price(sym, bid, ask) + + for oid in list(active_orders.keys()): + exchange.send_cancel_message(oid) + del active_orders[oid] + + # 전략 실행 + bond_arb() + xlf_arb() + + if sym in ["GS", "MS", "WFC"]: + market_make(sym) + + risk() + + elif msg["type"] == "fill": + qty = msg["size"] + sym = msg["symbol"] + + if msg["dir"] == Dir.BUY: + positions[sym] = positions.get(sym, 0) + qty + else: + positions[sym] = positions.get(sym, 0) - qty + +# ==================== +class ExchangeConnection: + def __init__(self, args): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect((args.exchange_hostname, args.port)) + self.reader = s.makefile("r", 1) + self.writer = s + self._write({"type": "hello", "team": team_name.upper()}) + + 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, oid, sym, dir, price, size): + self._write({"type":"add","order_id":oid,"symbol":sym,"dir":dir,"price":price,"size":size,"tif":"DAY"}) + + def send_add_message_ioc(self, oid, sym, dir, price, size): + self._write({"type":"add","order_id":oid,"symbol":sym,"dir":dir,"price":price,"size":size,"tif":"IOC"}) + + def send_cancel_message(self, oid): + self._write({"type": "cancel", "order_id": oid}) + + def _write(self, msg): + self.writer.send((json.dumps(msg)+"\n").encode()) + +# ==================== +def parse_arguments(): + 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") + + args = parser.parse_args() + + if args.production: + args.exchange_hostname = "production" + args.port = 25000 + else: + args.exchange_hostname = "test-exch-" + team_name + args.port = 22000 + + return args + +if __name__ == "__main__": + main() \ No newline at end of file