057bc4493e
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>
72 lines
1.8 KiB
Python
72 lines
1.8 KiB
Python
"""`yfin sector ...` — sector aggregates."""
|
|
from __future__ import annotations
|
|
|
|
from enum import Enum
|
|
from typing import Optional
|
|
|
|
import typer
|
|
import yfinance as yf
|
|
|
|
from .._shared import render_via_state
|
|
|
|
|
|
SECTOR_KEYS = [
|
|
"basic-materials",
|
|
"communication-services",
|
|
"consumer-cyclical",
|
|
"consumer-defensive",
|
|
"energy",
|
|
"financial-services",
|
|
"healthcare",
|
|
"industrials",
|
|
"real-estate",
|
|
"technology",
|
|
"utilities",
|
|
]
|
|
|
|
|
|
class Attribute(str, Enum):
|
|
overview = "overview"
|
|
top_companies = "top_companies"
|
|
top_etfs = "top_etfs"
|
|
top_mutual_funds = "top_mutual_funds"
|
|
industries = "industries"
|
|
research_reports = "research_reports"
|
|
name = "name"
|
|
symbol = "symbol"
|
|
|
|
|
|
app = typer.Typer(no_args_is_help=True, help="Sector aggregates.")
|
|
|
|
|
|
@app.command("list")
|
|
def list_sectors(ctx: typer.Context):
|
|
"""Print the 11 valid Yahoo sector keys (no Yahoo call)."""
|
|
render_via_state(ctx, SECTOR_KEYS)
|
|
|
|
|
|
@app.command("info")
|
|
def sector(
|
|
ctx: typer.Context,
|
|
key: str = typer.Argument(..., help="Sector slug (use `yfin sector list` to enumerate)."),
|
|
attribute: Optional[Attribute] = typer.Option(None, "--attribute"),
|
|
region: str = typer.Option("US", "--region"),
|
|
):
|
|
"""Sector aggregates (top companies / ETFs / mutual funds / industries)."""
|
|
s = yf.Sector(key, region=region)
|
|
if attribute is None:
|
|
out = {
|
|
"key": s.key,
|
|
"name": s.name,
|
|
"symbol": s.symbol,
|
|
"overview": s.overview,
|
|
"top_companies": s.top_companies,
|
|
"top_etfs": s.top_etfs,
|
|
"top_mutual_funds": s.top_mutual_funds,
|
|
"industries": s.industries,
|
|
"research_reports": s.research_reports,
|
|
}
|
|
else:
|
|
out = getattr(s, attribute.value)
|
|
render_via_state(ctx, out)
|