Тиковые данные книги заявок: источники MBO и NASDAQ ITCH
Сводка
В этом руководстве представлены два источника тиковых данных книги заявок по акциям US для исследования микроструктуры: события Databento market-by-order и сообщения NASDAQ TotalView-ITCH. Описаны форматы, особенности охвата, примерные объёмы данных и компромиссы. MBO предоставляет обработанные события заявок, такие как добавления, изменения, отмены и исполнения, тогда как ITCH — бесплатный сырой бинарный поток, который нужно разобрать и нормализовать.
Процесс включает оценку стоимости загрузки MBO до получения данных, загрузку выбранных дат, чтение доступных данных и изучение типов событий или сообщений. Рекомендуется ограничивать платные запросы MBO нужными символами и периодами; ITCH позволяет проводить более широкий анализ, но требует значительного места для хранения и работы по разбору данных. Это руководство по доступу к данным и их изучению, а не торговая стратегия или эмпирическое исследование; результаты анализа книги заявок не представлены.
Ключевые идеи
- MBO и ITCH дают данные о событиях на уровне заявок для реконструкции книги заявок и исследования микроструктуры.
- MBO обрабатываются и оплачиваются по символу и дню, тогда как ITCH — бесплатные сырые данные, требующие разбора.
- Оцени стоимость до запроса данных MBO.
- Файлам ITCH требуются значительное место для хранения и нормализация временных меток перед анализом.
- Руководство описывает процессы работы с данными, но не оценивает торговую стратегию.
Теги
Полный текст
# Tick Data Dataset
# Tick Data Dataset
Market-by-order tick data for order book analysis and microstructure research.
| Property | Value |
|----------|-------|
| **Providers** | Databento (MBO), NASDAQ FTP (ITCH) |
| **Asset Class** | US Equities |
| **Frequency** | Tick (microsecond) |
| **Coverage** | Point-in-time |
| **Size** | MBO: ~500 MB, ITCH: ~5 GB/day |
| **API Key** | MBO: `DATABENTO_API_KEY` (**PAID**), ITCH: None |
| **Loaders** | `load_mbo_data()`, `load_nasdaq_itch()` |
**NOTE**: MBO data is expensive (~$0.50/symbol/day). ITCH is free but requires parsing.
```python
"""Tick Data - download, explore, and update workflow."""
import os
from datetime import datetime, timedelta
from pathlib import Path
import polars as pl
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
```
## 1. Configuration
Two tick data sources are available:
| Source | Type | Cost | Parsing |
|--------|------|------|---------|
| Databento MBO | Order book events | ~$0.50/symbol/day | Pre-processed |
| NASDAQ ITCH | Raw exchange feed | Free | Requires parsing |
**MBO (Market-By-Order)**: Clean order book events - add, modify, cancel, trade.
**ITCH**: Native NASDAQ TotalView-ITCH 5.0 messages - requires binary parsing.
```python
print("=== Tick Data Configuration ===")
print()
print("Databento MBO:")
print(" Provider: Databento API (XNAS.ITCH dataset)")
print(" Cost: ~$0.45-0.50 per symbol per day")
print(" Default symbols: NVDA, SPY, TSLA")
print(" Format: Pre-processed Parquet")
print()
print("NASDAQ ITCH:")
print(" Provider: NASDAQ FTP (free)")
print(" Cost: Free (requires parsing)")
print(" File size: 4-6 GB per day (compressed)")
print(" Format: Binary (requires parsing)")
```
## 2. API Key Setup
### Databento MBO (Paid)
Databento requires a paid API key. New accounts receive $125 free credit.
1. Sign up at [Databento](https://databento.com/signup)
2. Navigate to **API Keys** in your dashboard
3. Add to your `.env` file:
```bash
DATABENTO_API_KEY=db-your-api-key-here
```
### NASDAQ ITCH (Free)
No API key required. Data is freely available from NASDAQ's FTP server.
```python
# Verify Databento API key
databento_key = os.getenv("DATABENTO_API_KEY")
if databento_key:
print(f"DATABENTO_API_KEY: {databento_key[:8]}... (configured)")
else:
print("DATABENTO_API_KEY: Not configured")
print(" Get key at: https://databento.com/signup ($125 free credit)")
print()
print("NASDAQ ITCH: No API key required (free FTP access)")
```
## 3. Download Data
**WARNING**: MBO data is expensive. Always estimate cost before downloading!
```python
# Default configuration
DEFAULT_MBO_SYMBOLS = ["NVDA", "SPY", "TSLA"]
DEFAULT_MBO_DAYS = 10
def get_trading_dates(start_date: str, end_date: str) -> list[str]:
"""Generate list of trading dates (weekdays) between start and end."""
start = datetime.strptime(start_date, "%Y-%m-%d")
end = datetime.strptime(end_date, "%Y-%m-%d")
dates = []
current = start
while current <= end:
if current.weekday() < 5: # Skip weekends
dates.append(current.strftime("%Y%m%d"))
current += timedelta(days=1)
return dates
def estimate_mbo_cost(
symbols: list[str] | None = None,
dates: list[str] | None = None,
start_date: str | None = None,
end_date: str | None = None,
) -> dict:
"""Estimate MBO download cost.
Args:
symbols: List of symbols (default: NVDA, SPY, TSLA)
dates: List of dates in YYYYMMDD format
start_date: Start date (YYYY-MM-DD) if not providing dates list
end_date: End date (YYYY-MM-DD) if not providing dates list
Returns:
Cost estimate dictionary
"""
if symbols is None:
symbols = DEFAULT_MBO_SYMBOLS
if dates is None and start_date and end_date:
dates = get_trading_dates(start_date, end_date)
elif dates is None:
# Default: 10 trading days
end = datetime(2024, 11, 15)
start = end - timedelta(days=20)
dates = get_trading_dates(start.strftime("%Y-%m-%d"), end.strftime("%Y-%m-%d"))
dates = dates[-DEFAULT_MBO_DAYS:]
cost_per_symbol_day = 0.50
total_symbol_days = len(symbols) * len(dates)
estimated_cost = total_symbol_days * cost_per_symbol_day
print("=== MBO Cost Estimate ===")
print(f"Symbols: {symbols}")
print(f"Days: {len(dates)} ({dates[0]} to {dates[-1]})")
print(f"Total symbol-days: {total_symbol_days}")
print(f"Cost per symbol-day: ${cost_per_symbol_day:.2f}")
print("")
print(f"ESTIMATED COST: ${estimated_cost:.2f}")
return {
"symbols": symbols,
"num_days": len(dates),
"total_symbol_days": total_symbol_days,
"estimated_cost_usd": estimated_cost,
}
def download_mbo_data(
symbols: list[str] | None = None,
dates: list[str] | None = None,
start_date: str | None = None,
end_date: str | None = None,
dry_run: bool = True, # Default True for safety!
force: bool = False,
):
"""Download MBO tick data from Databento.
Args:
symbols: List of symbols (default: NVDA, SPY, TSLA)
dates: List of dates in YYYYMMDD format
start_date: Start date (YYYY-MM-DD) if not providing dates list
end_date: End date (YYYY-MM-DD) if not providing dates list
dry_run: If True, show cost estimate without downloading (DEFAULT: True)
force: If True, re-download even if data exists
"""
import databento as db
from utils import ML4T_DATA_PATH
if symbols is None:
symbols = DEFAULT_MBO_SYMBOLS
if dates is None and start_date and end_date:
dates = get_trading_dates(start_date, end_date)
elif dates is None:
end = datetime(2024, 11, 15)
start = end - timedelta(days=20)
dates = get_trading_dates(start.strftime("%Y-%m-%d"), end.strftime("%Y-%m-%d"))
dates = dates[-DEFAULT_MBO_DAYS:]
output_dir = ML4T_DATA_PATH / "equities" / "market" / "microstructure" / "market_by_order"
print("=== MBO Data Download ===")
print(f"Symbols: {symbols}")
print(f"Dates: {len(dates)} days ({dates[0]} to {dates[-1]})")
print(f"Output: {output_dir}")
# Always show cost estimate
estimate = estimate_mbo_cost(symbols, dates)
if dry_run:
print("\n[DRY RUN] Would download:")
for symbol in symbols:
print(f" {symbol}: {len(dates)} days")
print("\nSet dry_run=False to actually download.")
print(f"WARNING: This will cost ~${estimate['estimated_cost_usd']:.2f}")
return
# Verify API key
api_key = os.getenv("DATABENTO_API_KEY")
if not api_key:
raise ValueError("DATABENTO_API_KEY not set. See API Key Setup section.")
client = db.Historical(api_key)
print(f"\nDownloading {len(symbols)} symbols x {len(dates)} days...")
for symbol in symbols:
symbol_dir = output_dir / symbol
symbol_dir.mkdir(parents=True, exist_ok=True)
for date in dates:
output_file = symbol_dir / f"{date}.parquet"
if output_file.exists() and not force:
print(f" Skipping {symbol}/{date} (exists)")
continue
print(f" {symbol}/{date}...", end=" ", flush=True)
try:
date_str = f"{date[:4]}-{date[4:6]}-{date[6:8]}"
data = client.timeseries.get_range(
dataset="XNAS.ITCH",
schema="mbo",
symbols=[symbol],
start=f"{date_str}T00:00:00",
end=f"{date_str}T23:59:59",
)
df = data.to_df()
if len(df) > 0:
pl_df = pl.from_pandas(df.reset_index())
pl_df.write_parquet(output_file)
print(f"OK ({len(df):,} events)")
else:
print("No data")
except Exception as e:
print(f"ERROR: {e}")
print("\n=== Complete ===")
print(f"Data saved to: {output_dir}")
def download_nasdaq_itch(date: str = "01302020", dry_run: bool = False):
"""Download NASDAQ ITCH sample data.
Args:
date: Date in MMDDYYYY format (default: 01302020)
dry_run: If True, show what would be downloaded
"""
from ml4t.data.providers.nasdaq_itch import ITCHSampleProvider
from utils import ML4T_DATA_PATH
output_dir = ML4T_DATA_PATH / "equities" / "market" / "microstructure" / "nasdaq_itch" / "raw"
print("=== NASDAQ ITCH Download ===")
print("Source: NASDAQ TotalView-ITCH 5.0")
print("URL: https://emi.nasdaq.com/ITCH/Nasdaq%20ITCH/")
print(f"Date: {date}")
print(f"Output: {output_dir}")
print()
print("WARNING: Files are 4-6 GB each!")
print(" Download may take 30-60 minutes.")
print(" Requires parsing before use (see Chapter 4 notebooks)")
if dry_run:
print("\n[DRY RUN] Would download:")
print(f" {date}.NASDAQ_ITCH50.gz (~5 GB)")
print("\nSet dry_run=False to actually download.")
return
output_dir.mkdir(parents=True, exist_ok=True)
provider = ITCHSampleProvider(download_path=output_dir)
print(f"\nDownloading {date}.NASDAQ_ITCH50.gz...")
output_path = provider.download(date_or_filename=date, output_path=output_dir)
print("\n=== Complete ===")
print(f"Data saved to: {output_path}")
print("\nNext steps:")
print(" 1. Parse the binary data using the Rust parser or Python")
print(" 2. See Chapter 4 notebooks for parsing examples")
```
### Estimate MBO Cost (ALWAYS DO THIS FIRST!)
```python
# Estimate cost for default symbols and dates
estimate_mbo_cost()
```
### Download MBO Data
```python
# Dry run (default) - shows what would be downloaded
download_mbo_data(dry_run=True)
```
```python
# Uncomment to actually download (after reviewing cost!)
# download_mbo_data(dry_run=False)
```
### Download NASDAQ ITCH
```python
# Dry run
download_nasdaq_itch(dry_run=True)
```
```python
# Uncomment to download (4-6 GB, takes 30-60 minutes)
# download_nasdaq_itch(dry_run=False)
```
## 4. Load and Explore
Once downloaded, use the loaders throughout the book:
```python
from data import load_mbo_data, load_nasdaq_itch
```
### MBO Data (Databento)
```python
# Load MBO data (if available)
mbo = load_mbo_data(symbols=["NVDA"], start_date="2024-11-04", end_date="2024-11-04")
print(f"Shape: {mbo.shape}")
print(f"Columns: {mbo.columns}")
print(f"Memory: {mbo.estimated_size('mb'):.1f} MB")
```
```python
# Preview
mbo.head(10)
```
```python
# Event type distribution
if "action" in mbo.columns:
print("Event types:")
mbo.group_by("action").len().sort("len", descending=True)
```
### NASDAQ ITCH
```python
# Load ITCH data (if available and parsed)
itch = load_nasdaq_itch()
print(f"Shape: {itch.shape}")
print(f"Memory: {itch.estimated_size('mb'):.1f} MB")
```
```python
# Message type distribution
if "msg_type" in itch.columns:
print("Message types:")
itch.group_by("msg_type").len().sort("len", descending=True)
```
## 5. Data Profile
```python
from ml4t.data.storage.data_profile import get_profile_path, load_profile
from utils import ML4T_DATA_PATH
microstructure = ML4T_DATA_PATH / "equities" / "market" / "microstructure"
for name, data_path in [
("MBO", microstructure / "market_by_order"),
("ITCH", microstructure / "nasdaq_itch"),
]:
profile_path = get_profile_path(data_path)
profile = load_profile(profile_path)
if profile is None:
print(f"No {name} profile at {profile_path}")
else:
print(f"=== {name} Profile ===")
print(f"Written by {profile.source}")
print(profile.summary())
print(
"\nThe two downloaders in this directory write raw vendor captures and do not go\n"
"through ml4t.data.storage.data_profile, so neither dataset carries a profile today.\n"
"Nothing in this notebook writes one either."
)
```
## 6. Loader Options
Both loaders support filtering by symbols and dates.
### MBO Data
```python
# Load specific symbol and date
nvda = load_mbo_data(symbols=["NVDA"], start_date="2024-11-04", end_date="2024-11-04")
print(f"NVDA Nov 4: {nvda.shape}")
```
```python
# Load multiple symbols
multi = load_mbo_data(symbols=["NVDA", "SPY"], start_date="2024-11-04", end_date="2024-11-04")
print(f"NVDA + SPY: {multi.shape}")
```
### NASDAQ ITCH
```python
# Load all parsed messages
itch_day = load_nasdaq_itch()
print(f"ITCH messages: {itch_day.shape}")
```
```python
# Load specific message types
# trades = load_nasdaq_itch(message_types=["P", "Q"])
```
## 7. Documentation
### Databento MBO
- [Databento Documentation](https://databento.com/docs/)
- [XNAS.ITCH Dataset](https://databento.com/docs/datasets/xnas-itch)
- [MBO Schema](https://databento.com/docs/schemas/mbo)
### MBO Event Types
| Action | Description |
|--------|-------------|
| `A` | Add order to book |
| `M` | Modify existing order |
| `C` | Cancel order |
| `T` | Trade execution |
| `F` | Order fully filled |
### NASDAQ ITCH
- [NASDAQ TotalView-ITCH](https://www.nasdaq.com/docs/TotalView-ITCH-5-0.pdf)
- [NASDAQ FTP](https://emi.nasdaq.com/ITCH/Nasdaq%20ITCH/)
### ITCH Message Types
| Type | Description |
|------|-------------|
| `S` | System event |
| `R` | Stock directory |
| `A` | Add order (no MPID) |
| `F` | Add order (with MPID) |
| `E` | Order executed |
| `C` | Order executed with price |
| `X` | Order cancel |
| `D` | Order delete |
| `U` | Order replace |
| `P` | Trade (non-cross) |
| `Q` | Cross trade |
### Data Quality Notes
- **MBO**: Pre-processed, clean timestamps, consistent schema
- **ITCH**: Raw binary, requires parsing, timestamp normalization needed
- **MBO cost**: ~$0.45-0.50 per symbol per day
- **ITCH size**: 4-6 GB per day (compressed)
## 8. Updating Data
Tick data is typically downloaded **point-in-time** for specific analysis periods.
### MBO Updates
```python
# Download specific dates (ALWAYS estimate first!)
estimate_mbo_cost(symbols=["AAPL"], start_date="2024-12-01", end_date="2024-12-05")
download_mbo_data(symbols=["AAPL"], start_date="2024-12-01", end_date="2024-12-05", dry_run=False)
```
### ITCH Updates
```python
# Download specific date
download_nasdaq_itch(date="01152025", dry_run=False)
```
### Cost Considerations
| Data Type | Cost | Recommendation |
|-----------|------|----------------|
| MBO | ~$0.50/symbol/day | Download only needed periods |
| ITCH | Free | Download as needed (5 GB/day) |
**Best practice**: Use ITCH for broad market analysis, MBO for specific symbols.
## Summary
| Source | Cost | Format | Use Case |
|--------|------|--------|----------|
| Databento MBO | ~$0.50/symbol/day | Pre-processed Parquet | Specific symbol analysis |
| NASDAQ ITCH | Free | Raw binary (5 GB/day) | Broad market analysis |
**Loaders**:
- `load_mbo_data(symbols, start_date, end_date)` - Databento MBO
- `load_nasdaq_itch(date)` - NASDAQ ITCH
**Primary use**: Order book reconstruction, microstructure research, market making analysis.
**Critical**: Always run `estimate_mbo_cost()` before downloading MBO data!Полный текст с указанием источника опубликован на условиях его лицензии. Лицензия: MIT
Это краткое изложение подготовлено исследовательским агентом Stratmill по оригиналу и не является его копией.