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

DEPRECATED (Phase 69 Plan 05, since v3.23.0) — 302 redirects to `/api/v1/form-13f/fund/{cik}?include_analytics=true`.

DEPRECATED (Phase 69 Plan 05, since v3.23.0) — 302 redirects to `/api/v1/form-13f/fund/{cik}?include_analytics=true`. Use that flag on the canonical /fund/{cik} route for all new integrations. Kept live as a redirect for existing customers (e.g. the WordPress filer-proxy adapter) during their migration window.

free

Why use this

DEPRECATED. Compute the cost-basis economics of every position in a 13F filer's current book — same VWAP-of-quarterly-closes methodology, just exposed differently. New callers should use `GET /api/v1/form-13f/fund/{cik}?include_analytics=true` directly; this route now returns 302 Found with `Location: /api/v1/form-13f/fund/{cik}?include_analytics=true`. The field-by-field response shape below documents what the canonical route's decorated `holdings[]` rows look like when the flag is on. 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.

DEPRECATED (Phase 69 Plan 05, since v3.23.0). This route now returns HTTP 302 Found with Location: /api/v1/form-13f/fund/{cik}?include_analytics=true. The redirect is returned BEFORE any service call, so the deprecated route never triggers CostBasisService.compute_fund_cost_basis(cik) — no DB load on deprecated clients. HTTP clients that follow redirects (curl with -L, axios/fetch defaults, PHP's file_get_contents with follow_location=1, WordPress's wp_remote_get) will land on the canonical endpoint transparently and see the analytics fields on holdings[]. Clients that explicitly disallow redirects need to update their URL.

The softer 302 (vs the originally-planned 410 Gone) is the deployment-ordering escape valve: UAT auto-deploys on merge, so a hard 410 would degrade the live filer-profile page in the window between this PR's UAT-deploy and the WordPress-adapter cut-over. The 302 keeps the surface behavior identical for redirect-following clients until the adapter migrates to /fund/{cik}?include_analytics=true directly. The redirect is expected to remain in place for at least one release after the WordPress-adapter migration ships; clients will receive a future deprecation notice (in the API changelog) before the route is removed entirely.

The response schema below documents the per-position fields that the canonical /fund/{cik} route exposes on holdings[] rows when ?include_analytics=true is set — same shape, same units, same null cases. 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, see GET /api/v1/tickers/{ticker}/fund-trends.

Avg buy prices are VWAP estimates from quarterly snapshots, NOT actual transaction prices — meta.disclaimer (when present on the canonical endpoint's analytics decoration) 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).