Paper Trading Loop¶
An SMA-crossover signal tracked as simulated paper trades.
Part 17 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).")
Why paper trade before risking capital¶
Paper trading replays a strategy's signal logic against historical or live prices and records what would have happened — without ever sending an order. It's the cheapest way to catch a broken signal, an off-by-one in your date handling, or a crossover rule that fires far more often than you intended, before any of it costs money.
It is not a substitute for live trading, though — a paper trading loop like the one below is missing three things that matter:
- Slippage. A market order to buy 75 quantity of an option doesn't always fill at the last traded price you saw; on a paper trade it always does.
- Fill uncertainty. A limit order might never fill, or might partially fill, when the real order book is thin. The simulation above assumes every signal becomes a full fill at the recorded close.
- Psychology. Paper trades carry no consequence, so they can't validate whether you will actually follow the strategy's exits when real money and a live drawdown are involved.
Treat a clean paper-trading run as evidence the logic works, not as evidence the strategy is profitable — those are different claims.
import pandas as pd
nifty = pd.read_csv("nifty_2y.csv", index_col=0, parse_dates=True)
nifty["sma_fast"] = nifty["Close"].rolling(10).mean()
nifty["sma_slow"] = nifty["Close"].rolling(30).mean()
nifty["signal"] = 0
nifty.loc[nifty["sma_fast"] > nifty["sma_slow"], "signal"] = 1
nifty.loc[nifty["sma_fast"] < nifty["sma_slow"], "signal"] = -1
nifty["position_change"] = nifty["signal"].diff().fillna(0)
trade_log = []
for date, row in nifty.dropna(subset=["sma_slow"]).iterrows():
if row["position_change"] != 0:
trade_log.append({"date": date, "signal": int(row["signal"]), "price": row["Close"]})
paper_trades = pd.DataFrame(trade_log)
print(f"{len(paper_trades)} paper trades generated")
paper_trades.tail()
« Previous: Order Management System
Next: Signal-to-Order Pipeline »
Try the concepts above interactively: Options Strategy Builder · Docs · Get your static IP