Files
yfinance-fork/CLAUDE.md
goldyard 057bc4493e Add yfin CLI + tool catalog + CLAUDE.md
Wraps the entire yfinance public API behind a single binary `yfin` with
51 subcommands across 13 namespaces (ticker, download, tickers, search,
lookup, market, sector, industry, calendars, screen, live, auth, config).
Output renders as Rich tables on TTY, JSON when piped; --format / --out
support table | json | ndjson | csv | tsv | parquet | yaml.

Highlights:
- 1857 LOC across 18 Python files under cli/yfin/
- Typer + Rich, packaged via hatchling + uv
- Install globally: `cd cli && uv tool install -e .`
- ~/.yfin/config.toml for persistent proxy/cookies/locale defaults
- Friendly YFRateLimitError handler (exit 2, no Rich traceback)
- Validated end-to-end with 33 live tests against Yahoo from a
  residential exit (AAPL, MSFT, NVDA, options, screens, calendars,
  financials, news, holders, parquet round-trip)

yfinance-tools.yaml is the single source of truth:
- tools (49)       — every public yfinance entry point with parameters
- cli (13 groups)  — exact CLI invocations, mapped back to tool names
- outputSchemas (27) — actual return shapes captured from live calls
- learnings (19)   — IP rate-limit, crumb handshake, Typer gotchas,
                     screen-build wrapping rules, upstream stubs, etc.

CLAUDE.md documents the upstream codebase layout for future agents.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-08 23:36:56 +08:00

7.4 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project

yfinance is a Python library (v1.4.1) that downloads market data from Yahoo! Finance's public web APIs. It is not affiliated with Yahoo — it reverse-engineers their v7/v10/v8 chart, quote, options, fundamentals, and websocket streaming endpoints. The package is published on PyPI and conda-forge.

Commands

Tests

Tests use the stdlib unittest runner. They hit real Yahoo endpoints, so a network connection is required and individual tests can be flaky against live data.

# Run everything
python -m unittest discover -s tests

# Single module
python -m unittest tests.test_ticker

# Single test
python -m unittest tests.test_ticker.TestTicker.test_history

# With coverage (mirrors CI)
pytest --cov=yfinance/

All test modules import tests/context.py first — it inserts the repo root onto sys.path and configures a dedicated test cache at <user_cache_dir>/py-yfinance-testing that auto-clears once per day. tests/context.py also exposes session_gbl (currently None); requests_cache/requests_ratelimiter sessions don't compose with curl_cffi so the rate-limiter examples are kept commented out as reference.

Local install

pip install -e .

extras_require: nospam (requests_cache + requests_ratelimiter) and repair (scipy, needed for Ticker.history(repair=True)).

Type check

Pyright is configured via pyrightconfig.json in basic mode with most checks at warning level.

Branching for PRs

Two-layer model (per CONTRIBUTING.md): submit PRs against dev. The maintainer batches dev → main for each PyPI release. Do not target main directly. CI (.travis.yml) only runs on main.

Architecture

Public surface

yfinance/__init__.py is the single entry point that re-exports the entire public API. Anything not exported there is private. The public types are: Ticker, Tickers, download, Market/MarketRegion, Search, Lookup, Calendars, Sector, Industry, WebSocket/AsyncWebSocket, EquityQuery/FundQuery/ETFQuery, screen, PREDEFINED_SCREENER_QUERIES, Auth, config, enable_debug_mode, set_tz_cache_location.

Ticker is a thin facade over scrapers

Ticker (yfinance/ticker.py) inherits from TickerBase (yfinance/base.py) and exposes ~50 @property accessors (info, financials, balance_sheet, news, options, funds_data, etc.). Each property just calls a get_*() method on TickerBase. The actual fetching/parsing logic for each property lives in a dedicated scraper module under yfinance/scrapers/:

  • quote.pyinfo, fast_info, calendar, sec_filings, news, ISIN
  • fundamentals.py — income statement, balance sheet, cash flow, earnings
  • analysis.py — analyst estimates, price targets, revisions, growth
  • holders.py — major/institutional/mutualfund/insider holders
  • history.py — OHLCV history, splits, dividends, price-repair (the largest file: ~164k)
  • funds.pyFundsData for ETFs/mutual funds

When adding a new ticker field, follow the established pattern: implement get_<thing>() in the relevant scraper, wire it through TickerBase, then add a @property on Ticker.

Multi-ticker downloads

Tickers (tickers.py) holds a dict of Ticker instances. download() (multi.py) is the heavy-lift batch path used for portfolio history — it parallelizes via the multitasking package and reshapes results into a single (multi-indexed) DataFrame. Don't extend Ticker.history() with batching logic; that belongs in multi.py.

HTTP and caching

  • yfinance/data.pyYfData (the per-session HTTP wrapper) and the Auth helper that solves Yahoo's crumb/cookie challenge. Every scraper goes through self._data.get(...).
  • yfinance/_http.py — low-level HTTP utilities.
  • curl_cffi is the default backend (it impersonates a browser TLS fingerprint, which is required to get past Yahoo's Cloudflare). Plain requests/requests_cache/requests_ratelimiter are not compatible — that's why tests/context.py keeps session_gbl = None and why the nospam extra is opt-in only for users supplying their own requests-based session.
  • yfinance/cache.py — peewee + SQLite caches for tz lookups and the IPO/cookie cache. User-facing location is set via yf.set_tz_cache_location(path).

Live streaming

yfinance/live.py provides WebSocket and AsyncWebSocket for Yahoo's real-time pricing feed. Wire-format is protobuf — yfinance/pricing.proto is the schema and yfinance/pricing_pb2.py is the generated code (both ship in the wheel via setup.py package_data). Regenerate pricing_pb2.py with protoc if the schema changes.

Domain / screener

  • yfinance/domain/Sector, Industry, Market/MarketRegion (sector overviews, industry summaries, market summary endpoints). They share a domain.py base.
  • yfinance/screener/query.py defines the typed EquityQuery/FundQuery/ETFQuery builders; screener.py defines screen() and PREDEFINED_SCREENER_QUERIES. New screener fields go in query.py keyed off Yahoo's screenable-field metadata.

Constants & utilities

  • yfinance/const.py (~48k) — every magic string from Yahoo: financial-statement field name maps (fundamentals_keys), pretty-name translation tables, user-agents, base URLs (_BASE_URL_, _ROOT_URL_, _SCRAPE_URL_), screener-field enums. Look here first before hard-coding any Yahoo field name.
  • yfinance/utils.py (~47k) — shared parsers, the project-wide get_yf_logger(), decorators, DataFrame helpers (empty_df, _pd_timedelta_to_interval), etc.

Config

yfinance/config.py defines YfConfig (exported as yfinance.config), a tiny nested-attribute store with auto-vivifying namespaces. The defaults are config.network.proxy, config.network.retries, config.debug.hide_exceptions, config.debug.logging, config.locale.lang, config.locale.region. The legacy set_config(proxy=, retries=) is a deprecated shim that forwards to config.network.*.

Conventions and gotchas

  • Version bump: edit yfinance/version.py (setup.py reads it textually — keep the version = "x.y.z" line shape) and meta.yaml ({% set version = "..." %}) together. meta.yaml is for conda-forge and includes a sha256 that the conda-forge bot updates after PyPI release.
  • Versioning is loose: bumps are not always semver-aligned with API changes. Check CHANGELOG.rst (the canonical changelog; CHANGELOG.md is the short rolling extract).
  • Logging: scrapers should call utils.get_yf_logger() rather than the stdlib logging module directly. End-users opt in with yf.enable_debug_mode().
  • Frequencies on financials: freq is one of 'yearly', 'quarterly', 'trailing' (TTM). The pretty=True flag on get_income_stmt/get_balance_sheet/get_cash_flow swaps Yahoo's raw camelCase keys for human-readable row labels via maps in const.py.
  • Price repair: Ticker.history(..., repair=True) runs the heuristics in scrapers/history.py against bad-tick patterns Yahoo emits (100x/0.01x splits, missing dividends). It needs scipy — guard new repair code behind the existing optional-import pattern.
  • Tests hit the network: there is no recorded-fixture infrastructure. When debugging a failing test, expect that the underlying Yahoo endpoint may have changed shape; check scrapers/yahoo-keys.txt for the latest observed key set.