@livefolio/sdk 0.3.2 → 0.3.3

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.d.ts CHANGED
@@ -114,7 +114,6 @@ declare class IndicatorHandle {
114
114
  private _sync;
115
115
  private _upsertSeries;
116
116
  private _querySeriesFromDb;
117
- withMarket(market: MarketProvider): IndicatorHandle;
118
117
  /**
119
118
  * Apply leverage compounding to a raw bar series, anchored to a stored
120
119
  * leveraged value. Used by both `_sync` and `computeAt` so they stay
@@ -130,37 +129,66 @@ declare class IndicatorHandle {
130
129
  */
131
130
  private _applyLeverage;
132
131
  /**
133
- * Compute the indicator's value at `date` using the given market (typically
134
- * an overlay market for pre-close preview). Pure no writes to storage.
132
+ * Compute the indicator's value at `date` without persisting anything, with
133
+ * optional live-quote `overrides` keyed by raw market symbol (the same symbol
134
+ * space `MarketProvider.fetchBars` uses — ticker symbols for Price/SMA/etc.,
135
+ * `^VIX` / `^VIX3M` for macro, FRED series IDs like `DGS3MO` for Treasury).
135
136
  *
136
- * For fetched types (yahoo/fred): fetches a small window of bars from
137
- * `market`, applies leverage compounding anchored to the stored leveraged
138
- * value at the bar before `date`.
139
- * For computed types (SMA, RSI, etc.): fetches enough raw price bars to
140
- * cover the indicator's lookback from `market`, applies leverage anchored
141
- * to the stored value just before the fetch window, runs the computation,
142
- * and returns the value at `date`.
143
- * For Threshold: returns the threshold constant.
144
- * For calendar: computes calendar value from the trading days list.
145
- * Returns null if the value cannot be computed.
137
+ * Bars for the underlying symbol are resolved storage-first when the market
138
+ * hasn't yet produced bars for `date` (trading day still open), and storage
139
+ * is the fallback whenever the remote fetch fails — see `_resolveRawBars`.
140
+ *
141
+ * For Threshold: returns the threshold constant. For calendar types: computed
142
+ * from `tradingDays.getRange()`. For all others: `_resolveRawBars` leverage
143
+ * compounding (if any) lookback-specific computation. Returns null if the
144
+ * value cannot be computed.
145
+ */
146
+ computeAt(date: string, overrides?: Record<string, number>): Promise<number | null>;
147
+ /**
148
+ * Raw (unleveraged) bars for `symbol` up through `date`, with the live quote
149
+ * from `overrides[symbol]` (if any) spliced in at `date`.
150
+ *
151
+ * Decision policy:
152
+ * - `date` > `tradingDays.getLatestClosed()`: market has nothing for that
153
+ * day yet — skip the remote fetch entirely and read from storage.
154
+ * - otherwise: try `this._market.fetchBars(symbol, from)`. On failure, fall
155
+ * back to storage — upstream HTTP providers (Yahoo / FRED) are flaky.
156
+ *
157
+ * After the base is resolved, `overrides[symbol]` is spliced at `date`
158
+ * (replaces the existing bar, or is appended in-order). When no override is
159
+ * present but `date` isn't in the base bars, the last known value is carried
160
+ * forward to `date` — this preserves the fallbackMissingQuotes behaviour the
161
+ * old overlay exposed so leverage compounding / computations always have a
162
+ * point at `date` to land on.
163
+ */
164
+ private _resolveRawBars;
165
+ /**
166
+ * Resolve raw (unleveraged) bars for a market symbol from storage. Maps:
167
+ * - `^VIX` → the VIX indicator's stored series
168
+ * - `^VIX3M` → the VIX3M indicator's stored series
169
+ * - `DGS*` → the matching Treasury-tenor indicator's stored series
170
+ * - anything else → the `Price` indicator for that ticker symbol with
171
+ * `leverage = 1` (the raw contract that `MarketProvider.fetchBars` has).
172
+ *
173
+ * Returns `[]` when the resolved indicator has no stored bars yet.
146
174
  */
147
- computeAt(market: MarketProvider, date: string): Promise<number | null>;
175
+ private _readStoredBars;
148
176
  series(range?: DateRange): Promise<DailyBar[]>;
149
177
  private _syntheticThresholdSeries;
150
178
  value(date?: string): Promise<number | null>;
151
179
  /**
152
- * Read-only preview of the indicator series that includes an in-memory bar
153
- * at `date` computed via `computeAt` against a quote-overlay market. Does
180
+ * Read-only preview of the indicator series with an in-memory bar at `date`
181
+ * computed via `computeAt` with the supplied live-quote `overrides`. Does
154
182
  * NOT write to `indicators_series`. Safe to call before market close.
155
183
  *
156
- * @param date - Target trading day whose value is computed in-memory from
157
- * the overridden quotes. Must be in `tradingDays.getRange()`.
158
- * @param quoteOverrides - Raw (unleveraged) quotes keyed by ticker symbol.
159
- * Symbols omitted here fall back to yesterday's close via the overlay.
184
+ * @param date - Target trading day whose value is computed in-memory.
185
+ * Must be in `tradingDays.getRange()`.
186
+ * @param overrides - Raw (unleveraged) quotes keyed by market symbol.
187
+ * Symbols omitted fall back to the last known value (see `_resolveRawBars`).
160
188
  * @param range - Optional filter applied to the returned bars.
161
189
  * @returns Stored historical bars plus (or with) today's in-memory value.
162
190
  */
163
- previewSeries(date: string, quoteOverrides: Record<string, number>, range?: DateRange): Promise<DailyBar[]>;
191
+ previewSeries(date: string, overrides: Record<string, number>, range?: DateRange): Promise<DailyBar[]>;
164
192
  }
165
193
 
166
194
  interface StorageProvider {
@@ -253,13 +281,12 @@ declare class SignalHandle {
253
281
  readonly comparison: Comparison;
254
282
  readonly tolerance: number;
255
283
  private _storage;
256
- private _market;
257
284
  private _resolvedId;
258
285
  private _resolving;
259
286
  private _cachedSeries;
260
287
  private _cachedAsOf;
261
288
  private _syncing;
262
- constructor(storage: StorageProvider, market: MarketProvider, identity: SignalIdentity);
289
+ constructor(storage: StorageProvider, _market: MarketProvider, identity: SignalIdentity);
263
290
  get id(): number;
264
291
  resolve(): Promise<{
265
292
  id: number;
@@ -273,11 +300,11 @@ declare class SignalHandle {
273
300
  private _sync;
274
301
  private _upsertSeries;
275
302
  private _querySeriesFromDb;
276
- withMarket(market: MarketProvider): SignalHandle;
277
303
  /**
278
- * Compute the signal's boolean value at `date` using the given market
279
- * (typically an overlay market for pre-close preview). Pure — no writes.
280
- * Returns null if either indicator cannot produce a value at `date`.
304
+ * Compute the signal's boolean value at `date` without persisting anything,
305
+ * with optional live-quote `overrides` that are routed through each
306
+ * indicator's `computeAt`. Returns null if either indicator cannot produce
307
+ * a value at `date`.
281
308
  *
282
309
  * @param prevBool - The signal's boolean value at the bar immediately
283
310
  * preceding `date`, used for hysteresis when `tolerance > 0`. If not
@@ -285,19 +312,19 @@ declare class SignalHandle {
285
312
  * standalone callers). On the preview path `_evaluate` passes this from
286
313
  * the in-memory `dateMap` so we never read stale storage.
287
314
  */
288
- computeAt(market: MarketProvider, date: string, prevBool?: boolean | null): Promise<boolean | null>;
315
+ computeAt(date: string, overrides?: Record<string, number>, prevBool?: boolean | null): Promise<boolean | null>;
289
316
  series(range?: DateRange): Promise<DailyBar[]>;
290
317
  value(date?: string): Promise<number | null>;
291
318
  /**
292
319
  * Read-only preview of the signal series with an in-memory bar at `date`
293
- * computed via `computeAt` against a quote-overlay market. Does NOT write
294
- * to `signals_series`.
320
+ * computed via `computeAt` with the supplied live-quote `overrides`. Does
321
+ * NOT write to `signals_series`.
295
322
  *
296
323
  * @param date - Target trading day whose boolean is computed in-memory.
297
- * @param quoteOverrides - Raw (unleveraged) quotes keyed by ticker symbol.
324
+ * @param overrides - Raw (unleveraged) quotes keyed by market symbol.
298
325
  * @param range - Optional filter applied to the returned bars.
299
326
  */
300
- previewSeries(date: string, quoteOverrides: Record<string, number>, range?: DateRange): Promise<DailyBar[]>;
327
+ previewSeries(date: string, overrides: Record<string, number>, range?: DateRange): Promise<DailyBar[]>;
301
328
  }
302
329
 
303
330
  declare class AllocationHandle {
@@ -348,6 +375,45 @@ interface FinalState {
348
375
  closePrices: Record<string, number>;
349
376
  leveragedPrices: Record<string, number>;
350
377
  }
378
+ /** Per-signal slice of a live strategy snapshot. */
379
+ interface LiveSignalState {
380
+ indicator1: {
381
+ value: number | null;
382
+ date: string | null;
383
+ };
384
+ indicator2: {
385
+ value: number | null;
386
+ date: string | null;
387
+ };
388
+ isTrue: boolean;
389
+ }
390
+ /** Per-rule collection of live signal states, in the same order as the rule's `when` list. */
391
+ interface LiveRuleState {
392
+ signals: LiveSignalState[];
393
+ }
394
+ /** Full live strategy view for a single evaluation date — no portfolio info. */
395
+ interface StrategyLiveState {
396
+ allocation: AllocationHandle | null;
397
+ activeRuleIndex: number;
398
+ rules: LiveRuleState[];
399
+ }
400
+ /**
401
+ * Combined live state returned by `SimulationHandle.pushAndPreview`: both the
402
+ * portfolio snapshot from a `push` and the strategy evaluation at the target
403
+ * date under the accumulated live-quote overrides.
404
+ */
405
+ interface LivePreviewState extends StrategyLiveState {
406
+ snapshot: PortfolioSnapshot;
407
+ }
408
+ /**
409
+ * Callback shape that `SimulationHandle.pushAndPreview` delegates to. Exists
410
+ * purely to break the circular import between `SimulationHandle` (in this
411
+ * file) and `StrategyHandle` (which creates simulations) — a strategy passes
412
+ * a bound `(date, overrides) => previewLiveState(...)` into the handle.
413
+ */
414
+ interface LiveEvaluator {
415
+ previewLiveState(date: string, overrides: Record<string, number>): Promise<StrategyLiveState>;
416
+ }
351
417
  declare class SimulationHandle {
352
418
  readonly series: DailyBar[];
353
419
  readonly trades: Trade[];
@@ -358,8 +424,30 @@ declare class SimulationHandle {
358
424
  private _lastLeveragedPrices;
359
425
  private _currentLeveragedPrices;
360
426
  private _lastDate;
361
- constructor(series: DailyBar[], trades: Trade[], startingPortfolio: PortfolioHandle, finalState?: FinalState);
427
+ private _pushedQuotes;
428
+ private _liveEvaluator;
429
+ constructor(series: DailyBar[], trades: Trade[], startingPortfolio: PortfolioHandle, finalState?: FinalState, liveEvaluator?: LiveEvaluator);
362
430
  push(...prices: [TickerHandle, number][]): PortfolioSnapshot;
431
+ /**
432
+ * One-call live update. Feeds portfolio-relevant ticker prices into `push`
433
+ * (derived from `quotes` via the running portfolio's holdings), accumulates
434
+ * every symbol in `quotes` into an internal override map so macro symbols
435
+ * (e.g. `^VIX`) persist across ticks, then delegates to the simulation's
436
+ * strategy for rule / signal / indicator evaluation at `date`.
437
+ *
438
+ * Without a live evaluator attached, returns just the portfolio snapshot
439
+ * with allocation/rules/signals empty.
440
+ *
441
+ * @param quotes Symbol → raw live price. Portfolio tickers flow through
442
+ * `push` for leveraged-equity math; non-portfolio symbols are still
443
+ * layered into the overlay so indicators can see them.
444
+ * @param options.date Target trading day to evaluate against. Defaults to
445
+ * the current UTC ISO date; callers with non-UTC semantics or after-hours
446
+ * rollover should supply their own.
447
+ */
448
+ pushAndPreview(quotes: Record<string, number>, options?: {
449
+ date?: string;
450
+ }): Promise<LivePreviewState>;
363
451
  }
364
452
 
365
453
  interface StrategyRule {
@@ -410,14 +498,13 @@ declare class StrategyHandle {
410
498
  /**
411
499
  * Pure evaluate — runs the same pipeline as _sync but returns the computed
412
500
  * evaluation instead of persisting. Used by both _sync (post-close write
413
- * path) and previewAllocation (pre-close read-only path).
501
+ * path) and the public preview methods (pre-close read-only path).
414
502
  *
415
- * The `market === this._market` identity check is what distinguishes the two
416
- * paths: when they are the same object the method takes the write path (syncing
417
- * signals through storage as normal); when they differ it takes the read-only
418
- * preview path (historical bars from storage, today's value computed in-memory
419
- * via `computeAt`). Callers that want the preview path must therefore supply a
420
- * *different* market object — for example one produced by `createQuoteOverlay`.
503
+ * When `overrides` is `undefined` we take the write path syncing signals
504
+ * through storage as normal. When `overrides` is provided (even an empty
505
+ * map) we take the read-only preview path: historical signal bars come
506
+ * straight from storage, today's bar is computed in-memory via
507
+ * `signal.computeAt(date, overrides, prevBool)`, and nothing is written.
421
508
  */
422
509
  private _evaluate;
423
510
  private _querySeriesFromDb;
@@ -430,23 +517,34 @@ declare class StrategyHandle {
430
517
  * signals_series, or indicators_series. Safe to call before market close.
431
518
  *
432
519
  * @param date - The trading day to preview (must be in tradingDays.getRange()).
433
- * @param quoteOverrides - Raw (unleveraged) live prices keyed by ticker symbol.
434
- * Symbols absent from this map will fall back to yesterday's close via the
435
- * quote overlay.
520
+ * @param overrides - Raw (unleveraged) live prices keyed by market symbol.
521
+ * Symbols absent from this map fall back to the last stored value
522
+ * (see `IndicatorHandle._resolveRawBars`).
436
523
  * @returns The AllocationHandle for `date`, or null if the strategy has no
437
524
  * evaluable entry for that date.
438
525
  */
439
- previewAllocation(date: string, quoteOverrides: Record<string, number>): Promise<AllocationHandle | null>;
526
+ previewAllocation(date: string, overrides: Record<string, number>): Promise<AllocationHandle | null>;
440
527
  /**
441
528
  * Read-only preview of the strategy's allocation series including `date`.
442
529
  * Returns stored historical allocations plus an in-memory bar at `date`
443
- * computed via the same overlay path as `previewAllocation`.
530
+ * computed via the same overrides-based preview path as `previewAllocation`.
444
531
  *
445
- * @param date - Target trading day to splice in-memory via overlay market.
446
- * @param quoteOverrides - Raw (unleveraged) quotes keyed by ticker symbol.
532
+ * @param date - Target trading day to splice in-memory.
533
+ * @param overrides - Raw (unleveraged) quotes keyed by market symbol.
447
534
  * @param range - Optional filter applied to the returned bars.
448
535
  */
449
- previewSeries(date: string, quoteOverrides: Record<string, number>, range?: DateRange): Promise<StrategyBar[]>;
536
+ previewSeries(date: string, overrides: Record<string, number>, range?: DateRange): Promise<StrategyBar[]>;
537
+ /**
538
+ * Full live strategy view at `date` under live-quote `overrides`: the active
539
+ * allocation, the index of the rule that fired (or fallback), and per-rule
540
+ * per-signal indicator values + truth. Computed entirely through the
541
+ * overrides preview path — no writes to any `*_series` tables.
542
+ *
543
+ * Threshold indicators have their date suppressed (`null`) since their
544
+ * synthetic series runs over every trading day in storage including future
545
+ * dates and would report a far-future date for the last bar.
546
+ */
547
+ previewLiveState(date: string, overrides: Record<string, number>): Promise<StrategyLiveState>;
450
548
  private _fetchPricesForTickers;
451
549
  private _fetchRawClosePrices;
452
550
  }
@@ -498,4 +596,4 @@ interface PriceStream {
498
596
  close(): void;
499
597
  }
500
598
 
501
- export { AllocationHandle, type Comparison, type DailyBar, type DateRange, IndicatorHandle, type IndicatorIdentity, type IndicatorType, type LivefolioClient, type LivefolioClientOptions, type MarketProvider, PortfolioHandle, type PortfolioSnapshot, type PriceStream, SignalHandle, type SignalIdentity, type SimulateOptions, SimulationHandle, type StorageProvider, type StrategyBar, type StrategyDefinition, StrategyHandle, type StrategyOptions, type StrategyReferenceData, type StrategyRule, type StrategyRuleDefinition, type StrategySeriesEntry, type StreamStatus, TickerHandle, type Trade, type TradingFreq, type Unit, createClient };
599
+ export { AllocationHandle, type Comparison, type DailyBar, type DateRange, IndicatorHandle, type IndicatorIdentity, type IndicatorType, type LiveEvaluator, type LivePreviewState, type LiveRuleState, type LiveSignalState, type LivefolioClient, type LivefolioClientOptions, type MarketProvider, PortfolioHandle, type PortfolioSnapshot, type PriceStream, SignalHandle, type SignalIdentity, type SimulateOptions, SimulationHandle, type StorageProvider, type StrategyBar, type StrategyDefinition, StrategyHandle, type StrategyLiveState, type StrategyOptions, type StrategyReferenceData, type StrategyRule, type StrategyRuleDefinition, type StrategySeriesEntry, type StreamStatus, TickerHandle, type Trade, type TradingFreq, type Unit, createClient };