fix: handle US session transitions and suppress US_DAY trading (#400)
Some checks failed
Gitea CI / test (pull_request) Failing after 5s

This commit is contained in:
agentson
2026-03-04 03:07:14 +09:00
parent f245f55a32
commit 2e3aed5664
4 changed files with 81 additions and 14 deletions

View File

@@ -3550,6 +3550,20 @@ def _run_context_scheduler(
)
def _has_market_session_transition(
market_states: dict[str, str], market_code: str, session_id: str
) -> bool:
"""Return True when market session changed (or market has no prior state)."""
return market_states.get(market_code) != session_id
def _should_rescan_market(
*, last_scan: float, now_timestamp: float, rescan_interval: float, session_changed: bool
) -> bool:
"""Force rescan on session transition; otherwise follow interval cadence."""
return session_changed or (now_timestamp - last_scan >= rescan_interval)
async def _run_evolution_loop(
evolution_optimizer: EvolutionOptimizer,
telegram: TelegramClient,
@@ -4063,7 +4077,7 @@ async def run(settings: Settings) -> None:
last_scan_time: dict[str, float] = {}
# Track market open/close state for notifications
_market_states: dict[str, bool] = {} # market_code -> is_open
_market_states: dict[str, str] = {} # market_code -> session_id
# Trading control events
shutdown = asyncio.Event()
@@ -4181,8 +4195,8 @@ async def run(settings: Settings) -> None:
if not open_markets:
# Notify market close for any markets that were open
for market_code, is_open in list(_market_states.items()):
if is_open:
for market_code, session_id in list(_market_states.items()):
if session_id:
try:
from src.markets.schedule import MARKETS
@@ -4199,7 +4213,7 @@ async def run(settings: Settings) -> None:
)
except Exception as exc:
logger.warning("Market close notification failed: %s", exc)
_market_states[market_code] = False
_market_states.pop(market_code, None)
# Clear playbook for closed market (new one generated next open)
playbooks.pop(market_code, None)
@@ -4245,13 +4259,16 @@ async def run(settings: Settings) -> None:
settings=settings,
)
# Notify market open if it just opened
if not _market_states.get(market.code, False):
# Notify on market/session transition (e.g., US_PRE -> US_REG)
session_changed = _has_market_session_transition(
_market_states, market.code, session_info.session_id
)
if session_changed:
try:
await telegram.notify_market_open(market.name)
except Exception as exc:
logger.warning("Market open notification failed: %s", exc)
_market_states[market.code] = True
_market_states[market.code] = session_info.session_id
# Check and handle domestic pending (unfilled) limit orders.
if market.is_domestic:
@@ -4283,7 +4300,12 @@ async def run(settings: Settings) -> None:
now_timestamp = asyncio.get_event_loop().time()
last_scan = last_scan_time.get(market.code, 0.0)
rescan_interval = settings.RESCAN_INTERVAL_SECONDS
if now_timestamp - last_scan >= rescan_interval:
if _should_rescan_market(
last_scan=last_scan,
now_timestamp=now_timestamp,
rescan_interval=rescan_interval,
session_changed=session_changed,
):
try:
logger.info("Smart Scanner: Scanning %s market", market.name)

View File

@@ -207,7 +207,7 @@ def get_open_markets(
from src.core.order_policy import classify_session_id
session_id = classify_session_id(market, now)
return session_id not in {"KR_OFF", "US_OFF"}
return session_id not in {"KR_OFF", "US_OFF", "US_DAY"}
return is_market_open(market, now)
open_markets = [
@@ -254,10 +254,10 @@ def get_next_market_open(
from src.core.order_policy import classify_session_id
ts = start_utc.astimezone(ZoneInfo("UTC")).replace(second=0, microsecond=0)
prev_active = classify_session_id(market, ts) not in {"KR_OFF", "US_OFF"}
prev_active = classify_session_id(market, ts) not in {"KR_OFF", "US_OFF", "US_DAY"}
for _ in range(7 * 24 * 60):
ts = ts + timedelta(minutes=1)
active = classify_session_id(market, ts) not in {"KR_OFF", "US_OFF"}
active = classify_session_id(market, ts) not in {"KR_OFF", "US_OFF", "US_DAY"}
if active and not prev_active:
return ts
prev_active = active