Skip to main content

bandl

One Python client for market data — crypto, Indian equities & options.
Same call everywhere. Get a pandas DataFrame or typed bars in three lines.

PyPI Python License


from bandl import Bandl, Interval

df = Bandl().crypto.get_ohlcv_dataframe("BTC/USDT", Interval.D1)   # no API key needed

One 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, BANKNIFTY via Zerodha.
  • 📈 Options, incl. expired contracts — NSE/BSE F&O + MCX commodities via Dhan.
  • 🐼 pandas or typed models — get_ohlcv_dataframe(...) or get_ohlcv(...) -> list[OHLCV].
  • ⏱️ Normalized everywhere — UTC timestamps, Decimal prices, one Interval enum.
  • 🤖 Agent-ready — a dedicated AGENTS.md reference for LLM tools.

bandl demo


Install

pip install bandl

Python 3.10+. Dev setup: pip install -e ".[dev]" (CONTRIBUTING.md).


60-second start

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

Want 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)

One API, every market

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.equity breeze ICICI Breeze key + session RELIANCE, INFY
client.derivatives dhan Dhan id + JWT GOLDM26JUN145000CE, NIFTY26JAN24000PE
client.derivatives breeze ICICI Breeze key + session CRUDEOIL, GOLDM options & futures

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.


Recipes

Indian equities & indices (Zerodha)

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")

Options & derivatives (Dhan)

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",
)

Indian equities, derivatives & commodities (ICICI Direct Breeze)

ICICI Direct Breeze provides historical OHLCV across equities, indices, and derivatives (including MCX commodities down to 1-second candles), along with Demat portfolio holdings and live order execution.

1. Obtaining API credentials & Session token

  • Register/login on the ICICI Direct Breeze API Portal.
  • Create an app to receive your App Key / API Key (api_key) and Secret Key (api_secret).
  • To generate your daily session token:
    1. Open: https://api.icicidirect.com/apiuser/login?api_key=<YOUR_API_KEY> in your browser.
    2. Log in with your ICICI Direct credentials and TOTP.
    3. After login, your browser redirects to your registered Redirect URL with ?apisession=<session_token>.
    4. Pass <session_token> as access_token and your ICICI User ID as account_id in ProviderSettings.

2. Configuration & Market Data

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={
    "breeze": ProviderSettings(
        api_key="your_app_key",
        api_secret="your_secret_key",
        access_token="your_daily_session_token",
        account_id="your_user_id",
    ),
}))

# 1) Equities & Indices (NSE / BSE)
df_rel = client.equity.get_ohlcv_dataframe("RELIANCE", Interval.D1, source="breeze", exchange="NSE")

# 2) 1-Minute / 1-Second Candles for Commodities & Futures (MCX)
df_crude = client.equity.get_ohlcv_dataframe(
    "CRUDEOIL", Interval.M1,
    datetime(2026, 9, 20, tzinfo=timezone.utc),
    datetime(2026, 9, 25, tzinfo=timezone.utc),
    source="breeze", exchange="MCX",
)

# 3) Commodity / Equity Options
contract = OptionContract(
    underlying="CRUDEOIL",
    expiry=date(2026, 10, 16),
    strike=Decimal("5600"),
    option_type=OptionType.CALL,
    exchange="MCX",
)
bars = client.derivatives.get_ohlcv(contract, Interval.M5, source="breeze")

3. Portfolio & Trading

from bandl.models.account.types import OrderSide, OrderType
from bandl.models.trading import OrderRequest, ProductType

# Demat holdings, cash balances, and margin info
holdings = client.portfolio.get_holdings(source="breeze")
balances = client.portfolio.get_balances(source="breeze")
margin   = client.portfolio.get_margin(source="breeze")

# Place a regular order
ack = client.trade.place_order(
    OrderRequest(
        symbol="RELIANCE",
        exchange="NSE",
        side=OrderSide.BUY,
        order_type=OrderType.LIMIT,
        quantity=Decimal(10),
        price=Decimal("2450.00"),
        product=ProductType.DELIVERY,
    ),
    source="breeze",
)
print("Order placed ID:", ack.order_id)

Typed bars instead of pandas

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 datetime

List tradable symbols

client.list_symbols(source="binance", search="BTC", limit=20)
client.list_symbols(source="zerodha", exchange="NSE",
                    instrument_types=("EQ",), search="RELI", limit=10)

Intervals & timezones

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 display

Configuration

from 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 set default_crypto_provider="coindcx".

CoinDCX empty DataFrame? Its public feed can lag by months. A start/end entirely after the feed raises DataNotAvailableError with the available span; pick an overlapping window.


More

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 coindcx

For AI agents

AGENTS.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 & development

pytest tests/bandl/
ruff check lib/bandl tests/bandl

Roadmap

  • Live streams / WebSockets
  • More brokers & deeper commodity history
  • Richer SymbolInfo and fundamentals

Contributing

PRs welcome — read CONTRIBUTING.md and CODE_OF_CONDUCT.md first.

License

MIT

Release files for bandl 0.8.0

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

Source distribution (sdist)

Source distribution for bandl 0.8.0
File Size Uploaded
bandl-0.8.0.tar.gz 85.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for bandl 0.8.0
File Interpreter ABI Platform
bandl-0.8.0-py3-none-any.whl Python 3 none any Details

Total release size: 193.9 kB

Release files / bandl-0.8.0.tar.gz

Download URL bandl-0.8.0.tar.gz
Size 85.6 kB
Tags Source
SHA-256 checksum
How to use checksums
ab59176059876cf5f2b2c5b3d9f4b2f1ee68f357ca4d57dda7623866d98a798e
BLAKE2b-256 checksum
How to use checksums
663ded456ae5e9b47cd5260d1054c1c3a196190a3f82a50080f62ce45cac28b1
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 27, 2026.

Transparency log

Release files / bandl-0.8.0-py3-none-any.whl

Download URL bandl-0.8.0-py3-none-any.whl
Size 108.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
25d7d6b2dffa79ead4c57212ca29d5887abe871e9c9c529a578062d3495744f5
BLAKE2b-256 checksum
How to use checksums
04c01466d8c5dfd55b4d4909148a66ccde505f53e279f5db275bcacdc290b25e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.13

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.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 27, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.8.0 This release

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

0.0.1

1 release file

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