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


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

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.7.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.7.0
File Size Uploaded
bandl-0.7.0.tar.gz 76.9 kB Details

Built distribution (wheel)

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

Total release size: 174.7 kB

Release files / bandl-0.7.0.tar.gz

Download URL bandl-0.7.0.tar.gz
Size 76.9 kB
Tags Source
SHA-256 checksum
How to use checksums
3d432b86f5a6f320c82fd59e91b2e2c5972c37a22fdc56ff4d208101a8a8f662
BLAKE2b-256 checksum
How to use checksums
c1622056fbfa5b6639846fe3e1d95cd78ad168ec386ea108e8076f2a7a33d7a5
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.7.0-py3-none-any.whl

Download URL bandl-0.7.0-py3-none-any.whl
Size 97.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8a05a556209e58dded5bd1f447105ffbe48e6ffe1c165db47b3e8057fc688e00
BLAKE2b-256 checksum
How to use checksums
67908fa1d7ee1dfe08dfe11d269cfe4e452d66de9477fe88dafb7748f354ce65
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

0.8.0

2 release files

This release

0.7.0 This release

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