TradeDash Add-On Data API¶
Mint a short-lived bearer token and pull option chains, greeks, the paper-options desk and wrapped broker reads from your TradeDash add-on — data + paper scope, no order path.
Part 36 of 37 in the ServLoci algo/options trading notebook series — full index in notebooks/README.md.
Setup — no proxy, just a token¶
# This notebook talks to a TradeDash add-on instance over plain HTTPS.
# Nothing to install beyond requests, and no SOCKS proxy — TradeDash resolves
# your already-connected broker session server-side.
#
# Deploy the add-on from the ServLoci dashboard (TradeDash card), then set:
# TRADEDASH_BASE_URL = https://<your-subdomain>.servloci.in
# TRADEDASH_USER = your TradeDash trader login username
# TRADEDASH_PASSWORD = its password (Users tab -> a broker account -> login credentials)
# Leave them unset to read this notebook in demo mode (no live calls).
!pip install -q requests
import os
TRADEDASH_BASE_URL = os.environ.get("TRADEDASH_BASE_URL", "").rstrip("/")
TRADEDASH_USER = os.environ.get("TRADEDASH_USER", "")
TRADEDASH_PASSWORD = os.environ.get("TRADEDASH_PASSWORD", "")
LIVE = bool(TRADEDASH_BASE_URL and TRADEDASH_USER and TRADEDASH_PASSWORD)
print("live mode:", LIVE, "| base:", TRADEDASH_BASE_URL or "(demo)")
What this is¶
The TradeDash add-on is your own single-tenant trading dashboard on a
dedicated *.servloci.in subdomain (deploy it from the ServLoci dashboard's
TradeDash card — SSO is already shared with your ServLoci login). Alongside the
web UI it exposes a small HTTP data API you can drive from a notebook.
Why use it instead of calling a broker SDK directly:
- No broker credentials in the notebook. You connect Dhan/Kite/Fyers once, inside TradeDash. The API then acts on that stored session; the notebook only ever holds a short-lived TradeDash token.
- One shape for every broker.
GET /api/options/chain?symbol=niftyreturns the same JSON whether the underlying session is Dhan or Fyers. - Extras the raw broker API doesn't have — locally computed greeks, an
autonomous paper-options desk you can read the equity curve of, and the
wrapped
/api/broker/*reads.
Scope is deliberately narrow: data + paper only. These tokens cannot place a real order, launch a trading session, touch feed control, or change order routing. Those stay behind the browser session.
Order routing over your static IP (notebooks 02-05, 16) is unchanged and still the right path for live order calls. This API is for research and paper experimentation, not execution.
Step 1 — mint a short-lived token¶
POST /api/auth/token with your TradeDash trader username + password returns a
bearer token. ttl_seconds is clamped to at most 24 h (default 8 h); regenerate
when calls start returning 401. You can also mint one from the panel: TradeDash
-> API tab.
import requests
session = requests.Session()
def mint_token(ttl_seconds=3600):
r = requests.post(TRADEDASH_BASE_URL + "/api/auth/token", json={
"username": TRADEDASH_USER,
"password": TRADEDASH_PASSWORD,
"ttl_seconds": ttl_seconds,
}, timeout=15)
r.raise_for_status() # 401 here means bad trader credentials
body = r.json()
session.headers["Authorization"] = "Bearer " + body["token"]
return body
if LIVE:
info = mint_token()
print("token scope:", info["scope"], "| expires:", info["expires_at"])
print("identity:", session.get(TRADEDASH_BASE_URL + "/api/auth/token").json())
else:
print("demo mode — skipping. Set TRADEDASH_* env vars to run this live.")
Step 2 — pull a live option chain¶
GET /api/options/chain trims to ATM +/- range strikes and fills local
Black-Scholes greeks on every contract. symbol is one of nifty,
banknifty, sensex, finnifty. It uses whichever broker session the
account has (?broker=dhan|fyers to force one).
DEMO_CHAIN = {
"spot": 24012.5, "atm_strike": 24000, "expiry": "2026-09-25", "pcr": 0.94,
"contracts": [
{"strike": 23900, "opt_type": "PE", "ltp": 74.2, "calc_greeks": {"delta": -0.34}},
{"strike": 24000, "opt_type": "CE", "ltp": 121.0, "calc_greeks": {"delta": 0.52}},
{"strike": 24000, "opt_type": "PE", "ltp": 108.5, "calc_greeks": {"delta": -0.48}},
{"strike": 24100, "opt_type": "CE", "ltp": 71.9, "calc_greeks": {"delta": 0.33}},
],
}
def get_chain(symbol="nifty", rng=10):
if not LIVE:
return DEMO_CHAIN
r = session.get(TRADEDASH_BASE_URL + "/api/options/chain",
params={"symbol": symbol, "range": rng}, timeout=20)
r.raise_for_status()
return r.json()
chain = get_chain("nifty", rng=10)
print("spot", chain["spot"], "| ATM", chain["atm_strike"], "| PCR", chain.get("pcr"))
for c in chain["contracts"][:6]:
g = (c.get("calc_greeks") or {}).get("delta")
print(f" {c['strike']:>7} {c['opt_type']} ltp={c['ltp']:<7} delta={g}")
Step 3 — the paper-options desk¶
If the desk is running on your instance it auto-trades NIFTY / BANKNIFTY / SENSEX at the current and next monthly expiry, strictly on paper, opening hedged structures only when its 0-100 qualifier clears 70. Read its state:
GET /api/options/campaign— per-series score, bias, open structure, equity.GET /api/options/campaign/ticks?series=NIFTY:2026-09-25— the equity / decision log for charting.
DEMO_CAMPAIGN = {
"active": True,
"campaign": {
"horizon_months": 6, "total_equity_inr": 3_012_450.0, "total_realized_inr": 12_450.0,
"series": [
{"symbol": "NIFTY", "expiry": "2026-09-25", "last_score": 74.0,
"last_bias": "pe", "last_regime": "range", "open_label": "iron_condor",
"open_legs": 4, "unrealized_inr": 2100.0, "realized_inr": 5400.0},
],
},
}
def get_campaign():
if not LIVE:
return DEMO_CAMPAIGN
r = session.get(TRADEDASH_BASE_URL + "/api/options/campaign", timeout=15)
r.raise_for_status()
return r.json()
camp = get_campaign()
if camp.get("active"):
c = camp["campaign"]
print(f"equity Rs {c['total_equity_inr']:,.0f} | realized Rs {c['total_realized_inr']:,.0f}")
for s in c["series"]:
print(f" {s['symbol']}:{s['expiry']} score={s['last_score']:.0f} "
f"{s['last_bias']}/{s['last_regime']} {s['open_label'] or 'flat'} "
f"({s['open_legs']} legs) uPnL Rs {s['unrealized_inr']:,.0f}")
else:
print("no active campaign on this instance:", camp.get("note"))
Step 4 — wrapped broker reads¶
GET /api/broker/* passes straight through to the account's Dhan session:
ltp, quote, funds, positions, holdings. Prices take
?symbols=NIFTY,RELIANCE (index names are resolved automatically; equities
assume NSE cash) or ?security_ids=<id,id>&segment=<seg> for full control.
def broker_ltp(symbols):
if not LIVE:
return {"segment": "NSE_EQ", "ltp": {s: None for s in symbols.split(",")}}
r = session.get(TRADEDASH_BASE_URL + "/api/broker/ltp",
params={"symbols": symbols}, timeout=15)
r.raise_for_status()
return r.json()
def broker_funds():
if not LIVE:
return {"available": None, "utilised": None}
r = session.get(TRADEDASH_BASE_URL + "/api/broker/funds", timeout=15)
r.raise_for_status()
return r.json()
print("LTP :", broker_ltp("NIFTY,RELIANCE"))
print("funds:", broker_funds())
Full endpoint list¶
GET {BASE}/api/docs returns the machine-readable catalog plus a copy-paste
Python quick-start. Reachable without a token so you can inspect it first.
| Method | Path | Purpose |
|---|---|---|
| POST/GET/DELETE | /api/auth/token |
mint / inspect / revoke a token |
| GET | /api/options/chain ?symbol&expiry&range&broker |
live chain + greeks |
| GET | /api/options/greeks ?symbol&expiry&strike&opt_type |
one contract's greeks |
| GET | /api/options/expiries ?symbol |
expiry list (Dhan) |
| GET | /api/options/history ?symbol&from&to |
rolling historical option series |
| GET | /api/options/campaign · /campaign/ticks |
paper-desk state + equity log |
| POST | /api/options/paper |
paper-trade commands (never real) |
| GET | /api/candles ?symbol&from&to |
daily historical candles |
| GET | /api/watchlist |
your tenant watchlist + quotes |
| GET | /api/broker/{ltp,quote,funds,positions,holdings} |
wrapped Dhan reads |
Not reachable with these tokens: order placement, /api/sessions,
/api/control/*, /api/order-routing, anything admin.
« Previous: Prophet, Drive Lab & Three Projectors
Try the concepts above interactively: Options Strategy Builder · Docs · Get your static IP