yfin-cli 0.1.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
src/utils.py ADDED
@@ -0,0 +1,91 @@
1
+ import json
2
+ import typer
3
+ from typing import Any, Callable
4
+ from datetime import datetime, timedelta
5
+ from pandas import DataFrame, Series
6
+ from rich.console import Console
7
+
8
+ console = Console()
9
+
10
+
11
+ def console_print(content: Any):
12
+ console.print(content)
13
+
14
+
15
+ def console_print_error(content: Any):
16
+ console.print(f"[red]{content}[/red]")
17
+
18
+
19
+ def console_print_warning(content: Any):
20
+ console.print(f"[yellow]{content}[/yellow]")
21
+
22
+
23
+ def count_specified(*args: str | None) -> int:
24
+ """Count the number of specified arguments"""
25
+ return sum(x is not None for x in args)
26
+
27
+
28
+ def compact(**kwargs):
29
+ """Return a dict with None values removed."""
30
+ return {k: v for k, v in kwargs.items() if v is not None}
31
+
32
+
33
+ def get_today_date_string() -> str:
34
+ return format_datetime(datetime.now())
35
+
36
+
37
+ def default_end_from_start(start: str, end: str | None) -> str:
38
+ if end is not None:
39
+ return end
40
+ start_date = datetime.strptime(start, "%Y-%m-%d")
41
+ return format_datetime(start_date + timedelta(days=7))
42
+
43
+
44
+ def format_datetime(val: datetime) -> str:
45
+ return val.strftime("%Y-%m-%d")
46
+
47
+
48
+ def is_number(s: str) -> bool:
49
+ try:
50
+ float(s)
51
+ return True
52
+ except ValueError:
53
+ return False
54
+
55
+
56
+ def data_frame_to_list(data_frame: DataFrame, index_name: str | None = None) -> list:
57
+ if data_frame is None:
58
+ return None
59
+ return json.loads(
60
+ data_frame.reset_index(names=index_name).to_json(
61
+ orient="records", date_format="iso"
62
+ )
63
+ )
64
+
65
+
66
+ def series_to_list(series: Series) -> list:
67
+ if series is None:
68
+ return None
69
+ return json.loads(series.reset_index().to_json(orient="records", date_format="iso"))
70
+
71
+
72
+ def validate_value_in_list(valid_values: list[str]) -> Callable[[str], str]:
73
+ def _validator(x: str) -> str:
74
+ if x in valid_values:
75
+ return x
76
+ raise typer.BadParameter(
77
+ f"Invalid value: {x}, should be one of {', '.join(valid_values)}"
78
+ )
79
+
80
+ return _validator
81
+
82
+
83
+ def validate_date_string(value: str) -> str:
84
+ """Validate date string format (YYYY-MM-DD)"""
85
+ try:
86
+ if len(value) != 10:
87
+ raise ValueError()
88
+ datetime.strptime(value, "%Y-%m-%d")
89
+ return value
90
+ except ValueError:
91
+ raise typer.BadParameter(f"Invalid date format: {value}. Use YYYY-MM-DD")
src/writer.py ADDED
@@ -0,0 +1,43 @@
1
+ import json
2
+ from typing import Protocol
3
+ from rich.table import Table
4
+ from .utils import console_print
5
+
6
+
7
+ class OutputWriter(Protocol):
8
+ def write(self, data: dict | list) -> None: ...
9
+
10
+
11
+ class WriterFactory:
12
+ @staticmethod
13
+ def get_writer(writer_type: str) -> OutputWriter:
14
+ if writer_type == "json":
15
+ return JsonWriter()
16
+ if writer_type == "table":
17
+ return TableWriter()
18
+ raise ValueError(f"Unsupported writer type: {writer_type}")
19
+
20
+
21
+ class JsonWriter(OutputWriter):
22
+ def write(self, data: dict | list) -> None:
23
+ console_print(json.dumps(data, indent=2, default=str))
24
+
25
+
26
+ class TableWriter(OutputWriter):
27
+ def write(self, data: dict | list) -> None:
28
+ table = Table(header_style="bold cyan")
29
+
30
+ if isinstance(data, dict):
31
+ data = [data]
32
+
33
+ if len(data) == 0:
34
+ console_print(table)
35
+ return
36
+
37
+ for key, value in data[0].items():
38
+ table.add_column(key)
39
+
40
+ for record in data:
41
+ table.add_row(*[str(value) for value in record.values()])
42
+
43
+ console_print(table)
@@ -0,0 +1,124 @@
1
+ Metadata-Version: 2.4
2
+ Name: yfin-cli
3
+ Version: 0.1.1
4
+ Summary: A command-line interface for Yahoo Finance data
5
+ License-Expression: MIT
6
+ License-File: LICENSE
7
+ Requires-Python: >=3.10
8
+ Requires-Dist: lxml>=6.0.2
9
+ Requires-Dist: rich>=14.2.0
10
+ Requires-Dist: typer>=0.21.1
11
+ Requires-Dist: yfinance>=1.1.0
12
+ Description-Content-Type: text/markdown
13
+
14
+ # yfin-cli
15
+
16
+ A command-line interface for Yahoo Finance data, powered by [yfinance](https://github.com/ranaroussi/yfinance).
17
+
18
+ ## Why yfin-cli
19
+
20
+ - Fast, scriptable access to Yahoo Finance data.
21
+ - JSON or table output for easy piping.
22
+ - Broad coverage: prices, financials, analyst data, screeners, sectors, industries.
23
+
24
+ ## Install
25
+
26
+ Requires Python 3.10+.
27
+
28
+ ### From PyPI (recommended)
29
+
30
+ ```bash
31
+ pipx install yfin-cli
32
+ # or
33
+ pip install yfin-cli
34
+ # or
35
+ uv tool install yfin-cli
36
+ ```
37
+
38
+ ### From source
39
+
40
+ ```bash
41
+ git clone <your-repo-url>
42
+ cd yfin-cli
43
+ uv tool install .
44
+ # or
45
+ pip install .
46
+ ```
47
+
48
+ ## Usage
49
+
50
+ ### Quickstart
51
+
52
+ ```bash
53
+ # Get historical stock data
54
+ yfin history AAPL
55
+
56
+ # Get quick summary metrics
57
+ yfin fast-info TSLA
58
+
59
+ # Check market status
60
+ yfin market-status
61
+
62
+ # View quarterly income statement
63
+ yfin income-stmt MSFT --frequency quarterly
64
+
65
+ # Get analyst recommendations
66
+ yfin recommendations NVDA
67
+
68
+ # Screen stocks
69
+ yfin screen --filter "sector eq Technology" --filter "intradaymarketcap gt 100000000000"
70
+
71
+ # Use a predefined screener
72
+ yfin screen --predefined day_gainers
73
+
74
+ # Output as a table
75
+ yfin --output table history AAPL --period 1y
76
+ ```
77
+
78
+ > For the complete command reference with all options and parameters, see [COMMANDS.md](COMMANDS.md).
79
+
80
+ ### Global options:
81
+
82
+ | Option | Description | Default |
83
+ | ---------- | ------------------------------- | ------- |
84
+ | `--output` | Output format (`json`, `table`) | `json` |
85
+ | `--help` | Show help message | — |
86
+
87
+ ## Available Commands
88
+
89
+ | Category | Commands |
90
+ | -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
91
+ | **Stock** | `history`, `dividends`, `fast-info`, `news` |
92
+ | **Market** | `market-status` |
93
+ | **Calendar** | `calendar-earnings`, `calendar-economic-events`, `calendar-ipo` |
94
+ | **Financials** | `income-stmt`, `balance-sheet`, `cashflow`, `earnings-dates`, `sec-filings` |
95
+ | **Analysis** | `recommendations`, `upgrades-downgrades`, `price-targets`, `earnings-estimate`, `revenue-estimate`, `earnings-history`, `eps-trend`, `eps-revisions`, `growth-estimates` |
96
+ | **Holders** | `insider-purchases`, `insider-transactions`, `insider-roster-holders`, `major-holders`, `institutional-holders`, `mutualfund-holders` |
97
+ | **Sector** | `sector-keys`, `sector-industries`, `sector-overview`, `sector-research-reports`, `sector-top-companies`, `sector-top-etfs`, `sector-top-mutual-funds` |
98
+ | **Industry** | `industry-overview`, `industry-research-reports`, `industry-top-companies`, `industry-top-growth-companies`, `industry-top-performing-companies` |
99
+ | **Screen** | `screen`, `screen-query-fields`, `screen-query-values`, `screen-predefined-queries` |
100
+
101
+ ## Development
102
+
103
+ This project uses uv for dependency management.
104
+
105
+ ```bash
106
+ # Install dependencies
107
+ uv sync
108
+
109
+ # Run the CLI
110
+ uv run yfin --help
111
+
112
+ # Run tests
113
+ uv run pytest
114
+
115
+ # Format code
116
+ uv run ruff format .
117
+
118
+ # Build package
119
+ uv build
120
+ ```
121
+
122
+ ## License
123
+
124
+ MIT
@@ -0,0 +1,20 @@
1
+ src/__init__.py,sha256=-aMOnBZnHvEG2-LRhGUjTFdQae8v9izcodgdi7Ycq8E,49
2
+ src/cli.py,sha256=cvoI9BMRnXxwg-bjjdhu3lZxNzt7j2iukvZ58b-RLUo,4243
3
+ src/decorators.py,sha256=dDWAyhQpGStIGK1lOHbAPNEUBja6J5Fpfd3J0cFGg28,1030
4
+ src/typer.py,sha256=-_6iu6-6WuuPOJZLJfEa6n3EBdR0VevE2Oic2sNsFp0,4687
5
+ src/utils.py,sha256=i55BB3R0kV5RMt3iaLe-VMIzjANZLSfG4lEVKbPDfiM,2321
6
+ src/writer.py,sha256=2o_CBC-Zhis5vGAE_xzJMCk25xoWou_RkAkkwJjvA6c,1108
7
+ src/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ src/commands/analysis.py,sha256=9adDjdOZsYARk6EmXYIuZtDZ8VnlOWVK8vo9-rW-dtg,3753
9
+ src/commands/calendar.py,sha256=x2iXVyMIu6i_-VmFnrLzt8uHpkML-tseXRFJAK0ChII,1900
10
+ src/commands/financials.py,sha256=Ffc9a0PCSE61-c34QWWluIikRS5QLdeRuqpeMikhy6E,1922
11
+ src/commands/industry.py,sha256=2yPy8-UfFd7htvCZy81lIDaGDQ4f6UW-UKR9LNZ5nJ8,1083
12
+ src/commands/market.py,sha256=jomhVsXGTIIjTvJkJr8YtQ7CJpi4GQjPLkKlZb7A2V8,187
13
+ src/commands/screen.py,sha256=UDKkJzDYJMJBcc5pHKDPZiy9UZcmL-gi_A7Cdhnrgik,8884
14
+ src/commands/sector.py,sha256=hXQTxMOdCgtGUqxOVMjARgwxL0-8pEQALgvs2U0qiDQ,1442
15
+ src/commands/stock.py,sha256=tbaYNx0kqXbKVOuUAJTwLUGSQI0uHVKt0Suc5dsN5Jc,2706
16
+ yfin_cli-0.1.1.dist-info/METADATA,sha256=63mEwvQKOkQBPpn0u7afjwFaBTS8EU1NKd640uQN5nM,4187
17
+ yfin_cli-0.1.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
18
+ yfin_cli-0.1.1.dist-info/entry_points.txt,sha256=AeTQvaF0pSSs34VdOcoGsJ_-Fjb47cPbhjO65l46aDg,37
19
+ yfin_cli-0.1.1.dist-info/licenses/LICENSE,sha256=k22ZS3asvWad8Mv9mA1YBc5zg7K0t5Ip94gQWIfpxR0,1065
20
+ yfin_cli-0.1.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.28.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ yfin = src.cli:app
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Rayyamhk
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.