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>
45 lines
1.7 KiB
Python
45 lines
1.7 KiB
Python
"""`yfin search ...` — Yahoo Finance keyword search."""
|
|
from __future__ import annotations
|
|
|
|
import typer
|
|
import yfinance as yf
|
|
|
|
from .._shared import render_via_state, get_state
|
|
|
|
|
|
app = typer.Typer(no_args_is_help=True, help="Yahoo Finance keyword search.")
|
|
|
|
|
|
@app.command("run")
|
|
def search(
|
|
ctx: typer.Context,
|
|
query: str = typer.Argument(..., help="Search query (ticker, partial ticker or company name)."),
|
|
max_results: int = typer.Option(8, "--max-results"),
|
|
news_count: int = typer.Option(8, "--news-count"),
|
|
lists_count: int = typer.Option(8, "--lists-count"),
|
|
include_cb: bool = typer.Option(True, "--include-cb/--no-include-cb"),
|
|
include_nav_links: bool = typer.Option(False, "--include-nav-links/--no-include-nav-links"),
|
|
include_research: bool = typer.Option(False, "--include-research/--no-include-research"),
|
|
include_cultural_assets: bool = typer.Option(False, "--include-cultural-assets/--no-include-cultural-assets"),
|
|
fuzzy: bool = typer.Option(False, "--fuzzy/--no-fuzzy", help="Alias for enable_fuzzy_query."),
|
|
recommended: int = typer.Option(8, "--recommended"),
|
|
raise_errors: bool = typer.Option(True, "--raise-errors/--no-raise-errors"),
|
|
):
|
|
"""Run a search and dump quotes + news + lists + research + nav."""
|
|
st = get_state(ctx)
|
|
s = yf.Search(
|
|
query,
|
|
max_results=max_results,
|
|
news_count=news_count,
|
|
lists_count=lists_count,
|
|
include_cb=include_cb,
|
|
include_nav_links=include_nav_links,
|
|
include_research=include_research,
|
|
include_cultural_assets=include_cultural_assets,
|
|
enable_fuzzy_query=fuzzy,
|
|
recommended=recommended,
|
|
timeout=st.timeout,
|
|
raise_errors=raise_errors,
|
|
)
|
|
render_via_state(ctx, s.all)
|