feat: instrument analysis

This commit is contained in:
OpenSquared
2026-06-28 23:28:21 +02:00
parent 5a0aa30d60
commit 3d7b3e47c9
2 changed files with 11 additions and 6 deletions

View File

@@ -73,9 +73,11 @@ export default function InstrumentChart({ priceData, indicators, events = [], he
const containerRef = useRef<HTMLDivElement>(null) const containerRef = useRef<HTMLDivElement>(null)
const cleanupRef = useRef<(() => void) | null>(null) const cleanupRef = useRef<(() => void) | null>(null)
const onHoverRef = useRef(onDateHover) const onHoverRef = useRef(onDateHover)
const onChartReadyRef = useRef(onChartReady)
// Keep callback ref fresh without triggering chart rebuild // Keep callback refs fresh without triggering chart rebuild
useEffect(() => { onHoverRef.current = onDateHover }, [onDateHover]) useEffect(() => { onHoverRef.current = onDateHover }, [onDateHover])
useEffect(() => { onChartReadyRef.current = onChartReady }, [onChartReady])
useEffect(() => { useEffect(() => {
cleanupRef.current?.() cleanupRef.current?.()
@@ -211,9 +213,9 @@ export default function InstrumentChart({ priceData, indicators, events = [], he
chart.timeScale().fitContent() chart.timeScale().fitContent()
// Expose coordinate mapping so siblings can align with the chart x-axis // Expose coordinate mapping so siblings can align with the chart x-axis
if (onChartReady && containerRef.current) { if (onChartReadyRef.current && containerRef.current) {
const canvasLeft = containerRef.current.getBoundingClientRect().left const canvasLeft = containerRef.current.getBoundingClientRect().left
onChartReady((d: string) => chart.timeScale().timeToCoordinate(d as any), canvasLeft) onChartReadyRef.current((d: string) => chart.timeScale().timeToCoordinate(d as any), canvasLeft)
} }
// ── Star overlay — ★ icons positioned via chart coordinate API ──────── // ── Star overlay — ★ icons positioned via chart coordinate API ────────
@@ -326,7 +328,7 @@ export default function InstrumentChart({ priceData, indicators, events = [], he
chart.timeScale().unsubscribeVisibleLogicalRangeChange(renderStars) chart.timeScale().unsubscribeVisibleLogicalRangeChange(renderStars)
if (starsOverlay.parentNode) starsOverlay.parentNode.removeChild(starsOverlay) if (starsOverlay.parentNode) starsOverlay.parentNode.removeChild(starsOverlay)
chart.remove() chart.remove()
onChartReady?.(null as any, 0) onChartReadyRef.current?.(null as any, 0)
} }
}) })
@@ -335,7 +337,7 @@ export default function InstrumentChart({ priceData, indicators, events = [], he
cleanupRef.current?.() cleanupRef.current?.()
cleanupRef.current = null cleanupRef.current = null
} }
}, [priceData, indicators, events, height, chartType, theoryCurve, onChartReady]) }, [priceData, indicators, events, height, chartType, theoryCurve])
return ( return (
<div className="bg-dark-900/60 rounded-xl border border-slate-700/40 overflow-hidden"> <div className="bg-dark-900/60 rounded-xl border border-slate-700/40 overflow-hidden">

View File

@@ -10,6 +10,9 @@ import InstrumentChart, { TheoPoint } from '../components/InstrumentChart'
const api = axios.create({ baseURL: '/api' }) const api = axios.create({ baseURL: '/api' })
// Stable empty array — prevents InstrumentChart useEffect from re-running on every render
const NO_CHART_EVENTS: never[] = []
// ── Types ───────────────────────────────────────────────────────────────────── // ── Types ─────────────────────────────────────────────────────────────────────
interface CausalTemplate { interface CausalTemplate {
@@ -1283,7 +1286,7 @@ export default function InstrumentDashboard() {
<InstrumentChart <InstrumentChart
priceData={snapshot.price_data} priceData={snapshot.price_data}
indicators={snapshot.indicators} indicators={snapshot.indicators}
events={[]} events={NO_CHART_EVENTS}
height={420} height={420}
chartType={chartStyle} chartType={chartStyle}
onDateHover={handleDateHover} onDateHover={handleDateHover}