File size: 3,139 Bytes
9cb3002
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
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>
  );
};