brokerkit-dhan
BrokerKit's Dhan adapter — wraps the official dhanhq SDK behind BrokerKit's broker-agnostic interfaces (auth, instruments, orders, portfolio, market data, historical candles, streaming), plus three Dhan-only extras: US equities, risk control and a sandbox.
pip install brokerkit-core brokerkit-dhan
This is the broadest-scope adapter in BrokerKit. Dhan is a second live-execution account, the only source of Global Stocks (US equity trading — no other broker here has it), and the source of real risk tooling.
Prerequisites
- Enable TOTP on the account first — web.dhan.co → DhanHQ APIs → Setup TOTP. Without it, token generation fails.
- Your
client_idand loginpin. - Static IP registration for order placement (SEBI rule). Reads work without it.
- Data API subscription — required for market data, historical candles, option chain and streaming. Without it those calls fail on subscription (historical returns a clean
DH-902), same posture as Groww. - US account activation, only if you want Global Stocks holdings/funds. Instruments and market status work without it.
Quick start
import asyncio
import os
from brokerkit import Exchange, Segment, create_broker
async def main():
broker = await create_broker(
"dhan",
client_id=os.environ["DHAN_CLIENT_ID"],
pin=os.environ["DHAN_PIN"],
totp_secret=os.environ["DHAN_TOTP_SECRET"],
# Strongly recommended — see below
access_token=os.environ.get("DHAN_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())
Use the access_token passthrough. Dhan rate-limits token generation to once every 2 minutes, so re-running a script repeatedly will hit "Token can be generated once every 2 minutes." Generate once, reuse it; pin + totp_secret are still used for the 24-hour refresh.
Extras
broker.global_stocks — US equities
Core models genuinely cannot represent this — core OrderRequest.quantity is an int but Global Stocks supports fractional shares, core Exchange has no US value, and prices are USD — so this has its own adapter-local models (GlobalInstrument, GlobalOrder, GlobalHolding, GlobalFundLimit, GlobalMarketStatus).
us = await broker.global_stocks.fetch_instruments() # ~11,458 US instruments
aapl = next(i for i in us if i.symbol == "AAPL")
print(aapl.security_id, aapl.exchange, aapl.fractional)
print(await broker.global_stocks.market_status())
Holdings and fund limits need US onboarding on the account (INX-1007 otherwise); instruments and market status do not.
broker.risk_control — kill switch + P&L auto-exit
await broker.risk_control.kill_switch_status()
await broker.risk_control.activate_kill_switch()
await broker.risk_control.get_pnl_exit()
Dhan's kill switch is account-wide (Upstox's is per-segment).
broker.sandbox_orders — order writes without the static-IP wall
Pass sandbox_access_token= (from developer.dhanhq.co) and broker.sandbox_orders gets wired. Dhan's sandbox covers a much broader surface than Upstox's — full order CRUD and reads.
It is deliberately a separate attribute from broker.orders, never merged, so a real order can never be confused with a sandbox one.
Adapter notes
tick_sizein the instrument master is in paise — the adapter divides by 100. Verified against real rows: a ₹1400 stock cannot have a ₹10 tick.- Both instrument CSVs are needed. The detailed CSV has ISIN and underlying but no trading symbol; the compact one has the symbol but neither of those. The adapter fetches both concurrently and joins them (195,524 instruments).
- Empty holdings arrive as a failure envelope, not
[]. Dhan returnsDH-1111 "No holdings available"as an error; the adapter translates it to an empty list. - Streaming uses Quote mode (17), not Ticker (15), specifically so
Tick.volumepopulates — Ticker mode carries no volume. Tick.minute_ohlcis alwaysNone— Dhan's feed carries day OHLC only, no server-computed minute candle. Aggregate ticks yourself.- Uses
dhanhq==2.3.0rc1, a pre-release, deliberately. It is the only version with Global Stocks at all, and diffing it against stable 2.2.0 from source showed it is purely additive — no changed or removed signatures.
Verification status
Live-verified: auth, instruments, portfolio, order list, Global Stocks instruments and market status, risk-control reads.
Blocked by account state rather than by code: market / historical / option chain / streaming need the paid Data API subscription (so their response parsing is written from docs and not yet live-confirmed); Global Stocks holdings and funds need US activation; real order writes need SEBI static IP or a sandbox token.
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_dhan-1.0.3.tar.gz.
File metadata
- Download URL: brokerkit_dhan-1.0.3.tar.gz
- Upload date:
- Size: 27.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 |
60aec75390538cd14e73482a933db9eb8bc3986e1c5e13340c2ae154f966c5e1
|
|
| MD5 |
62a1548d1c6bf56610d5f5cb97975915
|
|
| BLAKE2b-256 |
121cefa2add008fce34600f70788fdb64d73d2cc5b4956563007ef974172be5a
|
File details
Details for the file brokerkit_dhan-1.0.3-py3-none-any.whl.
File metadata
- Download URL: brokerkit_dhan-1.0.3-py3-none-any.whl
- Upload date:
- Size: 30.8 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 |
c054bee2ae2c72ee96ca382bd16194f050b2299955802d45bcb9ed2f279982c2
|
|
| MD5 |
135fb073c21d5c8e08d5c236396847db
|
|
| BLAKE2b-256 |
e33b15f00f3fcdd85a998b146206c5b13accf9be28e1099588ef3d4b586ca9f8
|