Your strategy should care about trading, not about the quirks of a particular broker’s API. Yet broker APIs are messy and all different — different authentication, different field names, different symbol formats, different rate limits, different ways of disconnecting. If you let those differences leak into your strategy code, you get a tangle that’s painful to maintain and impossible to move to another broker. The fix is a classic piece of software design applied to trading: a broker-adapter layer. This lesson builds that abstraction, which also sets up the crypto reuse in Lesson 13.
One Interface, Many Brokers
The core idea: define a single BrokerAdapter interface — a small set of operations your system needs — and make every broker implement it. Your strategy, risk layer and UI talk only to that interface, in one common language, and never know (or care) which broker is behind it.
The interface is deliberately small — the operations every broker must support:
place_order(...)— send an order (with your normalised fields).cancel(order_id)— cancel a resting order.positions()/orders()— query current positions and order states.subscribe(instruments)— subscribe to market data (Lesson 3).- plus callbacks/events for fills, order updates, and ticks.
Your strategy calls place_order and gets back a normalised result; it never writes broker-specific code. Behind the interface, each adapter is a translator: it takes these common calls and turns them into the specific API calls, field names, and formats that one particular broker expects — and translates the responses back into your common, normalised model.
What the Adapter Hides
The value of the adapter is everything ugly it keeps out of your strategy. A good adapter handles:
- Auth and token refresh. Many broker APIs (including Kite) use a login flow that produces a session/access token, sometimes valid only for the day. The adapter manages obtaining and refreshing it, so your strategy never thinks about auth.
- Symbol / instrument-id mapping. Every broker and exchange identifies instruments differently (a trading symbol, a numeric token, an exchange code). The adapter maps between your internal symbol and the broker’s identifiers.
- Order-field naming and semantics. One broker says
transaction_type: BUY, anotherside: B; order types, product types (intraday vs delivery), and validity flags all differ. The adapter normalises them. - Lot sizes and tick sizes. Derivatives trade in fixed lots and minimum price increments (Lesson 1); the adapter knows and enforces them.
- Rate limits, retry and backoff. Brokers cap how many orders/requests per second you may send. The adapter respects those caps (tying into the rate-limit risk check of Lesson 8) and retries transient failures with sensible backoff.
- Reconnection and re-subscription. When the market-data WebSocket drops (Lesson 3), the adapter reconnects, re-authenticates, re-subscribes, and re-snapshots — so your strategy just keeps receiving clean ticks.
- Error-code normalisation. Each broker returns its own error codes and messages; the adapter maps them into a common set your system understands (retryable vs fatal, rejected vs failed).
What comes out of the adapter is a common normalised model — one shape for orders, fills, positions and ticks, identical regardless of broker. That normalisation is the whole point: your strategy, OMS and risk layer (Lesson 8) operate on one consistent model forever.
Zerodha Kite Connect: the Worked Example
For Indian retail, Zerodha’s Kite Connect is the common broker API, and it’s a good concrete example of what an adapter wraps. In rough shape (check current docs before building — APIs change):
- Auth is a login flow that yields a daily access token you attach to requests; your adapter handles obtaining it (often a once-a-day step) and attaching it.
- Orders go over a REST API — place, modify, cancel — with Kite’s specific fields (exchange, tradingsymbol, transaction_type, quantity, order_type, product, etc.).
- Market data comes over a WebSocket ticker you subscribe to with instrument tokens, in Kite’s binary tick format, which your adapter decodes into your normalised tick model.
- Rate limits apply (orders per second, requests per minute); your adapter enforces them.
Your KiteAdapter implements the common BrokerAdapter interface by translating each common call into these Kite specifics and decoding Kite’s responses back into your normalised model. Your strategy, meanwhile, just calls place_order — blissfully unaware it’s Kite underneath. (The same is true if you later add a second Indian broker: a new adapter, nothing else changes.)
Why This Pays Off
The design discipline here delivers concrete wins:
- Adding a broker = writing one adapter. Want to run on a second broker, or switch? Implement the interface once; your strategies, risk layer, OMS and UI don’t change at all. Without the adapter layer, a broker switch means touching code everywhere.
- Testability. You can write a mock/paper adapter that implements the same interface with simulated fills — which is exactly how paper trading (Lesson 13) works: swap the live adapter for a simulated one, same strategy code.
- Isolation of failure and change. When a broker changes its API or misbehaves, the blast radius is one adapter, not your whole system.
- It extends to crypto. A crypto exchange is, from your system’s point of view, just another broker with a different API and some operational differences (24/7, key custody). Because you built against an interface, moving a strategy to crypto is mostly a new adapter (Lesson 13), not a rewrite.
This is just good software architecture — program to an interface, isolate what varies — applied where it pays off enormously, because broker APIs are both essential and maddeningly inconsistent.
Pitfalls to Avoid
- Broker-specific code in your strategy. It tangles your logic and locks you to one broker. Put it all behind the adapter interface.
- Not normalising the data model. If each broker’s orders/fills/ticks have different shapes in your core, every component has to special-case them. Normalise at the adapter boundary.
- Ignoring rate limits. Exceed the broker’s caps and you get rejected or throttled at the worst time. The adapter must enforce them (Lesson 8).
- No reconnection logic in the adapter. A dropped WebSocket then breaks your strategy. The adapter owns reconnect + re-subscribe + re-snapshot (Lesson 3).
- Hardcoding symbol formats. Instrument identifiers differ per broker/exchange; map them in the adapter, don’t scatter string formats through your code.
- Assuming the API is stable. Broker APIs change; keep the adapter current and version it. Read the current docs before building.
Quick Recap
- Put all broker-specific code behind a single BrokerAdapter interface (
place_order,cancel,positions,subscribe); your strategy speaks one common language. - Each adapter hides the mess: auth/token refresh, symbol mapping, field naming, lot/tick sizes, rate limits, reconnection, error normalisation — exposing a normalised model for orders, fills, positions and ticks.
- Kite Connect (REST orders + WebSocket ticks + daily access token) is the Indian worked example.
- Adding a broker = one adapter, with strategies/risk/UI unchanged; the same design enables paper trading (a mock adapter) and crypto (Lesson 13).
- Educational, not financial advice.
Next lesson: the single most important skill for not losing money — backtesting honestly. We’ll see, with measured demos, exactly how backtests lie through lookahead and overfitting, and how to stop them.