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:
2026-03-10 17:26:13 +09:00
parent 783e932145
commit a477072bdc
9 changed files with 661 additions and 87 deletions

View File

@@ -48,35 +48,31 @@ class ConsecutiveLossTracker:
entry["consecutive_losses"] = 0
entry["ban_until"] = None
async def save_to_db(self, db, stock_code: str):
"""인메모리 상태를 DB에 영속화 (record_trade_result 후 호출)"""
async def save_to_db(self, db=None, stock_code: str = None):
"""인메모리 상태를 DB에 영속화 (record_trade_result 후 호출)
NOTE: db 파라미터는 하위호환성을 위해 유지되지만 사용되지 않습니다.
실제 DB 저장은 db_worker.py의 db_task_queue를 통해 처리됩니다.
"""
if stock_code is None:
return
try:
from sqlalchemy import select
from app.models.models import StockBan
from app.services.db_worker import enqueue_stock_ban_upsert
entry = self._tracker.get(stock_code)
if entry is None:
return
result = await db.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=entry["consecutive_losses"],
ban_until=entry["ban_until"],
)
db.add(record)
else:
record.consecutive_losses = entry["consecutive_losses"]
record.ban_until = entry["ban_until"]
record.updated_at = datetime.now(timezone.utc)
await db.commit()
logger.debug(f"loss_tracker DB 저장 완료: {stock_code}")
# 큐에 UPSERT 작업 등록 (db_worker가 비동기적으로 처리)
await enqueue_stock_ban_upsert(
stock_code=stock_code,
consecutive_losses=entry["consecutive_losses"],
ban_until=entry["ban_until"],
)
logger.debug(f"loss_tracker DB 저장 큐 등록: {stock_code}")
except Exception as e:
logger.error(f"loss_tracker DB 저장 실패 ({stock_code}): {e}")
logger.error(f"loss_tracker DB 저장 큐 등록 실패 ({stock_code}): {e}")
async def load_from_db(self, db):
"""앱 시작 시 DB에서 ban 상태 복원"""