feat: 리스크 관리 강화 — 포트폴리오 락, MDD 단기전략 비활성화, 상관관계 필터
- portfolio.py: summary_lock으로 동시성 보호, apply_buy/apply_sell async화 - mdd_manager.py: MDD -10% 시 단기전략 비활성화 (is_short_term_strategy_paused) - loss_tracker.py: DB 직접 접근 → db_worker 큐 기반 전환 - db_worker.py: upsert_stock_ban 태스크 추가 - correlation_filter.py: 섹터 집중도 + 피어슨 상관관계 검증 (CLAUDE.md 5.4) - trade_executor.py: 상관관계 필터 통합, await 적용 - mean_reversion_strategy.py: config 값 타입 안전성 (float 변환) - main.py/day_trading.py: MDD 체크 후 자동매매/데이트레이딩 차단 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@ Supported task types:
|
||||
- insert_trade_history : dict → TradeHistory INSERT
|
||||
- upsert_stock_analysis : dict → StockAnalysis single UPSERT
|
||||
- bulk_upsert_stock_analysis : list → StockAnalysis batch UPSERT
|
||||
- upsert_stock_ban : dict → StockBan UPSERT (loss_tracker)
|
||||
- log_mcp_deny : dict → MCP 거부 이벤트 로그 (DB 저장 없이 로그만)
|
||||
"""
|
||||
import asyncio
|
||||
@@ -54,6 +55,18 @@ async def enqueue_db_write(task: dict) -> None:
|
||||
await db_task_queue.put(task)
|
||||
|
||||
|
||||
async def enqueue_stock_ban_upsert(stock_code: str, consecutive_losses: int, ban_until) -> None:
|
||||
"""StockBan UPSERT 를 큐에 등록 (loss_tracker에서 호출)."""
|
||||
await db_task_queue.put({
|
||||
"type": "upsert_stock_ban",
|
||||
"data": {
|
||||
"stock_code": stock_code,
|
||||
"consecutive_losses": consecutive_losses,
|
||||
"ban_until": ban_until,
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
# 워커 본체
|
||||
# ─────────────────────────────────────────────────────────────────────────────
|
||||
@@ -99,7 +112,38 @@ async def db_writer_worker() -> None:
|
||||
"✅ [Worker] Bulk StockAnalysis upsert: %d rows", len(data)
|
||||
)
|
||||
|
||||
# ── 4. MCP 거부 이벤트 로그 ───────────────────────────────────
|
||||
# ── 4. StockBan UPSERT ────────────────────────────────────────
|
||||
elif task_type == "upsert_stock_ban":
|
||||
from app.models.models import StockBan
|
||||
from sqlalchemy import select
|
||||
|
||||
stock_code = data.get("stock_code")
|
||||
consecutive_losses = data.get("consecutive_losses")
|
||||
ban_until = data.get("ban_until")
|
||||
|
||||
result = await session.execute(select(StockBan).where(StockBan.stock_code == stock_code))
|
||||
record = result.scalar_one_or_none()
|
||||
|
||||
if record is None:
|
||||
record = StockBan(
|
||||
stock_code=stock_code,
|
||||
consecutive_losses=consecutive_losses,
|
||||
ban_until=ban_until,
|
||||
)
|
||||
session.add(record)
|
||||
else:
|
||||
record.consecutive_losses = consecutive_losses
|
||||
record.ban_until = ban_until
|
||||
|
||||
await session.commit()
|
||||
logger.debug(
|
||||
"✅ [Worker] StockBan upsert: %s (losses=%d, ban_until=%s)",
|
||||
stock_code,
|
||||
consecutive_losses,
|
||||
ban_until.isoformat() if ban_until else "None",
|
||||
)
|
||||
|
||||
# ── 5. MCP 거부 이벤트 로그 ───────────────────────────────────
|
||||
elif task_type == "log_mcp_deny":
|
||||
# DB 저장 없이 로그만 기록 (필요 시 별도 테이블 확장 가능)
|
||||
logger.warning(
|
||||
|
||||
Reference in New Issue
Block a user