QF-Lib Quant Report: full strategy performance analytics

Backend: strategies/quant_report.py
  - equityCurve: daily PnL from trade history
  - monthlyReturns: heatmap matrix (years x months)
  - yearlyReturns: bar chart data with mean
  - monthlyReturnDistribution: histogram bins
  - qqPlot: theoretical vs observed quantiles
  - rollingStats: 6-month rolling return + volatility

API: /api/quant-report/{name}
  Computes full report from any backtest JSON file

Frontend: QuantReport.tsx
  - Strategy Performance chart (equity curve, blue line)
  - Monthly Returns heatmap (blue saturation)
  - Yearly Returns bar chart with mean line
  - Distribution histogram
  - Normal QQ plot with diagonal reference
  - Rolling Statistics (6-month, dual line)
  - QF-Lib header with logo and metadata
  - Access via QF-Lib Report button in detail view
This commit is contained in:
ramseshk
2026-08-06 03:37:25 +00:00
parent 03ebe9e795
commit 0e08543823
5 changed files with 781 additions and 4 deletions
+32 -3
View File
@@ -13,6 +13,7 @@ import { PositionsPanel } from "@/components/positions-panel";
import { OBIDetail } from "@/components/obi-detail";
import OrderBookDepthMap from "@/components/orderbook-depth-map";
import L2Terminal from "@/components/L2Terminal";
import QuantReport from "@/components/QuantReport";
import { useLiveMetrics, usePaperMetrics, fetchHistorical, fetchBacktestDetail, recalcBacktest } from "@/lib/api";
import type { Strategy, BacktestSummary, BacktestFull, Trade, Position, Order } from "@/lib/types";
@@ -28,6 +29,7 @@ export default function Dashboard() {
const [detailOpen, setDetailOpen] = useState(false);
const [l2TerminalOpen, setL2TerminalOpen] = useState(false);
const [quantReportOpen, setQuantReportOpen] = useState(false);
const [detailName, setDetailName] = useState("");
const [detailTab, setDetailTab] = useState<Tab>("live");
const [filter, setFilter] = useState("ALL");
@@ -228,9 +230,17 @@ export default function Dashboard() {
)}
<div>
<h4 className="text-[10px] font-semibold text-muted-foreground uppercase tracking-wider mb-3 pb-2 border-b border-border">
Trade History {detailTrades.length > 0 ? `(${detailTrades.length})` : ""}
</h4>
<div className="flex items-center justify-between mb-3 pb-2 border-b border-border">
<h4 className="text-[10px] font-semibold text-muted-foreground uppercase tracking-wider">
Trade History {detailTrades.length > 0 ? `(${detailTrades.length})` : ""}
</h4>
<button
onClick={() => setQuantReportOpen(true)}
className="text-[9px] px-2 py-0.5 bg-blue-50 text-blue-700 rounded font-mono hover:bg-blue-100 transition-colors"
>
QF-Lib Report
</button>
</div>
{detailTrades.length > 0 ? (
<div className="overflow-x-auto rounded-lg border border-border">
<Table>
@@ -379,6 +389,25 @@ export default function Dashboard() {
<L2Terminal coin="BTC" className="w-full h-full" />
</div>
)}
{/* Fullscreen Quant Report */}
{quantReportOpen && (
<div className="fixed inset-0 z-[200] bg-white overflow-auto">
<div className="sticky top-0 z-[201] bg-white border-b border-gray-200 px-4 py-2 flex justify-between items-center">
<span className="text-xs text-gray-600">QF-Lib Quant Report</span>
<button
onClick={() => setQuantReportOpen(false)}
className="text-xs text-gray-500 hover:text-black font-mono px-3 py-1 border border-gray-300 rounded"
>
Close
</button>
</div>
<QuantReport
strategyName={detailName}
backtestId={btFull ? `${detailName.replace(/\s+/g, "_").toLowerCase()}.json` : "live"}
/>
</div>
)}
</div>
);
}