Position Sizing & Risk Management¶
Fixed-fractional lot sizing and a hard max-loss guardrail.
Part 15 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).")
Position sizing is risk management, not a math afterthought¶
Fixed-fractional sizing risks a fixed percentage of current capital on each trade rather than a fixed number of lots. It's simple, but it does the one thing that matters most: it makes the size of a loss scale down automatically as capital shrinks, instead of a fixed lot count taking a proportionally bigger bite out of a smaller account after a losing streak.
Why a hard max-loss cap matters more than expected-value math. A strategy can have positive expected value over hundreds of trades and still blow up an account on a single oversized position — this is the "risk of ruin" problem. Expected value is an average over a distribution; ruin is about the tail of that distribution, and a large enough single loss removes you from the game before the average has a chance to play out. That's why guard_max_loss below is a hard raise, not a warning — a guardrail that can be silently ignored under pressure (in a live, moving market) is not a guardrail.
The psychological half of sizing. Position size that's mathematically "correct" but larger than a trader is emotionally prepared to lose tends to produce panic exits at the worst possible moment — which turns a manageable drawdown into a realized loss. Sizing conservatively enough to sit through a strategy's normal variance without deviating from the plan is itself part of risk management, not a separate soft-skills topic.
Fixed-fractional sizing + a hard max-loss guardrail — feed max_loss_per_lot from notebook 07/10's max_profit_loss() output for a real strategy.
def position_size(capital, risk_pct, max_loss_per_lot):
"""How many lots keep max loss within risk_pct of capital."""
if max_loss_per_lot <= 0:
return 0
return max(int((capital * risk_pct) // max_loss_per_lot), 0)
capital = 500_000
risk_pct = 0.02 # risk 2% of capital per trade
max_loss_per_lot = 4500 # from max_profit_loss()["maxLoss"] for one lot, notebooks 07/10
lots = position_size(capital, risk_pct, abs(max_loss_per_lot))
print(f"Capital Rs.{capital:,} at {risk_pct:.0%} risk -> {lots} lot(s), max loss Rs.{lots * abs(max_loss_per_lot):,}")
def guard_max_loss(strategy_max_loss, capital, hard_cap_pct=0.05):
if abs(strategy_max_loss) > capital * hard_cap_pct:
raise ValueError(f"strategy max loss {strategy_max_loss} exceeds hard cap {capital * hard_cap_pct}")
return True
guard_max_loss(lots * abs(max_loss_per_lot), capital)
« Previous: Backtest: Weekly Short Straddle
Next: Order Management System »
Try the concepts above interactively: Options Strategy Builder · Docs · Get your static IP