# ADR-005: Multi-asset historical data (F3)

**Status:** Accepted  
**Date:** 2026-10-02

## Context

Phase E proved SQLite + OANDA for EUR_USD M15. F3 requires multiple asset classes and longer history without rewriting chart, indicators, or warehouse semantics.

## Decision

1. **Keep SQLite** — single-file, $0, WAL mode, indexed range queries; sufficient for millions of rows on local dev/self-host.
2. **Canonical instrument registry** — `lib/market/instruments.ts` maps canonical symbols → asset class → historical source → provider symbol.
3. **Provider adapters** — `fetchHistoricalFromSource()` dispatches to OANDA (FX, XAU, NAS100) or Binance public spot klines (BTCUSDT, ETHUSDT). No adapter logic in chart/indicators.
4. **Non-destructive schema migration** — `user_version` 2 adds `asset_class`, `provider_symbol` on `dataset_meta` and composite index `(source, symbol, timeframe, timestamp_ms)`.
5. **Bounded queries** — warehouse API max 5000 bars per request; optional `startMs` / `endMs` / `afterMs`.
6. **Batch import** — provider pages inserted incrementally (no full-year RAM buffer).

## Providers (F3)

| Asset | Source | Auth | Notes |
|-------|--------|------|-------|
| FX | OANDA practice | `.env` token | unchanged Phase C/D |
| XAU_USD | OANDA practice | `.env` token | instrument `XAU_USD` |
| NAS100 | OANDA practice | `.env` token | provider `US100_USD`; account may restrict |
| BTCUSDT, ETHUSDT | Binance spot REST | **None** for public klines | quote volume; geo/IP limits possible |

## Rejected (for now)

- PostgreSQL / Parquet migration — no demonstrated SQLite limit hit in F3.
- Single provider for all asset classes — not legally/technically available at $0.
- HTF `request.security` — still out of scope (indicator/chart TF only).

## Consequences

- Future backtest/alerts consume the same canonical candles + query layer.
- Adding a provider = new adapter + instrument rows, not chart changes.
