Production-grade NSE data engine for Python. Cache-first, circuit-protected, async-ready.
Project description
nsefetch
Production-grade NSE data engine for Python. Cache-first, circuit-protected, async-ready.
pip install nsefetch
Quick Start
from nsefetch import MarketService
with MarketService() as service:
quote = service.get_stock("RELIANCE")
print(quote.data.last_price) # e.g. 2947.35
chain = service.get_option_chain("NIFTY")
print(chain.data.expiry) # nearest expiry date
Features
- ⚡ Cache-first runtime — in-process or Redis-backed, with per-operation TTLs
- 🔌 Circuit breaker — automatic failure isolation and recovery
- 🔄 Request coalescing — deduplicates concurrent identical requests within a process
- 🚦 GCRA rate limiter — Redis or in-memory, prevents NSE from rate-limiting you
- 🌊 Stale fallback — serves cached data gracefully on live fetch failure
- ⚙️ Async parity — every sync method has an exact async equivalent
- 🛡️ Typed responses — Pydantic v2 models on every response, always a
ResponseEnvelope[T] - 🧪 131 tests — zero live-network calls in normal test runs
- 🔒 NSE-only — no silent Yahoo Finance substitution; you always know what you're getting
API Reference
All methods are available on both MarketService (sync) and AsyncMarketService (async).
| Method | Description |
|---|---|
get_nifty50() |
NIFTY 50 index snapshot |
get_index(index_name) |
Any supported NSE index snapshot |
get_stock(symbol) |
Single-symbol equity quote |
get_bulk_stocks(symbols) |
Multi-symbol equity quotes with smart batching |
get_option_chain(symbol, expiry=None) |
Option chain; defaults to nearest expiry |
get_option_chain_expiries(symbol) |
All available option expiry dates |
get_futures_data(symbol) |
F&O futures snapshot |
get_delivery_data(symbol) |
Delivery / DPIIT data |
get_market_depth(symbol) |
Level-2 order book (optional data) |
get_sector_data() |
All NSE sector snapshots |
Every method returns ResponseEnvelope[T] with:
envelope.success # bool
envelope.data # typed payload
envelope.cache_hit # bool — was this served from cache?
envelope.stale # bool — was this a stale cache fallback?
envelope.degraded # bool — did a backend component fail?
envelope.fetched_at # datetime
envelope.warnings # list of WarningInfo
Runtime Modes
Direct (default)
Simple. No Redis, no background infrastructure needed.
from nsefetch import MarketService
service = MarketService()
quote = service.get_stock("RELIANCE")
service.close()
# or use as a context manager
with MarketService() as service:
quote = service.get_stock("RELIANCE")
Cached (scripts & repeated polling)
Adds in-process LRU cache + rate limiter. Best for local scripts that poll repeatedly.
from nsefetch import create_cached_market_service
with create_cached_market_service() as service:
# First call hits NSE; subsequent calls within TTL hit cache
quote = service.get_stock("RELIANCE")
Production (Redis-backed)
For dashboard backends and multi-worker deployments. Keeps frontend traffic reading from cache instead of hammering NSE directly.
from nsefetch import create_production_market_service
with create_production_market_service() as service:
snapshot = service.get_nifty50()
Async
All three modes have async counterparts:
from nsefetch import AsyncMarketService, create_async_cached_market_service
async with AsyncMarketService() as service:
quote = await service.get_stock("INFY")
async with create_async_cached_market_service() as service:
chain = await service.get_option_chain("BANKNIFTY")
Option Chain with Specific Expiry
with MarketService() as service:
# Discover all available expiries
expiries = service.get_option_chain_expiries("NIFTY")
print(expiries.data) # ['2026-05-29', '2026-06-26', ...]
# Fetch a specific expiry
chain = service.get_option_chain("NIFTY", expiry="2026-06-26")
Architecture
graph TD
A[MarketService / AsyncMarketService] --> B[Rate Limiter]
B --> C[Cache Layer]
C -->|cache miss| D[Circuit Breaker]
D --> E[NSE HTTP Client]
E --> F[curl_cffi Transport]
F --> G[NSE API]
C -->|cache hit| H[ResponseEnvelope]
D -->|open| I[Stale Fallback Cache]
I --> H
| Layer | Component | Purpose |
|---|---|---|
| Service | MarketService |
Public API, context manager lifecycle |
| Reliability | CircuitBreaker |
Blocks requests when provider is failing |
| Reliability | RateLimiter |
GCRA — prevents NSE from blocking you |
| Caching | CacheManager |
In-memory or Redis, request coalescing |
| Transport | NSEHttpClient |
Browser-impersonating session (curl_cffi) |
| Normalizer | NSEMarketDataNormalizer |
Raw payload → typed Pydantic schemas |
Configuration
All settings are configurable via environment variables prefixed with NSEFETCH_:
# Redis connection (for production/cached modes)
NSEFETCH_REDIS_URL=redis://localhost:6379/0
# Cache TTLs (seconds)
NSEFETCH_CACHE_TTL_STOCK=15
NSEFETCH_CACHE_TTL_INDEX=10
NSEFETCH_CACHE_TTL_OPTION_CHAIN=30
# Circuit breaker
NSEFETCH_CIRCUIT_BREAKER_FAILURE_THRESHOLD=5
NSEFETCH_CIRCUIT_BREAKER_RECOVERY_WINDOW=60
# Rate limiter
NSEFETCH_RATE_LIMIT_REQUESTS_PER_SECOND=2
# Live probe gate
NSEFETCH_LIVE_PROBE_ENABLED=1
Or pass a Settings object directly:
from nsefetch import MarketService, Settings
settings = Settings(redis_url="redis://localhost:6379/0")
service = MarketService(settings=settings)
Live Probe
Test your connectivity to NSE before deploying:
# Transport-level probe
NSEFETCH_LIVE_PROBE_ENABLED=1 python -m nsefetch.live_probe
# Service-level probe (exercises all 10 methods)
NSEFETCH_LIVE_PROBE_ENABLED=1 python -m nsefetch.live_probe --service
# Both together
NSEFETCH_LIVE_PROBE_ENABLED=1 python -m nsefetch.live_probe --all
Contributing
Contributions are welcome! See CONTRIBUTING.md for setup instructions, coding standards, and PR guidelines.
Good first issues include: new index names, BSE provider, pandas integration, and export utilities.
Legal
This library is for educational and research purposes only. It is not affiliated with, endorsed by, or connected to the National Stock Exchange of India (NSE). Use at your own risk.
See DISCLAIMER.md for the full legal notice and LICENSE for the MIT license.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nsefetch-0.1.0.tar.gz.
File metadata
- Download URL: nsefetch-0.1.0.tar.gz
- Upload date:
- Size: 54.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2d4218b23c25d856b7cb839141de52f6ba86bf688d0ee9074d1696dc3ad5a7a2
|
|
| MD5 |
37dad51ba5ce20d34a1d130acee2fb10
|
|
| BLAKE2b-256 |
6d33a4d71c0b4600ef7aa428df8d52c8f12def76535d29e0ed7f8c9872327d4b
|
Provenance
The following attestation bundles were made for nsefetch-0.1.0.tar.gz:
Publisher:
publish.yml on harsh-kumar-rai/nsefetch
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nsefetch-0.1.0.tar.gz -
Subject digest:
2d4218b23c25d856b7cb839141de52f6ba86bf688d0ee9074d1696dc3ad5a7a2 - Sigstore transparency entry: 1550148180
- Sigstore integration time:
-
Permalink:
harsh-kumar-rai/nsefetch@d42d7fdd52a83d506e554da268c246d0d9df0792 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/harsh-kumar-rai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d42d7fdd52a83d506e554da268c246d0d9df0792 -
Trigger Event:
release
-
Statement type:
File details
Details for the file nsefetch-0.1.0-py3-none-any.whl.
File metadata
- Download URL: nsefetch-0.1.0-py3-none-any.whl
- Upload date:
- Size: 42.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f11563817c426cc929b3e0a3535260e6d860a2bc7a7aa18afa9db5c4600275fd
|
|
| MD5 |
e4567a3b7d16d59d0527a3f77a6c4d1f
|
|
| BLAKE2b-256 |
41b8b7002f7b0dcf3ea52905ae996ee01b9cdb63d4a9835a1d5de492a0570491
|
Provenance
The following attestation bundles were made for nsefetch-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on harsh-kumar-rai/nsefetch
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nsefetch-0.1.0-py3-none-any.whl -
Subject digest:
f11563817c426cc929b3e0a3535260e6d860a2bc7a7aa18afa9db5c4600275fd - Sigstore transparency entry: 1550148183
- Sigstore integration time:
-
Permalink:
harsh-kumar-rai/nsefetch@d42d7fdd52a83d506e554da268c246d0d9df0792 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/harsh-kumar-rai
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@d42d7fdd52a83d506e554da268c246d0d9df0792 -
Trigger Event:
release
-
Statement type: