From 9944b55f94ca14b38296bc63a47fd82f88de9b29 Mon Sep 17 00:00:00 2001 From: joungmin Date: Thu, 5 Mar 2026 22:38:54 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20restore=5Fpositions=EC=97=90=EC=84=9C=20?= =?UTF-8?q?locked=20=EC=9E=94=EA=B3=A0=20=ED=8F=AC=ED=95=A8=20+=20?= =?UTF-8?q?=EA=B8=B0=EC=A1=B4=20=EB=A7=A4=EB=8F=84=EC=A3=BC=EB=AC=B8=20?= =?UTF-8?q?=EC=B7=A8=EC=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - balance + locked으로 보유 수량 판단 (지정가 매도 중이면 locked에 잡힘) - 복구 시 기존 미체결 매도 주문 취소 후 새로 제출 - 취소 후 실제 가용 수량 재조회 Co-Authored-By: Claude Opus 4.6 --- daemons/tick_trader.py | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/daemons/tick_trader.py b/daemons/tick_trader.py index e50d0c4..e776ece 100644 --- a/daemons/tick_trader.py +++ b/daemons/tick_trader.py @@ -640,7 +640,7 @@ def restore_positions() -> None: balances = upbit_client.get_balances() for b in balances: currency = b.get('currency', '') - bal = float(b.get('balance', 0)) + bal = float(b.get('balance', 0)) + float(b.get('locked', 0)) avg = float(b.get('avg_buy_price', 0)) if currency == 'KRW' or bal <= 0 or avg <= 0: continue @@ -649,23 +649,34 @@ def restore_positions() -> None: continue if ticker in positions: continue - # cascade ① 지정가 매도 즉시 제출 + # 기존 미체결 매도 주문 전부 취소 후 새로 제출 + try: + old_orders = upbit_client.get_order(ticker, state='wait') or [] + for o in (old_orders if isinstance(old_orders, list) else []): + if o.get('side') == 'ask': + cancel_order_safe(o.get('uuid')) + log.info(f"[복구] {ticker} 기존 매도 주문 취소: {o.get('uuid')}") + except Exception: + pass + # 취소 후 실제 가용 수량 재조회 + time.sleep(0.5) + actual_bal = upbit_client.get_balance(currency) or bal _, _, lr, stag = CASCADE_STAGES[0] target = avg * (1 + lr) - sell_uuid = submit_limit_sell(ticker, bal, target) + sell_uuid = submit_limit_sell(ticker, actual_bal, target) positions[ticker] = { 'entry_price': avg, 'entry_ts': datetime.now() - timedelta(seconds=LLM_MIN_ELAPSED), # LLM 즉시 활성 'running_peak': avg, - 'qty': bal, + 'qty': actual_bal, 'stage': 0, 'sell_uuid': sell_uuid, 'sell_price': target, 'llm_last_ts': None, 'llm_active': False, } - log.info(f"[복구] {ticker} 수량:{bal:.6f} 매수평균:{avg:,.0f}원") - tg(f"♻️ 포지션 복구 {ticker}\n매수평균: {avg:,.0f}원 수량: {bal:.6f}") + log.info(f"[복구] {ticker} 수량:{actual_bal:.6f} 매수평균:{avg:,.0f}원") + tg(f"♻️ 포지션 복구 {ticker}\n매수평균: {avg:,.0f}원 수량: {actual_bal:.6f}") if positions: log.info(f"[복구] 총 {len(positions)}개 포지션 복구됨") except Exception as e: