Capstone: End-to-End Algo Bot¶
SDK + strategy template + risk sizing + dry-run OMS dispatch, combined.
Part 19 of 37 in the ServLoci algo/options trading notebook series — full index in notebooks/README.md.
Setup¶
# Get your dedicated static IPv6 + SOCKS5 credentials free:
# https://comm.servloci.in/register (or /auth/google?free=1 for an instant trial)
# Your api_key / api_secret pair shows up in the portal after signup:
# https://comm.servloci.in/user
!pip install -q "requests[socks]"
!curl -sL https://comm.servloci.in/sdk/servloci.py -o servloci.py
import os
from servloci import ServLoci
SERVLOCI_API_KEY = os.environ.get("SERVLOCI_API_KEY", "dhan:1000000001") # broker:client_id
SERVLOCI_API_SECRET = os.environ.get("SERVLOCI_API_SECRET", "") # from the portal — leave blank to run this notebook in demo mode
sl = None
if SERVLOCI_API_SECRET:
sl = ServLoci(api_key=SERVLOCI_API_KEY, api_secret=SERVLOCI_API_SECRET)
print("ServLoci configured:", sl.host, sl.port)
else:
print("SERVLOCI_API_SECRET not set — running in demo mode (no live proxy calls).")
The request path of a real algo-trading system¶
Every earlier notebook in this course covered one link in a chain. This capstone runs the whole chain in one script, so the shape of a real system is visible end to end:
- Static IP + SDK (00-01) — a stable, whitelistable egress address, because most Indian broker APIs bind an app to a fixed IP.
- Broker auth (02-05) — exchange credentials for a session that can read data and place orders.
- Options math (06-10) — price a leg, know its Greeks, and choose a strategy template with a bounded, understood risk profile (an iron condor, here).
- Data + backtesting (11-14) — decide what to trade using historical evidence, not a hunch.
- Risk sizing (15) — turn "this strategy has a known max loss per lot" into "here is how many lots this account is allowed to hold."
- Execution (16-18) — an OMS that owns the order lifecycle, and a signal→dispatch boundary that can reject a bad decision before it fires.
run_once() below chains steps 3, 5, and 6 for a single iron condor: it sizes
the position from the account's risk budget, builds the four legs, and either
dry-run logs or dispatches each leg's order.
This is a skeleton, not a trading system you should run with real capital. Every notebook in this course used illustrative pricing, demo data, or dry-run dispatch — none of it accounted for brokerage, slippage, margin requirements, or what happens when an order partially fills mid-adjustment. Moving from this to live capital is a separate project: it needs its own risk review, a kill switch, monitoring for when the strategy's live behavior diverges from its backtest, and capital you can afford to lose while you find out where the model is wrong.
import logging
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
log = logging.getLogger("servloci-bot")
DRY_RUN = True
def nearest_strike(spot, step):
return round(spot / step) * step
def iron_condor(spot, step, qty=1):
atm = nearest_strike(spot, step)
return [
{"side": "sell", "type": "CE", "strike": atm + 2 * step, "qty": qty},
{"side": "buy", "type": "CE", "strike": atm + 4 * step, "qty": qty},
{"side": "sell", "type": "PE", "strike": atm - 2 * step, "qty": qty},
{"side": "buy", "type": "PE", "strike": atm - 4 * step, "qty": qty},
]
def position_size(capital, risk_pct, max_loss_per_lot):
if max_loss_per_lot <= 0:
return 0
return max(int((capital * risk_pct) // max_loss_per_lot), 0)
def run_once(spot, capital=500_000, risk_pct=0.02, assumed_max_loss_per_lot=4500):
lots = position_size(capital, risk_pct, assumed_max_loss_per_lot)
if lots == 0:
log.warning("position size is 0 lots at current risk budget — skipping")
return
legs = iron_condor(spot, step=50, qty=lots)
log.info("built iron condor: %s", legs)
if sl is None:
log.info("[DRY RUN — no SERVLOCI_API_SECRET] would dispatch %d lot(s)", lots)
return
session = sl.session()
# oms = OrderManager(session, base_url=os.environ["BROKER_API_BASE"]) # from notebook 16
for leg in legs:
order = {
"symbol": f"NIFTY{leg['strike']}{leg['type']}",
"transaction_type": "BUY" if leg["side"] == "buy" else "SELL",
"quantity": leg["qty"] * 75,
"order_type": "MARKET",
"product": "INTRADAY",
}
if DRY_RUN:
log.info("[DRY RUN] would place: %s", order)
else:
pass # oms.place(order)
run_once(spot=24000)
What this course covered¶
static IP (00) → SDK (01) → broker auth (02-05) → options pricing and Greeks (06-07) → strategy templates (08-10) → live data (11-12) → backtesting (13-14) → position sizing (15) → order management, paper trading, and a signal pipeline (16-18) → this capstone (19). Each stage above is a real, separately-testable component of a trading system — the discipline is in keeping them separate, not in any one clever indicator or strategy.
Continue with the broker API and indicator learning path in notebooks 20-23: comparing broker APIs, computing 50 indicators without a TA dependency, wiring broker candles into that indicator engine, and generating de-duplicated, risk-checked alerts.
Keep building at https://comm.servloci.in/tools/strategy-builder, or grab your own static IP at https://comm.servloci.in/register.
« Previous: Signal-to-Order Pipeline
Next: Indian Broker API Landscape »
Try the concepts above interactively: Options Strategy Builder · Docs · Get your static IP