A Python package for fetching historical data from Zerodha API Using Account Credentials.
Project description
Zerodha Data Fetcher
Python package for fetching historical market data from Zerodha's Kite web APIs with built-in authentication, rate limiting, instrument lookup, caching, and multi-account workflows.
Why Zerodha Data Fetcher?
Zerodha's Kite platform provides powerful market data, but programmatic access to historical data requires navigating authentication flows, managing rate limits, and handling session tokens. This library handles all of that so you can focus on analysis:
- No official API key needed -- authenticates through the Kite web interface using your existing account credentials
- Handles the full auth flow -- password login, TOTP 2FA, encrypted token caching in your OS keyring
- Production-grade reliability -- automatic retries, rate limiting, and configurable chunk failure modes
- Zero-config symbol resolution -- pass a symbol name like
"RELIANCE"instead of memorizing instrument tokens - Parallel fetching -- splits large date ranges into chunks and fetches them concurrently
Table of Contents
- Features
- Prerequisites
- Installation
- Quick Start
- TOTP Setup
- Configuration
- Runtime Configuration Override
- Historical Fetch Failure Modes
- Logging
- Multi-Account Parallel Processing
- Instrument Data Caching
- API Reference
- Error Handling
- Development
- Contributing
- Security
- License
- Disclaimer
- Support
Features
- Fast parallel historical data fetching with request pacing
- Automatic authentication flow with password, TOTP, and token handling
- Support for instrument tokens and symbol-based lookups
- Strict-by-default chunk failure handling for correctness-sensitive workloads
- Runtime overrides for environment-based configuration
- Instrument metadata search and caching
- Multi-account patterns for high-volume retrieval
- Structured logging with separate console and file formats
Prerequisites
Before using the package, make sure you have:
- Python 3.8 or newer
- A Zerodha account with Kite access
- TOTP enabled on that account
piporuvavailable in your environment
Installation
pip install zerodha-data-fetcher
For development:
uv sync --all-extras
Quick Start
TOTP Setup
Set up TOTP for your Zerodha account before using the package:
Environment Variables
Create a .env file in your project root:
# Required credentials
ZERODHA_USER_ID=your_user_id
ZERODHA_PASSWORD=your_password
ZERODHA_TOTP_SECRET=your_totp_secret
# Optional configurations
ZERODHA_TYPE=user_id
ZERODHA_BASE_URL=https://kite.zerodha.com
ZERODHA_LOGIN_URL=https://kite.zerodha.com/api/login
ZERODHA_2FA_URL=https://kite.zerodha.com/api/twofa
ZERODHA_HISTORICAL_URL=https://kite.zerodha.com/oms/instruments/historical/{token}/{timeframe}?user_id={userid}&oi=1&from={current_date}&to={next_date}
ZERODHA_KEYRING_TOKEN_KEY=zerodha_auth_token
ZERODHA_KEYRING_ENCRYPTION_KEY=zerodha_encryption_key
ZERODHA_INSTRUMENT_CACHE_TTL=1440
Basic Usage
from datetime import date, timedelta
from zerodha_data_fetcher import ZerodhaDataFetcher, setup_logging
setup_logging(log_level="INFO", log_file="logs/zerodha_fetcher.log")
fetcher = ZerodhaDataFetcher(
requests_per_second=3,
chunk_failure_mode="strict",
)
end_date = date.today()
start_date = end_date - timedelta(days=30)
data = fetcher.fetch_historical_data(
ticker_token=408065,
start_date=start_date,
end_date=end_date,
timeframe="minute",
)
print(f"Retrieved {len(data)} records")
print(data.head())
reliance_data = fetcher.fetch_historical_data(
ticker_token="RELIANCE",
start_date=start_date,
end_date=end_date,
timeframe="minute",
)
print(f"Retrieved {len(reliance_data)} records for RELIANCE")
print(reliance_data.head())
search_results = fetcher.search_symbols("TATA", limit=5)
print(search_results[["Instrument_Token", "Name", "Exchange"]])
instrument_info = fetcher.get_instrument_info("INFY")
print(instrument_info)
Authentication logs are sanitized by default. TOTP values, raw auth response bodies, headers, cookies, and encrypted token material are never written to the logs.
Configuration
Environment Variables
| Variable | Description | Required | Default |
|---|---|---|---|
ZERODHA_USER_ID |
Zerodha user ID | Yes | - |
ZERODHA_PASSWORD |
Zerodha password | Yes | - |
ZERODHA_TOTP_SECRET |
TOTP secret for 2FA | Yes | - |
ZERODHA_TYPE |
Account type (user_id or corporate) |
No | user_id |
ZERODHA_BASE_URL |
Zerodha base URL | No | https://kite.zerodha.com |
ZERODHA_LOGIN_URL |
Login endpoint URL | No | https://kite.zerodha.com/api/login |
ZERODHA_2FA_URL |
2FA endpoint URL | No | https://kite.zerodha.com/api/twofa |
ZERODHA_HISTORICAL_URL |
Historical API URL template | No | Built-in template |
ZERODHA_KEYRING_TOKEN_KEY |
Keyring token storage key | No | zerodha_auth_token |
ZERODHA_KEYRING_ENCRYPTION_KEY |
Keyring encryption key | No | zerodha_encryption_key |
ZERODHA_INSTRUMENT_CACHE_TTL |
Instrument cache TTL in minutes | No | 1440 |
Only ZERODHA_USER_ID, ZERODHA_PASSWORD, and ZERODHA_TOTP_SECRET are required for normal use.
Class Parameters
requests_per_second: API rate limit, clamped to the library's supported rangetoken_expiry_hours: Token validity periodcache_ttl_minutes: Instrument cache TTL in minuteschunk_failure_mode:"strict"or"partial"user_id: Runtime override forZERODHA_USER_IDpassword: Runtime override forZERODHA_PASSWORDtotp_secret: Runtime override forZERODHA_TOTP_SECRETuser_type: Runtime override forZERODHA_TYPE
Runtime Configuration Override
You can override environment variables during class instantiation:
fetcher = ZerodhaDataFetcher(
requests_per_second=3,
chunk_failure_mode="strict",
user_id="override_user_id",
password="override_password",
totp_secret="override_totp_secret",
user_type="user_id",
)
This is useful when credentials or account context need to be supplied at runtime instead of through a local .env file.
Historical Fetch Failure Modes
Historical data fetching defaults to strict correctness.
chunk_failure_mode="strict": any failed chunk raisesDataFetchErrorand no partial data is returned.chunk_failure_mode="partial": successful chunks are returned, failed ranges are summarized in a warning log, and an exception is raised only if all chunks fail.
You can set the default on the fetcher instance or override it per call:
fetcher = ZerodhaDataFetcher(chunk_failure_mode="strict")
strict_data = fetcher.fetch_historical_data(
"INFY",
start_date=start_date,
end_date=end_date,
)
partial_data = fetcher.fetch_historical_data(
"INFY",
start_date=start_date,
end_date=end_date,
chunk_failure_mode="partial",
)
Logging
setup_logging() uses separate defaults for console and file output.
- Console output is compact and human-readable, for example:
(20:30:29) - [INFO] - zerodha_data_fetcher.core.data_fetcher fetch_historical_data: Data fetch completed successfully
- File output includes timestamp, logger, function, line number, and thread name.
Customize each handler independently:
setup_logging(
log_level="INFO",
log_file="logs/zerodha_fetcher.log",
console_format="%(asctime)s %(levelname)s %(message)s",
file_format="%(asctime)s | %(levelname)s | %(name)s | %(funcName)s:%(lineno)d | %(threadName)s | %(message)s",
)
Behavior notes:
log_format=...still overrides both handlersconsole_formatandfile_formatcan be set independently whenlog_formatis not provided- Default console dates use
%H:%M:%S - Default file dates use
%Y-%m-%d %H:%M:%S
Multi-Account Parallel Processing
For large data retrieval jobs, you can create multiple fetcher instances with different credentials to spread work across accounts.
from concurrent.futures import ThreadPoolExecutor
from datetime import date, timedelta
from zerodha_data_fetcher import ZerodhaDataFetcher
accounts = [
{
"user_id": "account1_id",
"password": "account1_password",
"totp_secret": "account1_totp_secret",
},
{
"user_id": "account2_id",
"password": "account2_password",
"totp_secret": "account2_totp_secret",
},
{
"user_id": "account3_id",
"password": "account3_password",
"totp_secret": "account3_totp_secret",
},
]
def fetch_data_with_account(account_config, symbols_batch):
fetcher = ZerodhaDataFetcher(
requests_per_second=3,
user_id=account_config["user_id"],
password=account_config["password"],
totp_secret=account_config["totp_secret"],
)
results = {}
end_date = date.today()
start_date = end_date - timedelta(days=30)
for symbol in symbols_batch:
try:
data = fetcher.fetch_historical_data(
ticker_token=symbol,
start_date=start_date,
end_date=end_date,
timeframe="minute",
)
results[symbol] = data
print(f"Fetched {len(data)} records for {symbol} on {account_config['user_id']}")
except Exception as exc:
print(f"Failed to fetch {symbol} on {account_config['user_id']}: {exc}")
results[symbol] = None
return results
all_symbols = [
"RELIANCE",
"HDFC",
"INFY",
"TCS",
"ICICIBANK",
"SBIN",
"BAJFINANCE",
"BHARTIARTL",
"HDFCBANK",
]
symbols_per_account = len(all_symbols) // len(accounts)
symbol_batches = [
all_symbols[i:i + symbols_per_account]
for i in range(0, len(all_symbols), symbols_per_account)
]
if len(symbol_batches) > len(accounts):
symbol_batches[-2].extend(symbol_batches[-1])
symbol_batches.pop()
with ThreadPoolExecutor(max_workers=len(accounts)) as executor:
futures = []
for i, account in enumerate(accounts):
if i < len(symbol_batches):
futures.append(executor.submit(fetch_data_with_account, account, symbol_batches[i]))
all_results = {}
for future in futures:
all_results.update(future.result())
print(f"Completed fetching data for {len(all_results)} symbols across {len(accounts)} accounts")
Instrument Data Caching
The package bundles a snapshot of Zerodha's instrument list and keeps a fresh copy in your local cache directory.
How It Works
- On first use, the package attempts to download the latest instrument data from
https://api.kite.trade/instruments. - If the cached file is younger than the TTL, no download is attempted.
- If the download fails, the bundled snapshot is used as a fallback and a warning is logged.
Configuration
| Method | Example |
|---|---|
| Environment variable | ZERODHA_INSTRUMENT_CACHE_TTL=60 |
| Constructor | ZerodhaDataFetcher(cache_ttl_minutes=60) |
| Constructor | ZerodhaInstrumentManager(cache_ttl_minutes=60) |
If ZERODHA_INSTRUMENT_CACHE_TTL is invalid, the library logs one warning and falls back to 1440 minutes instead of crashing.
Manual Refresh
from zerodha_data_fetcher import refresh_instruments
refresh_instruments()
Cache location:
- Windows:
%LOCALAPPDATA%\zerodha_data_fetcher\Cache\ - Linux/macOS:
~/.cache/zerodha_data_fetcher/
API Reference
ZerodhaDataFetcher
Main class for fetching historical data.
Methods:
fetch_historical_data(ticker_token, start_date, end_date, timeframe="minute", chunk_failure_mode=None): fetch historical data with strict-by-default chunk failure handlingsearch_symbols(partial_name, limit=10): search the instrument data for matching trading symbolsget_instrument_info(symbol): return instrument metadata for a symbol when available
Package Helpers
setup_logging(...): configure console and optional rotating file loggingrefresh_instruments(): force-refresh the instrument cache, ignoring TTL
Error Handling
The package exposes dedicated exception types for common failure modes:
from zerodha_data_fetcher.utils.exceptions import (
AuthenticationError,
DataFetchError,
InvalidTickerError,
ZerodhaAPIError,
)
try:
data = fetcher.fetch_historical_data("INVALID", start_date, end_date)
except InvalidTickerError as exc:
print(f"Invalid ticker: {exc}")
except AuthenticationError as exc:
print(f"Authentication failed: {exc}")
except DataFetchError as exc:
print(f"Data fetch failed: {exc}")
except ZerodhaAPIError as exc:
print(f"Unexpected Zerodha API error: {exc}")
Development
Contributor setup and workflow guidance live in CONTRIBUTING.md.
Typical local workflow:
uv sync --all-extras
uv run pytest
uv run black .
uv run flake8
uv run mypy src/
Contributing
Contributions are welcome across bug fixes, docs, tests, and new features.
- Read CONTRIBUTING.md before opening a pull request
- Follow the expectations in CODE_OF_CONDUCT.md
- Never include real Zerodha credentials in code, issues, or examples
Security
Please review SECURITY.md for supported versions, private vulnerability reporting, and credential exposure guidance.
License
This project is licensed under the MIT License. See LICENSE for details.
Disclaimer
This package is for educational and research purposes. Make sure your usage complies with Zerodha's terms of service and any applicable laws or regulations.
Support
Project details
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 zerodha_data_fetcher-1.2.0.tar.gz.
File metadata
- Download URL: zerodha_data_fetcher-1.2.0.tar.gz
- Upload date:
- Size: 2.0 MB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9909b7e263db2c8a840a110782019a5147c8aed4f5514e040f58a96a81b81e46
|
|
| MD5 |
9442231dd726c47973e235331562346e
|
|
| BLAKE2b-256 |
a4808d2167cecba118950f7919ce7ceaa5e13412583b9159fe8f05ed2d2ea5bf
|
Provenance
The following attestation bundles were made for zerodha_data_fetcher-1.2.0.tar.gz:
Publisher:
publish.yml on JayceeGupta/Zerodha-Data-Fetcher
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
zerodha_data_fetcher-1.2.0.tar.gz -
Subject digest:
9909b7e263db2c8a840a110782019a5147c8aed4f5514e040f58a96a81b81e46 - Sigstore transparency entry: 1396974416
- Sigstore integration time:
-
Permalink:
JayceeGupta/Zerodha-Data-Fetcher@13972acc1dbecdadf1a66596e78a222880e917ae -
Branch / Tag:
refs/tags/v1.2.0 - Owner: https://github.com/JayceeGupta
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@13972acc1dbecdadf1a66596e78a222880e917ae -
Trigger Event:
push
-
Statement type:
File details
Details for the file zerodha_data_fetcher-1.2.0-py3-none-any.whl.
File metadata
- Download URL: zerodha_data_fetcher-1.2.0-py3-none-any.whl
- Upload date:
- Size: 2.1 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5ec08f981893f8c0449b4c2dc5bea227902fd14c2a695d39e9b4d04ac000ea3c
|
|
| MD5 |
d8d24b934a306b8f4b1b94fa0e424609
|
|
| BLAKE2b-256 |
a3b316305441d2ace28deb7795962e92fe5adb89a5f52b7c3a502f76069fa028
|
Provenance
The following attestation bundles were made for zerodha_data_fetcher-1.2.0-py3-none-any.whl:
Publisher:
publish.yml on JayceeGupta/Zerodha-Data-Fetcher
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
zerodha_data_fetcher-1.2.0-py3-none-any.whl -
Subject digest:
5ec08f981893f8c0449b4c2dc5bea227902fd14c2a695d39e9b4d04ac000ea3c - Sigstore transparency entry: 1396974432
- Sigstore integration time:
-
Permalink:
JayceeGupta/Zerodha-Data-Fetcher@13972acc1dbecdadf1a66596e78a222880e917ae -
Branch / Tag:
refs/tags/v1.2.0 - Owner: https://github.com/JayceeGupta
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@13972acc1dbecdadf1a66596e78a222880e917ae -
Trigger Event:
push
-
Statement type: