From 90a024fa8311c12ae5b82c0236e8f9738d16a936 Mon Sep 17 00:00:00 2001 From: khwkim1111 Date: Sat, 9 May 2026 15:43:33 +0900 Subject: [PATCH] commit --- bot bond sell.py | 97 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 64 insertions(+), 33 deletions(-) diff --git a/bot bond sell.py b/bot bond sell.py index 4e5b399..f8a9153 100644 --- a/bot bond sell.py +++ b/bot bond sell.py @@ -46,17 +46,22 @@ def main(): # pick? Also, you will need to send more orders over time. # --- 설정 --- BOND_FAIR_VALUE = 1000 # BOND fair value (고정) - BOND_ORDER_SIZE = 30 # BOND 주문당 수량 + BOND_ORDER_SIZE = 80 # BOND 주문당 수량 (크게 설정해서 체결 기회 극대화) XLF_CONVERSION_FEE = 100 # XLF 변환 비용 VALE_CONVERSION_FEE = 10 # VALE 변환 비용 + VALE_ARB_SIZE = 10 # VALE 차익거래 단위 (포지션 한도 10) REFRESH_INTERVAL = 5.0 # 주문 갱신 주기 (초) # XLF state machine + # IDLE → BUYING_BASKET → CONVERTING → SELLING_XLF → IDLE (바스켓→XLF) + # IDLE → BUYING_XLF → CONVERTING → SELLING_BASKET → IDLE (XLF→바스켓) xlf_state = "IDLE" xlf_pending = {} xlf_direction = None # VALE state machine + # IDLE → BUYING_VALBZ → CONVERTING → SELLING_VALE → IDLE + # IDLE → BUYING_VALE → CONVERTING → SELLING_VALBZ → IDLE vale_state = "IDLE" vale_pending = {} vale_direction = None @@ -66,8 +71,8 @@ def main(): market_open = False active_orders = {} # BOND 전용 {order_id: {"dir": ..., "price": ...}} - last_refresh = time.time() - vale_last_print = time.time() + last_refresh = time.time() + vale_last_print = time.time() def next_id(): return om.next_order() @@ -85,35 +90,44 @@ def main(): cancel_all_bond_orders() - buy_price = BOND_FAIR_VALUE - 1 - sell_price = BOND_FAIR_VALUE + 1 + buy_price = BOND_FAIR_VALUE - 1 # 999 + sell_price = BOND_FAIR_VALUE + 1 # 1001 position = om.positions["BOND"] + # 포지션에 따라 size 비대칭 조정 base_size = BOND_ORDER_SIZE adjustment = abs(position) // 5 if position < 0: + # 숏 포지션 → 매수를 더 많이 buy_size = min(base_size + adjustment, 100 - position) sell_size = max(base_size - adjustment, 1) elif position > 0: + # 롱 포지션 → 매도를 더 많이 buy_size = max(base_size - adjustment, 1) sell_size = min(base_size + adjustment, 100 + position) else: buy_size = base_size sell_size = base_size - bid = next_id() - if exchange.send_add_message( - order_id=bid, symbol="BOND", - dir=Dir.BUY, price=buy_price, size=buy_size - ) is not False: + # 포지션 한도 초과 방지 + buy_size = min(buy_size, 100 - position) + sell_size = min(sell_size, 100 + position) + + if buy_size > 0: + bid = next_id() + exchange.send_add_message( + order_id=bid, symbol="BOND", + dir=Dir.BUY, price=buy_price, size=buy_size + ) active_orders[bid] = {"dir": Dir.BUY, "price": buy_price} - ask = next_id() - if exchange.send_add_message( - order_id=ask, symbol="BOND", - dir=Dir.SELL, price=sell_price, size=sell_size - ) is not False: + if sell_size > 0: + ask = next_id() + exchange.send_add_message( + order_id=ask, symbol="BOND", + dir=Dir.SELL, price=sell_price, size=sell_size + ) active_orders[ask] = {"dir": Dir.SELL, "price": sell_price} print(f" BOND 주문 → 매수:{buy_price} x{buy_size}, 매도:{sell_price} x{sell_size}, 포지션:{position}") @@ -168,7 +182,7 @@ def main(): xlf_pending[oid] = 10 def handle_xlf_fill(order_id, symbol, dir_, qty): - """XLF state machine 체결 처리""" + """XLF state machine 체결 처리 (부분 체결 추적)""" nonlocal xlf_state, xlf_pending if order_id not in xlf_pending: @@ -203,31 +217,37 @@ def main(): if None in [vale_bid, vale_ask, valbz_bid, valbz_ask]: return + # 포지션 한도 내에서 최대 size 계산 + valbz_pos = om.positions["VALBZ"] + vale_pos = om.positions["VALE"] + # 케이스 1: VALE가 비쌀 때 → VALBZ 매수 → VALE 변환 → VALE 매도 profit1 = vale_bid - valbz_ask - VALE_CONVERSION_FEE - if profit1 > 0 and om.check_pos_limit("VALBZ"): - print(f" VALE 차익(VALBZ→VALE) 시작, 예상수익:{profit1}") + arb_size1 = min(VALE_ARB_SIZE, 10 - valbz_pos) + if profit1 > 0 and arb_size1 > 0: + print(f" VALE 차익(VALBZ→VALE) 시작, 예상수익:{profit1 * arb_size1}, size:{arb_size1}") vale_state = "BUYING_VALBZ" vale_direction = "VALBZ_TO_VALE" vale_pending.clear() oid = next_id() - exchange.send_add_message(oid, "VALBZ", Dir.BUY, valbz_ask, 1) - vale_pending[oid] = 1 + exchange.send_add_message(oid, "VALBZ", Dir.BUY, valbz_ask, arb_size1) + vale_pending[oid] = arb_size1 return # 케이스 2: VALBZ가 비쌀 때 → VALE 매수 → VALBZ 변환 → VALBZ 매도 profit2 = valbz_bid - vale_ask - VALE_CONVERSION_FEE - if profit2 > 0 and om.check_pos_limit("VALE"): - print(f" VALE 차익(VALE→VALBZ) 시작, 예상수익:{profit2}") + arb_size2 = min(VALE_ARB_SIZE, 10 - vale_pos) + if profit2 > 0 and arb_size2 > 0: + print(f" VALE 차익(VALE→VALBZ) 시작, 예상수익:{profit2 * arb_size2}, size:{arb_size2}") vale_state = "BUYING_VALE" vale_direction = "VALE_TO_VALBZ" vale_pending.clear() oid = next_id() - exchange.send_add_message(oid, "VALE", Dir.BUY, vale_ask, 1) - vale_pending[oid] = 1 + exchange.send_add_message(oid, "VALE", Dir.BUY, vale_ask, arb_size2) + vale_pending[oid] = arb_size2 def handle_vale_fill(order_id, symbol, dir_, qty): - """VALE state machine 체결 처리""" + """VALE state machine 체결 처리 (부분 체결 추적)""" nonlocal vale_state, vale_pending if order_id not in vale_pending: @@ -238,19 +258,22 @@ def main(): del vale_pending[order_id] if vale_state == "BUYING_VALBZ" and not vale_pending: - print(" VALBZ 매수 완료 → VALE 변환 시작") + # 체결된 수량만큼 변환 + size = qty # 마지막 체결 수량 대신 전체 수량 필요 → arb_size 저장 필요 + print(f" VALBZ 매수 완료 → VALE 변환 시작") vale_state = "CONVERTING" - exchange.send_convert_message(next_id(), "VALE", Dir.BUY, 1) + exchange.send_convert_message(next_id(), "VALE", Dir.BUY, qty) elif vale_state == "BUYING_VALE" and not vale_pending: - print(" VALE 매수 완료 → VALBZ 변환 시작") + print(f" VALE 매수 완료 → VALBZ 변환 시작") vale_state = "CONVERTING" - exchange.send_convert_message(next_id(), "VALE", Dir.SELL, 1) + exchange.send_convert_message(next_id(), "VALE", Dir.SELL, qty) # Set up some variables to track the bid and ask price of a symbol. Right # now this doesn't track much information, but it's enough to get a sense # of the VALE market. vale_last_print_time = time.time() + vale_arb_total_size = 0 # 변환할 총 수량 추적 # Here is the main loop of the program. It will continue to read and # process messages in a loop until a "close" message is received. You @@ -327,17 +350,25 @@ def main(): if vale_direction == "VALBZ_TO_VALE": vale_state = "SELLING_VALE" oid = next_id() + # 변환된 수량 = VALBZ 매수 수량 + converted = sum( + v for v in vale_pending.values() + ) if vale_pending else VALE_ARB_SIZE + sell_size = abs(om.positions["VALE"]) + sell_size = min(sell_size, 10) exchange.send_add_message( - oid, "VALE", Dir.SELL, state.bid_prices["VALE"], 1 + oid, "VALE", Dir.SELL, state.bid_prices["VALE"], sell_size ) - vale_pending[oid] = 1 + vale_pending[oid] = sell_size elif vale_direction == "VALE_TO_VALBZ": vale_state = "SELLING_VALBZ" oid = next_id() + sell_size = abs(om.positions["VALBZ"]) + sell_size = min(sell_size, 10) exchange.send_add_message( - oid, "VALBZ", Dir.SELL, state.bid_prices["VALBZ"], 1 + oid, "VALBZ", Dir.SELL, state.bid_prices["VALBZ"], sell_size ) - vale_pending[oid] = 1 + vale_pending[oid] = sell_size elif message["type"] == "fill": print(message)