fix: 리스크 결함 일괄 수정 — 누적 4% 상한·스윙 소유권·일일한도 분리·DT 순손익/체결가·시간손절 밴 제외·체결조회 경로

trade_executor
- 종목당 4% 상한을 기존 보유분 포함 누적으로 (sizing_core.remaining_position_room)
- 추천 경로는 스윙 소유 행만 매수·매도 (external/manual/daytrading/us_swing skip, 대칭), 고아 DT 행 warning
- 일일 매수한도는 스윙 소유 매수만 집계, 집계 실패 시 fail-closed
- 부분매도 반복 차단에서만 DT 매도 제외 (재매수 쿨다운은 유지)
- 체결 확인: 부분체결 잔량 자동 재주문 제거(가드 전부 우회·취소/거부 시 발동), PARTIAL→COMPLETED+체결수량, 초과체결 캡

korea_investment_api
- get_order_execution 이 존재하지 않는 /trading/inquire-ccnl 을 호출하던 결함 → inquire-daily-ccld
  (TTTC0081R 우선, 구 TR 폴백, 페이지네이션, ODNO 매칭, EXCG_ID_DVSN_CD=KRX), 실패 로그 warning

daytrading
- 시간손절은 loss_tracker 중립 (42일 밴이 스윙까지 막던 문제)
- 실현손익을 수수료·거래세 차감 순손익으로 (trade_cost_core), 체결가 백그라운드 보정 (fill_reconciler)
- legacy _record_trade strategy_type=daytrading 명시

db_worker
- update_trade_history_by_order_id 를 당일(KST)+최신 1행으로 한정 (일별 재사용 ODNO 로 과거 행 덮어쓰기 방지)

alembic 0013: trade_journals strategy_name='unknown' 을 trade_history.strategy_type 으로 보정 (백업 테이블 포함)
CLAUDE.md: 변경 동작 반영, MT 예약 리비전 0013→0014

998 passed

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 17:37:29 +09:00
parent 599de3b52e
commit 45677c8fbb
19 changed files with 2873 additions and 166 deletions

View File

@@ -164,6 +164,19 @@ class DayTradeExit:
sell_pct: float = 1.0
# [2026-10-01] 시간손절 사유 접두어 — 사유 문자열 생성과 판별이 이 상수 하나를 공유한다.
# 시간손절은 "진입 후 N분간 목표 방향 진행 미미"를 정리하는 **기회비용 청산**이지
# 손절선 이탈이 아니다. 이것까지 loss_tracker(3연패 → CONSECUTIVE_LOSS_BAN_DAYS 진입금지)에
# 집계하면 소폭 손실 시간손절 3회만으로 그 종목의 스윙 진입까지 42일간 막힌다.
# 판별은 exit_service 가 청산 사유로 한다(_execute_exit 시그니처 불변 유지).
TIME_STOP_REASON_PREFIX = "시간 손절"
def is_time_stop_exit_reason(reason: Optional[str]) -> bool:
"""청산 사유가 DT 시간손절인지 판별 (check_day_trade_exit 가 만든 사유 기준)."""
return bool(reason) and str(reason).startswith(TIME_STOP_REASON_PREFIX)
# ── 분봉 파싱 헬퍼 ────────────────────────────────────────────────────────────
def parse_minute_candles(raw_output2: list) -> List[MinuteCandle]:
@@ -771,7 +784,7 @@ def check_day_trade_exit(
if gain_pct < settings.DAY_TRADE_TIME_STOP_MIN_GAIN: # 최소 수익 미달 (수수료 커버 못함)
return DayTradeExit(
action="SELL_ALL",
reason=f"시간 손절: {elapsed_min:.0f}분 경과, 수익={gain_pct*100:.1f}% < {settings.DAY_TRADE_TIME_STOP_MIN_GAIN*100:.1f}%",
reason=f"{TIME_STOP_REASON_PREFIX}: {elapsed_min:.0f}분 경과, 수익={gain_pct*100:.1f}% < {settings.DAY_TRADE_TIME_STOP_MIN_GAIN*100:.1f}%",
)
# 4. 목표가 달성 → 50% 분할 매도 (CLAUDE.md 5.2: +2R 시 50% 분할 매도)