# ML4T Data Infrastructure Central data management for *Machine Learning for Trading, 3rd Edition*. Each dataset has its own directory with a download script, loader, config, and exploration notebook. All loaders return Polars DataFrames with a consistent API. --- ## Quick Start ```bash # 1. Set data path in repository root .env file ML4T_DATA_PATH=/path/to/your/data # 2. Download free datasets (no API keys needed) uv run python data/download_all.py --free-only # 3. Use in notebooks from data import load_etfs df = load_etfs() ``` --- ## Dataset Catalog Organized by asset class and data type. "Type" column maps each dataset to its place in the Ch2/Ch4 taxonomy: market (OHLCV / microstructure / options), fundamentals (accounting + regulatory filings), positioning (positions / insider activity), onchain (crypto-native fundamentals), or cross-asset (factors, macro, prediction markets, news, text). | Dataset | Asset Class | Type | Frequency | Symbols | Coverage | Source | Access | | ------------------------ | ------------ | ------------- | ------------ | ------- | --------- | ---------------- | ------ | | ETF Universe | Equity | Market | Daily | 100 | 2006-2025 | Yahoo Finance | No | | US Equities | Equity | Market | Daily | 3,199 | 1962-2018 | NASDAQ DL | Free | | S&P 500 Bars | Equity | Market | Daily | ~638 | 2017-2021 | AlgoSeek | Soon | | S&P 500 Options | Equity | Market | Daily | ~500 | 2017-2021 | AlgoSeek | Soon | | NASDAQ-100 Bars | Equity | Market | Minute | ~100 | 2020-2021 | AlgoSeek | Soon | | TAQ Tick | Equity | Market | Tick | 1 | Mar 2020 | AlgoSeek | Soon | | MBO Tick | Equity | Market | Tick | 1 | Nov 2024 | Databento | Manual | | NASDAQ ITCH | Equity | Market | Tick | all | varies | NASDAQ FTP | No | | IEX DEEP/TOPS | Equity | Market | Tick | all | varies | IEX public | No | | SEC XBRL Fundamentals | Equity | Fundamentals | Quarterly | 20 | 2022-2024 | SEC EDGAR | No | | SEC 10-K (SP100) | Equity | Fundamentals | Annual | ~100 | 2020-2025 | SEC EDGAR | No | | SEC 10-Q MD&A (SP500) | Equity | Fundamentals | Quarterly | ~600 | 2017-2021 | SEC EDGAR | No | | SEC 8-K (SP100) | Equity | Fundamentals | Event | ~100 | 2024-2025 | SEC EDGAR | No | | 13F Institutional | Equity | Positioning | Quarterly | 10 inst | rolling | SEC EDGAR | No | | Form 4 Insider | Equity | Positioning | Event | varies | varies | SEC EDGAR | No | | Firm Characteristics | Equity | Packaged | Monthly | anon | 1967-2016 | GitHub | No | | CME Futures | Futures | Market | Daily/Hourly | 30 | 2011-2025 | Databento | Paid | | CFTC Commitment of Traders | Futures | Positioning | Weekly | 25+ | 2020-2025 | CFTC public | No | | Crypto Perps | Crypto | Market | 1h | 19 | 2020-2025 | Binance Public | No | | Crypto Premium | Crypto | Market | 8h | 19 | 2020-2025 | Binance Public | No | | DefiLlama TVL | Crypto | Onchain | Daily | chains | varies | DefiLlama | No | | CoinGecko OHLCV | Crypto | Onchain | Daily | varies | 365 days | CoinGecko | No | | FX Pairs | Currency | Market | 4h/Daily | 20 | 2011-2025 | OANDA | Free | | FF Factors | Cross-asset | Factors | Monthly | 5 | 1926-now | Ken French | No | | AQR Factors | Cross-asset | Factors | Monthly | 8 | varies | AQR | No | | FRED Macro | Cross-asset | Macro | Various | 40 | 2000-2025 | FRED | Free | | Kalshi events | Cross-asset | Prediction | Daily | varies | 2021-2025 | Kalshi public | No | | Polymarket events | Cross-asset | Prediction | Daily | varies | 2020-2025 | Polymarket public| No | | FNSPID news | Cross-asset | News | Daily | 4,775 | 1999-2023 | HuggingFace | No | | Bloomberg news archive | Cross-asset | News | Daily | mixed | 2006-2013 | HuggingFace | No | | Financial Phrasebank | Cross-asset | Text | Static | — | n/a | HuggingFace | No | **Access legend.** `No` — included with the repo or fetched by an unauthenticated script. `Free` — script-download, free API key required. `Paid` — script-download, billed API (see per-dataset estimates). `Manual` — reader downloads from a hosted URL or provider portal and places the files under `$ML4T_DATA_PATH` (no script); the DataBento MBO one-off has step-by-step instructions below. `Soon` — the reduced reader-facing AlgoSeek datasets are being prepared for hosting; the download URL and instructions will be published before launch. --- ## Download Commands > **Times below are rough, indicative estimates only.** Actual duration > depends on your bandwidth, the providers' current rate limits, and disk > speed — treat them as ballpark, not guarantees. ### Free Datasets (No API Keys) ```bash # All free datasets at once (includes the ~1.5 GB firm-characteristics # dataset; add --skip-firm-characteristics to leave it out) uv run python data/download_all.py --free-only # Individual datasets (from repo root) uv run python data/etfs/market/download.py # ~30s uv run python data/crypto/market/download.py # ~10-15 min (see note) uv run python data/factors/ff_download.py # ~5s uv run python data/factors/aqr_download.py # ~5s uv run python data/equities/firm_characteristics/download.py # ~1.5 GB, largest free dataset; downloads + converts (minutes, bandwidth-dependent) uv run python data/futures/positioning/cot_download.py # ~2-3 min (CFTC CoT) ``` **Note on crypto download time**: The Binance public API returns max 1,500 rows per request with ~1s server response time. Downloading 5 years of hourly data for 19 symbols requires ~700 API calls. Downloads run in parallel (5 concurrent), but the total still takes 10-15 minutes. This is a Binance server-side rate limit, not a bug. ### Free API Key Required ```bash # FRED macro indicators uv run python data/macro/download.py # US Equities (NASDAQ Data Link — frozen, ends 2018) uv run python data/equities/market/us_equities/download.py # FX pairs (OANDA) uv run python data/fx/market/download.py # 4-hourly (default) uv run python data/fx/market/download.py --daily # Daily ``` ### Paid API Key (Databento) ```bash # CME Futures — ALWAYS estimate cost first! uv run python data/futures/market/download.py --estimate-only uv run python data/futures/market/download.py ``` ### Manual Download (Databento Download Center) The Chapter 3 MBO slice (NVDA, 10 trading days in November 2024) is best obtained as a one-off download from the Databento Download Center — total cost is under $10 and the files stay available for 30 days. See `data/equities/market/microstructure/MBO_DOWNLOAD.md` for step-by-step instructions. An API-based alternative (`mbo_download.py`) is available for users who already have a `DATABENTO_API_KEY`. ### Update Existing Data Extend datasets beyond the default end date: ```bash uv run python data/download_all.py --update ``` --- ## Using Loaders All loaders are importable from `data` and return Polars DataFrames: ```python from data import ( load_etfs, load_crypto_perps, load_crypto_premium, load_cme_futures, load_cot, load_fx_pairs, load_macro, load_us_equities, load_ff_factors, load_aqr_factors, load_firm_characteristics, load_nasdaq100_bars, load_sp500_daily_bars, load_sp500_options, load_sp500_options_eda, load_sp500_options_straddles_raw, load_sp500_options_surface, load_sp500_options_straddles, load_nasdaq100_taq, load_mbo_data, load_nasdaq_itch, load_iex_hist, ) # All loaders support filtering df = load_etfs(symbols=["SPY", "QQQ"], start_date="2020-01-01") # Futures use 'products' instead of 'symbols' futures = load_cme_futures(products=["ES", "NQ"], start_date="2020-01-01") # Test mode: limit to N random symbols (seed-deterministic) df = load_etfs(max_symbols=15) ``` When data is missing, loaders raise `DataNotFoundError` with download instructions. --- ## API Keys ### Free API Keys | Provider | Variable | Sign Up | | ---------------- | ---------------- | ------------------------------------------------- | | FRED | `FRED_API_KEY` | https://fred.stlouisfed.org/docs/api/api_key.html | | NASDAQ Data Link | `QUANDL_API_KEY` | https://data.nasdaq.com/sign-up | | OANDA | `OANDA_API_KEY` | https://www.oanda.com/ | ### Paid API Keys | Provider | Variable | Cost | | --------- | ------------------- | ---------------- | | Databento | `DATABENTO_API_KEY` | $125 free credit | ### Configuration Create `.env` in repository root: ```bash ML4T_DATA_PATH=/path/to/your/data # Free API keys FRED_API_KEY=your-fred-key QUANDL_API_KEY=your-nasdaq-key OANDA_API_KEY=your-oanda-key # Paid DATABENTO_API_KEY=db-your-key ``` --- ## Directory Structure Every dataset directory is self-contained: a download script, a loader (or re-export from a parent loader), a README with the full instructions that `DataNotFoundError` points readers to, and optionally a config and exploration notebook. Data is organized by **asset class × data type**, matching the Ch2 / Ch4 taxonomy. Each asset class has `market/` for OHLCV-style data, and optionally `fundamentals/`, `positioning/`, or other type-specific subdirectories. Cross-asset datasets (`factors/`, `macro/`, `prediction_markets/`, `alternative/`) sit at the top level. ``` data/ ├── __init__.py # Single import point for all loaders ├── exceptions.py # DataNotFoundError, DownloadError, MissingDependencyError ├── download_all.py # Download orchestrator ├── README.md # (this file) │ ├── equities/ # US equities │ ├── market/ # us_equities, sp500 (daily + options), nasdaq100, microstructure │ ├── fundamentals/ # 10-K / 10-Q / 8-K filings, XBRL financials │ ├── positioning/ # 13F institutional holdings, Form 4 insider │ ├── firm_characteristics/ # Chen-Pelger-Zhu panel (standalone packaged dataset) │ └── loader.py # All equities loaders in one module │ ├── futures/ # CME futures │ ├── market/ # Databento continuous + individual contracts │ ├── positioning/ # CFTC Commitment of Traders (CoT) │ └── loader.py │ ├── crypto/ # Crypto │ ├── market/ # Binance perps OHLCV + premium index │ ├── onchain/ # DefiLlama TVL + CoinGecko OHLCV │ └── loader.py │ ├── fx/market/ # FX pairs (OANDA) ├── etfs/market/ # ETF universe (Yahoo) │ ├── factors/ # Fama-French, AQR (cross-asset, academic) ├── macro/ # FRED macro indicators (cross-asset) ├── prediction_markets/ # Kalshi + Polymarket events │ └── alternative/ # Cross-asset third-party alt data ├── news/ # Bloomberg, FNSPID └── text/ # Financial Phrasebook sentiment benchmark ``` Every subdirectory owns its data's lifecycle — a reader can open any leaf README and find the download command and file layout without consulting the top-level doc. ### Equities Loaders (all in `equities/loader.py`) **Market (OHLCV, microstructure, options):** | Loader | Dataset | Source | | ------ | ------- | ------ | | `load_sp500_index()` | S&P 500 index OHLCV | Bundled | | `load_us_equities()` | 3,199 US stocks (1962-2018) | NASDAQ DL | | `load_sp500_daily_bars()` | S&P 500 daily OHLCV | AlgoSeek | | `load_sp500_options()` | Raw options chains (legacy) | AlgoSeek | | `load_sp500_options_eda()` | Options EDA slice (8 symbols, 2019-2020) | AlgoSeek (slim) | | `load_sp500_options_straddles_raw()` | ATM-band raw chains, lifecycle-preserving (2017-2021) | AlgoSeek (slim) | | `load_sp500_options_surface()` | Daily IV surface summary | Materialized | | `load_sp500_options_straddles()` | Daily ATM straddles | Materialized | | `load_nasdaq100_bars()` | NASDAQ-100 bars (minute default; resampling, quotes, full microstructure) | AlgoSeek | | `load_nasdaq100_taq()` | TAQ tick data (AAPL, 2020-03-13 / 2020-03-16) | AlgoSeek (slim) | | `load_mbo_data()` | MBO order book data | Databento | | `load_nasdaq_itch()` | NASDAQ ITCH messages | NASDAQ FTP | | `load_iex_hist()` | IEX DEEP/TOPS data | IEX (free) | **Fundamentals (SEC filings + XBRL):** | Loader | Dataset | Source | | ------ | ------- | ------ | | `load_sp500_10q_mda()` | S&P 500 10-Q MD&A text (2017-2021) | SEC EDGAR | | `load_sec_filings(form_type)` | 10-K / 10-Q / 8-K aggregate text | SEC EDGAR | | `resolve_sec_filings_dir()` | Per-ticker filings directory (Ch22 RAG) | SEC EDGAR | | `load_sec_xbrl_fundamentals()` | XBRL financial facts (CIK × quarter × concept) | SEC XBRL Frames | **Positioning (13F):** | Loader | Dataset | Source | | ------ | ------- | ------ | | `load_institutional_holdings_13f()` | 13F holdings (per-cik, 10 curated managers) | SEC EDGAR | | `load_13f_bulk_holdings(quarter)` | 13F full universe (~3M rows per quarter) | SEC bulk | | `load_13f_stock_features()` | Stock-level features (breadth, concentration) | Derived | | `load_13f_edges()` | Institution → stock edge list (graph) | Derived | **Firm characteristics (packaged dataset):** | Loader | Dataset | Source | | ------ | ------- | ------ | | `load_firm_characteristics()` | Chen-Pelger-Zhu panel (~180 features, returns + accounting) | GitHub | --- ## Storage Requirements | Tier | Datasets | Size | | ------------- | ------------------------------------- | ------- | | Minimum | ETFs, Crypto, Factors | ~70 MB | | Standard | + Macro, FX | ~75 MB | | With Equities | + US Equities | ~740 MB | | With Futures | + CME Futures | ~825 MB | | Full | + AlgoSeek slim package, ITCH, MBO | ~7 GB | --- ## Canonical Schema All loaders return data with consistent column names: - **Entity column**: `symbol` (exception: CME futures use `product`) - **Time column**: `timestamp` (for all frequencies — daily, hourly, minute, tick) Notebooks should always use these canonical names. If older data files use legacy names like `asset`, `date`, `ticker`, or `pair`, the loaders normalize them automatically.