fix: draw the trade chart for positions older than the window
Deploy / lint (push) Successful in 10s
Deploy / test (push) Successful in 1m20s
Deploy / deploy (push) Successful in 39s

TradeChart shows a fixed 21-bar window. Once a trade is older than that,
its entry bar precedes the window and entryIdx goes negative, so the price
and trail paths index past the start of series/stopPath and emit NaN
coordinates -- the browser then drops both paths entirely, leaving only the
horizontal level lines. Clamp the index to the left edge and drop the entry
marker when the entry bar is outside the window; the full-width entry line
already carries it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-04 21:12:32 +02:00
co-authored by Claude Opus 5
parent 2435abacaf
commit 07d864cf64
+12 -9
View File
@@ -378,16 +378,15 @@ export function TradeChart({
// it wanders left as more post-entry bars arrive.
const WINDOW = 21;
const MID = 10;
let start: number;
let entryIdx: number;
if (postCount <= MID + 1) {
start = Math.max(0, entryAbs - MID);
entryIdx = entryAbs - start;
} else {
const start = postCount <= MID + 1
? Math.max(0, entryAbs - MID)
// Enough history: keep the latest WINDOW bars; entry falls where it falls.
start = Math.max(0, bars.length - WINDOW);
entryIdx = entryAbs - start;
}
: Math.max(0, bars.length - WINDOW);
// A trade older than the window entered before the first visible bar. Clamp to
// the left edge — a negative index reads past the start of `series`/`stopPath`
// and NaNs out the price and trail paths entirely.
const entryBeforeWindow = entryAbs < start;
const entryIdx = Math.max(0, entryAbs - start);
const windowBars = bars.slice(start);
const series = windowBars.map((b) => b.close);
if (series.length < 2) return null;
@@ -601,7 +600,11 @@ export function TradeChart({
{entryIdx === lastIdx && (
<circle cx={px(entryIdx)} cy={py(series[entryIdx])} r="2" fill="var(--ink-3)" />
)}
{/* Entry marker only when the entry bar is actually in the window — for an
older trade the entry level line carries it instead. */}
{!entryBeforeWindow && (
<circle cx={px(entryIdx)} cy={py(entry)} r="3.5" fill="var(--ink-2)" stroke="var(--surface)" strokeWidth="1.5" />
)}
<circle cx={px(lastIdx)} cy={py(series[lastIdx])} r="4" fill={nowCol} stroke="var(--surface)" strokeWidth="2" />
</svg>
);