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>
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.py—info,fast_info,calendar,sec_filings,news, ISINfundamentals.py— income statement, balance sheet, cash flow, earningsanalysis.py— analyst estimates, price targets, revisions, growthholders.py— major/institutional/mutualfund/insider holdershistory.py— OHLCV history, splits, dividends, price-repair (the largest file: ~164k)funds.py—FundsDatafor 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.py—YfData(the per-session HTTP wrapper) and theAuthhelper that solves Yahoo's crumb/cookie challenge. Every scraper goes throughself._data.get(...).yfinance/_http.py— low-level HTTP utilities.curl_cffiis the default backend (it impersonates a browser TLS fingerprint, which is required to get past Yahoo's Cloudflare). Plainrequests/requests_cache/requests_ratelimiterare not compatible — that's whytests/context.pykeepssession_gbl = Noneand why thenospamextra is opt-in only for users supplying their ownrequests-based session.yfinance/cache.py— peewee + SQLite caches for tz lookups and the IPO/cookie cache. User-facing location is set viayf.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 adomain.pybase.yfinance/screener/—query.pydefines the typedEquityQuery/FundQuery/ETFQuerybuilders;screener.pydefinesscreen()andPREDEFINED_SCREENER_QUERIES. New screener fields go inquery.pykeyed 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-wideget_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.pyreads it textually — keep theversion = "x.y.z"line shape) andmeta.yaml({% set version = "..." %}) together.meta.yamlis for conda-forge and includes asha256that 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.mdis the short rolling extract). - Logging: scrapers should call
utils.get_yf_logger()rather than the stdlibloggingmodule directly. End-users opt in withyf.enable_debug_mode(). - Frequencies on financials:
freqis one of'yearly','quarterly','trailing'(TTM). Thepretty=Trueflag onget_income_stmt/get_balance_sheet/get_cash_flowswaps Yahoo's raw camelCase keys for human-readable row labels via maps inconst.py. - Price repair:
Ticker.history(..., repair=True)runs the heuristics inscrapers/history.pyagainst bad-tick patterns Yahoo emits (100x/0.01x splits, missing dividends). It needsscipy— 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.txtfor the latest observed key set.