Implement P1 local matcher/ledger and P2 strategy engine.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-24 17:03:46 +08:00
parent 0fca5f025e
commit 51b8bb8f8a
30 changed files with 2086 additions and 150 deletions
+85 -2
View File
@@ -1,8 +1,91 @@
import { useEffect, useState } from "react";
import { apiFetch } from "../api/client";
type Group = {
group_id: string;
status: string;
bias: string | null;
option_side: string | null;
perp_side: string | null;
initial_premium: number;
realized_pnl: number;
close_reason: string | null;
open_at_ms: number | null;
close_at_ms: number | null;
};
type Fill = {
id: number;
leg: string;
action: string;
side: string;
fill_px: number;
fee: number;
qty_eth: number;
};
export default function TradesPage() {
const [groups, setGroups] = useState<Group[]>([]);
const [selected, setSelected] = useState<string | null>(null);
const [fills, setFills] = useState<Fill[]>([]);
const [err, setErr] = useState("");
useEffect(() => {
apiFetch<{ groups: Group[] }>("/api/trades/groups")
.then((r) => setGroups(r.groups))
.catch((e) => setErr(e instanceof Error ? e.message : String(e)));
}, []);
async function openGroup(id: string) {
setSelected(id);
try {
const r = await apiFetch<{ fills: Fill[] }>(`/api/trades/groups/${id}`);
setFills(r.fills);
} catch (e) {
setErr(e instanceof Error ? e.message : String(e));
}
}
return (
<div className="card">
<div>
<h2 style={{ marginTop: 0 }}></h2>
<p style={{ color: "var(--muted)" }}> P1/P2 </p>
{err ? <div className="err">{err}</div> : null}
<div className="card" style={{ marginBottom: 12 }}>
{groups.length === 0 ? (
<p style={{ color: "var(--muted)" }}></p>
) : (
groups.map((g) => (
<div
key={g.group_id}
className="kv"
style={{ cursor: "pointer" }}
onClick={() => openGroup(g.group_id)}
>
<span className="mono">
{g.group_id} · {g.status} · {g.perp_side}/{g.option_side}
</span>
<span className="mono">
PnL {Number(g.realized_pnl || 0).toFixed(2)} · {g.close_reason || "—"}
</span>
</div>
))
)}
</div>
{selected ? (
<div className="card">
<h3 style={{ marginTop: 0 }}>{selected} </h3>
{fills.map((f) => (
<div key={f.id} className="kv">
<span className="mono">
{f.leg} {f.action} {f.side}
</span>
<span className="mono">
px {f.fill_px.toFixed(4)} · qty {f.qty_eth} · fee {f.fee.toFixed(4)}
</span>
</div>
))}
</div>
) : null}
</div>
);
}