BrokerKit
One async Python interface over six Indian brokers — Groww, Fyers, Upstox, Dhan, Angel One and Zerodha.
Every broker ships its own SDK with its own auth flow, its own symbol format, its own units (some report prices in paise, some in rupees), its own error convention (some raise, some return a failure dict, some silently return status: false) and its own idea of what a "quote" contains. BrokerKit normalizes all of that behind one typed, async contract, so strategy code doesn't change when the broker does.
from brokerkit import create_broker
broker = await create_broker("zerodha", api_key=..., api_secret=..., access_token=...)
instruments = await broker.instruments.fetch_instruments()
reliance = next(i for i in instruments if i.symbol == "RELIANCE")
quote = await broker.market.get_quote(reliance)
print(quote.last_price, quote.volume)
await broker.close()
Swap "zerodha" for "fyers" and the rest of that code is unchanged.
Status
The core contract is stable across six adapters. What varies is per-broker coverage, and where it stops it is almost always an account-state or regulatory wall rather than missing code. Nothing in the table below is aspirational — it reflects what has actually been run against real accounts.
| Groww | Fyers | Upstox | Dhan | Angel One | Zerodha | |
|---|---|---|---|---|---|---|
| auth | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| instruments | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| market / historical | 🔒 paid | ✅ | ✅ | 🔒 paid | ✅ | 🔒 paid |
| streaming | 🔒 paid | ✅ | ✅ | 🔒 paid | ⏳ | 🔒 paid |
| portfolio | ✅ | ⏳ | 🔒 oauth | ✅ | ✅ | ✅ |
| orders (read) | ⏳ | ⏳ | 🔒 oauth | ✅ | ✅ | ✅ |
| orders (write) | 🔒 ip | 🔒 ip | ✅ sandbox | 🔒 ip | 🔒 ip | 🔒 ip |
✅ verified against a real account · ⏳ implemented, not yet exercised live · 🔒 blocked
- paid — the broker charges for market data (Groww ~₹499/mo, Dhan Data API, Zerodha ₹500/mo).
- ip — SEBI requires a registered static IP for API order placement. Only Upstox and Dhan offer a sandbox that sidesteps it; Angel One and Zerodha do not, so their write paths may stay unverifiable.
- oauth — Upstox's order/portfolio token needs a real browser login daily, with no headless refresh.
Install
Not on PyPI yet, so install from the repo. Always install brokerkit-core plus the adapters you actually want — there is no need to install all six.
git clone https://github.com/dellindone/brokerkit.git
cd brokerkit
Pick one of the two cases below. The only thing that decides which is whether you need Groww and Fyers together.
Case 1 — you do NOT need both Groww and Fyers (almost everyone)
One command, any combination:
pip install ./packages/brokerkit-core \
./packages/brokerkit-zerodha \
./packages/brokerkit-angelone
Swap in whichever adapters you want: brokerkit-groww, brokerkit-fyers, brokerkit-upstox, brokerkit-dhan, brokerkit-angelone, brokerkit-zerodha. Just don't list Groww and Fyers in the same command.
Done. pip check will be clean.
Case 2 — you need both Groww and Fyers
These two cannot be resolved together in one pip install, so run three commands in this order:
# 1. everything except Groww
pip install ./packages/brokerkit-core \
./packages/brokerkit-fyers \
./packages/brokerkit-upstox \
./packages/brokerkit-dhan \
./packages/brokerkit-angelone \
./packages/brokerkit-zerodha
# 2. now add Groww (this pulls aiohttp forward to 3.14.x)
pip install ./packages/brokerkit-groww
# 3. put aiohttp back where Fyers needs it
pip install "aiohttp==3.9.3"
Then check it worked:
python -c "
from brokerkit.assembly.factory import _resolve
for n in ['groww','fyers','upstox','dhan','angelone','zerodha']:
print(n, '->', _resolve(n).__name__)
"
Expect pip check to complain after Case 2 — it will say growwapi wants aiohttp>=3.11.18 but you have 3.9.3. That warning is correct and unavoidable; the setup still works (verified end to end: both adapters resolve and both fetch their real instrument masters). Treat it as a deliberate workaround, not a supported configuration.
Why this conflict exists
It is upstream, not this project. fyers-apiv3 pins aiohttp exactly (==3.9.3 on the current 3.1.14, ==3.8.4 on older releases), while growwapi requires aiohttp>=3.11.18. No version of either satisfies both, and listing order makes no difference — both orders were tested and fail identically. In practice both SDKs run fine on 3.9.3, so the pins are stricter than the real need.
Do not reach for pip install --no-deps growwapi. --no-deps also skips growwapi's legitimate dependencies (pandas, nats-py, protobuf), and importing the adapter then fails with ModuleNotFoundError: No module named 'pandas'.
Developing on BrokerKit itself
Add -e to any of the commands above for an editable install, so source edits take effect without reinstalling:
pip install -e ./packages/brokerkit-core -e ./packages/brokerkit-zerodha
Once published
pip install brokerkit[zerodha]
pip install brokerkit[zerodha,upstox,dhan]
pip install brokerkit[all]
brokerkit[all] means every adapter that can coexist in one resolution — that is Fyers, Upstox, Dhan, Angel One and Zerodha. Groww is excluded on purpose: including it would make [all] fail for everyone, for the upstream reason described above. Install it explicitly with brokerkit[groww], and follow Case 2 if you want it alongside Fyers.
Architecture
A monorepo of independent distributions. brokerkit-core never imports an adapter; create_broker("zerodha", ...) lazily imports brokerkit_zerodha, which self-registers. Adding a broker touches no core code.
packages/
brokerkit-core/ # the `brokerkit` package: models, interfaces, assembly
brokerkit-groww/ # brokerkit_groww
brokerkit-fyers/ # brokerkit_fyers
brokerkit-upstox/ # brokerkit_upstox
brokerkit-dhan/ # brokerkit_dhan
brokerkit-angelone/ # brokerkit_angelone
brokerkit-zerodha/ # brokerkit_zerodha
examples/ # one runnable example per broker
Hyphens are the pip distribution name, underscores the importable module — hyphens are illegal in module names.
The contract
Every broker exposes the same seven providers:
| Attribute | Interface | What it does |
|---|---|---|
broker.instruments |
InstrumentProvider |
fetch_instruments() → normalized master |
broker.orders |
OrderProvider |
place / modify / cancel / get / list |
broker.portfolio |
PortfolioProvider |
holdings, positions |
broker.market |
MarketDataProvider |
quote, ltp, ohlc, option chain |
broker.historical |
HistoricalDataProvider |
candles |
broker.streaming |
StreamingProvider |
live tick subscription |
broker.auth |
AuthProvider |
login, token lifecycle |
Everything is async; adapters wrap sync vendor SDKs with asyncio.to_thread. Models are Pydantic v2 with Decimal prices. State is instance-scoped, so BrokerManager can hold several accounts at once.
Broker-specific extras
Capabilities only some brokers have live off the shared base rather than being forced into it:
| Broker | Extras |
|---|---|
| Upstox | fundamentals news market_information charges risk_control sandbox_orders |
| Dhan | global_stocks (US equities) risk_control sandbox_orders |
| Angel One | charges analytics |
| Zerodha | charges gtt |
charges implements a shared ChargesProvider interface; the rest are adapter-local because no other broker has an equivalent.
Auth, per broker
| Broker | Mechanism | Daily friction |
|---|---|---|
| Groww | TOTP | none — token expires 6 AM IST, auto-refreshed |
| Fyers | TOTP + PIN | none, but a new app needs one browser activation first |
| Upstox | Analytics Token (data) / OAuth (orders) | none for data; OAuth needs a daily browser login |
| Dhan | TOTP + PIN | none — but token generation is rate-limited to 1 per 2 min |
| Angel One | TOTP + MPIN | none — native refresh-token flow |
| Zerodha | browser only | a browser login every day |
Zerodha is the outlier: Kite Connect has no TOTP and no programmatic login of any kind, and its token dies at 6 AM IST. brokerkit_zerodha.get_access_token() captures the redirect with a local server so it is one click, and the token can then be passed back in to skip the browser for the rest of the day.
Examples
examples/<broker>/main.py — one per broker, each written around that broker's actual strengths, with every known wall handled explicitly. See examples/README.md for the comparison tables.
Two things to know if you're building a data pipeline
- Only Upstox provides a server-computed live 1-minute candle (
Tick.minute_ohlc). For Fyers, Dhan, Angel One and Zerodha it staysNone— you aggregate ticks yourself. - ISIN is the natural cross-broker join key, but Angel One's and Zerodha's masters have no ISIN column (
isinis alwaysNone). Join those onexchange_tokeninstead — it matches exactly across Groww, Fyers, Dhan and Zerodha (RELIANCE is2885on all of them).
Development
The repo's own correctness checks worth re-running after any adapter change:
- Cross-broker instrument diff — normalize the same real instruments through every adapter and compare. This is the highest-value check here: it once caught a 100x
tick_sizebug in the Upstox adapter that had been live for months and was invisible in isolation. get_type_hintssweep over every provider method — catches annotation breakage that Python 3.14's deferred evaluation (PEP 649) otherwise hides until runtime.- Dependency audit — declared dependencies vs actually imported modules, per package.
Each adapter's own README carries its design decisions, the SDK quirks found by reading source, and an explicit split between what is live-verified and what is still written from docs.
License
MIT © 2026 Aditya Vishwakarma <vaditya098@gmail.com>
See LICENSE.
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-1.0.3.tar.gz.
File metadata
- Download URL: brokerkit-1.0.3.tar.gz
- Upload date:
- Size: 20.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/6.2.0 CPython/3.14.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
72eb3abbbe16bc0b434e0a2fd777f9617e28434b0c90349664863a1fd4cc890d
|
|
| MD5 |
318f58ed83541c9712e315c2673f10c8
|
|
| BLAKE2b-256 |
ec8fa662c033ca2b86a52a6d4d61cff9305f9e10a3bf220b8773b8cb7e244b8e
|
File details
Details for the file brokerkit-1.0.3-py3-none-any.whl.
File metadata
- Download URL: brokerkit-1.0.3-py3-none-any.whl
- Upload date:
- Size: 6.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 |
22e7de23b30653db0184f2c62212989f554b35704cb26f46f6d87c95b63388e1
|
|
| MD5 |
e92619e06157a769b9674cf0a34bb403
|
|
| BLAKE2b-256 |
7f521a03da23ab065ab6b0f87ae92e54450f9ae460250d85cfa1b1b8095dc3b0
|