fix: 스윙 부분매도 중복 실행 — ActiveTrade 미존재 포지션 처리

동기화로 유입된 포지션(ActiveTrade 행 없음)에 1차 익절(50%)이 매 사이클
반복 실행돼 전량 청산되는 문제 수정 (2026-09-22 두산에너빌리티 18→9→0주).

- exit_service: 부분매도 시 ActiveTrade 없으면 필수 키 포함해 생성, Portfolio 잔량 즉시 감소
- db_worker: 필수 키 없는 ActiveTrade 신규 upsert는 재시도 대신 경고 후 스킵
- portfolio.py sync 청산 경로 동일 수정
- 회귀 테스트 추가

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-22 10:32:14 +09:00
parent c1deb8caae
commit 8ecedf65a8
4 changed files with 180 additions and 4 deletions

View File

@@ -552,6 +552,15 @@ async def db_writer_worker() -> None:
if record is None:
# remaining_pct_multiply는 신규 생성 시 무시
create_data = {k: v for k, v in data.items() if k != "remaining_pct_multiply"}
# 필수 컬럼(quantity/entry_price) 없이 신규 생성 요청이 오면
# IntegrityError로 3회 재시도만 낭비 → 경고 후 스킵
_missing = [k for k in ("quantity", "entry_price") if create_data.get(k) is None]
if _missing:
logger.warning(
"⚠️ [Worker] ActiveTrade upsert 스킵: %s active 행 없음 + 필수 키 누락 %s (keys=%s)",
stock_code, _missing, sorted(create_data.keys()),
)
continue
record = ActiveTrade(**create_data)
session.add(record)
else: