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:
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user