Every mart behind these dashboards is a plain file sitting in data/, refreshed on
its own schedule by a small local Python collector and pushed to this server. Nothing here requires
a login or a client library -- every link below is a direct download, and every endpoint in the
API Reference is a plain GET request returning JSON.
Prices and volume are the one exception: they live in a compact binary ring-buffer format
(.ser) rather than a growing CSV, so a new trading day is a few hundred bytes written
in place instead of rewriting a 30+MB file. They are still fully accessible as CSV -- see
Price/Volume History below -- just generated on request instead of stored twice.
The ticker universe itself -- every symbol the other marts key off of. Adding or delisting a symbol here is what adds or removes it everywhere else.
ticker, name, sector,
industryOne row per ticker, every column the Tickers Table computes from price and
volume history -- daily/weekly/monthly moves, moving-average distance, streak, volume z-score,
and so on. This file holds only server-computed values; identity (name/sector/industry) and
yfinance fundamentals are joined in from tickers.csv/profile.csv by
api/data.php at request time, not duplicated in here. See
Column Reference below for what every one of these means.
Per-calendar-year return, one row per ticker, derived from the price history (not a separately maintained figure, so it cannot disagree with the price mart). The year columns are a rolling 10-year window and shift every January -- whatever the file's own header carries is the current window, nothing about it is hardcoded on the consuming side.
ticker, one column per year in the current window
(e.g. 2017…2025), YTD (the in-progress year),
Avg (average of the year columns present)Fundamentals pulled from yfinance's per-ticker quote summary: market cap, shares outstanding, P/E, margins, growth rates, analyst targets, and the 50/200-day moving averages the Metrics mart compares price against. Refreshed once per trading day; a symbol that fails to fetch (yfinance throttling) keeps its prior day's values rather than being blanked out.
ticker -- see the Valuation, Growth, Margins
and Analyst families in Column Reference for what each one means (the
profile mart's own field names match those keys, except 52wH/52wL
there vs. w52h/w52l in the schema).One row per calendar date, listing every ticker reporting earnings that day.
Covers several years of settled history plus a rolling ~20-trading-day forward window (scheduled
dates get revised as companies confirm them, so the forward window is re-fetched every run rather
than appended once). This is what draws the green E markers on the Price History chart and
backs the ERDate/ER table columns.
date, tickers (space-separated list of
symbols reporting that date)One row per ticker per ex-dividend date, with the per-share rate. Same settled/forward-window shape as the earnings mart. Draws the blue D markers on the Price History chart.
date, ticker, dividend
(per-share rate; may be blank if the source omitted it for that date)Every known stock split, past-only (splits are not scheduled in advance the way earnings/dividends are). Used to split-adjust volume history onto the current share basis.
ticker, date, split
(ratio -- 2 means 2-for-1)The column contract every other mart and this very page's
Column Reference section is generated from: label, family, display type,
decimals, default sort direction, and methodology text for every column the dashboards know about.
Also served through the API as api/schema.php.
Full daily closing price for every ticker, split-adjusted, newest date first.
Generated fresh from prices.ser on every request rather than stored as a file -- see
API Reference below for the limit= parameter if you only want the
most recent N sessions.
ticker, one column per trading date (newest →
oldest), close price in dollarsFull daily share volume for every ticker, newest date first, generated fresh
from volume.ser on every request. Raw share counts as reported -- split adjustment
happens at read time in the dashboards, not in this file.
ticker, one column per trading date (newest →
oldest), shares tradedGenerated live from api/schema.php -- the same source the Tickers Table's column
picker reads, so this list can never drift out of sync with what the dashboards actually show.
All endpoints below are unauthenticated GET requests returning JSON (except
export.php, which returns a CSV download), and are safe to call directly from a browser,
a script, or a spreadsheet's web-import feature. Responses are cached for 5 minutes
(Cache-Control: public, max-age=300) -- there is no hard rate limit, but this runs on
shared hosting, so a script pulling many tickers should add a small delay between calls rather than
firing them all at once.
URLs below are relative to https://finance.shrum.net/api/.
The whole ticker table in one call: every symbol in tickers.csv, joined with its
profile, metrics and year-over-year rows by ticker. This is what main.html itself
fetches on load.
?sector=, ?ticker=, etc.
on the dashboard) happens in the browser, not the server, so this always returns everything.GET /api/data.php
{
"generated": "2026-08-04T20:15:00Z",
"count": 3163,
"rows": [
{ "ticker": "AAPL", "name": "Apple Inc.", "sector": "Technology", "curr": 309.38,
"d1pct": -1.78, "marketcap": 3456789012345, "2024": 12.34, "YTD": 8.02, ... },
...
]
}
The column contract: every column's label, family, display type, decimal places, default sort
direction and methodology text. This is data/schema.json served with cache headers,
and is what this very page's Column Reference section renders.
GET /api/schema.php
{
"families": ["Identity", "Price", "Volume", "Valuation", "Growth", "Margins", "Analyst", "YoY", "Position"],
"defaults": { "cols": [...], "sort": "mapct", "order": "desc" },
"columns": [
{ "key": "d1pct", "label": "1d%", "family": "Price", "type": "percent", "dec": 2,
"sort": "desc", "origin": "server",
"method": "Percent change from the prior close to the latest close." },
...
]
}
One ticker's full price or volume history, decoded directly from the .ser ring --
this is what the Price/Volume History charts fetch on ticker selection.
ticker (required) ·
mart = prices or volume (required) ·
limit (optional) -- newest N sessions only; omit for full history
GET /api/series.php?ticker=AAPL&mart=prices&limit=5
{
"ticker": "AAPL", "mart": "prices", "scale": 100, "count": 5,
"dates": ["2026-08-04", "2026-08-03", "2026-07-31", "2026-07-30", "2026-07-29"],
"values": [309.38, 303.42, 308.91, 333.43, 338.19]
}
Dates and values are newest-first, matching the ring's own storage order.
One ticker's full earnings report history -- every date it has ever appeared in
earnings.csv, past and scheduled-future, chronological.
ticker (required)GET /api/earnings.php?ticker=AAPL
{ "ticker": "AAPL", "count": 21, "dates": ["2021-07-27", "2021-10-28", ..., "2026-07-30"] }
One ticker's full ex-dividend payment history.
ticker (required)GET /api/dividends.php?ticker=AAPL
{
"ticker": "AAPL", "count": 21,
"payments": [{ "date": "2025-08-11", "amount": 0.26 }, ..., { "date": "2026-08-10", "amount": 0.27 }]
}
The full prices or volume mart as a CSV download, generated on demand from the .ser
ring (see Price/Volume History above) -- one row per ticker, one column per
date.
mart = prices or volume (required) ·
limit (optional) -- newest N dates only; omit for full history
GET /api/export.php?mart=prices&limit=30 → prices.csv (Content-Disposition: attachment)
Appends one day's prices or volume to the live ring buffers. Requires an HMAC signature over a
secret only the local collector scripts hold -- this is how _collect_daily.py pushes
each day's close, not a public write endpoint. Listed here only for completeness.