Valuation charts
GET/api/v1/families/valuation/series
The P/E chart behind each valuation: P/E and earnings over time, the cheap-to-expensive bands, and the rating. Pro and Unlimited.
Description
Returns the chart for each requested key: P/E, earnings per share, and price over time, the percentile bands used for the rating, and the same rating and latest P/E as the valuation endpoint. Sectors, industries, and indices also list their largest members with each one’s P/E and weight. Keys are listed tickers (IBM, BRK.B), SECTOR:name, INDUSTRY:name, or INDEX:SPY, INDEX:QQQ, and INDEX:DIA for the S&P 500, Nasdaq-100, and Dow Jones. Sector and industry names follow the current classification (for example SECTOR:consumer-discretionary, SECTOR:consumer-staples, SECTOR:communication, SECTOR:finance, INDUSTRY:software-infrastructure). Earlier sector keys still work: SECTOR:consumer-cyclical, SECTOR:consumer-defensive, SECTOR:communication-services, SECTOR:financial-services, and SECTOR:telecommunications return the current sector. Earlier industry keys work where one successor holds most of the old group. The response lists each one under aliases. With asof, a sector is answered under the name that day used. Retired keys return 404 with a hint. Full table: GET /api/v1/families/us-equities/fundamentals/groups/aliases. An industry with fewer than 5 common stocks is not a peer group: its stocks are listed under the industry Others (INDUSTRY:others), keep their own ratings, and still count in their sector. INDUSTRY:others has no P/E, rating, chart, or statements of its own; it is served with available false and reason others-not-a-group, and the industry keys it replaced resolve to it (named in aliases). POST the same path with {"symbols": [...]} for up to 5,000 keys. One key: GET /api/v1/families/valuation/series/{key}. Every sector, industry, and index chart of the day: GET /api/v1/families/valuation/series/catalog, with optional kind=sector,industry,index. Charts refresh once a day.
Authentication
v1 is client_id plus client_secret on every protected GET. A browser session is not enough. Google sign-in is for the website only — do not send a session cookie to v1.
- HTTP Basic —
Authorization: Basic base64(client_id:client_secret) - Headers —
X-Client-IdandX-Client-Secret
Create or rotate credentials on Account. Full notes are on Authentication.
Path parameters
This path has no parameters.
Query parameters
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
symbols | query | string | Yes | Comma-separated keys (max 500 on GET). Keys are listed tickers (IBM, BRK.B), SECTOR:name, INDUSTRY:name, or INDEX:SPY, INDEX:QQQ, and INDEX:DIA for the S&P 500, Nasdaq-100, and Dow Jones. Sector and industry names follow the current classification (for example SECTOR:consumer-discretionary, SECTOR:consumer-staples, SECTOR:communication, SECTOR:finance, INDUSTRY:software-infrastructure). Earlier sector keys still work: SECTOR:consumer-cyclical, SECTOR:consumer-defensive, SECTOR:communication-services, SECTOR:financial-services, and SECTOR:telecommunications return the current sector. Earlier industry keys work where one successor holds most of the old group. The response lists each one under aliases. With asof, a sector is answered under the name that day used. Retired keys return 404 with a hint. Full table: GET /api/v1/families/us-equities/fundamentals/groups/aliases. An industry with fewer than 5 common stocks is not a peer group: its stocks are listed under the industry Others (INDUSTRY:others), keep their own ratings, and still count in their sector. INDUSTRY:others has no P/E, rating, chart, or statements of its own; it is served with available false and reason others-not-a-group, and the industry keys it replaced resolve to it (named in aliases). Example: IBM,SECTOR:technology. |
asof | query | string | No | Past session, YYYY-MM-DD. Omit for the latest day. |
Example request
curl -sS -u "$CLIENT_ID:$CLIENT_SECRET" \
https://barquant.dev/api/v1/families/valuation/series?symbols=INDEX:SPYResponse attributes
| Field | Type | Description |
|---|---|---|
family | string | Always valuation. |
as_of | string | null | Session the charts describe, YYYY-MM-DD. |
computed_at | string | null | When that day’s charts were produced. |
requested | string[] | Normalized keys, in request order. |
aliases | object | Older sector or industry keys you asked for, mapped to the key served in symbols. Empty when none applied. Full table: GET /api/v1/families/us-equities/fundamentals/groups/aliases. |
symbols | object | One chart per requested key, or null when the key is unknown. |
symbols[key].valuation_label | string | null | Same rating as the valuation endpoint (null when withheld). |
symbols[key].latest_pe | number | null | Same latest P/E as the valuation endpoint. |
symbols[key].verdict_status | "ok" | "withheld" | Same as the valuation endpoint. |
symbols[key].dq | object | null | Same data-quality result as the valuation endpoint: status, reasons, coverage, quarantined_members. |
symbols[key].percentiles | object | null | P/E bands p15, p25, p50, p75, and p85 behind the rating. Null when the rating is withheld. |
symbols[key].peer_group | string | null | Tickers: the INDUSTRY: key to compare the stock with. Null for a stock listed under Others (peer_group_reason others-not-a-group: there is no Others P/E or benchmark). source_industry is the original industry name. |
symbols[key].percentiles_reason | string | null | Why percentiles is null: the first failing data-quality check, else the reason the key is unavailable. Null exactly when bands are served. |
symbols[key].label_pe | number | null | Same as the valuation endpoint, with label_as_of and tip_reason. |
symbols[key].chart_data | object[] | Chart points: date, avg_pe, avg_eps, avg_price, valuation_label, projected, coverage, reporters, members_sized, verdict_status, and dq. |
symbols[key].chart_data[].projected | boolean | true on the last point, which carries today’s P/E forward. Every other point is a calendar quarter that has ended on or before as_of. |
symbols[key].chart_data[].verdict_status | "ok" | "withheld" | ok when the point carries a rating. A point is rated only when the key passed every check, its P/E is between 1 and 1,000, and (sectors, industries, indices) at least 60% of member market cap reported. |
symbols[key].chart_data[].dq | object | status and reasons for the point, for example key-withheld, no-pe, pe-out-of-bounds, insufficient-coverage, aggregate-loss (earnings per share published as a loss, no P/E), earnings-near-zero, single-reporter, earnings-yield-cap (sectors, industries, and indices: every reporting member's earnings in that quarter are at the 25% earnings-yield cap, so the P/E is the cap, not a measurement; avg_pe stays, the rating does not), or price-implausible (the stored price history of that quarter is not usable; avg_price, avg_pe, and avg_eps are null). |
symbols[key].chart_data[].members_sized | number | null | Sectors, industries, and indices: members with a known market cap at the point. Null on stocks. |
symbols[key].constituents | object[] | Sectors, industries, and indices: largest members with symbol, pe, valuation, weight, and verdict_status. valuation is that member's own rating, only when its verdict passed every check and its P/E is valid (never Neutral); on a key that keeps its previous object (see held-label-fails-gate), each chip is checked against that member's verdict of the day, so a chip loses its rating when the member's own rating is withheld today. A second share class of one company (GOOG next to GOOGL) has weight null and counted_with naming the class that carries the company's weight. |
symbols[key].coverage | object | null | Sectors, industries, and indices at the latest point: market_cap_share (reporting share of sized cap), members_cap_share (reporting share of today's member market cap), reporters, members_sized, members, not_counted_count, and not_counted (members that do not count at the tip, with the reason and weight). Null on stocks. |
symbols[key].excluded | object[] | Members left out of the aggregate with the reason; share-class-duplicate entries carry counted_with (each company is counted once). |
pending | string[] | Keys whose chart is not published yet. Retry later. |
Sample response
{
"family": "valuation",
"as_of": "2026-09-11",
"computed_at": "2026-09-12T03:04:11Z",
"requested": [
"INDEX:SPY"
],
"aliases": {},
"symbols": {
"INDEX:SPY": {
"key": "INDEX:SPY",
"kind": "index",
"name": "S&P 500",
"available": true,
"reason": null,
"valuation_label": "Very expensive",
"latest_pe": 27.4,
"latest_eps": 262,
"verdict_status": "ok",
"dq": {
"status": "ok",
"reasons": [],
"coverage": 0.99,
"quarantined_members": []
},
"percentiles": {
"p15": 20.75,
"p25": 21.7,
"p50": 24.5,
"p75": 26.75,
"p85": 27.85
},
"chart_data": [
{
"date": "2026-06-30",
"avg_pe": 29,
"avg_eps": 262,
"avg_price": 7598,
"valuation_label": "Extremely expensive",
"projected": false,
"coverage": 0.99,
"reporters": 498,
"members_sized": 503,
"verdict_status": "ok",
"dq": {
"status": "ok",
"reasons": []
}
},
{
"date": "2026-09-28",
"avg_pe": 27.4,
"avg_eps": null,
"avg_price": 7749.96,
"valuation_label": "Very expensive",
"projected": true,
"coverage": 0.99,
"reporters": 498,
"members_sized": 503,
"verdict_status": "ok",
"dq": {
"status": "ok",
"reasons": []
}
}
],
"constituents": [
{
"symbol": "NVDA",
"pe": 41.07,
"valuation": "Relatively cheap",
"weight": 0.074
},
{
"symbol": "MSFT",
"pe": 34.15,
"valuation": "Relatively expensive",
"weight": 0.066
}
]
}
},
"pending": []
}Errors
| Status | When |
|---|---|
| 400 | symbols is missing or over the key limit, or asof is not YYYY-MM-DD. |
| 401 | Missing or wrong client_id / client_secret. |
| 403 | Authenticated, but this plan does not include valuation. It starts on Pro. |
| 404 | The single-key path names a key that is not in that day’s valuation, or the catalog path names an asof day that was never published. A retired sector or industry key also carries a hint. |
| 429 | Daily quota or per-minute plan quota. Read Retry-After and X-RateLimit-* headers. |
401 body:
{
"error": "Unauthorized"
}403 body:
{
"error": "This plan does not include that family.",
"plan": "basic",
"requiredPlan": "pro"
}429 body (per-minute / daily):
{
"error": "Too many requests."
}Plan access
Pro and Unlimited. Free and Basic receive 403. Every request counts as one API request against the plan quota, however many keys it names.
Daily and per-minute quotas live on Plans and limits.
© 2026–2035 Barquant