Quant Buffet API
Data API
load_daily_prices, load_price_panel, the disk cache, and price panel conventions.
Market data lives in `backtest.data`. The lab uses adjusted daily closes from Yahoo Finance (auto_adjust=True), cached as CSV under backtest/data_cache/ so repeat runs are fast and reproducible.
load_daily_prices
python
prices = load_daily_prices(
["SPY", "TLT", "GLD"], # symbols: list[str]
"2010-01-01", # start: str = "2000-01-01"
None, # end: str | None = None
use_cache=True, # keyword-only: read/write backtest/data_cache/
strict=False, # keyword-only: raise on first failure
)
# -> pd.DataFrame, DatetimeIndex rows, one float column per loaded ticker| Parameter | Type | Default | Description |
|---|---|---|---|
symbols | list[str] | — | Tickers to load, e.g. ["SPY", "TLT"]. |
start | str | "2000-01-01" | Inclusive ISO start date. |
end | str | None | None | Optional end date; None means latest available. |
use_cache | bool (keyword-only) | True | Read and write the CSV cache. |
strict | bool (keyword-only) | False | Raise on the first symbol failure instead of skipping it. |
Return value
- A `pd.DataFrame` indexed by a sorted, timezone-naive `DatetimeIndex`.
- One float column per symbol that loaded successfully — failed symbols are simply absent unless
strict=True. - Each column is forward-filled independently, so a symbol's gaps are patched but its pre-IPO history stays
NaN. - When some symbols fail, the reasons are attached to `prices.attrs["load_errors"]`.
- If no symbol loads, a
RuntimeErrorlists the first few errors.
The disk cache
| Aspect | Behaviour |
|---|---|
| Location | backtest/data_cache/ |
| Filename | {SYMBOL}_{start}_{end or 'latest'}.csv |
| Columns | Date, AdjClose |
| Reuse condition | File exists and is larger than 50 bytes |
| Cache key caveat | A different start produces a different file — and a fresh download |
load_price_panel
python
from backtest.data import load_price_panel
prices, missing = load_price_panel(["SPY", "TLT", "XYZ"], start="2010-01-01")
# prices: pd.DataFrame of everything that loaded
# missing: ["XYZ"] — symbols with no data
load_price_panel de-duplicates the symbol list, always runs non-strict, and hands back the missing symbols explicitly. Use it in scripts where you want to report gaps rather than crash.
Panel conventions to rely on
| Guarantee | Consequence for your code |
|---|---|
| Index is sorted ascending | rolling and shift behave as expected |
| Index is timezone-naive | No tz_localize needed for comparisons |
Columns follow ASSETS order | But may be shorter if a symbol failed |
| Values are adjusted closes | Splits and dividends are already handled |
| All-NaN rows are dropped by the runner | The first panel row has at least one real price |
python
# Defensive opening lines that belong in every strategy
cols = [c for c in ASSETS if c in prices.columns]
if not cols:
raise ValueError("No ASSETS loaded")
first_valid = {s: prices[s].first_valid_index() for s in cols}
# Inspect this when a backtest starts much later than you expected