@livefolio/sdk 0.3.7 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/handles/ticker.ts","../src/providers/mappings.ts","../src/computations/sma.ts","../src/computations/ema.ts","../src/computations/rsi.ts","../src/computations/returns.ts","../src/computations/volatility.ts","../src/computations/drawdown.ts","../src/computations/calendar.ts","../src/computations/index.ts","../src/handles/indicator.ts","../src/computations/signal.ts","../src/handles/signal.ts","../src/handles/allocation.ts","../src/handles/strategy.ts","../src/computations/strategy.ts","../src/handles/portfolio.ts","../src/backtest/simulate.ts","../src/metrics/returns.ts","../src/metrics/summary.ts","../src/metrics/risk.ts","../src/metrics/drawdown.ts","../src/metrics/riskAdjusted.ts","../src/metrics/activity.ts","../src/metrics/tables.ts","../src/metrics/compute.ts","../src/backtest/types.ts","../src/client.ts","../src/handles/allocation-equality.ts"],"sourcesContent":["import type { StorageProvider } from '../providers/storage';\n\nexport class TickerHandle {\n readonly symbol: string;\n readonly leverage: number;\n\n private _storage: StorageProvider;\n private _resolvedId: number | null = null;\n private _resolving: Promise<{ id: number }> | null = null;\n\n constructor(storage: StorageProvider, symbol: string, leverage: number = 1) {\n this._storage = storage;\n this.symbol = symbol.toUpperCase();\n this.leverage = leverage;\n }\n\n get id(): number {\n if (this._resolvedId == null)\n throw new Error('TickerHandle not yet resolved. Call resolve(), or access via an async method.');\n return this._resolvedId;\n }\n\n async resolve(): Promise<{ id: number }> {\n if (this._resolvedId != null) return { id: this._resolvedId };\n if (!this._resolving) this._resolving = this._doResolve();\n return this._resolving;\n }\n\n static fromResolved(storage: StorageProvider, id: number, symbol: string, leverage: number): TickerHandle {\n const handle = new TickerHandle(storage, symbol, leverage);\n handle._resolvedId = id;\n return handle;\n }\n\n private async _doResolve(): Promise<{ id: number }> {\n const result = await this._storage.tickers.findOrCreate(this.symbol, this.leverage);\n this._resolvedId = result.id;\n return result;\n }\n}\n","import type { IndicatorType } from './types';\n\nexport type ProviderInfo =\n | { provider: 'yahoo'; symbol: string; rateSeries?: true }\n | { provider: 'fred'; seriesId: string; rateSeries?: true }\n | { provider: 'computed'; dependsOn: 'Price'; symbol: string; rateSeries?: true }\n | { provider: 'calendar' }\n | { provider: 'none' };\n\nconst FRED_SERIES: Record<string, string> = {\n T3M: 'DGS3MO',\n T6M: 'DGS6MO',\n T1Y: 'DGS1',\n T2Y: 'DGS2',\n T3Y: 'DGS3',\n T5Y: 'DGS5',\n T7Y: 'DGS7',\n T10Y: 'DGS10',\n T20Y: 'DGS20',\n T30Y: 'DGS30',\n};\n\n// Ticker symbols whose \"price\" values are rates/yields (expressed in percent),\n// not prices. For these, percent-change returns are both broken (divide by\n// zero / sign flips) and semantically wrong — callers should use absolute\n// differences instead.\nconst RATE_TICKER_SYMBOLS = new Set<string>([\n 'DTB3',\n 'DTB6',\n 'DFF',\n 'DGS3MO',\n 'DGS6MO',\n 'DGS1',\n 'DGS2',\n 'DGS3',\n 'DGS5',\n 'DGS7',\n 'DGS10',\n 'DGS20',\n 'DGS30',\n]);\n\nconst COMPUTED_TYPES = new Set<string>(['SMA', 'EMA', 'RSI', 'Return', 'Volatility', 'Drawdown']);\nconst CALENDAR_TYPES = new Set<string>(['Month', 'Day of Week', 'Day of Month', 'Day of Year']);\n\nexport function isRateTickerSymbol(symbol: string | null): boolean {\n return symbol != null && RATE_TICKER_SYMBOLS.has(symbol);\n}\n\nexport function getProviderInfo(type: IndicatorType, tickerSymbol: string | null): ProviderInfo {\n if (type === 'Price') {\n const info: ProviderInfo = { provider: 'yahoo', symbol: tickerSymbol! };\n if (isRateTickerSymbol(tickerSymbol)) info.rateSeries = true;\n return info;\n }\n if (type === 'VIX') return { provider: 'yahoo', symbol: '^VIX' };\n if (type === 'VIX3M') return { provider: 'yahoo', symbol: '^VIX3M' };\n\n if (type in FRED_SERIES) return { provider: 'fred', seriesId: FRED_SERIES[type]!, rateSeries: true };\n\n if (COMPUTED_TYPES.has(type)) {\n const info: ProviderInfo = { provider: 'computed', dependsOn: 'Price', symbol: tickerSymbol! };\n if (isRateTickerSymbol(tickerSymbol)) info.rateSeries = true;\n return info;\n }\n\n if (CALENDAR_TYPES.has(type)) return { provider: 'calendar' };\n\n return { provider: 'none' };\n}\n","import type { DailyBar } from '../handles/indicator';\n\nexport function computeSma(bars: DailyBar[], lookback: number): DailyBar[] {\n if (bars.length < lookback) return [];\n const result: DailyBar[] = [];\n let sum = 0;\n for (let i = 0; i < lookback; i++) sum += bars[i].value;\n result.push({ date: bars[lookback - 1].date, value: sum / lookback });\n for (let i = lookback; i < bars.length; i++) {\n sum += bars[i].value - bars[i - lookback].value;\n result.push({ date: bars[i].date, value: sum / lookback });\n }\n return result;\n}\n\nexport interface SmaState {\n tail: number[];\n}\n\nexport function smaInitialState(bars: DailyBar[], lookback: number): SmaState | null {\n if (bars.length < lookback) return null;\n return { tail: bars.slice(-lookback).map((b) => b.value) };\n}\n\nexport function smaNext(prev: SmaState, newRaw: number, lookback: number): { value: number; state: SmaState } {\n const tail = [...prev.tail.slice(1), newRaw];\n const sum = tail.reduce((a, b) => a + b, 0);\n return { value: sum / lookback, state: { tail } };\n}\n","import type { DailyBar } from '../handles/indicator';\n\nexport function computeEma(bars: DailyBar[], lookback: number): DailyBar[] {\n if (bars.length < lookback) return [];\n const multiplier = 2 / (lookback + 1);\n const result: DailyBar[] = [];\n let sum = 0;\n for (let i = 0; i < lookback; i++) sum += bars[i].value;\n let ema = sum / lookback;\n result.push({ date: bars[lookback - 1].date, value: ema });\n for (let i = lookback; i < bars.length; i++) {\n ema = bars[i].value * multiplier + ema * (1 - multiplier);\n result.push({ date: bars[i].date, value: ema });\n }\n return result;\n}\n\nexport interface EmaState {\n ema: number;\n}\n\nexport function emaInitialState(bars: DailyBar[], lookback: number): EmaState | null {\n if (bars.length < lookback) return null;\n const series = computeEma(bars, lookback);\n if (series.length === 0) return null;\n return { ema: series[series.length - 1]!.value };\n}\n\nexport function emaNext(prev: EmaState, newRaw: number, lookback: number): { value: number; state: EmaState } {\n const multiplier = 2 / (lookback + 1);\n const ema = newRaw * multiplier + prev.ema * (1 - multiplier);\n return { value: ema, state: { ema } };\n}\n","import type { DailyBar } from '../handles/indicator';\n\nexport function computeRsi(bars: DailyBar[], lookback: number): DailyBar[] {\n if (bars.length < lookback + 1) return [];\n const changes: number[] = [];\n for (let i = 1; i < bars.length; i++) {\n changes.push(bars[i].value - bars[i - 1].value);\n }\n let avgGain = 0;\n let avgLoss = 0;\n for (let i = 0; i < lookback; i++) {\n if (changes[i] > 0) avgGain += changes[i];\n else avgLoss += Math.abs(changes[i]);\n }\n avgGain /= lookback;\n avgLoss /= lookback;\n const result: DailyBar[] = [];\n const rs = avgLoss === 0 ? 100 : avgGain / avgLoss;\n result.push({\n date: bars[lookback].date,\n value: avgLoss === 0 ? 100 : 100 - 100 / (1 + rs),\n });\n for (let i = lookback; i < changes.length; i++) {\n const gain = changes[i] > 0 ? changes[i] : 0;\n const loss = changes[i] < 0 ? Math.abs(changes[i]) : 0;\n avgGain = (avgGain * (lookback - 1) + gain) / lookback;\n avgLoss = (avgLoss * (lookback - 1) + loss) / lookback;\n const smoothRs = avgLoss === 0 ? 100 : avgGain / avgLoss;\n result.push({\n date: bars[i + 1].date,\n value: avgLoss === 0 ? 100 : 100 - 100 / (1 + smoothRs),\n });\n }\n return result;\n}\n\nexport interface RsiState {\n avgGain: number;\n avgLoss: number;\n prev: number;\n}\n\nexport function rsiInitialState(bars: DailyBar[], lookback: number): RsiState | null {\n if (bars.length < lookback + 1) return null;\n let avgGain = 0;\n let avgLoss = 0;\n for (let i = 1; i <= lookback; i++) {\n const change = bars[i]!.value - bars[i - 1]!.value;\n if (change > 0) avgGain += change;\n else avgLoss += -change;\n }\n avgGain /= lookback;\n avgLoss /= lookback;\n let state: RsiState = { avgGain, avgLoss, prev: bars[lookback]!.value };\n for (let i = lookback + 1; i < bars.length; i++) {\n const { state: next } = rsiNext(state, bars[i]!.value, lookback);\n state = next;\n }\n return state;\n}\n\nexport function rsiNext(prev: RsiState, newRaw: number, lookback: number): { value: number; state: RsiState } {\n const change = newRaw - prev.prev;\n const gain = change > 0 ? change : 0;\n const loss = change < 0 ? -change : 0;\n const avgGain = (prev.avgGain * (lookback - 1) + gain) / lookback;\n const avgLoss = (prev.avgLoss * (lookback - 1) + loss) / lookback;\n const rs = avgLoss === 0 ? 100 : avgGain / avgLoss;\n const value = avgLoss === 0 ? 100 : 100 - 100 / (1 + rs);\n return { value, state: { avgGain, avgLoss, prev: newRaw } };\n}\n","import type { DailyBar } from '../handles/indicator';\n\nexport type ReturnMode = 'pct' | 'abs';\n\nexport function computeReturns(bars: DailyBar[], lookback: number, mode: ReturnMode = 'pct'): DailyBar[] {\n if (bars.length <= lookback) return [];\n const result: DailyBar[] = [];\n for (let i = lookback; i < bars.length; i++) {\n const curr = bars[i]!.value;\n const prev = bars[i - lookback]!.value;\n const value = mode === 'abs' ? curr - prev : (curr - prev) / prev;\n result.push({ date: bars[i]!.date, value });\n }\n return result;\n}\n\nexport interface ReturnState {\n tail: number[];\n}\n\nexport function returnInitialState(bars: DailyBar[], lookback: number): ReturnState | null {\n if (bars.length < lookback + 1) return null;\n return { tail: bars.slice(-(lookback + 1)).map((b) => b.value) };\n}\n\nexport function returnNext(\n prev: ReturnState,\n newRaw: number,\n lookback: number,\n mode: ReturnMode = 'pct',\n): { value: number; state: ReturnState } {\n const tail = [...prev.tail.slice(1), newRaw];\n const old = tail[0]!;\n const value = mode === 'abs' ? newRaw - old : (newRaw - old) / old;\n return { value, state: { tail } };\n}\n","import type { DailyBar } from '../handles/indicator';\n\nexport function computeVolatility(bars: DailyBar[], lookback: number): DailyBar[] {\n if (bars.length < lookback + 1) return [];\n const dailyReturns: { date: string; value: number }[] = [];\n for (let i = 1; i < bars.length; i++) {\n dailyReturns.push({\n date: bars[i].date,\n value: bars[i].value / bars[i - 1].value - 1,\n });\n }\n if (dailyReturns.length < lookback) return [];\n const result: DailyBar[] = [];\n for (let i = lookback - 1; i < dailyReturns.length; i++) {\n const window = dailyReturns.slice(i - lookback + 1, i + 1);\n const mean = window.reduce((s, r) => s + r.value, 0) / lookback;\n const variance = window.reduce((s, r) => s + (r.value - mean) ** 2, 0) / lookback;\n result.push({ date: dailyReturns[i].date, value: Math.sqrt(variance) });\n }\n return result;\n}\n\nexport interface VolatilityState {\n tail: number[];\n}\n\nexport function volatilityInitialState(bars: DailyBar[], lookback: number): VolatilityState | null {\n if (bars.length < lookback + 1) return null;\n return { tail: bars.slice(-(lookback + 1)).map((b) => b.value) };\n}\n\nexport function volatilityNext(\n prev: VolatilityState,\n newRaw: number,\n lookback: number,\n): { value: number; state: VolatilityState } {\n const tail = [...prev.tail.slice(1), newRaw];\n const returns: number[] = [];\n for (let i = 1; i < tail.length; i++) returns.push(tail[i]! / tail[i - 1]! - 1);\n const mean = returns.reduce((s, r) => s + r, 0) / lookback;\n const variance = returns.reduce((s, r) => s + (r - mean) ** 2, 0) / lookback;\n return { value: Math.sqrt(variance), state: { tail } };\n}\n","import type { DailyBar } from '../handles/indicator';\n\nexport function computeDrawdown(bars: DailyBar[], lookback: number): DailyBar[] {\n if (bars.length < lookback) return [];\n const result: DailyBar[] = [];\n for (let i = lookback - 1; i < bars.length; i++) {\n let max = -Infinity;\n for (let j = i - lookback + 1; j <= i; j++) {\n if (bars[j].value > max) max = bars[j].value;\n }\n result.push({ date: bars[i].date, value: (bars[i].value - max) / max });\n }\n return result;\n}\n\nexport interface DrawdownState {\n tail: number[];\n}\n\nexport function drawdownInitialState(bars: DailyBar[], lookback: number): DrawdownState | null {\n if (bars.length < lookback) return null;\n return { tail: bars.slice(-lookback).map((b) => b.value) };\n}\n\nexport function drawdownNext(\n prev: DrawdownState,\n newRaw: number,\n _lookback: number,\n): { value: number; state: DrawdownState } {\n const tail = [...prev.tail.slice(1), newRaw];\n let max = -Infinity;\n for (const v of tail) if (v > max) max = v;\n return { value: (newRaw - max) / max, state: { tail } };\n}\n","import type { DailyBar } from '../handles/indicator';\n\ntype CalendarPeriod = 'Month' | 'Day of Week' | 'Day of Month' | 'Day of Year';\n\nfunction dayOfYear(d: Date): number {\n const start = new Date(d.getFullYear(), 0, 0);\n const diff = d.getTime() - start.getTime();\n return Math.floor(diff / (1000 * 60 * 60 * 24));\n}\n\nexport function computeCalendar(bars: DailyBar[], period: CalendarPeriod): DailyBar[] {\n return bars.map((bar) => {\n const [y, m, d] = bar.date.split('-').map(Number);\n const date = new Date(y, m - 1, d);\n let value: number;\n switch (period) {\n case 'Month':\n value = date.getMonth() + 1;\n break;\n case 'Day of Week':\n value = date.getDay();\n break;\n case 'Day of Month':\n value = date.getDate();\n break;\n case 'Day of Year':\n value = dayOfYear(date);\n break;\n }\n return { date: bar.date, value };\n });\n}\n","import type { DailyBar } from '../handles/indicator';\nimport type { IndicatorType } from '../providers/types';\nimport { computeSma } from './sma';\nimport { computeEma } from './ema';\nimport { computeRsi } from './rsi';\nimport { computeReturns } from './returns';\nimport { computeVolatility } from './volatility';\nimport { computeDrawdown } from './drawdown';\nimport { smaNext, smaInitialState } from './sma';\nimport { emaNext, emaInitialState } from './ema';\nimport { rsiNext, rsiInitialState } from './rsi';\nimport { returnNext, returnInitialState } from './returns';\nimport { volatilityNext, volatilityInitialState } from './volatility';\nimport { drawdownNext, drawdownInitialState } from './drawdown';\n\nexport { computeSma } from './sma';\nexport { computeEma } from './ema';\nexport { computeRsi } from './rsi';\nexport { computeReturns } from './returns';\nexport { computeVolatility } from './volatility';\nexport { computeDrawdown } from './drawdown';\nexport { computeCalendar } from './calendar';\ntype ComputeFn = (bars: DailyBar[], lookback: number) => DailyBar[];\n\nconst COMPUTATIONS: Partial<Record<IndicatorType, ComputeFn>> = {\n SMA: computeSma,\n EMA: computeEma,\n RSI: computeRsi,\n Return: computeReturns,\n Volatility: computeVolatility,\n Drawdown: computeDrawdown,\n};\n\nexport function getComputation(type: IndicatorType): ComputeFn | null {\n return COMPUTATIONS[type] ?? null;\n}\n\nexport type NextStepFn = (prev: unknown, newRaw: number, lookback: number) => { value: number; state: unknown };\n\nexport type InitialStateFn = (bars: DailyBar[], lookback: number) => unknown | null;\n\nconst NEXT: Record<string, NextStepFn> = {\n SMA: smaNext as NextStepFn,\n EMA: emaNext as NextStepFn,\n RSI: rsiNext as NextStepFn,\n Return: ((prev, newRaw, lookback) => returnNext(prev as { tail: number[] }, newRaw, lookback, 'pct')) as NextStepFn,\n Volatility: volatilityNext as NextStepFn,\n Drawdown: drawdownNext as NextStepFn,\n};\n\nconst SEED: Record<string, InitialStateFn> = {\n SMA: smaInitialState as InitialStateFn,\n EMA: emaInitialState as InitialStateFn,\n RSI: rsiInitialState as InitialStateFn,\n Return: returnInitialState as InitialStateFn,\n Volatility: volatilityInitialState as InitialStateFn,\n Drawdown: drawdownInitialState as InitialStateFn,\n};\n\nexport function getNextComputation(type: string): NextStepFn | undefined {\n return NEXT[type];\n}\n\nexport function getInitialStateFn(type: string): InitialStateFn | undefined {\n return SEED[type];\n}\n","import type { StorageProvider } from '../providers/storage';\nimport type { MarketProvider } from '../providers/market';\nimport type { IndicatorType, Unit } from '../providers/types';\nimport { TickerHandle } from './ticker';\nimport { getProviderInfo, isRateTickerSymbol } from '../providers/mappings';\nimport { getComputation, getNextComputation, getInitialStateFn } from '../computations/index';\nimport { computeReturns, returnNext } from '../computations/returns';\nimport { computeCalendar } from '../computations/calendar';\n\n/**\n * Inverse of `FRED_SERIES` in `providers/mappings.ts`. Lets `_readStoredBars`\n * map a FRED series ID (`DGS3MO`, `DGS10`, etc.) back to the indicator type\n * whose stored series holds that series' history.\n */\nconst FRED_SYMBOL_TO_TYPE: Record<string, string> = {\n DGS3MO: 'T3M',\n DGS6MO: 'T6M',\n DGS1: 'T1Y',\n DGS2: 'T2Y',\n DGS3: 'T3Y',\n DGS5: 'T5Y',\n DGS7: 'T7Y',\n DGS10: 'T10Y',\n DGS20: 'T20Y',\n DGS30: 'T30Y',\n};\n\n/**\n * Subtract `days` calendar days from an ISO date string (YYYY-MM-DD).\n * Used to compute a `from` cutoff for bounded bar fetches in `computeAt`.\n */\nfunction _subtractCalendarDays(date: string, days: number): string {\n const d = new Date(date);\n d.setUTCDate(d.getUTCDate() - days);\n return d.toISOString().slice(0, 10);\n}\n\nexport interface DailyBar {\n date: string;\n value: number;\n}\n\nexport interface IndicatorIdentity {\n type: IndicatorType;\n ticker: TickerHandle | null;\n lookback: number;\n delay: number;\n unit: Unit | null;\n threshold: number | null;\n}\n\nexport interface DateRange {\n from?: string;\n to?: string;\n}\n\nexport class IndicatorHandle {\n readonly type: IndicatorType;\n readonly ticker: TickerHandle | null;\n readonly lookback: number;\n readonly delay: number;\n readonly unit: Unit | null;\n readonly threshold: number | null;\n\n private _storage: StorageProvider;\n private _market: MarketProvider;\n private _resolvedId: number | null = null;\n private _resolving: Promise<{ id: number }> | null = null;\n\n private _cachedSeries: DailyBar[] | null = null;\n private _cachedAsOf: string | null = null;\n private _syncing: Promise<void> | null = null;\n\n constructor(storage: StorageProvider, market: MarketProvider, identity: IndicatorIdentity) {\n this._storage = storage;\n this._market = market;\n this.type = identity.type;\n this.ticker = identity.ticker;\n this.lookback = identity.lookback;\n this.delay = identity.delay;\n this.unit = identity.unit;\n this.threshold = identity.threshold;\n }\n\n get id(): number {\n if (this._resolvedId == null)\n throw new Error('IndicatorHandle not yet resolved. Call resolve(), or access via an async method.');\n return this._resolvedId;\n }\n\n async resolve(): Promise<{ id: number }> {\n if (this._resolvedId != null) return { id: this._resolvedId };\n if (!this._resolving) this._resolving = this._doResolve();\n return this._resolving;\n }\n\n static fromResolved(\n storage: StorageProvider,\n market: MarketProvider,\n id: number,\n identity: IndicatorIdentity,\n ): IndicatorHandle {\n const handle = new IndicatorHandle(storage, market, identity);\n handle._resolvedId = id;\n return handle;\n }\n\n private async _doResolve(): Promise<{ id: number }> {\n const tickerId = this.ticker ? (await this.ticker.resolve()).id : null;\n const result = await this._storage.indicators.findOrCreate({\n type: this.type,\n tickerId,\n lookback: this.lookback,\n delay: this.delay,\n unit: this.unit,\n threshold: this.threshold,\n });\n this._resolvedId = result.id;\n return result;\n }\n\n // ── Freshness & Sync ───────────────────────────────────────────────\n\n private async _getLatestClosedTradingDay(): Promise<string> {\n const date = await this._storage.tradingDays.getLatestClosed();\n if (!date) throw new Error('No closed trading days found');\n return date;\n }\n\n private async _getLatestSeriesDate(indicatorId: number): Promise<string | null> {\n return this._storage.indicators.getLatestSeriesDate(indicatorId);\n }\n\n private async _ensureFresh(): Promise<void> {\n const { id } = await this.resolve();\n const latestClosed = await this._getLatestClosedTradingDay();\n\n // In-memory cache still valid\n if (this._cachedAsOf === latestClosed) return;\n\n // `horizon` = the latest date this indicator's series can be written at.\n // delay = 0 → latestClosed; delay > 0 → latestClosed − delay trading days.\n // \"Fresh\" means the stored series already reaches that horizon.\n let horizon = latestClosed;\n if (this.delay > 0) {\n const tradingDays = await this._storage.tradingDays.getRange();\n const idx = tradingDays.indexOf(latestClosed);\n if (idx >= this.delay) {\n horizon = tradingDays[idx - this.delay]!;\n }\n }\n\n const latestSeries = await this._getLatestSeriesDate(id);\n\n if (latestSeries === horizon) {\n // DB is fresh — invalidate in-memory cache so next read picks up DB data\n this._cachedSeries = null;\n this._cachedAsOf = latestClosed;\n return;\n }\n\n // Need to sync — deduplicate concurrent calls. On sync failure (e.g.,\n // browser has no market provider, or upstream feed hasn't published the\n // new date yet), fall back to whatever storage already has and treat the\n // cache as fresh so downstream callers don't retry the failing sync on\n // every read.\n if (!this._syncing) {\n this._syncing = this._sync(latestSeries ?? undefined, latestClosed)\n .catch((err) => {\n console.warn('[sdk] indicator sync failed, using stored data:', err);\n })\n .finally(() => {\n this._syncing = null;\n });\n }\n await this._syncing;\n\n this._cachedSeries = null;\n this._cachedAsOf = latestClosed;\n }\n\n private async _sync(fromDate: string | undefined, latestClosed: string): Promise<void> {\n const tickerSymbol = this.ticker?.symbol ?? null;\n const info = getProviderInfo(this.type, tickerSymbol);\n if (info.provider === 'none') return;\n\n // Compute the horizon this indicator may publish up to.\n let horizon = latestClosed;\n if (this.delay > 0) {\n const tradingDays = await this._storage.tradingDays.getRange();\n const idx = tradingDays.indexOf(latestClosed);\n if (idx < this.delay) return;\n horizon = tradingDays[idx - this.delay]!;\n }\n\n // Fast path only applies when (a) we have a checkpoint, (b) the type is stateful\n // (has a *Next in the dispatch table), and (c) the checkpoint's date is strictly\n // less than horizon (i.e., there's at least one new bar to append).\n const nextFn = getNextComputation(this.type);\n const seedFn = getInitialStateFn(this.type);\n const { id } = await this.resolve();\n const checkpoint = nextFn ? await this._storage.indicators.getLatestBar(id) : null;\n\n if (fromDate && nextFn && seedFn && checkpoint && checkpoint.metadata != null && checkpoint.date < horizon) {\n // Fetch only the raw bars we need to step forward over.\n const rawBars = await this._fetchRawBarsForIncremental(info, checkpoint.date, horizon);\n if (rawBars.length === 0) return;\n const newBars: { date: string; value: number }[] = [];\n let state = checkpoint.metadata as unknown;\n for (const raw of rawBars) {\n if (raw.date <= checkpoint.date) continue;\n if (raw.date > horizon) break;\n const step =\n this.type === 'Return' && info.provider === 'computed' && info.rateSeries\n ? returnNext(state as { tail: number[] }, raw.value, this.lookback, 'abs')\n : nextFn(state, raw.value, this.lookback);\n newBars.push({ date: raw.date, value: step.value });\n state = step.state;\n }\n if (newBars.length === 0) return;\n await this._storage.indicators.writeSeries(id, newBars, { metadata: state });\n return;\n }\n\n // Cold path (existing logic, now augmented to park initial-state metadata).\n let bars: DailyBar[];\n switch (info.provider) {\n case 'yahoo':\n bars = await this._market.fetchBars(info.symbol, fromDate);\n break;\n\n case 'fred':\n bars = await this._market.fetchBars(info.seriesId, fromDate);\n break;\n\n case 'computed': {\n const priceHandle = new IndicatorHandle(this._storage, this._market, {\n type: 'Price',\n ticker: this.ticker,\n lookback: 0,\n delay: 0,\n unit: null,\n threshold: null,\n });\n await priceHandle._ensureFresh();\n const priceBars = await priceHandle._querySeriesFromDb();\n if (this.type === 'Return') {\n // For rate/yield series (e.g. DTB3, DFF), percentage change is broken\n // near zero and semantically wrong; use absolute differences instead.\n bars = computeReturns(priceBars, this.lookback, info.rateSeries ? 'abs' : 'pct');\n } else {\n const computeFn = getComputation(this.type);\n if (!computeFn) throw new Error(`No computation found for type \"${this.type}\"`);\n bars = computeFn(priceBars, this.lookback);\n }\n if (fromDate) bars = bars.filter((b) => b.date > fromDate);\n break;\n }\n\n case 'calendar': {\n // Fetch all trading days to compute calendar values\n const allDays = await this._storage.tradingDays.getRange();\n const dayBars: DailyBar[] = allDays.map((date) => ({ date, value: 0 }));\n bars = computeCalendar(dayBars, this.type as 'Month' | 'Day of Week' | 'Day of Month' | 'Day of Year');\n if (fromDate) bars = bars.filter((b) => b.date > fromDate);\n break;\n }\n }\n\n // Apply leverage to daily returns only for fetched (non-computed) indicators.\n // Computed indicators (RSI, SMA, etc.) already read from the leveraged price series.\n if (info.provider !== 'computed') {\n bars = await this._applyLeverage(bars, fromDate);\n }\n\n bars = bars.filter((b) => b.date <= horizon);\n if (bars.length === 0) return;\n\n // For stateful types, derive and park the terminal metadata so subsequent\n // syncs take the fast path.\n let metadata: unknown = undefined;\n if (seedFn) {\n // For stateful COMPUTED types, seed from the full price bars up to horizon;\n // for stateful FETCHED types (none in current code, but future-safe) seed\n // from the bars we're about to write.\n if (info.provider === 'computed') {\n const priceHandle = new IndicatorHandle(this._storage, this._market, {\n type: 'Price',\n ticker: this.ticker,\n lookback: 0,\n delay: 0,\n unit: null,\n threshold: null,\n });\n const priceBars = (await priceHandle._querySeriesFromDb()).filter((b) => b.date <= horizon);\n metadata = seedFn(priceBars, this.lookback) ?? undefined;\n } else {\n metadata = seedFn(bars, this.lookback) ?? undefined;\n }\n }\n\n await this._upsertSeries(bars, metadata);\n }\n\n private async _fetchRawBarsForIncremental(\n info: ReturnType<typeof getProviderInfo>,\n sinceDate: string,\n horizon: string,\n ): Promise<DailyBar[]> {\n if (info.provider === 'computed') {\n const priceHandle = new IndicatorHandle(this._storage, this._market, {\n type: 'Price',\n ticker: this.ticker,\n lookback: 0,\n delay: 0,\n unit: null,\n threshold: null,\n });\n await priceHandle._ensureFresh();\n return (await priceHandle._querySeriesFromDb({ from: sinceDate })).filter(\n (b) => b.date > sinceDate && b.date <= horizon,\n );\n }\n if (info.provider === 'yahoo' || info.provider === 'fred') {\n const symbol = info.provider === 'yahoo' ? info.symbol : info.seriesId;\n const bars = await this._market.fetchBars(symbol, sinceDate);\n return bars.filter((b) => b.date > sinceDate && b.date <= horizon);\n }\n if (info.provider === 'calendar') {\n const allDays = await this._storage.tradingDays.getRange();\n const dayBars: DailyBar[] = allDays.map((date) => ({ date, value: 0 }));\n return computeCalendar(dayBars, this.type as 'Month' | 'Day of Week' | 'Day of Month' | 'Day of Year').filter(\n (b) => b.date > sinceDate && b.date <= horizon,\n );\n }\n return [];\n }\n\n private async _upsertSeries(bars: DailyBar[], metadata?: unknown): Promise<void> {\n const { id } = await this.resolve();\n await this._storage.indicators.writeSeries(id, bars, metadata !== undefined ? { metadata } : undefined);\n }\n\n private async _querySeriesFromDb(range?: DateRange): Promise<DailyBar[]> {\n const { id } = await this.resolve();\n return this._storage.indicators.getSeries(id, range);\n }\n\n /**\n * Apply leverage compounding to a raw bar series, anchored to a stored\n * leveraged value. Used by both `_sync` and `computeAt` so they stay\n * consistent.\n *\n * `anchorDate` is the date of the last *already-stored* leveraged bar\n * (i.e., the bar just before `rawBars[0]`). The stored leveraged value\n * at that date becomes `leveraged[0]`; raw returns are then compounded\n * forward for each subsequent bar.\n *\n * If no stored anchor exists (first-ever sync), falls back to rawBars[0]\n * as the starting raw value — identical to `_sync`'s behaviour.\n */\n private async _applyLeverage(rawBars: DailyBar[], anchorDate: string | undefined): Promise<DailyBar[]> {\n const leverage = this.ticker?.leverage ?? 1;\n if (leverage === 1 || rawBars.length === 0) return rawBars;\n // Rate tickers (DTB3, DFF, etc.) skip leverage compounding: the stored series\n // stays raw; the simulator applies the leverage multiplier at accrual time.\n if (isRateTickerSymbol(this.ticker?.symbol ?? null)) return rawBars;\n\n let anchor: number;\n if (anchorDate) {\n const lastStored = await this._storage.indicators.getValue(this._resolvedId!, anchorDate);\n anchor = lastStored ?? rawBars[0]!.value;\n } else {\n anchor = rawBars[0]!.value;\n }\n\n const leveraged: DailyBar[] = [{ date: rawBars[0]!.date, value: anchor }];\n for (let i = 1; i < rawBars.length; i++) {\n const dailyReturn = (rawBars[i]!.value - rawBars[i - 1]!.value) / rawBars[i - 1]!.value;\n const prev = leveraged[i - 1]!.value;\n leveraged.push({ date: rawBars[i]!.date, value: prev * (1 + leverage * dailyReturn) });\n }\n return leveraged;\n }\n\n /**\n * Compute the indicator's value at `date` without persisting anything, with\n * optional live-quote `overrides` keyed by raw market symbol (the same symbol\n * space `MarketProvider.fetchBars` uses — ticker symbols for Price/SMA/etc.,\n * `^VIX` / `^VIX3M` for macro, FRED series IDs like `DGS3MO` for Treasury).\n *\n * Bars for the underlying symbol are resolved storage-first when the market\n * hasn't yet produced bars for `date` (trading day still open), and storage\n * is the fallback whenever the remote fetch fails — see `_resolveRawBars`.\n *\n * For Threshold: returns the threshold constant. For calendar types: computed\n * from `tradingDays.getRange()`. For all others: `_resolveRawBars` → leverage\n * compounding (if any) → lookback-specific computation. Returns null if the\n * value cannot be computed.\n */\n async computeAt(date: string, overrides?: Record<string, number>): Promise<number | null> {\n // Threshold is a special case: it has no market data, just a constant value.\n if (this.type === 'Threshold') return this.threshold;\n\n const tickerSymbol = this.ticker?.symbol ?? null;\n const info = getProviderInfo(this.type, tickerSymbol);\n\n if (info.provider === 'none') return null;\n\n if (info.provider === 'calendar') {\n const allDays = await this._storage.tradingDays.getRange();\n const dayBars: DailyBar[] = allDays.map((d) => ({ date: d, value: 0 }));\n const computed = computeCalendar(dayBars, this.type as 'Month' | 'Day of Week' | 'Day of Month' | 'Day of Year');\n return computed.find((b) => b.date === date)?.value ?? null;\n }\n\n if (info.provider === 'computed') {\n // Fast path: checkpoint is the trading day immediately before `date`.\n const nextFn = getNextComputation(this.type);\n if (nextFn) {\n const { id } = await this.resolve();\n const checkpoint = await this._storage.indicators.getLatestBar(id);\n if (checkpoint && checkpoint.metadata != null) {\n const tradingDays = await this._storage.tradingDays.getRange();\n const ckIdx = tradingDays.indexOf(checkpoint.date);\n const tgtIdx = tradingDays.indexOf(date);\n if (ckIdx >= 0 && tgtIdx === ckIdx + 1) {\n const rawBar = await this._resolveRawBarAt(info.symbol, date, overrides);\n if (rawBar === null) return null;\n\n // For leveraged tickers the checkpoint state (`checkpoint.metadata`)\n // was built on the leveraged price series, so its `prev` is a\n // leveraged value. Scale the new raw bar up to the same leveraged\n // scale before stepping the recursive computation — otherwise the\n // one-step `change` mixes unleveraged with leveraged and produces\n // a runaway delta (e.g. QQQ 3x RSI(10) spiking from 80 → 97 on a\n // flat intraday day). Rate tickers (DTB3, DFF, …) skip this: their\n // stored series is raw by convention, with leverage applied at\n // accrual time by the simulator.\n const leverage = this.ticker?.leverage ?? 1;\n let nextValue = rawBar;\n if (leverage !== 1 && !isRateTickerSymbol(this.ticker?.symbol ?? null)) {\n // Overrides are scoped to `date`, not `checkpoint.date`; resolving\n // the prior close *with* overrides in scope returns the override\n // (same symbol, any date) and makes dailyReturn=0. Pass undefined\n // so the prior close comes from storage.\n const prevRaw = await this._resolveRawBarAt(info.symbol, checkpoint.date, undefined);\n const prevLev = (checkpoint.metadata as { prev?: number }).prev;\n if (prevRaw !== null && prevRaw !== 0 && typeof prevLev === 'number') {\n const dailyReturn = (rawBar - prevRaw) / prevRaw;\n nextValue = prevLev * (1 + leverage * dailyReturn);\n }\n }\n\n const step =\n this.type === 'Return' && info.rateSeries\n ? returnNext(checkpoint.metadata as { tail: number[] }, nextValue, this.lookback, 'abs')\n : nextFn(checkpoint.metadata, nextValue, this.lookback);\n return step.value;\n }\n }\n }\n\n // Size the bar window by the computation's actual needs, expressed in\n // calendar days. Three buckets:\n //\n // Exact reads (SMA / Return / Volatility / Drawdown) want `lookback`\n // *trading* days in the result; with ~5 trading days per 7 calendar\n // days plus holidays that's ~`lookback * 1.5` calendar days, plus a\n // small fixed buffer for long weekends.\n //\n // EMA is recursive: seed = first N-bar SMA, then `(1-α)^k` decay with\n // α = 2 / (N+1). For small N the decay is fast; for N=200 decay is\n // ~0.99/bar, so we want several multiples of `lookback` to get close\n // to the fully-synced EMA value.\n //\n // Wilder's RSI decays at ~10%/bar regardless of lookback and starts\n // from a simple-average seed that can pin at 100 (or 0) for a window\n // full of only-up (or only-down) days; it needs the widest window.\n let calendarDays: number;\n if (this.type === 'RSI') {\n calendarDays = Math.max(this.lookback * 10, 90);\n } else if (this.type === 'EMA') {\n calendarDays = Math.max(this.lookback * 5, 60);\n } else {\n // SMA, Return, Volatility, Drawdown — exact-read, only need coverage.\n calendarDays = Math.ceil(this.lookback * 1.5) + 15;\n }\n const from = _subtractCalendarDays(date, this.lookback + calendarDays);\n const rawBars = await this._resolveRawBars(info.symbol, from, date, overrides);\n\n // Apply leverage anchored to the stored leveraged value at the date just\n // before the first resolved raw bar. Mirrors `_sync`'s anchor logic.\n const anchorDate = rawBars.length > 0 ? rawBars[0]!.date : undefined;\n const priceBars = await this._applyLeverage(rawBars, anchorDate);\n\n const computeFn = getComputation(this.type);\n if (!computeFn) throw new Error(`No computation found for type \"${this.type}\"`);\n const computed = computeFn(priceBars, this.lookback);\n return computed.find((b) => b.date === date)?.value ?? null;\n }\n\n // yahoo or fred: resolve a small window — just enough to get `date` and\n // one prior bar (needed for leverage return calculation). 15 calendar days\n // comfortably bridges a long weekend + holiday gap; FRED series in\n // particular publish on T+1 / T+2 cadences and can miss a market day.\n const symbol = info.provider === 'yahoo' ? info.symbol : info.seriesId;\n const from = _subtractCalendarDays(date, 15);\n const rawBars = await this._resolveRawBars(symbol, from, date, overrides);\n\n const leverage = this.ticker?.leverage ?? 1;\n if (leverage === 1) {\n return rawBars.find((b) => b.date === date)?.value ?? null;\n }\n\n // Apply leverage compounding.\n const dateIdx = rawBars.findIndex((b) => b.date === date);\n if (dateIdx < 0) return null; // date not in bars at all\n\n const prevBar = rawBars[dateIdx - 1];\n if (!prevBar) {\n // No previous bar in the window — can't compound. Return raw value as fallback.\n return rawBars[dateIdx]!.value;\n }\n\n const storedPrev = await this._storage.indicators.getValue(this._resolvedId!, prevBar.date);\n const leveragedPrev = storedPrev ?? prevBar.value;\n const rawReturn = (rawBars[dateIdx]!.value - prevBar.value) / prevBar.value;\n return leveragedPrev * (1 + leverage * rawReturn);\n }\n\n /**\n * Raw (unleveraged) bars for `symbol` up through `date`, with the live quote\n * from `overrides[symbol]` (if any) spliced in at `date`.\n *\n * Decision policy:\n * - `date` > `tradingDays.getLatestClosed()`: market has nothing for that\n * day yet — skip the remote fetch entirely and read from storage.\n * - otherwise: try `this._market.fetchBars(symbol, from)`. On failure, fall\n * back to storage — upstream HTTP providers (Yahoo / FRED) are flaky.\n *\n * After the base is resolved, `overrides[symbol]` is spliced at `date`\n * (replaces the existing bar, or is appended in-order). When no override is\n * present but `date` isn't in the base bars, the last known value is carried\n * forward to `date` — this preserves the fallbackMissingQuotes behaviour the\n * old overlay exposed so leverage compounding / computations always have a\n * point at `date` to land on.\n */\n private async _resolveRawBars(\n symbol: string,\n from: string,\n date: string,\n overrides?: Record<string, number>,\n ): Promise<DailyBar[]> {\n const latestClosed = await this._storage.tradingDays.getLatestClosed();\n const closedForDate = latestClosed !== null && date <= latestClosed;\n\n let bars: DailyBar[];\n if (closedForDate) {\n try {\n bars = await this._market.fetchBars(symbol, from);\n } catch {\n bars = await this._readStoredBars(symbol, from);\n }\n } else {\n bars = await this._readStoredBars(symbol, from);\n }\n\n const override = overrides?.[symbol];\n const existingIdx = bars.findIndex((b) => b.date === date);\n\n if (override !== undefined) {\n if (existingIdx >= 0) {\n bars[existingIdx] = { date, value: override };\n } else {\n bars = [...bars, { date, value: override }].sort((a, b) => a.date.localeCompare(b.date));\n }\n } else if (existingIdx < 0 && bars.length > 0) {\n // Carry last known value forward to `date` (matches the overlay's\n // `fallbackMissingQuotes` behaviour for every consumer that used it).\n bars = [...bars, { date, value: bars[bars.length - 1]!.value }];\n }\n\n return bars;\n }\n\n /**\n * Resolve the single raw (unleveraged) value for `symbol` at `date`.\n * Returns the override directly when present; otherwise delegates to\n * `_resolveRawBars` with a one-day window and picks the matching bar.\n */\n private async _resolveRawBarAt(\n symbol: string,\n date: string,\n overrides?: Record<string, number>,\n ): Promise<number | null> {\n const override = overrides?.[symbol];\n if (override !== undefined) return override;\n const bars = await this._resolveRawBars(symbol, date, date, overrides);\n const hit = bars.find((b) => b.date === date);\n return hit?.value ?? null;\n }\n\n /**\n * Resolve raw (unleveraged) bars for a market symbol from storage. Maps:\n * - `^VIX` → the VIX indicator's stored series\n * - `^VIX3M` → the VIX3M indicator's stored series\n * - `DGS*` → the matching Treasury-tenor indicator's stored series\n * - anything else → the `Price` indicator for that ticker symbol with\n * `leverage = 1` (the raw contract that `MarketProvider.fetchBars` has).\n *\n * Returns `[]` when the resolved indicator has no stored bars yet.\n */\n private async _readStoredBars(symbol: string, from: string): Promise<DailyBar[]> {\n let identity: {\n type: string;\n tickerId: number | null;\n lookback: number;\n delay: number;\n unit: string | null;\n threshold: number | null;\n };\n if (symbol === '^VIX') {\n identity = { type: 'VIX', tickerId: null, lookback: 0, delay: 0, unit: null, threshold: null };\n } else if (symbol === '^VIX3M') {\n identity = { type: 'VIX3M', tickerId: null, lookback: 0, delay: 0, unit: null, threshold: null };\n } else if (FRED_SYMBOL_TO_TYPE[symbol]) {\n identity = {\n type: FRED_SYMBOL_TO_TYPE[symbol]!,\n tickerId: null,\n lookback: 0,\n delay: 0,\n unit: null,\n threshold: null,\n };\n } else {\n const { id: tickerId } = await this._storage.tickers.findOrCreate(symbol, 1);\n identity = { type: 'Price', tickerId, lookback: 0, delay: 0, unit: null, threshold: null };\n }\n const { id } = await this._storage.indicators.findOrCreate(identity);\n return this._storage.indicators.getSeries(id, { from });\n }\n\n // ── Public data access ─────────────────────────────────────────────\n\n async series(range?: DateRange): Promise<DailyBar[]> {\n if (this.type === 'Threshold') {\n return this._syntheticThresholdSeries(range);\n }\n await this._ensureFresh();\n if (this._cachedSeries && !range) return this._cachedSeries;\n const bars = await this._querySeriesFromDb(range);\n if (!range) this._cachedSeries = bars;\n return bars;\n }\n\n private async _syntheticThresholdSeries(range?: DateRange): Promise<DailyBar[]> {\n const v = this.threshold!;\n const dates = await this._storage.tradingDays.getRange(range);\n return dates.map((date) => ({ date, value: v }));\n }\n\n async value(date?: string): Promise<number | null> {\n await this._ensureFresh();\n const { id } = await this.resolve();\n return this._storage.indicators.getValue(id, date);\n }\n\n /**\n * Read-only preview of the indicator series with an in-memory bar at `date`\n * computed via `computeAt` with the supplied live-quote `overrides`. Does\n * NOT write to `indicators_series`. Safe to call before market close.\n *\n * @param date - Target trading day whose value is computed in-memory.\n * Must be in `tradingDays.getRange()`.\n * @param overrides - Raw (unleveraged) quotes keyed by market symbol.\n * Symbols omitted fall back to the last known value (see `_resolveRawBars`).\n * @param range - Optional filter applied to the returned bars.\n * @returns Stored historical bars plus (or with) today's in-memory value.\n */\n async previewSeries(date: string, overrides: Record<string, number>, range?: DateRange): Promise<DailyBar[]> {\n const tradingDays = await this._storage.tradingDays.getRange();\n if (!tradingDays.includes(date)) {\n throw new Error(`previewSeries: ${date} is not a trading day`);\n }\n\n let bars: DailyBar[];\n if (this.type === 'Threshold') {\n bars = await this._syntheticThresholdSeries();\n } else {\n bars = await this._querySeriesFromDb();\n }\n\n // Only splice a \"today\" bar when the indicator is publishable at `date`\n // — i.e. `delay === 0`. For delay > 0 the latest usable point is already\n // `latestClosed − delay`, which lives in `bars` as-is from storage.\n if (this.delay === 0) {\n const todayValue = await this.computeAt(date, overrides);\n if (todayValue !== null) {\n const idx = bars.findIndex((b) => b.date === date);\n if (idx >= 0) {\n bars[idx] = { date, value: todayValue };\n } else {\n bars = [...bars, { date, value: todayValue }].sort((a, b) => a.date.localeCompare(b.date));\n }\n }\n }\n\n if (range) {\n bars = bars.filter(\n (b) => (range.from === undefined || b.date >= range.from) && (range.to === undefined || b.date <= range.to),\n );\n }\n\n return bars;\n }\n}\n","import type { DailyBar } from '../handles/indicator';\n\ntype Comparison = '>' | '<' | '=';\n\nfunction computeBuffers(v2: number, tolerance: number, absolute: boolean): { upper: number; lower: number } {\n if (tolerance === 0) return { upper: v2, lower: v2 };\n if (absolute) return { upper: v2 + tolerance, lower: v2 - tolerance };\n return { upper: v2 * (1 + tolerance / 100), lower: v2 * (1 - tolerance / 100) };\n}\n\nfunction rawCompare(v1: number, v2: number, comparison: Comparison): number {\n switch (comparison) {\n case '>':\n return v1 > v2 ? 1 : 0;\n case '<':\n return v1 < v2 ? 1 : 0;\n case '=':\n return v1 === v2 ? 1 : 0;\n }\n}\n\nexport function evaluateSignal(\n series1: DailyBar[],\n series2: DailyBar[],\n comparison: Comparison,\n tolerance: number,\n absolute: boolean,\n previousValue?: number,\n): DailyBar[] {\n const s2Map = new Map<string, number>();\n for (const bar of series2) {\n s2Map.set(bar.date, bar.value);\n }\n\n const result: DailyBar[] = [];\n let prev = previousValue;\n\n for (const bar1 of series1) {\n const v2 = s2Map.get(bar1.date);\n if (v2 === undefined) continue;\n\n const v1 = bar1.value;\n const { upper, lower } = computeBuffers(v2, tolerance, absolute);\n\n let value: number;\n\n if (tolerance === 0) {\n value = rawCompare(v1, v2, comparison);\n } else if (comparison === '=') {\n value = v1 >= lower && v1 <= upper ? 1 : 0;\n } else if (prev === undefined) {\n value = rawCompare(v1, v2, comparison);\n } else if (comparison === '>') {\n if (prev === 1) {\n value = v1 < lower ? 0 : 1;\n } else {\n value = v1 > upper ? 1 : 0;\n }\n } else {\n // comparison === '<'\n if (prev === 1) {\n value = v1 > upper ? 0 : 1;\n } else {\n value = v1 < lower ? 1 : 0;\n }\n }\n\n result.push({ date: bar1.date, value });\n prev = value;\n }\n\n return result;\n}\n","// src/handles/signal.ts\nimport type { StorageProvider } from '../providers/storage';\nimport type { MarketProvider } from '../providers/market';\nimport type { Comparison } from '../providers/types';\nimport type { IndicatorHandle, DailyBar, DateRange } from './indicator';\nimport { evaluateSignal } from '../computations/signal';\n\nconst ABSOLUTE_TOLERANCE_TYPES = new Set([\n 'Return',\n 'Volatility',\n 'Drawdown',\n 'VIX',\n 'VIX3M',\n 'T3M',\n 'T6M',\n 'T1Y',\n 'T2Y',\n 'T3Y',\n 'T5Y',\n 'T7Y',\n 'T10Y',\n 'T20Y',\n 'T30Y',\n]);\n\nexport interface SignalIdentity {\n indicator1: IndicatorHandle;\n indicator2: IndicatorHandle;\n comparison: Comparison;\n tolerance: number;\n}\n\nexport class SignalHandle {\n readonly indicator1: IndicatorHandle;\n readonly indicator2: IndicatorHandle;\n readonly comparison: Comparison;\n readonly tolerance: number;\n\n private _storage: StorageProvider;\n private _resolvedId: number | null = null;\n private _resolving: Promise<{ id: number }> | null = null;\n\n private _cachedSeries: DailyBar[] | null = null;\n private _cachedAsOf: string | null = null;\n private _syncing: Promise<void> | null = null;\n\n // The `market` parameter is kept in the signature for API compatibility with\n // `new SignalHandle(storage, market, identity)` — signals no longer carry\n // their own market reference since `computeAt` delegates to the indicator\n // handles, which already hold one.\n constructor(storage: StorageProvider, _market: MarketProvider, identity: SignalIdentity) {\n this._storage = storage;\n this.indicator1 = identity.indicator1;\n this.indicator2 = identity.indicator2;\n this.comparison = identity.comparison;\n this.tolerance = identity.tolerance;\n }\n\n get id(): number {\n if (this._resolvedId == null)\n throw new Error('SignalHandle not yet resolved. Call resolve(), or access via an async method.');\n return this._resolvedId;\n }\n\n async resolve(): Promise<{ id: number }> {\n if (this._resolvedId != null) return { id: this._resolvedId };\n if (!this._resolving) this._resolving = this._doResolve();\n return this._resolving;\n }\n\n static fromResolved(\n storage: StorageProvider,\n market: MarketProvider,\n id: number,\n identity: SignalIdentity,\n ): SignalHandle {\n const handle = new SignalHandle(storage, market, identity);\n handle._resolvedId = id;\n return handle;\n }\n\n private async _doResolve(): Promise<{ id: number }> {\n const [ind1, ind2] = await Promise.all([this.indicator1.resolve(), this.indicator2.resolve()]);\n const result = await this._storage.signals.findOrCreate({\n indicatorId1: ind1.id,\n indicatorId2: ind2.id,\n comparison: this.comparison,\n tolerance: this.tolerance,\n });\n this._resolvedId = result.id;\n return result;\n }\n\n // ── Freshness & Sync ───────────────────────────────────────────────\n\n private async _getLatestClosedTradingDay(): Promise<string> {\n const date = await this._storage.tradingDays.getLatestClosed();\n if (!date) throw new Error('No closed trading days found');\n return date;\n }\n\n private async _getLatestSignalSeriesDate(signalId: number): Promise<string | null> {\n return this._storage.signals.getLatestSeriesDate(signalId);\n }\n\n private async _getLastSignalValue(signalId: number): Promise<number | null> {\n return this._storage.signals.getLastValue(signalId);\n }\n\n private async _ensureFresh(): Promise<void> {\n const { id } = await this.resolve();\n const latestClosed = await this._getLatestClosedTradingDay();\n\n if (this._cachedAsOf === latestClosed) return;\n\n const latestSeries = await this._getLatestSignalSeriesDate(id);\n\n if (latestSeries === latestClosed) {\n this._cachedSeries = null;\n this._cachedAsOf = latestClosed;\n return;\n }\n\n // Determine whether the single-bar fast path applies so we know whether to\n // pre-sync the indicator series. The fast path uses `computeAt` and handles\n // its own freshness; the cold/multi-bar path requires indicators to be\n // synced to storage first.\n const isFastPath = await this._isSingleBarFastPath(latestSeries ?? undefined, latestClosed);\n if (!isFastPath) {\n await Promise.all([this.indicator1.series(), this.indicator2.series()]);\n }\n\n if (!this._syncing) {\n this._syncing = this._sync(latestSeries ?? undefined, latestClosed)\n .catch((err) => {\n console.warn('[sdk] signal sync failed, using stored data:', err);\n })\n .finally(() => {\n this._syncing = null;\n });\n }\n await this._syncing;\n\n this._cachedSeries = null;\n this._cachedAsOf = latestClosed;\n }\n\n private async _isSingleBarFastPath(fromDate: string | undefined, latestClosed: string): Promise<boolean> {\n if (!fromDate) return false;\n const tradingDays = await this._storage.tradingDays.getRange();\n const fromIdx = tradingDays.indexOf(fromDate);\n const closedIdx = tradingDays.indexOf(latestClosed);\n return fromIdx >= 0 && closedIdx === fromIdx + 1;\n }\n\n private async _sync(fromDate: string | undefined, latestClosed: string): Promise<void> {\n const { id } = await this.resolve();\n\n const absolute = ABSOLUTE_TOLERANCE_TYPES.has(this.indicator1.type);\n\n // Single-bar fast path: we have a checkpoint (fromDate), and the next bar to\n // produce is the trading day immediately after fromDate.\n if (fromDate) {\n const tradingDays = await this._storage.tradingDays.getRange();\n const fromIdx = tradingDays.indexOf(fromDate);\n const closedIdx = tradingDays.indexOf(latestClosed);\n if (fromIdx >= 0 && closedIdx === fromIdx + 1) {\n const newDate = tradingDays[closedIdx]!;\n const [v1, v2] = await Promise.all([\n this.indicator1.computeAt(newDate, undefined),\n this.indicator2.computeAt(newDate, undefined),\n ]);\n if (v1 === null || v2 === null) return;\n const prev = (await this._getLastSignalValue(id)) ?? undefined;\n const value = this._evaluateOneBar(v1, v2, absolute, prev);\n await this._upsertSeries([{ date: newDate, value }]);\n return;\n }\n }\n\n // Existing multi-bar / cold path.\n const range = fromDate ? { from: fromDate } : undefined;\n const [series1, series2] = await Promise.all([this.indicator1.series(range), this.indicator2.series(range)]);\n const previousValue = fromDate ? ((await this._getLastSignalValue(id)) ?? undefined) : undefined;\n const signalBars = evaluateSignal(series1, series2, this.comparison, this.tolerance, absolute, previousValue);\n const bars = signalBars.filter((b) => b.date <= latestClosed);\n if (bars.length > 0) await this._upsertSeries(bars);\n }\n\n private _evaluateOneBar(v1: number, v2: number, absolute: boolean, prev: number | undefined): number {\n if (this.tolerance === 0) {\n switch (this.comparison) {\n case '>':\n return v1 > v2 ? 1 : 0;\n case '<':\n return v1 < v2 ? 1 : 0;\n case '=':\n return v1 === v2 ? 1 : 0;\n }\n }\n const upper = absolute ? v2 + this.tolerance : v2 * (1 + this.tolerance / 100);\n const lower = absolute ? v2 - this.tolerance : v2 * (1 - this.tolerance / 100);\n if (this.comparison === '=') return v1 >= lower && v1 <= upper ? 1 : 0;\n if (prev === undefined) {\n return this.comparison === '>' ? (v1 > v2 ? 1 : 0) : v1 < v2 ? 1 : 0;\n }\n if (this.comparison === '>') {\n return prev === 1 ? (v1 < lower ? 0 : 1) : v1 > upper ? 1 : 0;\n }\n return prev === 1 ? (v1 > upper ? 0 : 1) : v1 < lower ? 1 : 0;\n }\n\n private async _upsertSeries(bars: DailyBar[]): Promise<void> {\n const { id } = await this.resolve();\n await this._storage.signals.writeSeries(id, bars);\n }\n\n private async _querySeriesFromDb(range?: DateRange): Promise<DailyBar[]> {\n const { id } = await this.resolve();\n return this._storage.signals.getSeries(id, range);\n }\n\n /**\n * Compute the signal's boolean value at `date` without persisting anything,\n * with optional live-quote `overrides` that are routed through each\n * indicator's `computeAt`. Returns null if either indicator cannot produce\n * a value at `date`.\n *\n * @param prevBool - The signal's boolean value at the bar immediately\n * preceding `date`, used for hysteresis when `tolerance > 0`. If not\n * provided, falls back to `storage.signals.getLastValue` (suitable for\n * standalone callers). On the preview path `_evaluate` passes this from\n * the in-memory `dateMap` so we never read stale storage.\n */\n async computeAt(\n date: string,\n overrides?: Record<string, number>,\n prevBool?: boolean | null,\n ): Promise<boolean | null> {\n const [v1, v2] = await Promise.all([\n this.indicator1.computeAt(date, overrides),\n this.indicator2.computeAt(date, overrides),\n ]);\n if (v1 === null || v2 === null) return null;\n\n const absolute = ABSOLUTE_TOLERANCE_TYPES.has(this.indicator1.type);\n\n // Replicate the evaluateSignal single-bar logic inline (no hysteresis needed\n // for a single-point preview; we use the last historical value as \"prev\").\n if (this.tolerance === 0) {\n switch (this.comparison) {\n case '>':\n return v1 > v2;\n case '<':\n return v1 < v2;\n case '=':\n return v1 === v2;\n }\n }\n\n const tolerance = this.tolerance;\n const upper = absolute ? v2 + tolerance : v2 * (1 + tolerance / 100);\n const lower = absolute ? v2 - tolerance : v2 * (1 - tolerance / 100);\n\n if (this.comparison === '=') {\n return v1 >= lower && v1 <= upper;\n }\n // For '>' and '<' with tolerance, we need hysteresis (prev state).\n // Use the in-memory prevBool if provided (preview path); otherwise fall\n // back to storage (standalone callers / write path).\n let resolvedPrevBool: boolean;\n if (prevBool !== undefined && prevBool !== null) {\n resolvedPrevBool = prevBool;\n } else {\n const prev = await this._storage.signals.getLastValue(this.id);\n resolvedPrevBool = prev === 1;\n }\n if (this.comparison === '>') {\n return resolvedPrevBool ? v1 >= lower : v1 > upper;\n }\n // '<'\n return resolvedPrevBool ? v1 <= upper : v1 < lower;\n }\n\n // ── Public data access ─────────────────────────────────────────────\n\n async series(range?: DateRange): Promise<DailyBar[]> {\n await this._ensureFresh();\n if (this._cachedSeries && !range) return this._cachedSeries;\n const bars = await this._querySeriesFromDb(range);\n if (!range) this._cachedSeries = bars;\n return bars;\n }\n\n async value(date?: string): Promise<number | null> {\n await this._ensureFresh();\n if (date) {\n const series = await this._querySeriesFromDb({ from: date, to: date });\n return series.length > 0 ? series[0]!.value : null;\n }\n const { id } = await this.resolve();\n return this._storage.signals.getLastValue(id);\n }\n\n /**\n * Read-only preview of the signal series with an in-memory bar at `date`\n * computed via `computeAt` with the supplied live-quote `overrides`. Does\n * NOT write to `signals_series`.\n *\n * @param date - Target trading day whose boolean is computed in-memory.\n * @param overrides - Raw (unleveraged) quotes keyed by market symbol.\n * @param range - Optional filter applied to the returned bars.\n */\n async previewSeries(date: string, overrides: Record<string, number>, range?: DateRange): Promise<DailyBar[]> {\n const tradingDays = await this._storage.tradingDays.getRange();\n if (!tradingDays.includes(date)) {\n throw new Error(`previewSeries: ${date} is not a trading day`);\n }\n\n let bars = await this._querySeriesFromDb();\n\n // Derive yesterday's boolean from the in-memory dateMap for hysteresis,\n // mirroring StrategyHandle._evaluate's preview path.\n const dateMap = new Map<string, boolean>();\n for (const bar of bars) dateMap.set(bar.date, bar.value === 1);\n\n const limitIdx = tradingDays.indexOf(date);\n const prevDate = limitIdx > 0 ? tradingDays[limitIdx - 1] : undefined;\n const prevBool = prevDate !== undefined ? (dateMap.get(prevDate) ?? null) : null;\n\n const todayBool = await this.computeAt(date, overrides, prevBool);\n if (todayBool !== null) {\n const numeric = todayBool ? 1 : 0;\n const idx = bars.findIndex((b) => b.date === date);\n if (idx >= 0) {\n bars[idx] = { date, value: numeric };\n } else {\n bars = [...bars, { date, value: numeric }].sort((a, b) => a.date.localeCompare(b.date));\n }\n }\n\n if (range) {\n bars = bars.filter(\n (b) => (range.from === undefined || b.date >= range.from) && (range.to === undefined || b.date <= range.to),\n );\n }\n\n return bars;\n }\n}\n","import type { StorageProvider } from '../providers/storage';\nimport { TickerHandle } from './ticker';\n\nexport class AllocationHandle {\n readonly holdings: [TickerHandle, number][];\n\n private _storage: StorageProvider;\n private _resolvedId: number | null = null;\n private _resolving: Promise<{ id: number }> | null = null;\n\n constructor(storage: StorageProvider, holdings: [TickerHandle, number][]) {\n const total = holdings.reduce((sum, [, weight]) => sum + weight, 0);\n if (Math.abs(total - 1) > 1e-9) {\n throw new Error(`Allocation weights must sum to 1, got ${total}`);\n }\n this._storage = storage;\n this.holdings = holdings;\n }\n\n get id(): number {\n if (this._resolvedId == null)\n throw new Error('AllocationHandle not yet resolved. Call resolve(), or access via an async method.');\n return this._resolvedId;\n }\n\n async resolve(): Promise<{ id: number }> {\n if (this._resolvedId != null) return { id: this._resolvedId };\n if (!this._resolving) this._resolving = this._doResolve();\n return this._resolving;\n }\n\n static fromResolved(storage: StorageProvider, id: number, holdings: [TickerHandle, number][]): AllocationHandle {\n const handle = new AllocationHandle(storage, holdings);\n handle._resolvedId = id;\n return handle;\n }\n\n toJSON(): Array<{ symbol: string; leverage: number; weight: number }> {\n return this.holdings\n .map(([ticker, weight]) => ({ symbol: ticker.symbol, leverage: ticker.leverage, weight }))\n .sort((a, b) => a.symbol.localeCompare(b.symbol) || a.leverage - b.leverage);\n }\n\n private async _doResolve(): Promise<{ id: number }> {\n await Promise.all(this.holdings.map(([ticker]) => ticker.resolve()));\n\n const holdingsJson: Record<string, number> = {};\n for (const [ticker, weight] of this.holdings) {\n const key = ticker.leverage !== 1 ? `${ticker.symbol}?L=${ticker.leverage}` : ticker.symbol;\n holdingsJson[key] = weight;\n }\n\n const result = await this._storage.allocations.findOrCreate(holdingsJson);\n this._resolvedId = result.id;\n return result;\n }\n}\n","import { customAlphabet } from 'nanoid';\nimport type { StorageProvider } from '../providers/storage';\nimport type { MarketProvider } from '../providers/market';\nimport type { TradingFreq, StrategySeriesEntry } from '../providers/types';\nimport { SignalHandle } from './signal';\nimport { AllocationHandle } from './allocation';\nimport { TickerHandle } from './ticker';\nimport { IndicatorHandle } from './indicator';\nimport type { DateRange } from './indicator';\nimport { evaluateStrategy, computeRebalanceDates } from '../computations/strategy';\nimport { runSimulation } from '../backtest/simulate';\nimport { SimulationHandle } from '../backtest/types';\nimport type {\n SimulateOptions,\n FinalState,\n LiveEvaluator,\n StrategyLiveState,\n LiveRuleState,\n LiveSignalState,\n} from '../backtest/types';\n\nconst nanoid = customAlphabet('0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 21);\n\nexport interface StrategyRule {\n when?: SignalHandle[];\n hold: AllocationHandle;\n}\n\nexport interface StrategyBar {\n date: string;\n allocation: AllocationHandle;\n}\n\nexport interface StrategyOptions {\n name: string;\n freq?: TradingFreq;\n offset?: number;\n rules: StrategyRule[];\n}\n\nexport class StrategyHandle {\n private _linkId: string | null;\n private _name: string | null;\n private _freq: TradingFreq;\n private _offset: number;\n private _rules: StrategyRule[];\n\n private _storage: StorageProvider;\n private _market: MarketProvider;\n private _resolvedId: number | null = null;\n private _resolvedLinkId: string | null = null;\n private _resolving: Promise<{ id: number }> | null = null;\n private _allocationMap: Map<number, AllocationHandle> = new Map();\n\n private _cache: StrategyBar[] | null = null;\n private _cachedAsOf: string | null = null;\n private _syncing: Promise<void> | null = null;\n\n constructor(storage: StorageProvider, market: MarketProvider, optionsOrLinkId: StrategyOptions | string) {\n this._storage = storage;\n this._market = market;\n\n if (typeof optionsOrLinkId === 'string') {\n this._linkId = optionsOrLinkId;\n this._name = null;\n this._freq = 'Daily';\n this._offset = 0;\n this._rules = [];\n } else {\n const opts = optionsOrLinkId;\n if (opts.rules.length === 0) {\n throw new Error('Strategy must have at least one rule');\n }\n const lastRule = opts.rules[opts.rules.length - 1]!;\n if (lastRule.when && lastRule.when.length > 0) {\n throw new Error('Last rule must be a fallback (no when clause)');\n }\n for (let i = 0; i < opts.rules.length - 1; i++) {\n const rule = opts.rules[i]!;\n if (rule.when !== undefined && rule.when.length === 0) {\n throw new Error(\n `Rule ${i} has an empty when clause and will match unconditionally, making subsequent rules unreachable`,\n );\n }\n }\n this._linkId = null;\n this._name = opts.name;\n this._freq = opts.freq ?? 'Daily';\n this._offset = opts.offset ?? 0;\n this._rules = opts.rules;\n }\n }\n\n get id(): number {\n if (this._resolvedId == null) throw new Error('StrategyHandle not yet resolved. Call resolve() first.');\n return this._resolvedId;\n }\n\n get link(): string {\n if (this._resolvedLinkId == null) throw new Error('StrategyHandle not yet resolved. Call resolve() first.');\n return this._resolvedLinkId;\n }\n\n get name(): string | null {\n return this._name;\n }\n\n get freq(): TradingFreq {\n return this._freq;\n }\n\n get offset(): number {\n return this._offset;\n }\n\n get rules(): StrategyRule[] {\n return this._rules;\n }\n\n marketSymbols(): string[] {\n const set = new Set<string>();\n for (const rule of this._rules) {\n for (const [ticker] of rule.hold.holdings) {\n if (ticker.symbol !== 'CASHX') set.add(ticker.symbol);\n }\n for (const signal of rule.when ?? []) {\n for (const ind of [signal.indicator1, signal.indicator2]) {\n if (ind.ticker !== null && ind.ticker.symbol !== 'CASHX') set.add(ind.ticker.symbol);\n if (ind.type === 'VIX') set.add('^VIX');\n if (ind.type === 'VIX3M') set.add('^VIX3M');\n }\n }\n }\n return Array.from(set).sort();\n }\n\n async resolve(): Promise<{ id: number }> {\n if (this._resolvedId != null) return { id: this._resolvedId };\n if (!this._resolving) {\n this._resolving =\n this._linkId !== null && this._name === null ? this._doResolveReference() : this._doResolveCreate();\n }\n return this._resolving;\n }\n\n private async _doResolveCreate(): Promise<{ id: number }> {\n const allSignals = new Set<SignalHandle>();\n const allAllocations = new Set<AllocationHandle>();\n for (const rule of this._rules) {\n if (rule.when) rule.when.forEach((s) => allSignals.add(s));\n allAllocations.add(rule.hold);\n }\n\n await Promise.all([\n ...Array.from(allSignals).map((s) => s.resolve()),\n ...Array.from(allAllocations).map((a) => a.resolve()),\n ]);\n\n const linkId = nanoid();\n const result = await this._storage.strategies.create({\n linkId,\n name: this._name!,\n freq: this._freq,\n offset: this._offset,\n rules: this._rules.map((rule) => ({\n signalIds: (rule.when ?? []).map((s) => s.id),\n allocationId: rule.hold.id,\n })),\n });\n\n this._resolvedId = result.id;\n this._resolvedLinkId = linkId;\n\n for (const rule of this._rules) {\n this._allocationMap.set(rule.hold.id, rule.hold);\n }\n\n return result;\n }\n\n private async _doResolveReference(): Promise<{ id: number }> {\n const ref = await this._storage.strategies.resolveReference(this._linkId!);\n this._resolvedId = ref.id;\n this._resolvedLinkId = this._linkId!;\n this._name = ref.name;\n this._freq = ref.freq;\n this._offset = ref.offset;\n\n // Build handles bottom-up from reference data\n const tickerMap = new Map<number, TickerHandle>();\n for (const t of ref.rules.tickers) {\n tickerMap.set(t.id, TickerHandle.fromResolved(this._storage, t.id, t.symbol, t.leverage));\n }\n\n const indicatorMap = new Map<number, IndicatorHandle>();\n for (const ind of ref.rules.indicators) {\n const ticker = ind.tickerId ? (tickerMap.get(ind.tickerId) ?? null) : null;\n indicatorMap.set(\n ind.id,\n IndicatorHandle.fromResolved(this._storage, this._market, ind.id, {\n type: ind.type,\n ticker,\n lookback: ind.lookback,\n delay: ind.delay,\n unit: ind.unit,\n threshold: ind.threshold,\n }),\n );\n }\n\n const signalMap = new Map<number, SignalHandle>();\n for (const sig of ref.rules.signals) {\n signalMap.set(\n sig.id,\n SignalHandle.fromResolved(this._storage, this._market, sig.id, {\n indicator1: indicatorMap.get(sig.indicatorId1)!,\n indicator2: indicatorMap.get(sig.indicatorId2)!,\n comparison: sig.comparison,\n tolerance: sig.tolerance,\n }),\n );\n }\n\n const allocationHandleMap = new Map<number, AllocationHandle>();\n for (const alloc of ref.rules.allocations) {\n const holdings: [TickerHandle, number][] = Object.entries(alloc.holdings).map(([key, weight]) => {\n const match = key.match(/^(.+)\\?L=(.+)$/);\n const symbol = match ? match[1]! : key;\n const leverage = match ? Number(match[2]) : 1;\n return [new TickerHandle(this._storage, symbol, leverage), weight];\n });\n const handle = AllocationHandle.fromResolved(this._storage, alloc.id, holdings);\n allocationHandleMap.set(alloc.id, handle);\n this._allocationMap.set(alloc.id, handle);\n }\n\n // Reconstruct rules\n this._rules = ref.rules.definition.map((rule) => ({\n when: rule.signalIds && rule.signalIds.length > 0 ? rule.signalIds.map((id) => signalMap.get(id)!) : undefined,\n hold: allocationHandleMap.get(rule.allocationId)!,\n }));\n\n return { id: ref.id };\n }\n\n private async _getLatestClosedTradingDay(): Promise<string> {\n const date = await this._storage.tradingDays.getLatestClosed();\n if (!date) throw new Error('No closed trading days found');\n return date;\n }\n\n private async _ensureFresh(): Promise<void> {\n await this.resolve();\n const latestClosed = await this._getLatestClosedTradingDay();\n\n // In-memory memoization: skip work if this handle already synced against\n // the current latestClosed. Still runs once per handle per trading day.\n if (this._cachedAsOf === latestClosed) return;\n\n // Always run _sync — even when the stored series already covers\n // latestClosed. _evaluate now re-derives [latestClosed, latestClosed] in\n // that case so a previously-written row is re-checked against the current\n // signals_series; if upstream signals have been recomputed since the\n // original write, writeSeries upserts the correction. Without this, once\n // a day is written the SDK never revisits it and drift accumulates.\n if (!this._syncing) {\n this._syncing = this._sync(latestClosed)\n .catch((err) => {\n console.warn('[sdk] strategy sync failed, using stored data:', err);\n })\n .finally(() => {\n this._syncing = null;\n });\n }\n await this._syncing;\n\n this._cache = null;\n this._cachedAsOf = latestClosed;\n }\n\n private async _sync(latestClosed: string): Promise<void> {\n const { id } = await this.resolve();\n const { entries } = await this._evaluate(latestClosed);\n if (entries.length > 0) {\n await this._storage.strategies.writeSeries(id, entries);\n }\n }\n\n /**\n * Pure evaluate — runs the same pipeline as _sync but returns the computed\n * evaluation instead of persisting. Used by both _sync (post-close write\n * path) and the public preview methods (pre-close read-only path).\n *\n * When `overrides` is `undefined` we take the write path — syncing signals\n * through storage as normal. When `overrides` is provided (even an empty\n * map) we take the read-only preview path: historical signal bars come\n * straight from storage, today's bar is computed in-memory via\n * `signal.computeAt(date, overrides, prevBool)`, and nothing is written.\n *\n * Incremental path: when a strategy checkpoint exists (`getLatestSeriesDate`\n * returns non-null), only the window (lastDate, limitDate] is processed.\n * The current allocation is carried forward from `getLatestAllocationId`.\n * Bootstrap: when no checkpoint exists, falls back to `_evaluateCold` which\n * runs the full-history evaluation.\n */\n private async _evaluate(\n limitDate: string,\n overrides?: Record<string, number>,\n ): Promise<{ allocations: AllocationHandle[]; entries: StrategySeriesEntry[] }> {\n const { id } = await this.resolve();\n const lastDate = await this._storage.strategies.getLatestSeriesDate(id);\n\n const tradingDays = await this._storage.tradingDays.getRange();\n const limitIdx = tradingDays.indexOf(limitDate);\n\n // Build the allocation index map exactly once per call.\n const allocations: AllocationHandle[] = [];\n const allocIndexMap = new Map<number, number>();\n const rulesInput = this._rules.map((rule) => {\n let allocIdx = allocIndexMap.get(rule.hold.id);\n if (allocIdx === undefined) {\n allocIdx = allocations.length;\n allocations.push(rule.hold);\n allocIndexMap.set(rule.hold.id, allocIdx);\n }\n return {\n signalIds: (rule.when ?? []).map((s) => s.id),\n allocationIndex: allocIdx,\n };\n });\n\n // Bootstrap: no checkpoint yet → fall back to full history compute.\n if (lastDate === null) {\n return this._evaluateCold(limitDate, overrides, rulesInput, allocations, tradingDays);\n }\n\n const lastAllocId = await this._storage.strategies.getLatestAllocationId(id);\n\n // Incremental window: (lastDate, limitDate], bounded by tradingDays.\n const incrementalStartIdx = tradingDays.indexOf(lastDate) + 1;\n const incrementalDays = tradingDays.slice(incrementalStartIdx, limitIdx + 1);\n\n // Latest-day refresh: when the stored series already covers limitDate,\n // re-derive that one day from current signals and allow the caller to\n // upsert if the rule-picked allocation has changed since the original\n // write. Covers both the preview path (overrides provided — today's bar\n // computed in-memory via signal.computeAt) and the post-close write path\n // (overrides undefined — today's bar read from current signals_series).\n // Guarded to `limitDate === lastDate` so we only re-evaluate the latest\n // written day — re-evaluating a strictly-past day would mis-seed `current`\n // from the latest stored allocation instead of the correct day-before\n // allocation.\n const isLatestRefresh = incrementalDays.length === 0 && limitDate === lastDate;\n const newDays = isLatestRefresh ? [limitDate] : incrementalDays;\n const startIdx = isLatestRefresh ? limitIdx : incrementalStartIdx;\n if (newDays.length === 0) return { allocations, entries: [] };\n\n // Build signal bar maps only for the new window.\n const allSignals = new Set<SignalHandle>();\n for (const rule of this._rules) if (rule.when) rule.when.forEach((s) => allSignals.add(s));\n const signalSeries = new Map<number, Map<string, boolean>>();\n await Promise.all(\n Array.from(allSignals).map(async (signal) => {\n const bars =\n overrides === undefined\n ? await signal.series({ from: newDays[0]!, to: limitDate })\n : await this._storage.signals.getSeries(signal.id, { from: newDays[0]!, to: limitDate });\n const dateMap = new Map<string, boolean>();\n for (const bar of bars) dateMap.set(bar.date, bar.value === 1);\n if (overrides !== undefined) {\n const prevDateIdx = startIdx - 1 >= 0 ? tradingDays[startIdx - 1] : undefined;\n const prevBool = prevDateIdx !== undefined ? (await signal.value(prevDateIdx)) === 1 : null;\n const todayValue = await signal.computeAt(limitDate, overrides, prevBool);\n if (todayValue !== null) dateMap.set(limitDate, todayValue);\n }\n signalSeries.set(signal.id, dateMap);\n }),\n );\n\n const rebalanceDates = computeRebalanceDates(tradingDays, this._freq, this._offset);\n\n // Walk new days, carrying forward `current` from the checkpoint allocation.\n const entries: StrategySeriesEntry[] = [];\n let current: number | undefined = lastAllocId !== null ? (allocIndexMap.get(lastAllocId) ?? undefined) : undefined;\n\n for (const date of newDays) {\n if (rebalanceDates.has(date)) {\n for (const rule of rulesInput) {\n if (rule.signalIds.length === 0) {\n current = rule.allocationIndex;\n break;\n }\n const allTrue = rule.signalIds.every((sid) => signalSeries.get(sid)?.get(date) ?? false);\n if (allTrue) {\n current = rule.allocationIndex;\n break;\n }\n }\n }\n if (current !== undefined) {\n entries.push({ date, allocationId: allocations[current]!.id });\n }\n }\n\n return { allocations, entries };\n }\n\n // Renamed body of the old _evaluate — used only for first-ever evaluate (bootstrap).\n private async _evaluateCold(\n limitDate: string,\n overrides: Record<string, number> | undefined,\n rulesInput: { signalIds: number[]; allocationIndex: number }[],\n allocations: AllocationHandle[],\n tradingDays: string[],\n ): Promise<{ allocations: AllocationHandle[]; entries: StrategySeriesEntry[] }> {\n const allSignals = new Set<SignalHandle>();\n for (const rule of this._rules) if (rule.when) rule.when.forEach((s) => allSignals.add(s));\n const signalSeries = new Map<number, Map<string, boolean>>();\n\n if (overrides === undefined) {\n // Normal (post-close) path: sync signals through storage, may write.\n await Promise.all(\n Array.from(allSignals).map(async (signal) => {\n const bars = await signal.series();\n const dateMap = new Map<string, boolean>();\n for (const bar of bars) dateMap.set(bar.date, bar.value === 1);\n signalSeries.set(signal.id, dateMap);\n }),\n );\n } else {\n // Preview (pre-close, no-write) path: read historical from storage, then\n // compute today's signal value in-memory via computeAt. No writes anywhere.\n //\n // Find the trading day immediately before limitDate so we can pass its\n // in-memory boolean as prevBool to computeAt (hysteresis).\n const limitIdx = tradingDays.indexOf(limitDate);\n const prevDate = limitIdx > 0 ? tradingDays[limitIdx - 1] : undefined;\n\n await Promise.all(\n Array.from(allSignals).map(async (signal) => {\n // Read all historical signal bars from storage (pure read).\n const historicalBars = await this._storage.signals.getSeries(signal.id);\n const dateMap = new Map<string, boolean>();\n for (const bar of historicalBars) dateMap.set(bar.date, bar.value === 1);\n\n // Look up yesterday's boolean from the in-memory map (avoids stale\n // storage read for hysteresis on the preview path).\n const prevBool = prevDate !== undefined ? (dateMap.get(prevDate) ?? null) : null;\n\n const todayValue = await signal.computeAt(limitDate, overrides, prevBool);\n if (todayValue !== null) {\n dateMap.set(limitDate, todayValue);\n }\n\n signalSeries.set(signal.id, dateMap);\n }),\n );\n }\n\n const rebalanceDates = computeRebalanceDates(tradingDays, this._freq, this._offset);\n const evalResult = evaluateStrategy(signalSeries, rulesInput, rebalanceDates, tradingDays);\n const entries: StrategySeriesEntry[] = Array.from(evalResult.entries())\n .filter(([date]) => date <= limitDate)\n .map(([date, allocIdx]) => ({ date, allocationId: allocations[allocIdx]!.id }));\n return { allocations, entries };\n }\n\n private async _querySeriesFromDb(range?: DateRange): Promise<StrategyBar[]> {\n const { id } = await this.resolve();\n const entries = await this._storage.strategies.getSeries(id, range);\n return entries.map((e) => ({\n date: e.date,\n allocation: this._allocationMap.get(e.allocationId)!,\n }));\n }\n\n async series(range?: DateRange): Promise<StrategyBar[]> {\n await this._ensureFresh();\n if (this._cache && !range) return this._cache;\n const bars = await this._querySeriesFromDb(range);\n if (!range) this._cache = bars;\n return bars;\n }\n\n async value(date?: string): Promise<AllocationHandle | null> {\n await this._ensureFresh();\n const bars = date ? await this._querySeriesFromDb({ from: date, to: date }) : await this._querySeriesFromDb();\n if (bars.length === 0) return null;\n return date ? bars[0]!.allocation : bars[bars.length - 1]!.allocation;\n }\n\n async simulate(options: SimulateOptions): Promise<SimulationHandle> {\n const bars = await this.series({ from: options.from, to: options.to });\n if (bars.length === 0) {\n return new SimulationHandle([], [], options.portfolio);\n }\n\n const prices = await this._fetchPricesForTickers(bars, options.from, options.to);\n const tradingDays = bars.map((b) => b.date);\n const rebalanceDates = computeRebalanceDates(tradingDays, this._freq, this._offset);\n\n // Force day 1 rebalance so existing positions align to strategy\n rebalanceDates.add(bars[0]!.date);\n\n const result = runSimulation(bars, prices, rebalanceDates, options.portfolio);\n\n // Build finalState for live push support\n const lastBar = bars[bars.length - 1]!;\n const lastDate = lastBar.date;\n const lastAllocation = lastBar.allocation;\n\n // leveragedPrices: keyed as \"symbol:leverage\", values are the leveraged prices from _fetchPricesForTickers\n const leveragedPrices: Record<string, number> = {};\n for (const [ticker, _weight] of lastAllocation.holdings) {\n if (ticker.symbol === 'CASHX') continue;\n const key = `${ticker.symbol}:${ticker.leverage}`;\n const price = prices[key]?.[lastDate];\n if (price != null) leveragedPrices[key] = price;\n }\n\n // closePrices: raw (unleveraged) close prices for computing real returns\n const closePrices: Record<string, number> = {};\n await this._fetchRawClosePrices(bars, lastDate, closePrices);\n\n const finalState: FinalState = {\n portfolio: result.finalPortfolio,\n allocation: lastAllocation,\n closePrices,\n leveragedPrices,\n };\n\n const liveEvaluator: LiveEvaluator = {\n previewLiveState: (date, overrides) => this.previewLiveState(date, overrides),\n };\n return new SimulationHandle(result.series, result.trades, options.portfolio, finalState, liveEvaluator);\n }\n\n /**\n * Preview the allocation this strategy would produce for `date` if today\n * closed at the provided raw quote prices. Does NOT write to strategies_series,\n * signals_series, or indicators_series. Safe to call before market close.\n *\n * @param date - The trading day to preview (must be in tradingDays.getRange()).\n * @param overrides - Raw (unleveraged) live prices keyed by market symbol.\n * Symbols absent from this map fall back to the last stored value\n * (see `IndicatorHandle._resolveRawBars`).\n * @returns The AllocationHandle for `date`, or null if the strategy has no\n * evaluable entry for that date.\n */\n async previewAllocation(date: string, overrides: Record<string, number>): Promise<AllocationHandle | null> {\n await this.resolve();\n\n const tradingDays = await this._storage.tradingDays.getRange();\n if (!tradingDays.includes(date)) {\n throw new Error(`previewAllocation: ${date} is not a trading day`);\n }\n\n const { allocations, entries } = await this._evaluate(date, overrides);\n\n const target = entries.find((e) => e.date === date);\n if (!target) return null;\n\n const alloc = allocations.find((a) => a.id === target.allocationId);\n return alloc ?? this._allocationMap.get(target.allocationId) ?? null;\n }\n\n /**\n * Read-only preview of the strategy's allocation series including `date`.\n * Returns stored historical allocations plus an in-memory bar at `date`\n * computed via the same overrides-based preview path as `previewAllocation`.\n *\n * @param date - Target trading day to splice in-memory.\n * @param overrides - Raw (unleveraged) quotes keyed by market symbol.\n * @param range - Optional filter applied to the returned bars.\n */\n async previewSeries(date: string, overrides: Record<string, number>, range?: DateRange): Promise<StrategyBar[]> {\n await this.resolve();\n\n const tradingDays = await this._storage.tradingDays.getRange();\n if (!tradingDays.includes(date)) {\n throw new Error(`previewSeries: ${date} is not a trading day`);\n }\n\n const { allocations, entries } = await this._evaluate(date, overrides);\n\n const allocById = new Map<number, AllocationHandle>();\n for (const a of allocations) allocById.set(a.id, a);\n for (const [id, a] of this._allocationMap) if (!allocById.has(id)) allocById.set(id, a);\n\n // When _evaluate returned only incremental entries (checkpoint path), fetch\n // stored history from the DB and prepend it so the caller gets the full series.\n const { id } = await this.resolve();\n const lastDate = await this._storage.strategies.getLatestSeriesDate(id);\n let storedBars: StrategyBar[] = [];\n if (lastDate !== null && entries.length > 0 && entries[0]!.date > (tradingDays[0] ?? '')) {\n // There may be stored history before the first entry — fetch it.\n const storedEntries = await this._storage.strategies.getSeries(id, { to: lastDate });\n storedBars = storedEntries.map((e) => ({\n date: e.date,\n allocation: allocById.get(e.allocationId) ?? this._allocationMap.get(e.allocationId)!,\n }));\n } else if (lastDate !== null && entries.length === 0) {\n // No new entries (e.g. limitDate === lastDate): return all stored history.\n const storedEntries = await this._storage.strategies.getSeries(id);\n storedBars = storedEntries.map((e) => ({\n date: e.date,\n allocation: allocById.get(e.allocationId) ?? this._allocationMap.get(e.allocationId)!,\n }));\n }\n\n const newBars: StrategyBar[] = entries.map((e) => ({\n date: e.date,\n allocation: allocById.get(e.allocationId)!,\n }));\n\n // Merge: stored history (excluding any dates already in newBars) + newBars.\n const newDates = new Set(newBars.map((b) => b.date));\n let bars: StrategyBar[] = [...storedBars.filter((b) => !newDates.has(b.date)), ...newBars];\n bars.sort((a, b) => a.date.localeCompare(b.date));\n\n if (range) {\n bars = bars.filter(\n (b) => (range.from === undefined || b.date >= range.from) && (range.to === undefined || b.date <= range.to),\n );\n }\n\n return bars;\n }\n\n /**\n * Full live strategy view at `date` under live-quote `overrides`: the active\n * allocation, the index of the rule that fired (or fallback), and per-rule\n * per-signal indicator values + truth. Computed entirely through the\n * overrides preview path — no writes to any `*_series` tables.\n *\n * Threshold indicators have their date suppressed (`null`) since their\n * synthetic series runs over every trading day in storage including future\n * dates and would report a far-future date for the last bar.\n */\n async previewLiveState(date: string, overrides: Record<string, number>): Promise<StrategyLiveState> {\n await this.resolve();\n\n const tradingDays = await this._storage.tradingDays.getRange();\n if (!tradingDays.includes(date)) {\n throw new Error(`previewLiveState: ${date} is not a trading day`);\n }\n\n const [{ allocations, entries }, rules] = await Promise.all([\n this._evaluate(date, overrides),\n Promise.all(\n this._rules.map(async (rule): Promise<LiveRuleState> => {\n const signalHandles = rule.when ?? [];\n const signals: LiveSignalState[] = await Promise.all(\n signalHandles.map(async (sig) => {\n const [i1Series, i2Series, sigSeries] = await Promise.all([\n sig.indicator1.previewSeries(date, overrides),\n sig.indicator2.previewSeries(date, overrides),\n sig.previewSeries(date, overrides),\n ]);\n const last1 = i1Series.at(-1);\n const last2 = i2Series.at(-1);\n const lastSig = sigSeries.at(-1);\n const i1IsThreshold = sig.indicator1.type === 'Threshold';\n const i2IsThreshold = sig.indicator2.type === 'Threshold';\n return {\n indicator1: {\n value: last1?.value ?? null,\n date: i1IsThreshold ? null : (last1?.date ?? null),\n },\n indicator2: {\n value: last2?.value ?? null,\n date: i2IsThreshold ? null : (last2?.date ?? null),\n },\n isTrue: lastSig?.value === 1,\n };\n }),\n );\n return { signals };\n }),\n ),\n ]);\n\n const target = entries.find((e) => e.date === date);\n const allocation = target\n ? (allocations.find((a) => a.id === target.allocationId) ?? this._allocationMap.get(target.allocationId) ?? null)\n : null;\n\n const fallbackIndex = this._rules.length - 1;\n let activeRuleIndex = fallbackIndex;\n if (target) {\n for (let r = 0; r < this._rules.length; r++) {\n if (this._rules[r]!.hold.id === target.allocationId) {\n activeRuleIndex = r;\n break;\n }\n }\n }\n\n return { allocation, activeRuleIndex, rules };\n }\n\n private async _fetchPricesForTickers(\n bars: StrategyBar[],\n from: string,\n to: string,\n ): Promise<Record<string, Record<string, number>>> {\n const tickerMap = new Map<string, TickerHandle>();\n for (const bar of bars) {\n for (const [ticker] of bar.allocation.holdings) {\n const key = `${ticker.symbol}:${ticker.leverage}`;\n if (!tickerMap.has(key)) {\n tickerMap.set(key, ticker);\n }\n }\n }\n\n const entries = await Promise.all(\n Array.from(tickerMap.entries()).map(async ([key, ticker]) => {\n const priceIndicator = new IndicatorHandle(this._storage, this._market, {\n type: 'Price',\n ticker,\n lookback: 0,\n delay: 0,\n unit: null,\n threshold: null,\n });\n const priceBars = await priceIndicator.series({ from, to });\n const dateMap: Record<string, number> = {};\n for (const bar of priceBars) {\n dateMap[bar.date] = bar.value;\n }\n return [key, dateMap] as const;\n }),\n );\n\n return Object.fromEntries(entries);\n }\n\n private async _fetchRawClosePrices(\n bars: StrategyBar[],\n lastDate: string,\n closePrices: Record<string, number>,\n ): Promise<void> {\n const symbols = new Set<string>();\n for (const bar of bars) {\n for (const [ticker] of bar.allocation.holdings) {\n if (ticker.symbol !== 'CASHX') symbols.add(ticker.symbol);\n }\n }\n\n await Promise.all(\n Array.from(symbols).map(async (symbol) => {\n const rawTicker = new TickerHandle(this._storage, symbol, 1);\n const priceIndicator = new IndicatorHandle(this._storage, this._market, {\n type: 'Price',\n ticker: rawTicker,\n lookback: 0,\n delay: 0,\n unit: null,\n threshold: null,\n });\n const priceBars = await priceIndicator.series({ from: lastDate, to: lastDate });\n if (priceBars.length > 0) {\n closePrices[symbol] = priceBars[0]!.value;\n }\n }),\n );\n }\n}\n","import type { TradingFreq } from '../providers/types';\n\nfunction getPeriodKey(dateStr: string, freq: TradingFreq): string {\n const d = new Date(dateStr + 'T00:00:00Z');\n const y = d.getUTCFullYear();\n const m = d.getUTCMonth();\n\n switch (freq) {\n case 'Weekly': {\n const thu = new Date(d);\n thu.setUTCDate(thu.getUTCDate() + 3 - ((thu.getUTCDay() + 6) % 7));\n const yearStart = new Date(Date.UTC(thu.getUTCFullYear(), 0, 1));\n const weekNo = Math.ceil(((thu.getTime() - yearStart.getTime()) / 86400000 + 1) / 7);\n return `${thu.getUTCFullYear()}-W${weekNo}`;\n }\n case 'Monthly':\n return `${y}-${m}`;\n case 'Bi-monthly':\n return `${y}-${Math.floor(m / 2)}`;\n case 'Quarterly':\n return `${y}-Q${Math.floor(m / 3)}`;\n case 'Every 4 Months':\n return `${y}-${Math.floor(m / 4)}`;\n case 'Semiannually':\n return `${y}-H${Math.floor(m / 6)}`;\n case 'Yearly':\n return `${y}`;\n default:\n return `${y}-${m}`;\n }\n}\n\nexport function computeRebalanceDates(tradingDays: string[], freq: TradingFreq, offset: number): Set<string> {\n if (freq === 'Daily') return new Set(tradingDays);\n\n const groups = new Map<string, number[]>();\n for (let i = 0; i < tradingDays.length; i++) {\n const key = getPeriodKey(tradingDays[i]!, freq);\n if (!groups.has(key)) groups.set(key, []);\n groups.get(key)!.push(i);\n }\n\n const result = new Set<string>();\n for (const indices of groups.values()) {\n const lastIdx = indices[indices.length - 1]!;\n const targetIdx = lastIdx - offset;\n if (targetIdx >= 0 && targetIdx < tradingDays.length) {\n result.add(tradingDays[targetIdx]!);\n }\n }\n\n return result;\n}\n\nexport interface StrategyRuleInput {\n signalIds: number[];\n allocationIndex: number;\n}\n\nexport function evaluateStrategy(\n signalSeries: Map<number, Map<string, boolean>>,\n rules: StrategyRuleInput[],\n rebalanceDates: Set<string>,\n tradingDays: string[],\n): Map<string, number> {\n const result = new Map<string, number>();\n let current: number | undefined;\n\n for (const date of tradingDays) {\n if (rebalanceDates.has(date)) {\n for (const rule of rules) {\n if (rule.signalIds.length === 0) {\n current = rule.allocationIndex;\n break;\n }\n const allTrue = rule.signalIds.every((id) => signalSeries.get(id)?.get(date) ?? false);\n if (allTrue) {\n current = rule.allocationIndex;\n break;\n }\n }\n }\n if (current !== undefined) {\n result.set(date, current);\n }\n }\n\n return result;\n}\n","import { TickerHandle } from './ticker';\nimport type { Trade } from '../backtest/types';\nimport { AllocationHandle } from './allocation';\nimport { isRateTickerSymbol } from '../providers/mappings';\n\nexport class PortfolioHandle {\n readonly holdings: [TickerHandle, number][];\n\n constructor(holdings: [TickerHandle, number][]) {\n // Check for duplicates\n const seen = new Set<string>();\n for (const [ticker] of holdings) {\n const key = `${ticker.symbol}:${ticker.leverage}`;\n if (seen.has(key)) {\n throw new Error(`Duplicate ticker: ${ticker.symbol}`);\n }\n seen.add(key);\n }\n\n this.holdings = holdings;\n }\n\n private _priceMap(prices: [TickerHandle, number][]): Map<string, number> {\n const map = new Map<string, number>();\n for (const [ticker, price] of prices) {\n map.set(`${ticker.symbol}:${ticker.leverage}`, price);\n }\n return map;\n }\n\n private _priceFor(ticker: TickerHandle, priceMap: Map<string, number>): number {\n if (ticker.symbol === 'CASHX') return 1;\n if (isRateTickerSymbol(ticker.symbol)) return 1;\n const key = `${ticker.symbol}:${ticker.leverage}`;\n const price = priceMap.get(key);\n if (price == null) {\n throw new Error(`Missing price for ${ticker.symbol}`);\n }\n return price;\n }\n\n value(prices: [TickerHandle, number][]): number {\n const priceMap = this._priceMap(prices);\n let total = 0;\n for (const [ticker, quantity] of this.holdings) {\n total += quantity * this._priceFor(ticker, priceMap);\n }\n return total;\n }\n\n weights(prices: [TickerHandle, number][]): [TickerHandle, number][] {\n const total = this.value(prices);\n if (total === 0) return [];\n\n const priceMap = this._priceMap(prices);\n const result: [TickerHandle, number][] = [];\n for (const [ticker, quantity] of this.holdings) {\n const dollarValue = quantity * this._priceFor(ticker, priceMap);\n if (dollarValue === 0) continue;\n result.push([ticker, dollarValue / total]);\n }\n return result;\n }\n\n trades(target: AllocationHandle, prices: [TickerHandle, number][], date: string): Trade[] {\n const priceMap = this._priceMap(prices);\n const totalValue = this.value(prices);\n\n // Build current dollar amounts by symbol\n const currentDollars = new Map<string, number>();\n for (const [ticker, quantity] of this.holdings) {\n if (ticker.symbol === 'CASHX') continue;\n const price = this._priceFor(ticker, priceMap);\n currentDollars.set(ticker.symbol, quantity * price);\n }\n\n // Build target dollar amounts by symbol\n const targetDollars = new Map<string, number>();\n for (const [ticker, weight] of target.holdings) {\n if (ticker.symbol === 'CASHX') continue;\n targetDollars.set(ticker.symbol, totalValue * weight);\n }\n\n // Build a symbol → TickerHandle lookup for price resolution\n const tickerBySymbol = new Map<string, TickerHandle>();\n for (const [ticker] of this.holdings) {\n if (ticker.symbol !== 'CASHX') tickerBySymbol.set(ticker.symbol, ticker);\n }\n for (const [ticker] of target.holdings) {\n if (ticker.symbol === 'CASHX') continue;\n const existing = tickerBySymbol.get(ticker.symbol);\n if (existing && existing.leverage !== ticker.leverage) {\n throw new Error(`Conflicting leverage for ${ticker.symbol}`);\n }\n tickerBySymbol.set(ticker.symbol, ticker);\n }\n\n // Collect all non-CASHX symbols from both sides\n const allSymbols = new Set([...currentDollars.keys(), ...targetDollars.keys()]);\n\n const sells: Trade[] = [];\n const buys: Trade[] = [];\n\n for (const symbol of allSymbols) {\n const current = currentDollars.get(symbol) ?? 0;\n const target$ = targetDollars.get(symbol) ?? 0;\n const delta = target$ - current;\n\n const ticker = tickerBySymbol.get(symbol)!;\n const price = this._priceFor(ticker, priceMap);\n\n const quantity = Math.abs(delta) / price;\n if (quantity < 1e-10) continue;\n\n const trade: Trade = { date, symbol, quantity, price, action: delta > 0 ? 'buy' : 'sell' };\n\n if (trade.action === 'sell') {\n sells.push(trade);\n } else {\n buys.push(trade);\n }\n }\n\n return [...sells, ...buys];\n }\n}\n","import type { DailyBar } from '../handles/indicator';\nimport type { StrategyBar } from '../handles/strategy';\nimport type { TickerHandle } from '../handles/ticker';\nimport type { Trade } from './types';\nimport { PortfolioHandle } from '../handles/portfolio';\nimport { isRateTickerSymbol } from '../providers/mappings';\n\nconst EPSILON = 1e-8;\n\nfunction tkey(symbol: string, leverage: number): string {\n return `${symbol}:${leverage}`;\n}\n\nfunction symbolFromKey(key: string): string {\n const idx = key.lastIndexOf(':');\n return idx === -1 ? key : key.slice(0, idx);\n}\n\nfunction isRateKey(key: string): boolean {\n return isRateTickerSymbol(symbolFromKey(key));\n}\n\nfunction navPriceForKey(\n key: string,\n date: string,\n prices: Record<string, Record<string, number>>,\n lastPrice: Record<string, number>,\n): number | undefined {\n if (isRateKey(key)) return 1;\n const live = prices[key]?.[date];\n if (live != null) {\n lastPrice[key] = live;\n return live;\n }\n return lastPrice[key];\n}\n\nfunction daysBetween(prevIsoDate: string, currIsoDate: string): number {\n // Both inputs are 'YYYY-MM-DD'. UTC midnight → diff in ms → days.\n const ms =\n Date.UTC(Number(currIsoDate.slice(0, 4)), Number(currIsoDate.slice(5, 7)) - 1, Number(currIsoDate.slice(8, 10))) -\n Date.UTC(Number(prevIsoDate.slice(0, 4)), Number(prevIsoDate.slice(5, 7)) - 1, Number(prevIsoDate.slice(8, 10)));\n return Math.round(ms / (1000 * 60 * 60 * 24));\n}\n\nexport function runSimulation(\n bars: StrategyBar[],\n prices: Record<string, Record<string, number>>,\n rebalanceDates: Set<string>,\n portfolio: PortfolioHandle,\n): { series: DailyBar[]; trades: Trade[]; finalPortfolio: PortfolioHandle } {\n const positions: Record<string, number> = {};\n const lastPrice: Record<string, number> = {};\n let cash = 0;\n for (const [ticker, quantity] of portfolio.holdings) {\n if (ticker.symbol === 'CASHX') {\n cash = quantity;\n } else {\n positions[tkey(ticker.symbol, ticker.leverage)] = quantity;\n }\n }\n const series: DailyBar[] = [];\n const trades: Trade[] = [];\n\n // Carry forward the last known close when today's price is missing so\n // a held position isn't silently valued at $0 (e.g. mutual fund NAV that\n // posts after the trading-day cutoff).\n function valuationPrice(key: string, date: string): number | undefined {\n return navPriceForKey(key, date, prices, lastPrice);\n }\n\n let prevDate: string | null = null;\n\n for (const bar of bars) {\n const date = bar.date;\n\n // Accrue interest on rate-ticker positions between the previous bar and today.\n if (prevDate != null) {\n const days = daysBetween(prevDate, date);\n if (days > 0) {\n for (const [key, shares] of Object.entries(positions)) {\n if (!isRateKey(key)) continue;\n const ratePct = prices[key]?.[prevDate];\n if (ratePct == null) continue;\n const leverage = Number(key.slice(key.lastIndexOf(':') + 1)) || 1;\n const factor = 1 + leverage * (ratePct / 100) * (days / 360);\n positions[key] = shares * factor;\n }\n }\n }\n\n if (rebalanceDates.has(date)) {\n // Compute current portfolio value before rebalancing\n let portfolioValue = cash;\n for (const [key, shares] of Object.entries(positions)) {\n const price = valuationPrice(key, date);\n if (price != null) portfolioValue += shares * price;\n }\n\n // Determine target holdings\n const targetWeights: Record<string, number> = {};\n for (const [ticker, weight] of bar.allocation.holdings) {\n targetWeights[tkey(ticker.symbol, ticker.leverage)] = weight;\n }\n\n // Compute target shares and execute trades\n const allKeys = new Set([...Object.keys(positions), ...Object.keys(targetWeights)]);\n for (const key of allKeys) {\n let price: number;\n if (isRateKey(key)) {\n price = 1;\n } else {\n const live = prices[key]?.[date];\n if (live == null || live <= 0) continue;\n price = live;\n }\n\n const currentShares = positions[key] ?? 0;\n const targetValue = portfolioValue * (targetWeights[key] ?? 0);\n const targetShares = targetValue / price;\n const delta = targetShares - currentShares;\n\n if (Math.abs(delta) <= EPSILON) continue;\n\n if (Math.abs(targetShares) <= EPSILON) {\n delete positions[key];\n } else {\n positions[key] = targetShares;\n }\n cash -= delta * price;\n\n trades.push({\n date,\n symbol: key.split(':')[0]!,\n quantity: Math.abs(delta),\n price,\n action: delta > 0 ? 'buy' : 'sell',\n });\n }\n\n if (Math.abs(cash) <= EPSILON) cash = 0;\n }\n\n // Compute end-of-day portfolio value\n let value = cash;\n for (const [key, shares] of Object.entries(positions)) {\n const price = valuationPrice(key, date);\n if (price != null) value += shares * price;\n }\n series.push({ date, value });\n prevDate = date;\n }\n\n // Build finalPortfolio from ending positions + cash\n const finalHoldings: [TickerHandle, number][] = [];\n\n // Map ticker keys back to TickerHandles from allocations and starting portfolio\n const tickerByKey = new Map<string, TickerHandle>();\n for (const bar of bars) {\n for (const [ticker] of bar.allocation.holdings) {\n const key = tkey(ticker.symbol, ticker.leverage);\n if (!tickerByKey.has(key)) {\n tickerByKey.set(key, ticker);\n }\n }\n }\n for (const [ticker] of portfolio.holdings) {\n const key = tkey(ticker.symbol, ticker.leverage);\n if (!tickerByKey.has(key)) {\n tickerByKey.set(key, ticker);\n }\n }\n\n for (const [key, shares] of Object.entries(positions)) {\n const ticker = tickerByKey.get(key);\n if (ticker && Math.abs(shares) > EPSILON) {\n finalHoldings.push([ticker, shares]);\n }\n }\n\n // Add CASHX\n const cashKey = tkey('CASHX', 1);\n const cashTicker = tickerByKey.get(cashKey) ?? portfolio.holdings.find(([t]) => t.symbol === 'CASHX')?.[0];\n if (cashTicker && Math.abs(cash) > EPSILON) {\n finalHoldings.push([cashTicker, cash]);\n }\n\n const finalPortfolio = new PortfolioHandle(finalHoldings);\n\n return { series, trades, finalPortfolio };\n}\n","import type { DailyBar } from '../handles/indicator';\n\nexport interface MonthlyReturn {\n year: number;\n month: number; // 0..11\n return: number;\n partial: boolean;\n}\n\nexport interface YearlyReturn {\n year: number;\n return: number;\n partial: boolean;\n}\n\nexport function dailyReturns(series: DailyBar[]): number[] {\n const out: number[] = [];\n for (let i = 1; i < series.length; i++) {\n const prev = series[i - 1]!.value;\n const curr = series[i]!.value;\n out.push(curr / prev - 1);\n }\n return out;\n}\n\nfunction ymd(date: string): { y: number; m: number; d: number } {\n return {\n y: Number(date.slice(0, 4)),\n m: Number(date.slice(5, 7)) - 1,\n d: Number(date.slice(8, 10)),\n };\n}\n\nfunction lastDayOfMonth(year: number, month: number): number {\n return new Date(Date.UTC(year, month + 1, 0)).getUTCDate();\n}\n\nexport function monthlyReturns(series: DailyBar[]): MonthlyReturn[] {\n if (series.length < 2) return [];\n\n type Bucket = {\n year: number;\n month: number;\n firstDate: string;\n firstValue: number;\n lastDate: string;\n lastValue: number;\n };\n const buckets: Bucket[] = [];\n for (const bar of series) {\n const { y, m } = ymd(bar.date);\n const last = buckets[buckets.length - 1];\n if (!last || last.year !== y || last.month !== m) {\n buckets.push({\n year: y,\n month: m,\n firstDate: bar.date,\n firstValue: bar.value,\n lastDate: bar.date,\n lastValue: bar.value,\n });\n } else {\n last.lastDate = bar.date;\n last.lastValue = bar.value;\n }\n }\n\n const out: MonthlyReturn[] = [];\n for (let i = 0; i < buckets.length; i++) {\n const b = buckets[i]!;\n const prevLast = i === 0 ? b.firstValue : buckets[i - 1]!.lastValue;\n const ret = b.lastValue / prevLast - 1;\n const startsAtMonthStart = ymd(b.firstDate).d === 1;\n const endsAtMonthEnd = ymd(b.lastDate).d === lastDayOfMonth(b.year, b.month);\n const isFirst = i === 0;\n const isLast = i === buckets.length - 1;\n const partial = (isFirst && !startsAtMonthStart) || (isLast && !endsAtMonthEnd);\n out.push({ year: b.year, month: b.month, return: ret, partial });\n }\n return out;\n}\n\nexport function yearlyReturns(series: DailyBar[]): YearlyReturn[] {\n if (series.length < 2) return [];\n\n type Bucket = {\n year: number;\n firstDate: string;\n firstValue: number;\n lastDate: string;\n lastValue: number;\n };\n const buckets: Bucket[] = [];\n for (const bar of series) {\n const { y } = ymd(bar.date);\n const last = buckets[buckets.length - 1];\n if (!last || last.year !== y) {\n buckets.push({\n year: y,\n firstDate: bar.date,\n firstValue: bar.value,\n lastDate: bar.date,\n lastValue: bar.value,\n });\n } else {\n last.lastDate = bar.date;\n last.lastValue = bar.value;\n }\n }\n\n const out: YearlyReturn[] = [];\n for (let i = 0; i < buckets.length; i++) {\n const b = buckets[i]!;\n const prevLast = i === 0 ? b.firstValue : buckets[i - 1]!.lastValue;\n const ret = b.lastValue / prevLast - 1;\n const isFirst = i === 0;\n const isLast = i === buckets.length - 1;\n const startsAtYearStart = b.firstDate.endsWith('-01-01');\n const endsAtYearEnd = b.lastDate.endsWith('-12-31');\n const partial = (isFirst && !startsAtYearStart) || (isLast && !endsAtYearEnd);\n out.push({ year: b.year, return: ret, partial });\n }\n return out;\n}\n","import type { DailyBar } from '../handles/indicator';\nimport type { MonthlyReturn, YearlyReturn } from './returns';\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\n\nfunction dateUTC(iso: string): number {\n return Date.UTC(Number(iso.slice(0, 4)), Number(iso.slice(5, 7)) - 1, Number(iso.slice(8, 10)));\n}\n\nexport function totalReturn(series: DailyBar[]): number {\n return series[series.length - 1]!.value / series[0]!.value - 1;\n}\n\nexport function years(series: DailyBar[]): number {\n const first = dateUTC(series[0]!.date);\n const last = dateUTC(series[series.length - 1]!.date);\n return (last - first) / DAY_MS / 365.25;\n}\n\nexport function cagr(series: DailyBar[]): number {\n const y = years(series);\n if (y <= 0) return 0;\n const ratio = series[series.length - 1]!.value / series[0]!.value;\n return Math.pow(ratio, 1 / y) - 1;\n}\n\nexport function bestYear(yr: YearlyReturn[]): { year: number; return: number } | null {\n let best: YearlyReturn | null = null;\n for (const y of yr) {\n if (y.partial) continue;\n if (!best || y.return > best.return) best = y;\n }\n return best ? { year: best.year, return: best.return } : null;\n}\n\nexport function worstYear(yr: YearlyReturn[]): { year: number; return: number } | null {\n let worst: YearlyReturn | null = null;\n for (const y of yr) {\n if (y.partial) continue;\n if (!worst || y.return < worst.return) worst = y;\n }\n return worst ? { year: worst.year, return: worst.return } : null;\n}\n\nfunction monthKey(m: MonthlyReturn): string {\n return `${m.year}-${String(m.month + 1).padStart(2, '0')}`;\n}\n\nexport function bestMonth(mr: MonthlyReturn[]): { date: string; return: number } | null {\n let best: MonthlyReturn | null = null;\n for (const m of mr) {\n if (m.partial) continue;\n if (!best || m.return > best.return) best = m;\n }\n return best ? { date: monthKey(best), return: best.return } : null;\n}\n\nexport function worstMonth(mr: MonthlyReturn[]): { date: string; return: number } | null {\n let worst: MonthlyReturn | null = null;\n for (const m of mr) {\n if (m.partial) continue;\n if (!worst || m.return < worst.return) worst = m;\n }\n return worst ? { date: monthKey(worst), return: worst.return } : null;\n}\n\nexport function pctPositiveMonths(mr: MonthlyReturn[]): number {\n let total = 0;\n let pos = 0;\n for (const m of mr) {\n if (m.partial) continue;\n total++;\n if (m.return > 0) pos++;\n }\n return total === 0 ? 0 : pos / total;\n}\n","import type { DailyBar } from '../handles/indicator';\n\nconst TRADING_DAYS = 252;\n\nexport function mean(xs: number[]): number {\n if (xs.length === 0) return 0;\n let s = 0;\n for (const x of xs) s += x;\n return s / xs.length;\n}\n\nexport function stdev(xs: number[]): number {\n if (xs.length < 2) return 0;\n const m = mean(xs);\n let s = 0;\n for (const x of xs) {\n const d = x - m;\n s += d * d;\n }\n return Math.sqrt(s / (xs.length - 1));\n}\n\nexport function volatility(returns: number[]): number {\n return stdev(returns) * Math.sqrt(TRADING_DAYS);\n}\n\nexport function downsideDeviation(returns: number[], marDaily: number): number {\n if (returns.length === 0) return 0;\n let s = 0;\n for (const r of returns) {\n const d = Math.min(0, r - marDaily);\n s += d * d;\n }\n return Math.sqrt(s / returns.length) * Math.sqrt(TRADING_DAYS);\n}\n\nexport function skewness(xs: number[]): number {\n const n = xs.length;\n if (n < 3) return 0;\n const m = mean(xs);\n const s = stdev(xs);\n if (s === 0) return 0;\n let sum = 0;\n for (const x of xs) {\n const z = (x - m) / s;\n sum += z * z * z;\n }\n return (n / ((n - 1) * (n - 2))) * sum;\n}\n\nexport function excessKurtosis(xs: number[]): number {\n const n = xs.length;\n if (n < 4) return 0;\n const m = mean(xs);\n const s = stdev(xs);\n if (s === 0) return 0;\n let sum = 0;\n for (const x of xs) {\n const z = (x - m) / s;\n sum += z * z * z * z;\n }\n const term1 = (n * (n + 1)) / ((n - 1) * (n - 2) * (n - 3));\n const term2 = (3 * (n - 1) * (n - 1)) / ((n - 2) * (n - 3));\n return term1 * sum - term2;\n}\n\nfunction quantile(sortedAsc: number[], p: number): number {\n if (sortedAsc.length === 0) return NaN;\n if (sortedAsc.length === 1) return sortedAsc[0]!;\n const idx = p * (sortedAsc.length - 1);\n const lo = Math.floor(idx);\n const hi = Math.ceil(idx);\n if (lo === hi) return sortedAsc[lo]!;\n const frac = idx - lo;\n return sortedAsc[lo]! * (1 - frac) + sortedAsc[hi]! * frac;\n}\n\nexport function historicalVar(returns: number[], confidence: number): number {\n if (returns.length === 0) return 0;\n const sorted = [...returns].sort((a, b) => a - b);\n const q = quantile(sorted, 1 - confidence);\n return Math.max(0, -q);\n}\n\nexport function historicalCvar(returns: number[], confidence: number): number {\n if (returns.length === 0) return 0;\n const sorted = [...returns].sort((a, b) => a - b);\n const q = quantile(sorted, 1 - confidence);\n const tail = sorted.filter((r) => r <= q);\n if (tail.length === 0) return 0;\n return Math.max(0, -mean(tail));\n}\n\nexport function ulcerIndex(series: DailyBar[]): number {\n if (series.length === 0) return 0;\n let runningMax = -Infinity;\n let sumSq = 0;\n for (const bar of series) {\n if (bar.value > runningMax) runningMax = bar.value;\n const ddPct = ((bar.value - runningMax) / runningMax) * 100;\n sumSq += ddPct * ddPct;\n }\n return Math.sqrt(sumSq / series.length);\n}\n","import type { DailyBar } from '../handles/indicator';\nimport type { DrawdownEntry } from './types';\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\nconst NOISE = 1e-4;\n\nfunction dateUTC(iso: string): number {\n return Date.UTC(Number(iso.slice(0, 4)), Number(iso.slice(5, 7)) - 1, Number(iso.slice(8, 10)));\n}\n\nfunction daysBetween(a: string, b: string): number {\n return Math.round((dateUTC(b) - dateUTC(a)) / DAY_MS);\n}\n\nexport function computeDrawdownTable(series: DailyBar[], topN: number): DrawdownEntry[] {\n if (series.length === 0) return [];\n\n type Open = { peakDate: string; peakValue: number; troughDate: string; troughValue: number };\n const segments: DrawdownEntry[] = [];\n let peakDate = series[0]!.date;\n let peakValue = series[0]!.value;\n let open: Open | null = null;\n\n for (let i = 0; i < series.length; i++) {\n const bar = series[i]!;\n if (bar.value >= peakValue) {\n if (open) {\n const recoveryDate = bar.date;\n const depth = open.troughValue / open.peakValue - 1;\n if (Math.abs(depth) >= NOISE) {\n segments.push({\n peakDate: open.peakDate,\n troughDate: open.troughDate,\n recoveryDate,\n depth,\n durationDays: daysBetween(open.peakDate, recoveryDate),\n underwaterDays: daysBetween(open.peakDate, open.troughDate),\n });\n }\n open = null;\n }\n peakDate = bar.date;\n peakValue = bar.value;\n } else {\n if (!open) {\n open = { peakDate, peakValue, troughDate: bar.date, troughValue: bar.value };\n } else if (bar.value < open.troughValue) {\n open.troughDate = bar.date;\n open.troughValue = bar.value;\n }\n }\n }\n\n if (open) {\n const lastDate = series[series.length - 1]!.date;\n const depth = open.troughValue / open.peakValue - 1;\n if (Math.abs(depth) >= NOISE) {\n segments.push({\n peakDate: open.peakDate,\n troughDate: open.troughDate,\n recoveryDate: null,\n depth,\n durationDays: daysBetween(open.peakDate, lastDate),\n underwaterDays: daysBetween(open.peakDate, open.troughDate),\n });\n }\n }\n\n segments.sort((a, b) => Math.abs(b.depth) - Math.abs(a.depth));\n return segments.slice(0, topN);\n}\n\nexport function currentDrawdown(series: DailyBar[]): number {\n if (series.length === 0) return 0;\n let runningMax = -Infinity;\n for (const bar of series) {\n if (bar.value > runningMax) runningMax = bar.value;\n }\n const last = series[series.length - 1]!.value;\n return last / runningMax - 1;\n}\n","import { mean, stdev, downsideDeviation } from './risk';\n\nconst TRADING_DAYS = 252;\n\nexport function dailyRiskFree(annual: number): number {\n return Math.pow(1 + annual, 1 / TRADING_DAYS) - 1;\n}\n\nexport function sharpe(returns: number[], rfAnnual: number): number {\n const rfDaily = dailyRiskFree(rfAnnual);\n const s = stdev(returns);\n if (s === 0) return NaN;\n return ((mean(returns) - rfDaily) / s) * Math.sqrt(TRADING_DAYS);\n}\n\nexport function sortino(returns: number[], rfAnnual: number): number {\n const rfDaily = dailyRiskFree(rfAnnual);\n const dd = downsideDeviation(returns, rfDaily);\n if (dd === 0) return NaN;\n return ((mean(returns) - rfDaily) * TRADING_DAYS) / dd;\n}\n\nexport function calmar(cagrValue: number, maxDdDepth: number): number {\n if (maxDdDepth === 0) return Infinity;\n return cagrValue / Math.abs(maxDdDepth);\n}\n","import type { DailyBar } from '../handles/indicator';\nimport type { Trade } from '../backtest/types';\n\nexport function rebalanceCount(trades: Trade[]): number {\n const dates = new Set<string>();\n for (const t of trades) dates.add(t.date);\n return dates.size;\n}\n\nexport function tradeCount(trades: Trade[]): number {\n return trades.length;\n}\n\nexport function turnover(trades: Trade[], series: DailyBar[], years: number): number {\n if (years <= 0 || series.length === 0) return 0;\n let gross = 0;\n for (const t of trades) {\n if (t.symbol === 'CASHX') continue;\n gross += Math.abs(t.quantity * t.price);\n }\n let navSum = 0;\n for (const bar of series) navSum += bar.value;\n const avgNav = navSum / series.length;\n if (avgNav === 0) return 0;\n return gross / avgNav / years;\n}\n\nfunction navAtOrBefore(series: DailyBar[], date: string): number | null {\n let result: number | null = null;\n for (const bar of series) {\n if (bar.date <= date) result = bar.value;\n else break;\n }\n return result;\n}\n\nexport function winRatePerRebalance(series: DailyBar[], trades: Trade[]): number {\n if (series.length < 2) return 0;\n const firstDate = series[0]!.date;\n const lastDate = series[series.length - 1]!.date;\n\n const distinctTradeDates = Array.from(new Set(trades.map((t) => t.date))).sort();\n const inRange = distinctTradeDates.filter((d) => d > firstDate && d < lastDate);\n\n if (inRange.length === 0) {\n const total = series[series.length - 1]!.value / series[0]!.value - 1;\n return total > 0 ? 1 : 0;\n }\n\n const boundaries = [firstDate, ...inRange, lastDate];\n let wins = 0;\n let total = 0;\n for (let i = 0; i < boundaries.length - 1; i++) {\n const a = navAtOrBefore(series, boundaries[i]!);\n const b = navAtOrBefore(series, boundaries[i + 1]!);\n if (a == null || b == null || a === 0) continue;\n total++;\n if (b / a - 1 > 0) wins++;\n }\n return total === 0 ? 0 : wins / total;\n}\n","import type { MonthlyReturnsTable } from './types';\nimport type { MonthlyReturn } from './returns';\n\nexport function buildMonthlyTable(monthly: MonthlyReturn[]): MonthlyReturnsTable {\n if (monthly.length === 0) return { rows: [] };\n\n const byYear = new Map<number, (number | null)[]>();\n for (const m of monthly) {\n let row = byYear.get(m.year);\n if (!row) {\n row = new Array(12).fill(null) as (number | null)[];\n byYear.set(m.year, row);\n }\n row[m.month] = m.return;\n }\n\n const years = Array.from(byYear.keys()).sort((a, b) => a - b);\n const rows = years.map((year) => {\n const months = byYear.get(year)!;\n let ytd: number | null = null;\n for (const v of months) {\n if (v == null) continue;\n ytd = (ytd == null ? 1 : 1 + ytd) * (1 + v) - 1;\n }\n return { year, months, ytd };\n });\n return { rows };\n}\n\nexport function buildYearlyList(monthly: MonthlyReturn[]): Array<{ year: number; return: number }> {\n const byYear = new Map<number, number[]>();\n for (const m of monthly) {\n if (m.partial) continue;\n let arr = byYear.get(m.year);\n if (!arr) {\n arr = [];\n byYear.set(m.year, arr);\n }\n arr.push(m.return);\n }\n const years = Array.from(byYear.keys()).sort((a, b) => a - b);\n return years.map((year) => {\n const months = byYear.get(year)!;\n let compounded = 1;\n for (const v of months) compounded *= 1 + v;\n return { year, return: compounded - 1 };\n });\n}\n","import type { DailyBar } from '../handles/indicator';\nimport type { Trade } from '../backtest/types';\nimport type { DrawdownEntry, MetricsOptions, MetricsResult } from './types';\nimport { dailyReturns, monthlyReturns, yearlyReturns } from './returns';\nimport { totalReturn, cagr, years, bestYear, worstYear, bestMonth, worstMonth, pctPositiveMonths } from './summary';\nimport {\n volatility,\n downsideDeviation,\n skewness,\n excessKurtosis,\n historicalVar,\n historicalCvar,\n ulcerIndex,\n} from './risk';\nimport { computeDrawdownTable, currentDrawdown } from './drawdown';\nimport { sharpe, sortino, calmar, dailyRiskFree } from './riskAdjusted';\nimport { rebalanceCount, tradeCount, turnover, winRatePerRebalance } from './activity';\nimport { buildMonthlyTable, buildYearlyList } from './tables';\n\nexport function computeMetrics(series: DailyBar[], trades: Trade[], options: MetricsOptions = {}): MetricsResult {\n if (series.length < 2) {\n throw new Error('metrics requires at least 2 daily bars');\n }\n const rfAnnual = options.riskFreeRate ?? 0;\n const topN = options.topDrawdowns ?? 5;\n const conf = options.varConfidence ?? 0.95;\n\n const ret = dailyReturns(series);\n const monthly = monthlyReturns(series);\n const yearly = yearlyReturns(series);\n const yrs = years(series);\n\n const dds = computeDrawdownTable(series, Math.max(topN, 1));\n const maxDd: DrawdownEntry = dds[0] ?? {\n peakDate: series[0]!.date,\n troughDate: series[0]!.date,\n recoveryDate: series[series.length - 1]!.date,\n depth: 0,\n durationDays: 0,\n underwaterDays: 0,\n };\n const cagrVal = cagr(series);\n\n return {\n range: { from: series[0]!.date, to: series[series.length - 1]!.date, years: yrs },\n returns: {\n totalReturn: totalReturn(series),\n cagr: cagrVal,\n bestYear: bestYear(yearly),\n worstYear: worstYear(yearly),\n bestMonth: bestMonth(monthly),\n worstMonth: worstMonth(monthly),\n pctPositiveMonths: pctPositiveMonths(monthly),\n },\n risk: {\n volatility: volatility(ret),\n downsideDeviation: downsideDeviation(ret, dailyRiskFree(rfAnnual)),\n maxDrawdown: maxDd,\n currentDrawdown: currentDrawdown(series),\n ulcerIndex: ulcerIndex(series),\n skew: skewness(ret),\n kurtosis: excessKurtosis(ret),\n var95: historicalVar(ret, conf),\n cvar95: historicalCvar(ret, conf),\n },\n riskAdjusted: {\n sharpe: sharpe(ret, rfAnnual),\n sortino: sortino(ret, rfAnnual),\n calmar: calmar(cagrVal, maxDd.depth),\n },\n activity: {\n rebalances: rebalanceCount(trades),\n trades: tradeCount(trades),\n turnover: turnover(trades, series, yrs),\n winRate: winRatePerRebalance(series, trades),\n },\n tables: {\n drawdowns: dds.slice(0, topN),\n monthly: buildMonthlyTable(monthly),\n yearly: buildYearlyList(monthly),\n },\n };\n}\n","import type { DailyBar } from '../handles/indicator';\nimport type { AllocationHandle } from '../handles/allocation';\nimport { PortfolioHandle } from '../handles/portfolio';\nimport type { TickerHandle } from '../handles/ticker';\nimport { computeMetrics } from '../metrics/compute';\nimport type { MetricsOptions, MetricsResult } from '../metrics/types';\n\nexport interface SimulateOptions {\n from: string;\n to: string;\n portfolio: PortfolioHandle;\n}\n\nexport interface Trade {\n date: string;\n symbol: string;\n quantity: number;\n price: number;\n action: 'buy' | 'sell';\n}\n\nexport interface PortfolioSnapshot {\n value: number;\n holdings: [TickerHandle, number][];\n weights: [TickerHandle, number][];\n pendingTrades: Trade[];\n}\n\nexport interface FinalState {\n portfolio: PortfolioHandle;\n allocation: AllocationHandle;\n closePrices: Record<string, number>;\n leveragedPrices: Record<string, number>;\n}\n\n/** Per-signal slice of a live strategy snapshot. */\nexport interface LiveSignalState {\n indicator1: { value: number | null; date: string | null };\n indicator2: { value: number | null; date: string | null };\n isTrue: boolean;\n}\n\n/** Per-rule collection of live signal states, in the same order as the rule's `when` list. */\nexport interface LiveRuleState {\n signals: LiveSignalState[];\n}\n\n/** Full live strategy view for a single evaluation date — no portfolio info. */\nexport interface StrategyLiveState {\n allocation: AllocationHandle | null;\n activeRuleIndex: number;\n rules: LiveRuleState[];\n}\n\n/**\n * Combined live state returned by `SimulationHandle.pushAndPreview`: both the\n * portfolio snapshot from a `push` and the strategy evaluation at the target\n * date under the accumulated live-quote overrides.\n */\nexport interface LivePreviewState extends StrategyLiveState {\n snapshot: PortfolioSnapshot;\n}\n\n/**\n * Callback shape that `SimulationHandle.pushAndPreview` delegates to. Exists\n * purely to break the circular import between `SimulationHandle` (in this\n * file) and `StrategyHandle` (which creates simulations) — a strategy passes\n * a bound `(date, overrides) => previewLiveState(...)` into the handle.\n */\nexport interface LiveEvaluator {\n previewLiveState(date: string, overrides: Record<string, number>): Promise<StrategyLiveState>;\n}\n\nexport class SimulationHandle {\n readonly series: DailyBar[];\n readonly trades: Trade[];\n readonly startingPortfolio: PortfolioHandle;\n\n private _portfolio: PortfolioHandle | null;\n private _currentAllocation: AllocationHandle | null;\n private _lastClosePrices: Record<string, number>;\n private _lastLeveragedPrices: Map<string, number>;\n private _currentLeveragedPrices: Map<string, number>;\n private _lastDate: string;\n private _pushedQuotes: Record<string, number>;\n private _liveEvaluator: LiveEvaluator | null;\n\n constructor(\n series: DailyBar[],\n trades: Trade[],\n startingPortfolio: PortfolioHandle,\n finalState?: FinalState,\n liveEvaluator?: LiveEvaluator,\n ) {\n this.series = series;\n this.trades = trades;\n this.startingPortfolio = startingPortfolio;\n\n if (finalState) {\n this._portfolio = finalState.portfolio;\n this._currentAllocation = finalState.allocation;\n this._lastClosePrices = finalState.closePrices;\n this._lastLeveragedPrices = new Map(Object.entries(finalState.leveragedPrices));\n this._currentLeveragedPrices = new Map(Object.entries(finalState.leveragedPrices));\n this._lastDate = series.at(-1)?.date ?? '';\n } else {\n this._portfolio = null;\n this._currentAllocation = null;\n this._lastClosePrices = {};\n this._lastLeveragedPrices = new Map();\n this._currentLeveragedPrices = new Map();\n this._lastDate = '';\n }\n\n this._pushedQuotes = {};\n this._liveEvaluator = liveEvaluator ?? null;\n }\n\n push(...prices: [TickerHandle, number][]): PortfolioSnapshot {\n if (!this._portfolio || !this._currentAllocation) {\n return { value: 0, holdings: [], weights: [], pendingTrades: [] };\n }\n\n // Update leveraged prices from raw market prices\n for (const [ticker, realPrice] of prices) {\n if (ticker.symbol === 'CASHX') continue;\n const lastClose = this._lastClosePrices[ticker.symbol];\n if (lastClose == null) continue;\n\n const realReturn = (realPrice - lastClose) / lastClose;\n\n // Apply leverage to all portfolio tickers sharing this symbol\n for (const [held] of this._portfolio.holdings) {\n if (held.symbol !== ticker.symbol) continue;\n if (held.symbol === 'CASHX') continue;\n const key = `${held.symbol}:${held.leverage}`;\n const baseLeveragedPrice = this._lastLeveragedPrices.get(key);\n if (baseLeveragedPrice == null) continue;\n const leveragedReturn = held.leverage * realReturn;\n this._currentLeveragedPrices.set(key, baseLeveragedPrice * (1 + leveragedReturn));\n }\n }\n\n // Build price array for PortfolioHandle methods\n const priceArray: [TickerHandle, number][] = [];\n for (const [held] of this._portfolio.holdings) {\n if (held.symbol === 'CASHX') continue;\n const key = `${held.symbol}:${held.leverage}`;\n const price = this._currentLeveragedPrices.get(key);\n if (price != null) priceArray.push([held, price]);\n }\n\n return {\n value: this._portfolio.value(priceArray),\n holdings: this._portfolio.holdings,\n weights: this._portfolio.weights(priceArray),\n pendingTrades: this._portfolio.trades(this._currentAllocation, priceArray, this._lastDate),\n };\n }\n\n /**\n * One-call live update. Feeds portfolio-relevant ticker prices into `push`\n * (derived from `quotes` via the running portfolio's holdings), accumulates\n * every symbol in `quotes` into an internal override map so macro symbols\n * (e.g. `^VIX`) persist across ticks, then delegates to the simulation's\n * strategy for rule / signal / indicator evaluation at `date`.\n *\n * Without a live evaluator attached, returns just the portfolio snapshot\n * with allocation/rules/signals empty.\n *\n * @param quotes Symbol → raw live price. Portfolio tickers flow through\n * `push` for leveraged-equity math; non-portfolio symbols are still\n * layered into the overlay so indicators can see them.\n * @param options.date Target trading day to evaluate against. Defaults to\n * the current UTC ISO date; callers with non-UTC semantics or after-hours\n * rollover should supply their own.\n */\n metrics(options: MetricsOptions = {}): MetricsResult {\n return computeMetrics(this.series, this.trades, options);\n }\n\n async pushAndPreview(quotes: Record<string, number>, options: { date?: string } = {}): Promise<LivePreviewState> {\n const priceArgs: [TickerHandle, number][] = [];\n if (this._portfolio) {\n const seen = new Set<string>();\n for (const [ticker] of this._portfolio.holdings) {\n if (ticker.symbol === 'CASHX') continue;\n if (seen.has(ticker.symbol)) continue;\n const price = quotes[ticker.symbol];\n if (price !== undefined) {\n priceArgs.push([ticker, price]);\n seen.add(ticker.symbol);\n }\n }\n }\n const snapshot = this.push(...priceArgs);\n\n // Merge into the running overlay map (macro symbols etc. persist across ticks).\n for (const [symbol, price] of Object.entries(quotes)) {\n this._pushedQuotes[symbol] = price;\n }\n\n if (!this._liveEvaluator) {\n return { snapshot, allocation: null, activeRuleIndex: -1, rules: [] };\n }\n\n const date = options.date ?? new Date().toISOString().slice(0, 10);\n // Pass a snapshot copy so downstream callers can retain the object without\n // seeing it mutate on later ticks.\n const strategyState = await this._liveEvaluator.previewLiveState(date, { ...this._pushedQuotes });\n return { snapshot, ...strategyState };\n }\n}\n","import type { StorageProvider } from './providers/storage';\nimport type { MarketProvider } from './providers/market';\nimport type { IndicatorType, Unit } from './providers/types';\nimport { TickerHandle } from './handles/ticker';\nimport { IndicatorHandle } from './handles/indicator';\nimport { SignalHandle } from './handles/signal';\nimport { AllocationHandle } from './handles/allocation';\nimport { StrategyHandle } from './handles/strategy';\nimport { PortfolioHandle } from './handles/portfolio';\nimport type { StrategyOptions } from './handles/strategy';\n\ntype TreasuryTenor = Extract<\n IndicatorType,\n 'T3M' | 'T6M' | 'T1Y' | 'T2Y' | 'T3Y' | 'T5Y' | 'T7Y' | 'T10Y' | 'T20Y' | 'T30Y'\n>;\ntype CalendarPeriod = Extract<IndicatorType, 'Month' | 'Day of Week' | 'Day of Month' | 'Day of Year'>;\n\ninterface IndicatorOpts {\n delay?: number;\n}\n\nexport interface LivefolioClient {\n ticker(symbol: string, leverage?: number): TickerHandle;\n\n // Ticker-bound\n sma(ticker: TickerHandle, lookback: number, opts?: IndicatorOpts): IndicatorHandle;\n ema(ticker: TickerHandle, lookback: number, opts?: IndicatorOpts): IndicatorHandle;\n price(ticker: TickerHandle, opts?: IndicatorOpts): IndicatorHandle;\n returns(ticker: TickerHandle, lookback: number, opts?: IndicatorOpts): IndicatorHandle;\n volatility(ticker: TickerHandle, lookback: number, opts?: IndicatorOpts): IndicatorHandle;\n drawdown(ticker: TickerHandle, lookback: number, opts?: IndicatorOpts): IndicatorHandle;\n rsi(ticker: TickerHandle, lookback: number, opts?: IndicatorOpts): IndicatorHandle;\n\n // Standalone\n vix(opts?: IndicatorOpts): IndicatorHandle;\n vix3m(opts?: IndicatorOpts): IndicatorHandle;\n treasury(tenor: TreasuryTenor, opts?: IndicatorOpts): IndicatorHandle;\n calendar(period: CalendarPeriod, opts?: IndicatorOpts): IndicatorHandle;\n\n // Threshold\n threshold(value: number, unit?: Unit): IndicatorHandle;\n\n // Signals\n gt(ind1: IndicatorHandle, ind2: IndicatorHandle, tolerance?: number): SignalHandle;\n lt(ind1: IndicatorHandle, ind2: IndicatorHandle, tolerance?: number): SignalHandle;\n eq(ind1: IndicatorHandle, ind2: IndicatorHandle, tolerance?: number): SignalHandle;\n\n // Allocations\n allocation(...holdings: [TickerHandle, number][]): AllocationHandle;\n\n // Portfolios\n portfolio(...holdings: [TickerHandle, number][]): PortfolioHandle;\n\n // Strategies\n strategy(linkId: string): StrategyHandle;\n strategy(options: StrategyOptions): StrategyHandle;\n strategy(optionsOrLinkId: string | StrategyOptions): StrategyHandle;\n}\n\nexport interface LivefolioClientOptions {\n storage: StorageProvider;\n market: MarketProvider;\n}\n\nfunction tickerBound(\n storage: StorageProvider,\n market: MarketProvider,\n type: IndicatorType,\n ticker: TickerHandle,\n lookback: number,\n opts?: IndicatorOpts,\n): IndicatorHandle {\n return new IndicatorHandle(storage, market, {\n type,\n ticker,\n lookback,\n delay: opts?.delay ?? 0,\n unit: null,\n threshold: null,\n });\n}\n\nfunction standalone(\n storage: StorageProvider,\n market: MarketProvider,\n type: IndicatorType,\n opts?: IndicatorOpts,\n): IndicatorHandle {\n return new IndicatorHandle(storage, market, {\n type,\n ticker: null,\n lookback: 0,\n delay: opts?.delay ?? 0,\n unit: null,\n threshold: null,\n });\n}\n\nexport function createClient(options: LivefolioClientOptions): LivefolioClient {\n const { storage, market } = options;\n\n return {\n ticker: (symbol, leverage) => new TickerHandle(storage, symbol, leverage),\n\n sma: (ticker, lookback, opts?) => tickerBound(storage, market, 'SMA', ticker, lookback, opts),\n ema: (ticker, lookback, opts?) => tickerBound(storage, market, 'EMA', ticker, lookback, opts),\n price: (ticker, opts?) => tickerBound(storage, market, 'Price', ticker, 0, opts),\n returns: (ticker, lookback, opts?) => tickerBound(storage, market, 'Return', ticker, lookback, opts),\n volatility: (ticker, lookback, opts?) => tickerBound(storage, market, 'Volatility', ticker, lookback, opts),\n drawdown: (ticker, lookback, opts?) => tickerBound(storage, market, 'Drawdown', ticker, lookback, opts),\n rsi: (ticker, lookback, opts?) => tickerBound(storage, market, 'RSI', ticker, lookback, opts),\n\n vix: (opts?) => standalone(storage, market, 'VIX', opts),\n vix3m: (opts?) => standalone(storage, market, 'VIX3M', opts),\n treasury: (tenor, opts?) => standalone(storage, market, tenor, opts),\n calendar: (period, opts?) => standalone(storage, market, period, opts),\n\n threshold: (value, unit?) =>\n new IndicatorHandle(storage, market, {\n type: 'Threshold',\n ticker: null,\n // Thresholds are constants — lookback/delay are semantically unused,\n // but the DB's canonical form has (lookback=1, delay=0). Matching that\n // lets `indicators.findOrCreate` reuse existing rows instead of creating\n // duplicates at (lookback=0, delay=0) that the schema permits.\n lookback: 1,\n delay: 0,\n unit: unit ?? null,\n threshold: value,\n }),\n\n gt: (ind1, ind2, tolerance?) =>\n new SignalHandle(storage, market, {\n indicator1: ind1,\n indicator2: ind2,\n comparison: '>',\n tolerance: tolerance ?? 0,\n }),\n lt: (ind1, ind2, tolerance?) =>\n new SignalHandle(storage, market, {\n indicator1: ind1,\n indicator2: ind2,\n comparison: '<',\n tolerance: tolerance ?? 0,\n }),\n eq: (ind1, ind2, tolerance?) =>\n new SignalHandle(storage, market, {\n indicator1: ind1,\n indicator2: ind2,\n comparison: '=',\n tolerance: tolerance ?? 0,\n }),\n\n allocation: (...holdings) => new AllocationHandle(storage, holdings),\n\n portfolio: (...holdings) => new PortfolioHandle(holdings),\n\n strategy: (optionsOrLinkId: StrategyOptions | string) => new StrategyHandle(storage, market, optionsOrLinkId),\n };\n}\n","import { AllocationHandle } from './allocation';\n\nexport function allocationsEqual(a: AllocationHandle | null, b: AllocationHandle | null): boolean {\n if (a === null && b === null) return true;\n if (a === null || b === null) return false;\n const aj = a.toJSON();\n const bj = b.toJSON();\n if (aj.length !== bj.length) return false;\n for (let i = 0; i < aj.length; i++) {\n if (aj[i]!.symbol !== bj[i]!.symbol) return false;\n if (aj[i]!.leverage !== bj[i]!.leverage) return false;\n if (Math.abs(aj[i]!.weight - bj[i]!.weight) > 1e-9) return false;\n }\n return true;\n}\n"],"mappings":"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","names":["dailyReturns","mean","leverage","from","rawBars","DAY_MS","dateUTC","daysBetween","TRADING_DAYS","years","total","years","id"]}
1
+ {"version":3,"sources":["../src/strategy/reconcile.ts","../src/portfolio/apply.ts","../src/strategy/run-backtest.ts","../src/features/series-utils.ts","../src/features/indicators/sma.ts","../src/features/indicators/ema.ts","../src/features/indicators/rsi.ts","../src/features/indicators/return.ts","../src/features/indicators/volatility.ts","../src/features/indicators/drawdown.ts","../src/features/spec.ts","../src/features/runtime.ts","../src/reference/memory-feature-cache.ts","../src/strategy/run-live.ts","../src/reference/backtest-executor.ts","../src/reference/routing-data-feed.ts","../src/reference/routing-streaming-data-feed.ts","../src/reference/polling-stream-from-historical.ts","../src/calendars/exchange-calendar.ts","../src/calendars/holiday-rules.ts","../src/calendars/nyse.ts","../src/calendars/lse.ts","../src/calendars/get-calendar.ts","../src/calendars/crypto-24x7.ts","../src/tactical/index.ts","../src/tactical/evaluate-rule-tree.ts","../src/tactical/asset-ref.ts","../src/tactical/evaluate-feature-specs.ts","../src/tactical/synthetics.ts","../src/tactical/from-spec.ts","../src/features/index.ts"],"sourcesContent":["import type { Portfolio } from '../portfolio/types';\nimport type { Asset, AssetId } from '../interfaces/types';\nimport type { RebalanceOrder } from '../orders/types';\n\n/**\n * Maps each asset ID to its desired portfolio weight as a fraction of total\n * portfolio value (e.g. `0.6` means 60 %). Weights need not sum to 1; any\n * residual becomes cash. Passing a weight of `0` or omitting an asset entirely\n * will generate a full exit order for any existing long position in that asset.\n */\nexport type TargetWeights = ReadonlyMap<AssetId, number>;\n\n/**\n * Maps each asset ID to its current market price. Required for every asset that\n * appears in `TargetWeights` and for every asset currently held in the portfolio.\n * `reconcile` throws if a target asset has no corresponding price entry.\n */\nexport type PriceMap = ReadonlyMap<AssetId, number>;\n\n/**\n * Converts target portfolio weights into a minimal set of `RebalanceOrder`\n * instructions that move the current portfolio toward the desired allocation.\n *\n * The algorithm:\n * 1. Compute total portfolio value as `cash + Σ(held_shares × price)`.\n * 2. For each target asset, derive `targetShares = floor(totalValue × weight / price)`.\n * 3. Emit a `RebalanceOrder` with `delta = targetShares - heldShares` for any\n * asset where the delta is non-zero (positive = buy, negative = sell).\n * 4. Emit exit orders (`delta = -heldShares`) for any long position in an asset\n * that does not appear in `targets`.\n *\n * Only long positions are considered — short positions in the portfolio are\n * ignored. Share counts are always floored to integer lots.\n *\n * @param targets - Desired weight per asset. Keys are `AssetId` strings. A weight\n * of `0` is valid and will result in a full exit for any existing position.\n * @param portfolio - Current portfolio. Cash and long positions determine total\n * value and existing share counts.\n * @param prices - Current prices for all assets that appear in `targets` or are\n * currently held. Throws `Error` if a target asset is missing from this map.\n * @returns A readonly array of `RebalanceOrder` objects. The array may be empty\n * if the portfolio is already at the target allocation. Order IDs are\n * deterministic within a single call (`rebal_<assetId>_<counter>`).\n *\n * @example\n * ```ts\n * import { reconcile } from '@livefolio/sdk';\n *\n * const targets = new Map([\n * ['US:SPY', 0.6],\n * ['US:BND', 0.4],\n * ]);\n * const prices = new Map([\n * ['US:SPY', 440.0],\n * ['US:BND', 75.0],\n * ]);\n *\n * // Empty portfolio with $100 000 cash\n * const portfolio = { cash: 100_000, positions: [] };\n * const orders = reconcile(targets, portfolio, prices);\n * // orders => [\n * // { id: 'rebal_US:SPY_0', kind: 'rebalance', asset: { ... }, delta: 136 },\n * // { id: 'rebal_US:BND_1', kind: 'rebalance', asset: { ... }, delta: 533 },\n * // ]\n * ```\n */\nexport function reconcile(\n targets: TargetWeights,\n portfolio: Portfolio,\n prices: PriceMap,\n): ReadonlyArray<RebalanceOrder> {\n const longByAsset = new Map<AssetId, { asset: Asset; quantity: number }>();\n for (const p of portfolio.positions) {\n if (p.side !== 'long') continue;\n const cur = longByAsset.get(p.asset.id);\n if (cur) cur.quantity += p.quantity;\n else longByAsset.set(p.asset.id, { asset: p.asset, quantity: p.quantity });\n }\n\n let totalValue = portfolio.cash;\n for (const { asset, quantity } of longByAsset.values()) {\n const price = prices.get(asset.id);\n if (price !== undefined) totalValue += quantity * price;\n }\n\n const orders: RebalanceOrder[] = [];\n let counter = 0;\n const nextId = (assetId: AssetId): string => `rebal_${assetId}_${counter++}`;\n\n const seen = new Set<AssetId>();\n\n for (const [assetId, weight] of targets) {\n const price = prices.get(assetId);\n if (price === undefined) {\n throw new Error(`reconcile: missing price for target asset ${assetId}`);\n }\n const targetShares = Math.floor((totalValue * weight) / price);\n const held = longByAsset.get(assetId);\n const currentShares = held?.quantity ?? 0;\n const delta = targetShares - currentShares;\n seen.add(assetId);\n if (delta !== 0) {\n const asset: Asset = held?.asset ?? {\n kind: 'equity',\n id: assetId,\n symbol: assetId.split(':').pop() ?? assetId,\n };\n orders.push({ id: nextId(assetId), kind: 'rebalance', asset, delta });\n }\n }\n\n for (const [assetId, { asset, quantity }] of longByAsset) {\n if (seen.has(assetId)) continue;\n orders.push({ id: nextId(assetId), kind: 'rebalance', asset, delta: -quantity });\n }\n\n return orders;\n}\n","import type { Portfolio, Position, PositionId } from './types';\nimport type { Order, Fill } from '../orders/types';\n\nconst newPositionId = (() => {\n let n = 0;\n return (): PositionId => `pos_${++n}`;\n})();\n\nfunction findOrder(orders: ReadonlyArray<Order>, id: string): Order | undefined {\n return orders.find((o) => o.id === id);\n}\n\n/**\n * Applies a batch of confirmed fills to a portfolio, returning a new\n * {@link Portfolio} snapshot. This is the single function that advances\n * portfolio state after order execution.\n *\n * For each fill the corresponding order is looked up in `orders` by\n * `fill.orderRef`. The order's `kind` determines the accounting treatment:\n * - `'open'` — adds a new {@link Position} and debits cash.\n * - `'close'` — removes shares from an existing position and credits cash.\n * - `'adjust'` — updates the position's `quantity`; only fees are debited.\n * - `'rebalance'` — buys or sells shares in the long position for `asset`;\n * creates or removes the position as needed.\n *\n * The returned `portfolio.t` is updated to the maximum fill timestamp.\n *\n * @param portfolio - The current portfolio state before this batch.\n * @param fills - Execution confirmations returned by {@link Executor.submit}.\n * Each fill's `orderRef` MUST match an `id` in `orders`.\n * @param orders - The full order batch that was submitted. Used to look up\n * order details for each fill.\n * @returns A new {@link Portfolio} with updated positions, cash, and timestamp.\n * The input `portfolio` is not mutated.\n *\n * @example\n * ```ts\n * import { applyFills } from '@livefolio/sdk';\n * import type { Portfolio, Order, Fill } from '@livefolio/sdk';\n *\n * const portfolio: Portfolio = { cash: 10_000, positions: [], t: new Date('2024-01-01') };\n *\n * const order: Order = {\n * id: 'ord_1', kind: 'open',\n * asset: { kind: 'equity', id: 'AAPL', symbol: 'AAPL' },\n * side: 'long', quantity: 10,\n * };\n * const fill: Fill = { orderRef: 'ord_1', t: new Date('2024-01-02'), quantity: 10, price: 185, fees: 0 };\n *\n * const next = applyFills(portfolio, [fill], [order]);\n * // next.cash === 8_250, next.positions.length === 1\n * ```\n */\nexport function applyFills(portfolio: Portfolio, fills: ReadonlyArray<Fill>, orders: ReadonlyArray<Order>): Portfolio {\n let positions: Position[] = [...portfolio.positions];\n let cash = portfolio.cash;\n let t = portfolio.t;\n\n for (const fill of fills) {\n const order = findOrder(orders, fill.orderRef);\n if (!order) {\n throw new Error(`applyFills: fill.orderRef \"${fill.orderRef}\" matches no known order`);\n }\n t = fill.t > t ? fill.t : t;\n\n switch (order.kind) {\n case 'open': {\n const pos: Position = {\n id: newPositionId(),\n asset: order.asset,\n side: order.side,\n quantity: fill.quantity,\n entry: { date: fill.t, price: fill.price },\n basis: fill.quantity * fill.price + fill.fees,\n };\n positions.push(pos);\n cash -= fill.quantity * fill.price + fill.fees;\n break;\n }\n case 'close': {\n const idx = positions.findIndex((p) => p.id === order.positionId);\n if (idx < 0) throw new Error(`applyFills: close target ${order.positionId} not found`);\n const pos = positions[idx]!;\n const sign = pos.side === 'long' ? 1 : -1;\n cash += sign * fill.quantity * fill.price - fill.fees;\n const remaining = pos.quantity - fill.quantity;\n if (remaining <= 0) {\n positions = positions.filter((_, i) => i !== idx);\n } else {\n positions[idx] = { ...pos, quantity: remaining };\n }\n break;\n }\n case 'adjust': {\n const idx = positions.findIndex((p) => p.id === order.positionId);\n if (idx < 0) throw new Error(`applyFills: adjust target ${order.positionId} not found`);\n const pos = positions[idx]!;\n const nextQty = order.changes.quantity ?? pos.quantity;\n positions[idx] = { ...pos, quantity: nextQty };\n cash -= fill.fees;\n break;\n }\n case 'rebalance': {\n const idx = positions.findIndex((p) => p.asset.id === order.asset.id && p.side === 'long');\n if (order.delta > 0) {\n const cost = fill.quantity * fill.price + fill.fees;\n cash -= cost;\n if (idx < 0) {\n positions.push({\n id: newPositionId(),\n asset: order.asset,\n side: 'long',\n quantity: fill.quantity,\n entry: { date: fill.t, price: fill.price },\n basis: cost,\n });\n } else {\n const prev = positions[idx]!;\n positions[idx] = {\n ...prev,\n quantity: prev.quantity + fill.quantity,\n basis: prev.basis + cost,\n };\n }\n } else {\n if (idx < 0) {\n throw new Error(`applyFills: rebalance reduce on ${order.asset.id} but no long position exists`);\n }\n const prev = positions[idx]!;\n cash += fill.quantity * fill.price - fill.fees;\n const remaining = prev.quantity - fill.quantity;\n if (remaining <= 0) {\n positions = positions.filter((_, i) => i !== idx);\n } else {\n const basisPerShare = prev.basis / prev.quantity;\n positions[idx] = {\n ...prev,\n quantity: remaining,\n basis: basisPerShare * remaining,\n };\n }\n }\n break;\n }\n }\n }\n\n return { cash, positions, t };\n}\n\n/**\n * Projects a portfolio forward through a set of pending (unfilled) orders,\n * returning a structurally updated snapshot. Used by strategy build helpers\n * to read the expected post-step state before fills arrive.\n *\n * **v0.4 contract — structural projection only.** Quantities are updated\n * exactly as the orders specify, but:\n * - `cash` is left unchanged (no price is available at projection time).\n * - Newly opened positions have `basis: 0` and `entry.price: 0` as\n * provisional values. A price-aware projection is planned for a later phase.\n *\n * Use {@link applyFills} (not this function) to settle the portfolio after\n * confirmed execution.\n *\n * @param portfolio - The current portfolio state to project from.\n * @param orders - The pending orders to apply structurally. Order must have\n * a valid `id` and `kind`; price fields are ignored.\n * @returns A new {@link Portfolio} with positions reflecting the orders.\n * `cash` and `t` are copied unchanged from `portfolio`.\n *\n * @example\n * ```ts\n * import { applyOrders } from '@livefolio/sdk';\n * import type { Portfolio, Order } from '@livefolio/sdk';\n *\n * const portfolio: Portfolio = { cash: 10_000, positions: [], t: new Date('2024-01-01') };\n *\n * const order: Order = {\n * id: 'ord_1', kind: 'open',\n * asset: { kind: 'equity', id: 'AAPL', symbol: 'AAPL' },\n * side: 'long', quantity: 10,\n * };\n *\n * const projected = applyOrders(portfolio, [order]);\n * // projected.positions.length === 1, projected.cash === 10_000 (unchanged)\n * ```\n */\nexport function applyOrders(portfolio: Portfolio, orders: ReadonlyArray<Order>): Portfolio {\n let positions: Position[] = [...portfolio.positions];\n\n for (const order of orders) {\n switch (order.kind) {\n case 'open': {\n positions.push({\n id: newPositionId(),\n asset: order.asset,\n side: order.side,\n quantity: order.quantity,\n entry: { date: portfolio.t, price: 0 },\n basis: 0,\n });\n break;\n }\n case 'close': {\n const idx = positions.findIndex((p) => p.id === order.positionId);\n if (idx < 0) break;\n const pos = positions[idx]!;\n const remove = order.quantity ?? pos.quantity;\n const remaining = pos.quantity - remove;\n if (remaining <= 0) {\n positions = positions.filter((_, i) => i !== idx);\n } else {\n positions[idx] = { ...pos, quantity: remaining };\n }\n break;\n }\n case 'adjust': {\n const idx = positions.findIndex((p) => p.id === order.positionId);\n if (idx < 0) break;\n const pos = positions[idx]!;\n positions[idx] = { ...pos, quantity: order.changes.quantity ?? pos.quantity };\n break;\n }\n case 'rebalance': {\n const idx = positions.findIndex((p) => p.asset.id === order.asset.id && p.side === 'long');\n if (order.delta > 0) {\n if (idx < 0) {\n positions.push({\n id: newPositionId(),\n asset: order.asset,\n side: 'long',\n quantity: order.delta,\n entry: { date: portfolio.t, price: 0 },\n basis: 0,\n });\n } else {\n const prev = positions[idx]!;\n positions[idx] = { ...prev, quantity: prev.quantity + order.delta };\n }\n } else if (idx >= 0) {\n const prev = positions[idx]!;\n const remaining = prev.quantity + order.delta;\n if (remaining <= 0) {\n positions = positions.filter((_, i) => i !== idx);\n } else {\n positions[idx] = { ...prev, quantity: remaining };\n }\n }\n break;\n }\n }\n }\n\n return { ...portfolio, positions };\n}\n","import type { Strategy, Features } from './types';\nimport type { Portfolio } from '../portfolio/types';\nimport type { DataFeed } from '../interfaces/data-feed';\nimport type { Executor } from '../interfaces/executor';\nimport type { Calendar } from '../interfaces/calendar';\nimport type { FeatureCache } from '../interfaces/feature-cache';\nimport type { AssetId, Bar, DateRange, Frequency } from '../interfaces/types';\nimport type { Order, Fill } from '../orders/types';\nimport type { FeatureRuntime } from '../features/runtime';\nimport { applyFills } from '../portfolio/apply';\n\n/**\n * Narrows the dual return type of `Strategy.build` to the stateful object form.\n *\n * `Array.isArray` does not narrow `ReadonlyArray<T>` out of a union in TypeScript 5.x\n * when the other arm is an object type, so we use an explicit type predicate instead.\n * The helper is defined at module scope so `runLive` (Task 8) can reuse it.\n */\nexport function isStateResult<S>(\n r: ReadonlyArray<Order> | { orders: ReadonlyArray<Order>; state: S },\n): r is { orders: ReadonlyArray<Order>; state: S } {\n return !Array.isArray(r);\n}\n\n/**\n * All inputs required to run a historical backtest.\n *\n * Callers must provide a concrete `Strategy`, a `DateRange`, and the four\n * pluggable runtime layers (`dataFeed`, `executor`, `calendar`, `featureCache`).\n * The reference implementations (`MemoryFeatureCache`, `BacktestExecutor`,\n * `NYSEExchangeCalendar`) satisfy all four without network dependencies.\n */\nexport type RunBacktestOptions<F extends Features = Features, S = unknown> = {\n /** The strategy under test. Must implement `universe`, `features`, and `build`. */\n strategy: Strategy<F, S>;\n /**\n * Inclusive date range over which to iterate. The calendar resolves this\n * range into the actual sequence of trading sessions.\n */\n range: DateRange;\n /**\n * Starting portfolio state. Cash and positions are carried forward through\n * the simulation as orders are filled. This value is never mutated.\n */\n initialPortfolio: Portfolio;\n /**\n * Source of OHLCV bar data and optionally fundamentals / corporate events.\n * `FeatureRuntime` uses this to hydrate price series before computing indicators.\n */\n dataFeed: DataFeed;\n /**\n * Order router responsible for converting `Order` objects into `Fill` records.\n * Use `BacktestExecutor` for historical simulations or swap in a live\n * broker implementation for paper/live trading.\n */\n executor: Executor;\n /**\n * Trading-day calendar. Used to enumerate `sessions` within `range` and to\n * determine rebalance day boundaries via `next`.\n */\n calendar: Calendar;\n /**\n * Optional persistent indicator cache. When omitted, each `runBacktest` call\n * recomputes all indicators from scratch. Provide `MemoryFeatureCache` (or a\n * cross-process cache) to memoize results across multiple runs.\n */\n featureCache?: FeatureCache;\n /**\n * Bar frequency forwarded to `DataFeed.bars`. Defaults to `'1d'` when omitted.\n * Must match the granularity expected by the strategy's indicator specs.\n */\n freq?: Frequency;\n /**\n * Optional `FeatureRuntime` instance. When provided, its accumulated bar buffer\n * is exported on `BacktestResult.bars` for use by `runLive` (lets the streaming\n * runtime seed its buffer from the historical bars without refetching).\n */\n featureRuntime?: FeatureRuntime;\n};\n\n/**\n * A point-in-time snapshot of the simulation at the end of a single trading session.\n *\n * Each entry in `BacktestResult.snapshots` corresponds to one call of the strategy\n * loop: `universe → features → build → executor.submit → applyFills`.\n */\nexport type BacktestSnapshot = {\n /** The session date for this snapshot (midnight UTC on the trading day). */\n t: Date;\n /** Portfolio state *after* fills have been applied for this session. */\n portfolio: Portfolio;\n /** Orders emitted by `strategy.build` during this session. */\n orders: ReadonlyArray<Order>;\n /** Fills returned by the executor for the orders above. */\n fills: ReadonlyArray<Fill>;\n};\n\n/**\n * The return value of `runBacktest`, containing the full simulation history\n * and the terminal portfolio state.\n */\nexport type BacktestResult<S = unknown> = {\n /**\n * Ordered list of snapshots, one per trading session in `range`. Empty when\n * the calendar has no sessions in the requested range.\n */\n snapshots: ReadonlyArray<BacktestSnapshot>;\n /**\n * Portfolio after the last session's fills have been applied. Equivalent to\n * `snapshots[snapshots.length - 1].portfolio` when there is at least one session,\n * or `initialPortfolio` when the range is empty.\n */\n finalPortfolio: Portfolio;\n /**\n * Final value of the strategy's auxiliary state after the last `build()` call.\n * `undefined` when the strategy is state-less (no `initialState()` defined).\n * Used by `runLive` to seed the live runtime so the first live tick continues\n * from the exact state the historical run ended on.\n */\n finalState: S | undefined;\n /**\n * Per-asset bar buffer accumulated by the `FeatureRuntime` during this run.\n * Empty `Map` when no `featureRuntime` was provided in `RunBacktestOptions`.\n * Used by `runLive` to seed its streaming `FeatureRuntime` so indicators with\n * warmup periods (SMA(200), etc.) work on the first live tick.\n */\n bars: ReadonlyMap<AssetId, ReadonlyArray<Bar>>;\n};\n\n/**\n * Drives a `Strategy` over a historical date range and returns a full audit trail\n * of orders, fills, and portfolio states.\n *\n * The simulation loop:\n * 1. Enumerate trading sessions via `opts.calendar.sessions(opts.range)`.\n * 2. Call `strategy.initialState?.()` once to seed the carry-over state.\n * 3. For each session `t`, call `strategy.universe(t, portfolio)`.\n * 4. Await `strategy.features(universe, portfolio, t)`.\n * 5. Call `strategy.build(features, portfolio, state, t)` to obtain orders and\n * the next state value. Both legacy `Order[]` returns and new `{ orders, state }`\n * returns are normalised — the legacy form leaves state unchanged.\n * 6. Await `opts.executor.submit(orders, t, portfolio)` to obtain fills.\n * 7. Apply fills to the portfolio with `applyFills`.\n * 8. Append a `BacktestSnapshot` and advance to the next session.\n *\n * The portfolio is never mutated in place; each session receives the immutable\n * result of the previous session's `applyFills`.\n *\n * @param opts - Backtest configuration. See {@link RunBacktestOptions}.\n * @returns A promise that resolves to a {@link BacktestResult} containing one\n * snapshot per trading session, the final portfolio state, and the final\n * strategy state (`finalState`). Returns\n * `{ snapshots: [], finalPortfolio: opts.initialPortfolio, finalState: undefined }`\n * when the calendar has no sessions in the requested range.\n *\n * @example\n * ```ts\n * import {\n * runBacktest,\n * fromSpec,\n * MemoryFeatureCache,\n * BacktestExecutor,\n * NYSEExchangeCalendar,\n * FeatureRuntime,\n * } from '@livefolio/sdk';\n *\n * const calendar = new NYSEExchangeCalendar();\n * const range = { from: new Date('2023-01-01'), to: new Date('2023-12-31') };\n * const featureCache = new MemoryFeatureCache();\n * const runtime = new FeatureRuntime({ dataFeed, featureCache, range, freq: '1d' });\n *\n * const strategy = fromSpec(myTacticalSpec, { runtime, calendar });\n *\n * const result = await runBacktest({\n * strategy,\n * range,\n * initialPortfolio: { cash: 100_000, positions: [] },\n * dataFeed,\n * executor: new BacktestExecutor({ dataFeed }),\n * calendar,\n * featureCache,\n * freq: '1d',\n * });\n *\n * console.log(result.finalPortfolio.cash);\n * console.log(result.snapshots.length); // one entry per NYSE trading day in 2023\n * ```\n */\nexport async function runBacktest<F extends Features = Features, S = unknown>(\n opts: RunBacktestOptions<F, S>,\n): Promise<BacktestResult<S>> {\n const initialStateValue: S | undefined = opts.strategy.initialState?.();\n const sessions = opts.calendar.sessions(opts.range);\n if (sessions.length === 0) {\n return {\n snapshots: [],\n finalPortfolio: opts.initialPortfolio,\n finalState: initialStateValue,\n bars: opts.featureRuntime?.getAllBars() ?? new Map<AssetId, ReadonlyArray<Bar>>(),\n };\n }\n\n let portfolio = opts.initialPortfolio;\n let state: S | undefined = initialStateValue;\n const snapshots: BacktestSnapshot[] = [];\n\n for (const t of sessions) {\n const universe = opts.strategy.universe(t, portfolio);\n const features = await opts.strategy.features(universe, portfolio, t);\n const buildResult = opts.strategy.build(features, portfolio, state as S, t);\n\n let orders: ReadonlyArray<Order>;\n if (isStateResult(buildResult)) {\n orders = buildResult.orders;\n state = buildResult.state;\n } else {\n // Legacy state-less return shape — state unchanged.\n orders = buildResult;\n }\n\n const fills = await opts.executor.submit(orders, t, portfolio);\n portfolio = applyFills(portfolio, fills, orders);\n snapshots.push({ t, portfolio, orders, fills });\n }\n\n const bars = opts.featureRuntime?.getAllBars() ?? new Map<AssetId, ReadonlyArray<Bar>>();\n return { snapshots, finalPortfolio: portfolio, finalState: state, bars };\n}\n","import type { Bar, Series } from '../interfaces/types';\n\n/**\n * The OHLCV field of a `Bar` that should be used when converting a bar array\n * into a scalar time series. Defaults to `'close'` throughout the feature\n * pipeline unless overridden via `FeatureRuntimeOptions.field`.\n *\n * Variants: `'open'` | `'high'` | `'low'` | `'close'` | `'volume'`.\n */\nexport type BarField = 'open' | 'high' | 'low' | 'close' | 'volume';\n\n/**\n * Drains an `AsyncIterable<Bar>` into a plain `Bar[]` array.\n *\n * Used internally by `FeatureRuntime` to materialise the stream returned by\n * `DataFeed.bars` before passing it to indicator functions that expect a\n * fully-in-memory array. The resulting array is in the same order as the\n * iterable yields (typically chronological).\n *\n * @param it - Any `AsyncIterable<Bar>`, such as the return value of `DataFeed.bars`.\n * @returns A promise that resolves to a `Bar[]` containing every bar yielded\n * by the iterable, in iteration order.\n *\n * @example\n * ```ts\n * import { collectBars } from '@livefolio/sdk';\n *\n * const bars = await collectBars(dataFeed.bars(asset, range, '1d'));\n * // bars is now a Bar[] — safe to index, slice, and pass to barsToSeries\n * ```\n */\nexport async function collectBars(it: AsyncIterable<Bar>): Promise<Bar[]> {\n const out: Bar[] = [];\n for await (const b of it) out.push(b);\n return out;\n}\n\n/**\n * Converts an array of OHLCV bars into a `Series` by extracting a single\n * numeric field from each bar.\n *\n * The resulting `Series` is a readonly array of `{ t: Date; v: number }` points\n * in the same order as `bars`. The timestamp `t` is taken directly from `bar.t`,\n * and `v` is the value of `field` for that bar.\n *\n * @param bars - Source OHLCV bars in chronological order.\n * @param field - Which OHLCV field to extract. Defaults to `'close'`.\n * @returns A `Series` of the same length as `bars`. Returns an empty array when\n * `bars` is empty.\n *\n * @example\n * ```ts\n * import { collectBars, barsToSeries } from '@livefolio/sdk';\n *\n * const bars = await collectBars(dataFeed.bars(asset, range, '1d'));\n * const closeSeries = barsToSeries(bars); // default: 'close'\n * const volumeSeries = barsToSeries(bars, 'volume');\n * ```\n */\nexport function barsToSeries(bars: ReadonlyArray<Bar>, field: BarField = 'close'): Series {\n return bars.map((b) => ({ t: b.t, v: b[field] }));\n}\n\n/**\n * Looks up the value at or immediately before timestamp `t` in a sorted `Series`.\n *\n * Uses binary search to find the largest index `i` where `series[i].t <= t`.\n * This is the standard \"as-of\" lookup used throughout the strategy loop to read\n * the most recent indicator value available on a given session date without\n * peeking into the future.\n *\n * @param series - A `Series` sorted in ascending timestamp order. Behaviour is\n * undefined for unsorted input.\n * @param t - The target date. May fall between two data points or exactly on one.\n * @returns The `v` value of the last data point at or before `t`, or `undefined`\n * if the series is empty or every point comes after `t`.\n *\n * @example\n * ```ts\n * import { seriesAt } from '@livefolio/sdk';\n *\n * const series = [\n * { t: new Date('2023-01-02'), v: 380.0 },\n * { t: new Date('2023-01-03'), v: 385.0 },\n * { t: new Date('2023-01-04'), v: 390.0 },\n * ];\n *\n * seriesAt(series, new Date('2023-01-03')); // => 385.0 (exact match)\n * seriesAt(series, new Date('2023-01-03T12:00:00Z')); // => 385.0 (between points)\n * seriesAt(series, new Date('2023-01-01')); // => undefined (before all points)\n * ```\n */\nexport function seriesAt(series: Series, t: Date): number | undefined {\n if (series.length === 0) return undefined;\n const target = t.getTime();\n // binary search for largest index where series[i].t <= target\n let lo = 0;\n let hi = series.length - 1;\n let ans = -1;\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1;\n if (series[mid]!.t.getTime() <= target) {\n ans = mid;\n lo = mid + 1;\n } else {\n hi = mid - 1;\n }\n }\n return ans < 0 ? undefined : series[ans]!.v;\n}\n","import type { Series } from '../../interfaces/types';\n\n/**\n * Computes a Simple Moving Average (SMA) over a price series.\n *\n * Math definition:\n * ```\n * SMA[i] = (series[i] + series[i-1] + ... + series[i-period+1]) / period\n * ```\n *\n * Warmup: the first output point corresponds to index `period - 1` in the input.\n * Inputs `series[0]` through `series[period - 2]` have no SMA value and are\n * excluded from the output entirely (no `undefined` placeholders; the output\n * array is shorter than the input).\n *\n * Edge cases:\n * - `period <= 0` — throws `Error`.\n * - `series.length < period` — returns `[]` (not enough data for even one window).\n * - `series.length === period` — returns a single-point `Series`.\n *\n * @param series - Input price series sorted in ascending timestamp order.\n * @param period - Window size in bars. Must be a positive integer.\n * @returns A `Series` of length `max(0, series.length - period + 1)`. Each point's\n * timestamp `t` is taken from the last bar in its window (`series[i + period - 1]`).\n *\n * @example\n * ```ts\n * import { sma } from '@livefolio/sdk';\n *\n * const prices = [\n * { t: new Date('2023-01-02'), v: 100 },\n * { t: new Date('2023-01-03'), v: 110 },\n * { t: new Date('2023-01-04'), v: 120 },\n * { t: new Date('2023-01-05'), v: 130 },\n * ];\n *\n * const result = sma(prices, 3);\n * // result.length === 2\n * // result[0] => { t: new Date('2023-01-04'), v: 110 } // (100+110+120)/3\n * // result[1] => { t: new Date('2023-01-05'), v: 120 } // (110+120+130)/3\n * ```\n */\nexport function sma(series: Series, period: number): Series {\n if (period <= 0) throw new Error(`sma: period must be positive, got ${period}`);\n if (series.length < period) return [];\n const out: { t: Date; v: number }[] = [];\n let sum = 0;\n for (let i = 0; i < period; i++) sum += series[i]!.v;\n out.push({ t: series[period - 1]!.t, v: sum / period });\n for (let i = period; i < series.length; i++) {\n sum += series[i]!.v - series[i - period]!.v;\n out.push({ t: series[i]!.t, v: sum / period });\n }\n return out;\n}\n","import type { Series } from '../../interfaces/types';\n\n/**\n * Computes an Exponential Moving Average (EMA) over a price series.\n *\n * Math definition:\n * ```\n * k = 2 / (period + 1) // smoothing factor\n * EMA[0] = SMA(series[0..period-1]) // seeded from simple average\n * EMA[i] = series[i] * k + EMA[i-1] * (1 - k)\n * ```\n *\n * Warmup: the first `period - 1` input bars are consumed to seed the SMA\n * initial value. The first EMA output point corresponds to input index\n * `period - 1`; subsequent points are computed from the recursive formula.\n * The output array is shorter than the input (no `undefined` placeholders).\n *\n * Edge cases:\n * - `period <= 0` — throws `Error`.\n * - `series.length < period` — returns `[]` (not enough data to seed the EMA).\n * - `series.length === period` — returns a single-point `Series` equal to the\n * simple average of all input values.\n *\n * @param series - Input price series sorted in ascending timestamp order.\n * @param period - Lookback window in bars. Must be a positive integer. Controls\n * the smoothing factor `k = 2 / (period + 1)`: smaller periods react faster\n * to recent prices.\n * @returns A `Series` of length `max(0, series.length - period + 1)`. Each\n * point's timestamp `t` is taken from the corresponding input bar.\n *\n * @example\n * ```ts\n * import { ema } from '@livefolio/sdk';\n *\n * const prices = [\n * { t: new Date('2023-01-02'), v: 100 },\n * { t: new Date('2023-01-03'), v: 110 },\n * { t: new Date('2023-01-04'), v: 120 },\n * { t: new Date('2023-01-05'), v: 130 },\n * ];\n *\n * const result = ema(prices, 3);\n * // result.length === 2\n * // result[0] => { t: new Date('2023-01-04'), v: 110 } // SMA seed: (100+110+120)/3\n * // result[1] => { t: new Date('2023-01-05'), v: ~116.7 } // EMA: 130*0.5 + 110*0.5\n * ```\n */\nexport function ema(series: Series, period: number): Series {\n if (period <= 0) throw new Error(`ema: period must be positive, got ${period}`);\n if (series.length < period) return [];\n const k = 2 / (period + 1);\n const out: { t: Date; v: number }[] = [];\n let sum = 0;\n for (let i = 0; i < period; i++) sum += series[i]!.v;\n let prev = sum / period;\n out.push({ t: series[period - 1]!.t, v: prev });\n for (let i = period; i < series.length; i++) {\n prev = series[i]!.v * k + prev * (1 - k);\n out.push({ t: series[i]!.t, v: prev });\n }\n return out;\n}\n","import type { Series } from '../../interfaces/types';\n\n/**\n * Computes the Relative Strength Index (RSI) using Wilder's smoothing method.\n *\n * Math definition:\n * ```\n * changes[i] = series[i] - series[i-1]\n *\n * // Seed from simple averages of the first `period` changes:\n * avgGain[0] = mean(max(changes[0..period-1], 0))\n * avgLoss[0] = mean(max(-changes[0..period-1], 0))\n *\n * // Wilder's smoothing for subsequent periods:\n * avgGain[i] = (avgGain[i-1] * (period-1) + gain[i]) / period\n * avgLoss[i] = (avgLoss[i-1] * (period-1) + loss[i]) / period\n *\n * RS[i] = avgGain[i] / avgLoss[i]\n * RSI[i] = 100 - 100 / (1 + RS[i])\n * ```\n *\n * Special case: when `avgLoss === 0`, RSI is clamped to 100 (infinite RS means\n * no losing periods in the window).\n *\n * Warmup: requires `period + 1` input bars to produce the first RSI value\n * (one extra bar for the initial change calculation). The first output point\n * corresponds to input index `period`. The output array is shorter than the\n * input (no `undefined` placeholders).\n *\n * Edge cases:\n * - `period <= 0` — throws `Error`.\n * - `series.length < period + 1` — returns `[]`.\n * - Flat price series (all changes = 0) — returns RSI values of 100 because\n * `avgLoss` stays 0.\n *\n * @param series - Input price series sorted in ascending timestamp order.\n * @param period - Lookback window in bars for Wilder's smoothing. Must be a\n * positive integer; 14 is the conventional default.\n * @returns A `Series` of length `max(0, series.length - period)`. Each point's\n * timestamp `t` is taken from the corresponding input bar. Values are in\n * the range `[0, 100]`.\n *\n * @example\n * ```ts\n * import { rsi } from '@livefolio/sdk';\n *\n * // Minimal example: 5 bars, period 3 → 2 RSI values\n * const prices = [\n * { t: new Date('2023-01-02'), v: 100 },\n * { t: new Date('2023-01-03'), v: 102 },\n * { t: new Date('2023-01-04'), v: 101 },\n * { t: new Date('2023-01-05'), v: 105 },\n * { t: new Date('2023-01-06'), v: 104 },\n * ];\n *\n * const result = rsi(prices, 3);\n * // result.length === 2\n * // result[0].t => new Date('2023-01-05')\n * // result[1].t => new Date('2023-01-06')\n * // values are in [0, 100]\n * ```\n */\nexport function rsi(series: Series, period: number): Series {\n if (period <= 0) throw new Error(`rsi: period must be positive, got ${period}`);\n if (series.length < period + 1) return [];\n const changes: number[] = [];\n for (let i = 1; i < series.length; i++) {\n changes.push(series[i]!.v - series[i - 1]!.v);\n }\n let avgGain = 0;\n let avgLoss = 0;\n for (let i = 0; i < period; i++) {\n if (changes[i]! > 0) avgGain += changes[i]!;\n else avgLoss += Math.abs(changes[i]!);\n }\n avgGain /= period;\n avgLoss /= period;\n const out: { t: Date; v: number }[] = [];\n const rs = avgLoss === 0 ? 100 : avgGain / avgLoss;\n out.push({\n t: series[period]!.t,\n v: avgLoss === 0 ? 100 : 100 - 100 / (1 + rs),\n });\n for (let i = period; i < changes.length; i++) {\n const gain = changes[i]! > 0 ? changes[i]! : 0;\n const loss = changes[i]! < 0 ? Math.abs(changes[i]!) : 0;\n avgGain = (avgGain * (period - 1) + gain) / period;\n avgLoss = (avgLoss * (period - 1) + loss) / period;\n const smoothRs = avgLoss === 0 ? 100 : avgGain / avgLoss;\n out.push({\n t: series[i + 1]!.t,\n v: avgLoss === 0 ? 100 : 100 - 100 / (1 + smoothRs),\n });\n }\n return out;\n}\n","import type { Series } from '../../interfaces/types';\n\n/**\n * Controls whether `returnSeries` computes percentage or absolute returns.\n *\n * - `'pct'` (default) — percentage return: `(curr - prev) / prev`. The result is\n * a dimensionless ratio (e.g. `0.05` means +5 %).\n * - `'abs'` — absolute price difference: `curr - prev`. The result is in the same\n * units as the input price series.\n */\nexport type ReturnMode = 'pct' | 'abs';\n\n/**\n * Computes a rolling period return over a price series.\n *\n * Math definition:\n * ```\n * // Percentage (default):\n * return[i] = (series[i] - series[i - period]) / series[i - period]\n *\n * // Absolute:\n * return[i] = series[i] - series[i - period]\n * ```\n *\n * Warmup: the first `period` bars are consumed as the lookback window for the\n * first output. The first output point corresponds to input index `period`.\n * The output array is shorter than the input (no `undefined` placeholders).\n *\n * Edge cases:\n * - `period <= 0` — throws `Error`.\n * - `series.length <= period` — returns `[]` (needs strictly more than `period` bars).\n * - `mode === 'pct'` with `prev === 0` — produces `Infinity` or `NaN`; callers\n * should filter or guard against zero-price series.\n *\n * @param series - Input price series sorted in ascending timestamp order.\n * @param period - Lookback distance in bars. A value of `1` gives a single-bar\n * (daily) return; larger values give multi-bar returns.\n * @param mode - Whether to return a percentage ratio or an absolute difference.\n * Defaults to `'pct'`.\n * @returns A `Series` of length `max(0, series.length - period)`. Each point's\n * timestamp `t` is taken from `series[i]` (the later of the two bars).\n *\n * @example\n * ```ts\n * import { returnSeries } from '@livefolio/sdk';\n *\n * const prices = [\n * { t: new Date('2023-01-02'), v: 100 },\n * { t: new Date('2023-01-03'), v: 105 },\n * { t: new Date('2023-01-04'), v: 110 },\n * ];\n *\n * const pct = returnSeries(prices, 1);\n * // pct[0] => { t: new Date('2023-01-03'), v: 0.05 } // (105-100)/100\n * // pct[1] => { t: new Date('2023-01-04'), v: ~0.048 } // (110-105)/105\n *\n * const abs = returnSeries(prices, 1, 'abs');\n * // abs[0] => { t: new Date('2023-01-03'), v: 5 } // 105-100\n * // abs[1] => { t: new Date('2023-01-04'), v: 5 } // 110-105\n *\n * // Two-bar return\n * const twoBar = returnSeries(prices, 2);\n * // twoBar[0] => { t: new Date('2023-01-04'), v: 0.1 } // (110-100)/100\n * ```\n */\nexport function returnSeries(series: Series, period: number, mode: ReturnMode = 'pct'): Series {\n if (period <= 0) throw new Error(`returnSeries: period must be positive, got ${period}`);\n if (series.length <= period) return [];\n const out: { t: Date; v: number }[] = [];\n for (let i = period; i < series.length; i++) {\n const curr = series[i]!.v;\n const prev = series[i - period]!.v;\n const v = mode === 'abs' ? curr - prev : (curr - prev) / prev;\n out.push({ t: series[i]!.t, v });\n }\n return out;\n}\n","import type { Series } from '../../interfaces/types';\n\n/**\n * Computes a rolling historical volatility as the population standard deviation\n * of daily log-like returns over a sliding window.\n *\n * Math definition:\n * ```\n * dailyReturn[i] = series[i] / series[i-1] - 1 // simple period return\n *\n * // For each window of `period` daily returns ending at index i:\n * mean = Σ dailyReturn[i..i-period+1] / period\n * variance = Σ (dailyReturn[j] - mean)² / period // population variance\n * vol[i] = sqrt(variance)\n * ```\n *\n * The result is the per-bar standard deviation expressed as a fraction (e.g.\n * `0.012` ≈ 1.2 % daily volatility). To annualise, multiply by `sqrt(252)` for\n * daily bars.\n *\n * Warmup: requires `period + 1` price bars to produce the first volatility value:\n * one extra bar to compute the first daily return, then `period` returns for the\n * first window. The first output point corresponds to the `period`-th daily-return\n * index. The output array is shorter than the input (no `undefined` placeholders).\n *\n * Edge cases:\n * - `period <= 0` — throws `Error`.\n * - `series.length < period + 1` — returns `[]`.\n * - Flat price series (all returns = 0) — returns volatility values of `0`.\n *\n * @param series - Input price series sorted in ascending timestamp order. Values\n * must be positive (non-zero); zero prices produce `NaN` daily returns.\n * @param period - Window size in daily-return bars. Must be a positive integer;\n * common values are 20 (≈ 1 month) or 252 (1 year) for daily data.\n * @returns A `Series` of length `max(0, series.length - period)`. Each point's\n * timestamp `t` is taken from the last daily-return bar in its window.\n *\n * @example\n * ```ts\n * import { volatility } from '@livefolio/sdk';\n *\n * // 5 price bars → 4 daily returns → 1 vol point (period=4)\n * const prices = [\n * { t: new Date('2023-01-02'), v: 100 },\n * { t: new Date('2023-01-03'), v: 101 },\n * { t: new Date('2023-01-04'), v: 99 },\n * { t: new Date('2023-01-05'), v: 102 },\n * { t: new Date('2023-01-06'), v: 100 },\n * ];\n *\n * const vol = volatility(prices, 4);\n * // vol.length === 1\n * // vol[0].t => new Date('2023-01-06')\n * // vol[0].v => population std-dev of the 4 daily returns (≈ 0.012)\n * ```\n */\nexport function volatility(series: Series, period: number): Series {\n if (period <= 0) throw new Error(`volatility: period must be positive, got ${period}`);\n if (series.length < period + 1) return [];\n const dailyReturns: { t: Date; v: number }[] = [];\n for (let i = 1; i < series.length; i++) {\n dailyReturns.push({\n t: series[i]!.t,\n v: series[i]!.v / series[i - 1]!.v - 1,\n });\n }\n if (dailyReturns.length < period) return [];\n const out: { t: Date; v: number }[] = [];\n for (let i = period - 1; i < dailyReturns.length; i++) {\n const window = dailyReturns.slice(i - period + 1, i + 1);\n const mean = window.reduce((s, r) => s + r.v, 0) / period;\n const variance = window.reduce((s, r) => s + (r.v - mean) ** 2, 0) / period;\n out.push({ t: dailyReturns[i]!.t, v: Math.sqrt(variance) });\n }\n return out;\n}\n","import type { Series } from '../../interfaces/types';\n\n/**\n * Computes the rolling drawdown relative to the period high for each bar.\n *\n * Math definition:\n * ```\n * rollingMax[i] = max(series[i-period+1], ..., series[i])\n * drawdown[i] = (series[i] - rollingMax[i]) / rollingMax[i]\n * ```\n *\n * The result is a non-positive fraction (e.g. `-0.15` means the current price\n * is 15 % below the period high). A value of `0` means the current price equals\n * the rolling maximum — i.e. the asset is at a new high within the window.\n *\n * Warmup: the first output point corresponds to input index `period - 1` (the\n * first complete window). The output array is shorter than the input by\n * `period - 1` points (no `undefined` placeholders).\n *\n * Edge cases:\n * - `period <= 0` — throws `Error`.\n * - `series.length < period` — returns `[]`.\n * - All prices in a window are equal — returns `0` (current equals max).\n * - Zero prices in the window — produces `NaN` (division by zero); callers\n * should guard against zero-price series.\n *\n * @param series - Input price series sorted in ascending timestamp order. Values\n * should be positive (non-zero) to avoid `NaN` results.\n * @param period - Rolling window size in bars. Must be a positive integer.\n * A value of `1` always returns `0` (current equals one-bar max).\n * @returns A `Series` of length `max(0, series.length - period + 1)`. Each\n * point's timestamp `t` is taken from `series[i]` (the last bar in its window).\n * Values are in the range `(-∞, 0]` but in practice within `[-1, 0]` for\n * positive price series.\n *\n * @example\n * ```ts\n * import { drawdown } from '@livefolio/sdk';\n *\n * const prices = [\n * { t: new Date('2023-01-02'), v: 100 },\n * { t: new Date('2023-01-03'), v: 105 },\n * { t: new Date('2023-01-04'), v: 95 },\n * { t: new Date('2023-01-05'), v: 98 },\n * ];\n *\n * const dd = drawdown(prices, 3);\n * // dd.length === 2\n * // dd[0].t => new Date('2023-01-04'), dd[0].v => (95-105)/105 ≈ -0.095\n * // dd[1].t => new Date('2023-01-05'), dd[1].v => (98-105)/105 ≈ -0.067\n * ```\n */\nexport function drawdown(series: Series, period: number): Series {\n if (period <= 0) throw new Error(`drawdown: period must be positive, got ${period}`);\n if (series.length < period) return [];\n const out: { t: Date; v: number }[] = [];\n for (let i = period - 1; i < series.length; i++) {\n let max = -Infinity;\n for (let j = i - period + 1; j <= i; j++) {\n if (series[j]!.v > max) max = series[j]!.v;\n }\n out.push({ t: series[i]!.t, v: (series[i]!.v - max) / max });\n }\n return out;\n}\n","import type { Series } from '../interfaces/types';\nimport { sma } from './indicators/sma';\nimport { ema } from './indicators/ema';\nimport { rsi } from './indicators/rsi';\nimport { returnSeries, type ReturnMode } from './indicators/return';\nimport { volatility } from './indicators/volatility';\nimport { drawdown } from './indicators/drawdown';\n\n/**\n * A discriminated union describing every built-in feature kind and its parameters.\n *\n * Each variant has a `kind` field that identifies the indicator together with the\n * parameters that fully determine its output. `FeatureSpec` objects are used as\n * cache keys (via `paramsHash`) and as dispatch tokens (via `getFeatureCompute`).\n *\n * Variants:\n * - `{ kind: 'price' }` — raw price series; no parameters.\n * - `{ kind: 'sma'; period: number }` — simple moving average over `period` bars.\n * - `{ kind: 'ema'; period: number }` — exponential moving average seeded from an SMA.\n * - `{ kind: 'rsi'; period: number }` — Wilder's Relative Strength Index.\n * - `{ kind: 'return'; period: number; mode?: ReturnMode }` — period return; percent or absolute.\n * - `{ kind: 'volatility'; period: number }` — rolling population standard deviation of daily returns.\n * - `{ kind: 'drawdown'; period: number }` — drawdown relative to the rolling maximum.\n */\nexport type FeatureSpec =\n | { kind: 'price' }\n | { kind: 'sma'; period: number }\n | { kind: 'ema'; period: number }\n | { kind: 'rsi'; period: number }\n | { kind: 'return'; period: number; mode?: ReturnMode }\n | { kind: 'volatility'; period: number }\n | { kind: 'drawdown'; period: number };\n\n/**\n * String literal union of all valid feature `kind` values derived from `FeatureSpec`.\n *\n * Useful for typing registry keys and dispatch tables without manually listing all\n * variants: `'price' | 'sma' | 'ema' | 'rsi' | 'return' | 'volatility' | 'drawdown'`.\n */\nexport type FeatureKind = FeatureSpec['kind'];\n\n/**\n * A pure function that computes a feature `Series` from an input price `Series` and the typed\n * `FeatureSpec` describing the indicator's parameters. Implementations must be deterministic and\n * side-effect free — the SDK uses the function as a content-addressed dispatch token via\n * {@link getFeatureCompute} and as the registration target for {@link defineFeature}.\n *\n * @param series - Input price series (typically the asset's close prices).\n * @param spec - Typed indicator spec carrying the parameters relevant to `kind`.\n * @returns The computed feature series, aligned to `series` on `t`.\n */\nexport type ComputeFn = (series: Series, spec: FeatureSpec) => Series;\n\nconst registry = new Map<FeatureKind, ComputeFn>();\n\n/**\n * Registers a compute function for a new or existing feature kind.\n *\n * Throws if `kind` is already registered. Call this once at module initialisation\n * time (top-level) to extend the built-in feature registry with custom indicators.\n * The compute function receives the raw price `Series` and the full typed spec\n * object for that kind; it must return a `Series` of the same or shorter length.\n *\n * @param kind - The `FeatureKind` string that identifies this indicator.\n * @param compute - Pure function that transforms a price series according to `spec`.\n * The `spec` argument is narrowed to `Extract<FeatureSpec, { kind: K }>` so\n * TypeScript enforces that only the correct parameter shape is accessed.\n * @returns `void`. Registration is a side-effectful, one-time operation.\n *\n * @example\n * ```ts\n * import { defineFeature } from '@livefolio/sdk';\n *\n * // Register a custom 'zscore' feature kind\n * defineFeature('sma', (series, spec) => {\n * // Already built-in; this would throw due to duplicate registration.\n * // Shown here for illustration only.\n * return series;\n * });\n * ```\n */\nexport function defineFeature<K extends FeatureKind>(\n kind: K,\n compute: (series: Series, spec: Extract<FeatureSpec, { kind: K }>) => Series,\n): void {\n if (registry.has(kind)) {\n throw new Error(`defineFeature: kind \"${kind}\" is already registered`);\n }\n registry.set(kind, compute as ComputeFn);\n}\n\n/**\n * Retrieves the registered compute function for a given feature kind.\n *\n * Throws `Error` if the kind has not been registered. In normal usage the\n * built-in `defineFeature` calls at the bottom of this module pre-populate the\n * registry, so this function only throws for custom kinds that were never registered.\n *\n * @param kind - The `FeatureKind` string to look up.\n * @returns The `ComputeFn` registered for `kind`.\n *\n * @example\n * ```ts\n * import { getFeatureCompute } from '@livefolio/sdk';\n *\n * const computeSma = getFeatureCompute('sma');\n * const result = computeSma(priceSeries, { kind: 'sma', period: 20 });\n * ```\n */\nexport function getFeatureCompute(kind: FeatureKind): ComputeFn {\n const fn = registry.get(kind);\n if (!fn) throw new Error(`getFeatureCompute: unknown feature kind \"${kind}\"`);\n return fn;\n}\n\n/**\n * Recursive canonicalization: sort object keys, skip undefined values,\n * preserve null + array order, recurse into nested objects.\n */\nfunction canonicalize(value: unknown): unknown {\n if (value === null || typeof value !== 'object') return value;\n if (Array.isArray(value)) return value.map(canonicalize);\n const obj = value as Record<string, unknown>;\n const sorted: Record<string, unknown> = {};\n for (const k of Object.keys(obj).sort()) {\n if (obj[k] === undefined) continue;\n sorted[k] = canonicalize(obj[k]);\n }\n return sorted;\n}\n\n/**\n * Returns a deterministic string that depends only on the spec's logical\n * content — key order and undefined optional fields are normalized away.\n *\n * The same logical spec always produces the same hash regardless of how the\n * object was constructed (different key insertion order, explicit `undefined`\n * vs. omitted optional field). This string is used as the `paramsHash` field\n * in `FeatureKey` to ensure cache-hit equivalence for semantically identical\n * specs.\n *\n * Callers depend on this function's contract (same logical content → same\n * result), not on the encoding. Future replacement with SHA-256 is\n * non-breaking.\n *\n * @param spec - The `FeatureSpec` object to hash.\n * @returns A JSON string with sorted keys and no undefined values.\n *\n * @example\n * ```ts\n * import { paramsHash } from '@livefolio/sdk';\n *\n * paramsHash({ kind: 'sma', period: 20 });\n * // => '{\"kind\":\"sma\",\"period\":20}'\n *\n * // Optional field omitted vs explicitly undefined — same result:\n * paramsHash({ kind: 'return', period: 10 });\n * paramsHash({ kind: 'return', period: 10, mode: undefined });\n * // both => '{\"kind\":\"return\",\"period\":10}'\n * ```\n */\nexport function paramsHash(spec: FeatureSpec): string {\n return JSON.stringify(canonicalize(spec));\n}\n\ndefineFeature('price', (series) => series);\ndefineFeature('sma', (series, spec) => sma(series, spec.period));\ndefineFeature('ema', (series, spec) => ema(series, spec.period));\ndefineFeature('rsi', (series, spec) => rsi(series, spec.period));\ndefineFeature('return', (series, spec) => returnSeries(series, spec.period, spec.mode));\ndefineFeature('volatility', (series, spec) => volatility(series, spec.period));\ndefineFeature('drawdown', (series, spec) => drawdown(series, spec.period));\n","import type { Asset, AssetId, Bar, DateRange, Frequency, Series } from '../interfaces/types';\nimport type { DataFeed } from '../interfaces/data-feed';\nimport type { FeatureCache, FeatureKey } from '../interfaces/feature-cache';\nimport { collectBars, barsToSeries, type BarField } from './series-utils';\nimport { getFeatureCompute, paramsHash, type FeatureSpec } from './spec';\n\n/** Sentinel range used as the `range` field in cache keys for streaming-mode\n * computations. Epoch-zero dates are never valid historical ranges, so this\n * value cannot collide with any real historical cache entry. */\nconst STREAMING_SENTINEL_RANGE: DateRange = { from: new Date(0), to: new Date(0) };\n\n/** Stub DataFeed used when no `dataFeed` is supplied in streaming mode.\n * Throws immediately if `.bars` is ever called, which surfaces accidental\n * historical-mode code paths at runtime rather than silently returning empty. */\nconst STREAMING_STUB_FEED: DataFeed = {\n bars: () => {\n throw new Error('dataFeed.bars called on streaming-mode FeatureRuntime');\n },\n};\n\n/**\n * Configuration for a `FeatureRuntime` instance.\n *\n * Accepts two shapes — select via the `mode` discriminant:\n *\n * - **`'historical'`** (default, `mode` may be omitted): range-bounded backtest\n * mode. Bars are fetched from `DataFeed` once per asset and cached in memory.\n * - **`'streaming'`**: open-ended live mode. No fixed `range`; bars are pushed\n * in via `appendBar`. Indicator computation reads from the growing in-process\n * buffer instead of calling `DataFeed.bars`.\n *\n * The historical variant is backward-compatible — existing callers that omit\n * `mode` compile and behave identically to before.\n */\nexport type FeatureRuntimeOptions =\n | {\n /** Selects historical (range-bounded) mode. May be omitted; defaults to\n * `'historical'`. */\n mode?: 'historical';\n /** The market-data source used to fetch OHLCV bars. */\n dataFeed: DataFeed;\n /**\n * Persistent indicator cache. Use `MemoryFeatureCache` for a single backtest\n * run, or supply a cross-process cache implementation to share results across\n * multiple runs or processes.\n */\n featureCache: FeatureCache;\n /**\n * The date range over which bars are fetched. This should span at least the\n * backtest range plus any indicator warmup period (e.g. `period - 1` extra\n * bars for SMA/EMA). `FeatureRuntime` does not automatically extend the range\n * for warmup — the caller is responsible for providing enough history.\n */\n range: DateRange;\n /**\n * Bar frequency forwarded to `DataFeed.bars` and embedded in cache keys.\n * Must match the granularity expected by the indicators (e.g. `'1d'` for\n * daily SMA/EMA).\n */\n freq: Frequency;\n /**\n * Which OHLCV field to use as the scalar price series. Defaults to `'close'`.\n * All indicators within a single `FeatureRuntime` instance share the same field.\n */\n field?: BarField;\n }\n | {\n /** Selects streaming (open-ended live) mode. Required. */\n mode: 'streaming';\n /** Optional — not called in streaming mode. Omit in streaming-only usages.\n * If provided it is stored but never invoked; supply only when sharing an\n * options object that also carries a `DataFeed` for other purposes. */\n dataFeed?: DataFeed;\n /**\n * Persistent indicator cache. In streaming mode the cache is bypassed\n * entirely — every `compute` call recomputes from the in-memory bar buffer.\n * The instance is still required so that a shared cache object can be\n * passed without special-casing at the call site.\n */\n featureCache: FeatureCache;\n /**\n * Bar frequency embedded in cache keys. Must match the granularity of the\n * bars pushed via `appendBar`.\n */\n freq: Frequency;\n /**\n * Which OHLCV field to use as the scalar price series. Defaults to `'close'`.\n */\n field?: BarField;\n /**\n * Optional seed bars per asset (keyed by `AssetId`), used to bootstrap the\n * streaming buffer from a prior historical run's `BacktestResult`.\n * Bars must already be in ascending `t` order per asset.\n */\n initialBars?: ReadonlyMap<AssetId, ReadonlyArray<Bar>>;\n };\n\n/**\n * Orchestrates indicator computation for a single backtest run or a live\n * streaming session.\n *\n * `FeatureRuntime` is the bridge between raw OHLCV data (via `DataFeed`) and the\n * typed indicator functions registered in the feature registry. It handles:\n *\n * - **Bar fetching** (historical mode) — Calls `DataFeed.bars` once per\n * `(asset, range, freq)` tuple and caches the resulting `Series` in memory for\n * the lifetime of the instance. Concurrent calls for the same asset share a\n * single in-flight promise; there is no redundant fetching even if `compute` is\n * called from multiple `Promise.all` branches simultaneously.\n * - **Bar buffering** (streaming mode) — Bars are pushed in via `appendBar`.\n * `compute` reads directly from the in-memory buffer; `DataFeed.bars` is never\n * called.\n * - **Indicator dispatch** — Delegates computation to the function registered via\n * `defineFeature` for the given `FeatureSpec.kind`.\n * - **Persistent caching** (historical mode only) — Checks `FeatureCache` before\n * computing. On a miss, the result is stored in the cache. Subsequent calls with\n * the same `(spec, asset)` combination return instantly from cache without\n * re-fetching bars.\n *\n * Caching semantics:\n * - Historical mode: cache keys incorporate `spec`, `asset.id`, `range`, and `freq`.\n * Results are read from and written to `featureCache`.\n * - Streaming mode: `featureCache` is bypassed entirely — every `compute` call\n * recomputes from the growing in-memory bar buffer. The `seriesCache` (per-asset\n * in-memory base-series cache) is the only cache layer; it is invalidated on each\n * `appendBar` so the next `compute` sees the updated buffer.\n * - Calling `appendBar` invalidates the in-memory series cache for that asset so\n * the next `compute` call rebuilds the series from the updated buffer.\n *\n * @example Historical mode (default)\n * ```ts\n * import {\n * FeatureRuntime,\n * MemoryFeatureCache,\n * seriesAt,\n * } from '@livefolio/sdk';\n *\n * const runtime = new FeatureRuntime({\n * dataFeed,\n * featureCache: new MemoryFeatureCache(),\n * range: { from: new Date('2022-01-01'), to: new Date('2023-12-31') },\n * freq: '1d',\n * });\n *\n * const spy = { kind: 'equity' as const, id: 'US:SPY', symbol: 'SPY' };\n * const smaSeries = await runtime.compute({ kind: 'sma', period: 20 }, spy);\n * const latestSma = seriesAt(smaSeries, new Date('2023-06-15'));\n * // => number | undefined\n * ```\n *\n * @example Streaming mode\n * ```ts\n * const runtime = new FeatureRuntime({\n * featureCache: new MemoryFeatureCache(),\n * mode: 'streaming',\n * freq: '1d',\n * initialBars, // optional seed from BacktestResult\n * });\n *\n * runtime.appendBar(spy, latestBar);\n * const smaSeries = await runtime.compute({ kind: 'sma', period: 20 }, spy);\n * ```\n */\nexport class FeatureRuntime {\n private readonly mode: 'historical' | 'streaming';\n private readonly dataFeed: DataFeed;\n private readonly featureCache: FeatureCache;\n private readonly range: DateRange | null;\n private readonly freq: Frequency;\n private readonly field: BarField;\n /** Per-asset bar buffer used in streaming mode. */\n private readonly streamingBars: Map<AssetId, Bar[]>;\n /** Per-asset bar buffer accumulated in historical mode after bars are fetched from DataFeed. */\n private readonly historicalBars: Map<AssetId, Bar[]>;\n /** Per-asset in-flight Series promise — shared across concurrent `compute` calls\n * for the same asset to avoid redundant bar fetching (historical) or rebuilding\n * (streaming). Invalidated on `appendBar`. */\n private readonly seriesCache: Map<AssetId, Promise<Series>>;\n\n constructor(opts: FeatureRuntimeOptions) {\n this.mode = opts.mode ?? 'historical';\n this.featureCache = opts.featureCache;\n this.freq = opts.freq;\n this.field = opts.field ?? 'close';\n this.seriesCache = new Map();\n this.streamingBars = new Map();\n this.historicalBars = new Map();\n\n if (opts.mode === 'streaming') {\n this.dataFeed = opts.dataFeed ?? STREAMING_STUB_FEED;\n this.range = null;\n if (opts.initialBars) {\n for (const [assetId, bars] of opts.initialBars) {\n this.streamingBars.set(assetId, [...bars]);\n }\n }\n } else {\n this.dataFeed = opts.dataFeed;\n this.range = opts.range;\n }\n }\n\n /**\n * Appends a bar to the streaming buffer for the given asset.\n *\n * Bars must be provided in non-decreasing `t` order per asset. A bar with\n * the same `t` as the most recent buffered bar replaces it in place — this\n * is the mark-to-market wiggle path used by `runLive`, where each incoming\n * tick updates the running open/high/low/close of the in-flight session bar.\n * A bar with `t` strictly greater than the buffered tail starts a fresh\n * in-flight bar (e.g. at session boundaries). A bar with `t` strictly less\n * than the buffered tail throws.\n *\n * Also invalidates the in-memory series cache for the asset so the next\n * `compute` call rebuilds the series from the updated buffer.\n *\n * @throws If called on a historical-mode runtime.\n * @throws If `bar.t` is strictly less than the last buffered bar's `t`.\n */\n appendBar(asset: Asset, bar: Bar): void {\n if (this.mode !== 'streaming') {\n throw new Error('appendBar is only valid in streaming mode');\n }\n const buf = this.streamingBars.get(asset.id) ?? [];\n const last = buf[buf.length - 1];\n if (last !== undefined && bar.t.getTime() < last.t.getTime()) {\n throw new Error(\n `appendBar: bars must be in non-decreasing t order; got ${bar.t.toISOString()} after ${last.t.toISOString()}`,\n );\n }\n if (last !== undefined && bar.t.getTime() === last.t.getTime()) {\n // Same-t mark-to-market wiggle: replace the in-flight bar in place.\n // Used by `runLive` to update the running OHLC of today's bar on each\n // tick so feature computation sees the live close.\n buf[buf.length - 1] = bar;\n } else {\n buf.push(bar);\n }\n this.streamingBars.set(asset.id, buf);\n // Invalidate cached series so next compute rebuilds from updated buffer.\n this.seriesCache.delete(asset.id);\n }\n\n private baseSeries(asset: Asset): Promise<Series> {\n const cached = this.seriesCache.get(asset.id);\n if (cached) return cached;\n\n let p: Promise<Series>;\n if (this.mode === 'streaming') {\n const buf = this.streamingBars.get(asset.id) ?? [];\n p = Promise.resolve(barsToSeries(buf, this.field));\n } else {\n // Historical mode: fetch from DataFeed and cache.\n p = (async () => {\n const bars = await collectBars(this.dataFeed.bars(asset, this.range!, this.freq));\n this.historicalBars.set(asset.id, bars);\n return barsToSeries(bars, this.field);\n })();\n }\n\n this.seriesCache.set(asset.id, p);\n return p;\n }\n\n /**\n * Returns the bar buffer for `asset`, or an empty array if none has been\n * fetched/buffered yet.\n *\n * In historical mode this is populated after the first `compute` call that\n * triggers a bar fetch for the asset. In streaming mode it reflects all bars\n * pushed via `appendBar`.\n */\n getBars(asset: Asset): ReadonlyArray<Bar> {\n return this.streamingBars.get(asset.id) ?? this.historicalBars.get(asset.id) ?? [];\n }\n\n /**\n * Returns the full per-asset bar map (keyed by `AssetId`). Merges historical\n * and streaming buffers (streaming wins on collision, but in practice an\n * instance is in one mode at a time so collisions don't occur).\n *\n * Returns a fresh `Map` — callers cannot mutate the internal state.\n */\n getAllBars(): ReadonlyMap<AssetId, ReadonlyArray<Bar>> {\n const merged = new Map<AssetId, ReadonlyArray<Bar>>();\n for (const [id, bars] of this.historicalBars) merged.set(id, bars);\n for (const [id, bars] of this.streamingBars) merged.set(id, bars);\n return merged;\n }\n\n private cacheKey(spec: FeatureSpec, asset: Asset): FeatureKey {\n return {\n feature: spec.kind,\n paramsHash: paramsHash(spec),\n scope: { kind: 'asset', asset: asset.id },\n range: this.mode === 'streaming' ? STREAMING_SENTINEL_RANGE : this.range!,\n freq: this.freq,\n };\n }\n\n /**\n * Computes (or retrieves from cache) the output `Series` for a given feature\n * spec applied to a specific asset.\n *\n * **Historical mode:** on the first call for a `(spec, asset)` pair:\n * 1. Fetches or reuses the in-memory base `Series` for the asset.\n * 2. Dispatches to the registered compute function for `spec.kind`.\n * 3. Stores the result in `featureCache`.\n * On subsequent calls, returns the cached `Series` directly from `featureCache`.\n *\n * **Streaming mode:** reads from the in-memory bar buffer populated via\n * `appendBar`. `DataFeed.bars` is never called. The persistent `featureCache`\n * is bypassed entirely — results are never read from or written to it.\n * The in-memory `seriesCache` (base series per asset) is the only cache layer\n * and is invalidated on each `appendBar`, so every `compute` after a new bar\n * reflects the updated buffer.\n *\n * @param spec - The feature specification describing which indicator to compute\n * and its parameters (e.g. `{ kind: 'sma', period: 20 }`).\n * @param asset - The asset for which to compute the feature. The asset's `id`\n * is used both for data fetching and cache key construction.\n * @returns A promise that resolves to the computed `Series`. The series length\n * is determined by the indicator's warmup: for example, SMA(20) returns\n * `series.length - 19` data points. Returns an empty array when the\n * base series is shorter than the indicator's warmup period.\n *\n * @example\n * ```ts\n * const spy = { kind: 'equity' as const, id: 'US:SPY', symbol: 'SPY' };\n *\n * const [priceSeries, smaSeries] = await Promise.all([\n * runtime.compute({ kind: 'price' }, spy),\n * runtime.compute({ kind: 'sma', period: 20 }, spy),\n * ]);\n * ```\n */\n async compute(spec: FeatureSpec, asset: Asset): Promise<Series> {\n const key = this.cacheKey(spec, asset);\n if (this.mode !== 'streaming') {\n const cached = await this.featureCache.get(key);\n if (cached) return cached;\n }\n const base = await this.baseSeries(asset);\n const compute = getFeatureCompute(spec.kind);\n const result = compute(base, spec);\n if (this.mode !== 'streaming') {\n await this.featureCache.set(key, result);\n }\n return result;\n }\n}\n","import type { FeatureCache, FeatureKey } from '../interfaces/feature-cache';\nimport type { Series } from '../interfaces/types';\n\nfunction canonicalKey(key: FeatureKey): string {\n const scopePart = key.scope.kind === 'asset' ? `asset:${key.scope.asset}` : `universe:${key.scope.universeHash}`;\n return [\n `feat=${key.feature}`,\n `params=${key.paramsHash}`,\n `scope=${scopePart}`,\n `from=${key.range.from.toISOString()}`,\n `to=${key.range.to.toISOString()}`,\n `freq=${key.freq}`,\n ].join('|');\n}\n\nfunction canonicalPrefix(prefix: Partial<FeatureKey>): string {\n const parts: string[] = [];\n if (prefix.feature !== undefined) parts.push(`feat=${prefix.feature}`);\n if (prefix.paramsHash !== undefined) parts.push(`params=${prefix.paramsHash}`);\n if (prefix.scope !== undefined) {\n const scopePart =\n prefix.scope.kind === 'asset' ? `asset:${prefix.scope.asset}` : `universe:${prefix.scope.universeHash}`;\n parts.push(`scope=${scopePart}`);\n }\n if (prefix.range !== undefined) {\n parts.push(`from=${prefix.range.from.toISOString()}`);\n parts.push(`to=${prefix.range.to.toISOString()}`);\n }\n if (prefix.freq !== undefined) parts.push(`freq=${prefix.freq}`);\n return parts.join('|');\n}\n\n/**\n * In-process, Map-backed implementation of {@link FeatureCache}. Caches\n * computed indicator series in memory for the lifetime of the instance.\n * There is no eviction policy — the cache grows until the instance is\n * garbage-collected.\n *\n * **When to use**: the right choice for single-run backtests or unit tests\n * where the full dataset fits in process memory and cross-run persistence is\n * not required. For long-running hosted services or multi-process setups,\n * substitute a persistent implementation (e.g. Redis-backed) that satisfies\n * the {@link FeatureCache} interface.\n *\n * Cache keys are content-addressed strings composed of `(feature kind, params\n * hash, asset scope, date range, frequency)` — see the internal\n * `canonicalKey` function. The `invalidate` method performs prefix-based\n * deletion using the same key segments.\n *\n * @example\n * ```ts\n * import { MemoryFeatureCache } from '@livefolio/sdk';\n * import { FeatureRuntime } from '@livefolio/sdk/features';\n *\n * const cache = new MemoryFeatureCache();\n * const runtime = new FeatureRuntime({ feed: myDataFeed, cache });\n * ```\n */\nexport class MemoryFeatureCache implements FeatureCache {\n private store = new Map<string, Series>();\n\n async get(key: FeatureKey): Promise<Series | undefined> {\n return this.store.get(canonicalKey(key));\n }\n\n async set(key: FeatureKey, series: Series): Promise<void> {\n this.store.set(canonicalKey(key), series);\n }\n\n async invalidate(prefix: Partial<FeatureKey>): Promise<void> {\n const needles = canonicalPrefix(prefix).split('|').filter(Boolean);\n if (needles.length === 0) return;\n for (const k of [...this.store.keys()]) {\n if (needles.every((n) => k.includes(n))) this.store.delete(k);\n }\n }\n}\n","import type { Asset, AssetId, Bar } from '../interfaces/types';\nimport type { StreamingDataFeed } from '../interfaces/streaming-data-feed';\nimport type { Executor } from '../interfaces/executor';\nimport type { Calendar } from '../interfaces/calendar';\nimport type { Order } from '../orders/types';\nimport type { Portfolio } from '../portfolio/types';\nimport type { Strategy, Features } from './types';\nimport type { BacktestResult, BacktestSnapshot } from './run-backtest';\nimport { isStateResult } from './run-backtest';\nimport { FeatureRuntime } from '../features/runtime';\nimport { MemoryFeatureCache } from '../reference/memory-feature-cache';\nimport { applyFills } from '../portfolio/apply';\n\n/**\n * Unified event stream from {@link runLive}. Discriminated union of two variants:\n *\n * - **`mark`** — emitted per tick. The strategy is run in PREVIEW mode (state\n * is snapshot/restored, no executor call, no portfolio commit). Use this to\n * render the wiggling rightmost chart point and the \"if the session ended now,\n * the strategy would do X\" preview UX.\n * - **`snapshot`** — emitted when a tick crosses a session boundary. The\n * just-closed bar is finalized, `strategy.build` runs for real, orders are\n * submitted to the executor, fills are applied, and state advances. Same\n * shape as {@link BacktestSnapshot} from {@link runBacktest} (plus the\n * `type: 'snapshot'` discriminant), so consumers can append snapshot events\n * to the same chart array used by historical results.\n */\nexport type LiveEvent<F extends Features = Features, _S = unknown> =\n | {\n type: 'mark';\n /** Wall-clock arrival time of this tick. */\n t: Date;\n /** Portfolio at the start of the current session — unchanged by the preview. */\n portfolio: Portfolio;\n /**\n * Per-asset accumulating close so far in the current session. Only assets\n * that have received at least one tick this session appear in the map.\n */\n prices: ReadonlyMap<AssetId, number>;\n /** Features recomputed for the in-progress session. */\n features: F;\n /**\n * Orders the strategy would emit if the session closed at the current\n * tick price. Computed from a state SNAPSHOT — the returned `state` value\n * is discarded, so no committed state is mutated.\n */\n previewOrders: ReadonlyArray<Order>;\n /**\n * Best-effort placeholder — returns the unchanged portfolio. A future\n * `simulateFills(orders, prices)` helper will compute the hypothetical\n * post-rebalance NAV that would result from applying `previewOrders` at\n * `prices`. Until then, consumers compute NAV themselves from\n * `portfolio` + `prices`.\n */\n previewPortfolio: Portfolio;\n }\n | (BacktestSnapshot & { type: 'snapshot' });\n\n/** Required inputs to {@link runLive}. */\nexport type RunLiveOptions<F extends Features = Features, S = unknown> = {\n /** The strategy to drive. If its `features` method depends on a captured\n * `FeatureRuntime` (e.g. tactical strategies built via `fromSpec`), pass the\n * same runtime instance via {@link RunLiveOptions.streamingRuntime} so the\n * live bar buffer stays in sync with what the strategy reads. */\n strategy: Strategy<F, S>;\n /**\n * Result of a prior {@link runBacktest} call. Provides the seed `portfolio`,\n * `state`, and `bars` map for the streaming runtime.\n */\n history: BacktestResult<S>;\n /** Source of streaming ticks. */\n dataFeed: StreamingDataFeed;\n /** Order router used at session boundaries to settle the just-closed bar. */\n executor: Executor;\n /** Calendar that resolves a tick's wall-clock time into its session date. */\n calendar: Calendar;\n /**\n * Optional streaming {@link FeatureRuntime}. Provide this to share the\n * runtime with the strategy — tactical strategies built via `fromSpec`\n * capture a runtime in their `features` closure, so passing the same\n * instance here keeps the live bar buffer in sync with what the strategy\n * reads. When omitted, `runLive` constructs its own streaming runtime\n * seeded from `history.bars`.\n */\n streamingRuntime?: FeatureRuntime;\n};\n\n/**\n * Returns a structurally equivalent copy of `state` so previews cannot mutate\n * the committed state value. Uses `structuredClone` (Node ≥20). State must be\n * structured-cloneable — JSON-serializable types plus Date/Map/Set/etc.\n */\nfunction snapshotState<S>(state: S | undefined): S | undefined {\n if (state === undefined) return undefined;\n return structuredClone(state);\n}\n\n/**\n * Returns the trading-day key (midnight UTC) for the session containing\n * instant `t`, as resolved by the supplied {@link Calendar}. Two ticks belong\n * to the same session iff `findSession(t1) === findSession(t2)`.\n *\n * Uses `calendar.next(t)` to find the next trading day strictly after `t`,\n * then `calendar.previous` to back-anchor to the session that contains `t`.\n * For NYSE: a tick at Friday 17:00 ET (after-close) has `next` = Monday and\n * `previous(Monday)` = Friday — the correct session anchor.\n */\nfunction findSession(t: Date, calendar: Calendar): Date {\n const next = calendar.next(t);\n return calendar.previous(next);\n}\n\n/**\n * Drives a {@link Strategy} against a streaming market-data source and yields\n * a unified event stream that consumer charts can append to historical\n * snapshots without code branching.\n *\n * **Lifecycle on each tick:**\n * 1. Resolve the tick's session date via the supplied {@link Calendar} —\n * `calendar.previous(calendar.next(tick.t))`. This correctly handles\n * after-hours ticks (NYSE 17:00 ET stays in the same session) and DST\n * transitions.\n * 2. If the tick crosses a session boundary, finalize the just-closed bar:\n * append it to the streaming `FeatureRuntime`, run `strategy.build` for\n * REAL (committing state), submit orders to the executor, apply fills,\n * and yield a `snapshot` event identical in shape to {@link BacktestSnapshot}.\n * 3. Record the tick into the current session's accumulating bar.\n * 4. Re-run `strategy.features` and `strategy.build` in PREVIEW mode (state\n * is snapshot/restored — committed state is untouched). Yield a `mark`\n * event with the recomputed features and preview orders.\n *\n * **State semantics:** preview-build always operates on a deep clone of the\n * committed `state`. Only the boundary-crossing commit branch advances\n * committed state. This guarantees that 1000 ticks within a single session\n * produce 1000 marks but leave `state` exactly where the prior session-close\n * commit left it.\n *\n * **FeatureRuntime:** if the strategy was built via `fromSpec` it captures its\n * own runtime in the `features` closure. Pass that same instance via\n * {@link RunLiveOptions.streamingRuntime} so `appendBar` calls land on the\n * runtime the strategy actually reads. When omitted, `runLive` constructs its\n * own streaming runtime seeded from `history.bars` — this works for hand-rolled\n * strategies whose `features` method consults the runtime directly, but it\n * leaves a `fromSpec` strategy reading a stale captured runtime.\n *\n * **Bar lineage:** the streaming `FeatureRuntime` (provided or constructed) is\n * seeded from `history.bars`, so indicators with warmup periods (SMA(200),\n * etc.) work on the first live tick.\n *\n * **Universe:** captured once at startup from\n * `strategy.universe(anchorTime, portfolio)`, where `anchorTime` is the last\n * historical snapshot's timestamp (or epoch zero for empty history). Dynamic\n * universes are not yet supported in live mode.\n *\n * **Termination:** the iterable terminates when the underlying\n * `StreamingDataFeed.subscribe` iterable terminates. Real adapters yield\n * forever; tests use bounded iterables to assert specific event sequences.\n *\n * @param opts - Live-runtime configuration. See {@link RunLiveOptions}.\n * @returns An open-ended `AsyncIterable<LiveEvent>`. Consumers `for await` the\n * stream and dispatch on `ev.type`.\n *\n * @example\n * ```ts\n * for await (const ev of runLive({ strategy, history, dataFeed, executor, calendar })) {\n * if (ev.type === 'mark') {\n * chart.updateLastBar({ t: ev.t, prices: ev.prices, previewOrders: ev.previewOrders });\n * } else {\n * chart.appendBar(ev); // BacktestSnapshot-shaped\n * }\n * }\n * ```\n */\nexport async function* runLive<F extends Features = Features, S = unknown>(\n opts: RunLiveOptions<F, S>,\n): AsyncIterable<LiveEvent<F, S>> {\n const { strategy, history, dataFeed, executor, calendar } = opts;\n\n // Streaming FeatureRuntime: prefer a caller-supplied instance (so `fromSpec`\n // strategies that captured a runtime keep reading the same buffer we append\n // to). Otherwise build one seeded from `history.bars` for hand-rolled\n // strategies that consult the runtime directly.\n const runtime =\n opts.streamingRuntime ??\n new FeatureRuntime({\n mode: 'streaming',\n featureCache: new MemoryFeatureCache(),\n freq: '1d',\n initialBars: history.bars,\n });\n\n let portfolio = history.finalPortfolio;\n let state: S | undefined = history.finalState;\n // Universe is captured once at startup using the last historical snapshot's\n // timestamp as an anchor (or epoch zero for empty history). Dynamic\n // universes are not yet supported in live mode.\n const anchorTime = history.snapshots.length > 0 ? history.snapshots[history.snapshots.length - 1]!.t : new Date(0);\n const universe = strategy.universe(anchorTime, portfolio);\n\n // Track the current session being accumulated. When history is non-empty,\n // its last snapshot represents an already-committed session, so the next\n // session to accumulate is `calendar.next(lastSnapshot.t)`. Without this\n // advance, the first live tick whose session exceeds `lastSnapshot.t` would\n // re-fire the boundary and emit a duplicate snapshot for the already-closed\n // session. With empty history, we lazily adopt the first tick's session.\n let currentSession: Date | null =\n history.snapshots.length > 0 ? calendar.next(history.snapshots[history.snapshots.length - 1]!.t) : null;\n let currentBarOpen = new Map<AssetId, number>();\n let currentBarHigh = new Map<AssetId, number>();\n let currentBarLow = new Map<AssetId, number>();\n let currentBarClose = new Map<AssetId, number>();\n\n function recordTick(asset: Asset, tickBar: Bar): void {\n const id = asset.id;\n const price = tickBar.close;\n if (!currentBarOpen.has(id)) currentBarOpen.set(id, price);\n currentBarHigh.set(id, Math.max(currentBarHigh.get(id) ?? -Infinity, price));\n currentBarLow.set(id, Math.min(currentBarLow.get(id) ?? Infinity, price));\n currentBarClose.set(id, price);\n }\n\n function finalizeBars(sessionDate: Date): void {\n for (const asset of universe) {\n const close = currentBarClose.get(asset.id);\n if (close === undefined) continue;\n runtime.appendBar(asset, {\n t: sessionDate,\n open: currentBarOpen.get(asset.id)!,\n high: currentBarHigh.get(asset.id)!,\n low: currentBarLow.get(asset.id)!,\n close,\n volume: 0,\n });\n }\n currentBarOpen = new Map();\n currentBarHigh = new Map();\n currentBarLow = new Map();\n currentBarClose = new Map();\n }\n\n for await (const tick of dataFeed.subscribe(universe)) {\n const tickSession = findSession(tick.bar.t, calendar);\n\n if (currentSession === null) {\n currentSession = tickSession;\n }\n\n // Boundary crossed: finalize the previous session's bar, run REAL build,\n // submit orders, apply fills, yield snapshot, then start the new session.\n if (tickSession.getTime() > currentSession.getTime()) {\n finalizeBars(currentSession);\n const sessionFeatures = await strategy.features(universe, portfolio, currentSession);\n const buildResult = strategy.build(sessionFeatures, portfolio, state as S, currentSession);\n let orders: ReadonlyArray<Order>;\n if (isStateResult(buildResult)) {\n orders = buildResult.orders;\n state = buildResult.state;\n } else {\n orders = buildResult;\n }\n const fills = await executor.submit(orders, currentSession, portfolio);\n portfolio = applyFills(portfolio, fills, orders);\n yield {\n type: 'snapshot',\n t: currentSession,\n portfolio,\n orders,\n fills,\n };\n currentSession = tickSession;\n }\n\n // Record the tick into the current session's accumulating bar.\n recordTick(tick.asset, tick.bar);\n\n // Wiggle: push the in-flight session bar into the streaming runtime so\n // feature computations see the running close. `runtime.appendBar` allows\n // same-t replacement, so subsequent ticks within the session overwrite\n // the in-flight bar in place. Without this step, features would be\n // pinned to yesterday's close — preview decisions would be stable\n // through the session and only refresh at session-close finalization,\n // which contradicts the model that every tick is \"as if the session\n // closed at this price.\"\n for (const asset of universe) {\n const close = currentBarClose.get(asset.id);\n if (close === undefined) continue;\n runtime.appendBar(asset, {\n t: currentSession,\n open: currentBarOpen.get(asset.id)!,\n high: currentBarHigh.get(asset.id)!,\n low: currentBarLow.get(asset.id)!,\n close,\n volume: 0,\n });\n }\n\n // Preview: snapshot state, recompute features, run build with the snapshot,\n // discard the returned state. Committed `state` is never touched here.\n const prices = new Map(currentBarClose);\n const features = await strategy.features(universe, portfolio, tick.bar.t);\n const previewState = snapshotState(state);\n const previewResult = strategy.build(features, portfolio, previewState as S, tick.bar.t);\n const previewOrders: ReadonlyArray<Order> = isStateResult(previewResult) ? previewResult.orders : previewResult;\n\n yield {\n type: 'mark',\n t: tick.bar.t,\n portfolio,\n prices,\n features,\n // TODO: replace with `simulateFills(previewOrders, prices)` when the\n // helper lands so consumers see the hypothetical post-rebalance NAV.\n previewOrders,\n previewPortfolio: portfolio,\n };\n }\n}\n","import type { Executor } from '../interfaces/executor';\nimport type { Calendar } from '../interfaces/calendar';\nimport type { Asset } from '../interfaces/types';\nimport type { Order, Fill } from '../orders/types';\nimport type { Portfolio } from '../portfolio/types';\n\n/**\n * Callback that resolves the next-open price for `asset` as seen from date `t`.\n * {@link BacktestExecutor} calls this once per order to determine the fill price.\n *\n * The function should return the opening price of the first trading session\n * strictly after `t`, along with that session's timestamp. In a typical\n * backtest setup this reads from the same data feed used to compute features.\n *\n * @param asset - The instrument being filled.\n * @param t - The date on which the rebalance order was submitted (the\n * \"signal date\"). The fill should occur on the next open after\n * this date to avoid look-ahead.\n * @returns An object with the fill timestamp `t` and the opening `price`.\n */\nexport type NextOpenFn = (asset: Asset, t: Date) => Promise<{ t: Date; price: number }>;\n\n/**\n * Constructor options for {@link BacktestExecutor}.\n */\nexport type BacktestExecutorOptions = {\n /** Exchange calendar used to route fills to the next open session. */\n calendar: Calendar;\n /**\n * Callback that resolves the next-open price for a given asset and date.\n * See {@link NextOpenFn} for the exact contract.\n */\n nextOpen: NextOpenFn;\n /**\n * One-way slippage in basis points applied to every fill. The fill price is\n * adjusted by `price × (1 + sign × slippageBps / 10 000)` where `sign` is\n * `+1` for buys and `−1` for sells. Defaults to `0`.\n */\n slippageBps?: number;\n /**\n * Flat per-share commission in the portfolio's base currency. Multiplied by\n * the fill quantity and recorded in `Fill.fees`. Defaults to `0`.\n */\n perShareFee?: number;\n};\n\nfunction resolveAsset(order: Order, portfolio: Portfolio): { asset: Asset; sign: 1 | -1; qty: number } {\n switch (order.kind) {\n case 'open':\n return { asset: order.asset, sign: order.side === 'long' ? 1 : -1, qty: order.quantity };\n case 'rebalance':\n return { asset: order.asset, sign: order.delta >= 0 ? 1 : -1, qty: Math.abs(order.delta) };\n case 'close': {\n const p = portfolio.positions.find((x) => x.id === order.positionId);\n if (!p) throw new Error(`BacktestExecutor: close target position ${order.positionId} not found`);\n return { asset: p.asset, sign: p.side === 'long' ? -1 : 1, qty: order.quantity ?? p.quantity };\n }\n case 'adjust': {\n const p = portfolio.positions.find((x) => x.id === order.positionId);\n if (!p) throw new Error(`BacktestExecutor: adjust target position ${order.positionId} not found`);\n const target = order.changes.quantity ?? p.quantity;\n const delta = target - p.quantity;\n return { asset: p.asset, sign: delta >= 0 ? 1 : -1, qty: Math.abs(delta) };\n }\n }\n}\n\n/**\n * Reference {@link Executor} implementation for backtesting. Fills each order\n * at the next-open price returned by the {@link NextOpenFn} callback, with\n * optional slippage and per-share commissions applied.\n *\n * **When to use**: suitable for historical simulations and unit tests where\n * real broker connectivity is not needed. For live or paper trading, substitute\n * a broker-backed `Executor` that satisfies the same interface.\n *\n * **Fill mechanics**: for each order in `orders`, the executor calls\n * `opts.nextOpen(asset, t)` to obtain the fill price and timestamp. The\n * raw price is then adjusted for slippage:\n * ```\n * adjustedPrice = nextOpen.price × (1 + sign × slippageBps / 10 000)\n * ```\n * where `sign` is `+1` for net-buy direction and `−1` for net-sell direction.\n * A flat per-share fee is added to `Fill.fees`. Orders with zero quantity are\n * silently skipped.\n *\n * @example\n * ```ts\n * import { BacktestExecutor } from '@livefolio/sdk';\n * import { getCalendar } from '@livefolio/sdk';\n *\n * const executor = new BacktestExecutor({\n * calendar: getCalendar('NYSE'),\n * nextOpen: async (asset, t) => {\n * // Return the first open bar strictly after t from your data feed.\n * const bar = await feed.nextBar(asset, t);\n * return { t: bar.t, price: bar.open };\n * },\n * slippageBps: 5, // 0.05% one-way\n * perShareFee: 0.005,\n * });\n * ```\n */\nexport class BacktestExecutor implements Executor {\n constructor(private readonly opts: BacktestExecutorOptions) {}\n\n async submit(orders: ReadonlyArray<Order>, t: Date, portfolio: Portfolio): Promise<ReadonlyArray<Fill>> {\n const fills: Fill[] = [];\n const slip = (this.opts.slippageBps ?? 0) / 10_000;\n const feePer = this.opts.perShareFee ?? 0;\n\n for (const order of orders) {\n const { asset, sign, qty } = resolveAsset(order, portfolio);\n if (qty === 0) continue;\n const open = await this.opts.nextOpen(asset, t);\n const adjustedPrice = open.price * (1 + sign * slip);\n fills.push({\n orderRef: order.id,\n t: open.t,\n quantity: qty,\n price: adjustedPrice,\n fees: feePer * qty,\n });\n }\n return fills;\n }\n}\n","import type { Asset, Bar, DateRange, Frequency } from '../interfaces/types';\nimport type { DataFeed, Fundamentals } from '../interfaces/data-feed';\n\n/**\n * Error thrown by {@link RoutingDataFeed} when an asset cannot be routed or\n * when the routed feed does not support the requested optional method.\n *\n * Distinguish the two cases via the message text: \"no feed registered\" vs\n * \"does not implement fundamentals\".\n */\nexport class RoutingDataFeedError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'RoutingDataFeedError';\n }\n}\n\n/** Function form of the routing rule. Returns the feed for `asset`, or `undefined` when no feed handles it. */\nexport type RoutingDataFeedRouteFn = (asset: Asset) => DataFeed | undefined;\n\n/** Map form of the routing rule. Keys are `Asset['kind']` discriminants. */\nexport type RoutingDataFeedRouteMap = Readonly<Partial<Record<Asset['kind'], DataFeed>>>;\n\n/**\n * A {@link DataFeed} that delegates each call to one of several underlying\n * feeds based on the asset. Use this to compose vendors — e.g. Yahoo for\n * equities and FRED for macro series — behind a single `DataFeed` instance\n * accepted by `runBacktest`, `FeatureRuntime`, and `BacktestExecutor`.\n *\n * Routing rules:\n * - **Map form:** `new RoutingDataFeed({ equity: yahoo, macro: fred })`.\n * Keys are `asset.kind` discriminants. The 90% case.\n * - **Function form:** `new RoutingDataFeed((a) => a.kind === 'macro' ? fred : yahoo)`.\n * Use when routing depends on more than `kind` (e.g. allowlists).\n *\n * The router does **not** implement `events()` — the optional method is\n * genuinely absent (`'events' in router === false`). Cross-feed event\n * fan-out is deferred until a real consumer materializes.\n *\n * @example\n * ```ts\n * import { RoutingDataFeed } from '@livefolio/sdk';\n *\n * const feed = new RoutingDataFeed({ equity: yahooFeed, macro: fredFeed });\n *\n * const result = await runBacktest({\n * strategy, range, initialPortfolio,\n * dataFeed: feed,\n * executor,\n * calendar,\n * });\n * ```\n */\nexport class RoutingDataFeed implements DataFeed {\n private readonly route: RoutingDataFeedRouteFn;\n\n constructor(routes: RoutingDataFeedRouteMap | RoutingDataFeedRouteFn) {\n if (typeof routes === 'function') {\n this.route = routes;\n } else {\n this.route = (asset) => routes[asset.kind];\n }\n }\n\n // Async generator (rather than plain delegation) so resolve() runs lazily on\n // the first next() call, surfacing errors via the iterable's normal rejection\n // path instead of throwing synchronously at call time.\n async *bars(asset: Asset, range: DateRange, freq: Frequency): AsyncGenerator<Bar> {\n const feed = this.resolve(asset);\n yield* feed.bars(asset, range, freq);\n }\n\n async fundamentals(asset: Asset, t: Date): Promise<Fundamentals> {\n const feed = this.resolve(asset);\n if (typeof feed.fundamentals !== 'function') {\n throw new RoutingDataFeedError(\n `RoutingDataFeed: routed feed for asset.kind=\"${asset.kind}\" (id=\"${asset.id}\") does not implement fundamentals()`,\n );\n }\n return feed.fundamentals(asset, t);\n }\n\n private resolve(asset: Asset): DataFeed {\n const feed = this.route(asset);\n if (feed === undefined) {\n throw new RoutingDataFeedError(\n `RoutingDataFeed: no feed registered for asset.kind=\"${asset.kind}\" (id=\"${asset.id}\")`,\n );\n }\n return feed;\n }\n}\n","import type { Asset } from '../interfaces/types';\nimport type { StreamingDataFeed, StreamingBar } from '../interfaces/streaming-data-feed';\n\n/**\n * Error thrown by {@link RoutingStreamingDataFeed} when an asset cannot be routed.\n */\nexport class RoutingStreamingDataFeedError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'RoutingStreamingDataFeedError';\n }\n}\n\n/** Function form of the routing rule. Returns the feed for `asset`, or `undefined` when no feed handles it. */\nexport type RoutingStreamingDataFeedRouteFn = (asset: Asset) => StreamingDataFeed | undefined;\n\n/** Map form of the routing rule. Keys are `Asset['kind']` discriminants. */\nexport type RoutingStreamingDataFeedRouteMap = Readonly<Partial<Record<Asset['kind'], StreamingDataFeed>>>;\n\n/**\n * A {@link StreamingDataFeed} that delegates `subscribe()` to one of several\n * underlying feeds based on the asset. Use this to compose vendors — e.g.\n * Polygon for equities and a polling adapter for macro series — behind a\n * single `StreamingDataFeed` instance accepted by `runLive`.\n *\n * Routing rules:\n * - **Map form:** `new RoutingStreamingDataFeed({ equity: polygon, macro: polling })`.\n * Keys are `asset.kind` discriminants. The 90% case.\n * - **Function form:** `new RoutingStreamingDataFeed((a) => a.kind === 'macro' ? polling : polygon)`.\n * Use when routing depends on more than `kind` (e.g. allowlists).\n *\n * Assets are grouped by routed feed (by reference identity) before calling\n * upstream `subscribe()` — so a vendor adapter that opens one socket for\n * `[AAPL, MSFT]` keeps doing that rather than receiving one-asset-at-a-time calls.\n *\n * @example\n * ```ts\n * import { RoutingStreamingDataFeed, pollingStreamFromHistorical } from '@livefolio/sdk';\n *\n * const feed = new RoutingStreamingDataFeed({\n * equity: polygonStreaming,\n * macro: pollingStreamFromHistorical({ feed: fredHistorical, freq: '1d', schedule: { kind: 'session-close', calendar: nyse } }),\n * });\n * ```\n */\nexport class RoutingStreamingDataFeed implements StreamingDataFeed {\n private readonly route: RoutingStreamingDataFeedRouteFn;\n\n constructor(routes: RoutingStreamingDataFeedRouteMap | RoutingStreamingDataFeedRouteFn) {\n if (typeof routes === 'function') {\n this.route = routes;\n } else {\n this.route = (asset) => routes[asset.kind];\n }\n }\n\n subscribe(assets: ReadonlyArray<Asset>): AsyncIterable<StreamingBar> {\n return this.merged(assets);\n }\n\n // Async generator so routing/grouping errors surface on first next() rather\n // than throwing synchronously at subscribe() call time — matches RoutingDataFeed.bars() shape.\n private async *merged(assets: ReadonlyArray<Asset>): AsyncGenerator<StreamingBar> {\n if (assets.length === 0) return;\n\n const groups = new Map<StreamingDataFeed, Asset[]>();\n for (const asset of assets) {\n const feed = this.route(asset);\n if (feed === undefined) {\n throw new RoutingStreamingDataFeedError(\n `RoutingStreamingDataFeed: no feed registered for asset.kind=\"${asset.kind}\" (id=\"${asset.id}\")`,\n );\n }\n const list = groups.get(feed) ?? [];\n list.push(asset);\n groups.set(feed, list);\n }\n\n const iters = [...groups.entries()].map(([feed, group]) => feed.subscribe(group)[Symbol.asyncIterator]());\n yield* mergeIterators(iters);\n }\n}\n\nasync function* mergeIterators(iters: ReadonlyArray<AsyncIterator<StreamingBar>>): AsyncGenerator<StreamingBar> {\n type Slot = {\n iter: AsyncIterator<StreamingBar>;\n promise: Promise<{ idx: number; r: IteratorResult<StreamingBar> }>;\n };\n const live = new Map<number, Slot>();\n\n const arm = (idx: number, iter: AsyncIterator<StreamingBar>): void => {\n live.set(idx, {\n iter,\n promise: iter.next().then((r) => ({ idx, r })),\n });\n };\n\n iters.forEach((iter, idx) => arm(idx, iter));\n\n try {\n while (live.size > 0) {\n const { idx, r } = await Promise.race([...live.values()].map((s) => s.promise));\n if (r.done) {\n live.delete(idx);\n } else {\n yield r.value;\n const slot = live.get(idx);\n if (slot) arm(idx, slot.iter);\n }\n }\n } finally {\n await Promise.allSettled(\n [...live.values()].map((s) => (s.iter.return ? s.iter.return(undefined) : Promise.resolve())),\n );\n }\n}\n","import type { Asset, AssetId, Frequency } from '../interfaces/types';\nimport type { DataFeed } from '../interfaces/data-feed';\nimport type { Calendar } from '../interfaces/calendar';\nimport type { StreamingDataFeed, StreamingBar } from '../interfaces/streaming-data-feed';\n\nexport type PollingSchedule = { kind: 'interval'; intervalMs: number } | { kind: 'session-close'; calendar: Calendar };\n\nexport type PollingStreamOptions = {\n /** Historical feed to poll. Each tick of the schedule calls `feed.bars(asset, …)` for each subscribed asset. */\n feed: DataFeed;\n /** Bar frequency to request. Single value — multi-frequency requires composing two polling streams via `RoutingStreamingDataFeed`. */\n freq: Frequency;\n /** When to poll. */\n schedule: PollingSchedule;\n /**\n * Window-start for the first poll per asset. Subsequent polls fetch\n * `(lastSeenT, now]` per asset. Defaults to `new Date(0)` — every bar the\n * feed has on the first poll is yielded. For replay-then-stream, set this\n * to your backtest range's `to` so polling picks up exactly where the\n * backtest left off.\n */\n initialFrom?: Date;\n /** Inject for tests or for accelerated-time simulations. Defaults to `() => new Date()`. */\n now?: () => Date;\n /** Inject for tests or for accelerated-time simulations. Defaults to `setTimeout`-based promise. */\n sleep?: (ms: number) => Promise<void>;\n};\n\nexport function pollingStreamFromHistorical(opts: PollingStreamOptions): StreamingDataFeed {\n const now = opts.now ?? (() => new Date());\n const sleep = opts.sleep ?? ((ms: number) => new Promise<void>((res) => setTimeout(res, ms)));\n const initialFrom = opts.initialFrom ?? new Date(0);\n\n return {\n subscribe(assets: ReadonlyArray<Asset>): AsyncIterable<StreamingBar> {\n return poll(assets);\n },\n };\n\n async function* poll(assets: ReadonlyArray<Asset>): AsyncGenerator<StreamingBar> {\n // Dedup by id, preserve input order.\n const seen = new Set<AssetId>();\n const uniq: Asset[] = [];\n for (const a of assets) {\n if (!seen.has(a.id)) {\n seen.add(a.id);\n uniq.push(a);\n }\n }\n if (uniq.length === 0) return;\n\n const lastSeenT = new Map<AssetId, Date>(uniq.map((a) => [a.id, initialFrom]));\n\n while (true) {\n await waitForNextPoll();\n for (const asset of uniq) {\n const from = lastSeenT.get(asset.id)!;\n const to = now(); // Fresh per asset by design — for cycle-stable to, pass a custom now() that caches.\n for await (const bar of opts.feed.bars(asset, { from, to }, opts.freq)) {\n const last = lastSeenT.get(asset.id)!;\n if (bar.t.getTime() > last.getTime()) {\n yield { asset, bar };\n lastSeenT.set(asset.id, bar.t);\n }\n }\n }\n }\n }\n\n async function waitForNextPoll(): Promise<void> {\n if (opts.schedule.kind === 'interval') {\n await sleep(opts.schedule.intervalMs);\n return;\n }\n // Resolve the next session close via cal.schedule() lookahead rather than\n // the cal.previous(cal.next(now)) idiom: Session exposes .close (not .end),\n // and the lookahead also covers the exotic-calendar fallback below.\n const cal = opts.schedule.calendar;\n const t = now();\n const lookaheadDays = 14;\n const range = {\n from: t,\n to: new Date(t.getTime() + lookaheadDays * 24 * 60 * 60 * 1000),\n };\n const sessions = cal.schedule(range);\n const upcoming = sessions.find((s) => s.close.getTime() > t.getTime());\n if (upcoming === undefined) {\n // No session in the next N days — sleep one day and retry.\n await sleep(24 * 60 * 60 * 1000);\n return;\n }\n const delay = Math.max(0, upcoming.close.getTime() - t.getTime());\n await sleep(delay);\n }\n}\n","import { DateTime } from 'luxon';\nimport type { Calendar, Session, TimeOfDay } from '../interfaces/calendar';\nimport type { DateRange } from '../interfaces/types';\nimport {\n resolveHolidays,\n resolveSpecialCloses,\n resolveSpecialOpens,\n type HolidayRule,\n type SpecialClose,\n type SpecialOpen,\n type AdhocTimeOverrides,\n} from './holiday-rules';\n\nconst MS_PER_DAY = 86_400_000;\n\nconst DEFAULT_WEEKMASK: ReadonlySet<number> = new Set([1, 2, 3, 4, 5]);\nconst EMPTY_ADHOC: AdhocTimeOverrides = new Map();\n\nfunction ymdKey(d: Date): string {\n return d.toISOString().slice(0, 10);\n}\n\n/**\n * Abstract base class for exchange trading calendars. Implements the full\n * {@link Calendar} interface by composing up to nine overridable hooks that\n * subclasses provide. Concrete implementations ship for {@link NYSEExchangeCalendar}\n * and {@link LSEExchangeCalendar}; additional exchanges can be added by\n * extending this class.\n *\n * **Per-year caching**: holiday sets and special-session maps are computed once\n * per calendar year and stored in private Maps, so repeated calls to `isOpen`,\n * `next`, or `sessions` within the same year are cheap.\n *\n * **Hook resolution order** (adhoc beats rule, rule beats regular):\n * 1. `adhocHolidays()` / `specialClosesAdhoc()` / `specialOpensAdhoc()` —\n * `YYYY-MM-DD` string sets/maps populated once at first access.\n * 2. `regularHolidays()` / `specialCloses()` / `specialOpens()` —\n * year-derived rule arrays applied per year via the resolver helpers.\n * 3. `regularOpen(date)` / `regularClose(date)` / `weekmask(date)` —\n * per-date fallbacks that subclasses override to encode era-varying session\n * times and trading-day sets.\n *\n * **Extending**: override only the hooks you need. All hooks have no-op / sensible\n * defaults (Mon–Fri weekmask, 09:30–16:00 session) so a minimal subclass need\n * only set `name`, `tz`, and `regularHolidays()`.\n */\nexport abstract class ExchangeCalendar implements Calendar {\n /** Short exchange name used as the registry key in {@link getCalendar}. */\n abstract readonly name: string;\n /** IANA timezone identifier, e.g. `'America/New_York'` or `'Europe/London'`. */\n abstract readonly tz: string;\n\n private readonly holidayCache = new Map<number, Set<number>>();\n private readonly specialCloseCache = new Map<number, Map<number, TimeOfDay>>();\n private readonly specialOpenCache = new Map<number, Map<number, TimeOfDay>>();\n\n private adhocHolidaysCache: ReadonlySet<string> | null = null;\n private adhocSpecialClosesCache: AdhocTimeOverrides | null = null;\n private adhocSpecialOpensCache: AdhocTimeOverrides | null = null;\n\n // --- Hooks ---\n\n /**\n * Returns the ordered list of year-derived holiday rules for this exchange.\n * The base implementation returns an empty array (no regular holidays). Override\n * to supply the full rule set; each {@link HolidayRule} in the array is applied\n * via {@link resolveHolidays} once per calendar year and cached. Rules may be\n * era-bounded via `validFrom` / `validUntil`.\n */\n protected regularHolidays(): ReadonlyArray<HolidayRule> {\n return [];\n }\n\n /**\n * Returns the set of `YYYY-MM-DD` strings for one-off full-day closures that\n * do not fit a repeating rule (e.g. presidential funerals, natural disasters).\n * The base implementation returns an empty set. Override with the complete\n * historical adhoc list for the exchange. This method is called at most once\n * per `ExchangeCalendar` instance; the result is cached.\n */\n protected adhocHolidays(): ReadonlySet<string> {\n return new Set();\n }\n\n /**\n * Returns the ordered list of year-derived early-close rules for this exchange.\n * The base implementation returns an empty array. Override to supply rules such\n * as \"day after Thanksgiving closes at 13:00\". Results are computed once per\n * year and cached; each rule is applied via {@link resolveSpecialCloses}.\n */\n protected specialCloses(): ReadonlyArray<SpecialClose> {\n return [];\n }\n\n /**\n * Returns the map of `YYYY-MM-DD` strings to override close times for\n * one-off early-close days that do not fit a repeating rule. The base\n * implementation returns an empty map. Override with the historical adhoc\n * set for the exchange. Called at most once per instance; result is cached.\n */\n protected specialClosesAdhoc(): AdhocTimeOverrides {\n return EMPTY_ADHOC;\n }\n\n /**\n * Returns the ordered list of year-derived late-open rules for this exchange.\n * The base implementation returns an empty array. Override to supply rules such\n * as \"delayed open due to a moment of silence\". Results are computed once per\n * year and cached; each rule is applied via {@link resolveSpecialOpens}.\n */\n protected specialOpens(): ReadonlyArray<SpecialOpen> {\n return [];\n }\n\n /**\n * Returns the map of `YYYY-MM-DD` strings to override open times for\n * one-off late-open days that do not fit a repeating rule. The base\n * implementation returns an empty map. Override with the historical adhoc\n * set for the exchange. Called at most once per instance; result is cached.\n */\n protected specialOpensAdhoc(): AdhocTimeOverrides {\n return EMPTY_ADHOC;\n }\n\n /**\n * Returns the default open time in local exchange time for `date` when no\n * special-open rule matches. The base implementation returns 09:30. Override\n * to encode era-varying session times (e.g. NYSE opened at 10:00 before\n * 1985-09-30).\n *\n * @param date - UTC midnight `Date` for the trading day being queried.\n */\n protected regularOpen(_date: Date): TimeOfDay {\n return { h: 9, m: 30 };\n }\n\n /**\n * Returns the default close time in local exchange time for `date` when no\n * special-close rule matches. The base implementation returns 16:00. Override\n * to encode era-varying session times (e.g. NYSE closed at 15:00 before\n * 1952-09-29, and at 15:30 until 1974-01-02).\n *\n * @param date - UTC midnight `Date` for the trading day being queried.\n */\n protected regularClose(_date: Date): TimeOfDay {\n return { h: 16, m: 0 };\n }\n\n /**\n * Returns the set of weekday indices (using `Date.getUTCDay()` convention:\n * 0 = Sunday, 1 = Monday, …, 6 = Saturday) that are regular trading days.\n * The base implementation returns `{1, 2, 3, 4, 5}` (Mon–Fri). Override to\n * encode historical six-day trading weeks (e.g. NYSE traded Mon–Sat before\n * 1952-09-29, keyed by `date` so the shift is era-aware).\n *\n * @param date - UTC midnight `Date` for the day being tested.\n */\n protected weekmask(_date: Date): ReadonlySet<number> {\n return DEFAULT_WEEKMASK;\n }\n\n // --- Adhoc caching getters ---\n private getAdhocHolidays(): ReadonlySet<string> {\n if (this.adhocHolidaysCache === null) this.adhocHolidaysCache = this.adhocHolidays();\n return this.adhocHolidaysCache;\n }\n private getAdhocSpecialCloses(): AdhocTimeOverrides {\n if (this.adhocSpecialClosesCache === null) this.adhocSpecialClosesCache = this.specialClosesAdhoc();\n return this.adhocSpecialClosesCache;\n }\n private getAdhocSpecialOpens(): AdhocTimeOverrides {\n if (this.adhocSpecialOpensCache === null) this.adhocSpecialOpensCache = this.specialOpensAdhoc();\n return this.adhocSpecialOpensCache;\n }\n\n // --- Caches ---\n /**\n * Cached lookup of regular-holiday timestamps for the given year.\n * Assumes `regularHolidays()` returns the same rule list on every call.\n */\n private holidaysForYear(year: number): Set<number> {\n let set = this.holidayCache.get(year);\n if (!set) {\n set = resolveHolidays(this.regularHolidays(), year);\n this.holidayCache.set(year, set);\n }\n return set;\n }\n\n private specialClosesForYear(year: number): Map<number, TimeOfDay> {\n let map = this.specialCloseCache.get(year);\n if (!map) {\n map = resolveSpecialCloses(this.specialCloses(), year);\n this.specialCloseCache.set(year, map);\n }\n return map;\n }\n\n private specialOpensForYear(year: number): Map<number, TimeOfDay> {\n let map = this.specialOpenCache.get(year);\n if (!map) {\n map = resolveSpecialOpens(this.specialOpens(), year);\n this.specialOpenCache.set(year, map);\n }\n return map;\n }\n\n private normalize(t: Date): Date {\n return new Date(Date.UTC(t.getUTCFullYear(), t.getUTCMonth(), t.getUTCDate()));\n }\n\n // --- Public Calendar API ---\n\n /** Returns `true` when `t` falls on a regular trading day (weekmask check, then holiday check). */\n isOpen(t: Date): boolean {\n const d = this.normalize(t);\n if (!this.weekmask(d).has(d.getUTCDay())) return false;\n if (this.getAdhocHolidays().has(ymdKey(d))) return false;\n const year = d.getUTCFullYear();\n if (this.holidaysForYear(year).has(d.getTime())) return false;\n return true;\n }\n\n /** Returns the first trading day strictly after `t`. */\n next(t: Date): Date {\n let d = new Date(this.normalize(t).getTime() + MS_PER_DAY);\n while (!this.isOpen(d)) d = new Date(d.getTime() + MS_PER_DAY);\n return d;\n }\n\n /** Returns the first trading day strictly before `t`. */\n previous(t: Date): Date {\n let d = new Date(this.normalize(t).getTime() - MS_PER_DAY);\n while (!this.isOpen(d)) d = new Date(d.getTime() - MS_PER_DAY);\n return d;\n }\n\n /**\n * Returns UTC midnight `Date` objects for every trading day in\n * `[range.from, range.to)`. The `from` bound is inclusive; `to` is exclusive.\n */\n sessions(range: DateRange): ReadonlyArray<Date> {\n const out: Date[] = [];\n let d = this.normalize(range.from);\n const end = this.normalize(range.to).getTime();\n while (d.getTime() < end) {\n if (this.isOpen(d)) out.push(d);\n d = new Date(d.getTime() + MS_PER_DAY);\n }\n return out;\n }\n\n schedule(range: DateRange): ReadonlyArray<Session> {\n const days = this.sessions(range);\n return days.map((date) => ({\n date,\n open: this.localizedTimestamp(date, this.openTimeFor(date)),\n close: this.localizedTimestamp(date, this.closeTimeFor(date)),\n }));\n }\n\n isEarlyClose(t: Date): boolean {\n const d = this.normalize(t);\n if (!this.isOpen(d)) return false;\n if (this.getAdhocSpecialCloses().has(ymdKey(d))) return true;\n return this.specialClosesForYear(d.getUTCFullYear()).has(d.getTime());\n }\n\n // --- Resolution ---\n /** Adhoc overrides win over rule-driven; both win over `regularOpen(date)`. */\n private openTimeFor(date: Date): TimeOfDay {\n const adhoc = this.getAdhocSpecialOpens().get(ymdKey(date));\n if (adhoc) return adhoc;\n const ruled = this.specialOpensForYear(date.getUTCFullYear()).get(date.getTime());\n if (ruled) return ruled;\n return this.regularOpen(date);\n }\n\n /** Adhoc overrides win over rule-driven; both win over `regularClose(date)`. */\n private closeTimeFor(date: Date): TimeOfDay {\n const adhoc = this.getAdhocSpecialCloses().get(ymdKey(date));\n if (adhoc) return adhoc;\n const ruled = this.specialClosesForYear(date.getUTCFullYear()).get(date.getTime());\n if (ruled) return ruled;\n return this.regularClose(date);\n }\n\n private localizedTimestamp(date: Date, time: TimeOfDay): Date {\n const dt = DateTime.fromObject(\n {\n year: date.getUTCFullYear(),\n month: date.getUTCMonth() + 1,\n day: date.getUTCDate(),\n hour: time.h,\n minute: time.m,\n },\n { zone: this.tz },\n );\n return new Date(dt.toUTC().toMillis());\n }\n}\n","import type { TimeOfDay } from '../interfaces/calendar';\n\nconst MS_PER_DAY = 86_400_000;\n\nexport type { TimeOfDay };\n\n/**\n * A year-derived holiday rule consumed by {@link ExchangeCalendar}. The rule\n * is active only for years in the range `[validFrom, validUntil]` (both\n * inclusive; omit either bound to leave it open).\n *\n * `resolve(year)` returns the UTC midnight `Date` for the holiday in that year,\n * or `null` if the holiday does not occur that year (e.g. a conditional rule\n * for Good Friday in certain years). When `observe` is `true`, a Saturday\n * result is moved to Friday and a Sunday result is moved to Monday (standard\n * US-style holiday observation).\n */\nexport type HolidayRule = {\n /** Human-readable name, used for debugging and logging. */\n name: string;\n /** Returns the UTC midnight `Date` for this holiday in `year`, or `null` to skip. */\n resolve: (year: number) => Date | null;\n /** First year (inclusive) this rule applies. Defaults to −∞. */\n validFrom?: number;\n /** Last year (inclusive) this rule applies. Defaults to +∞. */\n validUntil?: number;\n /** When `true`, Saturday dates are moved to Friday, Sunday dates to Monday. */\n observe?: boolean;\n};\n\n/**\n * A year-derived early-close rule consumed by {@link ExchangeCalendar}. Follows\n * the same validity bounds and `resolve` contract as {@link HolidayRule}, but\n * instead of marking a day closed entirely it overrides the session close time\n * to `closeAt` for the matched date.\n */\nexport type SpecialClose = {\n /** Human-readable name, used for debugging and logging. */\n name: string;\n /** Returns the UTC midnight `Date` for this early-close day in `year`, or `null` to skip. */\n resolve: (year: number) => Date | null;\n /** The overridden close time in local exchange time. */\n closeAt: TimeOfDay;\n /** First year (inclusive) this rule applies. Defaults to −∞. */\n validFrom?: number;\n /** Last year (inclusive) this rule applies. Defaults to +∞. */\n validUntil?: number;\n};\n\n/**\n * A year-derived late-open rule consumed by {@link ExchangeCalendar}. Follows\n * the same validity bounds and `resolve` contract as {@link HolidayRule}, but\n * overrides the session open time to `openAt` for the matched date.\n */\nexport type SpecialOpen = {\n /** Human-readable name, used for debugging and logging. */\n name: string;\n /** Returns the UTC midnight `Date` for this late-open day in `year`, or `null` to skip. */\n resolve: (year: number) => Date | null;\n /** The overridden open time in local exchange time. */\n openAt: TimeOfDay;\n /** First year (inclusive) this rule applies. Defaults to −∞. */\n validFrom?: number;\n /** Last year (inclusive) this rule applies. Defaults to +∞. */\n validUntil?: number;\n};\n\n/**\n * Map of `YYYY-MM-DD` date strings to override times. Used for one-off\n * historical specials (e.g. a single early close due to a snowstorm) that do\n * not fit a repeating year-derived rule. Keys must be in `YYYY-MM-DD` format\n * in UTC.\n */\nexport type AdhocTimeOverrides = ReadonlyMap<string, TimeOfDay>;\n\n/**\n * Era-bounded session-time rule. Lookup picks the latest rule with `effectiveFrom ≤ date`.\n * Use `effectiveFrom: undefined` for the default (since-inception) rule.\n */\nexport type SessionTimeRule = {\n effectiveFrom?: string; // YYYY-MM-DD inclusive\n time: TimeOfDay;\n};\n\n/**\n * Returns the UTC midnight `Date` of the nth occurrence of `weekday` in the\n * given `month` and `year`. `weekday` follows `Date.getUTCDay()` convention\n * (0 = Sunday, 1 = Monday, …, 6 = Saturday). `n` is 1-based.\n *\n * Example: 3rd Monday of January 2024 → `nthWeekdayOfMonth(2024, 1, 1, 3)`.\n */\nexport function nthWeekdayOfMonth(year: number, month: number, weekday: number, n: number): Date {\n const first = new Date(Date.UTC(year, month - 1, 1));\n const offset = (weekday - first.getUTCDay() + 7) % 7;\n return new Date(Date.UTC(year, month - 1, 1 + offset + (n - 1) * 7));\n}\n\n/**\n * Returns the UTC midnight `Date` of the last occurrence of `weekday` in the\n * given `month` and `year`. `weekday` follows `Date.getUTCDay()` convention.\n *\n * Example: last Monday of May 2024 → `lastWeekdayOfMonth(2024, 5, 1)`.\n */\nexport function lastWeekdayOfMonth(year: number, month: number, weekday: number): Date {\n const last = new Date(Date.UTC(year, month, 0));\n const offset = (last.getUTCDay() - weekday + 7) % 7;\n return new Date(last.getTime() - offset * MS_PER_DAY);\n}\n\n/**\n * Computes the UTC midnight `Date` of Easter Sunday for the given Gregorian\n * `year` using the Anonymous Gregorian algorithm (also known as the \"Meeus/Jones/Butcher\"\n * algorithm). Valid for years 1583–4099.\n */\nexport function easter(year: number): Date {\n const a = year % 19;\n const b = Math.floor(year / 100);\n const c = year % 100;\n const d = Math.floor(b / 4);\n const e = b % 4;\n const f = Math.floor((b + 8) / 25);\n const g = Math.floor((b - f + 1) / 3);\n const h = (19 * a + b - d - g + 15) % 30;\n const i = Math.floor(c / 4);\n const k = c % 4;\n const L = (32 + 2 * e + 2 * i - h - k) % 7;\n const m = Math.floor((a + 11 * h + 22 * L) / 451);\n const month = Math.floor((h + L - 7 * m + 114) / 31);\n const day = ((h + L - 7 * m + 114) % 31) + 1;\n return new Date(Date.UTC(year, month - 1, day));\n}\n\n/**\n * Applies Saturday → Friday, Sunday → Monday observation to a holiday date.\n * Weekday dates are returned unchanged. Used when a {@link HolidayRule} has\n * `observe: true`.\n */\nexport function observed(d: Date): Date {\n const dow = d.getUTCDay();\n if (dow === 6) return new Date(d.getTime() - MS_PER_DAY);\n if (dow === 0) return new Date(d.getTime() + MS_PER_DAY);\n return d;\n}\n\n/**\n * Applies a list of {@link HolidayRule} definitions to a single `year` and\n * returns a `Set` of UTC millisecond timestamps for all holidays active that\n * year. Rules outside their `[validFrom, validUntil]` bounds are skipped.\n * Rules that return `null` from `resolve` are also skipped.\n */\nexport function resolveHolidays(rules: ReadonlyArray<HolidayRule>, year: number): Set<number> {\n const out = new Set<number>();\n for (const rule of rules) {\n if (rule.validFrom !== undefined && year < rule.validFrom) continue;\n if (rule.validUntil !== undefined && year > rule.validUntil) continue;\n const raw = rule.resolve(year);\n if (raw === null) continue;\n const final = rule.observe ? observed(raw) : raw;\n out.add(final.getTime());\n }\n return out;\n}\n\n/**\n * Applies a list of {@link SpecialClose} rules to a single `year` and returns\n * a map from UTC millisecond timestamp to override close time. Rules outside\n * their `[validFrom, validUntil]` bounds and rules that return `null` from\n * `resolve` are skipped.\n */\nexport function resolveSpecialCloses(rules: ReadonlyArray<SpecialClose>, year: number): Map<number, TimeOfDay> {\n const out = new Map<number, TimeOfDay>();\n for (const rule of rules) {\n if (rule.validFrom !== undefined && year < rule.validFrom) continue;\n if (rule.validUntil !== undefined && year > rule.validUntil) continue;\n const d = rule.resolve(year);\n if (d === null) continue;\n out.set(d.getTime(), rule.closeAt);\n }\n return out;\n}\n\n/**\n * Applies a list of {@link SpecialOpen} rules to a single `year` and returns\n * a map from UTC millisecond timestamp to override open time. Rules outside\n * their `[validFrom, validUntil]` bounds and rules that return `null` from\n * `resolve` are skipped.\n */\nexport function resolveSpecialOpens(rules: ReadonlyArray<SpecialOpen>, year: number): Map<number, TimeOfDay> {\n const out = new Map<number, TimeOfDay>();\n for (const rule of rules) {\n if (rule.validFrom !== undefined && year < rule.validFrom) continue;\n if (rule.validUntil !== undefined && year > rule.validUntil) continue;\n const d = rule.resolve(year);\n if (d === null) continue;\n out.set(d.getTime(), rule.openAt);\n }\n return out;\n}\n\n// ─── pandas-equivalent date helpers ─────────────────────────────────────────\n// These are general-purpose calendar utilities modelled on pandas_market_calendars\n// helpers. They are exchange-agnostic and reused across NYSE, LSE, and future ports.\n\n/** pandas `sunday_to_monday`: only Sunday observation; Saturday stays Saturday. */\nexport function sundayToMonday(d: Date): Date {\n return d.getUTCDay() === 0 ? new Date(d.getTime() + MS_PER_DAY) : d;\n}\n\n/** pandas `nearest_workday`: Sat → Friday, Sun → Monday, weekday → unchanged. */\nexport function nearestWorkday(d: Date): Date {\n const dow = d.getUTCDay();\n if (dow === 6) return new Date(d.getTime() - MS_PER_DAY);\n if (dow === 0) return new Date(d.getTime() + MS_PER_DAY);\n return d;\n}\n\n/**\n * First Monday on/after the given day of the month (mimics pandas `weekday=MO(n)` offset).\n * Pass `nth > 1` to skip forward that many additional weeks.\n */\nexport function firstMondayOnOrAfter(year: number, month: number, day: number, nth = 1): Date {\n const start = new Date(Date.UTC(year, month - 1, day));\n const offset = (1 - start.getUTCDay() + 7) % 7; // MON = 1\n return new Date(start.getTime() + (offset + 7 * (nth - 1)) * MS_PER_DAY);\n}\n\n/** Easter offset by `dayDelta` days (e.g. Good Friday = easterPlus(y, -2)). */\nexport function easterPlus(year: number, dayDelta: number): Date {\n return new Date(easter(year).getTime() + dayDelta * MS_PER_DAY);\n}\n\n/** Helper to drop a holiday if its observed date falls outside an allowed weekday set. */\nexport function dropIfNotInDays(d: Date | null, allowed: ReadonlySet<number>): Date | null {\n if (d === null) return null;\n return allowed.has(d.getUTCDay()) ? d : null;\n}\n\n/**\n * Pick the rule with the latest `effectiveFrom ≤ date.toISOString().slice(0,10)`.\n * Rules without `effectiveFrom` are treated as the default (since inception).\n * Throws if no rule matches at all (provide a default rule to guarantee a match).\n */\nexport function resolveSessionTime(rules: ReadonlyArray<SessionTimeRule>, date: Date): TimeOfDay {\n const key = date.toISOString().slice(0, 10);\n let best: SessionTimeRule | null = null;\n for (const rule of rules) {\n if (rule.effectiveFrom === undefined) {\n if (best === null) best = rule;\n continue;\n }\n if (rule.effectiveFrom <= key) {\n if (best === null || best.effectiveFrom === undefined || best.effectiveFrom < rule.effectiveFrom) {\n best = rule;\n }\n }\n }\n if (best === null) {\n throw new Error('resolveSessionTime: no matching rule (provide a default rule with no effectiveFrom)');\n }\n return best.time;\n}\n","import { ExchangeCalendar } from './exchange-calendar';\nimport {\n dropIfNotInDays,\n easterPlus,\n firstMondayOnOrAfter,\n lastWeekdayOfMonth,\n nearestWorkday,\n nthWeekdayOfMonth,\n sundayToMonday,\n type AdhocTimeOverrides,\n type HolidayRule,\n type SpecialClose,\n type SpecialOpen,\n} from './holiday-rules';\nimport type { TimeOfDay } from '../interfaces/calendar';\n\nconst MS_PER_DAY = 86_400_000;\n\n// Day-of-week constants matching JS Date.getUTCDay(): Sun=0, Mon=1, ... Sat=6.\nconst SUN = 0;\nconst MON = 1;\nconst TUE = 2;\nconst WED = 3;\nconst THU = 4;\nconst FRI = 5;\nconst SAT = 6;\n\nconst SATURDAY_END_KEY = '1952-09-29'; // Saturday trading retired starting this date.\n\nfunction utcDate(y: number, m: number, d: number): Date {\n return new Date(Date.UTC(y, m - 1, d));\n}\n\nfunction ymd(date: Date): string {\n return date.toISOString().slice(0, 10);\n}\n\nconst WEEKDAYS_MON_FRI: ReadonlySet<number> = new Set([MON, TUE, WED, THU, FRI]);\nconst WEEKDAYS_MON_SAT: ReadonlySet<number> = new Set([MON, TUE, WED, THU, FRI, SAT]);\n\nconst REGULAR_HOLIDAYS: ReadonlyArray<HolidayRule> = [\n // ── New Year's Day ─────────────────────────────────────────────────────────\n // Post-1952: Sunday → Monday observance, Saturday-NYD drops (no Friday close).\n {\n name: \"New Year's Day (post-1952)\",\n validFrom: 1952,\n resolve: (y) => dropIfNotInDays(sundayToMonday(utcDate(y, 1, 1)), WEEKDAYS_MON_FRI),\n },\n // Pre-1952: Saturday is a trading day; NYD on Saturday is observed on Saturday.\n {\n name: \"New Year's Day (pre-1952)\",\n validUntil: 1952,\n resolve: (y) => dropIfNotInDays(sundayToMonday(utcDate(y, 1, 1)), WEEKDAYS_MON_SAT),\n },\n\n // ── MLK Day (3rd Mon of Jan, from 1998) ────────────────────────────────────\n {\n name: 'Martin Luther King Jr. Day',\n validFrom: 1998,\n resolve: (y) => nthWeekdayOfMonth(y, 1, MON, 3),\n },\n\n // ── Presidents Day (3rd Mon of Feb, from 1971) ────────────────────────────\n {\n name: 'Presidents Day',\n validFrom: 1971,\n resolve: (y) => nthWeekdayOfMonth(y, 2, MON, 3),\n },\n\n // ── Washington's Birthday (Feb 22) ─────────────────────────────────────────\n // Pre-1952: Mon-Sat with Sunday → Monday.\n {\n name: \"Washington's Birthday (pre-1952)\",\n validUntil: 1952,\n resolve: (y) => dropIfNotInDays(sundayToMonday(utcDate(y, 2, 22)), WEEKDAYS_MON_SAT),\n },\n // 1952-09-29 → 1963: Mon-Fri with Sunday → Monday.\n {\n name: \"Washington's Birthday (1952-1963)\",\n validFrom: 1953,\n validUntil: 1963,\n resolve: (y) => dropIfNotInDays(sundayToMonday(utcDate(y, 2, 22)), WEEKDAYS_MON_FRI),\n },\n // 1964-1970: nearest_workday observance.\n {\n name: \"Washington's Birthday (1964-1970)\",\n validFrom: 1964,\n validUntil: 1970,\n resolve: (y) => nearestWorkday(utcDate(y, 2, 22)),\n },\n\n // ── Lincoln's Birthday (Feb 12, 1896-1953) ─────────────────────────────────\n {\n name: \"Lincoln's Birthday\",\n validFrom: 1896,\n validUntil: 1953,\n resolve: (y) => sundayToMonday(utcDate(y, 2, 12)),\n },\n\n // ── Good Friday ────────────────────────────────────────────────────────────\n // Closed every year EXCEPT 1898, 1906, 1907.\n {\n name: 'Good Friday (1908+)',\n validFrom: 1908,\n resolve: (y) => easterPlus(y, -2),\n },\n {\n name: 'Good Friday (pre-1898)',\n validFrom: 1885,\n validUntil: 1897,\n resolve: (y) => easterPlus(y, -2),\n },\n {\n name: 'Good Friday (1899-1905)',\n validFrom: 1899,\n validUntil: 1905,\n resolve: (y) => easterPlus(y, -2),\n },\n\n // ── Memorial Day ───────────────────────────────────────────────────────────\n // Modern: last Monday of May, from 1971.\n {\n name: 'Memorial Day (modern, 1971+)',\n validFrom: 1971,\n resolve: (y) => firstMondayOnOrAfter(y, 5, 25),\n },\n // Pre-1952 (Mon-Sat with Sunday → Monday).\n {\n name: 'Memorial Day (pre-1952)',\n validUntil: 1952,\n resolve: (y) => dropIfNotInDays(sundayToMonday(utcDate(y, 5, 30)), WEEKDAYS_MON_SAT),\n },\n // 1952-09-29 → 1963.\n {\n name: 'Memorial Day (1952-1963)',\n validFrom: 1953,\n validUntil: 1963,\n resolve: (y) => dropIfNotInDays(sundayToMonday(utcDate(y, 5, 30)), WEEKDAYS_MON_FRI),\n },\n // 1964-1969 nearest_workday.\n {\n name: 'Memorial Day (1964-1969)',\n validFrom: 1964,\n validUntil: 1969,\n resolve: (y) => nearestWorkday(utcDate(y, 5, 30)),\n },\n\n // ── Juneteenth (from 2022) ─────────────────────────────────────────────────\n {\n name: 'Juneteenth',\n validFrom: 2022,\n resolve: (y) => nearestWorkday(utcDate(y, 6, 19)),\n },\n\n // ── Independence Day ───────────────────────────────────────────────────────\n // Modern: nearest_workday, from 1954.\n {\n name: 'Independence Day (modern, 1954+)',\n validFrom: 1954,\n resolve: (y) => dropIfNotInDays(nearestWorkday(utcDate(y, 7, 4)), WEEKDAYS_MON_FRI),\n },\n // Pre-1952.\n {\n name: 'Independence Day (pre-1952)',\n validUntil: 1952,\n resolve: (y) => dropIfNotInDays(sundayToMonday(utcDate(y, 7, 4)), WEEKDAYS_MON_SAT),\n },\n // 1952-09-29 → 1953 (post-Saturday-trading transition).\n {\n name: 'Independence Day (1953)',\n validFrom: 1953,\n validUntil: 1953,\n resolve: (y) => dropIfNotInDays(sundayToMonday(utcDate(y, 7, 4)), WEEKDAYS_MON_FRI),\n },\n\n // ── Labor Day (1st Mon of Sep, from 1887) ─────────────────────────────────\n {\n name: 'Labor Day',\n validFrom: 1887,\n resolve: (y) => nthWeekdayOfMonth(y, 9, MON, 1),\n },\n\n // ── Columbus Day (Oct 12, 1909-1953) ───────────────────────────────────────\n {\n name: 'Columbus Day',\n validFrom: 1909,\n validUntil: 1953,\n resolve: (y) => sundayToMonday(utcDate(y, 10, 12)),\n },\n\n // ── Election Day (1848-1967, every year; 1968-1980 adhoc; thereafter none) ─\n {\n name: 'Election Day (1848-1967)',\n validFrom: 1885,\n validUntil: 1967,\n resolve: (y) => {\n // First Tuesday on/after Nov 2 (pandas: month=11 day=2 offset=TU(1)).\n const start = utcDate(y, 11, 2);\n const offset = (TUE - start.getUTCDay() + 7) % 7;\n return new Date(start.getTime() + offset * MS_PER_DAY);\n },\n },\n\n // ── Veterans/Armistice Day (Nov 11, 1934-1953) ─────────────────────────────\n {\n name: 'Veterans Day (1934-1953)',\n validFrom: 1934,\n validUntil: 1953,\n resolve: (y) => sundayToMonday(utcDate(y, 11, 11)),\n },\n\n // ── Thanksgiving ───────────────────────────────────────────────────────────\n // Modern: 4th Thursday of Nov, from 1942.\n {\n name: 'Thanksgiving (modern, 1942+)',\n validFrom: 1942,\n resolve: (y) => nthWeekdayOfMonth(y, 11, THU, 4),\n },\n // Pre-1939: last Thursday of Nov.\n {\n name: 'Thanksgiving (pre-1939)',\n validFrom: 1864,\n validUntil: 1938,\n resolve: (y) => lastWeekdayOfMonth(y, 11, THU),\n },\n // 1939-1941: 2nd-to-last Thursday of Nov (Franklin Thanksgiving).\n {\n name: 'Thanksgiving (1939-1941)',\n validFrom: 1939,\n validUntil: 1941,\n resolve: (y) => {\n const last = lastWeekdayOfMonth(y, 11, THU);\n return new Date(last.getTime() - 7 * MS_PER_DAY);\n },\n },\n\n // ── Christmas ──────────────────────────────────────────────────────────────\n // Modern: nearest_workday, from 1999.\n {\n name: 'Christmas (1999+)',\n validFrom: 1999,\n resolve: (y) => nearestWorkday(utcDate(y, 12, 25)),\n },\n // 1954-1998.\n {\n name: 'Christmas (1954-1998)',\n validFrom: 1954,\n validUntil: 1998,\n resolve: (y) => nearestWorkday(utcDate(y, 12, 25)),\n },\n // Pre-1954: sunday_to_monday only.\n {\n name: 'Christmas (pre-1954)',\n validUntil: 1953,\n resolve: (y) => sundayToMonday(utcDate(y, 12, 25)),\n },\n];\n\n// ─── Adhoc full-day closures (literal date set) ──────────────────────────────\n// Sourced verbatim from pandas_market_calendars/holidays/nyse.py adhoc lists.\nconst ADHOC_RAW: ReadonlyArray<string> = [\n // SatAfterGoodFridayAdhoc\n '1900-04-14',\n '1901-04-06',\n '1902-03-29',\n '1903-04-11',\n '1905-04-22',\n '1907-03-30',\n '1908-04-18',\n '1909-04-10',\n '1910-03-26',\n '1911-04-15',\n '1913-03-22',\n '1920-04-03',\n '1929-03-30',\n '1930-04-19',\n // MonBeforeIndependenceDayAdhoc\n '1899-07-03',\n // SatBeforeIndependenceDayAdhoc\n '1887-07-02',\n '1892-07-02',\n '1898-07-02',\n '1904-07-02',\n '1909-07-03',\n '1910-07-02',\n '1920-07-03',\n '1921-07-02',\n '1926-07-03',\n '1932-07-02',\n '1937-07-03',\n // SatAfterIndependenceDayAdhoc\n '1890-07-05',\n '1902-07-05',\n '1913-07-05',\n '1919-07-05',\n '1930-07-05',\n // DaysAfterIndependenceDayAdhoc\n '1901-07-05',\n '1901-07-06',\n '1968-07-05',\n // SatBeforeLaborDayAdhoc\n '1888-09-01',\n '1898-09-03',\n '1900-09-01',\n '1901-08-31',\n '1902-08-30',\n '1903-09-05',\n '1904-09-03',\n '1907-08-31',\n '1908-09-05',\n '1909-09-04',\n '1910-09-03',\n '1911-09-02',\n '1912-08-31',\n '1913-08-30',\n '1917-09-01',\n '1919-08-30',\n '1920-09-04',\n '1921-09-03',\n '1926-09-04',\n '1929-08-31',\n '1930-08-30',\n '1931-09-05',\n // USElectionDay1968to1980Adhoc\n '1968-11-05',\n '1972-11-07',\n '1976-11-02',\n '1980-11-04',\n // FridayAfterThanksgivingAdHoc\n '1888-11-30',\n // SatBeforeChristmasAdhoc\n '1887-12-24',\n '1898-12-24',\n '1904-12-24',\n '1910-12-24',\n '1911-12-23',\n '1922-12-23',\n '1949-12-24',\n '1950-12-23',\n // SatAfterChristmasAdhoc\n '1891-12-26',\n '1896-12-26',\n '1903-12-26',\n '1908-12-26',\n '1925-12-26',\n '1931-12-26',\n '1936-12-26',\n // ChristmasEvesAdhoc\n '1900-12-24',\n '1945-12-24',\n '1956-12-24',\n // DayAfterChristmasAdhoc\n '1958-12-26',\n // USVetransDayAdHoc\n '1921-11-11',\n '1968-11-11',\n // SatAfterColumbusDayAdHoc\n '1917-10-13',\n '1945-10-13',\n // LincolnsBirthDayAdhoc\n '1968-02-12',\n // GrantsBirthDayAdhoc\n '1897-04-27',\n // SatBeforeNewYearsAdhoc\n '1916-12-30',\n // SatBeforeWashingtonsBirthdayAdhoc\n '1903-02-21',\n // SatAfterWashingtonsBirthdayAdhoc\n '1901-02-23',\n '1907-02-23',\n '1929-02-23',\n '1946-02-23',\n // SatBeforeAfterLincolnsBirthdayAdhoc\n '1899-02-11',\n '1909-02-13',\n // SatBeforeDecorationAdhoc\n '1904-05-28',\n '1909-05-29',\n '1910-05-28',\n '1921-05-28',\n '1926-05-29',\n '1937-05-29',\n // SatAfterDecorationAdhoc\n '1902-05-31',\n '1913-05-31',\n '1919-05-31',\n '1924-05-31',\n '1930-05-31',\n // DayBeforeDecorationAdhoc\n '1899-05-29',\n '1961-05-29',\n // ── Irregular full-day closures ──\n // UlyssesGrantFuneral1885\n '1885-08-08',\n // ColumbianCelebration1892\n '1892-10-12',\n '1892-10-21',\n '1892-10-22',\n '1893-04-27',\n // GreatBlizzardOf1888\n '1888-03-12',\n '1888-03-13',\n // WashingtonInaugurationCentennialCelebration1889\n '1889-04-29',\n '1889-04-30',\n '1889-05-01',\n // CharterDay1898\n '1898-05-04',\n // WelcomeNavalCommander1898\n '1898-08-20',\n // AdmiralDeweyCelebration1899\n '1899-09-29',\n '1899-09-30',\n // GarretHobartFuneral1899\n '1899-11-25',\n // QueenVictoriaFuneral1901\n '1901-02-02',\n // MovedToProduceExchange1901\n '1901-04-27',\n // EnlargedProduceExchange1901\n '1901-05-11',\n // McKinleyDeathAndFuneral1901\n '1901-09-14',\n '1901-09-19',\n // KingEdwardVIIcoronation1902\n '1902-08-09',\n // NYSEnewBuildingOpen1903\n '1903-04-22',\n // HudsonFultonCelebration1909\n '1909-09-25',\n // JamesShermanFuneral1912\n '1912-11-02',\n // WeatherHeatClosing1917\n '1917-08-04',\n // DraftRegistrationDay1917\n '1917-06-05',\n // WeatherNoHeatClosing1918\n '1918-01-28',\n '1918-02-04',\n '1918-02-11',\n // DraftRegistrationDay1918\n '1918-09-12',\n // ArmisticeSigned1918\n '1918-11-11',\n // Homecoming27Division1919\n '1919-03-25',\n // ParadeOf77thDivision1919\n '1919-05-06',\n // BacklogRelief1919\n '1919-07-19',\n '1919-08-02',\n '1919-08-16',\n // GeneralPershingReturn1919\n '1919-09-10',\n // OfficeLocationChange1920\n '1920-05-01',\n // HardingDeath1923, HardingFuneral1923\n '1923-08-03',\n '1923-08-10',\n // LindberghParade1927\n '1927-06-13',\n // BacklogRelief1928\n '1928-04-07',\n '1928-04-21',\n '1928-05-05',\n '1928-05-12',\n '1928-05-19',\n '1928-05-26',\n '1928-11-24',\n // BacklogRelief1929\n '1929-02-09',\n '1929-11-01',\n '1929-11-02',\n '1929-11-09',\n '1929-11-16',\n '1929-11-23',\n '1929-11-29',\n '1929-11-30',\n // CoolidgeFuneral1933\n '1933-01-07',\n // BankHolidays1933 (Mar 4, 6-14)\n '1933-03-04',\n '1933-03-06',\n '1933-03-07',\n '1933-03-08',\n '1933-03-09',\n '1933-03-10',\n '1933-03-11',\n '1933-03-13',\n '1933-03-14',\n // (Mar 12, 1933 was a Sunday — naturally non-trading; upstream set still\n // includes it but our weekmask excludes Sundays. Keep parity by listing it.)\n '1933-03-12',\n // HeavyVolume1933 (closed Saturdays)\n '1933-07-29',\n '1933-08-05',\n '1933-08-12',\n '1933-08-19',\n '1933-08-26',\n '1933-09-02',\n // SatClosings1944\n '1944-08-19',\n '1944-08-26',\n '1944-09-02',\n // RooseveltDayOfMourning1945\n '1945-04-14',\n // VJday1945\n '1945-08-15',\n '1945-08-16',\n // NavyDay1945\n '1945-10-27',\n // RailroadStrike1946\n '1946-05-25',\n // SevereWeather1948\n '1948-01-03',\n // KennedyFuneral1963\n '1963-11-25',\n // MLKdayOfMourning1968\n '1968-04-09',\n // PaperworkCrisis1968 (every Wednesday from 1968-06-12 through 1968-12-18,\n // skipping holiday weeks per upstream literal list)\n '1968-06-12',\n '1968-06-19',\n '1968-06-26',\n '1968-07-10',\n '1968-07-17',\n '1968-07-24',\n '1968-07-31',\n '1968-08-07',\n '1968-08-14',\n '1968-08-21',\n '1968-08-28',\n '1968-09-11',\n '1968-09-18',\n '1968-09-25',\n '1968-10-02',\n '1968-10-09',\n '1968-10-16',\n '1968-10-23',\n '1968-10-30',\n '1968-11-20',\n '1968-12-04',\n '1968-12-11',\n '1968-12-18',\n // SnowClosing1969\n '1969-02-10',\n // EisenhowerFuneral1969\n '1969-03-31',\n // FirstLunarLandingClosing1969\n '1969-07-21',\n // TrumanFuneral1972\n '1972-12-28',\n // JohnsonFuneral1973\n '1973-01-25',\n // NewYorkCityBlackout77\n '1977-07-14',\n // HurricaneGloriaClosings1985\n '1985-09-27',\n // NixonFuneral1994\n '1994-04-27',\n // ReaganMourning2004\n '2004-06-11',\n // FordMourning2007\n '2007-01-02',\n // September11Closings2001\n '2001-09-11',\n '2001-09-12',\n '2001-09-13',\n '2001-09-14',\n // HurricaneSandyClosings2012\n '2012-10-29',\n '2012-10-30',\n // GeorgeHWBushDeath2018\n '2018-12-05',\n // JimmyCarterDeath2025\n '2025-01-09',\n];\n\n// Saturday-summer closings 1945-1952 (every Saturday in the listed window).\nfunction* generateSummerSaturdays(): IterableIterator<string> {\n const ranges: ReadonlyArray<[string, string]> = [\n ['1945-07-07', '1945-09-01'],\n ['1946-06-01', '1946-09-28'],\n ['1947-05-31', '1947-09-27'],\n ['1948-05-29', '1948-09-25'],\n ['1949-05-28', '1949-09-24'],\n ['1950-06-03', '1950-09-30'],\n ['1951-06-02', '1951-09-29'],\n ['1952-05-31', '1952-09-27'],\n ];\n for (const [from, to] of ranges) {\n let d = new Date(`${from}T00:00:00.000Z`);\n const end = new Date(`${to}T00:00:00.000Z`);\n while (d.getTime() <= end.getTime()) {\n if (d.getUTCDay() === SAT) yield ymd(d);\n d = new Date(d.getTime() + MS_PER_DAY);\n }\n }\n}\n\n// WWI shutdown 1914-07-31 → 1914-12-11 (every Mon-Sat).\n// Upstream: OnsetOfWWI1914 uses CustomBusinessDay(weekmask=\"Mon Tue Wed Thu Fri Sat\"),\n// confirming that Saturdays are included — consistent with the pre-1952 Mon-Sat trading week.\nfunction* generateWWIShutdown(): IterableIterator<string> {\n let d = new Date('1914-07-31T00:00:00.000Z');\n const end = new Date('1914-12-11T00:00:00.000Z');\n while (d.getTime() <= end.getTime()) {\n const dow = d.getUTCDay();\n if (dow !== SUN) yield ymd(d);\n d = new Date(d.getTime() + MS_PER_DAY);\n }\n}\n\nconst ADHOC_HOLIDAYS: ReadonlySet<string> = new Set<string>([\n ...ADHOC_RAW,\n ...generateSummerSaturdays(),\n ...generateWWIShutdown(),\n]);\n\n// ─── Rule-driven special closes (early-close rules) ─────────────────────────\nconst SPECIAL_CLOSES: ReadonlyArray<SpecialClose> = [\n // 1pm — Day-after-Thanksgiving 1993+, Christmas Eve weekday 1999+,\n // pre-Independence Day Mon/Tue/Thu (1995+), Wed before Independence Day (2013+),\n // Friday-after-Independence Day pre-2013 (1996-2012).\n {\n name: 'Day after Thanksgiving 1pm (1993+)',\n validFrom: 1993,\n closeAt: { h: 13, m: 0 },\n resolve: (y) => {\n const t = nthWeekdayOfMonth(y, 11, THU, 4);\n return new Date(t.getTime() + MS_PER_DAY);\n },\n },\n {\n name: 'Day after Thanksgiving 2pm (1992)',\n validFrom: 1992,\n validUntil: 1992,\n closeAt: { h: 14, m: 0 },\n resolve: (y) => {\n const t = nthWeekdayOfMonth(y, 11, THU, 4);\n return new Date(t.getTime() + MS_PER_DAY);\n },\n },\n {\n name: 'Christmas Eve Mon-Thu 1pm (1999+)',\n validFrom: 1999,\n closeAt: { h: 13, m: 0 },\n resolve: (y) => {\n const d = utcDate(y, 12, 24);\n const dow = d.getUTCDay();\n return dow >= MON && dow <= THU ? d : null;\n },\n },\n {\n name: 'Mon/Tue/Thu before Independence Day 1pm (1995+)',\n validFrom: 1995,\n closeAt: { h: 13, m: 0 },\n resolve: (y) => {\n const d = utcDate(y, 7, 3);\n const dow = d.getUTCDay();\n return dow === MON || dow === TUE || dow === THU ? d : null;\n },\n },\n {\n name: 'Wed before Independence Day 1pm (2013+)',\n validFrom: 2013,\n closeAt: { h: 13, m: 0 },\n resolve: (y) => {\n const d = utcDate(y, 7, 3);\n return d.getUTCDay() === WED ? d : null;\n },\n },\n {\n name: 'Friday after Independence Day 1pm (1996-2012)',\n validFrom: 1996,\n validUntil: 2012,\n closeAt: { h: 13, m: 0 },\n resolve: (y) => {\n const d = utcDate(y, 7, 5);\n return d.getUTCDay() === FRI ? d : null;\n },\n },\n];\n\n// ─── Adhoc special closes (literal map) ─────────────────────────────────────\nconst SPECIAL_CLOSES_ADHOC: AdhocTimeOverrides = new Map<string, TimeOfDay>([\n // 1pm closes\n ['1908-06-26', { h: 13, m: 0 }], // Grover Cleveland funeral\n // ChristmasEve1pmEarlyCloseAdhoc\n ['1951-12-24', { h: 13, m: 0 }],\n ['1996-12-24', { h: 13, m: 0 }],\n ['1997-12-24', { h: 13, m: 0 }],\n ['1998-12-24', { h: 13, m: 0 }],\n ['1999-12-24', { h: 13, m: 0 }],\n // DayAfterChristmas1pmEarlyCloseAdhoc\n ['1997-12-26', { h: 13, m: 0 }],\n ['2003-12-26', { h: 13, m: 0 }],\n // BacklogRelief1pmEarlyClose1929\n ['1929-11-06', { h: 13, m: 0 }],\n ['1929-11-07', { h: 13, m: 0 }],\n ['1929-11-08', { h: 13, m: 0 }],\n ['1929-11-11', { h: 13, m: 0 }],\n ['1929-11-12', { h: 13, m: 0 }],\n ['1929-11-13', { h: 13, m: 0 }],\n ['1929-11-14', { h: 13, m: 0 }],\n ['1929-11-15', { h: 13, m: 0 }],\n ['1929-11-18', { h: 13, m: 0 }],\n ['1929-11-19', { h: 13, m: 0 }],\n ['1929-11-20', { h: 13, m: 0 }],\n ['1929-11-21', { h: 13, m: 0 }],\n ['1929-11-22', { h: 13, m: 0 }],\n // 12pm early close — ParadeOfNationalGuard1917\n ['1917-08-29', { h: 12, m: 0 }],\n // LibertyDay 1917\n ['1917-10-24', { h: 12, m: 0 }],\n // LibertyDay 1918\n ['1918-04-26', { h: 12, m: 0 }],\n // WallStreetExplosion 1920\n ['1920-09-16', { h: 12, m: 0 }],\n // NRAdemonstration 1933\n ['1933-09-13', { h: 12, m: 0 }],\n // 12:30pm — RooseveltFuneral 1919\n ['1919-01-07', { h: 12, m: 30 }],\n // WoodrowWilsonFuneral 1924\n ['1924-02-06', { h: 12, m: 30 }],\n // TaftFuneral 1930\n ['1930-03-11', { h: 12, m: 30 }],\n // GasFumes 1933\n ['1933-08-04', { h: 12, m: 30 }],\n // 11am close — KingEdwardDeath 1910\n ['1910-05-07', { h: 11, m: 0 }],\n // 14:00 — HooverFuneral 1964\n ['1964-10-23', { h: 14, m: 0 }],\n // Snow2pmEarlyClose1967 (Feb 7, 1967)\n ['1967-02-07', { h: 14, m: 0 }],\n // Snow2pmEarlyClose1978\n ['1978-02-06', { h: 14, m: 0 }],\n // Snow2pmEarlyClose1996\n ['1996-01-08', { h: 14, m: 0 }],\n // 14:07 — Kennedy assassination\n ['1963-11-22', { h: 14, m: 7 }],\n // 14:30 — FalseArmistice 1918\n ['1918-11-07', { h: 14, m: 30 }],\n // CromwellFuneral 1925\n ['1925-09-18', { h: 14, m: 30 }],\n // Snow230EarlyClose1975\n ['1975-02-12', { h: 14, m: 30 }],\n // Snow230pmEarlyClose1994\n ['1994-02-11', { h: 14, m: 30 }],\n // 15:00 — HurricaneWatch 1976\n ['1976-08-09', { h: 15, m: 0 }],\n // 15:17 — Reagan assassination attempt\n ['1981-03-30', { h: 15, m: 17 }],\n // 15:28 — ConEd power fail\n ['1981-09-09', { h: 15, m: 28 }],\n // 15:30 — CircuitBreakerTriggered 1997\n ['1997-10-27', { h: 15, m: 30 }],\n // 15:56 — SystemProb 2005\n ['2005-06-01', { h: 15, m: 56 }],\n // ChristmasEve2pmEarlyCloseAdhoc\n ['1974-12-24', { h: 14, m: 0 }],\n ['1975-12-24', { h: 14, m: 0 }],\n ['1990-12-24', { h: 14, m: 0 }],\n ['1991-12-24', { h: 14, m: 0 }],\n ['1992-12-24', { h: 14, m: 0 }],\n // HeavyVolume2pmEarlyClose1933\n ['1933-07-26', { h: 14, m: 0 }],\n ['1933-07-27', { h: 14, m: 0 }],\n ['1933-07-28', { h: 14, m: 0 }],\n // BacklogRelief2pmEarlyClose1928 (May 21-25, 1928 Mon-Fri+Sat)\n ['1928-05-21', { h: 14, m: 0 }],\n ['1928-05-22', { h: 14, m: 0 }],\n ['1928-05-23', { h: 14, m: 0 }],\n ['1928-05-24', { h: 14, m: 0 }],\n ['1928-05-25', { h: 14, m: 0 }],\n // 1987 backlog 2pm: Oct 23-30 (Fri-Fri); Mon-Fri set\n ['1987-10-23', { h: 14, m: 0 }],\n ['1987-10-26', { h: 14, m: 0 }],\n ['1987-10-27', { h: 14, m: 0 }],\n ['1987-10-28', { h: 14, m: 0 }],\n ['1987-10-29', { h: 14, m: 0 }],\n ['1987-10-30', { h: 14, m: 0 }],\n // 1987 backlog 2:30pm: Nov 2-4\n ['1987-11-02', { h: 14, m: 30 }],\n ['1987-11-03', { h: 14, m: 30 }],\n ['1987-11-04', { h: 14, m: 30 }],\n // 1987 backlog 3pm: Nov 5-6\n ['1987-11-05', { h: 15, m: 0 }],\n ['1987-11-06', { h: 15, m: 0 }],\n // 1987 backlog 3:30pm: Nov 9-11\n ['1987-11-09', { h: 15, m: 30 }],\n ['1987-11-10', { h: 15, m: 30 }],\n ['1987-11-11', { h: 15, m: 30 }],\n]);\n\n// 1966 transit strike 2pm closes (Jan 6-14 weekdays).\n(() => {\n let d = new Date('1966-01-06T00:00:00.000Z');\n const end = new Date('1966-01-14T00:00:00.000Z');\n while (d.getTime() <= end.getTime()) {\n const dow = d.getUTCDay();\n if (dow >= MON && dow <= FRI) {\n (SPECIAL_CLOSES_ADHOC as Map<string, TimeOfDay>).set(ymd(d), { h: 14, m: 0 });\n }\n d = new Date(d.getTime() + MS_PER_DAY);\n }\n})();\n\n// 1967 backlog 2pm closes (Aug 9-18 weekdays).\n(() => {\n let d = new Date('1967-08-09T00:00:00.000Z');\n const end = new Date('1967-08-18T00:00:00.000Z');\n while (d.getTime() <= end.getTime()) {\n const dow = d.getUTCDay();\n if (dow >= MON && dow <= FRI) {\n (SPECIAL_CLOSES_ADHOC as Map<string, TimeOfDay>).set(ymd(d), { h: 14, m: 0 });\n }\n d = new Date(d.getTime() + MS_PER_DAY);\n }\n})();\n\n// 1968 backlog 2pm closes (Jan 22 - Mar 1 weekdays).\n(() => {\n let d = new Date('1968-01-22T00:00:00.000Z');\n const end = new Date('1968-03-01T00:00:00.000Z');\n while (d.getTime() <= end.getTime()) {\n const dow = d.getUTCDay();\n if (dow >= MON && dow <= FRI) {\n (SPECIAL_CLOSES_ADHOC as Map<string, TimeOfDay>).set(ymd(d), { h: 14, m: 0 });\n }\n d = new Date(d.getTime() + MS_PER_DAY);\n }\n})();\n\n// 1969 paperwork crisis 2pm (Jan 1 - Jul 3 weekdays).\n(() => {\n let d = new Date('1969-01-01T00:00:00.000Z');\n const end = new Date('1969-07-03T00:00:00.000Z');\n while (d.getTime() <= end.getTime()) {\n const dow = d.getUTCDay();\n if (dow >= MON && dow <= FRI) {\n (SPECIAL_CLOSES_ADHOC as Map<string, TimeOfDay>).set(ymd(d), { h: 14, m: 0 });\n }\n d = new Date(d.getTime() + MS_PER_DAY);\n }\n})();\n\n// 1969 paperwork crisis 2:30pm (Jul 7 - Sep 26 weekdays).\n(() => {\n let d = new Date('1969-07-07T00:00:00.000Z');\n const end = new Date('1969-09-26T00:00:00.000Z');\n while (d.getTime() <= end.getTime()) {\n const dow = d.getUTCDay();\n if (dow >= MON && dow <= FRI) {\n (SPECIAL_CLOSES_ADHOC as Map<string, TimeOfDay>).set(ymd(d), { h: 14, m: 30 });\n }\n d = new Date(d.getTime() + MS_PER_DAY);\n }\n})();\n\n// 1969-1970 paperwork crisis 3pm (Sep 29, 1969 - May 1, 1970 weekdays).\n(() => {\n let d = new Date('1969-09-29T00:00:00.000Z');\n const end = new Date('1970-05-01T00:00:00.000Z');\n while (d.getTime() <= end.getTime()) {\n const dow = d.getUTCDay();\n if (dow >= MON && dow <= FRI) {\n (SPECIAL_CLOSES_ADHOC as Map<string, TimeOfDay>).set(ymd(d), { h: 15, m: 0 });\n }\n d = new Date(d.getTime() + MS_PER_DAY);\n }\n})();\n\n// ─── Rule-driven special opens ──────────────────────────────────────────────\nconst SPECIAL_OPENS: ReadonlyArray<SpecialOpen> = [];\n\n// ─── Adhoc special opens (literal map) ──────────────────────────────────────\nconst SPECIAL_OPENS_ADHOC: AdhocTimeOverrides = new Map<string, TimeOfDay>([\n // 9:31am — ConEdXformer1990\n ['1990-12-27', { h: 9, m: 31 }],\n // EnduringFreedomMomentSilence 2001\n ['2001-10-08', { h: 9, m: 31 }],\n // 9:32am — IraqiFreedom 2003\n ['2003-03-20', { h: 9, m: 32 }],\n // ReaganMomentSilence 2004\n ['2004-06-07', { h: 9, m: 32 }],\n // FordMomentSilence 2006\n ['2006-12-27', { h: 9, m: 32 }],\n // 9:33am — Sept11MomentSilence 2001\n ['2001-09-17', { h: 9, m: 33 }],\n // 10:15 — Snow1015LateOpen1967\n ['1967-02-07', { h: 10, m: 15 }],\n // MerrillLynchComputer1015LateOpen1974\n ['1974-01-16', { h: 10, m: 15 }],\n // FireDrill1015LateOpen1974\n ['1974-11-22', { h: 10, m: 15 }],\n // FireDrill1015LateOpen1976\n ['1976-06-08', { h: 10, m: 15 }],\n // 10:30 — TrafficBlockLateOpen1919\n ['1919-12-30', { h: 10, m: 30 }],\n // TrafficBlockLateOpen1920\n ['1920-02-06', { h: 10, m: 30 }],\n // Computer1030LateOpen1995\n ['1995-12-18', { h: 10, m: 30 }],\n // 10:45 — EclipseOfSunLateOpen1925\n ['1925-01-24', { h: 10, m: 45 }],\n // Storm1045LateOpen1969\n ['1969-06-02', { h: 10, m: 45 }],\n // 11:00 — Snow11amLateOpen1934\n ['1934-02-20', { h: 11, m: 0 }],\n // KingGeorgeVFuneral1936\n ['1936-01-28', { h: 11, m: 0 }],\n // Snow11amLateOpening1960\n ['1960-12-12', { h: 11, m: 0 }],\n // Snow11amLateOpen1969\n ['1969-02-11', { h: 11, m: 0 }],\n // Ice11amLateOpen1973\n ['1973-12-17', { h: 11, m: 0 }],\n // Snow11amLateOpen1978\n ['1978-02-07', { h: 11, m: 0 }],\n // Fire11amLateOpen1989\n ['1989-11-10', { h: 11, m: 0 }],\n // Snow11amLateOpen1996\n ['1996-01-08', { h: 11, m: 0 }],\n // 11:05 — PowerFail1965\n ['1965-11-10', { h: 11, m: 5 }],\n // 11:15 — Storm1115LateOpen1976\n ['1976-02-02', { h: 11, m: 15 }],\n // 12:00 — KingEdwardFuneral1910\n ['1910-05-20', { h: 12, m: 0 }],\n // JPMorganFuneral1913\n ['1913-04-14', { h: 12, m: 0 }],\n // WilliamGaynorFuneral1913\n ['1913-09-22', { h: 12, m: 0 }],\n // Snow12pmLateOpen1978\n ['1978-01-20', { h: 12, m: 0 }],\n // Sept11Anniversary 2002\n ['2002-09-11', { h: 12, m: 0 }],\n // BacklogRelief12pmLateOpen1929\n ['1929-10-31', { h: 12, m: 0 }],\n // HeavyVolume12pmLateOpen1933\n ['1933-07-24', { h: 12, m: 0 }],\n ['1933-07-25', { h: 12, m: 0 }],\n // HeavyVolume11amLateOpen1933\n ['1933-07-26', { h: 11, m: 0 }],\n ['1933-07-27', { h: 11, m: 0 }],\n ['1933-07-28', { h: 11, m: 0 }],\n // 13:00 — AnnunciatorBoardFire 1921\n ['1921-08-02', { h: 13, m: 0 }],\n // TroopsInGulf931LateOpens1991\n ['1991-01-17', { h: 9, m: 31 }],\n ['1991-02-25', { h: 9, m: 31 }],\n]);\n\n/**\n * New York Stock Exchange (NYSE) trading-day calendar covering 1885-01-01 to\n * the present. Also applicable to NYSE-equivalent venues (NASDAQ, BATS, DJIA,\n * DOW). Faithful port of `pandas_market_calendars`' `nyse.py`.\n *\n * **Era boundaries:**\n * - Weekmask: Mon–Sat through 1952-09-28; Mon–Fri from 1952-09-29 onward\n * (Saturday trading retired on that date).\n * - Regular open: 10:00 ET before 1985-09-30; 09:30 ET from 1985-09-30 onward.\n * - Regular close: 15:00 ET before 1952-09-29; 15:30 ET through 1973-12-31;\n * 16:00 ET from 1974-01-02 onward. Saturday closes (pre-1952) are\n * approximated as 12:00.\n *\n * Holiday coverage includes the full set of regular (rule-derived) and adhoc\n * (literal date set) closures sourced from `pandas_market_calendars`, spanning\n * historical events from the Ulysses Grant funeral (1885) through the Jimmy\n * Carter national day of mourning (2025).\n */\nexport class NYSEExchangeCalendar extends ExchangeCalendar {\n readonly name = 'NYSE';\n readonly tz = 'America/New_York';\n\n protected override regularHolidays(): ReadonlyArray<HolidayRule> {\n return REGULAR_HOLIDAYS;\n }\n\n protected override adhocHolidays(): ReadonlySet<string> {\n return ADHOC_HOLIDAYS;\n }\n\n protected override specialCloses(): ReadonlyArray<SpecialClose> {\n return SPECIAL_CLOSES;\n }\n\n protected override specialClosesAdhoc(): AdhocTimeOverrides {\n return SPECIAL_CLOSES_ADHOC;\n }\n\n protected override specialOpens(): ReadonlyArray<SpecialOpen> {\n return SPECIAL_OPENS;\n }\n\n protected override specialOpensAdhoc(): AdhocTimeOverrides {\n return SPECIAL_OPENS_ADHOC;\n }\n\n protected override regularOpen(date: Date): TimeOfDay {\n return ymd(date) < '1985-09-30' ? { h: 10, m: 0 } : { h: 9, m: 30 };\n }\n\n protected override regularClose(date: Date): TimeOfDay {\n const key = ymd(date);\n // Saturday close pre-1952 was 12:00 (approximation, see spec).\n if (key < SATURDAY_END_KEY && date.getUTCDay() === SAT) return { h: 12, m: 0 };\n if (key < SATURDAY_END_KEY) return { h: 15, m: 0 };\n if (key < '1974-01-02') return { h: 15, m: 30 };\n return { h: 16, m: 0 };\n }\n\n protected override weekmask(date: Date): ReadonlySet<number> {\n return ymd(date) < SATURDAY_END_KEY ? WEEKDAYS_MON_SAT : WEEKDAYS_MON_FRI;\n }\n}\n","import { ExchangeCalendar } from './exchange-calendar';\nimport {\n dropIfNotInDays,\n easterPlus,\n firstMondayOnOrAfter,\n lastWeekdayOfMonth,\n type AdhocTimeOverrides,\n type HolidayRule,\n type SpecialClose,\n type SpecialOpen,\n} from './holiday-rules';\nimport type { TimeOfDay } from '../interfaces/calendar';\n\nconst MS_PER_DAY = 86_400_000;\n\n// Day-of-week constants matching JS Date.getUTCDay(): Sun=0, Mon=1, ..., Sat=6.\nconst SUN = 0;\nconst MON = 1;\nconst TUE = 2;\nconst SAT = 6;\n\nfunction utcDate(y: number, m: number, d: number): Date {\n return new Date(Date.UTC(y, m - 1, d));\n}\n\nconst WEEKDAYS_MON_FRI: ReadonlySet<number> = new Set([1, 2, 3, 4, 5]);\nconst MON_TUE: ReadonlySet<number> = new Set([MON, TUE]);\n\n/**\n * pandas `weekend_to_monday`: Sat → Monday, Sun → Monday. Weekday → unchanged.\n * Used by LSE for New Year's Day observance.\n */\nfunction weekendToMonday(d: Date): Date {\n const dow = d.getUTCDay();\n if (dow === SAT) return new Date(d.getTime() + 2 * MS_PER_DAY);\n if (dow === SUN) return new Date(d.getTime() + MS_PER_DAY);\n return d;\n}\n\n/**\n * pandas `previous_friday`: if Sat → Friday (−1 day); if Sun → Friday (−2 days);\n * weekday → unchanged. Used by LSE for Christmas Eve and New Year's Eve early-close\n * observance — the early close moves to the prior Friday when the calendar date\n * falls on a weekend.\n */\nfunction previousFriday(d: Date): Date {\n const dow = d.getUTCDay();\n if (dow === SAT) return new Date(d.getTime() - MS_PER_DAY);\n if (dow === SUN) return new Date(d.getTime() - 2 * MS_PER_DAY);\n return d;\n}\n\n// ─── Regular holidays ───────────────────────────────────────────────────────\n// Faithful port of pandas_market_calendars/holidays/uk.py rule definitions.\nconst REGULAR_HOLIDAYS: ReadonlyArray<HolidayRule> = [\n // ── New Year's Day ─────────────────────────────────────────────────────────\n // pandas: weekend_to_monday observance (Sat → Mon, Sun → Mon).\n {\n name: \"New Year's Day\",\n resolve: (y) => weekendToMonday(utcDate(y, 1, 1)),\n },\n\n // ── Good Friday (easter − 2) ───────────────────────────────────────────────\n {\n name: 'Good Friday',\n resolve: (y) => easterPlus(y, -2),\n },\n\n // ── Easter Monday (easter + 1) ─────────────────────────────────────────────\n {\n name: 'Easter Monday',\n resolve: (y) => easterPlus(y, 1),\n },\n\n // ── Early May Bank Holiday — first Monday of May ───────────────────────────\n // Upstream splits this into three eras to remove May 4 1995 and May 4 2020,\n // which were displaced for VE-Day anniversaries.\n {\n name: 'Early May Bank Holiday (pre-1995)',\n validUntil: 1994,\n resolve: (y) => firstMondayOnOrAfter(y, 5, 1),\n },\n {\n name: 'Early May Bank Holiday (1996-2019)',\n validFrom: 1996,\n validUntil: 2019,\n resolve: (y) => firstMondayOnOrAfter(y, 5, 1),\n },\n {\n name: 'Early May Bank Holiday (2021+)',\n validFrom: 2021,\n resolve: (y) => firstMondayOnOrAfter(y, 5, 1),\n },\n\n // ── Spring Bank Holiday — last Monday of May ───────────────────────────────\n // Upstream splits to skip the regular Spring Bank in 2002 (Golden Jubilee),\n // 2012 (Diamond Jubilee), and 2022 (Platinum Jubilee). Those years have\n // adhoc Jubilee closures that replace it.\n {\n name: 'Spring Bank Holiday (pre-2002)',\n validUntil: 2001,\n resolve: (y) => lastWeekdayOfMonth(y, 5, MON),\n },\n {\n name: 'Spring Bank Holiday (2003-2011)',\n validFrom: 2003,\n validUntil: 2011,\n resolve: (y) => lastWeekdayOfMonth(y, 5, MON),\n },\n {\n name: 'Spring Bank Holiday (2013-2021)',\n validFrom: 2013,\n validUntil: 2021,\n resolve: (y) => lastWeekdayOfMonth(y, 5, MON),\n },\n {\n name: 'Spring Bank Holiday (2023+)',\n validFrom: 2023,\n resolve: (y) => lastWeekdayOfMonth(y, 5, MON),\n },\n\n // ── Summer Bank Holiday — last Monday of August ────────────────────────────\n {\n name: 'Summer Bank Holiday',\n resolve: (y) => lastWeekdayOfMonth(y, 8, MON),\n },\n\n // ── Christmas Day (Dec 25) ─────────────────────────────────────────────────\n // pandas Holiday with no observance — the literal Dec 25 is added; if it\n // falls on a weekend the WeekendChristmas rule below adds a substitute Mon/Tue.\n {\n name: 'Christmas Day',\n resolve: (y) => utcDate(y, 12, 25),\n },\n\n // ── Weekend Christmas substitute (Dec 27, only Mon/Tue) ────────────────────\n // If Dec 25 is Sat → Dec 27 is Mon (substitute Christmas).\n // If Dec 25 is Sun → Dec 27 is Tue (substitute Christmas, after Boxing Day Mon Dec 26).\n {\n name: 'Weekend Christmas',\n resolve: (y) => dropIfNotInDays(utcDate(y, 12, 27), MON_TUE),\n },\n\n // ── Boxing Day (Dec 26) ────────────────────────────────────────────────────\n {\n name: 'Boxing Day',\n resolve: (y) => utcDate(y, 12, 26),\n },\n\n // ── Weekend Boxing Day substitute (Dec 28, only Mon/Tue) ───────────────────\n // If Dec 26 is Sat → Dec 28 is Mon (substitute Boxing).\n // If Dec 26 is Sun → Dec 28 is Tue (substitute Boxing, after Christmas observed Mon Dec 27).\n {\n name: 'Weekend Boxing Day',\n resolve: (y) => dropIfNotInDays(utcDate(y, 12, 28), MON_TUE),\n },\n];\n\n// ─── Adhoc full-day closures ────────────────────────────────────────────────\n// Sourced verbatim from pandas_market_calendars/holidays/uk.py UniqueCloses.\nconst ADHOC_HOLIDAYS: ReadonlySet<string> = new Set<string>([\n // VE-Day anniversaries (Early May Bank Holiday displaced)\n '1995-05-08', // 50th anniversary\n '2020-05-08', // 75th anniversary\n\n // Queen Elizabeth II Jubilees\n '1977-06-07', // Silver Jubilee\n '2002-06-03', // Golden Jubilee — Spring Bank holiday moved\n '2002-06-04', // Golden Jubilee — additional\n '2012-06-04', // Diamond Jubilee — Spring Bank holiday moved\n '2012-06-05', // Diamond Jubilee — additional\n '2022-06-02', // Platinum Jubilee — Spring Bank holiday moved\n '2022-06-03', // Platinum Jubilee — additional\n\n // State funerals\n '2022-09-19', // Queen Elizabeth II\n\n // Royal weddings\n '1973-11-14', // Princess Anne and Mark Phillips\n '1981-07-29', // Prince Charles and Diana Spencer\n '2011-04-29', // Prince William and Catherine Middleton\n\n // Coronation of King Charles III\n '2023-05-08',\n\n // Miscellaneous\n '1999-12-31', // Eve of 3rd Millennium A.D.\n]);\n\n// ─── Rule-driven special closes (12:30 early close) ─────────────────────────\n// Upstream LSE: ChristmasEve and LSENewYearsEve — both use `previous_friday`\n// observance, so when Dec 24 / Dec 31 falls on a weekend the early close moves\n// to the prior Friday (a regular trading day). Modern session close is 16:30\n// so a 12:30 close is genuinely early.\nconst SPECIAL_CLOSES: ReadonlyArray<SpecialClose> = [\n {\n name: 'Christmas Eve early close',\n closeAt: { h: 12, m: 30 },\n resolve: (y) => dropIfNotInDays(previousFriday(utcDate(y, 12, 24)), WEEKDAYS_MON_FRI),\n },\n {\n name: \"New Year's Eve early close\",\n closeAt: { h: 12, m: 30 },\n resolve: (y) => dropIfNotInDays(previousFriday(utcDate(y, 12, 31)), WEEKDAYS_MON_FRI),\n },\n];\n\n// ─── Adhoc special closes (literal) ─────────────────────────────────────────\n// Upstream LSE has no adhoc early-close map.\nconst SPECIAL_CLOSES_ADHOC: AdhocTimeOverrides = new Map<string, TimeOfDay>();\n\n// ─── Special opens — none in upstream LSE ───────────────────────────────────\nconst SPECIAL_OPENS: ReadonlyArray<SpecialOpen> = [];\nconst SPECIAL_OPENS_ADHOC: AdhocTimeOverrides = new Map<string, TimeOfDay>();\n\n/**\n * London Stock Exchange (LSE) trading-day calendar. Faithful port of\n * `pandas_market_calendars`' `lse.py` and `holidays/uk.py`. Historical\n * coverage begins 1801-01-01, aligned with the start of the modern exchange\n * after the Banking and Financial Dealings Act 1971 codified the current\n * bank-holiday framework.\n *\n * **Session**: 08:00–16:30 Europe/London. The exchange observes BST (UTC+1)\n * in summer and GMT (UTC+0) in winter — DST handling is delegated to luxon via\n * the `Europe/London` IANA timezone, so wall-clock session times are stable\n * across the DST transition while their UTC equivalents shift by one hour.\n *\n * **Early closes**: Christmas Eve (Dec 24) and New Year's Eve (Dec 31) close\n * at 12:30. Both use `previous_friday` observance — when the calendar date\n * falls on a weekend, the early close moves to the prior Friday.\n *\n * **Era boundaries**: bank-holiday exceptions for Royal Jubilees and VE-Day\n * anniversaries are implemented by splitting affected `Spring Bank Holiday`\n * and `Early May Bank Holiday` rules into era-bounded shards (matching\n * upstream `start_date` / `end_date` markers) and adding the displaced dates\n * as adhoc closures.\n */\nexport class LSEExchangeCalendar extends ExchangeCalendar {\n readonly name = 'LSE';\n readonly tz = 'Europe/London';\n\n protected override regularHolidays(): ReadonlyArray<HolidayRule> {\n return REGULAR_HOLIDAYS;\n }\n\n protected override adhocHolidays(): ReadonlySet<string> {\n return ADHOC_HOLIDAYS;\n }\n\n protected override specialCloses(): ReadonlyArray<SpecialClose> {\n return SPECIAL_CLOSES;\n }\n\n protected override specialClosesAdhoc(): AdhocTimeOverrides {\n return SPECIAL_CLOSES_ADHOC;\n }\n\n protected override specialOpens(): ReadonlyArray<SpecialOpen> {\n return SPECIAL_OPENS;\n }\n\n protected override specialOpensAdhoc(): AdhocTimeOverrides {\n return SPECIAL_OPENS_ADHOC;\n }\n\n protected override regularOpen(_date: Date): TimeOfDay {\n return { h: 8, m: 0 };\n }\n\n protected override regularClose(_date: Date): TimeOfDay {\n return { h: 16, m: 30 };\n }\n\n protected override weekmask(_date: Date): ReadonlySet<number> {\n return WEEKDAYS_MON_FRI;\n }\n}\n","import { ExchangeCalendar } from './exchange-calendar';\nimport { NYSEExchangeCalendar } from './nyse';\nimport { LSEExchangeCalendar } from './lse';\n\n/**\n * Union of supported exchange names accepted by {@link getCalendar}.\n *\n * - `'NYSE'` — New York Stock Exchange (and NYSE-equivalent venues).\n * - `'LSE'` — London Stock Exchange.\n */\nexport type ExchangeName = 'NYSE' | 'LSE';\n\n/**\n * Returns a new instance of the {@link ExchangeCalendar} registered under\n * `name`. Acts as a simple factory / registry for the two built-in calendar\n * implementations.\n *\n * Supported exchange names: `'NYSE'` ({@link NYSEExchangeCalendar}) and\n * `'LSE'` ({@link LSEExchangeCalendar}). TypeScript's exhaustive switch\n * prevents unknown names from compiling.\n *\n * @param name - One of the supported {@link ExchangeName} values.\n * @returns A fresh `ExchangeCalendar` instance for the named exchange.\n *\n * @example\n * ```ts\n * import { getCalendar } from '@livefolio/sdk';\n *\n * const nyse = getCalendar('NYSE');\n * console.log(nyse.isOpen(new Date('2024-07-04'))); // false — US Independence Day\n *\n * const lse = getCalendar('LSE');\n * console.log(lse.isOpen(new Date('2024-12-25'))); // false — Christmas Day\n * ```\n */\nexport function getCalendar(name: ExchangeName): ExchangeCalendar {\n switch (name) {\n case 'NYSE':\n return new NYSEExchangeCalendar();\n case 'LSE':\n return new LSEExchangeCalendar();\n }\n}\n","import type { Calendar, Session } from '../interfaces/calendar';\nimport type { DateRange } from '../interfaces/types';\n\nconst MS_PER_DAY = 86_400_000;\n\nfunction midnightUtc(d: Date): Date {\n return new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));\n}\n\n/**\n * 24/7 calendar where every day is a single session running midnight UTC to\n * the next midnight UTC. Suitable for crypto strategies (BTC, ETH) and any\n * always-on market.\n *\n * - `isOpen(t)` always returns `true`.\n * - `next(t)` returns midnight UTC of the day after `t`.\n * - `previous(t)` returns midnight UTC of the day before `t`.\n * - `sessions(range)` returns one Date per day in `[range.from, range.to)`.\n * - `schedule(range)` returns full Sessions with `open`/`close` at midnight UTC.\n * - `isEarlyClose(t)` always returns `false`.\n */\nexport class Crypto24x7Calendar implements Calendar {\n isOpen(_t: Date): boolean {\n return true;\n }\n\n next(t: Date): Date {\n return new Date(midnightUtc(t).getTime() + MS_PER_DAY);\n }\n\n previous(t: Date): Date {\n return new Date(midnightUtc(t).getTime() - MS_PER_DAY);\n }\n\n sessions(range: DateRange): ReadonlyArray<Date> {\n const out: Date[] = [];\n let cursor = midnightUtc(range.from);\n const end = range.to.getTime();\n while (cursor.getTime() < end) {\n out.push(cursor);\n cursor = new Date(cursor.getTime() + MS_PER_DAY);\n }\n return out;\n }\n\n schedule(range: DateRange): ReadonlyArray<Session> {\n return this.sessions(range).map((date) => ({\n date,\n open: date,\n close: new Date(date.getTime() + MS_PER_DAY),\n }));\n }\n\n isEarlyClose(_t: Date): boolean {\n return false;\n }\n}\n","export type {\n AssetRef,\n SyntheticAsset,\n RebalanceFrequency,\n RebalanceConfig,\n TacticalFeatureSpec,\n TacticalFeatureKind,\n FeatureRef,\n Tolerance,\n Comparison,\n ComparisonOp,\n AllocateNode,\n IfNode,\n RuleNode,\n TacticalSpec,\n RuleTreeState,\n} from './types';\nexport { evaluateRuleTree } from './evaluate-rule-tree';\nexport { evaluateFeatureSpecs } from './evaluate-feature-specs';\nexport { withSynthetics } from './synthetics';\nexport {\n fromSpec,\n isRebalanceDay,\n periodKey,\n _resetTacticalDeprecationWarningForTesting,\n type TacticalFeatures,\n type FromSpecOptions,\n} from './from-spec';\n","import type { TargetWeights } from '../strategy/reconcile';\nimport type { AssetId } from '../interfaces/types';\nimport type { Comparison, FeatureRef, RuleNode, RuleTreeState, Tolerance } from './types';\n\nfunction isRef(operand: FeatureRef | number): operand is FeatureRef {\n return typeof operand === 'object' && operand !== null && 'ref' in operand;\n}\n\nfunction resolve(operand: FeatureRef | number, values: ReadonlyMap<string, number>): number {\n if (!isRef(operand)) return operand;\n const v = values.get(operand.ref);\n if (v === undefined) {\n throw new Error(`evaluateRuleTree: feature \"${operand.ref}\" has no value`);\n }\n return v;\n}\n\nfunction rawCompare(op: Comparison['op'], l: number, r: number): boolean {\n switch (op) {\n case 'gt':\n return l > r;\n case 'lt':\n return l < r;\n case 'gte':\n return l >= r;\n case 'lte':\n return l <= r;\n }\n}\n\nfunction band(right: number, tol: Tolerance): { lower: number; upper: number } {\n if (tol.mode === 'absolute') {\n return { lower: right - tol.value, upper: right + tol.value };\n }\n const factor = tol.value / 100;\n return { lower: right * (1 - factor), upper: right * (1 + factor) };\n}\n\nfunction evalComparison(\n cond: Comparison,\n values: ReadonlyMap<string, number>,\n state: RuleTreeState,\n outState: Map<string, 0 | 1>,\n): boolean {\n const l = resolve(cond.left, values);\n const r = resolve(cond.right, values);\n\n if (!cond.tolerance) {\n return rawCompare(cond.op, l, r);\n }\n if (cond.id === undefined) {\n throw new Error('evaluateRuleTree: comparison with tolerance requires id');\n }\n if (cond.op !== 'gt' && cond.op !== 'lt') {\n throw new Error(`evaluateRuleTree: tolerance is only supported for op gt/lt, got ${cond.op}`);\n }\n\n const prev = state.get(cond.id);\n const { lower, upper } = band(r, cond.tolerance);\n let result: 0 | 1;\n\n if (prev === undefined) {\n result = rawCompare(cond.op, l, r) ? 1 : 0;\n } else if (cond.op === 'gt') {\n if (prev === 1) result = l < lower ? 0 : 1;\n else result = l > upper ? 1 : 0;\n } else {\n if (prev === 1) result = l > upper ? 0 : 1;\n else result = l < lower ? 1 : 0;\n }\n\n outState.set(cond.id, result);\n return result === 1;\n}\n\nfunction walk(\n rules: RuleNode,\n values: ReadonlyMap<string, number>,\n state: RuleTreeState,\n outState: Map<string, 0 | 1>,\n): TargetWeights {\n if (rules.op === 'allocate') {\n const out = new Map<AssetId, number>();\n for (const [assetId, weight] of Object.entries(rules.weights)) {\n out.set(assetId, weight);\n }\n return out;\n }\n return evalComparison(rules.cond, values, state, outState)\n ? walk(rules.then, values, state, outState)\n : walk(rules.else, values, state, outState);\n}\n\n/**\n * Evaluates a {@link RuleNode} tree against a resolved set of feature values\n * and returns the target allocation weights together with the updated\n * hysteresis state.\n *\n * The tree is walked depth-first. At each {@link IfNode} the comparison is\n * evaluated (with hysteresis applied when `tolerance` and `id` are present)\n * and the walk follows either `then` or `else`. Evaluation terminates at an\n * {@link AllocateNode} whose `weights` map is returned verbatim.\n *\n * Hysteresis: when a {@link Comparison} carries a `tolerance`, the previous\n * outcome in `state` is used to decide whether to flip the result. The updated\n * outcomes for all visited comparisons are collected in the returned `state` map.\n *\n * Throws if a {@link FeatureRef} resolves to `undefined` (the caller should\n * suppress this with a guard or catch-block, as {@link fromSpec} does).\n *\n * @param rules - Root of the rule tree to evaluate.\n * @param values - Resolved feature values, keyed by feature id. Must contain\n * every `ref` string used in the tree; missing keys throw.\n * @param state - Prior hysteresis state from the previous evaluation step.\n * Pass an empty `Map` on the first call.\n * @returns An object with:\n * - `weights` — target portfolio weights as a `Map<AssetId, number>`.\n * - `state` — updated {@link RuleTreeState} to pass to the next step.\n *\n * @example\n * ```ts\n * import { evaluateRuleTree } from '@livefolio/sdk';\n * import type { RuleNode, RuleTreeState } from '@livefolio/sdk';\n *\n * const rules: RuleNode = {\n * op: 'if',\n * cond: { op: 'gt', left: { ref: 'price' }, right: { ref: 'sma200' } },\n * then: { op: 'allocate', weights: { SPY: 1 } },\n * else: { op: 'allocate', weights: { SHY: 1 } },\n * };\n *\n * let state: RuleTreeState = new Map();\n * const values = new Map([['price', 450], ['sma200', 420]]);\n * const result = evaluateRuleTree(rules, values, state);\n * // result.weights → Map { 'SPY' => 1 }\n * state = result.state;\n * ```\n */\nexport function evaluateRuleTree(\n rules: RuleNode,\n values: ReadonlyMap<string, number>,\n state: RuleTreeState = new Map(),\n): { weights: TargetWeights; state: RuleTreeState } {\n const next = new Map<string, 0 | 1>(state);\n const weights = walk(rules, values, state, next);\n return { weights, state: next };\n}\n","import type { Asset } from '../interfaces/types';\nimport type { AssetRef } from './types';\n\n/**\n * Resolves a spec-form {@link AssetRef} to a runtime {@link Asset}. The\n * `kind` field on the ref selects the variant; absent `kind` defaults to\n * `'equity'` for backward compatibility.\n *\n * Pure. No I/O. Used by `fromSpec`, `withSynthetics`, and\n * `evaluateFeatureSpecs` so the resolution rule lives in one place.\n */\nexport function resolveAssetRef(ref: AssetRef): Asset {\n if (ref.kind === 'macro') {\n return { kind: 'macro', id: ref.id, symbol: ref.symbol };\n }\n return ref.exchange !== undefined\n ? { kind: 'equity', id: ref.id, symbol: ref.symbol, exchange: ref.exchange }\n : { kind: 'equity', id: ref.id, symbol: ref.symbol };\n}\n","import type { Series } from '../interfaces/types';\nimport type { FeatureSpec } from '../features/spec';\nimport type { FeatureRuntime } from '../features/runtime';\nimport type { TacticalFeatureSpec } from './types';\nimport { resolveAssetRef } from './asset-ref';\n\nfunction toFeatureSpec(spec: TacticalFeatureSpec): FeatureSpec {\n switch (spec.kind) {\n case 'price':\n return { kind: 'price' };\n case 'sma':\n return { kind: 'sma', period: spec.period };\n case 'ema':\n return { kind: 'ema', period: spec.period };\n case 'rsi':\n return { kind: 'rsi', period: spec.period };\n case 'return':\n return spec.mode !== undefined\n ? { kind: 'return', period: spec.period, mode: spec.mode }\n : { kind: 'return', period: spec.period };\n case 'volatility':\n return { kind: 'volatility', period: spec.period };\n case 'drawdown':\n return { kind: 'drawdown', period: spec.period };\n }\n}\n\nfunction indexAtOrBefore(series: Series, t: Date): number {\n if (series.length === 0) return -1;\n const target = t.getTime();\n let lo = 0;\n let hi = series.length - 1;\n let ans = -1;\n while (lo <= hi) {\n const mid = (lo + hi) >>> 1;\n if (series[mid]!.t.getTime() <= target) {\n ans = mid;\n lo = mid + 1;\n } else {\n hi = mid - 1;\n }\n }\n return ans;\n}\n\nfunction readDelayed(series: Series, t: Date, delay: number): number | undefined {\n const idx = indexAtOrBefore(series, t);\n if (idx < 0) return undefined;\n const target = idx - delay;\n if (target < 0) return undefined;\n return series[target]!.v;\n}\n\n/**\n * Resolves each {@link TacticalFeatureSpec} in `specs` to a scalar value as of\n * date `t` by calling into `runtime` and reading the series at the appropriate\n * bar index. All specs are computed in parallel via `Promise.all`.\n *\n * The returned map uses each spec's `id` as the key. The value is `undefined`\n * when the indicator series has no data on or before `t`, or when the `delay`\n * offset steps past the beginning of the series.\n *\n * Validation performed before dispatching to the runtime:\n * - Duplicate `id` values in `specs` throw immediately.\n * - A non-integer or negative `delay` throws immediately.\n *\n * @param specs - Ordered list of feature declarations from {@link TacticalSpec.features}.\n * @param runtime - Feature computation backend that owns the data feed and cache.\n * @param t - Evaluation date; the series is read at the latest bar on or before `t`.\n * @returns A map from feature id to resolved numeric value (`undefined` when unavailable).\n *\n * @example\n * ```ts\n * import { evaluateFeatureSpecs } from '@livefolio/sdk';\n * import type { TacticalFeatureSpec } from '@livefolio/sdk';\n *\n * const specs: TacticalFeatureSpec[] = [\n * { id: 'spy_sma200', kind: 'sma', asset: { id: 'SPY', symbol: 'SPY' }, period: 200 },\n * { id: 'spy_price', kind: 'price', asset: { id: 'SPY', symbol: 'SPY' } },\n * ];\n *\n * const values = await evaluateFeatureSpecs(specs, runtime, new Date('2024-06-01'));\n * // values.get('spy_price') → 528.3\n * ```\n */\nexport async function evaluateFeatureSpecs(\n specs: ReadonlyArray<TacticalFeatureSpec>,\n runtime: FeatureRuntime,\n t: Date,\n): Promise<Map<string, number | undefined>> {\n const seen = new Set<string>();\n for (const spec of specs) {\n if (seen.has(spec.id)) {\n throw new Error(`evaluateFeatureSpecs: duplicate feature id \"${spec.id}\"`);\n }\n seen.add(spec.id);\n const d = spec.delay;\n if (d !== undefined && (!Number.isInteger(d) || d < 0)) {\n throw new Error(`evaluateFeatureSpecs: delay must be a non-negative integer, got ${d}`);\n }\n }\n\n const entries = await Promise.all(\n specs.map(async (spec) => {\n const series = await runtime.compute(toFeatureSpec(spec), resolveAssetRef(spec.asset));\n const delay = spec.delay ?? 0;\n return [spec.id, readDelayed(series, t, delay)] as const;\n }),\n );\n\n return new Map(entries);\n}\n","import type { Asset, Bar, DateRange, Frequency } from '../interfaces/types';\nimport type { DataFeed } from '../interfaces/data-feed';\nimport type { SyntheticAsset } from './types';\nimport { resolveAssetRef } from './asset-ref';\n\nconst TRADING_DAYS_PER_YEAR = 252;\n\nasync function* synthesize(\n underlyingBars: AsyncIterable<Bar>,\n leverage: number,\n expense: number | undefined,\n): AsyncIterable<Bar> {\n const drag = (expense ?? 0) / TRADING_DAYS_PER_YEAR;\n let prevUnderlyingClose: number | undefined;\n let prevSynthClose: number | undefined;\n for await (const u of underlyingBars) {\n let close: number;\n if (prevSynthClose === undefined || prevUnderlyingClose === undefined) {\n close = u.close;\n } else {\n const safe = Number.isFinite(prevUnderlyingClose) && prevUnderlyingClose !== 0;\n const r = safe ? (u.close - prevUnderlyingClose) / prevUnderlyingClose : 0;\n close = prevSynthClose * (1 + leverage * r) * (1 - drag);\n }\n yield {\n t: u.t,\n open: close,\n high: close,\n low: close,\n close,\n volume: u.volume,\n };\n prevUnderlyingClose = u.close;\n prevSynthClose = close;\n }\n}\n\n/**\n * Wraps a {@link DataFeed} so that requests for any asset whose `id` appears in\n * `synthetics` are intercepted and their bar stream is derived on-the-fly from\n * the corresponding `underlying` asset.\n *\n * The synthesized close price on each bar is computed as:\n * ```\n * close_t = close_{t-1} × (1 + leverage × underlyingReturn_t) × (1 − expense/252)\n * ```\n * The first bar in the stream uses the underlying close directly. OHLC fields\n * other than `close` are all set to the synthesized close (they are not\n * independently scaled); `volume` is passed through from the underlying bar.\n *\n * Non-synthetic assets are proxied transparently to the original `dataFeed`.\n * `fundamentals` and `events` methods, if present, are forwarded unchanged.\n *\n * Throws at construction time if `synthetics` contains duplicate `id` values.\n *\n * @param dataFeed - The real data feed to wrap.\n * @param synthetics - Synthetic asset definitions; typically `spec.synthetics ?? []`.\n * @returns A new {@link DataFeed} that intercepts synthetic asset ids.\n *\n * @example\n * ```ts\n * import { withSynthetics } from '@livefolio/sdk';\n * import type { SyntheticAsset } from '@livefolio/sdk';\n *\n * const leveraged: SyntheticAsset = {\n * id: 'SPY_3X', symbol: 'SPY3X',\n * underlying: { id: 'SPY', symbol: 'SPY' },\n * leverage: 3,\n * expense: 0.01,\n * };\n *\n * const feed = withSynthetics(realFeed, [leveraged]);\n * // Requesting bars for asset { id: 'SPY_3X', ... } now returns 3× leveraged returns.\n * ```\n */\nexport function withSynthetics(dataFeed: DataFeed, synthetics: ReadonlyArray<SyntheticAsset>): DataFeed {\n const byId = new Map<string, SyntheticAsset>();\n for (const s of synthetics) {\n if (byId.has(s.id)) {\n throw new Error(`withSynthetics: duplicate synthetic asset id \"${s.id}\"`);\n }\n byId.set(s.id, s);\n }\n\n const wrapped: DataFeed = {\n bars(asset: Asset, range: DateRange, freq: Frequency): AsyncIterable<Bar> {\n const synth = byId.get(asset.id);\n if (!synth) return dataFeed.bars(asset, range, freq);\n const underlying = resolveAssetRef(synth.underlying);\n return synthesize(dataFeed.bars(underlying, range, freq), synth.leverage, synth.expense);\n },\n };\n\n if (dataFeed.fundamentals) {\n wrapped.fundamentals = dataFeed.fundamentals.bind(dataFeed);\n }\n if (dataFeed.events) {\n wrapped.events = dataFeed.events.bind(dataFeed);\n }\n\n return wrapped;\n}\n","import type { Asset, AssetId } from '../interfaces/types';\nimport type { Calendar } from '../interfaces/calendar';\nimport type { Strategy } from '../strategy/types';\nimport { reconcile } from '../strategy/reconcile';\nimport type { FeatureRuntime } from '../features/runtime';\nimport { seriesAt } from '../features/series-utils';\nimport type { RebalanceFrequency, RuleTreeState, TacticalSpec } from './types';\nimport { resolveAssetRef } from './asset-ref';\nimport { evaluateRuleTree } from './evaluate-rule-tree';\nimport { evaluateFeatureSpecs } from './evaluate-feature-specs';\n\nlet _warnedV0 = false;\n\n/** Test-only: reset the once-per-process deprecation gate. */\nexport function _resetTacticalDeprecationWarningForTesting(): void {\n _warnedV0 = false;\n}\n\n/**\n * The feature bundle computed on each rebalance step and passed to the rule\n * tree. Produced by the `features` method of the {@link Strategy} returned by\n * {@link fromSpec}.\n *\n * - `values` — named indicator results keyed by the `id` field of each\n * {@link TacticalFeatureSpec}. A value is `undefined` when the indicator\n * cannot be computed for that bar (e.g. insufficient history).\n * - `prices` — most-recent closing prices for each asset in the universe,\n * keyed by asset ID.\n */\nexport type TacticalFeatures = {\n values: ReadonlyMap<string, number | undefined>;\n prices: ReadonlyMap<AssetId, number>;\n};\n\n/**\n * Runtime dependencies required by {@link fromSpec} to hydrate a\n * {@link TacticalSpec} into a runnable {@link Strategy}.\n */\nexport type FromSpecOptions = {\n /** Feature computation backend — wraps the data feed and caching layer. */\n runtime: FeatureRuntime;\n /** Exchange calendar used to gate rebalance days via {@link isRebalanceDay}. */\n calendar: Calendar;\n};\n\nfunction validateSynthetics(spec: TacticalSpec): void {\n const synths = spec.synthetics ?? [];\n if (synths.length === 0) return;\n\n const universeIds = new Set(spec.universe.map((u) => u.id));\n\n for (const s of synths) {\n if (s.underlying.id === s.id) {\n throw new Error(`fromSpec: synthetic asset \"${s.id}\" cannot reference itself as underlying`);\n }\n const u = spec.universe.find((x) => x.id === s.id);\n if (!u) continue;\n if (u.symbol !== s.symbol) {\n throw new Error(`fromSpec: synthetic asset id \"${s.id}\" collides with a universe AssetRef of a different symbol`);\n }\n if (!universeIds.has(s.underlying.id)) {\n throw new Error(\n `fromSpec: synthetic asset id \"${s.id}\" collides with a universe AssetRef whose underlying is not declared in the universe`,\n );\n }\n }\n}\n\n/**\n * Returns a stable string key that identifies the rebalance period containing\n * date `t` for the given `freq`. Two dates that map to the same key belong to\n * the same period and therefore produce the same rebalance decision. Used\n * internally by {@link isRebalanceDay} to detect period boundaries.\n *\n * @param t - The date to classify.\n * @param freq - Rebalance cadence (see {@link RebalanceFrequency}).\n * @returns A compact string such as `'2024-3'` (monthly), `'2024-W14'`\n * (weekly), or `'2024-1'` (quarterly Q2).\n */\nexport function periodKey(t: Date, freq: RebalanceFrequency): string {\n const y = t.getUTCFullYear();\n const m = t.getUTCMonth();\n switch (freq) {\n case 'Daily':\n return `${y}-${m}-${t.getUTCDate()}`;\n case 'Weekly': {\n const thu = new Date(t);\n thu.setUTCDate(thu.getUTCDate() + 3 - ((thu.getUTCDay() + 6) % 7));\n const yearStart = new Date(Date.UTC(thu.getUTCFullYear(), 0, 1));\n const weekNo = Math.ceil(((thu.getTime() - yearStart.getTime()) / 86_400_000 + 1) / 7);\n return `${thu.getUTCFullYear()}-W${weekNo}`;\n }\n case 'Monthly':\n return `${y}-${m}`;\n case 'Quarterly':\n return `${y}-Q${Math.floor(m / 3)}`;\n case 'Yearly':\n return `${y}`;\n }\n}\n\n/**\n * Returns `true` when `t` is the last trading day of its rebalance period\n * according to `freq` and `calendar`. The check is: `periodKey(t) !== periodKey(next(t))`.\n * For `'Daily'` cadence this always returns `true`.\n *\n * @param t - Current trading day (must itself be a trading day).\n * @param freq - Rebalance cadence (see {@link RebalanceFrequency}).\n * @param calendar - Exchange calendar used to find the next trading day.\n * @returns `true` if today is the last day of its period and orders should be issued.\n */\nexport function isRebalanceDay(t: Date, freq: RebalanceFrequency, calendar: Calendar): boolean {\n if (freq === 'Daily') return true;\n const next = calendar.next(t);\n return periodKey(t, freq) !== periodKey(next, freq);\n}\n\n/**\n * Hydrates a plain {@link TacticalSpec} data object into a runnable\n * {@link Strategy} that `runBacktest` can drive step-by-step.\n *\n * State is threaded explicitly through `build` via the\n * {@link Strategy | `Strategy<F, S>.build`} signature. `initialState()` returns\n * an empty {@link RuleTreeState} Map; the runtime is responsible for storing and\n * forwarding the state between calls. This design makes `build` a pure function\n * of its inputs — calling it twice with identical arguments produces identical\n * outputs, enabling snapshot/restore for preview-builds in live mode.\n *\n * Validation performed at construction time:\n * - A `'tactical/v0'` `kind` emits a one-time deprecation warning to `console.warn`.\n * - Synthetic assets are checked for self-reference, symbol collisions, and\n * missing universe entries (see internal `validateSynthetics`).\n *\n * @param spec - The declarative strategy spec.\n * @param opts - Runtime dependencies (feature backend and calendar).\n * @returns A {@link Strategy} whose `features` method fetches indicator values\n * and whose `build` method converts them to rebalance orders.\n *\n * @example\n * ```ts\n * import { fromSpec, MemoryFeatureCache, NYSEExchangeCalendar } from '@livefolio/sdk';\n * import { FeatureRuntime } from '@livefolio/sdk/features';\n *\n * const calendar = new NYSEExchangeCalendar();\n * const cache = new MemoryFeatureCache();\n * const runtime = new FeatureRuntime({ feed: myDataFeed, cache });\n *\n * const strategy = fromSpec(mySpec, { runtime, calendar });\n * ```\n */\nexport function fromSpec(spec: TacticalSpec, opts: FromSpecOptions): Strategy<TacticalFeatures, RuleTreeState> {\n if (spec.kind === 'tactical/v0' && !_warnedV0) {\n _warnedV0 = true;\n\n console.warn(\n '[@livefolio/sdk] tactical/v0 is deprecated; migrate to tactical/v1. ' +\n 'The two are byte-for-byte equivalent. This warning fires once per process.',\n );\n }\n validateSynthetics(spec);\n const universe: ReadonlyArray<Asset> = spec.universe.map(resolveAssetRef);\n const { runtime, calendar } = opts;\n const cadence: RebalanceFrequency = spec.rebalance?.frequency ?? 'Daily';\n\n return {\n universe: () => universe,\n\n features: async (_u, _p, t) => {\n const [values, priceEntries] = await Promise.all([\n evaluateFeatureSpecs(spec.features, runtime, t),\n Promise.all(\n universe.map(async (asset) => {\n const s = await runtime.compute({ kind: 'price' }, asset);\n return [asset.id, seriesAt(s, t)] as const;\n }),\n ),\n ]);\n const prices = new Map<AssetId, number>();\n for (const [id, v] of priceEntries) {\n if (v !== undefined) prices.set(id, v);\n }\n return { values, prices };\n },\n\n initialState: () => new Map() as RuleTreeState,\n\n build: (features, portfolio, state, t) => {\n if (!isRebalanceDay(t, cadence, calendar)) {\n return { orders: [], state };\n }\n\n const defined = new Map<string, number>();\n for (const [id, v] of features.values) {\n if (v !== undefined) defined.set(id, v);\n }\n let evaluated;\n try {\n evaluated = evaluateRuleTree(spec.rules, defined, state);\n } catch (e) {\n if (e instanceof Error && /has no value/.test(e.message)) {\n return { orders: [], state };\n }\n throw e;\n }\n for (const assetId of evaluated.weights.keys()) {\n if (!features.prices.has(assetId)) {\n return { orders: [], state };\n }\n }\n return {\n orders: reconcile(evaluated.weights, portfolio, features.prices),\n state: evaluated.state,\n };\n },\n };\n}\n","export * from './indicators';\nexport { collectBars, barsToSeries, seriesAt } from './series-utils';\nexport type { BarField } from './series-utils';\nexport {\n defineFeature,\n getFeatureCompute,\n paramsHash,\n type FeatureSpec,\n type FeatureKind,\n type ComputeFn,\n} from './spec';\nexport { FeatureRuntime } from './runtime';\nexport type { FeatureRuntimeOptions } from './runtime';\n"],"mappings":"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CA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA,EAGA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA,EAGA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AAAA,EAEA;AAAA;AA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,GAAG,EAAE,CAAC;AAAA;AAAA,EAE9B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,EAAE,CAAC;AAAA;AAAA,EAE9B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,EAAE,CAAC;AAAA;AAAA,EAE9B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,EAAE,CAAC;AAAA;AAAA,EAE9B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,GAAG,CAAC;AAAA;AAAA,EAE/B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,GAAG,CAAC;AAAA;AAAA,EAE/B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,GAAG,CAAC;AAAA;AAAA,EAE/B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,GAAG,CAAC;AAAA;AAAA,EAE/B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,EAAE,CAAC;AAAA;AAAA,EAE9B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,EAAE,CAAC;AAAA;AAAA,EAE9B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,EAAE,CAAC;AAAA;AAAA,EAE9B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,EAAE,CAAC;AAAA;AAAA,EAE9B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,EAAE,CAAC;AAAA;AAAA,EAE9B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,EAAE,CAAC;AAAA;AAAA,EAE9B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,GAAG,CAAC;AAAA;AAAA,EAE/B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,GAAG,CAAC;AAAA;AAAA,EAE/B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,GAAG,CAAC;AAAA;AAAA,EAE/B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,GAAG,CAAC;AAAA;AAAA,EAE/B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,EAAE,CAAC;AAAA;AAAA,EAE9B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,GAAG,CAAC;AAAA;AAAA,EAE/B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,GAAG,CAAC;AAAA;AAAA,EAE/B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,GAAG,CAAC;AAAA;AAA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G,GAAG,GAAG,CAAC;AAAA;AAAA,EAE9B,CAAC,cAAc,EAAE,GAAG,GAAG,GAAG,GAAG,CAAC;AAAA;AAAA,EAE9B,CAAC,cAAc,EAAE,GAAG,GAAG,GAAG,GAAG,CAAC;AAAA;AAAA,EAE9B,CAAC,cAAc,EAAE,GAAG,GAAG,GAAG,GAAG,CAAC;AAAA;AAAA,EAE9B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,GAAG,CAAC;AAAA;AAAA,EAE/B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,GAAG,CAAC;AAAA;AAAA,EAE/B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,GAAG,CAAC;AAAA;AAAA,EAE/B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,GAAG,CAAC;AAAA;AAAA,EAE/B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,GAAG,CAAC;AAAA;AAAA,EAE/B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,GAAG,CAAC;AAAA;AAAA,EAE/B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,GAAG,CAAC;AAAA;AAAA,EAE/B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,GAAG,CAAC;AAAA;AAAA,EAE/B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,GAAG,CAAC;AAAA;AAAA,EAE/B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,EAAE,CAAC;AAAA;AAAA,EAE9B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,EAAE,CAAC;AAAA;AAAA,EAE9B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,EAAE,CAAC;AAAA;AAAA,EAE9B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,EAAE,CAAC;AAAA;AAAA,EAE9B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,EAAE,CAAC;AAAA;AAAA,EAE9B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,EAAE,CAAC;AAAA;AAAA,EAE9B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,EAAE,CAAC;AAAA;AAAA,EAE9B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,EAAE,CAAC;AAAA;AAAA,EAE9B,CAAC,cAAc,EAAE,GAAG,IAAI,GAAG,EAAE,CAAC;AAAA;AA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","names":["MS_PER_DAY","MS_PER_DAY","MS_PER_DAY","SUN","MON","TUE","SAT","utcDate","WEEKDAYS_MON_FRI","REGULAR_HOLIDAYS","ADHOC_HOLIDAYS","SPECIAL_CLOSES","SPECIAL_CLOSES_ADHOC","SPECIAL_OPENS","SPECIAL_OPENS_ADHOC","MS_PER_DAY"]}