Agent Skillsmarketcalls/openalgo › broker-integration

broker-integration

GitHub

用于在OpenAlgo中集成或修改印度券商插件,处理认证、订单、行情及WebSocket流。指导将特定券商API映射至通用格式,并识别参考模板以避免常见陷阱。

.claude/skills/broker-integration/SKILL.md marketcalls/openalgo

Trigger Scenarios

集成新的印度券商 修改现有券商插件 调试券商特定的符号或价格缩放问题

Install

npx skills add marketcalls/openalgo --skill broker-integration -g -y
More Options

Non-standard path

npx skills add https://github.com/marketcalls/openalgo/tree/main/.claude/skills/broker-integration -g -y

Use without installing

npx skills use marketcalls/openalgo@broker-integration

指定 Agent (Claude Code)

npx skills add marketcalls/openalgo --skill broker-integration -a claude-code -g -y

安装 repo 全部 skill

npx skills add marketcalls/openalgo --all -g -y

预览 repo 内 skill

npx skills add marketcalls/openalgo --list

SKILL.md

Frontmatter
{
    "name": "broker-integration",
    "description": "Integrate a new Indian broker into OpenAlgo, or modify an existing broker plugin. Use when wiring up a broker's auth\/login, orders, quotes, depth, history, funds, margin, symbol master, or WebSocket streaming; when a broker does not appear in the login dropdown or fails to load; or when debugging broker-specific symbol, exchange-code, price-scaling, or order-field mapping."
}

Integrating a broker into OpenAlgo

Golden rule: OpenAlgo has a common symbol format, common API, and common WebSocket format. Your only job per file is to translate the broker's specific shapes into those common contracts (and back). Copy the closest reference broker, then adapt the broker-specific bits.

35 brokers already exist. Almost every problem you will hit has been solved in one of them — the skill is knowing which one to copy, and which details are genuinely broker-specific.

Where broker code sits in the stack

restx_api/<endpoint>.py     Marshmallow schema validation + per-IP rate limit. Thin.
  services/<x>_service.py   Auth resolution, analyze-mode branch, event emission.
                            Returns (success: bool, response_data: dict, status_code: int)
    broker/<name>/api/*     <- YOU ARE HERE. The only place broker specifics live.

Two consequences worth internalizing:

  • You never emit events. events/ and utils/event_bus.py are a services-layer concern (order placed, cancelled, GTT triggered). Broker modules do not import them. The one exception in the tree (broker/iiflcapital/streaming/iiflcapital_order_adapter.py) is an order-update stream, not the REST path — do not copy that pattern by default.
  • Analyze mode never reaches you. get_analyze_mode() in the service short-circuits to sandbox_service before any broker call. So "it works in analyzer" proves nothing about your integration.

Step 1 — identify the broker's family, then copy that broker

This is the highest-leverage decision. Indian brokers cluster into four auth families, and picking the right template saves days:

Family Members already in the tree Auth shape Copy
OAuth2 / checksum redirect zerodha, upstox, fyers, dhan, arrow, groww, paytm, aliceblue, definedge Redirect to broker, get request_token/code back on callback, exchange it (often SHA256 checksum of api_key + token + secret) broker/zerodha/
Noren / Finvasia shoonya, flattrade, tradesmart, zebu, ibulls, wisdom Shared upstream codebase. Near-identical endpoints, jData=/jKey= form bodies, susurl/scrip-master CSVs per exchange broker/shoonya/ or broker/flattrade/
Symphony XTS fivepaisaxts, jainamxts, compositedge, rmoney, iiflcapital Dual credentials: interactive + market-data. BROKER_API_KEY_MARKET / _SECRET_MARKET broker/fivepaisaxts/
Direct login + TOTP angel, mstock, motilal, kotak, firstock, samco, nubra, tradejini, fivepaisa User submits clientcode/password/TOTP in a form; no redirect broker/angel/

Special cases: broker/fyers/ if the broker offers depth beyond 5 levels (dual WebSocket, 50-level TBT socket). broker/deltaexchange/ is the only broker_type: "crypto" plugin and the only one with leverage_config: true — ignore it for Indian equity brokers.

If the broker is a white-label of one of the above (very common — many Indian brokers resell Noren or XTS), the family template is often 90% correct as-is. Check the API docs for tell-tale endpoint paths (/NorenWClientTP/, /interactive/user/session) before assuming it is bespoke.

Step 2 — read the common contracts before writing anything

These define the format you must conform to. Do not infer them from a reference broker's code — read the specs:

Topic File
Symbol format (EQ/FUT/CE/PE, indices, exchange codes) docs/prompt/symbol-format.md
Order constants (product, pricetype, action, exchanges) docs/prompt/order-constants.md
Lot size conventions docs/prompt/LotSize.md
Common API request/response per endpoint docs/api/** (esp. account-services/, market-data/, order-management/)
WebSocket streaming format docs/prompt/websockets-format.md, docs/api/websocket-streaming/*
Services layer contract docs/prompt/services_documentation.md
Rate limits docs/api/rate-limiting.md
Long-form integration notes docs/broker-integration-guide.md
Runtime constraints (eventlet, NullPool, FD hygiene) root CLAUDE.md

Inspect the LIVE db/openalgo.db symtoken table of a working broker (e.g. connect zerodha once). This is the single most useful reference — it shows the exact column values your master contract must reproduce. Do this BEFORE wiping symtoken with your new broker's data — the old broker's rows are your ground truth for NCO symbol format, MCX_INDEX names, expiry formatting and the index symbol set. Once you overwrite the table, that reference is gone.

Calibrate against the plugins that already exist

Before deciding what is normal for a broker — batch caps, rate limits, depth levels, which capabilities OpenAlgo even has a contract for — read references/cross-broker-reference.md. It records how all 35 existing plugins actually behave, measured from the tree, so you are not guessing at defaults or reinventing a decision someone already made.

If you have no reachable documentation for your broker, read its family sibling in the tree — a Noren white-label behaves essentially like broker/flattrade/, an XTS white-label like broker/fivepaisaxts/.

The broker's official SDK is your second source of truth

When the broker's docs omit literal details (JSON field names, binary byte offsets, enum codes, endpoint routes), download their official Python SDK from PyPI and read its source — it encodes what the server actually accepts:

pip download <broker-sdk-package> --no-deps -d /tmp/sdk && cd /tmp/sdk && unzip -o *.whl
# then read: routes/constants (endpoint paths, enum codes), the request
# plumbing (json vs form body), and any _parse_*_packet binary parsers

For Arrow this single trick resolved: the websocket binary offsets (docs don't publish them), the margin request field names + product enum (C/I/M), the basket-margin endpoint shape, and the quote modes/exchange enum. Reading the SDK is minutes; guessing wrong costs hours of cryptic 400s.

Step 3 — the module contract

Services do importlib.import_module(f"broker.{broker}.api.<module>") and call fixed names — these ARE the contract. Verified against services/*.py:

Service Module Function Returns
login api.auth_api authenticate_broker(...) (auth_token, error) — arity varies, see below
place api.order_api place_order_api(data, auth) (response, response_data, orderid); response.status == 200 = success
smart api.order_api place_smartorder_api(data, auth) same shape
modify api.order_api modify_order(data, auth) (dict, status_code)
cancel api.order_api cancel_order(orderid, auth) (dict, status_code)
cancel all api.order_api cancel_all_orders_api(data, auth) (canceled[], failed[])
close api.order_api close_all_positions(api_key, auth) (dict, status_code)
orderbook api.order_api + mapping.order_data get_order_book(auth); map_order_data, calculate_order_statistics, transform_order_data raw -> normalized
tradebook api.order_api + mapping.order_data get_trade_book(auth); map_trade_data, transform_tradebook_data
positions api.order_api + mapping.order_data get_positions(auth); map_position_data, transform_positions_data
holdings api.order_api + mapping.order_data get_holdings(auth); map_portfolio_data, calculate_portfolio_statistics, transform_holdings_data
(internal) api.order_api get_open_position(symbol, exchange, product, auth) net qty as str (used by smart order)
funds api.funds get_margin_data(auth) dict
quotes api.data BrokerData(auth).get_quotes(symbol, exchange) dict
depth api.data BrokerData(auth).get_depth(symbol, exchange) dict (5 levels)
history api.data BrokerData(auth).get_history(symbol, exchange, interval, start, end) pandas DataFrame
multiquotes api.data BrokerData(auth).get_multiquotes(symbols) list — optional, see below
intervals api.data BrokerData(auth).timeframe_map (attribute) dict
master database.master_contract_db master_contract_download() emits socketio event
margin api.margin_api calculate_margin_api(positions, auth) (response, data); data.data = {total_margin_required, span_margin, exposure_margin} (+ optional total_charges)
GTT api.gtt_api place_gtt_order, modify_gtt_order, cancel_gtt_order, get_gtt_book optional — only Dhan and Zerodha have one; the capability gate returns 501 when absent

auth is always the decrypted broker token string (last positional arg).

There is one more optional surface: an order-update stream (real-time fills, rejections, cancellations pushed to the client). 11 of 35 brokers implement it. It is registered separately in services/order_update_service.py, not in the table above — see references/order-updates.md.

NUANCE — BrokerData.__init__ arity is introspected, not fixed

services/quotes_service.py inspects BrokerData.__init__.__code__.co_argcount and passes (auth_token, feed_token) when the constructor takes two args, otherwise (auth_token). So a broker whose market-data API needs a separate feed token simply declares def __init__(self, auth_token, feed_token) and the service adapts. All the common templates (zerodha/dhan/fyers/flattrade/ angel/arrow) are single-arg — only add the second parameter if the broker truly has a distinct feed credential.

NUANCE — get_multiquotes is optional and silently degrades

The service does hasattr(data_handler, "get_multiquotes") and falls back to looping get_quotes per symbol if absent. That fallback works but is brutally slow for the options tools, which request 180+ symbols at once. Implement get_multiquotes for any broker with a batch quote endpoint.

NUANCE — margin: never sum legs when a basket endpoint exists

Copy broker/dhan/api/margin_api.py — it is the reference pattern: route ONE position to the broker's single-order calculator (detailed charge breakdown) and 2+ positions to the basket/multi calculator so the broker nets spread/hedge benefits (an Arrow NIFTY short straddle priced at ~207k via basket vs ~337k as a naive per-leg sum). Include Dhan's two guards: a JSON-decode guard (non-JSON broker reply -> 502) and _normalise_success_response (broker sends an error payload with HTTP 200 -> convert to a 400 response object, because margin_service trusts HTTP 200).

Symbol translation helpers you must use

Import from database.token_db (re-exported from token_db_enhanced) — never hand-roll symbol lookups:

Helper Direction
get_token(symbol, exchange) OpenAlgo symbol -> broker instrument token
get_symbol(token, exchange) token -> OpenAlgo symbol
get_br_symbol(symbol, exchange) OpenAlgo symbol -> broker tradingsymbol
get_oa_symbol(brsymbol, exchange) broker tradingsymbol -> OpenAlgo symbol
get_brexchange(symbol, exchange) OpenAlgo exchange -> broker exchange code
get_symbol_info(symbol, exchange) full SymToken row (lotsize, tick_size, expiry, ...)
get_tokens_bulk(pairs) batch token lookup — use in get_multiquotes

Step 4 — required directory layout

broker/<name>/
  __init__.py
  plugin.json                         # metadata; see below
  api/__init__.py
  api/baseurl.py                      # (optional) hosts + auth-header builder (DRY)
  api/auth_api.py                     # authenticate_broker(...)
  api/order_api.py                    # place/modify/cancel/book/positions/holdings
  api/data.py                         # class BrokerData (quotes/depth/history)
  api/funds.py                        # get_margin_data(auth)
  api/margin_api.py                   # (optional) calculate_margin_api
  api/gtt_api.py                      # (optional) GTT support
  mapping/__init__.py
  mapping/transform_data.py           # OpenAlgo order -> broker payload + enum maps
  mapping/order_data.py               # broker JSON -> OpenAlgo normalized rows
  mapping/exchange.py                 # (optional) exchange/index translation (shared)
  database/__init__.py
  database/master_contract_db.py      # master_contract_download() + SymToken
  streaming/__init__.py               # exports <Name>WebSocketAdapter
  streaming/<name>_adapter.py         # class <Name>WebSocketAdapter(BaseBrokerWebSocketAdapter)
  streaming/<name>_websocket.py       # sync websocket-client thread
  streaming/<name>_mapping.py         # exchange + capability registries

plugin.json fields that actually do something: supported_exchanges (drives capability checks and what you must live-test), broker_type (IN_stock for all 34 Indian brokers, crypto for deltaexchange), leverage_config (false for every Indian broker in the tree).

Shared utils/ a broker plugin depends on

Never hand-roll these — the shared helper is the contract, and bypassing it is how FD leaks, unredacted secrets and rate-limit breaches get introduced. Usage counts across the 35 existing plugins:

Module Uses What you must take from it
utils.logging ~339 logger = get_logger(__name__) in every module. Its SensitiveDataFilter is what stops broker tokens reaching the logs — a bare print() or logging.getLogger() bypasses that redaction. Errors use logger.exception().
utils.httpx_client ~197 get_httpx_client() — the shared pooled HTTP/2 client. Never construct a per-call client. Always pass an explicit timeout=.
utils.mpp_slab ~16 Market Price Protection slabs for emulating MARKET/SL-M. See references/order-type-emulation.md.
utils.config ~5 get_broker_api_key(), get_broker_api_secret(), get_host_server(), rate-limit getters. Prefer these over raw os.getenv so composite ::: keys and defaults resolve consistently.
utils.constants 1 EXCHANGE_NSE, EXCHANGE_NFO, ... — canonical exchange codes. Use them instead of string literals.
utils.plugin_loader Discovers broker/*/plugin.json at startup and requires the exact name authenticate_broker. You do not call it; it calls you.

utils.event_bus exists but is a services-layer concern — broker modules do not publish events.

You do not touch restx_api/

No broker plugin references restx_api/, and a new broker must not add one. That layer is broker-agnostic: each file is a thin Marshmallow-validated, rate-limited Flask-RESTX resource that calls a service, which then dispatches to whichever broker is configured. Adding an endpoint there for one broker's special feature would break the "common API across all brokers" contract.

If a broker offers something OpenAlgo has no endpoint for (GTT on a third broker, bracket orders, 20-level depth), the change is: service layer first, then restx_api/ — as a capability available to every broker, not a one-off. See the capability list in references/cross-broker-reference.md.

Step 5 — HTTP pooling and FD hygiene (mandatory, applies throughout)

  • All REST via utils/httpx_client.get_httpx_client() — a shared pooled HTTP/2 client. NEVER httpx.Client() / requests / urllib / aiohttp per call.
  • The shared client has a default 120s timeout; add an explicit timeout= for large/slow calls (e.g. the instrument-master download).
  • DB engines via database.engine_factory.create_db_engine() (NullPool).
  • Use with db_session() as session: for reads; db_session.remove() in a finally for background-thread work.
  • After building, run the fd-audit skill on your change.

Detailed references — load the one for the phase you are in

Phase Read
Calibration: batch caps, rate limits, depth, capability gaps references/cross-broker-reference.md
Auth, login callback, .env + install wiring references/auth-and-login.md
Instrument master, SymToken, symbol construction references/master-contract.md
Quotes / depth + account-data normalization references/data-and-account.md
Historical data — timestamps, chunking, boundaries references/history-data.md
Rate limiting — pacing strategy, 429 handling references/rate-limiting.md
MARKET / SL-M emulation when the broker lacks them references/order-type-emulation.md
Market-data WebSocket adapter, binary parsing, ZMQ references/streaming.md
Account-level order/trade update stream references/order-updates.md
Live-hardening pass, verification, cheat-sheet references/hardening-and-verification.md

Build order

  1. Research — API docs, pick the family template, read the common contracts, inspect a live symtoken, download the broker SDK.
  2. plugin.json + api/auth_api.py — get login working end-to-end first. Nothing else can be tested until a token is stored.
  3. Platform wiringVALID_BROKERS, install scripts, BrokerSelect.tsx, websocket_proxy/__init__.py, brlogin.py branch. See references/auth-and-login.md. Without this the broker will not even appear in the dropdown.
  4. database/master_contract_db.py — symbols must exist before quotes/orders can be tested. Validate offline against the live symtoken reference.
  5. mapping/ + api/data.py — quotes, depth, history.
  6. api/order_api.py + mapping/order_data.py — orders and books.
  7. api/funds.py, api/margin_api.py — funds and margin.
  8. streaming/ — market data first (the hardest part), then the optional order-update adapter.
  9. Live-hardening pass — see references/hardening-and-verification.md. Budget real time for this; it is where the actual bugs are.

What "done" does not mean

  • Analyze mode passing proves nothing. It routes to the sandbox and never calls your code.
  • A clean code review proves little. All six Arrow bugs survived review; every one needed a live probe.
  • NSE working proves nothing about the other exchanges. Test every exchange listed in your plugin.json — that list is a promise.

Version History

  • fc15cca Current 2026-08-02 21:02

Same Skill Collection

.claude/skills/custom-indicator/SKILL.md
.claude/skills/fd-audit/SKILL.md
.claude/skills/indicator-chart/SKILL.md
.claude/skills/indicator-dashboard/SKILL.md
.claude/skills/indicator-expert/SKILL.md
.claude/skills/indicator-scanner/SKILL.md
.claude/skills/indicator-setup/SKILL.md
.claude/skills/live-feed/SKILL.md
.claude/skills/security-audit/SKILL.md
.claude/skills/version-bump/SKILL.md

Metadata

Files
0
Version
2d8edfd
Hash
2f98090d
Indexed
2026-08-02 21:02

inicio - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-08-17 05:42
浙ICP备14020137号-1 $mapa de visitantes$