QuantHive / ui /src /components /MetricsPanel.jsx
ARKAISW's picture
Hackathon Final Submission: PettingZoo multi-agent arch, GRPO training, docs
9cb3002
import React from 'react';
import { motion } from 'framer-motion';
const clamp = (value) => Math.min(Math.max(value || 0, 0), 1);
const MetricCard = ({ label, value, tone, hint }) => (
<div className="rounded-[1.6rem] border border-white/65 bg-white/80 p-4 shadow-[0_16px_30px_rgba(77,44,26,0.08)]">
<div className="flex items-center justify-between text-[11px] font-semibold uppercase tracking-[0.24em] text-stone-500">
<span>{label}</span>
<span>{clamp(value).toFixed(2)}</span>
</div>
<div className="mt-4 h-3 rounded-full bg-stone-200/80">
<motion.div
className="h-3 rounded-full"
style={{ background: tone }}
initial={{ width: 0 }}
animate={{ width: `${clamp(value) * 100}%` }}
transition={{ type: 'spring', stiffness: 130, damping: 24 }}
/>
</div>
<div className="mt-3 text-sm text-stone-600">{hint}</div>
</div>
);
export const MetricsPanel = ({ metrics, trade, agents }) => {
const reward = clamp(metrics?.reward);
const grade = clamp(metrics?.grade);
const drawdown = clamp(1 - (metrics?.drawdown || 0));
const sharpe = clamp(metrics?.sharpe);
const confidences = Object.values(agents || {}).map((agent) => agent?.confidence || 0);
const deskSync = confidences.length
? confidences.reduce((sum, confidence) => sum + confidence, 0) / confidences.length
: 0;
return (
<div className="rounded-[2rem] border border-[#7d5a4f]/15 bg-[#fff8ef]/92 p-6 shadow-[0_28px_50px_rgba(77,44,26,0.12)]">
<div className="mb-5 flex items-end justify-between gap-6">
<div>
<div className="text-[11px] font-semibold uppercase tracking-[0.34em] text-stone-500">Training Pulse</div>
<h3 className="mt-2 text-2xl font-semibold text-stone-800">Desk metrics in motion</h3>
</div>
<div className="rounded-full bg-white/80 px-4 py-2 text-[11px] font-semibold uppercase tracking-[0.24em] text-stone-500">
{trade?.override ? 'PM override live' : 'Autonomy running'}
</div>
</div>
<div className="grid gap-4 md:grid-cols-5">
<MetricCard
label="Reward"
value={reward}
tone="linear-gradient(90deg, #4cc9f0, #90e0ef)"
hint="Immediate step reward from the latest action."
/>
<MetricCard
label="Grade"
value={grade}
tone="linear-gradient(90deg, #52b788, #95d5b2)"
hint="Overall normalized performance quality."
/>
<MetricCard
label="Drawdown"
value={drawdown}
tone="linear-gradient(90deg, #f4a261, #f6bd60)"
hint="Higher means the desk is protecting capital."
/>
<MetricCard
label="Sharpe"
value={sharpe}
tone="linear-gradient(90deg, #7f8ce6, #9ec5fe)"
hint="Risk-adjusted return trend for the episode."
/>
<MetricCard
label="Desk Sync"
value={deskSync}
tone="linear-gradient(90deg, #f28c6f, #f6bd60)"
hint="Average conviction across all five agents."
/>
</div>
</div>
);
};