Open, reproducible pipeline for EU Emissions Trading System analysis from free public data
Project description
carbon-ets
Open, reproducible pipeline for EU Emissions Trading System (EU ETS) analysis from free public data.
Everything runs on published, non-paywalled sources: EEX primary-auction clearing prices, Eurostat industrial production, European Commission MSR Communications, and Open-Meteo weather. Free replacement for ~€20-50k/year of paid EU ETS data infrastructure.
Companion code to Causal Systems research report Factories to carbon.
Try it in 30 seconds: click the "Open in Colab" badge above.
What's in the box
- Historical EUA prices 2012-present — daily primary auction clearing prices scraped from EEX archive
- Eurostat industrial production — via SDMX bulk endpoint with JSON-stat fallback
- TNAC reference series 2016-2025 — verified values from every Commission Communication PDF, with primary-source citations
- MSR mechanism helpers — thresholds, invalidation history, regime-context lookup for any TNAC value
- Feature engineering — log returns, z-scores, momentum, realised volatility, IP YoY
- V1 baseline backtest — long-only causal-chain strategy from the CS/RES/05 report
- Markov-switching regression — two-regime model for EUA return dynamics (descriptive, not predictive)
- Standard plots — equity curves, TNAC history with MSR thresholds, regime diagnostics
What's NOT in v0.1
Being explicit about scope. We removed features that failed our internal validation rather than shipping them broken:
- Monthly TNAC nowcast — validated at 20%+ median error against Commission-published values, well outside a defensible confidence band. Planned for v0.2 once we wire in real EUTL per-year data.
- Compliance-buy timing signal — tested empirically and does not persistently outperform naive strategies.
- Sector transmission model — regressions of Rotterdam-cluster equities on EUA did not clear statistical significance.
Choosing to ship less rather than ship broken is the design principle here.
Install
pip install carbon-ets # core (no yfinance)
pip install carbon-ets[yfinance] # with Yahoo Finance for equity/gas proxies
pip install carbon-ets[all] # everything including Jupyter
Or from source:
git clone https://github.com/causalsystems-co/carbon-ets
cd carbon-ets
pip install -e .[all]
Quickstart
from carbon_ets.data import build_full_panel
from carbon_ets.features import engineer
from carbon_ets.models import backtest_v1
from carbon_ets.tnac import nowcast_monthly
panel = build_full_panel(start="2012-01-01")
feats = engineer(panel)
stats, equity = backtest_v1(feats)
print(f"Sharpe = {stats['sharpe']:.2f}, CAGR = {stats['cagr']:+.1%}")
# Current TNAC nowcast — updated as new data arrives
tnac = nowcast_monthly()
print(f"Estimated TNAC ({tnac.as_of.date()}): {tnac.tnac_estimate:,.0f} allowances")
See examples/quickstart.py for the full end-to-end run.
What's honest about this
This toolkit does not claim to be a trading system. The backtest returns you see are:
- In-sample and window-dependent — Sharpe 0.8-1.0 on 2015-2024 EUA settlement data, but not tested out-of-sample
- Sensitive to feature specification — different regime interpretations arise from different feature sets
- Not corrected for realistic transaction costs, slippage, or execution frictions
The toolkit is designed for research and policy analysis, not live trading. If you want to trade EUA, you need paid data feeds, a proper execution stack, and independent validation.
The core empirical finding — that the demand-side chain explains ~5% of monthly variance on average and up to 63% in specific windows — is reproducible from the pipeline and is the piece worth citing.
Architecture
carbon_ets/
├── data.py — EEX auction fetcher, Eurostat SDMX, panel builder
├── features.py — engineered features (returns, z-scores, momentum, vol)
├── models.py — backtest_v1, Markov-switching MS-2 wrapper
├── tnac.py — hardcoded TNAC series + monthly nowcast + validation
├── plots.py — equity curves, TNAC diagnostics
└── __init__.py
examples/
└── quickstart.py — end-to-end reproducibility
pyproject.toml — package config, dependencies
Contributing
Issues and pull requests welcome, especially:
- Data gap fills — missing pre-2013 auction data, alternative EUA proxies (KEUA, CFI), or additional emissions data sources
- Feature ideas — CBAM import volumes, ETS2 preparation data, sector-specific compliance proxies
- Method extensions — regime-switching alternatives, structural VAR, natural experiments around MSR events
- Cross-market ports — California CCA (CARB), UK ETS, RGGI applications of the same architecture
Citing
If you use this in published work, please cite:
Causal Systems (2026). Factories to carbon: a demand-side model of EU allowance prices. CS/RES/05. https://causalsystems.co/research/factories-to-carbon
License
MIT. See LICENSE.
Contact
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file carbon_ets-0.1.0.tar.gz.
File metadata
- Download URL: carbon_ets-0.1.0.tar.gz
- Upload date:
- Size: 20.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2820607e5ba6e28bc1b7bd24adb26ee1bf998e5f9d0c7e26716cf40afb3fb9a3
|
|
| MD5 |
7f0d7b1b4f45acb353370f1a8811d254
|
|
| BLAKE2b-256 |
f008e5d3d02fc10b222ac13f97596766b5fb19a852cbdd15f6cf5f7ca5dd3316
|
File details
Details for the file carbon_ets-0.1.0-py3-none-any.whl.
File metadata
- Download URL: carbon_ets-0.1.0-py3-none-any.whl
- Upload date:
- Size: 17.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.9
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aeb66b13d8c264026b22053908c269fba24868e1c11a46aa68873f08e108f472
|
|
| MD5 |
94915d28653a8aaec82d101f478bcfbd
|
|
| BLAKE2b-256 |
1a70a75250049e7a536eb4dfa813196478b02bf87b2651bb2485494715a4fcf7
|