feat: show ops-map summaries as detailed period tables
Replace paragraph text with day-hit stats (days/days_hit/pct) so leverage and move charts list each hour with counts. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+107
-8
@@ -10,7 +10,12 @@ import AppNav from "../components/AppNav";
|
||||
import LeverageChart from "../components/LeverageChart";
|
||||
import LoginGate from "../components/LoginGate";
|
||||
import MovePointsChart from "../components/MovePointsChart";
|
||||
import { leverageSummary, moveSummary } from "../lib/opsSummary";
|
||||
import {
|
||||
fmtNum,
|
||||
fmtPct,
|
||||
leverageSummaryTable,
|
||||
moveSummaryTable,
|
||||
} from "../lib/opsSummary";
|
||||
|
||||
type RangeKey = "day" | "week" | "month";
|
||||
type SideKey = "both" | "C" | "P";
|
||||
@@ -215,9 +220,49 @@ export default function OpsMapPage() {
|
||||
minLeverage={lev.min_leverage}
|
||||
title={`上图 · 时段杠杆均值(${rangeLabel})`}
|
||||
/>
|
||||
<p className="chart-summary">
|
||||
{leverageSummary(range, lev.buckets, lev.min_leverage)}
|
||||
</p>
|
||||
{(() => {
|
||||
const levTable = leverageSummaryTable(
|
||||
range,
|
||||
lev.buckets,
|
||||
lev.min_leverage
|
||||
);
|
||||
if (levTable.kind === "empty") {
|
||||
return <p className="chart-summary">{levTable.message}</p>;
|
||||
}
|
||||
return (
|
||||
<div className="chart-summary chart-summary-table">
|
||||
{levTable.note && (
|
||||
<div className="summary-note">{levTable.note}</div>
|
||||
)}
|
||||
<div className="summary-table-wrap">
|
||||
<table className="summary-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>时段</th>
|
||||
<th>一共几天</th>
|
||||
<th>达标几天</th>
|
||||
<th>达标概率</th>
|
||||
<th>杠杆均值</th>
|
||||
<th>样本数</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{levTable.rows.map((r) => (
|
||||
<tr key={r.label}>
|
||||
<td>{r.label}</td>
|
||||
<td>{r.days}</td>
|
||||
<td>{r.daysHit}</td>
|
||||
<td>{r.pct != null ? fmtPct(r.pct) : "—"}</td>
|
||||
<td>{r.mean != null ? fmtNum(r.mean) : "—"}</td>
|
||||
<td>{r.n}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
|
||||
<div className="toolbar" style={{ marginTop: "1.25rem" }}>
|
||||
<div className="seg">
|
||||
@@ -250,14 +295,68 @@ export default function OpsMapPage() {
|
||||
moveMode === "abs" ? "abs" : "signed"
|
||||
})`}
|
||||
/>
|
||||
<p className="chart-summary">
|
||||
{moveSummary(range, mov?.buckets ?? [], {
|
||||
{(() => {
|
||||
const movTable = moveSummaryTable(range, mov?.buckets ?? [], {
|
||||
pendingExpiry: mov?.pending_expiry,
|
||||
pendingCount: mov?.pending_count,
|
||||
mode: moveMode,
|
||||
apiMessage: mov?.message,
|
||||
})}
|
||||
</p>
|
||||
});
|
||||
if (movTable.kind === "empty") {
|
||||
return <p className="chart-summary">{movTable.message}</p>;
|
||||
}
|
||||
return (
|
||||
<div className="chart-summary chart-summary-table">
|
||||
{movTable.note && (
|
||||
<div className="summary-note">{movTable.note}</div>
|
||||
)}
|
||||
<div className="summary-table-wrap">
|
||||
<table className="summary-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>时段</th>
|
||||
<th>一共几天</th>
|
||||
<th>样本数</th>
|
||||
<th>
|
||||
{moveMode === "abs" ? "绝对波动均值" : "带符号均值"}
|
||||
</th>
|
||||
<th>
|
||||
{moveMode === "abs" ? "带符号均值" : "绝对波动均值"}
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{movTable.rows.map((r) => (
|
||||
<tr key={r.label}>
|
||||
<td>{r.label}</td>
|
||||
<td>{r.days}</td>
|
||||
<td>{r.n}</td>
|
||||
<td>
|
||||
{moveMode === "abs"
|
||||
? r.meanAbs != null
|
||||
? fmtNum(r.meanAbs, 2)
|
||||
: "—"
|
||||
: r.meanSigned != null
|
||||
? fmtNum(r.meanSigned, 2)
|
||||
: "—"}
|
||||
</td>
|
||||
<td>
|
||||
{moveMode === "abs"
|
||||
? r.meanSigned != null
|
||||
? fmtNum(r.meanSigned, 2)
|
||||
: "—"
|
||||
: r.meanAbs != null
|
||||
? fmtNum(r.meanAbs, 2)
|
||||
: "—"}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user