+
+
+
+
+ Positions
+
+
+ {lastUpdated ? `Updated ${lastUpdated.toLocaleTimeString("en-IN", { timeZone: "Asia/Kolkata", hour12: false })} IST` : "Live positions from Angel One"}
+
+
+
+
+
+ {error && (
+
+ {error}
+
+ )}
+
+ {/* Summary stat cards */}
+
+ = 0 ? TrendingUp : TrendingDown}
+ className={summary && summary.totalPnl < 0 ? "border-rose-500/30" : "border-emerald-500/30"}
+ />
+
+
+ 0 ? `${closed.length} closed today` : undefined}
+ />
+
+
+ {/* Open positions table */}
+
+
+ Open Positions ({open.length})
+
+
+ {loading ? (
+ Loading…
+ ) : open.length === 0 ? (
+ No open positions
+ ) : (
+
+
+
+
+ | Symbol |
+ Qty |
+ Avg |
+ LTP |
+ Unrealised |
+ Total P&L |
+ Type |
+
+
+
+ {open.map(p => (
+
+ | {p.tradingsymbol} |
+
+ 0 ? "text-emerald-500" : "text-rose-500"}>
+ {p.netqty > 0 ? "+" : ""}{p.netqty}
+
+ |
+ ₹{p.avg_price.toFixed(2)} |
+ ₹{p.ltp.toFixed(2)} |
+ |
+ |
+
+
+ {p.instrumenttype || p.producttype}
+
+ |
+
+ ))}
+
+
+
+ )}
+
+
+
+ {/* Closed today */}
+ {!loading && closed.length > 0 && (
+
+
+ Closed Today ({closed.length})
+
+
+
+
+
+
+ | Symbol |
+ Realised P&L |
+ Type |
+
+
+
+ {closed.map(p => (
+
+ | {p.tradingsymbol} |
+ |
+
+
+ {p.instrumenttype || p.producttype}
+
+ |
+
+ ))}
+
+
+
+
+
+ )}
+
+ )
+}
diff --git a/dashboard/src/components/app-sidebar.tsx b/dashboard/src/components/app-sidebar.tsx
index 2bbf438..5fa8e33 100644
--- a/dashboard/src/components/app-sidebar.tsx
+++ b/dashboard/src/components/app-sidebar.tsx
@@ -10,6 +10,7 @@ import {
DollarSign,
FolderOpen,
Briefcase,
+ BarChart2,
} from "lucide-react"
import { useTigerLogs } from "@/hooks/use-bridge"
@@ -46,6 +47,11 @@ const navMain = [
url: "/tasks",
icon: CheckSquare,
},
+ {
+ title: "Positions",
+ url: "/positions",
+ icon: BarChart2,
+ },
{
title: "Cost Monitor",
url: "/cost",