Quant Buffet API
Engine API
PortfolioEngine, EngineConfig, trades, and BacktestResult.
`backtest.engine` implements a daily, long-only simulator with cash, commission, and slippage. Strategies interact almost exclusively through `set_target_weights`.
EngineConfig
@dataclass
class EngineConfig:
initial_cash: float = 100_000.0
commission_bps: float = 5.0 # basis points on notional per fill
slippage_bps: float = 2.0 # basis points price impact per sideThe lab sandbox uses `initial_cash=100_000`, `commission_bps=5`, `slippage_bps=2` by default.
PortfolioEngine
config = EngineConfig(
initial_cash=100_000.0,
commission_bps=5.0, # 5 bps per fill notional
slippage_bps=2.0, # 2 bps price impact per side
)
engine = PortfolioEngine(prices, config)
def on_day(engine: PortfolioEngine, dt: pd.Timestamp) -> None:
engine.set_target_weights(dt, {"SPY": 0.6, "TLT": 0.4})
result = engine.run(on_day, start=pd.Timestamp("2015-01-01"))
# result.equity, result.holdings, result.trades, result.cashset_target_weights(dt, weights)
weights:dict[str, float]mapping symbol → target fraction of equity (0–1).- Symbols not in the dict are treated as 0%.
- If weights sum to > 1, they are normalized to sum to 1.
- Rebalance is skipped when targets are unchanged (within 1e-6) — avoids dust trades on mean-reversion strategies.
- Sells execute before buys to free cash; buys may scale down if cash is insufficient.
BacktestResult
| Field | Type | Description |
|---|---|---|
equity | pd.Series | Total portfolio value over time. |
holdings | pd.DataFrame | Share counts per symbol by date. |
trades | list[Trade] | Every fill with side, shares, price, commission. |
cash | pd.Series | Cash balance over time. |
benchmark | pd.Series | None | Optional benchmark series (set by caller). |
meta | dict | Extra metadata bag. |
Trade
@dataclass
class Trade:
date: str # "YYYY-MM-DD"
symbol: str
side: str # "buy" | "sell"
shares: float
price: float # after slippage
value: float # notional
commission: float