Issue 1344 — RecessionAlert monthly leading US index

This notebook records an offline, exploratory best-effort campaign. The cached March 3, 2016 article discloses monthly component and recession-probability context but no source-linked observations, complete transformations, publication lag, or buy/sell execution rule. The public proxies below are explicitly inferred and are not a native RecessionAlert replication.

Canonical source SHA256: sha256:deedcf22d1d280248542375b8093cf84c98462b27f8eb4f92d09c0d5e1c8b246; no live request or database write is used.

In [1]:
import sys
from pathlib import Path
for candidate in (Path.cwd(), *Path.cwd().parents):
    if (candidate / 'research').is_dir():
        sys.path.insert(0, str(candidate))
        break

from research.research_campaign.recessionalert_1344 import run_campaign, run_diagnostics

campaign = run_campaign()
diagnostics = run_diagnostics()
print('tested variants:', len(campaign['variants']))
print('families:', sorted({row['family'] for row in campaign['variants']}))
print('timing rows:', len(diagnostics['timing_sensitivity']))
print('regime rows:', len(diagnostics['regime_results']))
print('event rows:', len(diagnostics['event_results']))
print('combination rows:', len(diagnostics['combination_results']))
tested variants: 9
families: ['curve_stress', 'indpro_health', 'unrate_regime']
timing rows: 3
regime rows: 27
event rows: 8
combination rows: 3

Causal protocol

INDPRO, UNRATE, and T10Y3MM are month-end public proxies loaded from the tracked market cache. Lag 1 is the causal baseline (one available monthly bar after the observation); lag 2 is a conservative sensitivity; lag 0 is retained only as a same-close research diagnostic. SPY is the risk-on sleeve and IEF/BIL are descriptive defensive sleeves. Unknown inputs remain unavailable rather than being imputed as neutral or risk-on.

In [2]:
for row in campaign['variants']:
    metrics = row['metrics']['SPY_IEF']
    print(row['id'], 'cagr=', round(metrics['annualized_return'], 4), 'sharpe=', round(metrics['sharpe'], 3), 'drawdown=', round(metrics['max_drawdown'], 4), 'risk_off=', round(metrics['risk_off_fraction'], 3))
recessionalert.1344.indpro_health.lb6.lag0.t0p0 cagr= 0.0959 sharpe= 0.855 drawdown= -0.1761 risk_off= 0.331
recessionalert.1344.indpro_health.lb12.lag1.t0p0 cagr= 0.1055 sharpe= 0.901 drawdown= -0.2393 risk_off= 0.3
recessionalert.1344.indpro_health.lb21.lag2.tm0p5 cagr= 0.0971 sharpe= 0.825 drawdown= -0.2393 risk_off= 0.233
recessionalert.1344.unrate_regime.lb6.lag0.t0p0 cagr= 0.099 sharpe= 0.853 drawdown= -0.2393 risk_off= 0.287
recessionalert.1344.unrate_regime.lb12.lag1.t0p5 cagr= 0.0902 sharpe= 0.818 drawdown= -0.3323 risk_off= 0.329
recessionalert.1344.unrate_regime.lb21.lag2.t0p0 cagr= 0.0709 sharpe= 0.661 drawdown= -0.315 risk_off= 0.364
recessionalert.1344.curve_stress.lb6.lag0.t0p0 cagr= 0.0877 sharpe= 0.66 drawdown= -0.5078 risk_off= 0.156
recessionalert.1344.curve_stress.lb12.lag1.t0p0 cagr= 0.0913 sharpe= 0.687 drawdown= -0.488 risk_off= 0.142
recessionalert.1344.curve_stress.lb21.lag2.tm0p5 cagr= 0.1011 sharpe= 0.739 drawdown= -0.5078 risk_off= 0.073

Result

Nine inferred variants produce executable overlay series and metrics, but those metrics cannot validate the undisclosed RecessionAlert composite. The native gaps remain: the 23-versus-21 component discrepancy, exact transformations and weights, four probability equations and calibration, release/vintage policy, and source-specific buy/sell mapping. Publish derived charts and metrics as exploratory Other / Research evidence only.