BharatStock Python Client
Official Python client for the BharatStock API — reliable Indian stock market data (NSE/BSE): EOD prices, quarterly/annual financials, shareholding patterns, corporate actions, derived per-stock metrics, a screener, bulk/block deals, insider trades, indices, and market-wide FII/DII activity.
📋 Jump to Changelog — what's new in each release.
Install
pip install bharatstock
Requires Python 3.9+ (the only dependency is httpx).
To work on the client from a checkout of this repo, install it editable:
pip install -e sdk/python
Authentication
Every data endpoint is authenticated with your bsk_live_... key, sent in the
X-API-Key header. Get one from the dashboard.
from bharatstock import BharatStock
# Pass the key explicitly...
client = BharatStock(api_key="bsk_live_...")
# ...or set BHARATSTOCK_API_KEY in the environment and omit it:
client = BharatStock()
Quickstart
from bharatstock import BharatStock
client = BharatStock(api_key="bsk_live_...")
# A single stock, with latest price + ~70 derived metrics
stock = client.stocks.get("RELIANCE")
print(stock.company_name, stock.exchange)
print("P/E:", stock.metrics.pe_ratio, "ROE:", stock.metrics.roe)
# Batch quotes for a watchlist (one call, up to 50 symbols)
for q in client.stocks.quotes(["TCS", "INFY", "HDFCBANK"]):
print(q.symbol, q.close, q.change_pct)
# Search
for hit in client.search("tata"):
print(hit.symbol, hit.company_name)
# Public data-integrity status (no key required)
print(client.status().status) # "operational" | "degraded"
Pagination
List endpoints return a Page object: iterate it directly for the rows, or read
.total_pages / .has_next to page through manually.
# One page
page = client.stocks.prices("RELIANCE", from_date="2026-01-01", page_size=100)
print(page.total_items, page.total_pages)
for row in page:
print(row.trade_date, row.close, row.adjusted_close)
# Auto-iterate every stock across all pages (lazy generator)
for s in client.stocks.iter_all(sector="Banking"):
print(s.symbol)
Date ranges use from_date= / to_date= (sent to the API as from / to),
in YYYY-MM-DD form.
Screener
results = client.screener.run(
filters=["pe_ratio.lt.15", "roe.gt.18", "market_cap.gt.10000"], # Cr
sort_by="roe",
sort_order="desc",
page_size=25,
)
for r in results:
print(r.symbol, r.pe_ratio, r.roe)
Filter syntax is metric.operator.value where the operator is one of
gt | lt | gte | lte | eq. market_cap values are in Crores.
Rate limits & retries
Plans have a daily request cap. When you exceed it the API returns HTTP 429.
The client automatically retries a 429 a few times with exponential backoff
(the API does not send a Retry-After header, so the wait is client-side); if
it's still capped it raises RateLimitError.
from bharatstock import BharatStock, RateLimitError, NotFoundError
client = BharatStock(api_key="bsk_live_...", max_retries=3)
try:
stock = client.stocks.get("NONEXISTENT")
except NotFoundError:
print("no such ticker")
except RateLimitError as e:
print("slow down:", e.detail)
All errors subclass BharatStockError, so you can catch that one type to handle
any API failure. Specific subclasses: AuthenticationError (401),
NotFoundError (404), RateLimitError (429), BadRequestError (400/422),
APIError (everything else).
Method reference
Every method and its parameters. Types ship with the package (py.typed), so
your editor autocompletes each method and every field on the returned objects.
Keyword-only params show their default; page/page_size are omitted from the
notes below but accepted by every paginated method. Methods that return Page
are paginated (iterate directly, or use .total_pages / .has_next); the rest
return a single object or a plain list.
client.stocks
| Method | Key parameters | Returns |
|---|---|---|
list(...) |
q=None, sector=None, active_only=True |
Page[StockSummary] |
iter_all(...) |
q=None, sector=None, active_only=True (lazy, walks all pages) |
iterator of StockSummary |
get(ticker, exchange=None) |
ticker accepts a symbol or ISIN; exchange = "NSE"/"BSE" to disambiguate a shared ticker |
StockDetail |
quotes(symbols) |
symbols: list of up to 50 tickers |
list[QuoteItem] (unknown symbols returned with found=False) |
compare(sector, ...) |
sort = market_cap|pe_ratio|pb_ratio|roe|roce (default market_cap), limit=20 |
list[ComparisonItem] |
prices(ticker, ...) |
from_date=None, to_date=None (YYYY-MM-DD), exchange=None |
Page[DailyPricePoint] |
financials(ticker, ...) |
period_type = quarterly|annual (default quarterly), exchange=None |
Page[FinancialPeriod] |
ratios(ticker, exchange=None) |
— | RatioSnapshot |
corporate_actions(ticker, ...) |
action_type=None (dividend|bonus|split|rights|buyback), exchange=None |
Page[CorporateActionItem] |
technical_indicators(ticker, ...) |
from_date, to_date, sma_period=20, ema_period=20, rsi_period=14, exchange=None |
Page[TechnicalIndicatorPoint] |
shareholding(ticker, ...) |
exchange=None |
Page[ShareholdingPatternItem] |
mf_holdings(ticker, ...) |
month=None (YYYY-MM), exchange=None |
Page[MFHoldingItem] |
bulk_deals(ticker, ...) |
buy_sell=None (BUY|SELL), exchange=None |
Page[DealItem] |
block_deals(ticker, ...) |
buy_sell=None (BUY|SELL), exchange=None |
Page[DealItem] |
insider_trades(ticker, ...) |
transaction_type=None (acquisition|disposal), promoters_only=False, exchange=None |
Page[InsiderTradeItem] |
client.deals (market-wide, across all stocks)
| Method | Key parameters | Returns |
|---|---|---|
bulk(...) |
buy_sell=None (BUY|SELL) |
Page[DealItem] |
block(...) |
buy_sell=None (BUY|SELL) |
Page[DealItem] |
insider_trades(...) |
transaction_type=None (acquisition|disposal), promoters_only=False |
Page[InsiderTradeItem] |
client.screener
| Method | Key parameters | Returns |
|---|---|---|
run(...) |
filters=None (list of metric.operator.value), sector=None, exchange=None, sort_by="market_cap", sort_order="desc" (asc|desc) |
Page[ScreenerResult] |
client.indices
| Method | Key parameters | Returns |
|---|---|---|
list(...) |
category=None, active_only=True |
Page[IndexSummary] |
prices(name, ...) |
from_date=None, to_date=None (YYYY-MM-DD) |
Page[IndexPricePoint] |
client.market
| Method | Key parameters | Returns |
|---|---|---|
fii_dii(...) |
from_date=None (default 30 days before to), to_date=None (default today), limit=30, latest=False (only the single most recent day; ignores from/to/limit) |
FiiDiiActivity (.data is a list of FiiDiiDay) |
client.mutual_funds
The industry-wide AMFI scheme NAV dataset — every scheme/plan/option across
all AMCs, keyed by AMFI scheme_code (distinct from stocks.mf_holdings,
which is which schemes hold a given stock).
| Method | Key parameters | Returns |
|---|---|---|
list_schemes(...) |
q=None, amc=None, category=None (e.g. "Flexi Cap"), plan=None ("Direct"/"Regular"), option=None ("Growth"/"IDCW"), isin=None, limit=50, offset=0 |
MFSchemeList (.data is a list of MFScheme) |
get_scheme(scheme_code) |
MFScheme (incl. latest_nav, latest_nav_date) |
|
nav(scheme_code, ...) |
from_date=None (default 1y), to_date=None, limit=400 (free-tier keys limited to a recent window) |
MFNavHistory (.data is a list of MFNavPoint) |
returns(scheme_code) |
MFSchemeReturns (.returns_pct maps 1m/3m/6m/1y/3y/5y/since_inception → % (CAGR for ≥1y), computed from NAV) |
Top-level helpers
| Method | Key parameters | Returns |
|---|---|---|
client.search(q, limit=10) |
fuzzy match on symbol or company name | list[StockSummary] |
client.movers(category="gainers", limit=20) |
category = gainers|losers|active |
list[MoverItem] |
client.price_shockers(min_change_pct=5.0, direction="both", limit=50) |
direction = up|down|both |
list[PriceShockerItem] |
client.status() |
no auth required | StatusReport (.status, .checks, .is_operational) |
Notes
market_capunits differ by endpoint (this mirrors the current API, so the client reports exactly what the server sends):- Rupees:
stocks.get,stocks.list/iter_all,search(StockSummary/StockDetail.market_cap),stocks.compare(ComparisonItem), andstocks.ratios(RatioSnapshot). - Crores (1 Cr = 10,000,000): the metrics block on
stocks.get(StockDetail.metrics.market_cap) andscreener.run(ScreenerResult). - The
screener.runmarket_capfilter value is also in Crores (e.g."market_cap.gt.10000"= > 10,000 Cr). Sostock.market_capandstock.metrics.market_capon the same object are in different units (rupees vs Crores) — divide the rupee value by 1e7 to compare. Convert withcrores = rupees / 10_000_000.
- Rupees:
- Use the client as a context manager (
with BharatStock(...) as c:) to close the underlying HTTP connection pool when you're done. - Types ship with the package (
py.typed), so editors autocomplete every method and response field.
Changelog
- 0.1.8 (2026-09-15): Packaging metadata only — the PyPI sidebar
Changeloglink now points at this README's own Changelog section on the PyPI page (pypi.org/project/bharatstock/#user-content-changelog) instead of the external docs site. No code, API, or behavior changes. - 0.1.7 (2026-09-15): Packaging metadata only — the PyPI sidebar
Changeloglink now points at the docs-site changelog section (bharatstockapi.com/reference.html#changelog, a real anchor) and a "Jump to Changelog" link was added at the top of this README. No code, API, or behavior changes. - 0.1.6 (2026-09-15): Packaging metadata only — added a
Changelogproject URL and a standaloneCHANGELOG.md. No code, API, or behavior changes. - 0.1.5 (2026-09-15): Documentation and metadata refresh for the Mutual
Funds surface — no code or behavior changes, fully backward compatible.
The
MutualFundsresource is now completely documented in the README with runnable examples: list and search the full universe of AMFI schemes (client.mutual_funds.list_schemes(...), filter by AMC / plan / option / category), fetch a single scheme's identity and latest NAV (client.mutual_funds.get_scheme(scheme_code)), pull its daily NAV time series going back as far as ~20 years for backtesting and SIP/rolling-return analysis (client.mutual_funds.nav(scheme_code, from_date=..., to_date=...), server-side capped at 5000 points per call — page withfrom_date/to_date), and read trailing returns computed from that NAV series (client.mutual_funds.returns(scheme_code)→1m/3m/6m/1y/3y/5y/since_inception, where ≥1-year horizons are annualized CAGR). All response models are fully typed (MFSchemeList,MFScheme,MFNavHistory,MFSchemeReturns). Free-tier keys are limited to ~1 year of NAV history; paid tiers get the full archive. - 0.1.4: Added the
MutualFundsresource (client.mutual_funds) — the first release with mutual fund coverage. Introducedlist_schemes(),get_scheme(),nav()andreturns()plus their typed response dataclasses (MFSchemeList,MFScheme,MFNavHistory,MFSchemeReturns), backed by the AMFI industry-wide daily NAV feed and the returns endpoint (1m/3m/6m/1y/3y/5y/since-inception). No breaking changes to the existing stock / deals / screener / indices / market resources.
License
MIT
Metadata
Release files for bharatstock 0.1.8
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| bharatstock-0.1.8.tar.gz | 25.5 kB | With provenance | Details for bharatstock-0.1.8.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| bharatstock-0.1.8-py3-none-any.whl | Python 3 | none | any | Details for bharatstock-0.1.8-py3-none-any.whl |
Total release size: 45.8 kB
Release files / bharatstock-0.1.8.tar.gz
| Download URL | bharatstock-0.1.8.tar.gz |
|---|---|
| Size | 25.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
881fb8a4088e9b234539d3af620434ebbd954ef6c58604dac7936f0509e62e3c
|
|
BLAKE2b-256 checksum How to use checksums |
8aa73b02ff58be5e4785e1f7aaca467005bc41200dfbc5a43740280782968e62
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 18, 2026.
Transparency logRelease files / bharatstock-0.1.8-py3-none-any.whl
| Download URL | bharatstock-0.1.8-py3-none-any.whl |
|---|---|
| Size | 20.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a1a9f6e774312031e52173d947f31e2fade3c2aff7ab890de87ecb70e30aaef3
|
|
BLAKE2b-256 checksum How to use checksums |
e345b346684caeb5a73fd62d73fed0affc6984410955ecd4f40b97975aa99c1f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 18, 2026.
Transparency logSecurity for bharatstock 0.1.8
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for bharatstock-0.1.8.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 18, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.