fix: handle US session transitions and suppress US_DAY trading (#400)
Some checks failed
Gitea CI / test (pull_request) Failing after 5s
Some checks failed
Gitea CI / test (pull_request) Failing after 5s
This commit is contained in:
@@ -33,6 +33,7 @@ from src.main import (
|
||||
_extract_avg_price_from_balance,
|
||||
_extract_held_codes_from_balance,
|
||||
_extract_held_qty_from_balance,
|
||||
_has_market_session_transition,
|
||||
_handle_market_close,
|
||||
_inject_staged_exit_features,
|
||||
_maybe_queue_order_intent,
|
||||
@@ -41,6 +42,7 @@ from src.main import (
|
||||
_retry_connection,
|
||||
_run_context_scheduler,
|
||||
_run_evolution_loop,
|
||||
_should_rescan_market,
|
||||
_should_block_overseas_buy_for_fx_buffer,
|
||||
_should_force_exit_for_overnight,
|
||||
_split_trade_pnl_components,
|
||||
@@ -140,6 +142,38 @@ class TestExtractAvgPriceFromBalance:
|
||||
result = _extract_avg_price_from_balance(balance, "AAPL", is_domestic=False)
|
||||
assert result == 170.5
|
||||
|
||||
|
||||
class TestRealtimeSessionStateHelpers:
|
||||
"""Tests for realtime loop session-transition/rescan helper logic."""
|
||||
|
||||
def test_has_market_session_transition_when_state_missing(self) -> None:
|
||||
states: dict[str, str] = {}
|
||||
assert _has_market_session_transition(states, "US_NASDAQ", "US_REG")
|
||||
|
||||
def test_has_market_session_transition_when_session_changes(self) -> None:
|
||||
states = {"US_NASDAQ": "US_PRE"}
|
||||
assert _has_market_session_transition(states, "US_NASDAQ", "US_REG")
|
||||
|
||||
def test_has_market_session_transition_false_when_same_session(self) -> None:
|
||||
states = {"US_NASDAQ": "US_REG"}
|
||||
assert not _has_market_session_transition(states, "US_NASDAQ", "US_REG")
|
||||
|
||||
def test_should_rescan_market_forces_on_session_transition(self) -> None:
|
||||
assert _should_rescan_market(
|
||||
last_scan=1000.0,
|
||||
now_timestamp=1050.0,
|
||||
rescan_interval=300.0,
|
||||
session_changed=True,
|
||||
)
|
||||
|
||||
def test_should_rescan_market_uses_interval_without_transition(self) -> None:
|
||||
assert not _should_rescan_market(
|
||||
last_scan=1000.0,
|
||||
now_timestamp=1050.0,
|
||||
rescan_interval=300.0,
|
||||
session_changed=False,
|
||||
)
|
||||
|
||||
def test_returns_zero_when_field_absent(self) -> None:
|
||||
"""Returns 0.0 when pchs_avg_pric key is missing entirely."""
|
||||
balance = {"output1": [{"pdno": "005930", "ord_psbl_qty": "5"}]}
|
||||
|
||||
@@ -165,6 +165,17 @@ class TestGetOpenMarkets:
|
||||
)
|
||||
assert {m.code for m in extended} == {"US_NASDAQ", "US_NYSE", "US_AMEX"}
|
||||
|
||||
def test_get_open_markets_excludes_us_day_when_extended_enabled(self) -> None:
|
||||
"""US_DAY should be treated as non-tradable even in extended-session lookup."""
|
||||
# Monday 2026-02-02 10:30 KST = 01:30 UTC (US_DAY by session classification)
|
||||
test_time = datetime(2026, 2, 2, 1, 30, tzinfo=ZoneInfo("UTC"))
|
||||
extended = get_open_markets(
|
||||
enabled_markets=["US_NASDAQ", "US_NYSE", "US_AMEX"],
|
||||
now=test_time,
|
||||
include_extended_sessions=True,
|
||||
)
|
||||
assert extended == []
|
||||
|
||||
|
||||
class TestGetNextMarketOpen:
|
||||
"""Test get_next_market_open function."""
|
||||
@@ -214,8 +225,8 @@ class TestGetNextMarketOpen:
|
||||
def test_get_next_market_open_prefers_extended_session(self) -> None:
|
||||
"""Extended lookup should return premarket open time before regular open."""
|
||||
# Monday 2026-02-02 07:00 EST = 12:00 UTC
|
||||
# By v3 KST session rules, US is OFF only in KST 07:00-10:00 (UTC 22:00-01:00).
|
||||
# At 12:00 UTC market is active, so next OFF->ON transition is 01:00 UTC next day.
|
||||
# US_DAY is treated as non-tradable in extended lookup, so after entering
|
||||
# US_DAY the next tradable OFF->ON transition is US_PRE at 09:00 UTC next day.
|
||||
test_time = datetime(2026, 2, 2, 12, 0, tzinfo=ZoneInfo("UTC"))
|
||||
market, next_open = get_next_market_open(
|
||||
enabled_markets=["US_NASDAQ"],
|
||||
@@ -223,7 +234,7 @@ class TestGetNextMarketOpen:
|
||||
include_extended_sessions=True,
|
||||
)
|
||||
assert market.code == "US_NASDAQ"
|
||||
assert next_open == datetime(2026, 2, 3, 1, 0, tzinfo=ZoneInfo("UTC"))
|
||||
assert next_open == datetime(2026, 2, 3, 9, 0, tzinfo=ZoneInfo("UTC"))
|
||||
|
||||
|
||||
class TestExpandMarketCodes:
|
||||
|
||||
Reference in New Issue
Block a user