Skip to content

Market Strength Dashboard

A decision-grade macro analysis platform that combines recession risk, regime detection, fund-flow analytics, and systemic stress indicators into one governed, point-in-time surface.

Solo builder: product, architecture, implementation

PythonFlaskDuckDBpandasscikit-learnXGBoostSHAPhmmlearnFRED APITiingoRailway
temporal correctnessregime detectionfund-flow analyticsrecession riskproduction-deployedscheduled rebuilds
← Back to all projects

The Problem

The gap was not a lack of charts. Existing tools can show macro series, fund-flow data, or model outputs separately. The problem was the absence of a decision-grade surface: one place that combines recession risk, market regime, systemic stress, and capital rotation into a point-in-time view that does not cheat with future data or hide stale inputs. Without that, reading the macro environment meant manually cross-referencing multiple sources, each with different update schedules, revision histories, and temporal semantics. The question the dashboard answers is simple: should I be leaning risk-on or defensive, and how trustworthy is the signal telling me that?

The Approach

I built a Python-based analysis platform with a governed rebuild pipeline and a single-page frontend. The first screen shows an action-matrix summary, recession risk, market fragility, system stress, economic-health breadth, rates and risk context, and a capital-flows panel with top inflows, outflows, and sector rotation. The entire system is designed around temporal correctness: every signal, model output, and backtest is computed using only information that was available at each point in time. The pipeline rebuilds daily on a schedule, and an operations page exposes pipeline state directly rather than hiding it.

Architecture

The backend is Python with Flask and Gunicorn. The data pipeline uses pandas and NumPy for transformation, DuckDB and PyArrow for analytical storage, and Parquet for intermediate artifacts. Modeling includes scikit-learn, XGBoost with SHAP for feature importance, and hmmlearn for Hidden Markov Model regime inference. Custom modeling code handles nowcasts, historical analogs, revision risk scoring, absorption ratio, and transfer entropy. Data sources include FRED/ALFRED for macroeconomic series, Tiingo and yfinance for market data, Polygon for ETF fund flows, and FMP for the bearish-earnings module. Storage uses JSON, Parquet, DuckDB, and pickle bundles on a Railway-mounted volume. The frontend is a vanilla HTML/CSS/JS single-page app with TradingView Lightweight Charts and custom Canvas renderers. The system tracks 31 macro series plus roughly 19 market tickers, 26 ETF flow tickers, and 15 fund-flow composites. The macro feature table covers 371 monthly rows from June 1995 through April 2026. A 10-year fund-flow archive holds 56,720 records. Rebuilds run daily at 5:30 PM ET on Railway.

Technical Decisions & Tradeoffs

Chose DuckDB over a traditional database for the analytical workload. DuckDB handles columnar queries on Parquet files efficiently without requiring a running database server, which keeps the Railway deployment simple. The tradeoff is less ecosystem support for concurrent writes, but the pipeline is single-writer by design. Separated daily fund-flow analytics from the monthly macro feature table. This added complexity to the data layer but was essential: mixing daily and monthly signals without clean timing semantics would contaminate the point-in-time guarantee. Each data source carries its own effective date, processed date, and local build timestamp as separate fields. Built the frontend as vanilla HTML/JS rather than a framework. For a single-page analytical surface consumed by one user, the simplicity was worth the tradeoff. A React or Next.js frontend would have added build tooling and bundle complexity without proportional benefit. The custom Canvas renderers give full control over how data visualizations render. Used one authoritative rebuild endpoint (/api/rebuild) as the control plane for the entire pipeline. This centralized approach means there is exactly one path for data to enter the system, which makes debugging provenance issues tractable.

What Broke & What I Learned

FRED rate limits were not the main problem. The harder failures were subtler. Partial provider failures were silently interpreted as neutral fund flows. When a data source returned incomplete data instead of an error, the pipeline treated missing values as zero movement rather than flagging the gap. The fix required explicit completeness checks at ingestion: if a provider returns fewer records than expected for the requested window, the pipeline marks that source as degraded rather than interpolating. Temporal correctness was a recurring source of bugs. Label embargoes in recession backtests were initially too short, letting the model see information it would not have had in real time. Nowcasts were being fit on the full history instead of walk-forward. HMM regime probabilities were being computed with the Viterbi algorithm (which uses the full sequence) instead of forward-only filtered probabilities for live interpretation. Each of these was a form of lookahead bias that made backtests look better than the live system would perform. Fixing them required understanding the difference between provider effective date, processed date, and local build time, and enforcing that distinction everywhere. The most important operational failure was a Railway mounted-storage incident. The platform's storage volume served older archive data than the repo image contained, because Railway mounts persist across deploys and the volume had not been invalidated after a schema change. The dashboard rendered without errors but displayed stale signals. The fix was adding provenance checks that verify archive vintage against the current build timestamp at startup. This incident taught me that deployment provenance is a first-class concern, not an afterthought.

Outcomes

The dashboard is deployed on Railway and in active daily use for investment research. The macro dashboard and fund-flows surface are production-verified, with fund flows confirmed operational as of April 2026. The system processes 31 macro series, 19 market tickers, 26 ETF flow tickers, and 15 fund-flow composites on a daily rebuild schedule. The current stored vintage backtest detects 2 out of 2 in-window recession starts. A newer bearish-earnings module has a narrow operator-only watchlist API proven in production, with a broader productionized version in planning. The full pipeline generates a 3.1 MB macro payload and a 1.37 MB fund-flow artifact per rebuild. The operations page surfaces build status, data freshness, and source health directly to the user rather than hiding pipeline state behind the analytical surface.