Harden scheduler and stale breakout reentry
This commit is contained in:
@@ -47,6 +47,7 @@ class VolatilityBreakout:
|
||||
self._entry_times: dict = {} # ticker → 마지막 진입 datetime (쿨다운 추적)
|
||||
self._exit_times: dict = {} # ticker -> 마지막 최종 청산 datetime (쿨다운 추적)
|
||||
self._tp_closed_tickers: set[str] = set() # TP로 전량 청산된 당일 재진입 차단
|
||||
self._rebreak_required_tickers: set[str] = set() # TIME/FORCE 후 목표가 재돌파 대기
|
||||
|
||||
# ── AI 컨텍스트 로드 ──
|
||||
|
||||
@@ -103,6 +104,9 @@ class VolatilityBreakout:
|
||||
if not prev:
|
||||
logger.info(f"목표가 제외({ticker}): 전일 데이터 없음")
|
||||
return
|
||||
if open_price <= 0:
|
||||
logger.info(f"목표가 제외({ticker}): 당일 시가 미확정({open_price})")
|
||||
return
|
||||
if prev["amount"] < MIN_TRADE_AMOUNT:
|
||||
logger.info(
|
||||
f"목표가 제외({ticker}): 전일 거래대금 {prev['amount']/1e8:.0f}억"
|
||||
@@ -126,8 +130,10 @@ class VolatilityBreakout:
|
||||
exit_time = exit_time or datetime.now()
|
||||
if reason in ("TIME", "FORCE"):
|
||||
self._exit_times[ticker] = exit_time
|
||||
self._rebreak_required_tickers.add(ticker)
|
||||
elif reason in ("TP1", "TP2"):
|
||||
self._tp_closed_tickers.add(ticker)
|
||||
self._rebreak_required_tickers.discard(ticker)
|
||||
|
||||
# ── 진입 신호 판단 ──
|
||||
|
||||
@@ -151,6 +157,16 @@ class VolatilityBreakout:
|
||||
result["reason"] = "TP 당일 재진입 차단"
|
||||
return result
|
||||
|
||||
# 목표가 확인
|
||||
target = self.targets.get(ticker, 0)
|
||||
if target <= 0:
|
||||
result["reason"] = "목표가 없음"
|
||||
return result
|
||||
|
||||
# TIME/FORCE 이후 쿨다운 중이라도 목표가 아래로 내려온 사실은 기록한다.
|
||||
if ticker in self._rebreak_required_tickers and current_price < target:
|
||||
self._rebreak_required_tickers.discard(ticker)
|
||||
|
||||
# TIME/FORCE 청산 후 쿨다운은 진입 시각이 아니라 청산 시각 기준이다.
|
||||
last_exit = self._exit_times.get(ticker)
|
||||
if last_exit is not None:
|
||||
@@ -159,10 +175,10 @@ class VolatilityBreakout:
|
||||
result["reason"] = f"재진입 쿨다운 ({elapsed:.0f}분 / {TICKER_REENTRY_COOLDOWN_MIN}분)"
|
||||
return result
|
||||
|
||||
# 목표가 확인
|
||||
target = self.targets.get(ticker, 0)
|
||||
if target <= 0:
|
||||
result["reason"] = "목표가 없음"
|
||||
# TIME/FORCE 청산 뒤에는 남아 있는 당일 돌파 신호를 그대로 재사용하지 않는다.
|
||||
# 목표가 아래로 식은 뒤 다시 돌파해야 새로운 진입 신호로 인정한다.
|
||||
if ticker in self._rebreak_required_tickers:
|
||||
result["reason"] = f"재돌파 대기 ({current_price:,} >= {target:,.0f})"
|
||||
return result
|
||||
|
||||
# 기술적 조건: 현재가 >= 목표가
|
||||
|
||||
Reference in New Issue
Block a user