The Macro Lens framework
This page is the canonical specification for how Macro Lens reads the market every weekday morning. It is the transparency artifact — the one place where the technical detail is fully exposed so that any serious reader, RIA, regulator, or skeptic can verify the work.
The framework has a version number. Current version is v2.3. Revisions are announced here with effective dates and rationale.
What we measure — thirteen sensors
Every weekday morning, before any AI is involved, the engine reads thirteen sensors: six rotation ratios that combine into the regime score, three macro dials that frame the conditions underneath, and four physical-market sensors — the Brent oil price, the Brent−WTI supply-shock spread, Cushing hub inventories, and refining stress — that watch the physical energy market for stress. The six ratios below carry the analytical weight of the daily call; the three dials and the four physical-market sensors (documented after the aggregate read) are descriptive context and do not move the score.
The six rotation ratios (the regime score)
The engine computes six rotation signals from publicly available daily close prices:
| # | Signal | What it reads |
|---|---|---|
| 1 | Tech leadership | Whether semiconductors are leading the broader market — a proxy for growth and risk appetite |
| 2 | Consumer strength | Whether discretionary spending is rotating into defensive staples — the consumer cycle in real time |
| 3 | Risk appetite (rates + risk) | Whether financials are leading utilities — the rate environment and risk-on signal |
| 4 | Small-cap participation | Whether small companies are participating in the rally or being left behind — the breadth signal |
| 5 | Credit conditions | Whether high-yield corporate bonds are outperforming long Treasuries — the leading-indicator signal of stress |
| 6 | Energy pressure | Whether energy is leading the broader market — the fast, energy-led inflation/commodity read |
Each signal is computed as a ratio of two ETFs. The specific ETF pairs used are documented internally and are not particularly important to a reader; what matters is what the ratio measures. The signals together cover growth, the consumer cycle, the rate regime, breadth, credit stress, and inflation pressure — the six axes that broadly govern US-market behavior.
How each signal is classified
For each signal, the engine computes two moving averages on the daily close price ratio:
- Fast — a 21-day simple moving average (approximately one trading month)
- Slow — a 50-day simple moving average (the most-watched intermediate-term reference)
The classification rule for each signal is mechanical:
| State | Condition |
|---|---|
| Constructive | the ratio is above its fast line and the fast line is above the slow line |
| Cautious | the ratio is below its fast line and the fast line is below the slow line |
| Mixed | any other configuration |
The 21- and 50-day periods are deliberate. They align with how institutional flows are framed and avoid the whipsaw of shorter periods. They are not optimized to a backtest, and they are not changed without a published methodology revision.
How the aggregate read is built
The aggregate market read is derived from the count of signals in each state:
| Aggregate read | Count condition | Confidence |
|---|---|---|
| All clear | 5 or 6 signals constructive | High |
| Mostly clear | 4 signals constructive | Medium |
| Mixed signals | anything else | Low |
| Some caution | 4 signals cautious | Medium |
| Cautious | 5 or 6 signals cautious | High |
A reader who downloads the same ETF closing prices from any free source — yfinance, Yahoo Finance, Google Finance, the Wall Street Journal, an SEC filing — and reproduces the moving averages will arrive at the same aggregate read. The math is reproducible from public data. That reproducibility is the entire point.
The three macro dials — descriptive context
Alongside the six rotation ratios, the engine reads three slower macro dials from the Federal Reserve's FRED database. They frame the conditions the ratios move inside, but they are descriptive context only — they do not change the six-ratio regime score.
| # | Dial | What it reads | FRED series |
|---|---|---|---|
| 7 | Yield curve | 10-year minus 2-year Treasury yields; inversion has historically preceded recessions | T10Y2Y |
| 8 | Inflation expectations | 10-year breakeven — the bond market's expected average inflation over the next decade | T10YIE |
| 9 | The dollar | Broad, trade-weighted U.S. dollar index; a strong dollar tightens global conditions | DTWEXBGS |
Each dial is a band signal with hysteresis — it changes state only on a real, sustained move — and carries decades of backfilled flip history. The six ratios report what investors are doing; the three dials report the conditions they are doing it in.
The oil sensors — physical-market stress
The tenth sensor is the oil price — a level dial on front-month Brent
crude (read from the free public ICE Brent BZ=F futures series). The eleventh sensor
is a band signal (with hysteresis, like the dials) on the Brent−WTI
crude spread — the gap between the world oil benchmark (Brent, priced at
sea) and the U.S. benchmark (WTI, priced inland at Cushing). Both are read
daily from free public front-month futures, with FRED spot as a fail-open fallback.
| # | Sensor | What it reads | Source series |
|---|---|---|---|
| 10 | Oil price | Front-month Brent level (BZ=F futures; FRED spot fallback); a level dial on the world oil benchmark — the absolute price of oil, not the spread |
BZ=F |
| 11 | Oil supply shock | Brent minus WTI (front-month futures); bands set from the spread series' own recent distribution; a wide gap flags physical-supply stress | BZ=F, CL=F |
In the modern export era a self-correcting export arbitrage loosely
tethers the spread near the cost of shipping a barrel from the U.S. Gulf
Coast to a seaborne buyer — but that is not a fixed anchor (the spread
ranges widely with the export cycle). The three-state bands are therefore
derived from the BZ=F − CL=F futures spread's own recent history:
stressed (gap unusually wide, enter ≈ $5.50 ≈ 85th pct, exit ≈ $4.50),
normal (the broad middle of the distribution), compressed (unusually
narrow, enter ≈ $2.20 ≈ 10th pct — futures Brent rarely falls below WTI). We
price off the futures tape because FRED's spot series lags by ~a week; the
FRED DCOILBRENTEU − DCOILWTICO spread stays as a lagged cross-check and
fallback (a few dollars narrower — a definition difference, not an error).
While stressed, a
sub-type reads why: risk-premium when Brent is rising (a
seaborne-supply threat) or us-glut when Brent is flat or falling (a
U.S. storage bottleneck — the 2011–2013 and April-2020 pattern). It lives
in the Early Warning Signs group. A wide gap means supply-chain stress —
not a promise that fuel prices spiral; demand can absorb a shock.
The hub-inventory and refining-stress sensors (12 & 13)
Two more physical-market sensors join the Early Warning Signs group — the price sensors tell you what oil costs; these read the barrels and the fuels.
The twelfth sensor is hub inventories — crude held at Cushing, Oklahoma (the WTI delivery point), read weekly from the EIA Petroleum Status Report as a percent of working storage capacity (comparable across a history over which capacity grew ~48M → ~78M barrels; capacity from EIA's semi-annual report, linearly interpolated, step-held after the latest). Four states with hysteresis and a weekly dwell: tank_bottom (≤ ~28% — at/near the operational floor, where not all stored oil can be delivered), tight (≤ ~40%), comfortable (the middle), glut (≥ ~88% — near-full). It reads the physical layer the price sensors are blind to; it would have flagged the 2026 Cushing squeeze in real time. Cadence is disclosed: "weekly, as of week ending {date}".
The thirteenth sensor is refining stress — the 3-2-1 crack spread, the
refining margin between crude and the fuels it becomes, computed daily from
front-month futures with the formula published in full:
crack = (2×gasoline + 1×diesel − 3×crude) ÷ 3 ($/bbl; RBOB RB=F, ULSD HO=F, WTI
CL=F; gasoline/diesel ×42 gal→bbl). Four states from the recent-5-year $/bbl
distribution: compressed (≤ ~$18 — margins below operating cost, run-cut
territory), normal, elevated (≥ ~$42), extreme (≥ ~$57 — the 2022 and 2026
crises both land here). Strong fuel prices during weak crude mean refining is the
bottleneck, not that demand is strong — this reads that layer directly.
Thirteen sensors in all.
Edge cases the engine must handle
The engine is built for the live tape, which is messy. It explicitly handles:
-
Insufficient data. If a signal does not have at least 50 days of price history (rare, only on a newly-listed ticker), it is marked "no data" and excluded from the count. Aggregate confidence drops to "low" if any signal is missing.
-
Stale data. If the most recent close is more than four calendar days old, the engine logs a warning. Markets close on weekends and holidays, so the four-day tolerance covers long weekends without firing false alarms.
-
Data fetch failure. If the price feed returns empty for any ticker, the engine retries once after a short delay. If that also fails, it falls back to the last persisted aggregate read and the morning brief explicitly notes the data issue.
-
Same-day repeat calls. The aggregate read is computed at most hourly during market hours and at most every six hours after close. Repeated calls hit a cache, which keeps the engine cheap and prevents redundant external API calls.
What the framework does NOT do
- It does not predict short-term price direction. A constructive read is not a buy signal; a cautious read is not a sell signal.
- It does not generate buy or sell signals on individual stocks. Macro Lens addresses the market and the regime — never specific securities.
- It does not "time the market" in the literal sense.
- It does not replace fundamental analysis or risk management or the diversification a sensible investor already maintains.
What it does do, reliably, is keep the reader positioned with the prevailing flow of capital and out of the way when that flow reverses. Across history, that alone is more durable than most signal frameworks designed for retail.
Versioning policy
The framework is versioned. The current version is v2.3 — the revision that added two physical-market sensors to the Early Warning Signs group: Cushing hub inventories (weekly EIA working-stocks utilization) and refining stress (the 3-2-1 crack spread from front-month futures), bringing the framework to thirteen sensors. Version v2.2 added the oil price (Brent) sensor; version v2.1 added the oil supply-shock sensor (the Brent−WTI crude spread); version v2.0 added the three Tier-0 macro dials (yield curve, inflation expectations, the dollar) alongside the six rotation ratios.
Future revisions may:
- Add additional signals — for example, a volatility overlay, a breadth confirmation signal, or a rates-sensitivity ratio
- Adjust aggregation thresholds based on observed false-positive rates
- Add a momentum confirmation layer
Version history is maintained on this page with effective dates. This is how a serious analytical publication treats its own infrastructure.
Corrections
Correction — July 2026 (oil supply-shock sensor). For a period ending
in July 2026, the oil supply-shock sensor labelled an ordinary Brent−WTI
spread as compressed. The cause was not a calculation error — the
engine always computed Brent minus WTI in the correct direction — but a
definition-and-calibration gap. At the time, the sensor read the reproducible FRED
spot series (DCOILBRENTEU − DCOILWTICO), while its state bands had
been anchored to the ~$4 futures "shipping-cost" narrative rather than to
the spot series' own distribution. Because that spot spread has a long-run
median near zero — and was negative for most of the pre-shale era — the old
"compressed below ~$1" threshold sat almost exactly at the median, so
routine readings were mislabelled. The immediate fix: the bands were re-derived
directly from that series' own historical
percentiles, the pinned spread convention lives in one tested constant,
the flip history has been recomputed from source data, and a daily
plausibility monitor now cross-checks the sensor's direction and freshness,
flagging any implausible or stale reading for review. The methodology text
was corrected to match. We publish this in the spirit of the "check us"
promise — surfacing exactly this kind of gap is why the promise exists.
Update — July 2026 (oil sensors → live futures). Shortly after the
correction above, a second, deeper gap surfaced: FRED relays the EIA spot
series with about a week's lag, so a sensor whose job is "what changed
today" was structurally reading week-old data — a published brief showed oil
dated seven days earlier. The bands were fine; the source was the defect.
Both oil sensors now price off the front-month futures tape — ICE Brent
(BZ=F) and NYMEX WTI (CL=F), the same daily feed the six ratios use —
classified only on settled closes so a state flip is never dated on a
mid-day tick, with FRED spot demoted to a lagged cross-check and fail-open
fallback. Because futures spreads run a few dollars wider than spot, the bands
were re-anchored to the futures spread's own recent distribution (enter-stressed
≈ $5.50), and the flip history was recomputed on the new source. Reproducibility
is preserved by naming the exact public symbols.
How the AI synthesis layer fits in
The framework above produces a single structured output every morning: the aggregate read, the per-signal states, and a small set of narrative hooks (which signals are leading, which are lagging, which are close to a state change). That structured output is the input to the AI synthesis layer.
The AI's job is to translate that structured input into plain-language prose. It is constrained — by prompt and by post-output validation — from contradicting the framework. If the framework reports constructive, the prose sounds constructive. If the framework reports cautious, the prose sounds cautious. The AI carries voice; the framework carries the analytical weight.
This separation is the single most important design decision in the product. Generic AI-fintech products mix the two layers, which is why their output is unreliable. Macro Lens keeps them clean.
Reproducibility — the trust artifact
If you want to reproduce a Macro Lens read for any historical date:
- Pull daily close prices for SMH/SPY, XLY/XLP, XLF/XLU, IWM/SPY, HYG/TLT, XLE/SPY for the prior 200 days
- Compute the 21-day and 50-day simple moving averages of each ratio
- Classify each ratio as constructive / cautious / mixed using the rule above
- Count and aggregate using the table above
You will arrive at exactly the same aggregate read the engine arrived at. There is no proprietary feed, no private model, no hand-tuning. That reproducibility is what we publish — and it is the foundation of every brief and every "Should I worry?" answer.
Methodology version 2.3 · Last updated: 2026-07-22
Revisions to the framework will be announced on this page and in the methodology page with effective dates and rationale.