Skip to content

fix(research): [PR2] get_balance_sheet → fundamentals S3 (R3)#198

Merged
cipher813 merged 2 commits into
mainfrom
fix/yf-pr2-balsheet
May 17, 2026
Merged

fix(research): [PR2] get_balance_sheet → fundamentals S3 (R3)#198
cipher813 merged 2 commits into
mainfrom
fix/yf-pr2-balsheet

Conversation

@cipher813
Copy link
Copy Markdown
Owner

yfinance-centralization arc — PR 2 (balance-sheet tool → fundamentals S3)

Plan doc: alpha-engine-docs/private/yfinance-centralization-260516.md (item R3, PR 2 — the last HOT research yfinance socket).

Exact change

Rewrote agents/sector_teams/quant_tools.py::get_balance_sheet to read alpha-engine-data's weekly Finnhub fundamentals snapshot from S3 instead of yfinance.Ticker().info; removed the import yfinance as yf from that path (it was the only yfinance ref in the module — quant_tools.py is now yfinance-free for PR2's scope).

  • New module-level read_fundamentals_from_s3() — reads archive/fundamentals/{date}.json; with no run_date, scans the prefix and reads the most-recent snapshot. Mirrors the predictor's inference/stages/fetch_alt_data.py read + date-resolution pattern and the in-repo read_factor_profiles_from_s3 S3 helper style.
  • Cached once at tool-creation time (one S3 read per sector team per Saturday SF run — same pattern/budget as factor_profiles) via a new fundamentals_data context key (also test-injectable → no S3/network in tests).

Schema-mapping correction (vs the plan doc)

The plan assumed raw Finnhub keys (peTTM, totalDebt/totalEquityAnnual, …) are present in the S3 JSON. They are notalpha-engine-data/collectors/fundamentals.py persists a normalized/clipped per-ticker schema: {pe_ratio, pb_ratio, debt_to_equity, revenue_growth_yoy, fcf_yield, gross_margin, roe, current_ratio}. I followed the plan's intent (consume the exact S3 key the predictor already reads) and mapped the actual schema onto the tool's existing output keys:

tool output ← data-module key note
debt_to_equity debt_to_equity already a ratio — NO yfinance %/100 scaling (per plan)
current_ratio current_ratio
pe_ratio pe_ratio
price_to_book pb_ratio
revenue_growth revenue_growth_yoy
gross_margins gross_margin
forward_pe — → None not persisted by the collector
market_cap — → None computed transiently for fcf_yield, not persisted

The agent consumes these as soft directional context, not a hard gate (the hard D/E gate R2 is deleted in PR1), so the normalized-scale / trailing-vs-TTM delta is tolerable per the plan's risk note.

Graceful-degrade preserved

Exact return-schema keys unchanged. A ticker absent from the snapshot (or an empty/missing snapshot) returns {"error": ...} per the existing contract — never raises under all-agents-strict (#195). The read_* helper returns None on any S3 failure so the tool degrades rather than propagating. No read that degraded before now raises.

Tests

Added tests/test_get_balance_sheet_s3.py8 tests, monkeypatch/fakes, no unittest.mock.patch (per the documented full-suite bleed; mirrors tests/test_held_thesis_strict.py style): mapped schema from a faked fundamentals JSON, D/E not %/100-rescaled, {"error":...} on missing ticker + empty snapshot (no raise), no-yfinance-import assertion, S3-reader scan-for-latest + None-on-failure. Full suite: 1329 passed (1321 baseline + 8 new), 1 pre-existing acceptable failuretests/test_scoring.py::TestRSIScoring::test_bull_overbought_matches_neutral_post_revert (stale-local-config; passes on CI). Zero new failures.

Deferred

None. Independent of PR1 and PR3 (off origin/main).


DEPLOY HELD — research auto-deploys on merge; do not merge until user directs. Part of the yfinance-centralization arc (plan doc alpha-engine-docs/private/yfinance-centralization-260516.md); intended to land before the held Research re-run.

🤖 Generated with Claude Code

cipher813 and others added 2 commits May 16, 2026 18:04
yfinance-centralization arc (plan: alpha-engine-docs/private/yfinance-centralization-260516.md),
PR 2 — R3, the last HOT research yfinance socket.

Rewrote agents/sector_teams/quant_tools.py::get_balance_sheet to read
alpha-engine-data's weekly Finnhub fundamentals snapshot instead of
yfinance.Ticker().info. Removed `import yfinance as yf` from that path —
quant_tools.py is now yfinance-free for PR2's scope (the get_balance_sheet
`import yfinance as yf` was the only yfinance reference).

Mechanics (mirrors the in-repo factor_profiles pattern + predictor's
inference/stages/fetch_alt_data.py read/date-resolution):
- New module-level `read_fundamentals_from_s3()` — reads
  archive/fundamentals/{date}.json; if no run_date, scans the prefix and
  reads the most-recent snapshot (predictor's fallback; the snapshot is a
  slow weekly signal so stale-by-days is acceptable). Returns None on any
  failure (caller graceful-degrades, never raises).
- Cached once at tool-creation time (one S3 read per sector team per
  Saturday SF run, same as factor_profiles) via a new `fundamentals_data`
  context key (also injectable for tests — no S3/network in tests).

Schema-mapping correction vs the plan doc: the data-module collector does
NOT persist raw Finnhub keys — collectors/fundamentals.py writes a
NORMALIZED/CLIPPED per-ticker schema {pe_ratio, pb_ratio, debt_to_equity,
revenue_growth_yoy, fcf_yield, gross_margin, roe, current_ratio}. Followed
the plan's intent (consume the S3 key the predictor already reads) and
mapped that ACTUAL schema onto the tool's exact existing output keys:
  debt_to_equity ← debt_to_equity (already a ratio — NO yfinance %/100
                   scaling, per plan)
  current_ratio  ← current_ratio
  pe_ratio       ← pe_ratio
  price_to_book  ← pb_ratio
  revenue_growth ← revenue_growth_yoy
  gross_margins  ← gross_margin
  forward_pe     → None  (not persisted by the collector)
  market_cap     → None  (computed transiently for fcf_yield, not persisted)
The agent consumes these as soft directional context (not a hard gate —
the hard D/E gate R2 is being deleted in PR1), so the normalized-scale /
trailing-vs-TTM delta is tolerable per the plan's risk note.

Graceful-degrade preserved: exact return-schema keys unchanged; a ticker
absent from the snapshot (or an empty/missing snapshot) returns
{"error": ...} per the existing contract — never raises (all-agents-strict,
#195). No read that degraded before now raises.

Tests: added tests/test_get_balance_sheet_s3.py (8 tests, monkeypatch/fakes,
NO unittest.mock.patch per the documented full-suite bleed) — mapped schema
from a faked fundamentals JSON, D/E not %/100-rescaled, {"error":...} on
missing ticker + empty snapshot (no raise), no yfinance import, S3-reader
scan-for-latest + None-on-failure. Full suite: 1329 passed
(1321 baseline + 8 new), 1 pre-existing acceptable failure
(tests/test_scoring.py::TestRSIScoring::test_bull_overbought_matches_neutral_post_revert
— stale-local-config, passes on CI). Zero new failures.

**DEPLOY HELD — research auto-deploys on merge; do not merge until user
directs. Part of the yfinance-centralization arc (plan doc
alpha-engine-docs/private/yfinance-centralization-260516.md); intended to
land before the held Research re-run.**

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@cipher813 cipher813 merged commit 571d0e4 into main May 17, 2026
1 check passed
@cipher813 cipher813 deleted the fix/yf-pr2-balsheet branch May 17, 2026 01:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant