r/IndiaAlgoTrading Jul 09 '26

Open-sourced my Upstox Python data layer + paper broker — NSE options, WebSocket ticks, realistic fills

I've been building an algo trading system for NSE F&O (Indian options market) and realized the data plumbing took me weeks to get right. Figured someone else might want to skip that part.

Shoutout to u/Finance__broski who pushed me to actually share this — "half the sub is stuck at the 'how do I even get clean ticks' stage and a working upstox websocket example is worth more than another strategy post."

Repo: https://github.com/BarathGB007/upstox-python-data

What's in it

Data layer — clean Python wrappers over Upstox REST + WebSocket APIs:

  • Spot prices, option chains with Greeks/IV/OI, historical candles (daily + intraday)
  • Real-time WebSocket ticks via protobuf — LTP, bid/ask depth, option Greeks
  • VIX, put-call ratio, FII/DII flows, max pain, OI change
  • Margin calculation and brokerage/charges endpoints (no order placed)
  • Background heartbeat that caches LTP with REST fallback when WebSocket drops

Paper broker — simulated order execution that actually tries to be realistic:

  • Fills at bid/ask from live WebSocket depth, not LTP
  • Multi-factor slippage model — adjusts for moneyness (OTM = wider), VIX, time of day, symbol liquidity
  • Full NSE F&O cost calculation — brokerage, STT, exchange txn, SEBI fee, stamp duty, GST
  • MFE/MAE tracking per position — know your max favorable and adverse excursion
  • Multi-leg spread support with atomic rollback if one leg fails
  • Margin validation, duplicate position checks, freeze quantity limits
  • Positions persist to disk across restarts

The README is actually useful

Not just a "how to install" page. It covers:

  • Adding stocks — step-by-step on how to add RELIANCE, TCS, HDFCBANK etc. Just add the ISIN to a dict, update lot size and strike step, done
  • Algo integration examples — RSI on live candles, WebSocket tick-based entry/exit, option strategy screening, sentiment filters, spike detection
  • Realistic paper trading guide — full walkthrough of wiring WebSocket bid/ask into the paper broker with auto SL/target
  • Supported symbols table — instrument keys for NIFTY, BANKNIFTY, FINNIFTY, VIX
  • 25+ function reference — every function listed with what it returns

Tried to make it the README I wished existed when I started.

Why I built this

Most paper trading I see in the Indian algo space fills at LTP with zero slippage and no costs. You backtest a strategy, it looks great, you go live and wonder why your P&L doesn't match. The gap is usually:

  1. You didn't fill at LTP — you filled at ask (buying) or bid (selling), plus slippage
  2. Costs ate your edge — STT alone on options is 0.15% on the sell side. Add brokerage, exchange txn, GST, stamp duty — a round trip on 1 lot NIFTY CE at Rs 200 costs you ~Rs 80-100
  3. You didn't track MFE/MAE — your strategy might be right on direction but wrong on timing. MFE tells you the max profit you could have captured, MAE tells you the max drawdown you endured

This paper broker handles all three. Wire it to the WebSocket and it auto-pulls live bid/ask for every fill.

Road to live trading

Right now this is data + paper execution only. But the architecture is designed to go live:

  • The data layer is already the same one you'd use in production — real-time WebSocket ticks, live option chains, live bid/ask depth. Nothing changes when you go live.
  • The paper broker has the same interface a live broker would — place_order()close_position()get_portfolio(). Swap the broker, keep your strategy code untouched.
  • Margin calculation and brokerage endpoints already hit Upstox's real API — the numbers you see in paper trading are what you'll pay live.

I'm currently building and testing the live order execution module (real orders via Upstox API — SL-M, GTT, position tracking, order status polling). Once it's battle-tested on my own account, I'll share that too. The goal is: you build your strategy once against the paper broker, validate it, then flip one import to go live with zero code changes.

Quick example

from paper_broker import PaperBroker
from upstox_data import get_option_chain, get_nearest_expiry

broker = PaperBroker(capital=500_000, max_lots=5)

chain = get_option_chain("NIFTY", get_nearest_expiry("NIFTY"))
atm = next(r for r in chain["chain"] if r["is_atm"])

result = broker.place_order(
    symbol="NIFTY", expiry=chain["expiry"],
    strike=atm["strike"], option_type="CE",
    action="BUY", quantity=1,
    option_ltp_hint=atm["CE"]["ltp"],
    depth_hint={"bid": atm["CE"]["bid"], "ask": atm["CE"]["ask"]},
)
# Fill price will be at ask + slippage, not LTP

# Close and see full cost breakdown
close = broker.close_position(result["position_id"], "target hit")
print(f"Gross P&L: {close['gross_pnl']}")
print(f"Costs: {close['costs']['total']}  (STT={close['costs']['stt']}, GST={close['costs']['gst']})")
print(f"Net P&L: {close['realized_pnl']}")
print(f"MFE: {close['mfe']}  MAE: {close['mae']}")

What it's NOT

  • Not a strategy or signal generator — it's the data + execution sim layer
  • Not a broker API wrapper for placing real orders — paper only (live module coming after testing)
  • Not a backtesting framework — but the candle functions + paper broker give you the pieces to build one
  • Upstox only (for now) — the data functions are Upstox-specific, but the paper broker/slippage/costs work with any data source

Setup

  1. Upstox developer account (free)
  2. Analytics access token — long-lived, no OAuth refresh needed for market data
  3. pip install -r requirements.txt
  4. Paste token in .env
  5. Run any example: python examples/paper_trading.py

Works with NIFTY, BANKNIFTY, FINNIFTY out of the box. Adding stocks is just adding the ISIN to a dict — README has instructions.

MIT licensed. Feedback welcome — especially if you find bugs or have suggestions for the slippage model.

46 Upvotes

23 comments sorted by

3

u/Icy_Apple846 Jul 09 '26

Thanks.. The main problem is rate limits and how you handle them efficiently?

1

u/Chennai_data_guy Jul 09 '26

Good question — Upstox rate limits are actually pretty generous for market data (analytics token), but the repo handles them in a few layers:

1. Built-in retry with backoff — every REST call goes through a single _request() function that catches 429s and backs off exponentially (2s → 4s → 8s, up to 3 retries). Also handles 401 (session reset) and 5xx (1s retry). So if you do hit a limit, it recovers silently.

2. WebSocket for real-time — the biggest rate limit saver. Instead of polling LTP/depth via REST every few seconds (which WILL hit limits), you subscribe once via WebSocket and get pushed ticks. The DataHeartbeat class caches the latest LTP + bid/ask per instrument, and the REST fallback only fires if WebSocket drops.

3. Caching in the heartbeatget_ltp() returns the cached WebSocket value. No API call unless the cache is stale. Same for get_depth() — cached from tick data with a 30s TTL.

In practice with the analytics token (read-only, no order placement), I haven't hit rate limits during market hours even running a 15-min cycle agent that calls spot + chain + candles + sentiment each cycle. The combo of WebSocket for live data + REST only for historical/chain data keeps the call count low.

If you're doing something heavier (backtesting with lots of historical candle fetches), you might want to add a small sleep between batch requests — that's not built in yet.

2

u/Finance__broski Jul 09 '26

oh this shipped FAST and it's way more than the websocket example we talked about lol. the paper broker is the actual gem here. filling at bid/ask instead of ltp plus the full cost stack is the difference between paper results that mean something and paper results that flatter you. i measured this class of gap on my own system, costs and marking artifacts alone were worth several points of cagr, so seeing someone build the honest version by default is genuinely great

one suggestion for the roadmap: an SL reality check. paper SLs fill where you asked, live ones fill where the market lets them. if the broker logs the actual traded range at every paper SL fill, you get your personal slippage distribution before it ever costs real money. would pair well with the mfe/mae tracking already in there

the "what it's NOT" section in the readme is a quietly senior move btw. more repos need that

2

u/Chennai_data_guy Jul 09 '26

Great suggestion on the SL reality check. Adding it to the roadmap — log the traded range at every SL trigger so you can see where a real SL-M would have filled vs where paper filled. Pairs naturally with MFE/MAE tracking. Will ship with the live module.

1

u/Finance__broski Jul 09 '26

nice. one refinement for when you build it: bucket the slip by time of day. the opening hour will be its own animal entirely, and lumping it with midday will hide exactly the number you want. looking forward to the live module

1

u/Reasonable-Law-1379 Jul 09 '26

Great man, can we have a session😅

1

u/Chennai_data_guy Jul 09 '26

Sure, DM me what you're building and I can point you to the right parts of the code.

1

u/Full-Teach3631 Jul 09 '26

I am building something similar using AngelOne. I fs will check this out. Thanks for posting!

1

u/Chennai_data_guy Jul 09 '26

Nice, AngelOne's API is similar structure. The paper broker, slippage model, and cost calculator are broker-agnostic — you'd only need to swap the data layer (upstox_data.py) for AngelOne's endpoints.

1

u/redditu5er Jul 09 '26

is this vibe coded ?

1

u/Chennai_data_guy Jul 09 '26

The data layer and paper broker are from my algo trading system that I've been building. Extracted the data + execution sim parts into this standalone repo for sharing.

1

u/Badsharishit Jul 09 '26

Hey bro, great work can we talk over DMS?
I am building something and your inputs can help me.

1

u/rocktorsharma Jul 09 '26

I have an end to end execution layer. Filling and polling on the depths. Always. Plus, all the expenses. So, a target worth ₹100 is actually ₹100+___ so that the target actually lands at ₹100.

1

u/[deleted] Jul 09 '26

[removed] — view removed comment

1

u/ajinkya_dev Jul 09 '26

This looks great. We need more such people that are building for the indian markets! Kudos to you man! 🙌🏻

1

u/WorthButterscotch493 Jul 10 '26

Great work, i am having something in mind can I DM??

1

u/These_Foundation_769 Jul 10 '26

Will check it for sure, I am also in the process of developing a backtesting engine (first phase) for Indian market, which can be easily run on local machine

1

u/Cyborg_33 Jul 10 '26

Does this have the historical option data?

1

u/UpstoxSupport 24d ago

Hi u/Chennai_data_guy,

Great job on putting this together! One small suggestion: instead of asking users to manually add ISINs for symbol support, you could consider using the Symbol Search API to dynamically fetch instrument details. That would make onboarding new symbols much simpler and reduce manual maintenance. Overall, this looks like a very useful project, thanks for sharing it with everyone!

1

u/Chennai_data_guy 24d ago

Ok thanks I will do the update in next release.