Skip to content
/api/v1/form-13f/fund/{cik}/holdings-analytics

Per-holding cost-basis analytics for a fund: avg buy price, unrealized P&L, holding period, sector, and last-transaction quarter — long-equity only.

Per-holding cost-basis analytics for a fund: avg buy price, unrealized P&L, holding period, sector, and last-transaction quarter — long-equity only.

free

Why use this

Compute the cost-basis economics of every position in a 13F filer's current book. Average buy price uses VWAP of daily closing prices during each quarter of share increase (resets on full sell-out). Returns per-position `cost_basis`, `market_value`, `unrealized_pnl`, `unrealized_pnl_pct`, `holding_period_days`, `holding_period_quarters`, `first_added`, `sector` (Phase 68), `last_transaction_quarter` + `last_share_delta` (Phase 68 — most recent quarter with non-zero split-adjusted share movement). Long-equity-only by design — options are out of scope (use `/fund/{cik}?include_options=true` for the options book).

Common use case

Powering the 'Holdings' tab on `/filer/<slug>-<cik>/` — the per-filer analytics page that lists every current position with sortable columns: avg buy price, P&L %, market value, holding period, sector, last transaction. Also drives the 'Latest Trades' sort mode (sorts holdings by `last_transaction_quarter DESC`) for spotting recent portfolio activity. Replaces what would otherwise be a sequence of 12+ DAILY price queries per CUSIP from a frontend.

Returns per-holding cost-basis economics for a fund's CURRENT 13F book — the analytics drill-down behind the 'Holdings' tab on /filer/<slug>-<cik>/. Computes VWAP-estimated avg_buy_price by walking the fund's tracked-holdings history chronologically, using the mean of daily closing prices during each quarter of share increase. Cost basis resets on a full sell-out (so a buy → full exit → re-entry path will report cost basis from the re-entry, not the original buy).

Response rows surface the standard cost-basis fields (avg_buy_price, cost_basis, market_value, unrealized_pnl, unrealized_pnl_pct), holding-period telemetry (first_added, holding_period_days, holding_period_quarters), AND three Phase 68 enrichments designed for the per-filer analytics page: sector (GICS-style classification via cusip_mappings.ticker → all_stocks_list.sector with holding_info.sector fallback), last_transaction_quarter (most-recent quarter with non-zero split-adjusted share delta), and last_share_delta (signed share movement on that quarter). The last-transaction tracking is split-adjustment-aware: a 4:1 split alone does NOT register as a transaction.

Long-equity ONLY by design. Options positions (puts/calls) are excluded — for the options book on the same fund, use GET /api/v1/form-13f/fund/{cik} with ?include_options=true and filter client-side on is_option=true. For aggregated cross-fund views of a single ticker (instead of per-fund-per-ticker), see GET /api/v1/tickers/{ticker}/fund-trends which is fully split-adjusted on the aggregation surface.

Avg buy prices are VWAP estimates from quarterly snapshots, NOT actual transaction prices — meta.disclaimer surfaces this verbatim and should be displayed on any UI that exposes avg_buy_price or unrealized_pnl_pct. All monetary amounts are in USD (post-Plan-51 thousands-vs-actual normalization). Share counts are split-adjusted (Phase 52) before cost-basis and last-transaction tracking.

Parameters

NameInRequiredDefaultAllowedDescriptionExample
cikpathrequiredFund CIK in 10-char zero-padded form (e.g. `0001067983` for Berkshire Hathaway, `0001364742` for BlackRock, `0000884144` for Vanguard, `0001037389` for Renaissance Technologies). Server-side normalization handles 6/7/10-char input forms.0001067983
sort_byqueryoptionalmarket_valueSort key for `holdings[]`. Allowed values: `market_value`, `unrealized_pnl_pct`, `holding_period_days`, `avg_buy_price`, `cost_basis`. Returns 400 INVALID_PARAM on any other value. Use `holding_period_days` for a 'longest-held positions' view; `unrealized_pnl_pct` for a 'biggest gainers/losers' view.
orderqueryoptionaldescSort order: `desc` (default) or `asc`. Combined with `sort_by` — e.g. `sort_by=unrealized_pnl_pct&order=asc` surfaces the worst-performing positions first.

Response schema

FieldTypeNullableDescription
cikstringno10-char zero-padded fund CIK echoed back from the request.
holdings_countintegernoNumber of current positions in the response (positions with `final_shares > 0` after the chronological cost-basis walk). Excludes positions that have been fully sold out — those reset cost basis on sell-out and are not surfaced as 'current' holdings.
summaryobjectnoPortfolio-level rollups: `{ total_cost_basis, total_market_value, total_unrealized_pnl, total_unrealized_pnl_pct, avg_holding_period_days }`. All USD; null when current prices are unavailable.
summary.total_cost_basisnumberyesSum of `holdings[].cost_basis` across the portfolio. Reflects the cumulative VWAP-estimated dollar amount the fund has put to work in current positions. Null when no holdings have a computed cost basis.
summary.total_market_valuenumberyesSum of `holdings[].market_value` across the portfolio (using each position's most recent close × split-adjusted shares). USD. Null when current prices are unavailable for all holdings.
summary.total_unrealized_pnlnumberyes`total_market_value - total_cost_basis`. Positive = portfolio in the money on a cost basis; negative = portfolio underwater. Excludes any realized P&L from sold positions (those reset on sell-out).
summary.total_unrealized_pnl_pctnumberyes`(total_unrealized_pnl / total_cost_basis) × 100`. Portfolio-wide unrealized return percentage on cost basis. Null when `total_cost_basis` is null or zero.
summary.avg_holding_period_daysintegeryesMean of `holdings[].holding_period_days` across positions with a populated value. Useful as a 'patience proxy' — Berkshire-style books show 1500+ days; quant books show 90-180 days.
holdingsarraynoPer-position rows sorted by `sort_by` / `order`. Each row carries cost-basis economics, holding period, and (Phase 68) sector + last-transaction enrichment. Long-equity only — options are excluded by design (use `/fund/{cik}?include_options=true` for the options book).
holdings[].cusipstringno9-char CUSIP — natural primary key for the position. Apple's canonical CUSIP is `037833100`.
holdings[].tickerstringyesResolved ticker via `cusip_mappings`. Null for unmapped CUSIPs (~3% in steady state). Multi-class issuers preserve the actual filed class (e.g. `BRK-A` vs `BRK-B`).
holdings[].namestringnoIssuer name as filed (typically all-caps EDGAR convention, e.g. `APPLE INC`). Falls back to the CUSIP itself when no name is available.
holdings[].sharesintegernoCurrent split-adjusted share count (final position size after the chronological walk). Phase 52 split-adjustment is honored — a 4:1 split is reflected in this number, not just in `last_share_delta`.
holdings[].avg_buy_pricenumberyesVWAP-estimated average buy price across all share-increase quarters in this position's history. Computed using the mean daily closing price during each quarter of share increase. Resets on full sell-out. NOT actual transaction prices — surfaced verbatim in `meta.disclaimer`. Null when the fund has held the position with zero shares throughout the window.
holdings[].current_pricenumberyesMost-recent close price for the resolved ticker. Null when the ticker is unmapped or the price feed is missing recent data (e.g. delisted issuers).
holdings[].cost_basisnumberyes`avg_buy_price × final_shares` (USD). The total dollar amount the fund has put to work in this position on a VWAP-estimated basis. Null when `avg_buy_price` is null.
holdings[].market_valuenumberyes`current_price × final_shares` (USD). Position size at most-recent close. Null when `current_price` or `avg_buy_price` is unavailable.
holdings[].unrealized_pnlnumberyes`market_value - cost_basis` (USD). Positive = position in the money; negative = position underwater. Null when `market_value` is null.
holdings[].unrealized_pnl_pctnumberyes`(current_price / avg_buy_price - 1) × 100`. Unrealized return percentage on the position. Null when `avg_buy_price` is null or zero. Use as the sort key for a 'biggest gainers/losers' table view.
holdings[].holding_period_daysintegeryesDays from `first_added` (the first quarter the fund acquired any shares) to the latest quarter in the response. Null when the position has been held with zero shares throughout the window.
holdings[].holding_period_quartersintegeryesNumber of quarterly 13F-HR snapshots in which the fund reported a non-zero share count for this position since `first_added`. Diverges from `holding_period_days / 90` when the fund had a temporary full sell-out and re-entered.
holdings[].first_addedstringyesISO `YYYY-MM-DD` quarter-end date of the first 13F filing in which the fund reported any shares of this CUSIP. Survives across temporary sell-outs (the chronological walk resets cost basis but not `first_added`).
holdings[].sectorstringyesPhase 68 enrichment: GICS-style sector for the holding. Resolution priority: (1) `cusip_mappings.ticker` → `all_stocks_list.sector` (canonical, Phase 53 hyphen-normalized); (2) `holding_info.sector` fallback (excluding the literal `'Equity'` which is not a real sector). Null for un-mapped CUSIPs and for CUSIPs whose all_stocks_list row has a null/empty sector. Use to populate a Sector column + Industry filter dropdown on per-filer Holdings tables.
holdings[].last_transaction_quarterstringyesPhase 68 enrichment: ISO `YYYY-MM-DD` quarter-end date of the most-recent quarter where the fund's split-adjusted share count CHANGED (non-zero delta). Tracked AFTER split-adjustment, so a 4:1 stock split alone does NOT register as a transaction (delta == 0 post-adjustment) — real buys/sells layered on top of a split quarter still register correctly. Null for positions that have been static since `first_added`. Powers the 'Latest Trades' sort mode on `/filer/<slug>-<cik>/`.
holdings[].last_share_deltaintegernoPhase 68 enrichment: signed split-adjusted share movement on `last_transaction_quarter`. Positive = added shares; negative = trimmed shares; 0 = position has been static since `first_added` (in which case `last_transaction_quarter` is null). Use the magnitude to surface the size of the most recent activity ('Berkshire trimmed AAPL by 100M shares in Q3 2025').
meta.sort_bystringnoEchoed-back sort key from the request.
meta.orderstringnoEchoed-back sort order from the request.
meta.disclaimerstringnoCost-basis estimation disclaimer surfaced verbatim: average buy prices are VWAP estimates of daily closing prices during the quarter of each share increase, NOT actual transaction prices. Display this on any UI that surfaces `avg_buy_price` or `unrealized_pnl_pct` to set user expectations correctly.

Sample response

·
  • "cik": "0001067983"
  • "holdings_count": 47
  • "summary":
    • "total_cost_basis": 130000000000
    • "total_market_value": 308000000000
    • "total_unrealized_pnl": 178000000000
    • "total_unrealized_pnl_pct": 136.92
    • "avg_holding_period_days": 1842
    }
  • "holdings":
    ]
  • "meta":
    • "sort_by": "market_value"
    • "order": "desc"
    • "disclaimer": "Average buy prices are estimated from quarterly 13F filings using VWAP of daily closing prices during the reported quarter. Not actual transaction prices."
    }
}

Errors

StatusLabelDescription
200OKRequest succeeded.
400Bad RequestInvalid query, body, or path parameter.
401UnauthorizedMissing or invalid Authorization header / api_Token.
402Payment RequiredInsufficient token balance for this call. Top up
429Too Many RequestsRate limit exceeded for your tier (see /pricing for tier limits). Tier limits
500Server ErrorUnexpected server-side failure. Retry with backoff; report if persistent.

Code samples

curl "https://api.finradar.ai/api/v1/form-13f/fund/{cik}/holdings-analytics" \
  -H "Authorization: Bearer YOUR_JWT_TOKEN"

Generate an API key in /account/credentials to run live queries (literal YOUR_API_KEY placeholder shown until then).