feat: 세션 전환 시 리스크 파라미터 동적 재로딩 (#327) #344

Merged
jihoson merged 2 commits from feature/issue-327-session-risk-reload into feature/v3-session-policy-stream 2026-03-01 09:31:14 +09:00
Showing only changes of commit 42c06929ea - Show all commits

View File

@@ -4,6 +4,7 @@ from datetime import UTC, date, datetime
from unittest.mock import ANY, AsyncMock, MagicMock, patch from unittest.mock import ANY, AsyncMock, MagicMock, patch
import pytest import pytest
import src.main as main_module
from src.config import Settings from src.config import Settings
from src.context.layer import ContextLayer from src.context.layer import ContextLayer
@@ -17,6 +18,7 @@ from src.main import (
KILL_SWITCH, KILL_SWITCH,
_SESSION_RISK_LAST_BY_MARKET, _SESSION_RISK_LAST_BY_MARKET,
_SESSION_RISK_OVERRIDES_BY_MARKET, _SESSION_RISK_OVERRIDES_BY_MARKET,
_SESSION_RISK_PROFILES_MAP,
_STOPLOSS_REENTRY_COOLDOWN_UNTIL, _STOPLOSS_REENTRY_COOLDOWN_UNTIL,
_apply_staged_exit_override_for_hold, _apply_staged_exit_override_for_hold,
_compute_kr_atr_value, _compute_kr_atr_value,
@@ -105,6 +107,8 @@ def _reset_kill_switch_state() -> None:
_RUNTIME_EXIT_PEAKS.clear() _RUNTIME_EXIT_PEAKS.clear()
_SESSION_RISK_LAST_BY_MARKET.clear() _SESSION_RISK_LAST_BY_MARKET.clear()
_SESSION_RISK_OVERRIDES_BY_MARKET.clear() _SESSION_RISK_OVERRIDES_BY_MARKET.clear()
_SESSION_RISK_PROFILES_MAP.clear()
main_module._SESSION_RISK_PROFILES_RAW = "__reset__"
_STOPLOSS_REENTRY_COOLDOWN_UNTIL.clear() _STOPLOSS_REENTRY_COOLDOWN_UNTIL.clear()
yield yield
KILL_SWITCH.clear_block() KILL_SWITCH.clear_block()
@@ -112,6 +116,8 @@ def _reset_kill_switch_state() -> None:
_RUNTIME_EXIT_PEAKS.clear() _RUNTIME_EXIT_PEAKS.clear()
_SESSION_RISK_LAST_BY_MARKET.clear() _SESSION_RISK_LAST_BY_MARKET.clear()
_SESSION_RISK_OVERRIDES_BY_MARKET.clear() _SESSION_RISK_OVERRIDES_BY_MARKET.clear()
_SESSION_RISK_PROFILES_MAP.clear()
main_module._SESSION_RISK_PROFILES_RAW = "__reset__"
_STOPLOSS_REENTRY_COOLDOWN_UNTIL.clear() _STOPLOSS_REENTRY_COOLDOWN_UNTIL.clear()
@@ -234,6 +240,76 @@ def test_stoploss_cooldown_minutes_uses_session_override() -> None:
assert value == 45 assert value == 45
def test_resolve_market_setting_ignores_profile_when_reload_disabled() -> None:
settings = Settings(
KIS_APP_KEY="k",
KIS_APP_SECRET="s",
KIS_ACCOUNT_NO="12345678-01",
GEMINI_API_KEY="g",
US_MIN_PRICE=5.0,
SESSION_RISK_RELOAD_ENABLED=False,
SESSION_RISK_PROFILES_JSON='{"US_PRE": {"US_MIN_PRICE": 9.5}}',
)
market = MagicMock()
market.code = "US_NASDAQ"
with patch("src.main.get_session_info", return_value=MagicMock(session_id="US_PRE")):
value = _resolve_market_setting(
market=market,
settings=settings,
key="US_MIN_PRICE",
default=5.0,
)
assert value == pytest.approx(5.0)
def test_resolve_market_setting_falls_back_on_invalid_profile_json() -> None:
settings = Settings(
KIS_APP_KEY="k",
KIS_APP_SECRET="s",
KIS_ACCOUNT_NO="12345678-01",
GEMINI_API_KEY="g",
US_MIN_PRICE=5.0,
SESSION_RISK_PROFILES_JSON="{invalid-json",
)
market = MagicMock()
market.code = "US_NASDAQ"
with patch("src.main.get_session_info", return_value=MagicMock(session_id="US_PRE")):
value = _resolve_market_setting(
market=market,
settings=settings,
key="US_MIN_PRICE",
default=5.0,
)
assert value == pytest.approx(5.0)
def test_resolve_market_setting_coerces_bool_string_override() -> None:
settings = Settings(
KIS_APP_KEY="k",
KIS_APP_SECRET="s",
KIS_ACCOUNT_NO="12345678-01",
GEMINI_API_KEY="g",
OVERNIGHT_EXCEPTION_ENABLED=True,
SESSION_RISK_PROFILES_JSON='{"US_AFTER": {"OVERNIGHT_EXCEPTION_ENABLED": "false"}}',
)
market = MagicMock()
market.code = "US_NASDAQ"
with patch("src.main.get_session_info", return_value=MagicMock(session_id="US_AFTER")):
value = _resolve_market_setting(
market=market,
settings=settings,
key="OVERNIGHT_EXCEPTION_ENABLED",
default=True,
)
assert value is False
def test_estimate_pred_down_prob_from_rsi_uses_linear_mapping() -> None: def test_estimate_pred_down_prob_from_rsi_uses_linear_mapping() -> None:
assert _estimate_pred_down_prob_from_rsi(None) == 0.5 assert _estimate_pred_down_prob_from_rsi(None) == 0.5
assert _estimate_pred_down_prob_from_rsi(0.0) == 0.0 assert _estimate_pred_down_prob_from_rsi(0.0) == 0.0