The series to aggregate; each carries ascending points.
The mean-price series, ascending by time.
buildAggregateSeries([
{ points: [{ t: 1, usd: 10 }, { t: 3, usd: 8 }] },
{ points: [{ t: 1, usd: 20 }, { t: 3, usd: 18 }] },
]);
// => [{ t: 1, usd: 15 }, { t: 3, usd: 13 }]
export function buildAggregateSeries(seriesList: readonly PriceHistoryEntry[]): PricePoint[] {
const withPoints = seriesList.filter((series) => series.points.length > 0);
if (withPoints.length === 0) {
return [];
}
const times = Array.from(
new Set(withPoints.flatMap((series) => series.points.map((point) => point.t))),
).sort((a, b) => a - b);
const aggregate: PricePoint[] = [];
for (const t of times) {
let sum = 0;
let count = 0;
for (const series of withPoints) {
const point = lastPointAtOrBefore(series.points, t);
if (point !== undefined) {
sum += point.usd;
count += 1;
}
}
if (count === 0) {
continue;
}
const usd = round2(sum / count);
if (aggregate.at(-1)?.usd === usd) {
continue;
}
aggregate.push({ t, usd });
}
return aggregate;
}
Collapse several price series into one synthetic mean-price series so a group (e.g. all of a product's variants) can be summarized by a single trend. At each recorded timestamp the mean is taken over every series that has started by then (forward-filling each series' last-known price), and consecutive-equal means are deduped so describeTrend's last two points reflect an actual move. Empty in ⇒ empty out.