fix(research): [PR2] get_balance_sheet → fundamentals S3 (R3)#198
Merged
Conversation
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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_sheetto read alpha-engine-data's weekly Finnhub fundamentals snapshot from S3 instead ofyfinance.Ticker().info; removed theimport yfinance as yffrom that path (it was the only yfinance ref in the module — quant_tools.py is now yfinance-free for PR2's scope).read_fundamentals_from_s3()— readsarchive/fundamentals/{date}.json; with norun_date, scans the prefix and reads the most-recent snapshot. Mirrors the predictor'sinference/stages/fetch_alt_data.pyread + date-resolution pattern and the in-reporead_factor_profiles_from_s3S3 helper style.factor_profiles) via a newfundamentals_datacontext 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 not —alpha-engine-data/collectors/fundamentals.pypersists 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:debt_to_equitydebt_to_equitycurrent_ratiocurrent_ratiope_ratiope_ratioprice_to_bookpb_ratiorevenue_growthrevenue_growth_yoygross_marginsgross_marginforward_peNonemarket_capNoneThe 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). Theread_*helper returnsNoneon 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.py— 8 tests,monkeypatch/fakes, nounittest.mock.patch(per the documented full-suite bleed; mirrorstests/test_held_thesis_strict.pystyle): 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 failure —tests/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