fix(journal): 장중 일지 자동 생성 + 전략명 unknown + profit_factor 단위 오류

- 장중 10분 주기 journal_intraday_scheduler 신설 (SELECT 전용, 쓰기는 db_worker 큐)
  - 매도 후 3분 유예(JOURNAL_INTRADAY_GRACE_MIN), trade_id in-flight TTL 30분
  - order_id 로 해소된 trade_id 에 일지가 있으면 INSERT skip (중복 방지)
- 16:00 배치 enqueue_trade_journal 이 strategy_type 을 넘기지 않아 전 일지가 'unknown' 이던 결함 수정
- analyze_performance profit_factor 를 손익률(%) 합이 아닌 금액 기준으로 (1.22 → 0.62)
- 일지 대상 SELL 상태에 PARTIAL 포함 (성과 집계 필터는 불변)
- journals 단건 생성: 중복 행 시 500 대신 409, JOURNAL_SELL_STATUSES 사용
- 16:00 배치 조회일수 config 화, 손익 0 기간 PF 오경고 제거

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 17:00:05 +09:00
parent b4e958b477
commit e4346d30fb
7 changed files with 419 additions and 21 deletions

View File

@@ -754,7 +754,10 @@ async def enqueue_trade_journal(trade, content: str) -> None:
from app.services.trade_analyzer import _to_float, _parse_strategy, _parse_exit_type
pl_rate = _to_float(trade.profit_loss_rate)
strategy = _parse_strategy(trade.entry_reason)
# [2026-10-01] strategy_type 컬럼(swing/daytrading/manual)을 넘겨야 한다. 빠져 있어
# entry_reason 키워드만 보다 16:00 배치 일지가 전부 'unknown' 이 됐다
# (create_journal_record 는 넘기고 있었다 — 같은 거래가 경로에 따라 다른 전략명).
strategy = _parse_strategy(trade.entry_reason, getattr(trade, "strategy_type", None))
exit_type = _parse_exit_type(trade.exit_reason)
mood = "positive" if pl_rate > 0 else ("neutral" if pl_rate > -3.0 else "negative")
tags = [strategy, exit_type]
@@ -819,6 +822,16 @@ async def _handle_insert_trade_journal(session, data: dict) -> None:
resolved = result.scalar_one_or_none()
if resolved:
payload["trade_id"] = resolved
# 해소된 trade_id 로 이미 일지가 있으면 중복 생성 금지 (장중 태스크·16:00 배치와
# 즉시 생성 경로의 경합). 명시 trade_id 경로는 조회하지 않는다(기존 계약).
dup = await session.execute(
select(TradeJournal.id).where(TradeJournal.trade_id == resolved).limit(1)
)
if dup.scalar_one_or_none() is not None:
logger.info(
"[Worker] TradeJournal skip — trade_id=%s 일지 이미 존재", resolved
)
return
else:
logger.warning(
"⚠️ [Worker] TradeJournal trade_id 미해소 (order_id=%s, %s) — "