/api-data-fetcher¶
Builds reproducible Python acquisition pipelines for economic APIs (FRED, World Bank, BLS, OECD SDMX, IMF, Eurostat, Yahoo Finance) with DIME conventions ported to Python: an immutable data/raw/ layer written with vintage suffixes, a run_all.py master orchestrator, dynamic absolute paths via pathlib, API keys treated as PII and read only from env vars, content-addressed deterministic caching, and a source codebook recording series ID, units, frequency, transformation, vintage, and access date.
data-handlingCC0-1.0 per the repo LICENSE file and README ("CC0 1.0 — public domain"); GitHub's API reports the licence as NOASSERTION / "Other" — record bothdata-acquisitionAPI Data Fetcher¶
Generate rigorous, reproducible Python pipelines for fetching economic data from public APIs. Apply DIME Analytics' reproducibility principles and data-cleaning discipline to Python: an immutable raw layer, a master orchestration script, dynamic absolute paths, secrets in env vars only, codebook-style source documentation, and asserted output schemas.
Operating Principles¶
- Raw is immutable, like in DIME. Every API response is written to
data/raw/with a vintage suffix (_v2026-05-05) and never edited. Cleaning happens indata/intermediate/; analysis-ready outputs indata/processed/. This mirrors DIME's DataWork folder. - Secrets are PII. API keys are treated like personally identifiable information (DIME PII page): never hardcode, never commit, never log. Read from environment variables or
.envfiles that are.gitignored. - Master script orchestrates. A
pipelines/run_all.pyfile is the Python equivalent of DIME's master do-file: installs packages, defines paths viapathlib, sets seeds, runs each fetcher in order, and is the single command that reproduces the dataset. - Document provenance. Every fetched series carries a source codebook entry: source name, series ID, units, frequency, transformation, vintage, access date, license. This is the DIME data documentation principle applied to API data.
- Cache deterministically. Cache files are content-addressed by request parameters; identical calls return identical bytes; cache invalidation is explicit, not silent.
requests-cacheor a hand-rolled JSON cache work fine. - Validate the schema. After every fetch, assert: expected columns, dtypes, frequency, date range, no extra series IDs returned, no silent NaN explosions. Use
panderaor hand-rolled assertions.
Decision Policy¶
This skill follows the repo-wide Agent Policy. For cross-cutting data discipline (unit of analysis, ID variables, merging, master dataset, PII), this skill defers to working-with-data.
ASK before proceeding (blocking):
- Indicators (which exact series IDs / indicator codes), geography, frequency, and date range.
- Data vintage policy: real-time first releases vs current revisions (matters for forecasting / policy work).
- Update cadence: one-shot vs scheduled refresh (changes how vintage tagging and caching are set up).
- License attribution requirements (especially for redistribution).
DEFAULT + flag (use this default; tell the user how to override):
- One immutable parquet per series in
data/raw/<source>/<series>_<vintage>.parquet. - Long-format country/entity-date-indicator file in
data/processed/as the canonical analysis input. requests-cacheSQLite cache or content-addressed JSON cache indata/cache/; explicit invalidation only.- Hand-rolled
assertschema validation; upgrade topanderawhen the schema gets non-trivial. - Source codebook CSV at
docs/source_codebook.csv, one row per series.
DOCUMENT and proceed (write into the decisions log + docs/source_codebook.csv):
- Vintage and access timestamp for every fetched series.
- Source-side units, transformations applied locally, and the resulting unit.
- Any silent re-mapping (e.g. World Bank country code aliases).
PROCEED items: API keys via env vars only (.env + .gitignore), polite throttling (≥ 0.2s between calls), exponential backoff on 429/5xx, dynamic absolute paths via pathlib, mkdir(parents=True, exist_ok=True) for output folders.
Pre-flight Checklist¶
Before writing code, confirm — and write the answers in the script docstring:
- Indicators. Which series IDs (FRED) / indicators (World Bank) / topic codes (OECD)?
- Geography. Single country, custom country list, or all-available?
- Frequency. Annual, quarterly, monthly, daily? Are mixed frequencies acceptable?
- Date range. Fixed or rolling window?
- Vintage. Real-time data (
fred.get_series_first_release) or current revisions? - Update cadence. One-shot, daily, monthly?
- Output format. Long-format country-year-indicator parquet, or wide-format CSVs per indicator?
- License and citation. Is there an attribution requirement?
Project Layout (DIME-style, in Python)¶
ProjectABC/
├── pyproject.toml # pinned deps via uv / pip-tools
├── .env # API keys; .gitignore'd
├── .gitignore
├── data/
│ ├── raw/ # IMMUTABLE; vintage-suffixed files
│ │ ├── fred/
│ │ │ └── GDP_2026-05-05.csv
│ │ └── worldbank/
│ ├── intermediate/ # cleaned per-source files
│ ├── processed/ # analysis-ready, multi-source
│ └── cache/ # request cache (content-addressed)
├── docs/
│ └── source_codebook.csv # one row per fetched series
├── pipelines/
│ ├── run_all.py # master orchestration script
│ ├── fetch_fred.py
│ ├── fetch_worldbank.py
│ ├── fetch_bls.py
│ ├── fetch_oecd.py
│ ├── fetch_imf.py
│ └── build_panel.py # combine sources
└── README.md
Source Selection Decision Tree¶
US macro time series (GDP, CPI, unemployment, FFR, yields, M2):
└── FRED via `fredapi`. Set FRED_API_KEY.
For real-time vintages: fred.get_series_first_release(...)
or use ALFRED via the same package.
Cross-country development (GDP per capita, poverty, education, health):
└── World Bank Indicators via `wbdata` (no key needed) or `pandas-datareader`.
US labor (CES, CPS, JOLTS, OES):
└── BLS Public Data API via `bls` package. Register for a key for >25 series/day.
OECD panels (Main Economic Indicators, OECD.Stat):
└── `pandasdmx` against the OECD SDMX endpoint. No key.
IMF:
└── IFS, WEO, BOP via `imf-reader` (formerly `imfpy`) or direct SDMX with pandasdmx.
Eurostat:
└── `eurostat` package or `pandasdmx`.
Markets / financial:
└── `yfinance` for equities; for fixed-income use FRED.
For commercial-grade data, route to Bloomberg / Refinitiv (paid, not in scope).
Geospatial / nightlights / weather:
└── See climate / GIS skills; this skill is for tabular API data.
Output Skeleton (run_all.py)¶
"""
Project : ProjectABC
Pipeline : Fetch, validate, and combine FRED + World Bank data.
Author : First Last
Created : 2026-05-05
Inputs : public APIs (FRED, World Bank)
Outputs : data/processed/macro_panel.parquet
docs/source_codebook.csv
"""
from __future__ import annotations
import os
from datetime import date
from pathlib import Path
from pipelines.fetch_fred import fetch_fred
from pipelines.fetch_worldbank import fetch_worldbank
from pipelines.build_panel import build_macro_panel
## 1. Paths (DIME-style: dynamic absolute paths)
PROJECT = Path(__file__).resolve().parents[1]
DATA_RAW = PROJECT / "data" / "raw"
DATA_INT = PROJECT / "data" / "intermediate"
DATA_FINAL = PROJECT / "data" / "processed"
DOCS = PROJECT / "docs"
for p in (DATA_RAW, DATA_INT, DATA_FINAL, DOCS):
p.mkdir(parents = True, exist_ok = True)
VINTAGE = date.today().isoformat()
## 2. Secrets (never hardcoded; read from env)
assert os.getenv("FRED_API_KEY"), "Set FRED_API_KEY in .env"
## 3. Run each fetcher (each writes to RAW with vintage suffix)
fetch_fred(out_dir = DATA_RAW / "fred", vintage = VINTAGE)
fetch_worldbank(out_dir = DATA_RAW / "worldbank", vintage = VINTAGE)
## 4. Build the analysis-ready panel
build_macro_panel(
raw_dir = DATA_RAW,
int_dir = DATA_INT,
final_dir = DATA_FINAL,
docs_dir = DOCS,
vintage = VINTAGE,
)
print(f"Pipeline complete. Vintage = {VINTAGE}")
Common Pitfalls¶
- Hardcoding API keys in scripts or notebooks. Use
os.environ+.env. - Overwriting raw files when re-running. Always include a vintage suffix.
- Silent frequency mixing (annual GDP joined to monthly CPI without resampling).
- Trusting series titles instead of series IDs. FRED renames titles; IDs are stable.
- Ignoring data revisions. For policy-relevant analysis use real-time vintages, not the latest revisions.
- Caching by URL only and missing changes in headers/parameters. Hash the full request.
- Pulling enormous datasets into memory. Stream to parquet and load lazily with
pyarrow. - Not recording units. World Bank / OECD often switch units between releases.
- Treating missing values as zero. World Bank coverage is uneven; drop or impute deliberately.
Additional Resources¶
reference.md— extended patterns: source codebook schema, caching, validation, real-time vintages, rate limiting.examples/— runnable scripts:examples/economic_data_fetcher.py— minimal FRED + World Bank fetch (legacy reference)examples/run_all.py— master orchestration scriptexamples/fetch_fred.py— vintage-aware FRED fetcherexamples/fetch_worldbank.py— World Bank country-year panelexamples/fetch_oecd_sdmx.py— OECD via SDMX/pandasdmxexamples/fetch_bls.py— BLS Public Data APIexamples/build_panel.py— combine sources, validate schema, write parquetexamples/source_codebook.csv— example provenance log
Requirements¶
- Python >= 3.10.
- Core:
pandas,pyarrow,requests,python-dotenv. - Source clients:
fredapi,wbdata,pandasdmx,bls,eurostat,yfinance. - Validation:
pandera(optional but recommended).
pip install pandas pyarrow requests python-dotenv pandera \
fredapi wbdata pandasdmx bls eurostat yfinance
.env template:
.gitignore:
References¶
DIME Conceptual Inputs¶
- DIME Analytics, Reproducible Research
- DIME Analytics, DataWork Folder
- DIME Analytics, Master Do-files
- DIME Analytics, Data Cleaning
- DIME Analytics, Personally Identifiable Information (PII)
- DIME Analytics, Data Documentation
API Documentation¶
- FRED API
- World Bank Indicators API
- BLS Public Data API
- OECD SDMX
- IMF Data Services
- Eurostat REST API
Style¶
- QuantEcon, Python Programming for Economics and Finance.
- Wickham (2014), Tidy Data.