feat: instrument analysis

This commit is contained in:
OpenSquared
2026-06-30 18:31:43 +02:00
parent 75489a54bd
commit 479b2b7b05

View File

@@ -762,17 +762,49 @@ function CausalFrise({
} | null>(null)
const [popupScore, setPopupScore] = useState<number | null | 'loading'>('loading')
// Fetch activation_score live when popup opens for a specific event
// Fetch analysis live when popup opens — compute same precision as MarketEvents expanded view
useEffect(() => {
const evId = activeChip?.ev.id
if (!evId) { setPopupScore(null); return }
setPopupScore('loading')
api.get(`/causal-lab/analyses?market_event_id=${evId}&limit=1`)
.then(r => {
const score = r.data?.[0]?.activation_score
setPopupScore(score != null ? Math.round(score * 100) : null)
const analysis = r.data?.[0]
console.log('[CausalFrise] analysis for event', evId, analysis)
if (!analysis) { setPopupScore(null); return }
// Compute magnitude-weighted precision (same formula as MarketEvents expanded panel)
const preds: Record<string, number> = analysis.prediction_json || {}
const actuals: Record<string, number> = analysis.actual_json || {}
const graph = analysis.graph_json || {}
const outputNodes: { id: string; instrument?: string }[] = (graph.nodes || [])
.filter((n: { type?: string }) => n.type === 'market_asset' || n.type === 'output')
console.log('[CausalFrise] preds:', preds, 'actuals:', actuals, 'outputNodes:', outputNodes)
const nodeScores = outputNodes.map((n: { id: string; instrument?: string }) => {
const pred = preds[n.id]
const act = actuals[n.instrument || n.id] ?? actuals[n.id]
if (pred == null || act == null) return null
if (pred === 0 && act === 0) return 100
if (pred === 0) return 40
const sameDir = pred * act > 0
if (!sameDir) return 0
const ratio = Math.min(Math.abs(act), Math.abs(pred)) / Math.max(Math.abs(act), Math.abs(pred))
return Math.round(50 + ratio * 50)
}).filter((s): s is number => s != null)
console.log('[CausalFrise] nodeScores:', nodeScores)
if (nodeScores.length > 0) {
setPopupScore(Math.round(nodeScores.reduce((a, b) => a + b, 0) / nodeScores.length))
} else {
// Fallback: use stored activation_score if no prediction data
const stored = analysis.activation_score
setPopupScore(stored != null ? Math.round(stored * 100) : null)
}
})
.catch(() => setPopupScore(null))
.catch(err => { console.error('[CausalFrise] fetch error:', err); setPopupScore(null) })
}, [activeChip?.ev.id])
useEffect(() => {