A class is a blueprint that bundles together data (attributes) and behaviour (methods).
Instead of passing a trade dict to dozens of functions, a Trade object
knows its own entry, SL, target — and can compute its own P&L.
Trade is the class; my_trade is an instance.self.symbol, self.entry, self.pnl.trade.update_ltp(22450), trade.is_sl_hit().__init__Trade(...).class Trade: """Represents a single live or closed trade.""" def __init__(self, symbol, side, entry, lot_size, lots, sl_pts=150, tgt_pts=300): self.symbol = symbol self.side = side self.entry = entry self.lot_size = lot_size self.lots = lots self.sl = entry - sl_pts if side == "BUY" else entry + sl_pts self.target = entry + tgt_pts if side == "BUY" else entry - tgt_pts self.ltp = entry self.status = "OPEN" def update_ltp(self, ltp): """Update live price and check exit conditions.""" self.ltp = ltp if self.side == "BUY": if ltp <= self.sl: self.status = "SL_HIT" elif ltp >= self.target: self.status = "TARGET_HIT" def pnl(self): """Unrealised or realised P&L.""" mul = 1 if self.side == "BUY" else -1 return (self.ltp - self.entry) * self.lot_size * self.lots * mul def summary(self): print(f"{'='*40}") print(f"Symbol : {self.symbol} ({self.side})") print(f"Entry : ₹{self.entry} | LTP: ₹{self.ltp}") print(f"SL/TGT : ₹{self.sl} / ₹{self.target}") print(f"P&L : ₹{self.pnl():+,}") print(f"Status : {self.status}") print(f"{'='*40}") # Create a trade object t = Trade("NIFTY25JUNFUT", "BUY", entry=22300, lot_size=50, lots=2) t.update_ltp(22480) t.summary()
======================================== Symbol : NIFTY25JUNFUT (BUY) Entry : ₹22300 | LTP: ₹22480 SL/TGT : ₹22150 / ₹22600 P&L : ₹+18,000 Status : OPEN ========================================
A RiskManager class manages daily P&L, trade counts, and kill-switch logic — completely separate from trade logic. This is good separation of concerns.
class RiskManager: def __init__(self, capital, daily_loss_limit_pct=2.0, max_trades=5): self.capital = capital self.daily_loss_limit = -(capital * daily_loss_limit_pct / 100) self.max_trades = max_trades self.daily_pnl = 0 self.trades_taken = 0 def record_trade(self, pnl): self.daily_pnl += pnl self.trades_taken += 1 def can_trade(self): if self.daily_pnl <= self.daily_loss_limit: return False, "KILL: Daily loss limit hit" if self.trades_taken >= self.max_trades: return False, "KILL: Max trades reached" return True, "OK" def status(self): ok, reason = self.can_trade() print(f"Daily P&L : ₹{self.daily_pnl:+,}") print(f"Trades Taken : {self.trades_taken}/{self.max_trades}") print(f"Can Trade : {'✅ YES' if ok else '🚨 NO — ' + reason}") # Simulate a day rm = RiskManager(capital=500000, daily_loss_limit_pct=2.0, max_trades=5) rm.record_trade(12000) rm.record_trade(-8000) rm.record_trade(5500) rm.status()
Daily P&L : ₹+9,500 Trades Taken : 3/5 Can Trade : ✅ YES
Inheritance lets one class extend another. A VWAPStrategy inherits all the common behaviour of a BaseStrategy and adds its own signal logic.
class BaseStrategy: def __init__(self, symbol, lot_size): self.symbol = symbol self.lot_size = lot_size self.trades = [] def log_trade(self, trade): self.trades.append(trade) print(f"Trade logged: {trade['side']} {trade['symbol']} @ ₹{trade['entry']}") def total_pnl(self): return sum(t.get("pnl", 0) for t in self.trades) class VWAPStrategy(BaseStrategy): # inherits from BaseStrategy def __init__(self, symbol, lot_size, sl_pts=150, tgt_pts=300): super().__init__(symbol, lot_size) # call parent constructor self.sl_pts = sl_pts self.tgt_pts = tgt_pts def get_signal(self, ltp, vwap, rsi): if ltp > vwap and rsi < 65: return "BUY" if ltp < vwap and rsi > 35: return "SELL" return "HOLD" def on_tick(self, ltp, vwap, rsi): signal = self.get_signal(ltp, vwap, rsi) if signal in ("BUY", "SELL"): trade = {"symbol":self.symbol, "side":signal, "entry":ltp, "pnl":0} self.log_trade(trade) else: print(f"Tick: LTP={ltp} — HOLD") strat = VWAPStrategy("NIFTY25JUNFUT", lot_size=50) strat.on_tick(22485, 22380, 53) strat.on_tick(22410, 22450, 50) # HOLD
Trade logged: BUY NIFTY25JUNFUT @ ₹22485 Tick: LTP=22410 — HOLD
Zipline, Backtesting.py, and Zerodha's PyAlgomate all use this same inheritance pattern: a BaseStrategy with lifecycle methods (on_tick, on_candle, on_order_fill) that child classes override.
__init__ in a class?class VWAPStrategy(BaseStrategy), what does super().__init__() do?def update_ltp(self, ltp), what does self refer to?Candle class with attributes: open, high, low, close, volume.
Add methods: is_bullish() (returns True if close > open),
body_size() (returns abs(close - open)), and wick_ratio().
PositionManager class that stores open trades as a dict
keyed by symbol. Methods: open_trade(symbol, side, entry, lots),
close_trade(symbol, exit_price), get_pnl(symbol),
total_pnl().
self.positions = {}.NIFTYVWAPStrategy class with: __init__ (config),
on_tick(ltp, vwap, rsi) (generates signal), on_fill(price) (records trade),
and daily_report() (prints P&L summary and trade count).
self.trade_log = [] to store all trades.