Shop It Docs
Portfolio Module

Summary & Valuation

Headline summary numbers, valuation time-series, and broker-analysis bucket

Three read endpoints under the Portfolio Swagger tag drive dashboard widgets that don't fit on the bundled /portfolios/{id} detail call.

MethodPathService method
GET/portfolios/{id}/summarycore.Service.FindSummary
GET/portfolios/{id}/valuationcore.Service.FindValuation
GET/portfolios/{id}/broker-analysiscore.Service.FindBrokerAnalysis

GET /portfolios/{id}/summary

Returns just the summary block from the full detail call. Cheap for clients that only need headline numbers. Internally delegates to FindDetail and slices the summary out — same Redis cache key (portfolio:detail:{id}).

{
  "message": "Portfolio summary fetched successfully",
  "data": {
    "cUnits": 100,        // current units across all companies
    "sUnits": 40,         // cumulative sold units across all companies
    "totalInv": 50000,    // all-time invested (current cost basis + user cost of sold)
    "curInv": 30000,      // current cost basis (WACC × current units)
    "curVal": 36000,      // market value (LTP × current units)
    "soldVal": 24000,     // gross sold (Σ SELL.amount)
    "div": 4000,          // Σ DIVIDEND.amount
    "unrealPnl": 6000,    // curVal − curInv
    "realPnl": 3800,      // Σ (SELL.netAmount − SELL.basePrice × qty)
    "totalPnl": 13800,    // unrealPnl + realPnl + div
    "totalPnlPct": 27.6,  // totalPnl / totalInv × 100, omitted if totalInv == 0
    "dayPnl": 1850,       // sum of per-company DayPnL
    "dayPnlPct": 5.42,    // dayPnl / (Σ CurUnits × PrevClose) × 100
    "recv": 0             // Σ pending dividend receivables
  }
}

GET /portfolios/{id}/valuation

Time-series of portfolio value (v) and cost basis (cb) for charting.

Query params

ParamDefaultValues
range3M1D, 1W, 1M, 3M, 6M, 1Y, YTD, ALL

Algorithm

1D is intraday: bulk-fetch 15-min bucketed prices for today, replay transactions, emit one point per bucket.

All other ranges are daily: bulk-fetch close prices for the requested window, replay transactions, emit one point per trading day:

for each trading day d in range:
  apply every event with transactedAt <= d to running State
  v(d)  = Σ CurUnits × close(company, d)
  cb(d) = Σ CostCurrent

The same incremental sweep produces both the value and profit-over-time series.

Success

{
  "message": "Portfolio valuation fetched successfully",
  "data": {
    "range": "3M",
    "series": [
      { "d": "2026-01-28", "v": 28500, "cb": 30000 },
      { "d": "2026-01-29", "v": 29100, "cb": 30000 }
    ]
  }
}

Caching

KeyTTL
portfolio:valuation:{id}:1D60s
portfolio:valuation:{id}:{1W,1M,3M,6M,1Y,YTD,ALL}5min

All ranges are busted as a group on every transaction mutation.

GET /portfolios/{id}/broker-analysis

Today's accumulation/distribution/mixed buckets for the portfolio's currently held companies. Standalone — not bundled with /portfolios/{id} because most users never scroll to it and the dashboard shouldn't pay for it on first paint.

{
  "message": "Broker analysis fetched successfully",
  "data": {
    "tradeDate": "2026-04-28",
    "accumulation": {
      "count": 1,
      "items": [
        {
          "sym": "NABIL", "name": "Nabil Bank Limited", "icon": "...",
          "brokerSignal": { "buyers": 4, "sellers": 12 },
          "impact": 12345678.50
        }
      ]
    },
    "distribution": { "count": 0, "items": [] },
    "mixed":        { "count": 0, "items": [] }
  }
}

Threshold ratio for accumulation/distribution classification: 1.5×.