trader.marketdata.earnings module¶
The next known earnings date for a symbol.
Issue #89. Mirrors marketdata/analysts.py’s shape exactly (the pattern issue #32 established): a Protocol, a yfinance-backed implementation, and a per-process cache so “no upcoming earnings” for an ETF is derived once, not every ~15-minute cycle forever (issue #100’s discipline, applied here from the start rather than retrofitted).
Implementation-time spike (issue #89’s open question): `.calendar` vs. `.get_earnings_dates()`. Tried both against AAPL, TSLA, MSFT and SPY on 2026-08-31. .get_earnings_dates() raises ImportError: Missing optional dependency ‘lxml’ in this project’s environment — it scrapes and parses an HTML table via pandas.read_html, which needs lxml and this project does not carry as a dependency (nor should it, for one optional yfinance code path). .calendar needs no extra dependency: it is yfinance’s structured quoteSummary JSON surface, same family as .info (already used by analysts.py), and returned a clean dict for every ticker tried — {‘Earnings Date’: [date(2026, 10, 29)], …} for AAPL/TSLA/MSFT, and an empty {} for SPY (an ETF, no earnings — not an exception, not a 404, matching the “ETFs get a clean empty answer” shape .recommendations already established for analyst coverage). .calendar is what this module uses.
Absent/unknown is None, never a fabricated date — same “missing is not zero” discipline AnalystOpinion uses for coverage.
- class trader.marketdata.earnings.EarningsProvider(*args, **kwargs)[source]¶
Bases:
ProtocolThe next known earnings date for a symbol, or None.
- class trader.marketdata.earnings.YFinanceEarningsProvider(ticker_factory=None)[source]¶
Bases:
objectNext earnings date from yfinance’s .calendar. No pandas type escapes.
Caches a successful answer per symbol for this instance’s lifetime (issue #100, applied here the same way YFinanceAnalystProvider uses it) — “no upcoming earnings” for an ETF is a structural fact, not something that changes cycle to cycle, and a real company’s earnings date does not move minute to minute either. Deliberately no TTL, the same accepted tradeoff analysts.py documents: a symbol whose earnings date is later announced or revised stays cached until the process restarts. Never cached on an exception, so a transient fetch failure is retried fresh next call rather than permanently misremembered.
- Parameters:
ticker_factory (Callable[[str], object] | None)