Skip to main content

brokerkit-zerodha

BrokerKit's Zerodha adapter — wraps the official kiteconnect SDK behind BrokerKit's broker-agnostic interfaces (auth, instruments, orders, portfolio, market data, historical candles, streaming), plus two Zerodha-only extras: charges and GTT.

pip install brokerkit-core brokerkit-zerodha

Read this first: two things Zerodha does differently

1. There is no programmatic login. At all. Kite Connect has no TOTP, no password grant, nothing headless — verified against the SDK source (zero TOTP/2FA references anywhere in kiteconnect) and the official docs, which describe only the browser flow. You open Zerodha's login page, log in there, and the redirect carries a request_token you exchange for an access_token. That token expires at 6:00 AM IST the next day, so this is a once-a-day step.

renew_access_token exists in the SDK, but Zerodha only issues the refresh_token it needs to "certain approved platforms" — a personal app generally never receives one, so there is no unattended refresh.

2. The free plan has no market data. This is the inverse of Groww and Dhan:

Plan Price Includes
Personal free orders, GTT, portfolio, margins — no live data, no historical
Connect ₹500/month everything above plus WebSocket streaming and historical candles

So on a free app, market, historical and streaming fail with a permission error. That is your subscription, not a bug — the adapter's error message says so explicitly.

There is also no sandbox of any kind (unlike Upstox and Dhan), so order writes additionally need SEBI static-IP registration with no way around it.

Prerequisites

  1. Create an app at developers.kite.trade — you get an api_key and api_secret, and you register a redirect URL (use a plain http://127.0.0.1:<port>/).
  2. Static IP registration for order placement (SEBI rule). Reads work without it.
  3. The ₹500/mo Connect plan, only if you need market data / historical / streaming.

Quick start

Mint a token once a day:

python -m brokerkit_zerodha.login_helper <api_key> <api_secret> http://127.0.0.1:5001/

This opens the browser and captures the redirect with a local server — nothing to copy-paste. (Port 5001, not 5000: macOS AirPlay Receiver squats on 5000 by default.)

Then reuse the printed token all day:

import asyncio
import os

from brokerkit import Exchange, Segment, create_broker


async def main():
    broker = await create_broker(
        "zerodha",
        api_key=os.environ["ZERODHA_API_KEY"],
        api_secret=os.environ["ZERODHA_API_SECRET"],
        access_token=os.environ["ZERODHA_ACCESS_TOKEN"],
    )

    instruments = await broker.instruments.fetch_instruments()
    reliance = next(
        i for i in instruments
        if i.symbol == "RELIANCE"
        and i.exchange == Exchange.NSE
        and i.segment == Segment.CASH
    )

    print(await broker.portfolio.holdings())
    await broker.close()


asyncio.run(main())

Omit access_token and pass redirect_uri= instead, and create() will run the browser login itself — right for an interactive first run, wrong for anything unattended.

Extras

broker.charges — pre-trade cost estimate

Implements the core ChargesProvider via Kite's virtual contract note.

from decimal import Decimal
from brokerkit.enums import Product, TransactionType

charges = await broker.charges.get_brokerage(
    reliance, quantity=10, product=Product.CNC,
    transaction_type=TransactionType.BUY, price=Decimal("1400"),
)
print(charges.total, charges.taxes.stt, charges.other_charges.sebi_turnover)

Works on the free plan.

broker.gtt — Good-Till-Triggered orders

A standing instruction that sits on Zerodha's servers (up to a year) and fires a real order when price crosses a trigger. No other broker in BrokerKit has this, so it is adapter-local with its own models rather than forced into OrderProvider — GTTs are a separate order book with their own endpoints and lifecycle, not an order type.

from decimal import Decimal
from brokerkit.enums import TransactionType
from brokerkit_zerodha import GttLeg

await broker.gtt.place(
    reliance,
    trigger_values=[Decimal("1500")],
    last_price=Decimal("1400"),          # current LTP; Kite validates against it
    legs=[GttLeg(transaction_type=TransactionType.SELL,
                 quantity=1, price=Decimal("1500"))],
)

for t in await broker.gtt.list_triggers():
    print(t.trigger_id, t.trading_symbol, t.status, t.trigger_values)

Two-leg (OCO — stop-loss and target together, whichever fires cancels the other) is supported with trigger_type="two-leg", two ascending trigger values and two legs.

Adapter notes

  • Instrument master is already in rupees. Unlike Dhan, Angel One and Upstox, no paise division is needed — tick_size and strike come through as-is. The master is a public CSV needing no auth (122,526 rows → 82,715 normalized instruments).
  • Index rows carry instrument_type "EQ". Kite's master has only four type values (EQ/FUT/CE/PE) and no index type; indices are identifiable only by segment == "INDICES". Trusting instrument_type alone would classify all 220 indices as tradeable equities. The adapter maps them to InstrumentType.IDX correctly.
  • No option-chain endpoint and no greeks endpoint. get_option_chain is assembled from the master plus batched quotes. OptionContract.greeks is always None here — Kite has nothing to merge. Use the Fyers or Upstox adapter if you need greeks.
  • Instrument.isin is always None — Kite's master has no ISIN column. Join against other brokers on exchange_token (RELIANCE is 2885 on Groww, Fyers, Dhan and Zerodha alike).
  • Streaming runs on the Twisted global reactor. KiteTicker.stop() calls reactor.stop(), which is process-wide and irreversible, so this adapter's close() deliberately closes only the socket. "full" mode is used rather than "quote" because the quote packet carries no timestamp field at all.
  • Tick.minute_ohlc is always None — Kite's feed has no server-computed minute candle. Aggregate ticks yourself.

Verification status

Live-verified against a real account: auth, instruments, portfolio, orders (read), and charges end to end.

Blocked by account state rather than by code: market / historical / streaming / option chain need the paid Connect plan; order and GTT writes need SEBI static IP, with no sandbox available to sidestep it.

License

MIT © 2026 Aditya Vishwakarma

Metadata

Release files for brokerkit-zerodha 1.0.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for brokerkit-zerodha 1.0.3
File Size Uploaded Provenance Actions
brokerkit_zerodha-1.0.3.tar.gz 33.1 kB Without provenance Details for brokerkit_zerodha-1.0.3.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for brokerkit-zerodha 1.0.3
File Interpreter ABI Platform Actions
brokerkit_zerodha-1.0.3-py3-none-any.whl Python 3 none any Details for brokerkit_zerodha-1.0.3-py3-none-any.whl

Total release size: 70.0 kB

Release files / brokerkit_zerodha-1.0.3.tar.gz

Download URL brokerkit_zerodha-1.0.3.tar.gz
Size 33.1 kB
Tags Source
SHA-256 checksum
How to use checksums
228b83eb18529fd451dc087e352f55dfcc6e27e18f28fbccc0cd2f3e48688cb0
BLAKE2b-256 checksum
How to use checksums
d820b7f3110292f75d9873750ad9525b41b828d2915784507bf615964d34b79c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.6

Release files / brokerkit_zerodha-1.0.3-py3-none-any.whl

Download URL brokerkit_zerodha-1.0.3-py3-none-any.whl
Size 36.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
473e6d292200de21e4ad3cac1fb66c17fbf9599a9c0fc31ee5f159639f551da3
BLAKE2b-256 checksum
How to use checksums
d27fe015fe5b261350fae6dbf09efa8dbbf6263805b56a962887e253509ba4be
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.6

Security for brokerkit-zerodha 1.0.3

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A 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.

Release history Release notifications | RSS feed

This release

1.0.3 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page