봇 무음 크래시 방지 — trading_loop 예외 처리 + 워치독 추가
- app/main.py: trading_loop while 루프 전체를 try/except로 감싸 예외 발생 시 로그+Discord 알림 후 루프 재개 (연속 10회 오류 시에만 종료) - scripts/_watchdog.py: 봇 PID 생존 확인, 죽어있으면 Discord 알림 + 자동 재시작 - scripts/run_watchdog.ps1: 워치독 PowerShell 래퍼 - scripts/setup_scheduler.ps1: StockBot_Watchdog 태스크 등록 추가 (5분 간격) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+51
-30
@@ -321,44 +321,65 @@ class StockBot:
|
||||
"""1초 단위 메인 루프"""
|
||||
logger.info("매매 루프 시작")
|
||||
self.running = True
|
||||
_consecutive_errors = 0
|
||||
|
||||
while self.running:
|
||||
now = datetime.now()
|
||||
now_str = now.strftime("%H:%M")
|
||||
try:
|
||||
now = datetime.now()
|
||||
now_str = now.strftime("%H:%M")
|
||||
|
||||
# 14:50 강제 청산
|
||||
if now_str >= FORCE_EXIT:
|
||||
await self.force_exit_all()
|
||||
self.running = False
|
||||
break
|
||||
# 14:50 강제 청산
|
||||
if now_str >= FORCE_EXIT:
|
||||
await self.force_exit_all()
|
||||
self.running = False
|
||||
break
|
||||
|
||||
# 14:00 이후 신규 진입 중단 (청산은 계속)
|
||||
if now_str > "14:00":
|
||||
# 14:00 이후 신규 진입 중단 (청산은 계속)
|
||||
if now_str > "14:00":
|
||||
await self.check_exits()
|
||||
await asyncio.sleep(1)
|
||||
continue
|
||||
|
||||
# 09:00 이전 대기
|
||||
if now_str < "09:00":
|
||||
await asyncio.sleep(1)
|
||||
continue
|
||||
|
||||
# midday_context.json 갱신 감지 (점심 세션 이벤트 기반 시작)
|
||||
self._check_midday_context()
|
||||
|
||||
# 리스크 체크 (L2/L4/L5 하드 중단)
|
||||
if not self.risk.can_trade():
|
||||
await asyncio.sleep(5)
|
||||
continue
|
||||
|
||||
# 보유 포지션 청산 체크
|
||||
await self.check_exits()
|
||||
|
||||
# 신규 진입 체크
|
||||
if self.risk.can_add_position(len(self.positions)):
|
||||
await self.check_entries()
|
||||
|
||||
_consecutive_errors = 0
|
||||
await asyncio.sleep(1)
|
||||
continue
|
||||
|
||||
# 09:00 이전 대기
|
||||
if now_str < "09:00":
|
||||
await asyncio.sleep(1)
|
||||
continue
|
||||
|
||||
# midday_context.json 갱신 감지 (점심 세션 이벤트 기반 시작)
|
||||
self._check_midday_context()
|
||||
|
||||
# 리스크 체크 (L2/L4/L5 하드 중단)
|
||||
if not self.risk.can_trade():
|
||||
except asyncio.CancelledError:
|
||||
raise
|
||||
except Exception as e:
|
||||
_consecutive_errors += 1
|
||||
logger.error(
|
||||
f"매매 루프 오류 (연속 {_consecutive_errors}회): "
|
||||
f"{type(e).__name__}: {e}",
|
||||
exc_info=True,
|
||||
)
|
||||
await notify_error(f"매매 루프 오류 {_consecutive_errors}회: {type(e).__name__}: {e}")
|
||||
# 연속 10회 오류 시 루프 종료 (무한 오류 방지)
|
||||
if _consecutive_errors >= 10:
|
||||
logger.critical("연속 오류 10회 — 매매 루프 강제 종료")
|
||||
await notify_error("연속 오류 10회 — 매매 루프 강제 종료")
|
||||
self.running = False
|
||||
break
|
||||
await asyncio.sleep(5)
|
||||
continue
|
||||
|
||||
# 보유 포지션 청산 체크
|
||||
await self.check_exits()
|
||||
|
||||
# 신규 진입 체크
|
||||
if self.risk.can_add_position(len(self.positions)):
|
||||
await self.check_entries()
|
||||
|
||||
await asyncio.sleep(1)
|
||||
|
||||
# ─────────────────────────────────────────
|
||||
# 진입 체크
|
||||
|
||||
Reference in New Issue
Block a user