수정
Some checks failed
CI/CD Pipeline / test-backend (push) Has been cancelled
CI/CD Pipeline / test-frontend (push) Has been cancelled
CI/CD Pipeline / build-and-push (push) Has been cancelled

This commit is contained in:
2026-04-06 13:16:15 +09:00
parent 24443621f9
commit ab1b1a4cb6
5 changed files with 45 additions and 14 deletions

View File

@@ -36,8 +36,19 @@ def _to_float(val) -> float:
return 0.0
def _parse_strategy(entry_reason: Optional[str]) -> str:
"""entry_reason 문자열에서 전략 이름 추출."""
def _parse_strategy(entry_reason: Optional[str], strategy_type: Optional[str] = None) -> str:
"""strategy_type 컬럼 우선, 없으면 entry_reason 문자열에서 전략 이름 추출."""
# strategy_type 컬럼이 있으면 우선 사용
if strategy_type and strategy_type.strip():
st = strategy_type.strip().lower()
_type_map = {
"swing": "mean_reversion",
"daytrading": "day_trade",
"kosdaq_scan": "kosdaq_scanner",
"short_term": "short_term",
}
return _type_map.get(st, st)
if not entry_reason:
return "unknown"
reason = entry_reason.lower()
@@ -439,7 +450,7 @@ async def analyze_performance(db: AsyncSession, days: int = 30) -> Dict[str, Any
# ── 전략별 성과 ──────────────────────────────────────────────────────
by_strategy: Dict[str, list] = {}
for t in trades:
strat = _parse_strategy(t.entry_reason)
strat = _parse_strategy(t.entry_reason, getattr(t, "strategy_type", None))
by_strategy.setdefault(strat, []).append(_to_float(t.profit_loss_rate))
strategy_stats = {}
@@ -491,8 +502,9 @@ async def analyze_performance(db: AsyncSession, days: int = 30) -> Dict[str, Any
stock_pnl[code] = stock_pnl.get(code, 0.0) + _to_float(t.net_profit_loss)
sorted_stocks = sorted(stock_pnl.items(), key=lambda x: x[1])
worst_stocks = [{"stock_code": c, "net_pnl": round(p, 2)} for c, p in sorted_stocks[:5]]
best_stocks = [{"stock_code": c, "net_pnl": round(p, 2)} for c, p in sorted_stocks[-5:][::-1]]
# 손실 종목만 (음수), 수익 종목만 (양수) 필터링하여 색상 혼동 방지
worst_stocks = [{"stock_code": c, "net_pnl": round(p, 2)} for c, p in sorted_stocks if p < 0][:5]
best_stocks = [{"stock_code": c, "net_pnl": round(p, 2)} for c, p in sorted_stocks[::-1] if p > 0][:5]
# ── 리스크 조정 수익률 지표 ────────────────────────────────────────────
risk_metrics = _calc_risk_adjusted_metrics(trades)
@@ -660,7 +672,7 @@ def generate_journal_for_trade(trade: TradeHistory, perf_context: Optional[Dict]
pl_amount = _to_float(trade.net_profit_loss)
exec_price = _to_float(trade.executed_price)
exec_qty = trade.executed_quantity or trade.order_quantity or 0
strategy = _parse_strategy(trade.entry_reason)
strategy = _parse_strategy(trade.entry_reason, getattr(trade, "strategy_type", None))
exit_type = _parse_exit_type(trade.exit_reason)
# 결과 평가
@@ -729,7 +741,7 @@ async def create_journal_record(
) -> TradeJournal:
"""TradeJournal 레코드를 DB에 저장 후 반환."""
pl_rate = _to_float(trade.profit_loss_rate)
strategy = _parse_strategy(trade.entry_reason)
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")