@livefolio/sdk / runBacktest
Function: runBacktest()
runBacktest<
F,S>(opts):Promise<BacktestResult<S>>
Defined in: strategy/run-backtest.ts:189
Drives a Strategy over a historical date range and returns a full audit trail of orders, fills, and portfolio states.
The simulation loop:
- Enumerate trading sessions via
opts.calendar.sessions(opts.range). - Call
strategy.initialState?.()once to seed the carry-over state. - For each session
t, callstrategy.universe(t, portfolio). - Await
strategy.features(universe, portfolio, t). - Call
strategy.build(features, portfolio, state, t)to obtain orders and the next state value. Both legacyOrder[]returns and new{ orders, state }returns are normalised — the legacy form leaves state unchanged. - Await
opts.executor.submit(orders, t, portfolio)to obtain fills. - Apply fills to the portfolio with
applyFills. - Append a
BacktestSnapshotand advance to the next session.
The portfolio is never mutated in place; each session receives the immutable result of the previous session's applyFills.
Type Parameters
| Type Parameter | Default type |
|---|---|
F extends Readonly<Record<string, unknown>> | Readonly<Record<string, unknown>> |
S | unknown |
Parameters
| Parameter | Type | Description |
|---|---|---|
opts | RunBacktestOptions<F, S> | Backtest configuration. See RunBacktestOptions. |
Returns
Promise<BacktestResult<S>>
A promise that resolves to a BacktestResult containing one snapshot per trading session, the final portfolio state, and the final strategy state (finalState). Returns { snapshots: [], finalPortfolio: opts.initialPortfolio, finalState: undefined } when the calendar has no sessions in the requested range.
Example
ts
import {
runBacktest,
fromSpec,
MemoryFeatureCache,
BacktestExecutor,
NYSEExchangeCalendar,
FeatureRuntime,
} from '@livefolio/sdk';
const calendar = new NYSEExchangeCalendar();
const range = { from: new Date('2023-01-01'), to: new Date('2023-12-31') };
const featureCache = new MemoryFeatureCache();
const runtime = new FeatureRuntime({ dataFeed, featureCache, range, freq: '1d' });
const strategy = fromSpec(myTacticalSpec, { runtime, calendar });
const result = await runBacktest({
strategy,
range,
initialPortfolio: { cash: 100_000, positions: [] },
dataFeed,
executor: new BacktestExecutor({ dataFeed }),
calendar,
featureCache,
freq: '1d',
});
console.log(result.finalPortfolio.cash);
console.log(result.snapshots.length); // one entry per NYSE trading day in 2023