Change one word. Trade any broker.
One unified Python API across 15 Indian brokers β authentication, instrument tokens,
orders, positions, and account data, all returned in one consistent shape.
Install Β· Quickstart Β· Features Β· Brokers Β· Constants Β· Paper Mode Β· Documentation
Every Indian broker ships its own REST API with its own URLs, field names, constants for order side and product type, error envelope, and rate limits. Writing a strategy against one broker means re-learning all of that for the next. Fenix is an adapter library: each broker is a class that implements the same methods and returns the same dictionaries β a single unified interface purpose-built for the Indian markets (NSE, BSE, NFO, BFO, MCX, CDS).
# swap one word β the rest never changes
from fenix import Zerodha
from fenix import Side, Product
broker = Zerodha()
broker.authenticate(params=creds)
broker.market_order(token_dict=contract, quantity=1, side=Side.BUY, product=Product.MIS, unique_id="entry-1")It is built for coders, quant developers, technically-skilled traders, and data scientists building algorithmic trading systems on top of one stable API.
- Learn it once, ship everywhere. The same method names, parameters, and return shapes work across every adapter. Porting a strategy to a new broker is a one-line change β not a rewrite.
- One vocabulary, not fifteen. Your code speaks in Fenix constants β
Side.BUY,Product.MIS,OrderType.SLMβ and each adapter translates to its broker's dialect, with validation. - Backtest with paper mode. Flip one flag and the same strategy runs against a built-in matching engine β realistic fills, positions, and PnL, with no credentials and zero live calls.
- Safe by default. Token-bucket rate limiting per endpoint, structured errors with HTTP-status mapping, and automatic redaction of secrets from every log line.
Fenix 2.0 requires Python 3.10 or newer and runs on Windows, macOS, and Linux.
pip install fenixTo install a specific release:
pip install fenix==2.0.0Verify the installation and inspect the broker registry:
import fenix
print(fenix.__version__) # 2.0.0
print(fenix.brokers) # ['AliceBlue', 'AngelOne', 'AnandRathi', ...]Instantiate a broker, authenticate, download instrument tokens, place an order, and read it back β all through the unified API. The same code runs against any broker.
from fenix import Zerodha, Side, Validity
# 1 Β· Instantiate
broker = Zerodha()
# 2 Β· Authenticate β each broker declares the credentials it needs in `tokenParams`
creds = {
"user_id": "YOUR_USER_ID",
"password": "YOUR_PASSWORD",
"totpstr": "YOUR_TOTP_SECRET", # the TOTP *seed*, not a 6-digit code
"api_key": "YOUR_API_KEY",
"api_secret": "YOUR_API_SECRET",
}
broker.authenticate(params=creds)
# 3 Β· Download instrument tokens (reshaped into a standardized lookup)
fno, _ = broker.load_fno_tokens()
contract = fno["Options"]["NFO"]["NIFTY"][0]
# 4 Β· Place an order β returns a unified order record (same keys for every broker)
order = broker.limit_order(
token_dict=contract,
side=Side.BUY,
price=152.0,
quantity=75,
unique_id="entry-1",
)
# 5 Β· Read it back, then modify or cancel
detail = broker.fetch_order(order["id"])
broker.modify_order(order_id=order["id"], price=151.5, quantity=75)
broker.cancel_order(order_id=order["id"])
# 6 Β· Inspect positions and account
positions = broker.fetch_net_positions()
holdings = broker.fetch_holdings()
margins = broker.fetch_margin_limits() # unified RMS record
profile = broker.fetch_profile()See the Quickstart guide for the full walkthrough, including reusing an authenticated session across runs.
| Order entry | Account & order reads |
|---|---|
place_order, modify_order, cancel_order |
fetch_orderbook, fetch_tradebook |
market_order, limit_order, sl_order, slm_order |
fetch_order, fetch_order_history |
market_buy_order, market_sell_order |
fetch_net_positions, fetch_day_positions |
limit_buy_order, limit_sell_order |
fetch_holdings, fetch_margin_limits |
sl_buy_order, slm_sell_order, β¦ |
fetch_profile |
Fenix 2.0 is a ground-up refactor of the broker layer. Highlights:
- π Unified, one-line broker swap. Identical method names, parameters, and return shapes across all 15 adapters β port a strategy by changing a single class name.
- π§± One shared base class. Every adapter subclasses
fenix.base.broker.Broker, which owns the HTTP session, request wrapper, URL building, constant translation, and error mapping. New brokers stay thin and consistent. - π Built-in paper-mode engine. An in-process matching engine simulates fills, positions,
and PnL with no credentials and zero live calls β flip
paper_modeand the same code runs. - π£οΈ One vocabulary. Fenix constants (
Side,Product,OrderType,Validity,Variety,Status) are translated per broker with validation β see Constants. - π¦ Per-endpoint rate limiting. Token-bucket throttling defined in each adapter's
rateLimits; requests self-throttle before hitting the broker. - π Secret redaction. Passwords, tokens, API keys, authorization headers, and TOTP values are automatically scrubbed from every log line.
- π§Ύ Structured errors. Broker error envelopes are mapped to typed Fenix exceptions with HTTP-status context.
- π©Ί Request/response diagnostics. Every broker keeps the latest HTTP snapshots
(
last_request_*,last_response_*) β plus paper-mode equivalents. - β¨οΈ Typed. Ships a PEP 561
py.typedmarker so downstream type checkers pick up Fenix's annotations.
Fenix 2.0 exposes 15 broker adapters. Each has its own reference page documenting every method it supports.
The Class name is the public identifier β it is exactly what fenix.brokers lists and what
broker.describe()["id"] returns.
import fenix
print(fenix.brokers) # always reflects exactly what your installed version supportsThe deprecated v1 modules
choice,kotak,kunjee, andvpcwere removed in v2.0.
Your strategy speaks Fenix constants; each adapter translates them to its broker's dialect and
validates them. The constant classes are top-level exports (from fenix import Side, Product, β¦).
| Constant | Common values |
|---|---|
Side |
BUY, SELL |
OrderType |
MARKET, LIMIT, SL, SLM |
Product |
MIS, NRML, CNC, MARGIN, MTF, BO, CO |
Validity |
DAY, IOC, GTD, GTC, FOK, TTL |
Variety |
REGULAR, STOPLOSS, AMO, BO, CO, ICEBERG, AUCTION |
Status |
PENDING, OPEN, PARTIALLY_FILLED, FILLED, REJECTED, CANCELLED |
ExchangeCode |
NSE, NFO, BSE, BFO, MCX, CDS, β¦ |
Root |
NIFTY, BANKNIFTY, FINNIFTY, SENSEX, CRUDEOIL, β¦ |
Option |
CE, PE |
Returned records also use a fixed key set (Order, Position, Profile, RMS), so the same
parsing code works for every broker. Full reference at fenix.hardeep.tech.
Paper mode routes supported order entry and account reads through Fenix's in-process matching engine instead of live broker endpoints β no credentials, zero live calls. Flip one flag and the exact same code runs against the simulator.
from fenix import AliceBlue, Side, UniqueID
broker = AliceBlue({"paper_mode": True})
broker.authenticate() # no-op in paper mode
token = {"Token": 12345, "Symbol": "TESTSTOCK", "Exchange": "NSE"}
order = broker.market_order(
token_dict=token, quantity=1, side=Side.BUY, unique_id=UniqueID.MARKET_ORDER,
)
broker.on_tick(token=12345, ltp=2500.0) # feed prices to drive fills
print(broker.fetch_orderbook())
print(broker.fetch_positions())Paper mode supports order books, trade books, order history, positions, holdings, margin limits, profile data, stop-order validation, and square-off validation.
Every adapter β Zerodha, AngelOne, Fyers, β¦ β subclasses fenix.base.broker.Broker. The
base class owns everything identical across brokers (HTTP session, throttling, the fetch()
request wrapper, URL building, constant translation, logging/redaction, error mapping, and the
embedded paper engine), while each subclass supplies only what is broker-specific.
Your strategy Fenix Β· Unified API Brokers
ββββββββββββββββββ ββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββ
β β β authenticate Β· login β β Zerodha Β· Angel One β
β one codebase β βββββββΆ β orders Β· positions β βββββββΆ β Fyers Β· Upstox Β· Dhan β
β β call β account Β· paper mode β REST β β¦ + 10 more brokers β
ββββββββββββββββββ ββββββββββββββββββββββββββββ ββββββββββββββββββββββββββββ
- Rate limits. Adapters define token-bucket buckets in
rateLimits; requests throttle automatically before hitting endpoints. Configure withenableRateLimitandrate_limit_padding. - Logging & redaction. Pass a logger or
verbose=Trueto inspect request/response flow. Fenix redacts passwords, tokens, API keys, authorization headers, and TOTP values. - Diagnostics. Every broker keeps the latest HTTP snapshots (
last_request_*,last_response_*) β and in paper mode,last_paper_request/last_paper_response/last_paper_interaction. - Typed. Ships a PEP 561
py.typedmarker so downstream type checkers pick up Fenix's annotations.
Fenix-Pro is the paid, real-time companion to Fenix. It hides
each broker's WebSocket transport, payload format, and subscription conventions behind a unified,
callback-oriented interface β LTP, market depth, and order updates, normalized into one
TickData / Order shape across 15 live-feed adapters. It shares Fenix's broker roster and
instrument-token shapes, so the two compose cleanly.
Full developer documentation β guides, architecture, the unified API reference, paper mode, constants, and a reference page per broker β lives at fenix.hardeep.tech.
Fenix is released under the GNU General Public License v3.0. See LICENSE for details.
Built for the Indian markets Β· fenix.hardeep.tech
