Capstone: End-to-End Algo Bot¶
SDK + strategy template + risk sizing + dry-run OMS dispatch, combined.
Part 19 of 20 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).")
Combines the SDK, an options template, risk-based sizing, and dry-run order dispatch into one runnable skeleton — the sum of notebooks 01, 10, 15, 16.
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)
That's the series. Recap: static IP (00) → SDK (01) → broker auth (02-05) → options math (06-10) → live data (11-12) → backtesting (13-14) → risk + execution (15-19).
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
Try the concepts above interactively: Options Strategy Builder · Docs · Get your static IP