trader.persistence.focus_list module¶
Repository for focus_list (issue #44).
A history, not a pure set: trading_day anchors each row to the session trader build-focus-list computed it for (Decision 7), so the intraday read _build_universe needs every cycle is a plain, indexed (trading_day, symbol) lookup — never a scan over watchlist_events’ JSON-in-text note, which is audit-only and never a worklist (see that module’s own docstring).
Structurally typed against discovery.candidates.Candidate via FocusListCandidate below, rather than importing it: persistence/ stays free of a discovery/ dependency, the mirror image of discovery/scan.py’s own duck-typed index_repository/consensus_repository parameters that keep that package free of a persistence/ dependency.
- class trader.persistence.focus_list.FocusListCandidate(*args, **kwargs)[source]¶
Bases:
ProtocolWhat upsert reads off each candidate. discovery.candidates.Candidate already has every one of these attributes, so it satisfies this structurally with no import needed on either side.
Declared as read-only @property members, not plain attributes: a plain Protocol attribute requires the implementer to support both read and write, and Candidate is frozen=True — assignment raises. upsert only ever reads these fields, so the Protocol should ask for no more than that, and mypy’s structural check enforces the read/write distinction even though it is invisible in an ad hoc, single-module reproduction.
- property symbol: str¶
- property theme: str¶
- property origin: str¶
- property headline: str | None¶
- property url: str | None¶
- property recommendation_mean: float | None¶
- class trader.persistence.focus_list.FocusListRepository(session_factory)[source]¶
Bases:
objectWrites and reads focus_list.
- Parameters:
session_factory (sessionmaker[Session])
- upsert(trading_day, candidates, *, generated_at)[source]¶
Record candidates as the focus list for trading_day.
UNIQUE(trading_day, symbol) is what makes a same-day rerun (a manual retry after a partial build-focus-list failure) update the existing row rather than fail on the constraint or leave a stale duplicate readable — the rerun’s data replaces the first attempt’s.
- Parameters:
trading_day (date)
candidates (Iterable[FocusListCandidate])
generated_at (datetime)
- Return type:
None
- symbols_for(trading_day)[source]¶
Every symbol recorded under trading_day.
[] when the batch never ran, or ran and stamped a different day — the same “this source contributes nothing” degrade themes: [] and a never-run scan-universe already give, extended to a third source (Decision 7).
- Parameters:
trading_day (date)
- Return type:
list[str]