finfetch 0.2.1
Free financial data for Indian stocks — no API key needed.
Requires Python: >=3.10
Keywords: finance, stocks, india, nse, bse, scraper, screener, pandas

# finfetch

Free financial data for Indian stocks. No API key needed.

`finfetch` scrapes publicly available data, returning clean **pandas DataFrames** with normalised field names. One `pip install` and you're ready — no extra setup, no reinstalling to fetch data.

## Installation

```bash
pip install finfetch
```

That's it. Everything is installed automatically. No separate install steps, no system packages to manage.

## Quick Start

```python
import finfetch as ff

stock = ff.Ticker("RELIANCE")

# Current price (INR)
stock.price

# Company info (dict of key ratios)
stock.info

# Annual income statement
stock.financials

# Other statements
stock.balance_sheet
stock.cashflow
stock.ratios
stock.quarterly_financials

# Historical OHLCV price data
stock.history(period="1y")
```

## NSE Industry Classification

Get the exact 4-level NSE industry hierarchy for any listed stock:

```python
c = ff.fetch_classification("TECHM")
print(c.breadcrumb())
# Information Technology > Information Technology > IT - Software > Computers - Software & Consulting

print(c.macro_economic_sector)  # "Information Technology"
print(c.sector)                 # "Information Technology"
print(c.industry)               # "IT - Software"
print(c.basic_industry)         # "Computers - Software & Consulting"

c.to_dict()  # returns all 4 levels as a plain dict
```

Also available via CLI:

```bash
finfetch classify RELIANCE
```

## Indian Index Data

Fetch historical data and live snapshots for 15 major Indian indices (NIFTY 50, SENSEX, Bank Nifty, sectoral indices, India VIX):

```python
# Historical data for an index
df = ff.fetch_index_data("NIFTY 50", period="6mo")

# Current snapshot of all indices
snapshot = ff.fetch_index_snapshot()
#        Index     Ticker   Current  Change  Change %
# 0   NIFTY 50     ^NSEI  23472.45  159.30      0.68
# 1     SENSEX   ^BSESN  77186.74  523.45      0.68
# ...

# List all supported indices
ff.list_indices()
# {"NIFTY 50": "^NSEI", "SENSEX": "^BSESN", ...}
```

CLI:

```bash
finfetch index "NIFTY 50" --period 6mo --export xlsx
finfetch indices --export both
```

**Supported indices:** NIFTY 50, SENSEX, NIFTY BANK, NIFTY IT, NIFTY MIDCAP 100, NIFTY SMALLCAP 100, NIFTY PHARMA, NIFTY METAL, NIFTY AUTO, NIFTY FMCG, NIFTY ENERGY, NIFTY REALTY, NIFTY INFRA, NIFTY FIN SERVICE, INDIA VIX.

## Price History

```python
# Default: 1 year of daily data
stock.history()

# Custom period
stock.history(period="5y")
stock.history(period="1mo", interval="1h")

# Custom date range
stock.history(start="2022-01-01", end="2023-12-31")

# Weekly/monthly bars
stock.history(period="2y", interval="1wk")
stock.history(period="10y", interval="1mo")

# Dividend and split history
stock.dividends
stock.splits
```

**Available periods:** `1d`, `5d`, `1mo`, `3mo`, `6mo`, `1y`, `2y`, `5y`, `10y`, `ytd`, `max`

**Available intervals:** `1m`, `2m`, `5m`, `15m`, `30m`, `60m`, `90m`, `1h`, `1d`, `5d`, `1wk`, `1mo`, `3mo`

## Custom Timelines (Fundamentals)

```python
# Up to 20+ years of P&L
stock.get_financials(years=20)

# Specific year range
stock.get_balance_sheet(from_year=2005, to_year=2015)

# From a year onwards
stock.get_cashflow(from_year=2010)

# Quarterly with timeline filter
stock.get_quarterly_financials(years=3)
```

## Export to Excel & CSV

Export any DataFrame to `.xlsx` and/or `.csv` with auto-adjusted column widths:

```python
df = stock.financials
ff.export_data(df, "reliance_pl", fmt="xlsx")   # → ./finfetch_exports/reliance_pl.xlsx
ff.export_data(df, "reliance_pl", fmt="csv")    # → ./finfetch_exports/reliance_pl.csv
ff.export_data(df, "reliance_pl", fmt="both")   # both files

# Custom output directory
ff.export_data(df, "reliance_pl", fmt="xlsx", output_dir="./my_exports")
```

The CLI `--export` flag works on index commands:

```bash
finfetch index "NIFTY 50" --period 1y --export xlsx
finfetch indices --export both
```

## Multiple Tickers

```python
tickers = ff.Tickers("RELIANCE TCS INFY")
tickers["RELIANCE"].price
tickers["TCS"].financials

for t in tickers:
    print(t.ticker, t.price)
```

## Convenience Functions

```python
# Quick price lookup
ff.get_price("RELIANCE")

# Search for tickers
ff.search("Reliance")
# [{"symbol": "RELIANCE", "name": "Reliance Industries", "url": "..."}, ...]

# List all available canonical field names
ff.available_fields()
ff.available_fields("pl")   # fields for P&L only
```

## CLI

After `pip install`, the `finfetch` command is available globally:

```bash
# Industry classification
finfetch classify RELIANCE

# Index historical data
finfetch index "NIFTY 50" --period 6mo --export csv

# All indices snapshot
finfetch indices --export both

# Version
finfetch --version
```

## Features

- **Price history** — OHLCV data (daily, weekly, monthly, intraday)
- **Dividends & splits** — full history
- **Quarterly results** — quarterly P&L
- **Annual fundamentals** — P&L, balance sheet, cash flow, ratios
- **Extended history** — 20+ years of financial data
- **NSE industry classification** — exact 4-level hierarchy (Macro Sector > Sector > Industry > Basic Industry)
- **Indian index data** — 15 major indices
- **Excel & CSV export** — one-line export with auto-column-widths
- **CLI tool** — `finfetch` command for terminal usage
- **Lazy loading** — data is only fetched when you access a property
- **Built-in caching** — results cached per Ticker instance
- **Retry with backoff** — handles rate limits and transient errors
- **Normalised output** — canonical field names, NaN for missing values
- **No API keys** — pure web scraping of publicly available data
- **Rate limiting** — built-in per-domain rate limiter to avoid getting blocked
- **Single install** — `pip install finfetch` gets everything, no extra steps

## Consolidated vs Standalone

```python
stock = ff.Ticker("RELIANCE", view="standalone")
stock = ff.Ticker("RELIANCE", view="consolidated")  # default
```

## Output Format

**Financial DataFrames** (financials, balance_sheet, cashflow, ratios):
- **Index**: Canonical field names (e.g., `revenue`, `net_profit`, `operating_profit`)
- **Columns**: Period labels normalised to `Mon YYYY` format (e.g., `Mar 2024`)
- **Values**: `float64` in Crores (INR) for monetary fields, percentages as-is
- **Missing data**: `NaN`

**Price history DataFrame** (from `stock.history()`):
- **Index**: `DatetimeIndex`
- **Columns**: `open`, `high`, `low`, `close`, `volume`
- **Values**: Prices in INR, volume in shares

## Available Fields

Use `ff.available_fields()` to see all canonical field names:

| Statement | Fields |
|---|---|
| P&L | `revenue`, `revenue_gross`, `excise_and_levies`, `total_revenue`, `total_expenses`, `operating_profit`, `operating_direct_expenses`, `opm_pct`, `other_income`, `interest_expense`, `depreciation`, `profit_before_exceptional`, `profit_before_tax`, `tax_expense`, `tax_pct`, `current_tax`, `deferred_tax`, `mat_credit`, `tax_earlier_years`, `net_profit`, `eps`, `eps_basic`, `eps_diluted`, `dividend_payout_pct`, `dividend_per_share`, `raw_material_cost`, `employee_cost`, `other_expenses`, `purchase_stock_in_trade`, `inventory_change`, `sga_expense`, `exceptional_items`, `extraordinary_items`, `prior_period_items`, `minority_interest`, `associate_profit_share`, `equity_share_dividend`, `tax_on_dividend`, `equity_dividend_rate`, `imported_raw_materials`, `indigenous_raw_materials`, `imported_stores_and_spares`, `indigenous_stores_and_spares` |
| Balance Sheet | `equity_capital`, `total_share_capital`, `reserves`, `shareholders_funds`, `total_borrowings`, `long_term_borrowings`, `short_term_borrowings`, `other_liabilities`, `total_liabilities`, `fixed_assets`, `tangible_assets`, `intangible_assets`, `intangible_under_dev`, `cwip`, `goodwill`, `investments`, `non_current_investments`, `current_investments`, `other_assets`, `total_assets`, `inventories`, `trade_receivables`, `cash_and_equivalents`, `trade_payables`, `deferred_tax_asset`, `deferred_tax_liability`, `long_term_provisions`, `short_term_provisions`, `long_term_loans_advances`, `short_term_loans_advances`, `other_current_assets_detail`, `other_current_liabilities`, `other_long_term_liabilities`, `other_non_current_assets`, `total_current_assets`, `total_current_liabilities`, `total_non_current_assets`, `total_non_current_liabilities`, `contingent_liabilities`, `book_value`, `minority_interest` |
| Cash Flow | `cfo`, `cfi`, `cff`, `net_cash_flow`, `cf_capex`, `cf_depreciation`, `cf_interest_paid`, `cf_interest_received`, `cf_tax_paid`, `cf_dividends_paid`, `cf_dividend_received`, `cf_investment_purchase`, `cf_investment_sale`, `cf_asset_sale`, `cf_borrowing_proceeds`, `cf_borrowing_repayment` |
| Ratios | `debtor_days`, `inventory_days`, `days_payable`, `cash_conversion_cycle`, `working_capital_days`, `roce_pct`, `roe_pct`, `roa_pct`, `current_ratio`, `quick_ratio`, `debt_equity_ratio`, `total_debt_equity`, `interest_cover`, `pe_ratio`, `pb_ratio`, `ps_ratio`, `ev_ebitda`, `earnings_yield`, `opm_pct`, `npm_pct`, `gpm_pct`, `asset_turnover`, `inventory_turnover`, `debtors_turnover`, `fixed_asset_turnover`, `revenue`, `operating_profit`, `net_profit`, `pbdit`, `pbit`, `pbt`, `eps_basic`, `eps_cash`, `eps_diluted`, `book_value`, `dividend_per_share`, `dividend_payout_pct` |

## Error Handling

```python
from finfetch import TickerNotFoundError, DataUnavailableError, RateLimitError

try:
    stock = ff.Ticker("INVALID")
    data = stock.financials
except TickerNotFoundError as e:
    print(f"Bad ticker: {e}")
except DataUnavailableError as e:
    print(f"No data: {e}")
except RateLimitError as e:
    print(f"Rate limited: {e}")
```

## Building from Source

```bash
pip install build
python -m build
# Output: dist/finfetch-0.2.01-py3-none-any.whl
```