Issue 1348 — RecessionAlert Weekly Leading Economic Index¶
This notebook is exploratory research, not an official WLEI reconstruction. The SHA-verified cached article documents a weekly growth index built from more than 20 weekly series in six broad categories, at most a one-week input lag, and Thursday-afternoon publication. It does not disclose source-linked observations, formula, threshold, portfolio action, or recurring vintage metadata.
The experiment therefore uses checked-in FRED/Yahoo snapshots only. Monthly proxies are carried to Friday evaluation bars after their dated observations; the primary execution policy uses one available weekly bar of lag. Same-close is shown only as a research timing sensitivity.
from research.research_campaign.recessionalert_1348 import (
PROXY_SERIES, default_variants, evaluate_variant, load_weekly_inputs,
weekly_market_inputs, SOURCE_SHA256,
)
inputs = load_weekly_inputs()
market = weekly_market_inputs(['SPY', 'IEF'])
print('Loaded proxies:', ', '.join(inputs))
print('Proxy signal histories: 1948-02-20..2026-07-10 (v1) through 1986-06-13..2026-06-19 (v3)')
print('SPY/IEF overlay window: 2002-08-09..2026-07-24')
print('Variants executed:', len(default_variants()), '(four causal/inferred or speculative plus one same-close sensitivity)')
print('Canonical source:', SOURCE_SHA256)
Frozen trial summary¶
The common investable comparison uses a lagged risk-off state: SPY in risk-on weeks and IEF in risk-off weeks. Unavailable warm-up states are excluded rather than treated as risk-on. Every number below is a descriptive proxy result; none is a native RecessionAlert claim.
import numpy as np
import pandas as pd
from research.research_campaign.recessionalert_1348 import *
inputs = load_weekly_inputs()
market = weekly_market_inputs(['SPY', 'IEF'])
prices = pd.concat(market, axis=1).sort_index()
returns = prices.pct_change(fill_method=None)
start, end = pd.Timestamp('2002-08-09'), pd.Timestamp('2026-07-24')
def stats(series):
values = series.loc[start:end].dropna()
equity = (1 + values).cumprod()
years = (values.index[-1] - values.index[0]).days / 365.25
annualized = equity.iloc[-1] ** (1 / years) - 1
volatility = values.std(ddof=1) * np.sqrt(52)
return annualized, annualized / volatility, (equity / equity.cummax() - 1).min()
annualized, sharpe, drawdown = stats(returns['SPY'])
print(f'SPY baseline annualized={annualized:.6f} sharpe={sharpe:.6f} max_drawdown={drawdown:.6f}')
for variant in default_variants():
result = evaluate_variant(variant['family'], inputs, lookback=variant['lookback'], threshold=variant['threshold'], lag_bars=variant['lag_bars'])
state = result['risk_off'].reindex(returns.index)
overlay = ((1 - state) * returns['SPY'] + state * returns['IEF']).where(state.notna())
annualized, sharpe, drawdown = stats(overlay)
risk_off_pct = state.loc[start:end].mean() * 100
print(f"{variant['id']} annualized={annualized:.6f} sharpe={sharpe:.6f} max_drawdown={drawdown:.6f} risk_off_pct={risk_off_pct:.3f}")
Interpretation and gaps¶
The one-bar weighted variants underperform same-window SPY; the diffusion threshold is degenerate all-risk-off; acceleration is the strongest causal proxy in this small grid but remains speculative and has a large drawdown. Same-close appears better than the causal baseline, demonstrating lookahead sensitivity.
The native WLEI observation span, exact formula, threshold/state mapping, point-in-time release clock, revision policy, and buy/sell/hold semantics remain undisclosed. Follow-up work requires an authorized source-linked dataset or an explicitly independent constituent reconstruction.
from research.signal_spec.validate import validate_spec
for variant in default_variants():
result = evaluate_variant(variant['family'], inputs, lookback=variant['lookback'], threshold=variant['threshold'], lag_bars=variant['lag_bars'])
assert not validate_spec(result['spec'], require_implementable=True)
valid = result['signal'].notna() & result['dsl_signal'].notna()
assert valid.any()
assert (result['signal'][valid] - result['dsl_signal'][valid]).abs().max() <= 1e-12
print('Validated 5 generated SignalSpecs and zero imperative-vs-DSL parity error on available dates.')