Spaces:
Sleeping
Sleeping
Download scripts/snapshot_consensus.py from Viney/readthrough: direct link, hf CLI and curl.
- Browser
- Download file 4.89 kB
-
https://huggingface.co/spaces/Viney/readthrough/resolve/main/scripts/snapshot_consensus.py
- Command line
-
hf download hf://spaces/Viney/readthrough/scripts/snapshot_consensus.py
-
curl -L -o snapshot_consensus.py https://huggingface.co/spaces/Viney/readthrough/resolve/main/scripts/snapshot_consensus.py
4.89 kB
| #!/usr/bin/env python | |
| """Capture today's street consensus for every covered ticker. | |
| Run daily, after the US close. Each run appends one record per (ticker, | |
| metric) to data/consensus_snapshots.jsonl, stamped with our own UTC capture | |
| time. That timestamp is what later lets analytics/consensus.aligned_consensus | |
| prove an estimate predates a release. | |
| A gap in this archive cannot be backfilled from any public source, which is | |
| why the job logs failures loudly and exits non-zero only when nothing at all | |
| was captured. | |
| The street doesn't publish a period label alongside its estimate β yfinance | |
| only exposes relative codes ("0q", "+1q", "0y") β so this script derives the | |
| label itself, as the quarter after the ticker's most recently reported one | |
| (``analytics.consensus.next_unreported_period``). A ticker whose latest | |
| reported filing is old enough that a newer one has probably already been | |
| missed (see the staleness warning below) gets a label that is probably | |
| wrong, so it is worth watching this output, not just its exit code. | |
| """ | |
| from __future__ import annotations | |
| import sys | |
| from datetime import datetime, timezone | |
| from pathlib import Path | |
| sys.path.insert(0, str(Path(__file__).resolve().parents[1])) | |
| from analytics.consensus import next_unreported_period | |
| from analytics.staleness import filing_staleness | |
| from ingestion.analyst import fetch_analyst_estimates | |
| from storage.forecast_store import CONSENSUS_PATH, read_snapshots | |
| from storage.metrics_db import get_all_metrics, list_tickers | |
| def main() -> int: | |
| tickers = list_tickers() | |
| if not tickers: | |
| print("no covered tickers found in data/metrics.db", file=sys.stderr) | |
| return 1 | |
| before = len(read_snapshots()) | |
| started = datetime.now(timezone.utc).isoformat() | |
| ok, failed = [], [] | |
| for ticker in tickers: | |
| period = next_unreported_period(ticker) | |
| if period is None: | |
| failed.append((ticker, "no_parseable_quarterly_period")) | |
| print( | |
| f" {ticker}: SKIPPED β no parseable quarterly period in " | |
| f"metrics_db, refusing to archive an unlabeled estimate", | |
| file=sys.stderr, | |
| ) | |
| continue | |
| # 120 days matches analytics/staleness.py::filing_staleness β roughly | |
| # one quarter plus the usual filing delay. Beyond it, a newer | |
| # quarterly report has probably already been missed, which means the | |
| # period this script just derived is probably wrong for this ticker. | |
| rows = get_all_metrics(ticker) | |
| latest_report_date = rows[0].get("report_date") if rows else None | |
| staleness = filing_staleness(latest_report_date) | |
| if staleness["likely_newer_filing"]: | |
| print( | |
| f" {ticker}: WARNING β latest reported filing is " | |
| f"{staleness['days_old']} days old (>120d); the derived " | |
| f"target_period {period!r} is probably wrong for this ticker", | |
| file=sys.stderr, | |
| ) | |
| # snapshot_period is what opts this call into archiving. It is | |
| # separate from target_period on purpose: only a caller that has | |
| # derived the period the estimate is actually FOR (here, the next | |
| # unreported quarter) may label an archive record, and this script | |
| # is the only such caller. See ingestion/analyst.py's docstring. | |
| payload, error = fetch_analyst_estimates( | |
| ticker, target_period=period, snapshot_period=period | |
| ) | |
| if payload is None: | |
| failed.append((ticker, error)) | |
| print(f" {ticker}: FAILED β {error}", file=sys.stderr) | |
| else: | |
| ok.append(ticker) | |
| print(f" {ticker}: captured for {payload.get('target_period')}") | |
| written = len(read_snapshots()) - before | |
| print( | |
| f"\nrun {started}: {len(ok)} ok, {len(failed)} failed, " | |
| f"{written} new records in {CONSENSUS_PATH}" | |
| ) | |
| # The exit code tracks records WRITTEN, not fetches that returned. Those | |
| # are different things: the append happens inside | |
| # ingestion.analyst.record_consensus_snapshot, which swallows every | |
| # exception and returns 0. Counting successful fetches meant a run whose | |
| # every append failed still printed a success line per ticker and exited | |
| # 0 -- a green check over an empty archive, on the one log whose missing | |
| # days cannot be reconstructed from any public source. A day with nothing | |
| # captured is a failed day, whatever the fetches did. | |
| if not written: | |
| print( | |
| "captured 0 new records - treating this run as FAILED. Either " | |
| "every append failed (see the [consensus capture] lines above) " | |
| "or every snapshot for today is already in the archive.", | |
| file=sys.stderr, | |
| ) | |
| return 1 | |
| return 0 | |
| if __name__ == "__main__": | |
| raise SystemExit(main()) | |