Skip to content

Multi-instrument engines

Single-instrument strategies see one symbol and decide long/flat. The engines here are a different shape: they relate or combine many instruments. They’re vectorized (return-level) engines, not registry Strategy subclasses, and each has its own anti-overfit ladder. You reach them from the Backtests builders or the CLI.

ats/workers/cross_sectional.py · python -m ats.cross_sectional

Each rebalance, rank the whole universe by a signal and hold the top-K. Signals: momentum, reversion, low_vol. The benchmark is holding the universe equal-weight, so you judge excess vs equal-weight, not raw return. The load-bearing gate is the rank test: does the real ranking beat N random-selection twins at the same turnover? Then optimize (held-out), walk_forward, and a 2× cost-stress. Honest findings: cross-asset/country momentum is the one cross-sectional edge that clears the bar; the low-vol factor is refuted (a beta tilt, not a timing edge); sector reversion shows no edge. (Cross-sectional has no live order path — a significant result is a research finding until bridged to a rebalance strategy.) A session-aware intraday variant, intraday_relval (python -m ats.intraday_relval), buys the intraday laggard and goes flat by the close.

ats/workers/pairs.py · python -m ats.pairs --legs LQD,HYG

Trade the spread log(A) − β·log(B) between two cointegrated instruments, dollar-neutral — near-zero correlation to a long book, so a validated pair is an ideal diversifier. The hedge ratio β (ats/workers/kalman.py) can be fixed (β=1, the default and validated config), rolling_ols, or kalman (a state-space filter that lets β drift). Same ladder; the gate is the rank test vs random entry timing, and 2× cost stress matters more (both legs trade). Finding: the time-varying hedge did not raise significance on the daily US-ETF universe — simple fixed wins. Discovering pairs (python -m ats.pair_screen) scans for cointegrated candidates (Engle-Granger + OU half-life + β stability); the rank test, not the screen, is the gate.

ats/workers/portfolio.py (blend) and ats/workers/portfolio_search.py (search) · python -m ats.portfolio_search

A sleeve is one ingredient (a strategy on an instrument, or a pair). Portfolio search takes a pool of validated sleeves and searches subsets × allocation methods (equal, inverse-vol, risk-parity, min-variance, max-diversification) for the best held-out Sharpe, with a deflated Sharpe that discounts for the size of the search (a search for high Sharpe is mass multiple-testing). --mode walk_forward re-runs the whole search per window and reports selection stability. Lessons: diversification across uncorrelated edges is the only real Sharpe lever; forcing capital deployment trades against Sharpe; validate the process, not one “best” portfolio.

ats/workers/book.py · python -m ats.book (or Validate faithfully on a search winner)

A portfolio blend combines independently-run single backtests — great for selecting a mix, but not how a live book deploys. A book backtest runs every sleeve as a real strategy on one BacktestEngine / cash account, exactly as the live node, and reports the real per-bar capital deployment (Σ position notionals ÷ equity), the true Sharpe, a capital-efficiency figure, a book walk-forward, and a modeled-vs-faithful gap. Always judge a multi-strategy deployment on the faithful book. (Order-placing registry strategies only — pairs/cross-sectional have no live order path.)

Every portfolio run reports a stress block: rolling 63-day pairwise correlation, behaviour in named crisis windows (COVID, the 2022 rate shock, the book’s own worst window), and a ρ=0.8 correlation-spike vol estimate. Read the spike number as a risk bound, not a forecast — the next regime that breaks diversification rarely resembles the last.