Previous-Tick Interpolation
Install and import
npm install fintech-algorithmsimport { previousTick } from "fintech-algorithms/market-data-engineering/time-synchronization/previous-tick-interpolation";Signature
previousTick(observations, requests, maxStalenessMs)Samples a series onto a grid by carrying the last value known *at that moment* forward. The only interpolation that is safe on live data: it never uses a value that had not yet arrived.
Parameters
| Name | Type | Notes |
|---|---|---|
observations | Observation[] | Observations carrying both event_time and available_time, which is what allows the as-of rule to be applied honestly. |
requests | { grid_time: string; query_time: string }[] | The grid points to sample, each with the knowledge time the answer must respect. |
maxStalenessMs | number | How old a carried-forward value may be before the sample is reported unusable rather than silently stale. min: 0 |
Returns
Sample[] · length same-as-input
One sample per request with the value used, its age, and whether the staleness budget was met.
Errors
- When maxStalenessMs is negative — throws
Complexity: time O(n + m),
space O(m).
Worked example
executed Captured by running this function on the input its own test provides. Real output of real code — but not asserted against a published figure.
Input
[
{
"instrument": "A",
"event_time": "2026-01-02T14:30:00.100Z",
"available_time": "2026-01-02T14:30:00.180Z",
"revision": 0,
"value": 100
},
{
"instrument": "A",
"event_time": "2026-01-02T14:30:00.100Z",
"available_time": "2026-01-02T14:30:01.400Z",
"revision": 1,
"value": 99.8
},
{
"instrument": "A",
"event_time": "2026-01-02T14:30:02.200Z",
"available_time": "2026-01-02T14:30:02.260Z",
"revision": 0,
"value": 100.4
}
]Showing 3 of 5 elements.
[
{
"grid_time": "2026-01-02T14:30:00.000Z",
"query_time": "2026-01-02T14:30:00.000Z"
},
{
"grid_time": "2026-01-02T14:30:01.000Z",
"query_time": "2026-01-02T14:30:01.000Z"
},
{
"grid_time": "2026-01-02T14:30:01.000Z",
"query_time": "2026-01-02T14:30:02.000Z"
}
]Showing 3 of 5 elements.
1500Call
previousTick(observations, requests, maxStalenessMs)Returns
array of 10 objects
[
{
"instrument": "A",
"grid_time": "2026-01-02T14:30:00.000Z",
"query_time": "2026-01-02T14:30:00.000Z",
"value": null,
"source_event_time": null,
"source_available_time": null,
"source_revision": null,
"staleness_ms": null,
"status": "no_history"
},
{
"instrument": "A",
"grid_time": "2026-01-02T14:30:01.000Z",
"query_time": "2026-01-02T14:30:01.000Z",
"value": 100,
"source_event_time": "2026-01-02T14:30:00.100Z",
"source_available_time": "2026-01-02T14:30:00.180Z",
"source_revision": 0,
"staleness_ms": 900,
"status": "carried"
},
{
"instrument": "A",
"grid_time": "2026-01-02T14:30:01.000Z",
"query_time": "2026-01-02T14:30:02.000Z",
"value": 99.8,
"source_event_time": "2026-01-02T14:30:00.100Z",
"source_available_time": "2026-01-02T14:30:01.400Z",
"source_revision": 1,
"staleness_ms": 900,
"status": "carried"
}
]Showing 3 of 10 elements.
Diagrams
Calculation flow
Point-in-time previous-tick decision
flowchart LR
A["Stored source revisions"] --> B{"Event time <= grid time?"}
B -->|No| C["No history"]
B -->|Yes| D{"Availability time <= query time?"}
D -->|No| E["Not yet available"]
D -->|Yes| F["Latest event, latest available revision"]
F --> G{"Source age <= expiry?"}
G -->|Yes| H["Exact or carried value"]
G -->|No| I["Stale missing value with lineage"]
How it works
This page states the contract — how to call it correctly. The article explains the concept: why it works, and where it breaks.
References
- R01 - RFC 3339: Date and Time on the Internet: Timestamps — Internet Engineering Task Force; G. Klyne and C. Newman
- R02 - On covariance estimation of non-synchronously observed diffusion processes — Takaki Hayashi and Nakahiro Yoshida
- R03 - NYSE Holidays and Trading Hours — New York Stock Exchange
- Implementation choices in this package
- Dataset and historical-evidence classification