@livefolio/sdk / FeatureRuntime
Class: FeatureRuntime
Defined in: features/runtime.ts:164
Orchestrates indicator computation for a single backtest run or a live streaming session.
FeatureRuntime is the bridge between raw OHLCV data (via DataFeed) and the typed indicator functions registered in the feature registry. It handles:
- Bar fetching (historical mode) — Calls
DataFeed.barsonce per(asset, range, freq)tuple and caches the resultingSeriesin memory for the lifetime of the instance. Concurrent calls for the same asset share a single in-flight promise; there is no redundant fetching even ifcomputeis called from multiplePromise.allbranches simultaneously. - Bar buffering (streaming mode) — Bars are pushed in via
appendBar.computereads directly from the in-memory buffer;DataFeed.barsis never called. - Indicator dispatch — Delegates computation to the function registered via
defineFeaturefor the givenFeatureSpec.kind. - Persistent caching (historical mode only) — Checks
FeatureCachebefore computing. On a miss, the result is stored in the cache. Subsequent calls with the same(spec, asset)combination return instantly from cache without re-fetching bars.
Caching semantics:
- Historical mode: cache keys incorporate
spec,asset.id,range, andfreq. Results are read from and written tofeatureCache. - Streaming mode:
featureCacheis bypassed entirely — everycomputecall recomputes from the growing in-memory bar buffer. TheseriesCache(per-asset in-memory base-series cache) is the only cache layer; it is invalidated on eachappendBarso the nextcomputesees the updated buffer. - Calling
appendBarinvalidates the in-memory series cache for that asset so the nextcomputecall rebuilds the series from the updated buffer.
Examples
import {
FeatureRuntime,
MemoryFeatureCache,
seriesAt,
} from '@livefolio/sdk';
const runtime = new FeatureRuntime({
dataFeed,
featureCache: new MemoryFeatureCache(),
range: { from: new Date('2022-01-01'), to: new Date('2023-12-31') },
freq: '1d',
});
const spy = { kind: 'equity' as const, id: 'US:SPY', symbol: 'SPY' };
const smaSeries = await runtime.compute({ kind: 'sma', period: 20 }, spy);
const latestSma = seriesAt(smaSeries, new Date('2023-06-15'));
// => number | undefinedconst runtime = new FeatureRuntime({
featureCache: new MemoryFeatureCache(),
mode: 'streaming',
freq: '1d',
initialBars, // optional seed from BacktestResult
});
runtime.appendBar(spy, latestBar);
const smaSeries = await runtime.compute({ kind: 'sma', period: 20 }, spy);Constructors
Constructor
new FeatureRuntime(
opts):FeatureRuntime
Defined in: features/runtime.ts:180
Parameters
| Parameter | Type |
|---|---|
opts | FeatureRuntimeOptions |
Returns
FeatureRuntime
Methods
appendBar()
appendBar(
asset,bar):void
Defined in: features/runtime.ts:220
Appends a bar to the streaming buffer for the given asset.
Bars must be provided in non-decreasing t order per asset. A bar with the same t as the most recent buffered bar replaces it in place — this is the mark-to-market wiggle path used by runLive, where each incoming tick updates the running open/high/low/close of the in-flight session bar. A bar with t strictly greater than the buffered tail starts a fresh in-flight bar (e.g. at session boundaries). A bar with t strictly less than the buffered tail throws.
Also invalidates the in-memory series cache for the asset so the next compute call rebuilds the series from the updated buffer.
Parameters
| Parameter | Type |
|---|---|
asset | Asset |
bar | Bar |
Returns
void
Throws
If called on a historical-mode runtime.
Throws
If bar.t is strictly less than the last buffered bar's t.
compute()
compute(
spec,asset):Promise<Series>
Defined in: features/runtime.ts:337
Computes (or retrieves from cache) the output Series for a given feature spec applied to a specific asset.
Historical mode: on the first call for a (spec, asset) pair:
- Fetches or reuses the in-memory base
Seriesfor the asset. - Dispatches to the registered compute function for
spec.kind. - Stores the result in
featureCache. On subsequent calls, returns the cachedSeriesdirectly fromfeatureCache.
Streaming mode: reads from the in-memory bar buffer populated via appendBar. DataFeed.bars is never called. The persistent featureCache is bypassed entirely — results are never read from or written to it. The in-memory seriesCache (base series per asset) is the only cache layer and is invalidated on each appendBar, so every compute after a new bar reflects the updated buffer.
Parameters
| Parameter | Type | Description |
|---|---|---|
spec | FeatureSpec | The feature specification describing which indicator to compute and its parameters (e.g. { kind: 'sma', period: 20 }). |
asset | Asset | The asset for which to compute the feature. The asset's id is used both for data fetching and cache key construction. |
Returns
Promise<Series>
A promise that resolves to the computed Series. The series length is determined by the indicator's warmup: for example, SMA(20) returns series.length - 19 data points. Returns an empty array when the base series is shorter than the indicator's warmup period.
Example
const spy = { kind: 'equity' as const, id: 'US:SPY', symbol: 'SPY' };
const [priceSeries, smaSeries] = await Promise.all([
runtime.compute({ kind: 'price' }, spy),
runtime.compute({ kind: 'sma', period: 20 }, spy),
]);getAllBars()
getAllBars():
ReadonlyMap<string, readonlyBar[]>
Defined in: features/runtime.ts:284
Returns the full per-asset bar map (keyed by AssetId). Merges historical and streaming buffers (streaming wins on collision, but in practice an instance is in one mode at a time so collisions don't occur).
Returns a fresh Map — callers cannot mutate the internal state.
Returns
ReadonlyMap<string, readonly Bar[]>
getBars()
getBars(
asset): readonlyBar[]
Defined in: features/runtime.ts:273
Returns the bar buffer for asset, or an empty array if none has been fetched/buffered yet.
In historical mode this is populated after the first compute call that triggers a bar fetch for the asset. In streaming mode it reflects all bars pushed via appendBar.
Parameters
| Parameter | Type |
|---|---|
asset | Asset |
Returns
readonly Bar[]