data_updater_v2.data_clients.general
GeneralClient — the sources that are neither FMP nor EODHD: Bitstamp (crypto,
exchange-direct), OpenFIGI (identifiers), Nasdaq and Nasdaq Trader (its listings’ own
record), Coin Metrics (a coin’s supply, valuation, network and exchange metrics), FINRA (the
listed short interest and the daily short-sale volume), IB’s shortable file (the borrow fee
and the shares available, today) with the history companiesmarketcap republishes of it, and
the NYSE calendar from pandas_market_calendars (mcal). EODHD is EODHDClient
(eodhd.py), its own; the DataClient combines all three.
Its sections match FMPClient’s names and parameters so the DataClient combines them one to one:
2 · UNIVERSE cryptos() — Bitstamp's USD pairs · figis() / coin_figis() — OpenFIGI ids3 · CALENDAR sessions() · closures() (mcal; no HTTP) · nyse_calendar()4 · PRICES daily() / intraday() — Bitstamp, for the pairs it lists5 · CORPORATE ACTIONS nasdaq_dividends() / nasdaq_dividends_calendar() / nasdaq_splits_calendar() — Nasdaq's own record · nasdaq_events() / nasdaq_today() — Nasdaq Trader's listings, delistings, renames7 · METRICS coin_catalog() · coin_metrics(table) · coin_metric_definitions() — Coin Metrics' community API, the four tables, built or updated · short_interest() / short_interest_dates() / short_volume() — FINRA · ib_shortable() — IB's file, today · borrow_slugs() / borrow_history() — companiesmarketcap, IB's numbers since 2023The HTTP vendors sit underneath, each a BaseClient of its own (one base URL, one quota);
Nasdaq’s facts are on NasdaqClient, FINRA’s, IB’s and companiesmarketcap’s on their
blocks below:
BitstampClient https://www.bitstamp.net/api/v2/, public, no key (live-verified by
nc-feeds 2026-08-10). ohlc/{pair}/?step&limit&start&end: at most 1,000 bars a call;
with both start and end the server anchors to the END (the last <= 1,000 bars up
to end), so a window exactly 1,000 bars wide comes back whole, and a narrower one or
a sparse era returns bars from BEFORE its start — every walk is clipped to its ask
(seen live 2026-10-03: 120 bars before the start). Bars are stamped at their START in
UTC epoch seconds; volume is in COINS of the base currency (BTC for btcusd: ~1,900 a
day on this one venue), served as strings. History from 2011-08-18 (BTC’s first print).
Rates: no published limit; nc-feeds’ guidance is ~8,000 calls per 10 minutes.
CoinMetricsClient https://community-api.coinmetrics.io/v4/, public, no key: the facts
sit on the COIN METRICS block below (routes, paging, the 403 on a metric an asset does
not carry, the completion stamp, the flash status, 6,000 calls a 20-second window).
OpenFIGIClient https://api.openfigi.com/v3/mapping, POST a JSON list of jobs, one
answer per job in order. Without a key: 25 requests a minute (ratelimit-* headers),
10 jobs a request; a key (header X-OPENFIGI-APIKEY) raises it to 250 a minute and
100 jobs (ratelimit-policy: 250;w=60, probed 2026-10-05). Probed 2026-10-04: a share
class is spelled with a SLASH (BRK/B;
BRK-B and BRK.B find nothing); an ISIN or CUSIP returns every US venue record
(US = the composite, UA/UC/… the venues), so the composite is kept; a dead
ticker (KOL) is found only with includeUnlistedEquities; there is no CIK id type.
Classes
BitstampClient
Bases: BaseClient
Bitstamp’s public market-data API. Carried state: the base’s only.
fetch_bars
fetch_bars(pair: str, interval: str, start: dt.datetime, end: dt.datetime) -> RawResponseOne pair’s bars of one width whose START lies in [start, end] (aware instants), as Bitstamp serves them (timestamp, OHLC and coin volume as strings), oldest first, clipped to the ask.
fetch_currencies
fetch_currencies() -> RawResponseBitstamp’s currency catalog: name, type (crypto / fiat), decimals, networks.
fetch_pairs
fetch_pairs() -> RawResponseEvery pair Bitstamp lists (~300): name (BTC/USD), url_symbol (btcusd),
description, trading (Enabled/Disabled), decimals, minimum order.
CoinMetricsClient
Bases: BaseClient
Coin Metrics’ community API. Carried state: the base’s only.
fetch_catalog
fetch_catalog(assets: Sequence[str]) -> RawResponseThe catalog of the asked assets as served: each asset’s metrics and frequencies.
fetch_metrics
fetch_metrics(assets: Sequence[str], metrics: Sequence[str], start: dt.date | None = None, end: dt.date | None = None) -> RawResponseThe daily rows of many assets and metrics in one walk, as served ({asset, time, <metric>: "number", <metric>-status ...}), every page.
fetch_reference
fetch_reference(metrics: Sequence[str] | None = None) -> RawResponseThe metric definitions as served, all of them or the asked ones.
CompaniesMarketCapClient
Bases: BaseClient
companiesmarketcap.com’s pages. Carried state: the base’s only.
fetch_borrow
fetch_borrow(slug: str) -> RawResponseOne company’s cost-to-borrow page as served (HTML); no such company: 404, empty.
fetch_page
fetch_page(n: int) -> RawResponseOne ranking page as served (HTML); a page past the last is 404: empty.
FinraBearer
Bases: BearerAuthenticator
common-auth’s bearer with FINRA’s token admitted: the token FINRA mints carries *
(2,331 characters, 2026-10-19), which the RFC 6750 grammar the package enforces refuses,
so the one check is widened to the header’s token characters (RFC 7230) here; validity
(not before, expiry) and the token type are checked as the package checks them. A gap
to close in common-auth, named here until it is.
FinraClient
Bases: BaseClient
FINRA’s Query API. Carried state: the base’s only (the bearer, when one is handed in, is the authenticator’s).
fetch_data
fetch_data(dataset: tuple[str, str], start: dt.date | None = None, end: dt.date | None = None, offset: int = 0, limit: int | None = None, fields: Sequence[str] | None = None, equal: Mapping[str, str] | None = None, date_field: str = 'settlementDate') -> RawResponseOne page of one dataset as served (a JSON list of rows; a window with nothing
answers 204: ok, no rows): start / end as a dateRangeFilter on
date_field, equal as compareFilters, fields the columns asked.
fetch_partitions
fetch_partitions(dataset: tuple[str, str]) -> RawResponseOne dataset’s partitions document as served.
FinraFilesClient
Bases: BaseClient
FINRA’s Reg SHO daily files on its CDN. Carried state: the base’s only.
fetch_short_volume
fetch_short_volume(day: dt.date) -> RawResponseOne day’s consolidated NMS short-sale volume file as served (text).
GeneralClient
Bitstamp, NYSE, Nasdaq, Nasdaq Trader, OpenFIGI, Coin Metrics, FINRA, IB’s file,
companiesmarketcap and mcal behind FMPClient’s section names (EODHD is EODHDClient,
its own):
2 · UNIVERSE cryptos() · coin_figis() · figis()3 · CALENDAR sessions() · nyse_calendar() (mcal, the NYSE page)4 · PRICES daily() · intraday() (Bitstamp)5 · CORPORATE ACTIONS nasdaq_events() · nasdaq_dividends() · the Nasdaq calendars7 · METRICS coin_catalog() · coin_metrics(table) · coin_metric_definitions() (Coin Metrics: the four tables, built or updated) · short_interest() · short_interest_dates() · short_volume() (FINRA) · ib_shortable() (IB's file) · borrow_slugs() · borrow_history() (companiesmarketcap)Carried state: the nine vendor clients it OWNS (built from the borrowed limiter it is handed, or given ready-made) and closes; the mcal NYSE calendar object. Nothing about any call is kept.
aclose
aclose() -> Noneaopen
aopen() -> GeneralClientborrow_history
borrow_history(symbols: str | Iterable[str], start: dt.date | None = None, end: dt.date | None = None, slugs: Mapping[str, Mapping[str, Any]] | None = None) -> dict[str, RawResponse]IB’s borrow fee and shares available per day as companiesmarketcap republishes
them, our symbol -> answer with rows {symbol, date, borrow_fee (annual fraction: 25 bps -> 0.0025), shortable_shares} oldest first, one row a day (the day’s last
reading, UTC) in [start, end] (None: from BORROW_FLOOR; None: today). One page a
symbol, CONCURRENCY at a time; slugs (borrow_slugs; read here when not
handed in) says the page. A symbol the site does not rank, or whose page carries no
borrow data (Berkshire), answers ok and empty with the reason named; a failed page
comes back as it is.
borrow_slugs
borrow_slugs() -> dict[str, dict[str, Any]]The site’s slug for every company it ranks, symbol (as the site spells it: BRK-B
as we do; a foreign one with its suffix, 2222.SR) -> {slug, name}: its ranking pages
read one after another until one is past the last (114 pages of 100 on 2026-10-19,
about two minutes at the declared pace). FetchError on a failed page (a catalog:
no holes).
closures
closures(start: dt.date, end: dt.date) -> list[dict[str, Any]]The NYSE’s weekday closures and shortened weekday sessions in [start, end], oldest first: date, is_closed, open_et / close_et (the shortened session’s wall-clock times; None for a closure). Saturdays are sessions of their own, never holidays.
coin_catalog
coin_catalog(symbols: str | Iterable[str]) -> dict[str, dict[str, dict[str, Any]]]Each coin’s daily metrics on the community tier, our symbol -> {metric: {first,
last}} (the first and last day served); a coin Coin Metrics does not know is absent.
One call per COINS_PER_CALL coins. FetchError when a catalog call fails (a
catalog: no holes).
coin_figis
coin_figis(bases: Iterable[str] | None = None) -> list[dict[str, Any]]OpenFIGI’s coin records (securityType2 CRYPTO; the pairs it calls CROSS and
FORWARD left out): figi, ticker (the coin’s code on its “Crypto” records, Bloomberg’s
on its 47 SPOT ones: XBT for bitcoin), name. bases None: every one (the
filter list, ~4 minutes); else only those its mapping finds under each code (one
job each, 100 a request keyed). A code is not a coin: OpenFIGI’s TIA is Tianhe, not
Celestia; BB is BlackBerry’s — the caller matches on the name too.
coin_metric_definitions
coin_metric_definitions(metrics: Iterable[str] | None = None) -> list[dict[str, Any]]Coin Metrics’ own definitions of its metrics (metric, full_name, description,
category, unit, data_type), all of them or the asked ones; FetchError on a
failed call.
coin_metrics
coin_metrics(symbols: str | Iterable[str], table: str, start: dt.date | None = None, end: dt.date | None = None, catalog: Mapping[str, Mapping[str, Mapping[str, Any]]] | None = None) -> dict[str, RawResponse]One table’s days per coin (COIN_TABLES: supply, valuation, network, exchange),
our symbol -> answer with rows {symbol, date, <column>..., complete, final}
oldest first, values as floats (None where the day carries none). complete is
Coin Metrics’ own word that the day’s end-of-day values were all computed
(COIN_COMPLETE, set 01:30-04:10 UTC the following day; None for an asset without
the stamp, the ones with no node); final is False while any value carries the
flash status — the exchange flows keep it for days (btc’s of 10-15 still flash on
10-19), so a flash value is a provisional number to land and replace, never one to
wait for. start None is the whole history (COIN_FLOOR; the API serves from each
metric’s first day), end None yesterday UTC, the last complete day: the build and
the update are this one verb windowed, and an update re-asking the last days replaces
what was provisional. The catalog
(coin_catalog; read here when not handed in) says which of the table’s metrics
each coin carries: coins are grouped by that set and asked together, COINS_PER_CALL
a call, so no call names a metric an asset lacks (a 403 on the whole call); a coin
carrying none of the table’s metrics answers ok and empty, the reason named; a day
served with no value at all drops by reason. A coin Coin Metrics does not know is a
failed answer only when asked alone; grouped, it is absent from the catalog and so
asked for nothing.
cryptos
cryptos(trading_only: bool = False) -> list[dict[str, Any]]Bitstamp’s crypto/USD pairs: name ending /USD whose base is a CRYPTO
currency in Bitstamp’s own catalog (EUR/USD, GBP/USD… are fiat pairs and dropped),
each with symbol added in FMP’s spelling (BTCUSD) so the catalogs join and the
base currency’s catalog row as currency; disabled pairs kept unless
trading_only.
daily
daily(symbols: str | Symbols, start: dt.date | None = None, end: dt.date | None = None) -> RawResponse | dict[str, RawResponse]Bitstamp’s daily candles (UTC days), one pair or many, oldest first, finished days
only (bars.settled). start None = Bitstamp’s first day; end None = today.
Coin volume served, dollars = coins x the day’s typical price (Bitstamp has no daily
VWAP); a candle with no coins traded is no bar (named).
figis
figis(listings: Iterable[Mapping[str, Any]], unlisted: bool = False) -> dict[str, list[dict[str, Any]]]OpenFIGI’s US-composite records for catalog rows (symbol, plus isin /
cusip / figi when known): symbol -> the records (figi, compositeFIGI,
shareClassFIGI, ticker, name, securityType, securityType2, marketSector, exchCode);
unlisted for delisted eras (figi_jobs).
Each row is asked by its surest id first and by the next only while nothing is found
(figi_jobs), one batch per step over the rows still empty. A figi from FMP’s
sec-profile is the ISSUER’s for notes and preferreds (STRC, STRD -> MicroStrategy’s
common; SOJC -> Southern’s; probed 2026-10-05), so what it finds counts only under the
row’s own ticker. Each record also says what it IS (papers.openfigi_kind):
asset_class, security_type, refused. An empty list = OpenFIGI found
nothing. A failed request raises FetchError (ids are a catalog: no holes).
ib_shortable
ib_shortable(country: str = 'usa') -> dict[str, Any]IB’s shortable file for one country read (_ib_file): as_of (the file’s
day) and time, declared (the trailer’s count, checked against the rows:
ValueError when they differ), rows — one per USD line, in our shape: symbol
(ours: papers.spell_ib), symbol_as_told, date, name, conid, isin (as IB masks it),
figi, borrow_fee and rebate_rate (annual FRACTIONS: 0.2782% -> 0.002782; None for
IB’s NA), shortable_shares (IB_AVAILABLE_CAP for “>10000000”, capped True) —
and dropped: a line in another currency, a spelling that is no US ticker (a dead
era’s .OLD marker, a bond’s CUSIP), named. The DataClient lands the fee and the
shares (the rebate is told, not stored).
intraday
intraday(symbols: str | Symbols, start: dt.date | None = None, end: dt.date | None = None, interval: Interval = '1min') -> RawResponse | dict[str, RawResponse]Bitstamp’s intraday bars of the UTC days [start, end], one pair or many, oldest
first, in the common shape, every width; coins served, dollars = coins x the bar’s
typical price. start None = INTRADAY_FLOOR; end None = today.
nasdaq_dividends
nasdaq_dividends(symbols: str | Symbols, start: dt.date | None = None, end: dt.date | None = None, asset: Asset) -> RawResponse | dict[str, RawResponse]Nasdaq listings’ dividend histories (asset etf or equity), oldest first, in the
common shape: the payouts with cash (Cash, and Cash/Stock beside a stock
dividend: CBSH’s December 0.27), amount as paid, period ‘unknown’ (Nasdaq names none),
currency as stated. A symbol Nasdaq does not list comes back failed, named.
start / end bound the ex-dates.
nasdaq_dividends_calendar
nasdaq_dividends_calendar(start: dt.date, end: dt.date) -> RawResponseEvery dividend Nasdaq’s calendar lists with its ex-date in [start, end] (its own
listings), one call per calendar day, in the common shape; a future day lists what is
announced. Symbols in our spelling (BRK.B -> BRK-B).
nasdaq_events
nasdaq_events(start: dt.date, end: dt.date) -> RawResponseNasdaq’s own listing events dated in [start, end] (its status history: Nasdaq
listings only, from 2024-01-01 — an earlier start is clipped), every page, oldest
first: symbol (ours), date, name, event (NASDAQ_EVENTS: listed, delisted,
suspended, listing_expected, delisting_expected, renamed — that one names no old or
new ticker —, else Nasdaq’s words, lower-cased: financial status changes, market
class changes; 617 events 2026-09-01..10-09). A row it cannot read is dropped, named.
The pages are asked one at a time (the client’s quota paces them: Nasdaq’s site
serves about a dozen, then rests); a page that comes back blank is asked again after
a wait (_nasdaq_status_page). A failed page fails the answer.
nasdaq_splits_calendar
nasdaq_splits_calendar(since: dt.date | None = None) -> RawResponseEvery split Nasdaq’s calendar lists — every US venue, not its listings only — in
splits’ shape: symbol (ours: BRK.B -> BRK-B), date (the effective day),
split_to / split_from, split_type None. It reaches back about six months whatever
since says (probed 2026-10-08: since 2020-01-01 answered from 2026-04-08)
and lists announced splits weeks ahead. Ratios are to : from (“3 : 1” forward,
“1 : 10” reverse) or a stock dividend “2%” (102 for 100); a row it cannot read is
dropped, named. Its ratio is not the authority: on CDT 2026-09-29 it said 1:10 where
the price moved 25x, as FMP and EODHD had it (DataClient judges on the price).
nasdaq_today
nasdaq_today() -> RawResponseToday’s adds and deletes on Nasdaq’s trading systems, every primary market (its newest day only): symbol (ours), date, name, event (listed / delisted), market (Nasdaq’s code of the primary listing market: Q Nasdaq, N NYSE, P NYSE Arca, A NYSE American, Z Cboe BZX …). A failed answer comes back as it is.
nyse_calendar
nyse_calendar() -> dict[str, Any]NYSE’s own announced calendar (nyse_calendar): the years it covers, its
closures and its early closes. FetchError when the page does not come back,
ValueError when it cannot be read whole.
sessions
sessions(start: dt.date, end: dt.date) -> list[dict[str, Any]]Every NYSE session in [start, end], Saturdays included (the NYSE traded them until 1952): date, open/close as UTC instants and on the US/Eastern wall clock, and whether it is shortened (half day) against ITS era’s regular hours — mcal’s own early closes and late opens (10:00-15:00 until 1952, 15:30 until 1974, 9:30 from 1985), so a 1960 session closing 15:30 is a full day, and so is a Saturday’s 10:00-12:00 (its regular hours).
short_interest
short_interest(symbols: Iterable[str] | None = None, start: dt.date | None = None, end: dt.date | None = None) -> RawResponseFINRA’s consolidated short interest settled in [start, end] (None: from
SHORT_INTEREST_FLOOR; None: today), every venue, oldest first, in our shape:
symbol (ours: papers.spell_finra reads the glued ABRPRD as ABR-PD, BRKB
on the NYSE as BRK-B), symbol_as_told, date (the settlement date), short_interest
(shares), previous_short_interest, change, change_percent, average_daily_volume,
days_to_cover, market_class (FINRA’s code), name, split, revised. symbols keeps
those of ours (every symbol otherwise: 22,581 a settlement date). Asked a calendar
month at a time, every page (5,000 rows; two settlement dates a month run to nine
pages); a spelling that is no US ticker is dropped, named (one in 22,581: a
when-issued right). A failed page comes back as it is.
short_interest_dates
short_interest_dates() -> list[dt.date]The settlement dates FINRA serves short interest for, oldest first (the
partitions: a new one is the update’s signal). FetchError on a failed call.
short_volume
short_volume(start: dt.date, end: dt.date | None = None) -> RawResponseFINRA’s consolidated daily short-sale volume for the weekdays in [start, end]
(None: start alone), one file a day (SHORT_VOLUME_FLOOR), oldest first, in
our shape: symbol (ours), symbol_as_told, date, short_volume, short_exempt_volume,
total_volume (shares, fractional as FINRA serves them), markets (the venues the
volume printed on: B, Q, N). A day with no file (a holiday; today before the file
is cut) is noted in dropped, never a failure; a file whose trailer count differs
from its rows fails the answer; a failed call comes back as it is.
IBFilesClient
IB’s public shortable files over FTP (no HTTP: ftplib in a worker thread).
Carried state: none; fetcher is handed in for tests (a callable from a file name to
its bytes).
fetch_countries
fetch_countries() -> list[str]The countries IB publishes a file for (usa, canada …).
fetch_shortable
fetch_shortable(country: str = 'usa') -> strOne country’s file as served (text).
NYSEClient
Bases: BaseClient
NYSE’s hours-and-calendars page: the exchange’s own announced holidays and early closes (three years ahead). Carried state: the base’s only.
NasdaqClient
Bases: BaseClient
Nasdaq’s public quote API (api.nasdaq.com): the exchange’s own dividend record for
the securities it lists. Keyless; it answers only a browser’s headers. Probed 2026-10-07:
amounts are cash AS PAID (AAPL 2020-08-07 $0.82, before its 4:1); only Nasdaq listings
are carried (SPY, KO: an empty answer; BRK-B: “Symbol not exists”); the daily
calendar lists that day’s ex-dates for its listings, and had same-day ETF payouts (CEPI,
FEPI, MST on 10-07) before FMP and EODHD did. Carried state: the base’s only.
fetch_dividends
fetch_dividends(symbol: str, assetclass: str) -> RawResponseOne listing’s dividend record as served (assetclass etf or stocks).
fetch_dividends_calendar
fetch_dividends_calendar(day: str) -> RawResponseOne day’s ex-dates as served (YYYY-MM-DD).
fetch_splits_calendar
fetch_splits_calendar(since: str) -> RawResponseEvery split Nasdaq’s calendar lists from since (an ISO day) on, as served.
NasdaqTraderClient
Bases: BaseClient
Nasdaq Trader (www.nasdaqtrader.com): the exchange’s own record of what it lists
and stops listing. Keyless, a browser’s headers. Probed 2026-10-10:
Trader.aspx?id=nasdaq-security-status-updates&from=MM/DD/YYYY&to=MM/DD/YYYY[&page=N] an HTML table, dated, Nasdaq listings only, from 2024-01-01: Effective Date, Symbol, Company Name, Issue Event (Security Additions, Security Deletions, Anticipated Security Additions / Deletions, Name/Symbol Changes — with no old or new ticker —, Financial Status Changes …), and the financial statuses; pages linked beneath it (~50 rows each) dynamic/SymDir/TradingSystemAddsDeletes.txt today’s adds and deletes on Nasdaq’s three trading systems, every primary market (Symbol|Company Name|NASDAQ Action|BX Action|PSX Action|Effective Date|Primary Listing Market): the newest day only, no history
Carried state: the base’s only.
OpenFIGIClient
Bases: BaseClient
OpenFIGI’s mapping API: keyless unless the flow hands in an authenticator for its
key (AUTH), which raises both the quota and the jobs a request carries. Carried
state: the base’s only (jobs_per_request reads whether a key was handed in).
filter_all
filter_all(body: Mapping[str, Any]) -> list[dict[str, Any]]Every record OpenFIGI’s filter holds for body (e.g. every coin:
{“marketSecDes”: “Curncy”, “securityType2”: “CRYPTO”} — 8,168 on 2026-10-10, 82 pages
of 100), page after page by its next cursor, spaced to FILTER_PER_MINUTE
(the quota paces mapping’s 25 or 250 a minute, not filter’s 20). A failed page
raises FetchError (a catalog: no holes).
map_jobs
map_jobs(jobs: list[dict[str, Any]]) -> list[RawResponse]Map OpenFIGI jobs ({"idType": ..., "idValue": ..., "exchCode": ...}), sent
jobs_per_request at a time as one common-http batch. One response per REQUEST:
its rows are the per-job answers in job order ({"data": [...]}, or
{"warning": "No identifier found."}, or {"error": ...}).
Functions
figi_jobs
figi_jobs(listing: Mapping[str, Any], unlisted: bool = False) -> list[dict[str, Any]]The OpenFIGI jobs for one catalog row, surest first — each asked only when the ones
before it found nothing: its ISIN, its CUSIP, its ticker on the US composite (LISTED
instruments only), and a FIGI handed in as figi (FMP’s sec-profile
openFigiComposite). The ticker is always asked when the ids find nothing: a reissued
ISIN can be missing from OpenFIGI (CPOP after its reverse split, 2026-10-05). Unlisted
instruments are asked for only with unlisted (a delisted era: a dead ticker is found
only with includeUnlistedEquities): for an active listing that flag would also return
every dead instrument that once carried the ticker (89 of 5,725 active equities on
2026-10-05: WBD -> Wimm-Bill-Dann’s ADR beside Warner Bros. Discovery, NXT -> an ETF).
figi_ticker
figi_ticker(symbol: str) -> strA share class in Bloomberg’s spelling, which OpenFIGI requires (BRK/B found;
BRK-B and BRK.B not, probed): a one-letter class after a dash (everyone’s,
FMP’s), a dot (FMP lines that kept Nasdaq’s), or already a slash. Anything else is
passed as it is (the equity universe holds common stock only: no preferreds here).
nasdaq_adds_deletes
nasdaq_adds_deletes(text: str) -> list[dict[str, str]]Nasdaq’s adds-and-deletes file as rows (its header’s columns). ValueError when the
header is not the one expected.
nasdaq_page_blank
nasdaq_page_blank(page: str) -> boolWhether a status page came back without its results grid at all — Nasdaq’s throttle (a 212-byte blank under a 200), never a page with no events: that one still carries the grid.
nasdaq_status_page
nasdaq_status_page(page: str) -> tuple[list[dict[str, str]], int]One page of Nasdaq Trader’s status history: its rows (the header’s columns) and the
last page it links to. ValueError when the table is not the one expected.
nyse_calendar
nyse_calendar(page: str) -> dict[str, Any]NYSE’s announced calendar from its hours-and-calendars page (the holiday table it
embeds as JSON cells, and the early closes it states in footnotes): years it covers,
closed {date: holiday name}, early {date: close time, ET}. A year whose cell is a
dash observes no such holiday (2028: New Year’s Day falls on a Saturday). Raises
ValueError when the page cannot be read whole (a missing year header, a holiday row,
a cell without a date, no early close) — never a partial calendar.