Skip to content

data_updater_v2.jobs.events

events.py — the corporate actions, one class a table: Splits and Dividends; and EventChecks, the filers’ own word on both, weekly.

splits_build / dividends_build by hand: every active ETF's and equity's whole record
from every source, a family at a time in batches,
each batch written before the next is fetched
splits_update / dividends_update once the day's listed bars have landed: the window
(``lookback_days`` back through today, ``ahead_days``
ahead) from every source's calendar, EODHD's files
through today only, combined, the window made exact
splits_repair / dividends_repair 02:00-04:00 New York while an issue is open: the
window again, then the listings left to retry
build_splits (one step: fetch and write a batch at a time)
fetch_split_window ─▶ write_split_window
retry_splits
events_sec_check Sundays 22:00 New York: every equity the SEC holds
(a CIK), its filed dividends per share against our
payouts by fiscal quarter, its filed split ratios
against our splits — ``sec_disagrees`` (a quarter
whose payouts do not sum to what the filer declared)
and ``sec_only`` (a split the filer reported that we
lack) opened as notices for a person, closed when the
next check no longer finds them

Sources: FMP (per-listing history and its five-year calendar on a build; its split and dividend calendars on an update), EODHD (per-listing history; its split and dividend bulks, one call a calendar day, on an update), Nasdaq (its calendars: the exchange’s own record for its listings). A split the sources tell differently is judged by the listing’s raw daily bars (daily=); a dividend’s cash is settled by Nasdaq where it lists the name.

The write law: a complete answer makes its window exact — reconcile over the listings answered for by the window, a cancelled announcement archived. A calendar that did not answer means the night writes upsert only (nothing retired) and opens an unread issue on the table; the repair re-sweeps the window. The window is the safety net: every night asks the last lookback_days again, so a late or corrected line, or a missed night, lands the next pass. Stored splits against the fetched → split_changed issues, the daily job’s refill.

Classes

Dividends

Bases: DataJob

The dividends table: built from every source’s record, updated a window at a time after the day’s bars land, retried from the issues. Carried state: the base’s, with params this job’s DividendsParams.

build_dividends

build_dividends(cfg: RunConfig) -> None

Every active ETF’s and equity’s dividend record — FMP’s, EODHD’s, Nasdaq’s for its own listings — combined one row a payout, a family at a time in batches, each batch written before the next is fetched: one receipt a batch, carrying the gaps; the fetch failures opened as issues.

dividends_repair_due

dividends_repair_due(context: Any) -> Any

As Splits.splits_repair_due, for the dividends table.

fetch_dividend_window

fetch_dividend_window(cfg: RunConfig) -> dict[str, Any]

The window’s payouts (lookback_days back, ahead_days ahead) for every active ETF and equity: FMP’s dividend calendar, EODHD’s dividend bulk one call a day, Nasdaq’s calendar one call a day, combined, Nasdaq settling the cash where it lists the name; the calendars that did not answer named. Writes nothing.

retry_dividends

retry_dividends(cfg: RunConfig) -> None

The listings an earlier fetch left to retry (dividend_backfill): their whole record fetched again, written; the ones that answered have their issues closed, the others are seen again.

write_dividend_window

write_dividend_window(cfg: RunConfig, fetch_dividend_window: dict[str, Any]) -> None

The window landed: every calendar answered → the window made exact for the listings answered for (a cancelled announcement moved aside); a calendar unanswered → upsert only, nothing retired, and an unread issue the repair acts on. Receipt with the gaps; the fetch failures opened; the unread closed once every calendar answers.

DividendsParams

Bases: JobParams

A dividends job’s row params, as SplitsParams: which listings, the build’s window and batch, the update’s window, and how the table is written.

EventCheckParams

Bases: JobParams

The weekly SEC check’s knobs (the row’s params).

EventChecks

Bases: DataJob

The SEC’s word on our splits and dividends, a week at a time (DataClient .check_dividends_sec / check_splits_sec): what the filer filed that our record does not show is opened as a notice (no job acts on it: a person looks), each closed when the next check no longer finds it. Funds and most ADRs file no dividend per share: they are not checked. Nothing is written. Carried state: the base’s, with params this job’s EventCheckParams.

check_dividends_sec

check_dividends_sec(cfg: RunConfig) -> None

Each equity’s payouts summed into its fiscal quarters against the dividends per share it declared: a quarter that disagrees opens sec_disagrees.

check_splits_sec

check_splits_sec(cfg: RunConfig) -> None

Each equity’s filed split ratios against our splits (the filer’s rounding allowed, within SPLIT_SEC_DAYS): a ratio the filer reported that no split of ours matches opens sec_only.

Splits

Bases: DataJob

The splits table: built from every source’s record, updated a window at a time after the day’s bars land, retried from the issues. Carried state: the base’s, with params this job’s SplitsParams.

build_splits

build_splits(cfg: RunConfig) -> None

Every active ETF’s and equity’s split record — FMP’s history and five-year calendar, EODHD’s history, Nasdaq’s calendar — judged on the listing’s raw daily bars, a family at a time in batches, each batch written before the next is fetched: one receipt a batch, carrying the gaps; the fetch failures opened as issues.

fetch_split_window

fetch_split_window(cfg: RunConfig) -> dict[str, Any]

The window’s splits (lookback_days back, ahead_days ahead) for every active ETF and equity: FMP’s split calendar, EODHD’s split bulk one call a day, Nasdaq’s calendar, combined and judged on the listings’ raw daily bars from JUDGE_DAYS before the window; the calendars that did not answer named. Writes nothing.

retry_splits

retry_splits(cfg: RunConfig) -> None

The listings an earlier fetch left to retry (split_backfill): their whole record fetched again, judged on their daily, written; the ones that answered have their issues closed, the others are seen again.

splits_repair_due

splits_repair_due(context: Any) -> Any

Once a night, 02:00-04:00 New York (two hours: the night the clocks go forward has no 02:00), only while a splits issue the repair acts on is open: a calendar unread, a listing to retry.

write_split_window

write_split_window(cfg: RunConfig, fetch_split_window: dict[str, Any]) -> None

The window landed. First the stored splits against the fetched, for the listings answered for: split_changed issues (the daily job’s refill). Then the write: every calendar answered → the window made exact for those listings (a cancelled announcement moved aside); a calendar unanswered → upsert only, nothing retired, and an unread issue the repair acts on. Receipt with the gaps; the fetch failures opened; the unread closed once every calendar answers.

SplitsParams

Bases: JobParams

A splits job’s row params: which listings, the build’s window and batch, the update’s window, and how the table is written (build_splits / update_splits / write_splits’ own).

Functions

unanswered

unanswered(section: str, model: Any, calendars: list[str]) -> list[dict[str, Any]]

The unread issue each calendar that did not answer opens on its table: the night wrote without retiring anything, and the repair re-sweeps the window.