fix: 분할매도 잔량 미갱신 — 스윙·국내 executor·미국 경로 동일 패턴 + 수동매도 ActiveTrade 정리

DT에서 찾은 '분할매도 후 ActiveTrade.quantity 미갱신' 패턴이 3곳 더 있었음:
- us_market_scheduler: total_qty = trade.quantity 를 매도량 산정에 직접 사용 →
  분할매도 후 다음 사이클이 원래 수량 기준으로 팔아 과다매도(US_TRADING_ENABLED=true 상태)
- swing/exit_service, trade_executor._execute_sell: remaining_pct만 갱신
또한 수동 매도(/portfolio/sell)가 ActiveTrade를 전혀 정리하지 않아 청산된 종목이 active로
잔존(삼아알미늄·LG 등) → 재매수 시 옛 remaining_pct가 살아나 1차 익절이 건너뛰어짐.
전량 매도 시 close, 분할 시 잔량 갱신으로 수정.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-23 10:36:00 +09:00
parent f32bf412f3
commit b933e23777
5 changed files with 64 additions and 0 deletions

View File

@@ -1457,6 +1457,25 @@ async def sell_stock(
await db.commit()
# ActiveTrade 정리 — 누락 시 유령 active 행이 남아, 같은 종목을 다시 매수했을 때
# 옛 remaining_pct(예: 0.50)가 살아나 1차 익절이 건너뛰어진다.
# (2026-09-23 확인: 삼아알미늄·LG 등 수동 청산 종목이 active 상태로 잔존)
from app.services.db_worker import (
enqueue_close_active_trade as _enq_close_at,
enqueue_active_trade_upsert as _enq_at_upsert,
)
try:
if quantity >= original_holding_qty:
await _enq_close_at(stock_code, strategy_name=None)
else:
await _enq_at_upsert({
"stock_code": stock_code,
"quantity": original_holding_qty - quantity,
"current_price": float(executed_price),
})
except Exception as _at_err:
logger.warning(f"[SELL] ActiveTrade 정리 실패 {stock_code}: {_at_err}")
# ✅ 인메모리 캐시 즉시 반영 (KIS 재동기화 전에도 화면에서 즉시 제거)
if quantity >= original_holding_qty:
portfolio_cache.holdings = [