Quant BuffetRelax, Not Over Thinking

Quant Buffet API

Lab contract

Required symbols, function signatures, and the make_on_day → on_day pattern.

The sandbox loader (backtest/sandbox_runner.py) expects a fixed contract. Strategies that omit or rename these pieces fail with ContractError before any prices load.

ASSETS (required)

Define at module scope (not inside a function):

ASSETS = ["SPY", "QQQ", "TLT", "GLD", "BIL"]
  • Each ticker must be in the Quant Buffet whitelist (see Universes page).
  • Maximum 15 symbols per strategy.
  • Crypto proxies BTC-USD and ETH-USD are allowed via yfinance.
  • Order does not matter; missing history is forward-filled per column.

make_on_day(prices)

Signature and return value:

def make_on_day(prices: pd.DataFrame):
    # prices: rows = trading dates, columns = ASSETS tickers (float close)
    ...
    return on_day, ready
ReturnTypeDescription
on_dayCallable[[PortfolioEngine, pd.Timestamp], None]Invoked once per date in the backtest window.
readypd.Timestamp | NoneFirst date when signals exist. Backtest starts here via engine.run(..., start=ready).

on_day(engine, dt)

  • Receive the live `PortfolioEngine` instance and the current `pd.Timestamp`.
  • Compute target portfolio weights and pass them to `engine.set_target_weights(dt, weights)`.
  • Weights are long-only; sum must be ≤ 1.0 (remainder stays in cash).
  • Use a state dict closed over by on_day to throttle rebalance frequency (e.g. monthly).
  • Guard early dates with if indicator.loc[dt].isna().all(): return.

Recommended imports

from __future__ import annotations

import numpy as np
import pandas as pd

from backtest.data import load_daily_prices
from backtest.engine import EngineConfig, PortfolioEngine
from backtest.metrics import compute_metrics

Anti-patterns

  • Putting ASSETS inside make_on_day — the loader reads module-level ASSETS only.
  • Returning weights from make_on_day instead of an on_day callback.
  • Calling set_target_weights every day with identical weights — the engine skips no-ops, but churny float noise still slows runs.
  • Using tickers outside the whitelist (e.g. single stocks) — blocked at load time.
  • Importing os, sys, subprocess, or third-party packages — blocked by AST validation.