fix: only count matured setups in the live track record
The outcome stats were dominated by quick stop-outs: near stops resolve as losses within days while far targets take weeks, so a young sample (mostly pending, 0 expired) skewed sharply negative (e.g. 13.8% hit / -0.46R vs the backtest's 35.8% / +0.18R) — a maturation artifact, not a real result. get_performance_stats now counts only setups whose full ~30-day window has elapsed (_MATURITY_DAYS), so winners had as long as losers (unbiased, and comparable to the backtest). A new `maturing` count reports the younger setups held back. The Track Record UI relabels "Evaluated" -> "Matured", shows the maturing count, and explains the window in the empty state + methodology note. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -171,7 +171,10 @@ export function TrackRecordPanel() {
|
||||
neither level hit within 30 trading days <span className="text-gray-300">expire</span> at
|
||||
0R. Avg R is the expectancy per trade: wins earn their R:R ratio, losses cost −1R — a
|
||||
positive value means the signals have been profitable on a risk-adjusted basis. The
|
||||
evaluator runs nightly after OHLCV collection.
|
||||
evaluator runs nightly after OHLCV collection. Only setups whose full 30-day window has
|
||||
elapsed are counted — younger ones show as <span className="text-gray-300">maturing</span>,
|
||||
since near stops resolve in days while far targets need time, so early numbers would skew
|
||||
negative.
|
||||
</p>
|
||||
</Disclosure>
|
||||
<div className="flex shrink-0 items-center gap-2">
|
||||
@@ -198,10 +201,12 @@ export function TrackRecordPanel() {
|
||||
|
||||
{data && data.overall.total === 0 && (
|
||||
<Callout variant="empty">
|
||||
{qualifiedOnly
|
||||
? 'No evaluated setups meet the activation thresholds yet. Untick "Qualified signals only" to see all evaluated setups, or wait for more outcomes.'
|
||||
: 'No evaluated setups yet. Outcomes appear once setups are old enough for their stop or target to be hit — the evaluator runs nightly, or click Evaluate Now.'}
|
||||
{data.pending > 0 && ` ${data.pending} setup${data.pending === 1 ? '' : 's'} pending evaluation.`}
|
||||
{data.maturing > 0
|
||||
? `No setups have completed their ~30-day evaluation window yet — ${data.maturing} still maturing. ` +
|
||||
'Stats appear once a setup’s full window has elapsed; counting them earlier would skew toward quick stop-outs.'
|
||||
: qualifiedOnly
|
||||
? 'No matured setups meet the activation thresholds yet. Untick "Qualified signals only" to see all, or wait for more outcomes.'
|
||||
: 'No matured setups yet. Outcomes appear once setups complete their evaluation window — the evaluator runs nightly, or click Evaluate Now.'}
|
||||
</Callout>
|
||||
)}
|
||||
|
||||
@@ -226,9 +231,9 @@ export function TrackRecordPanel() {
|
||||
sub="cumulative risk-adjusted result"
|
||||
/>
|
||||
<StatCard
|
||||
label="Evaluated"
|
||||
label="Matured"
|
||||
value={String(data.overall.total)}
|
||||
sub={`${data.pending} pending · ${data.overall.expired} expired`}
|
||||
sub={`${data.maturing} maturing · ${data.overall.expired} expired`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -153,6 +153,7 @@ export interface OutcomeBucketStats {
|
||||
export interface PerformanceStats {
|
||||
overall: OutcomeBucketStats;
|
||||
pending: number;
|
||||
maturing: number;
|
||||
by_direction: Record<string, OutcomeBucketStats>;
|
||||
by_action: Record<string, OutcomeBucketStats>;
|
||||
by_confidence: Record<string, OutcomeBucketStats>;
|
||||
|
||||
Reference in New Issue
Block a user