박재오 결정 2026-05-19 — V2를 정식 명칭 ai_trade로 graduation, V1은 deprecated 마킹 (legacy 디렉토리 이동은 file lock 풀린 후 후속). 변경 사항: - signal_v2/ → ai_trade/ (git mv, import 일괄 sed: signal_v2.x → ai_trade.x) - root start.bat → legacy/start_v1.bat (V1 자동 시작 차단) - ai_trade/start.bat 내부 uvicorn target signal_v2.main → ai_trade.main - signal_v1/DEPRECATED.md 추가 (사용 금지 명시) - CLAUDE.md 디렉토리 표·서버 시작 방식 갱신 - services/ 디렉토리 미래 예정 (Plan-B-Insta 작업 시 신설) ai_trade tests 59/59 PASS 확인. signal_v1/ 디렉토리 자체 이동(legacy/signal_v1/)은 telegram_bot.log + data/news_snapshots.db file lock으로 보류. lock 해제 후 후속 커밋. 후속 작업: Plan-B-Insta (services/insta-render + NAS insta 분할) Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
82 lines
2.6 KiB
Python
82 lines
2.6 KiB
Python
"""Tests for scheduler interval logic."""
|
|
from datetime import datetime
|
|
|
|
import pytest
|
|
|
|
from ai_trade.scheduler import _next_interval, _is_market_day, KST
|
|
|
|
|
|
def _kst(year, month, day, hour, minute=0):
|
|
return datetime(year, month, day, hour, minute, tzinfo=KST)
|
|
|
|
|
|
def test_next_interval_pre_market_5min():
|
|
now = _kst(2026, 5, 18, 8, 30) # Monday 08:30
|
|
assert _next_interval(now) == 300
|
|
|
|
|
|
def test_next_interval_market_open_1min():
|
|
now = _kst(2026, 5, 18, 10, 0) # Monday 10:00
|
|
assert _next_interval(now) == 60
|
|
|
|
|
|
def test_next_interval_post_market_5min():
|
|
now = _kst(2026, 5, 18, 17, 0) # Monday 17:00
|
|
assert _next_interval(now) == 300
|
|
|
|
|
|
def test_next_interval_overnight_skip_to_next_morning():
|
|
now = _kst(2026, 5, 18, 2, 30) # Monday 02:30 (dead zone, not NXT window)
|
|
interval = _next_interval(now)
|
|
# Dead zone 23:30-04:30 → next 04:30 is ~2h away
|
|
assert 2 * 3600 - 60 < interval < 2 * 3600 + 60
|
|
|
|
|
|
def test_next_interval_holiday_skip():
|
|
# 2026-05-05 어린이날 (Tuesday holiday)
|
|
now = _kst(2026, 5, 5, 10, 0)
|
|
assert _is_market_day(now) is False
|
|
interval = _next_interval(now)
|
|
# Next: 2026-05-06 (Wed) 07:00, ~21h away
|
|
assert 20 * 3600 < interval < 22 * 3600
|
|
|
|
|
|
def test_next_interval_at_market_open_boundary():
|
|
"""09:00:00 정확 second → 60초 (market 구간 진입)."""
|
|
now = _kst(2026, 5, 18, 9, 0) # Monday 09:00:00
|
|
assert _next_interval(now) == 60
|
|
|
|
|
|
def test_next_interval_at_market_close_boundary():
|
|
"""15:30:00 정확 second → 300초 (post-market 구간 진입)."""
|
|
now = _kst(2026, 5, 18, 15, 30) # Monday 15:30:00
|
|
assert _next_interval(now) == 300
|
|
|
|
|
|
def test_next_interval_at_polling_window_end_boundary():
|
|
"""23:30:00 정확 second → dead zone skip (다음 04:30 까지)."""
|
|
now = _kst(2026, 5, 18, 23, 30) # Monday 23:30:00 (NXT_PRE_END boundary)
|
|
interval = _next_interval(now)
|
|
# Dead zone 23:30-04:30 → next 04:30 is ~5h away
|
|
assert 5 * 3600 - 60 < interval < 5 * 3600 + 60
|
|
|
|
|
|
def test_next_interval_nxt_evening_5min():
|
|
"""22:00 평일 (NXT 야간) → 300 (5분)."""
|
|
now = _kst(2026, 5, 18, 22, 0)
|
|
assert _next_interval(now) == 300
|
|
|
|
|
|
def test_next_interval_nxt_dawn_5min():
|
|
"""05:30 평일 (NXT 새벽) → 300 (5분)."""
|
|
now = _kst(2026, 5, 18, 5, 30)
|
|
assert _next_interval(now) == 300
|
|
|
|
|
|
def test_next_interval_dead_zone_skip():
|
|
"""02:00 평일 (dead zone 23:30-04:30) → 다음 04:30 까지 (~9000s)."""
|
|
now = _kst(2026, 5, 18, 2, 0)
|
|
interval = _next_interval(now)
|
|
# 02:00 → 04:30 = 2.5h = 9000s
|
|
assert 9000 - 60 < interval < 9000 + 60
|