Skip to main content

A Python package for fetching historical data from Zerodha API Using Account Credentials.

Project description

Zerodha Data Fetcher

PyPI version Python versions Tests License Downloads

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

  • 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
  • pip or uv available 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:

Zerodha TOTP Setup Guide

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 range
  • token_expiry_hours: Token validity period
  • cache_ttl_minutes: Instrument cache TTL in minutes
  • chunk_failure_mode: "strict" or "partial"
  • user_id: Runtime override for ZERODHA_USER_ID
  • password: Runtime override for ZERODHA_PASSWORD
  • totp_secret: Runtime override for ZERODHA_TOTP_SECRET
  • user_type: Runtime override for ZERODHA_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 raises DataFetchError and 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 handlers
  • console_format and file_format can be set independently when log_format is 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 handling
  • search_symbols(partial_name, limit=10): search the instrument data for matching trading symbols
  • get_instrument_info(symbol): return instrument metadata for a symbol when available

Package Helpers

  • setup_logging(...): configure console and optional rotating file logging
  • refresh_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

zerodha_data_fetcher-1.2.0.tar.gz (2.0 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

zerodha_data_fetcher-1.2.0-py3-none-any.whl (2.1 MB view details)

Uploaded Python 3

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

Hashes for zerodha_data_fetcher-1.2.0.tar.gz
Algorithm Hash digest
SHA256 9909b7e263db2c8a840a110782019a5147c8aed4f5514e040f58a96a81b81e46
MD5 9442231dd726c47973e235331562346e
BLAKE2b-256 a4808d2167cecba118950f7919ce7ceaa5e13412583b9159fe8f05ed2d2ea5bf

See more details on using hashes here.

Provenance

The following attestation bundles were made for zerodha_data_fetcher-1.2.0.tar.gz:

Publisher: publish.yml on JayceeGupta/Zerodha-Data-Fetcher

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file zerodha_data_fetcher-1.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for zerodha_data_fetcher-1.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5ec08f981893f8c0449b4c2dc5bea227902fd14c2a695d39e9b4d04ac000ea3c
MD5 d8d24b934a306b8f4b1b94fa0e424609
BLAKE2b-256 a3b316305441d2ace28deb7795962e92fe5adb89a5f52b7c3a502f76069fa028

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page