A Bloomberg-style climate-intelligence terminal that turns the El Niño / La Niña (ENSO) cycle into actionable commodity & sector positioning — with the causal rigor to tell which links are real and which are spurious.
Live Demo · The Moat · Screenshots · 9 Pages · Methodology · Run It · Deploy · FAQ
The ENSO Macro Risk Desk is a production-grade, open-source Python dashboard that answers one question for a commodity / macro analyst or climate-aware portfolio manager: when the El Niño–Southern Oscillation (ENSO) cycle shifts, what commodity and sector exposure should you reposition — and which of those links survive causal testing?
It ingests canonical ENSO data directly from NOAA CPC (the Oceanic Niño Index), ERSSTv5 sea-surface-temperature grids, the World Bank Pink Sheet commodity database, and IMD monsoon records. It then runs a dual-model forecasting engine (SARIMA + PyTorch LSTM) and a causal-inference engine (Granger causality + Convergent Cross Mapping) across nine interactive pages — a dark, data-dense terminal UI, no API keys required to start.
The product philosophy is describe → prescribe: every region and commodity ends in a positioning view (constructive / cautious / watch + swing catalyst + risk), not just a chart.
Who it's for: commodity & macro research analysts, climate-risk and energy-transition desks, agricultural economists, and data-science portfolio reviewers.
TL;DR
- 🌍 ENSO Exposure Index — a world choropleth + leaderboard ranking where an ENSO swing reprices commodity & sector risk.
- 🔬 Causal rigor as the moat — Granger + Convergent Cross Mapping (CCM) separate real ENSO→price links from spurious ones. Most don't survive — and that's the honest headline.
- 📈 12-month forecasts — SARIMA + LSTM ensemble, walk-forward backtested, beating persistence at all 12 leads.
- 🛰️ Live data — NOAA CPC ONI + ENSO advisory fetched at runtime; ERSSTv5 SST grids; 71 World Bank commodities.
- 🇮🇳 Region deep-dives — India (ENSO × Indian Ocean Dipole → monsoon → food CPI) and SE Asia (palm oil), each ending in a desk view.
- 🚀 Live & auto-deployed — running on Hugging Face Spaces, CI/CD from GitHub.
The Macro Risk Desk landing — left rail (Niño-3.4 gauge, ONI trajectory, 12-month forecast cone), the world ENSO Exposure Index choropleth, a most-exposed-regions leaderboard, and the causation strip (the honesty layer):
Anyone can plot a correlation between El Niño and cocoa prices. The hard — and honest — part is asking does it survive a causal test? This desk runs two complementary engines on every ONI→commodity link:
- Granger causality (linear): does lagged ONI add predictive power over the commodity's own history?
- Convergent Cross Mapping / CCM (nonlinear, Sugihara et al. Science 2012): does cross-map skill rise and converge with library size in one direction only? Self-coded via simplex projection — no
pyEDMdependency.
The result is deliberately humbling. Of the six headline ONI→commodity-price links on the desk, none is strongly causal (max CCM ρ ≈ 0.32); palm oil & wheat are only moderate, the rest weak / confounded. So the takeaway the desk leads with is:
Most ENSO→commodity-price trades the market makes don't survive causal testing. The clean ENSO signal lives on the climate & production side — the monsoon and Maritime-Continent drought we prove in the region deep-dives — not in noisy monthly prices.
That "misattribution guard" — showing the computed verdict instead of an asserted one, even when it undercuts a tidy narrative — is the whole point. Cocoa and wheat were expected to fail; the data said wheat is actually one of the stronger ones, and the desk reports that, not the assumption.
| # | Page | What it does |
|---|---|---|
| 00 | Macro Risk Desk (landing) | Command-bar terminal: Niño-3.4 gauge · ONI trajectory · forecast cone · ENSO Exposure Index choropleth · most-exposed leaderboard · causal-test strip |
| 01 | ENSO Monitor | Live ONI + RONI dual series (1950–present), gauge, live NOAA advisory badge, CSV export |
| 02 | Global SST Map | ERSSTv5 2°×2° anomaly grids, flat + orthographic globe, teleconnection zones |
| 03 | Forecast | SARIMA + LSTM + ensemble fan chart, CI bands, ACC-vs-lead skill |
| 04 | Sector Impact | Detrended lag-correlation heatmap, ONI × 71 commodities, lags 0–24 mo |
| 05 | Causation Explorer | Live Granger + CCM, both directions, plain-language verdict |
| 06 | Historical Events | Per-event cards since 1950: peak ONI/RONI, Callahan & Mankin 2023 GDP losses |
| 07 | 🇮🇳 India deep-dive | ENSO × IOD → monsoon → food CPI; real OLS regression (n=117); desk view |
| 08 | 🌴 SE Asia deep-dive | Palm oil; honest WATCH — the ENSO-premium story fails its own composite |
916 ENSO months · 42 events detected · 71 commodities · 2°×2° global SST grids from 1854 · 12-month forecast horizon · zero API keys required.
Two models share an identical walk-forward verification harness, scored against a persistence reference (last observed ONI held constant):
| Model | Type | Architecture | Result |
|---|---|---|---|
| SARIMA | Statistical | statsmodels SARIMAX(2,0,1)(1,0,0,12) | Beats persistence at all 12 leads ✅ |
| LSTM | Deep Learning | PyTorch, 2-layer, 64 hidden | Beats persistence at all 12 leads ✅ |
Honest result: SARIMA outperforms the LSTM on this short univariate ONI series. The LSTM needs ancillary indices (IOD/MJO/PDO) or spatial SST fields (CNN track) to close the gap — framing it otherwise would misrepresent the evidence. Both models' skill (ACC) drops below the 0.5 useful-skill threshold at 6–8 months, consistent with the ENSO spring predictability barrier.
Both tests run on linearly detrended (not differenced — differencing kills the low-frequency ENSO band) ONI vs. commodity series:
- Granger causality (linear): F-test across lags 0–24.
- Convergent Cross Mapping (nonlinear): in-repo simplex projection (NumPy/SciPy), no pyEDM (its multiprocessing is incompatible with the Panel server on Windows). Genuine causation → cross-map skill rises and converges with library size in one direction only.
Surrogate (phase-randomized) significance testing is on the roadmap; current verdicts are exploratory.
NOAA CPC · ERSSTv5 · World Bank · IMD data/ingest/ ──► data/cache/*.parquet
data/process/ ──► (phases · RONI · Granger+CCM · exposure index)
│
forecasting/ (SARIMA · LSTM · ensemble · skill) ──► forecasts/skill caches
│
▼
app.py ──► HoloViz Panel + Plotly ──► 00 Desk · 01 Monitor · 02 Map · 03 Forecast
04 Impact · 05 Causation · 06 History · 07 India · 08 SE Asia
│
Dockerfile ──► 🤗 Hugging Face Space (CI/CD from GitHub)
The dashboard reads parquet caches only — the heavy ingest/forecast pipeline (PyTorch, xarray, netCDF4) runs offline, so the deployed image is lean and serves instantly.
Requires Python 3.12 (Hugging Face Spaces parity; the ML/geo stack lacks wheels on newer builds).
# 1 — environment
py -3.12 -m venv .venv
.venv\Scripts\activate # Windows · source .venv/bin/activate on macOS/Linux
# 2 — dependencies
pip install -r requirements.txt
# 3 — (optional) refresh live data into data/cache/*.parquet
python data/ingest/oni_fetcher.py -v
python data/ingest/pink_sheet.py -v
# 4a — serve the whole site (landing at / + all 9 pages) via the unified entry point
python app.py # → http://localhost:5006
# 4b — or serve a single page
panel serve dashboard/pages/00_landing.py --showNo API keys required for any module — every data source is free and public.
Live now: el-nino-green.vercel.app (Next.js front-door on Vercel — prewarms the app host on visit) → huggingface.co/spaces/DogInfantry/enso-macro-risk-desk (the app — Docker SDK, free CPU Basic).
Panel/Bokeh is a long-running WebSocket server, so the app ships as a Docker Space (not Gradio/Static, and not Vercel without WASM conversion) running real panel serve via app.py. The web/ directory is a static-exported Next.js 15 landing page deployed on Vercel; it deep-links into the Space and polls the HF runtime API for live status. Data caches are refreshed monthly with one command: python scripts/refresh_data.py. A GitHub Action (.github/workflows/deploy-hf.yml) auto-syncs the Space on every push to master — push to GitHub → the Space redeploys itself, and each run is recorded under the repo's Deployments tab. The serve-only dependency set (requirements-space.txt) excludes torch/xarray/kaleido, keeping the image small.
| Source | Provider | Module | Auth |
|---|---|---|---|
| ONI ASCII feed | NOAA CPC | oni_fetcher.py |
None |
| ENSO Diagnostic Discussion (PDF) | NOAA CPC / IRI | advisory_fetcher.py |
None |
| Pink Sheet — monthly commodities | World Bank | pink_sheet.py |
None |
| ERSSTv5 netCDF grids | NOAA NCEI | ersst_fetcher.py |
None |
| IMD 36-subdivision rainfall (JJAS monsoon) | India Met. Dept. | monsoon_fetcher.py |
None |
| ERA5 reanalysis · USDA NASS · EM-DAT | Copernicus / USDA / CRED | (roadmap) | Free |
Rigorous analysis means disclosing limits. Read before drawing conclusions.
- ONI vs RONI. Charts label every index. On 16 Feb 2026 NOAA adopted RONI (subtracts tropical-mean SST to remove background warming) as the official ENSO index; under RONI the 2023–24 El Niño is ~0.6 °C cooler. Don't compare ONI- and RONI-classified events directly. This repo's RONI is computed from ERSSTv5 on a fixed 1991–2020 base — it approximates the official value.
- The 3-month mean lags raw Niño-3.4. A weekly spike can precede the smoothed ONI crossing ±0.5 °C by ~2 months. Current phase is fetched live, never hardcoded.
- Correlation ≠ causation. Sector links are detrended Pearson r; the IOD and MJO can drive spurious co-movement. Causal direction needs Granger / CCM (Page 05) — and most price links fail it (see The Moat).
- Exposure Index is a research construct — 50% computed peak lagged ONI–commodity correlation + 50% curated structural exposure. Not an official product.
- Source freshness. The World Bank Pink Sheet workbook currently ends 2024-12; fetchers degrade gracefully to cache. India crop/CPI tabs are illustrative pending USDA/FAOSTAT ingestion.
What is the ENSO Macro Risk Desk?
It's an interactive Python dashboard that maps the El Niño–Southern Oscillation (ENSO) cycle to commodity and sector risk, and stress-tests each link with causal inference (Granger + Convergent Cross Mapping). It's built for commodity/macro analysts and climate-risk desks, and it's live on Hugging Face Spaces.
What is ENSO, and why does it matter for commodity markets?
ENSO is the dominant year-to-year driver of global climate variability. El Niño (ONI ≥ +0.5 °C) suppresses rainfall in Southeast Asia and Australia and enhances it on South America's west coast; La Niña (ONI ≤ −0.5 °C) reverses it. Because ENSO disrupts rainfall in the world's key agricultural zones, it is linked to price shocks in wheat, maize, rice, coffee, cocoa, and palm oil — typically 3–9 months after the SST anomaly peak.
What is the difference between ONI and RONI?
ONI is the 3-month running mean of Niño-3.4 SST anomalies against a rolling 30-year base. RONI (Relative ONI) subtracts the tropical-mean (20°S–20°N) anomaly, removing the warming trend that increasingly inflates ONI. NOAA adopted RONI as the official ENSO index in February 2026; under it the 2023–24 El Niño is ~0.6 °C weaker.
What is Convergent Cross Mapping (CCM)?
CCM (Sugihara et al., Science, 2012) is a nonlinear causal-inference method for dynamical systems. It tests whether X drives Y by checking whether Y's reconstructed attractor can recover X's states — and whether that cross-map skill converges as the observation library grows. Unlike Granger causality it doesn't assume linearity. This project implements CCM in-repo via simplex projection (NumPy/SciPy), without pyEDM, for Windows/Panel compatibility.
Is it really live? How is it deployed?
Yes — running on Hugging Face Spaces as a Docker Space serving panel serve via app.py, on the free CPU tier (it may cold-start after inactivity). A GitHub Action auto-redeploys on every push to master.
Why does SARIMA outperform the LSTM?
ONI is a short (~70-year) quasi-periodic univariate signal that SARIMA exploits directly through its seasonal AR structure. Without ancillary indices (IOD/MJO/PDO) or spatial SST input (CNN track), the LSTM lacks the signal to overcome SARIMA's parsimony at this data scale — an honest, common finding for short univariate climate series.
Can I run it on macOS or Linux?
Yes. Swap .venv\Scripts\activate for source .venv/bin/activate; the rest is cross-platform. The only Windows-specific choice is avoiding pyEDM — the in-repo CCM is fully portable.
Data © respective providers: NOAA/NWS (ONI, advisory, ERSSTv5), World Bank (Pink Sheet), India Meteorological Department (monsoon), Copernicus/ECMWF, USDA, FAO, CRED (EM-DAT). Code & dashboard: research and educational use — cite the primary data sources when reusing outputs.
Key reference: Callahan, C. W. & Mankin, J. S. (2023). Persistent effect of El Niño on global economic growth. Science, 381, 789–793. DOI: 10.1126/science.adf0374
Built with HoloViz Panel, Plotly, PyTorch, statsmodels, and data from NOAA CPC and the World Bank.
Topics: el-nino · la-nina · enso · enso-forecast · climate-risk · commodity-markets · macro-research · teleconnections · oceanic-nino-index · oni · roni · nino-3.4 · granger-causality · convergent-cross-mapping · ccm · sarima · lstm · time-series-forecasting · climate-finance · indian-ocean-dipole · monsoon · palm-oil · sea-surface-temperature · python-dashboard · holoviz-panel · plotly · data-visualization




