One Python client for market data — crypto, Indian equities & options.
Same call everywhere. Get a pandas DataFrame or typed bars in three lines.
from bandl import Bandl, Interval
df = Bandl().crypto.get_ohlcv_dataframe("BTC/USDT", Interval.D1) # no API key neededOne client, one API. Switch markets by changing the symbol — not your code.
- 🟢 Zero-config crypto — Binance & CoinDCX public data, no keys.
- 🇮🇳 Indian equities & indices —
RELIANCE,NIFTY 50,BANKNIFTYvia Zerodha. - 📈 Options, incl. expired contracts — NSE/BSE F&O + MCX commodities via Dhan.
- 🐼 pandas or typed models —
get_ohlcv_dataframe(...)orget_ohlcv(...) -> list[OHLCV]. - ⏱️ Normalized everywhere — UTC timestamps,
Decimalprices, oneIntervalenum. - 🤖 Agent-ready — a dedicated AGENTS.md reference for LLM tools.
pip install bandlPython 3.10+. Dev setup: pip install -e ".[dev]" (CONTRIBUTING.md).
No API key required — crypto works out of the box:
from bandl import Bandl, Interval
client = Bandl()
df = client.crypto.get_ohlcv_dataframe("BTC/USDT", Interval.D1)
print(df.tail())
# timestamp open high low close volume
# 2025-01-10 00:00:00 94000.1 95200.0 92800.5 94850.2 12930.4451Want a window? Pass start / end (UTC). Want raw bars instead of pandas? Call
get_ohlcv(...) — same arguments, returns list[OHLCV].
from datetime import datetime, timedelta, timezone
end = datetime.now(timezone.utc)
start = end - timedelta(days=30)
bars = client.crypto.get_ohlcv("ETHUSDT", Interval.H1, start, end)
print(bars[-1].close, bars[-1].source)| Facet | Provider | Auth | Example symbols |
|---|---|---|---|
client.crypto |
binance |
None | BTC/USDT, ETHUSDT |
client.crypto |
coindcx |
None | BTCUSDT, ETHUSDT |
client.equity |
zerodha |
Kite key + token | RELIANCE, NIFTY 50, BANKNIFTY |
client.derivatives |
dhan |
Dhan id + JWT | GOLDM26JUN145000CE, NIFTY26JAN24000PE |
Every facet exposes the same two calls — get_ohlcv(...) and
get_ohlcv_dataframe(...). Pick a provider with source="...", or rely on each
facet's default.
Add your Kite Connect credentials once; the rest
is identical to crypto. Symbol aliases (NIFTY 50 → NIFTY50) are handled for you.
from bandl import Bandl, BandlConfig, Interval, ProviderSettings
client = Bandl(BandlConfig(providers={
"zerodha": ProviderSettings(api_key="kite_api_key", access_token="daily_token"),
}))
reliance = client.equity.get_ohlcv_dataframe("RELIANCE", Interval.D1, source="zerodha")
nifty = client.equity.get_ohlcv_dataframe("NIFTY 50", Interval.D1, source="zerodha")client.derivatives serves option OHLCV across NSE/BSE F&O and MCX commodities — with
open_interest on every bar. Give it a symbol string (auto-resolved against Dhan's
scrip master) or a structured OptionContract.
from datetime import date, datetime, timezone
from decimal import Decimal
from bandl import Bandl, BandlConfig, Interval, ProviderSettings
from bandl.models.market import OptionContract, OptionType
client = Bandl(BandlConfig(providers={
"dhan": ProviderSettings(api_key="dhan_client_id", access_token="dhan_jwt"),
}))
# 1) Symbol string — easiest
df = client.derivatives.get_ohlcv_dataframe(
"GOLDM26JUL145000CE", Interval.M5, source="dhan", exchange="MCX",
)
# 2) Structured contract — explicit & unambiguous
contract = OptionContract(
underlying="GOLDM", expiry=date(2026, 7, 29),
strike=Decimal("145000"), option_type=OptionType.CALL, exchange="MCX",
)
bars = client.derivatives.get_ohlcv(contract, Interval.M1, source="dhan")
# What expiries exist for an underlying?
expiries = client.derivatives.list_expiries("GOLDM", source="dhan", exchange="MCX")Need expired contracts? Most APIs drop them. bandl still fetches their minute
candles — pass the native instrument_id once (look it up via Dhan, or the bundled
examples/dhan_expired_probe.py):
bars = client.derivatives.get_ohlcv(
"GOLDM26JUN143500CE", Interval.M1,
datetime(2026, 6, 26, tzinfo=timezone.utc),
datetime(2026, 6, 27, tzinfo=timezone.utc),
source="dhan", exchange="MCX", instrument_id="570800",
)from bandl import OHLCV
bars: list[OHLCV] = client.crypto.get_ohlcv("BTCUSDT", Interval.H1)
bars[-1].close # Decimal — no float rounding
bars[-1].timestamp # tz-aware UTC datetimeclient.list_symbols(source="binance", search="BTC", limit=20)
client.list_symbols(source="zerodha", exchange="NSE",
instrument_types=("EQ",), search="RELI", limit=10)One enum maps to every provider's native interval. Timestamps come back UTC.
from bandl import Interval
Interval.M1, Interval.M5, Interval.H1, Interval.D1 # 1m / 5m / 1h / 1d
df["timestamp"] = df["timestamp"].dt.tz_convert("Asia/Kolkata") # → IST for displayfrom bandl import BandlConfig, ProviderSettings
config = BandlConfig(
providers={
"zerodha": ProviderSettings(api_key="...", access_token="..."),
"dhan": ProviderSettings(api_key="client_id", access_token="jwt"),
},
timeout_seconds=30,
default_crypto_provider="binance", # client.crypto default
default_equity_provider="zerodha", # client.equity default
default_derivatives_provider="dhan", # client.derivatives default
)| Provider | api_key |
access_token |
Notes |
|---|---|---|---|
zerodha |
Kite API key | daily token | Tokens expire daily — regenerate after login. 403 ⇒ expired/wrong token or no historical-API access. |
dhan |
client id | JWT | JWT generated in the Dhan web/app. Expired contracts leave the scrip master — fetch by instrument_id. |
binance / coindcx |
— | — | Public OHLCV needs no keys. |
Binance HTTP 451? Binance blocks some regions/cloud IPs (US, Colab). Use
source="coindcx"— same symbols, no key — or setdefault_crypto_provider="coindcx".CoinDCX empty
DataFrame? Its public feed can lag by months. Astart/endentirely after the feed raisesDataNotAvailableErrorwith the available span; pick an overlapping window.
Account history — orders, fills & PnL via client.account
fills = client.account.get_fills(start, end, source="coindcx")
pnl = client.account.get_pnl(start, end, source="zerodha", prefer="auto")
bundle = client.account.export_analysis_bundle(start, end)Full guide: docs/ACCOUNT_HISTORY.md.
Futures 24h leaders — rolling ticker stats
from bandl import AssetType
tickers = client.crypto.get_24hr_tickers(source="coindcx", asset_type=AssetType.CRYPTO_PERP)Runnable demos
cp examples/.env.example .env # add ZERODHA_* / DHAN_* to test authed providers
python examples/main.py
python examples/dhan_options.py
python examples/futures_24hr_leaders.py --source coindcxAGENTS.md is a purpose-built reference (provider matrix, recipes, errors) for LLM coding tools. It is not shipped in the PyPI wheel — point your agent at the GitHub link:
https://github.com/stockalgo/bandl/blob/master/AGENTS.md
Pin a tag (e.g. .../blob/v0.4.0/AGENTS.md) for a fixed version. See
agents/README.md.
- docs/BANDL.md — layout & design notes
- docs/ACCOUNT_HISTORY.md — account facet
- CONTRIBUTING.md — tests, Ruff, pull requests
- SECURITY.md — reporting vulnerabilities
pytest tests/bandl/
ruff check lib/bandl tests/bandl- Live streams / WebSockets
- More brokers & deeper commodity history
- Richer
SymbolInfoand fundamentals
PRs welcome — read CONTRIBUTING.md and CODE_OF_CONDUCT.md first.