feat: Add performance metrics dashboard and metrics calculator
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>{{ title }}</title>
|
||||
<script src="https://unpkg.com/htmx.org@1.9.12"></script>
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Arial, sans-serif;
|
||||
background: #0b1220;
|
||||
color: #e5eefb;
|
||||
}
|
||||
.shell {
|
||||
max-width: 1120px;
|
||||
margin: 0 auto;
|
||||
padding: 32px 20px 48px;
|
||||
}
|
||||
.hero {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
gap: 24px;
|
||||
align-items: end;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
.title {
|
||||
font-size: 2rem;
|
||||
margin: 0 0 8px;
|
||||
}
|
||||
.subtitle {
|
||||
margin: 0;
|
||||
color: #9fb2d0;
|
||||
}
|
||||
.panel {
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-radius: 16px;
|
||||
padding: 20px;
|
||||
}
|
||||
.grid {
|
||||
display: grid;
|
||||
gap: 16px;
|
||||
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
|
||||
}
|
||||
.card {
|
||||
background: rgba(255, 255, 255, 0.04);
|
||||
border-radius: 14px;
|
||||
padding: 16px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
}
|
||||
.label {
|
||||
color: #9fb2d0;
|
||||
font-size: 0.85rem;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.value {
|
||||
font-size: 1.4rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
.meta {
|
||||
margin-top: 18px;
|
||||
color: #7f95b7;
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
.toolbar {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.button {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
padding: 10px 14px;
|
||||
border-radius: 999px;
|
||||
background: #2d6cdf;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
}
|
||||
.button.secondary {
|
||||
background: transparent;
|
||||
border: 1px solid rgba(255, 255, 255, 0.14);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<main class="shell">
|
||||
<section class="hero">
|
||||
<div>
|
||||
<h1 class="title">Arbitrade Dashboard</h1>
|
||||
<p class="subtitle">Live execution, P&L, and system state.</p>
|
||||
</div>
|
||||
<div class="toolbar">
|
||||
<a
|
||||
class="button"
|
||||
href="{{ metrics_endpoint }}"
|
||||
hx-get="{{ metrics_endpoint }}"
|
||||
hx-target="#metrics-panel"
|
||||
hx-swap="outerHTML"
|
||||
>Refresh metrics</a
|
||||
>
|
||||
<a class="button secondary" href="/health">Health</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section
|
||||
id="metrics-shell"
|
||||
hx-get="{{ metrics_endpoint }}"
|
||||
hx-target="this"
|
||||
hx-trigger="load, every 15s"
|
||||
hx-swap="outerHTML"
|
||||
>
|
||||
{% include "partials/metrics.html" %}
|
||||
</section>
|
||||
|
||||
<script>
|
||||
const stream = new EventSource("{{ stream_endpoint }}");
|
||||
stream.addEventListener("metrics", (event) => {
|
||||
const panel = document.getElementById("metrics-panel");
|
||||
if (panel) {
|
||||
panel.outerHTML = JSON.parse(event.data);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,31 @@
|
||||
<div id="metrics-panel" class="panel">
|
||||
<div class="grid">
|
||||
<article class="card">
|
||||
<div class="label">Realized P&L</div>
|
||||
<div class="value">{{ realized_pnl }}</div>
|
||||
</article>
|
||||
<article class="card">
|
||||
<div class="label">Win Rate</div>
|
||||
<div class="value">{{ win_rate }}</div>
|
||||
</article>
|
||||
<article class="card">
|
||||
<div class="label">Avg Trade Duration</div>
|
||||
<div class="value">{{ avg_trade_duration }}</div>
|
||||
</article>
|
||||
<article class="card">
|
||||
<div class="label">Opportunities / Min</div>
|
||||
<div class="value">{{ opportunities_per_minute }}</div>
|
||||
</article>
|
||||
<article class="card">
|
||||
<div class="label">Fill Rate</div>
|
||||
<div class="value">{{ fill_rate }}</div>
|
||||
</article>
|
||||
<article class="card">
|
||||
<div class="label">Latency p50 / p95 / p99</div>
|
||||
<div class="value">
|
||||
{{ latency_p50 }} | {{ latency_p95 }} | {{ latency_p99 }}
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
<div class="meta">Updated {{ generated_at }}</div>
|
||||
</div>
|
||||
Reference in New Issue
Block a user