""" Unit tests for WalkForwardEngine window generation logic. """ from datetime import date import pytest from app.services.backtest.walkforward_engine import WalkForwardEngine, Window class TestGenerateWindows: """Test _generate_windows static method.""" def test_basic_windows(self): """2-year period with 12m train, 3m test, 3m step -> 4 windows.""" windows = WalkForwardEngine._generate_windows( start=date(2020, 1, 1), end=date(2021, 12, 31), train_months=12, test_months=3, step_months=3, ) assert len(windows) == 4 assert windows[0].index == 0 assert windows[0].train_start == date(2020, 1, 1) assert windows[0].train_end == date(2020, 12, 31) assert windows[0].test_start == date(2021, 1, 1) assert windows[0].test_end == date(2021, 3, 31) def test_single_window(self): """Exactly 15 months -> 1 window with 12m train + 3m test.""" windows = WalkForwardEngine._generate_windows( start=date(2020, 1, 1), end=date(2021, 3, 31), train_months=12, test_months=3, step_months=3, ) assert len(windows) == 1 assert windows[0].train_start == date(2020, 1, 1) assert windows[0].test_end == date(2021, 3, 31) def test_no_windows_period_too_short(self): """Period shorter than train + test -> 0 windows.""" windows = WalkForwardEngine._generate_windows( start=date(2020, 1, 1), end=date(2020, 12, 31), train_months=12, test_months=3, step_months=3, ) assert len(windows) == 0 def test_partial_last_window(self): """Last window with partial test period is included.""" windows = WalkForwardEngine._generate_windows( start=date(2020, 1, 1), end=date(2021, 2, 15), train_months=12, test_months=3, step_months=3, ) assert len(windows) == 1 assert windows[0].test_end == date(2021, 2, 15) def test_step_larger_than_test(self): """step_months > test_months creates non-overlapping test windows.""" windows = WalkForwardEngine._generate_windows( start=date(2019, 1, 1), end=date(2022, 12, 31), train_months=12, test_months=3, step_months=6, ) assert len(windows) >= 2 # test windows should not overlap for i in range(1, len(windows)): assert windows[i].test_start > windows[i - 1].test_end def test_monthly_step(self): """step_months=1 creates many overlapping windows.""" windows = WalkForwardEngine._generate_windows( start=date(2020, 1, 1), end=date(2021, 6, 30), train_months=6, test_months=3, step_months=1, ) assert len(windows) >= 9 def test_window_indices_sequential(self): """Window indices should be sequential starting from 0.""" windows = WalkForwardEngine._generate_windows( start=date(2019, 1, 1), end=date(2022, 12, 31), train_months=12, test_months=3, step_months=3, ) for i, w in enumerate(windows): assert w.index == i def test_window_dates_consistent(self): """train_end < test_start and test_start <= test_end for all windows.""" windows = WalkForwardEngine._generate_windows( start=date(2019, 1, 1), end=date(2023, 12, 31), train_months=12, test_months=6, step_months=3, ) for w in windows: assert w.train_start < w.train_end assert w.train_end < w.test_start assert w.test_start <= w.test_end