feat(web): rolling 'Last N days' presets in backtest picker (Stage E)

Adds a "Recent" preset row to HistoricalPresetPicker with three rolling
windows resolved against today at click time:

  - Last 30 days  — fast feedback for recently saved plans
  - Last 90 days  — captures most recent regime shifts
  - Last 12 months — captures multiple regime cycles

These complement the fixed-date "Historical events" row (COVID etc.)
already shipped in Stage A. Together they answer two distinct user
questions: "how would this plan have played my last 90 days?" (Recent)
vs. "how would this plan have done in the COVID crash?" (Historical).

Internals:
  - Refactored HistoricalEventPreset to use resolveRange() instead of
    static fromDate/toDate strings — lets rolling windows stay accurate
    across days without rebuilding the preset list.
  - HistoricalPresetPicker now accepts both `recentPresets` and
    `historicalPresets` props. Either can be empty/omitted to hide that
    row.

No backend changes — uses existing /api/backtest/run with kraken or
upload sources. Stage E of docs/backtest/ENGINE_READINESS.md §4.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
Devin 2026-05-10 10:53:08 +00:00
parent 1a6c0352e3
commit 81b71dc96e

View File

@ -1,55 +1,84 @@
import React from 'react';
/**
* Preset historical event windows for the backtest configurator.
* Preset windows for the backtest configurator.
*
* These are pre-validated against typical Kraken/Alpaca data depth (5-7
* years), so customers don't waste a backtest on a window that will return
* "no data" for newer symbols. See docs/backtest/ENGINE_READINESS.md §3.4.
* Two categories:
* - "Recent" rolling windows relative to today. Most useful for
* "how would this plan have played my last 90 days?" (Stage E of
* docs/backtest/ENGINE_READINESS.md §4).
* - "Historical events" fixed-date windows around significant market
* regimes. Pre-validated against typical Kraken/Alpaca data depth
* (5-7 years) so customers don't waste a backtest on a window with
* no data for newer symbols.
*/
export interface HistoricalEventPreset {
id: string;
label: string;
description: string;
fromDate: string; // YYYY-MM-DD
toDate: string; // YYYY-MM-DD
/** YYYY-MM-DD; resolved at click time so "Last 30 days" stays accurate. */
resolveRange: () => { fromDate: string; toDate: string };
}
const isoDate = (d: Date): string => d.toISOString().slice(0, 10);
const fixedRange = (from: string, to: string) => () => ({ fromDate: from, toDate: to });
const trailingDays = (n: number) => () => {
const to = new Date();
const from = new Date(to.getTime() - n * 24 * 60 * 60 * 1000);
return { fromDate: isoDate(from), toDate: isoDate(to) };
};
export const RECENT_PRESETS: HistoricalEventPreset[] = [
{
id: 'recent-30d',
label: 'Last 30 days',
description: 'Rolling 30-day window — fast feedback for recently saved plans.',
resolveRange: trailingDays(30),
},
{
id: 'recent-90d',
label: 'Last 90 days',
description: 'Rolling quarter — captures most recent regime shifts.',
resolveRange: trailingDays(90),
},
{
id: 'recent-365d',
label: 'Last 12 months',
description: 'Rolling year — captures multiple regime cycles.',
resolveRange: trailingDays(365),
},
];
export const DEFAULT_HISTORICAL_PRESETS: HistoricalEventPreset[] = [
{
id: 'covid-crash',
label: 'COVID crash',
description: 'Feb-Apr 2020 — ~30% drawdown across most assets in 5 weeks.',
fromDate: '2020-02-15',
toDate: '2020-04-30',
resolveRange: fixedRange('2020-02-15', '2020-04-30'),
},
{
id: 'covid-recovery',
label: 'COVID recovery',
description: 'Apr-Dec 2020 — fastest bull market in modern history.',
fromDate: '2020-04-01',
toDate: '2020-12-31',
resolveRange: fixedRange('2020-04-01', '2020-12-31'),
},
{
id: 'russia-ukraine',
label: 'Russia/Ukraine 2022',
description: 'Feb-Jun 2022 — energy + commodity shocks, risk-off pivot.',
fromDate: '2022-02-01',
toDate: '2022-06-30',
resolveRange: fixedRange('2022-02-01', '2022-06-30'),
},
{
id: 'bear-2022',
label: '2022 bear market',
description: 'Full year — sustained drawdown across crypto + tech equities.',
fromDate: '2022-01-01',
toDate: '2022-12-31',
resolveRange: fixedRange('2022-01-01', '2022-12-31'),
},
{
id: 'svb-banking',
label: 'SVB banking shock',
description: 'Mar 2023 — bank failures + emergency Fed response.',
fromDate: '2023-03-01',
toDate: '2023-04-15',
resolveRange: fixedRange('2023-03-01', '2023-04-15'),
},
];
@ -59,35 +88,56 @@ export interface HistoricalPresetPickerProps {
/** Called with `(fromDate, toDate, presetId)` when a preset is clicked. */
onSelect: (fromDate: string, toDate: string, presetId: string) => void;
/** Override the default preset list. */
presets?: HistoricalEventPreset[];
recentPresets?: HistoricalEventPreset[];
historicalPresets?: HistoricalEventPreset[];
className?: string;
}
const renderRow = (
presets: HistoricalEventPreset[],
selectedId: string | null,
onSelect: HistoricalPresetPickerProps['onSelect']
) => (
<div className="historical-preset-picker-row">
{presets.map((preset) => {
const active = selectedId === preset.id;
const range = preset.resolveRange();
return (
<button
key={preset.id}
type="button"
onClick={() => onSelect(range.fromDate, range.toDate, preset.id)}
className={`historical-preset-chip ${active ? 'is-active' : ''}`}
title={`${preset.description} (${range.fromDate}${range.toDate})`}
>
{preset.label}
</button>
);
})}
</div>
);
export const HistoricalPresetPicker: React.FC<HistoricalPresetPickerProps> = ({
selectedId,
onSelect,
presets = DEFAULT_HISTORICAL_PRESETS,
recentPresets = RECENT_PRESETS,
historicalPresets = DEFAULT_HISTORICAL_PRESETS,
className,
}) => {
return (
<div className={`historical-preset-picker ${className || ''}`}>
<div className="historical-preset-picker-label">Historical events</div>
<div className="historical-preset-picker-row">
{presets.map((preset) => {
const active = selectedId === preset.id;
return (
<button
key={preset.id}
type="button"
onClick={() => onSelect(preset.fromDate, preset.toDate, preset.id)}
className={`historical-preset-chip ${active ? 'is-active' : ''}`}
title={`${preset.description} (${preset.fromDate}${preset.toDate})`}
>
{preset.label}
</button>
);
})}
</div>
{recentPresets.length > 0 ? (
<>
<div className="historical-preset-picker-label">Recent</div>
{renderRow(recentPresets, selectedId, onSelect)}
</>
) : null}
{historicalPresets.length > 0 ? (
<>
<div className="historical-preset-picker-label">Historical events</div>
{renderRow(historicalPresets, selectedId, onSelect)}
</>
) : null}
</div>
);
};