feat: instrument analysis

This commit is contained in:
OpenSquared
2026-06-29 00:06:14 +02:00
parent 3bcecdab09
commit 5e65424500
3 changed files with 28 additions and 5 deletions

View File

@@ -1176,7 +1176,7 @@ def list_analyses(
rows = conn.execute(f""" rows = conn.execute(f"""
SELECT a.*, e.name as event_name, e.category, e.start_date, SELECT a.*, e.name as event_name, e.category, e.start_date,
t.name as template_name t.name as template_name, t.graph_json as template_graph_json
FROM causal_event_analyses a FROM causal_event_analyses a
LEFT JOIN market_events e ON e.id = a.market_event_id LEFT JOIN market_events e ON e.id = a.market_event_id
LEFT JOIN causal_graph_templates t ON t.id = a.template_id LEFT JOIN causal_graph_templates t ON t.id = a.template_id
@@ -1194,6 +1194,10 @@ def list_analyses(
d[f] = json.loads(d[f] or "{}") d[f] = json.loads(d[f] or "{}")
except Exception: except Exception:
d[f] = {} d[f] = {}
try:
d["graph_json"] = json.loads(d.get("template_graph_json") or "{}")
except Exception:
d["graph_json"] = {}
result.append(d) result.append(d)
return result return result

View File

@@ -5,6 +5,7 @@ regime detection, trend summary, event filtering, and AI narrative.
""" """
import json import json
import os import os
import re
import logging import logging
import numpy as np import numpy as np
import pandas as pd import pandas as pd
@@ -12,6 +13,11 @@ from pathlib import Path
from typing import Dict, Any, List, Optional, Tuple from typing import Dict, Any, List, Optional, Tuple
from datetime import datetime, date from datetime import datetime, date
def _base_ticker(t: str) -> str:
"""Normalize Yahoo Finance tickers for comparison: EURUSD=X → EURUSD, BZ=F → BZ, ^GSPC → GSPC."""
return re.sub(r'(=X|=F|=RR|-USD|\^)$', '', t.strip().upper())
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
# ── Config loading ───────────────────────────────────────────────────────────── # ── Config loading ─────────────────────────────────────────────────────────────
@@ -586,8 +592,10 @@ def _get_relevant_events(
asset_hit = any(ra in ev_assets for ra in related) asset_hit = any(ra in ev_assets for ra in related)
# Always include events that have a causal analysis for this instrument # Always include events that have a causal analysis for this instrument
# Normalize tickers: strip Yahoo Finance suffixes (=X, =F, ^, -USD, =RR) for comparison
analyzed = ev.get("analyzed_instruments") or "" analyzed = ev.get("analyzed_instruments") or ""
analysis_hit = inst_upper and inst_upper in [i.strip().upper() for i in analyzed.split(",") if i.strip()] analyzed_bases = [_base_ticker(s) for s in analyzed.split(",") if s.strip()]
analysis_hit = bool(inst_upper and _base_ticker(inst_upper) in analyzed_bases)
if keyword_hit or asset_hit or analysis_hit: if keyword_hit or asset_hit or analysis_hit:
filtered.append({ filtered.append({

View File

@@ -60,6 +60,8 @@ interface CausalAnalysis {
activation_score: number | null activation_score: number | null
analyzed_at: string analyzed_at: string
prediction_json: Record<string, number> prediction_json: Record<string, number>
actual_json: Record<string, number>
graph_json?: { nodes: GraphNode[]; edges: GraphEdge[] }
} }
interface TemplateRef { interface TemplateRef {
@@ -410,9 +412,18 @@ function EventDetail({
if (r.ok) { if (r.ok) {
const data: CausalAnalysis[] = await r.json() const data: CausalAnalysis[] = await r.json()
setAnalyses(data) setAnalyses(data)
// Pre-select the most recent analysis's template so the form isn't blank on re-open if (data.length > 0) {
if (data.length > 0 && data[0].template_id) { const latest = data[0]
setSelTmpl(data[0].template_id) if (latest.template_id) setSelTmpl(latest.template_id)
// Reconstruct graph state from stored analysis so it's always visible on reopen
setAnResult({
score: latest.activation_score,
preds: latest.prediction_json || {},
actuals: latest.actual_json || {},
})
if (latest.graph_json?.nodes?.length) {
setGraphData(latest.graph_json as GraphData)
}
} }
} }
}, [event.id]) }, [event.id])