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
- Create an app at developers.kite.trade — you get an
api_keyandapi_secret, and you register a redirect URL (use a plainhttp://127.0.0.1:<port>/). - Static IP registration for order placement (SEBI rule). Reads work without it.
- 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_sizeandstrikecome 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 bysegment == "INDICES". Trustinginstrument_typealone would classify all 220 indices as tradeable equities. The adapter maps them toInstrumentType.IDXcorrectly. - No option-chain endpoint and no greeks endpoint.
get_option_chainis assembled from the master plus batched quotes.OptionContract.greeksis alwaysNonehere — Kite has nothing to merge. Use the Fyers or Upstox adapter if you need greeks. Instrument.isinis alwaysNone— Kite's master has no ISIN column. Join against other brokers onexchange_token(RELIANCE is2885on Groww, Fyers, Dhan and Zerodha alike).- Streaming runs on the Twisted global reactor.
KiteTicker.stop()callsreactor.stop(), which is process-wide and irreversible, so this adapter'sclose()deliberately closes only the socket. "full" mode is used rather than "quote" because the quote packet carries no timestamp field at all. Tick.minute_ohlcis alwaysNone— 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
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 brokerkit_zerodha-1.0.3.tar.gz.
File metadata
- Download URL: brokerkit_zerodha-1.0.3.tar.gz
- Upload date:
- Size: 33.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
228b83eb18529fd451dc087e352f55dfcc6e27e18f28fbccc0cd2f3e48688cb0
|
|
| MD5 |
e37792f9e04a3f0edd43a171f34dd95c
|
|
| BLAKE2b-256 |
d820b7f3110292f75d9873750ad9525b41b828d2915784507bf615964d34b79c
|
File details
Details for the file brokerkit_zerodha-1.0.3-py3-none-any.whl.
File metadata
- Download URL: brokerkit_zerodha-1.0.3-py3-none-any.whl
- Upload date:
- Size: 36.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
473e6d292200de21e4ad3cac1fb66c17fbf9599a9c0fc31ee5f159639f551da3
|
|
| MD5 |
af3592e7334dbe53e505961afc32594c
|
|
| BLAKE2b-256 |
d27fe015fe5b261350fae6dbf09efa8dbbf6263805b56a962887e253509ba4be
|