Skip to content

feat(pipeline): #503 Phase 3a — warmup_window validation#508

Merged
MDUYN merged 4 commits into
feat/502-pipeline-api-phase2-vectorfrom
feat/503-pipeline-api-phase3-live
May 4, 2026
Merged

feat(pipeline): #503 Phase 3a — warmup_window validation#508
MDUYN merged 4 commits into
feat/502-pipeline-api-phase2-vectorfrom
feat/503-pipeline-api-phase3-live

Conversation

@MDUYN

@MDUYN MDUYN commented May 2, 2026

Copy link
Copy Markdown
Collaborator

Stacked on #507 (Phase 2). Closes the first milestone of #503.

What

When a strategy declares pipelines = [...], TradingStrategy.__init__ now validates that every OHLCV data source has warmup_window >= pipeline.required_window(). If any source is short — or warmup_window is left unset — strategy instantiation raises OperationalException with an actionable message listing the offending sources and the required window size.

Why

Without this guard, a live bot silently trades on NaN factor columns until enough bars accrue. This is a known footgun for live deployments on AWS Lambda / Azure Functions where warm-container restarts can swallow startup warnings.

What's not in scope

  • 3b — streaming panel updates
  • 3c — partial-bar handling
  • 3d — live observability hooks

These will follow in stacked PRs.

Tests

  • 6 new tests in `tests/app/test_pipeline_warmup_validation.py` covering: sufficient/insufficient/unset warmup_window, no OHLCV source, no pipelines (zero-cost path), and multi-pipeline max-window aggregation.
  • Full regression suite: 1400 passed, 42 skipped, no regressions.
  • flake8 clean on touched files.

Docs

  • `docusaurus/docs/Advanced Concepts/pipelines-live.md` — added "Warmup validation (shipped)" section, marked the bullet ✅ in the Phase 3 plan.

Refs: #503

…ion (#503 phase 3a)

When a strategy declares pipelines=[...], TradingStrategy.__init__ now checks that every OHLCV data source has warmup_window >= pipeline.required_window() and raises OperationalException with an actionable message otherwise. Without this guard a live bot silently trades on NaN columns until enough bars accrue.

- 6 new tests covering: sufficient/insufficient/unset warmup, no OHLCV source, no pipelines (zero-cost), and multi-pipeline max-window aggregation.

- pipelines-live.md: mark warmup validation shipped.
…esilience (#503 phase 3b/3c/3d)

Completes the framework-side hardening for live pipeline trading.
Async/batched CCXT fetch (#503's last bullet) is deferred to a
follow-up because it needs live integration testing.

Phase 3b — Live envelope validation
  * Strategies that declare pipelines and run in any non-BACKTEST
    environment are validated once per run against a v1 envelope:
      - Maximum 50 unique OHLCV symbols per strategy
      - Daily-or-coarser timeframes only
  * Violations raise OperationalException with an actionable message
    naming the strategy and the offending symbols / timeframe.
  * Backtests are completely unaffected (no-op).

Phase 3c — Universe-refresh cadence
  * New Pipeline class attribute 'refresh_universe_every: timedelta'.
  * When set, the engine caches the surviving symbol set after each
    refresh and reuses it on subsequent bars within the cadence,
    skipping universe-filter evaluation entirely. Factors are still
    recomputed every bar.
  * Default None preserves Phase 1 / Phase 2 behaviour exactly.

Phase 3d — Per-pipeline resilience
  * In live (non-BACKTEST) mode a single failing pipeline.evaluate()
    is logged and the iteration continues with an empty output for
    that pipeline. Backtests still re-raise so failures stay
    deterministic.

Tests
  * 12 new tests in tests/app/test_pipeline_live_hardening.py covering
    sub-daily rejection, >50-symbol rejection, no-pipeline pass-through,
    backtest skip, one-shot validation, all four cadence-cache cases,
    and live-vs-backtest error handling.

Docs
  * docusaurus/docs/Advanced Concepts/pipelines-live.md updated with
    Live envelope, Universe refresh cadence, and Per-pipeline
    resilience sections.

Full regression: 1344 passed, 3 skipped.
MDUYN added 2 commits May 4, 2026 10:32
CI uses 'unittest discover' and does not install pytest as a dev
dependency, so 'import pytest' caused ImportError on the runner.
Rewrites all assertions/raises to native unittest.TestCase APIs.
No production code changes; behavior covered is identical.
Same fix as the previous commit — CI uses 'unittest discover' which
doesn't have pytest available. Converts test_vector_pipeline_engine,
test_factor_arithmetic_and_lazy, and test_vector_backtest_pipeline_injection
to native unittest.TestCase, with pytest.approx -> assertAlmostEqual,
pytest.raises -> assertRaises, parametrize -> subTest, monkeypatch ->
unittest.mock.patch.object, and caplog -> assertLogs.
MDUYN added a commit that referenced this pull request May 4, 2026
CI uses 'unittest discover' which doesn't have pytest available.
pytest.approx -> assertAlmostEqual, pytest.raises -> assertRaises.
Includes the test_factors/test_pipeline/test_pipeline_engine and
phase-2/3 conversions cherry-picked from PRs #506 and #508.
@MDUYN MDUYN merged commit abdec3b into feat/502-pipeline-api-phase2-vector May 4, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant