fix(strategy-ui): correct rankings, currency, injection view and staleness
- MaxDD ranks shallower drawdowns first (values are negative); ruined results are badged and never ranked as best. - Metrics render '—' for null/non-finite values instead of crashing. - Amounts use the market's currency (CNY for CN) instead of hard-coded USD. - Injection scenarios show invested / final value / profit / return on invested from capitalFlows and label return metrics as time-weighted. - Precomputed results show their data end date and warn when older than 7 days; live strategies warn when not updated for 4 days, show start date, price as-of, stale holdings, and same-window benchmark with excess return. - Unknown precomputed scenario returns 400 instead of silently serving the first scenario; the client uses the scenarioId it receives. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -172,6 +172,7 @@ function resolveScenarios(raw: { scenarios?: Record<string, unknown>; markets?:
|
||||
label: string;
|
||||
description?: string;
|
||||
capital: number;
|
||||
capitalByMarket?: Record<string, number>;
|
||||
injectionSchedule: unknown;
|
||||
markets: Record<string, unknown>;
|
||||
}>;
|
||||
@@ -191,6 +192,7 @@ function resolveScenarios(raw: { scenarios?: Record<string, unknown>; markets?:
|
||||
label: string;
|
||||
description?: string;
|
||||
capital: number;
|
||||
capitalByMarket?: Record<string, number>;
|
||||
injectionSchedule: unknown;
|
||||
markets: Record<string, unknown>;
|
||||
}>;
|
||||
@@ -207,6 +209,7 @@ app.get("/api/strategies/precomputed/index", (_request, response, next) => {
|
||||
label: sc.label,
|
||||
description: sc.description,
|
||||
capital: sc.capital,
|
||||
capitalByMarket: sc.capitalByMarket,
|
||||
injectionSchedule: sc.injectionSchedule ?? null,
|
||||
availableMarkets: Object.keys(sc.markets ?? {}),
|
||||
}));
|
||||
@@ -223,9 +226,12 @@ app.get("/api/strategies/precomputed", (_request, response, next) => {
|
||||
const raw = loadPrecomputedFile();
|
||||
const scenarios = resolveScenarios(raw);
|
||||
const scenarioIds = Object.keys(scenarios);
|
||||
const scenarioId = requestedScenario && scenarios[requestedScenario]
|
||||
? requestedScenario
|
||||
: scenarioIds[0];
|
||||
// An explicit but unknown scenario is a client error; silently serving
|
||||
// another scenario would mislabel the results.
|
||||
if (requestedScenario && !Object.hasOwn(scenarios, requestedScenario)) {
|
||||
throw new Error(`Unknown pre-computed scenario: ${requestedScenario}`);
|
||||
}
|
||||
const scenarioId = requestedScenario ?? scenarioIds[0];
|
||||
const scenario = scenarios[scenarioId];
|
||||
if (!scenario) {
|
||||
throw new Error("No pre-computed scenarios available.");
|
||||
|
||||
Reference in New Issue
Block a user