feat: instrument analysis

This commit is contained in:
OpenSquared
2026-06-28 16:57:16 +02:00
parent e4e17330b4
commit 6a683411ed
3 changed files with 85 additions and 20 deletions

View File

@@ -1066,14 +1066,20 @@ function ExplanationScore({
// ── Main page ─────────────────────────────────────────────────────────────────
const PERIODS = [
{ key: '3mo', label: '3M' }, { key: '6mo', label: '6M' },
{ key: '1y', label: '1Y' }, { key: '2y', label: '2Y' }, { key: '5y', label: '5Y' },
{ key: '5d', label: '5D' },
{ key: '1mo', label: '1M' },
{ key: '3mo', label: '3M' },
{ key: '6mo', label: '6M' },
{ key: '1y', label: '1Y' },
{ key: '2y', label: '2Y' },
{ key: '5y', label: '5Y' },
]
export default function InstrumentDashboard() {
const { id = 'SPY' } = useParams<{ id: string }>()
const navigate = useNavigate()
const [period, setPeriod] = useState('1y')
const [chartStyle, setChartStyle] = useState<'candles' | 'line'>('candles')
const [instruments, setInstruments] = useState<InstrumentConfig[]>([])
const [snapshot, setSnapshot] = useState<Snapshot | null>(null)
const [narrative, setNarrative] = useState('')
@@ -1265,6 +1271,20 @@ export default function InstrumentDashboard() {
)}
<div className="ml-auto flex items-center gap-2">
{/* Chart style toggle */}
<div className="flex items-center bg-dark-800 border border-slate-700/40 rounded-xl p-1">
<button
onClick={() => setChartStyle('candles')}
title="Chandeliers"
className={clsx('p-1.5 rounded-lg transition-colors', chartStyle === 'candles' ? 'bg-blue-700/50 text-blue-300' : 'text-slate-500 hover:text-white hover:bg-dark-700')}
><BarChart2 className="w-3.5 h-3.5" /></button>
<button
onClick={() => setChartStyle('line')}
title="Courbe lisse"
className={clsx('p-1.5 rounded-lg transition-colors', chartStyle === 'line' ? 'bg-blue-700/50 text-blue-300' : 'text-slate-500 hover:text-white hover:bg-dark-700')}
><TrendingUp className="w-3.5 h-3.5" /></button>
</div>
{/* Period selector */}
<div className="flex items-center gap-1 bg-dark-800 border border-slate-700/40 rounded-xl p-1">
{PERIODS.map(p => (
<button key={p.key} onClick={() => setPeriod(p.key)}
@@ -1300,6 +1320,7 @@ export default function InstrumentDashboard() {
indicators={snapshot.indicators}
events={[]}
height={420}
chartType={chartStyle}
onDateHover={handleDateHover}
/>

View File

@@ -998,6 +998,7 @@ export default function MarketEvents() {
// ── Filter state ─────────────────────────────────────────────────────────
const [search, setSearch] = useState('')
const [category, setCategory] = useState('')
const [level, setLevel] = useState('')
const [minScore, setMinScore] = useState(0)
const [evaluated, setEvaluated] = useState<'' | 'true' | 'false'>('')
@@ -1049,6 +1050,7 @@ export default function MarketEvents() {
setLoading(true)
const params = new URLSearchParams()
if (search) params.set('search', search)
if (category) params.set('category', category)
if (level) params.set('level', level)
if (minScore) params.set('min_score', String(minScore))
if (dateFrom) params.set('date_from', dateFrom)
@@ -1075,7 +1077,7 @@ export default function MarketEvents() {
if (e.name === 'AbortError') return // superseded by a newer load
}
setLoading(false)
}, [search, level, minScore, dateFrom, dateTo, genFrom, genTo, evaluated,
}, [search, category, level, minScore, dateFrom, dateTo, genFrom, genTo, evaluated,
instTicker, instMinScore, instDir, sortBy, sortDir])
useEffect(() => {
@@ -1163,6 +1165,33 @@ export default function MarketEvents() {
</div>
{/* ── Quick category filter ── */}
<div className="px-3 py-1.5 border-b border-slate-800/40 flex items-center gap-1 flex-wrap">
{([
{ key: '', label: 'Tout', dot: 'bg-slate-500' },
{ key: 'event_calendar', label: '★ Cal.', dot: 'bg-amber-500' },
{ key: 'geopolitical', label: '★ Géo.', dot: 'bg-red-500' },
{ key: 'fundamental', label: '★ Fund.', dot: 'bg-emerald-500' },
{ key: 'report', label: '★ Rep.', dot: 'bg-blue-500' },
{ key: 'sentiment', label: '★ Sent.', dot: 'bg-violet-500' },
{ key: 'technical', label: '★ Tech.', dot: 'bg-cyan-500' },
] as const).map(({ key, label, dot }) => (
<button
key={key}
onClick={() => setCategory(key)}
className={clsx(
'flex items-center gap-1 px-2 py-0.5 rounded text-[10px] border transition-colors',
category === key
? 'bg-slate-700/80 border-slate-500/60 text-slate-200'
: 'border-slate-800/60 text-slate-600 hover:border-slate-600 hover:text-slate-400'
)}
>
<span className={clsx('w-1.5 h-1.5 rounded-full shrink-0', dot)} />
{label}
</button>
))}
</div>
{/* ── Sort + more filters toggle ── */}
<div className="px-3 py-1.5 border-b border-slate-800/40 flex items-center gap-2">
<span className="text-xs text-slate-600">Tri:</span>
@@ -1183,7 +1212,7 @@ export default function MarketEvents() {
? 'bg-slate-700 border-slate-600 text-slate-300'
: 'border-slate-800 text-slate-600 hover:border-slate-600')}>
<SlidersHorizontal size={10} />
Filtres {(level || minScore > 0 || evaluated || instTicker) ? '●' : ''}
Filtres {(category || level || minScore > 0 || evaluated || instTicker) ? '●' : ''}
</button>
</div>