Options Income Strategies System
Executive Summary & Implementation Roadmap
Executive Overview
This comprehensive guide delivers a complete options income generation system for Indian markets, designed for ₹5-10 lakh capital. The framework prioritizes regime-adaptive strategy selection, risk-first execution, and scalable implementation from manual trading to full automation.
Top 3 Recommended Starting Strategies:
- Short Iron Condor (Sideways/Low Vol) — High win-rate, defined risk, capital-efficient
- Credit Put Spreads (Neutral-Bullish) — Directional bias with controlled risk
- Short Strangles with Protective Wings (Sideways/Medium Vol) — Higher premium, managed tail risk
Capital Deployment Philosophy:
- Start with 10-15% of capital per strategy (₹50k-₹1.5L per position)
- Maximum 3 concurrent strategies initially
- Reserve 40% capital for margin buffer and opportunity reserve
- Per-trade risk cap: 1.5-2% of total capital (₹7.5k-₹20k max loss per trade)
Expected Timeline to Proficiency:
- Weeks 1-2: Setup, backtesting infrastructure, paper trading
- Months 2-3: Live pilot with micro-positions (₹25-50k notional)
- Months 4-6: Scale to full position sizing with 3-4 active strategies
- Month 6+: Portfolio diversification and automation layers
Strategy Universe: 12 Options Income Strategies
Regime Classification Matrix
| Strategy | Bull | Bear | Sideways | High Vol | Low Vol | Capital Efficiency | Complexity |
|---|---|---|---|---|---|---|---|
| 1. Short Iron Condor | ○ | ○ | ● | ○ | ● | High | Medium |
| 2. Credit Put Spread | ● | ○ | ● | ○ | ● | High | Low |
| 3. Credit Call Spread | ○ | ● | ● | ○ | ● | High | Low |
| 4. Short Strangle + Wings | ○ | ○ | ● | ● | ○ | Medium | Medium |
| 5. Ratio Put Spread | ● | ○ | ● | ● | ○ | High | High |
| 6. Calendar Spread (Put/Call) | ○ | ○ | ● | ● | ○ | Medium | High |
| 7. Jade Lizard | ● | ○ | ● | ○ | ● | High | Medium |
| 8. Big Lizard | ○ | ● | ● | ○ | ● | High | Medium |
| 9. Diagonal Spread | ● | ● | ● | ● | ○ | Medium | High |
| 10. Iron Butterfly | ○ | ○ | ● | ○ | ● | High | Medium |
| 11. Covered Strangle (Cash-secured) | ○ | ○ | ● | ● | ○ | Low | Low |
| 12. Butterfly Spread (Debit) | ○ | ○ | ● | ○ | ● | Very High | Medium |
Legend: ● Primary fit | ○ Secondary fit
STRATEGY CARD 1: Short Iron Condor
Overview
- Name: Short Iron Condor (4-leg neutral strategy)
- Regime Fit: Sideways/Rangebound markets, Low-to-Medium Volatility
- Goal: Collect premium from time decay while price remains within defined range
- Win Rate (Typical): 65-75% (hypothetical, structure-dependent)
Intuition
Sell OTM call spread + OTM put spread simultaneously. Profit from theta decay when underlying stays between short strikes. Defined max risk through long wings.
Instruments
- Primary: NIFTY Index options (weekly expiry preferred for faster theta)
- Alternative: BANKNIFTY (higher premiums, more volatile), Liquid stocks (RELIANCE, INFY, TCS)
- Expiry: 7-14 DTE (Days To Expiry) for optimal theta/gamma balance
- Lot Size Reference: NIFTY = 25 units/lot (verify current), BANKNIFTY = 15 units/lot (verify current)
Exact Setup
Strike Selection Rules:
Underlying = Spot price at entry
Short Put Strike = Spot - (1.5-2 × ATR_14) ≈ 16-20 delta
Long Put Strike = Short Put - ₹100-200 (NIFTY) [wing width]
Short Call Strike = Spot + (1.5-2 × ATR_14) ≈ 16-20 delta
Long Call Strike = Short Call + ₹100-200 (NIFTY)
Example (NIFTY @ 22,000):
- Sell 21,700 Put (0.18 delta)
- Buy 21,600 Put (0.12 delta)
- Sell 22,300 Call (0.18 delta)
- Buy 22,400 Call (0.12 delta)
Net Credit = ₹60/unit × 25 units = ₹1,500 per lot
Max Risk = (₹100 wing width - ₹60 credit) × 25 = ₹1,000 per lot
Position Sizing (for ₹5L capital):
- Conservative: 1 lot (₹1,000 risk = 0.2% capital)
- Moderate: 3-5 lots (₹3-5k risk = 0.6-1% capital)
- Aggressive: 8-10 lots (₹8-10k risk = 1.6-2% capital)
- Margin Requirement: ≈₹25-35k per lot (verify with broker SPAN+Exposure)
Entry Rules (Precise Triggers)
Primary Filter:
- IV Percentile Check: Enter when NIFTY VIX is in 20th-60th percentile of 90-day range (neither extreme high nor extreme low)
- Trend Filter: ADX < 25 (weak trend = good for range-bound strategy)
- Momentum Filter: Close price within ±0.75% of 20-day SMA
- Time Filter: Enter Monday-Wednesday (avoid Thursday/Friday for weekly expiries)
Technical Confirmation:
- Bollinger Bands: Price in middle 40-60% of band width
- RSI between 40-60 (no strong directional momentum)
- No major earnings/events within expiry window
Execution Timing:
- First 30 min after open: Avoid (high volatility)
- 10:00-11:30 AM or 2:00-3:00 PM: Preferred (better pricing)
Exit Rules
Profit Targets:
- Primary: Close at 50-60% of max credit (₹30-36 per unit in example)
- Theta Decay Target: If 70% of time expired with profit >40% of max, close
- Early Exit: Volatility crush (VIX drops 15%+) → take 40% profit
Stop Losses:
- Hard Stop: Position reaches 200% of credit received (₹120 loss per unit = ₹3,000 per lot)
- Dynamic Stop: If underlying breaches short strike → close immediately
- Gamma Threshold: If delta magnitude exceeds 0.30 on either side → reduce/exit
Time-Based Rules:
- Exit at 2 DTE regardless of P&L (avoid assignment/gamma risk)
- If position profitable and <5 DTE, consider rolling to next week
Adjustment Rules:
- Threatened Side: If underlying approaches short strike (within 50% of width):
- Roll threatened spread out and up/down (collect more credit)
- Add protective long option on threatened side
- Inverted Position: If position shows loss >100% credit, close entire structure
Greeks Profile
At Entry (Target Values):
Delta: ±0.05 to 0.10 (near delta-neutral)
Gamma: -0.08 to -0.15 (negative, increases near short strikes)
Theta: +25 to +45 per day per lot (our profit engine)
Vega: -8 to -15 (profit from vol decrease, risk from vol spike)
Greeks Evolution:
- Days 7-10: Theta acceleration (sweet spot)
- Days 3-5: Gamma explosion (danger zone if ATM)
- Days 0-2: Assignment risk, exit recommended
Portfolio Greeks Limits:
- Net Portfolio Delta: ±0.15 per ₹1L capital
- Net Portfolio Vega: <₹5,000 exposure per VIX point
Transaction Cost Model (India)
Per-Leg Costs (per lot):
Brokerage: ₹20-40 per executed order (flat fee model, verify with broker)
STT (Securities Transaction Tax): 0.0625% on sell side premium (options)
Exchange Charges: ≈0.05% of premium
GST: 18% on brokerage
SEBI Turnover Fee: ₹10 per ₹1 crore turnover
Stamp Duty: 0.003% on buy side (State-dependent)
Example Iron Condor (4 legs, entry + exit = 8 orders):
- Brokerage: 8 × ₹30 = ₹240
- STT (on 2 short legs, ₹1,500 credit): 0.0625% × ₹1,500 = ₹0.94 (minimal)
- Exchange + GST + Misc: ≈₹100
Total Round-Trip Cost: ≈₹350-400 per lot
Breakeven Impact: ₹400/25 units = ₹16 per unit (reduce net credit by ₹16)
Cost Optimization:
- Use limit orders (avoid market impact)
- Batch orders at favorable spreads
- Consider zero-brokerage plans for high-frequency
Position Sizing Formula
# Conservative sizing
max_risk_per_trade = 0.015 # 1.5% of capital
capital = 500000 # ₹5L
max_loss_per_lot = (wing_width - net_credit) * lot_size
# Example: (100 - 60) × 25 = ₹1,000
lots = floor(capital × max_risk_per_trade / max_loss_per_lot)
# = floor(500000 × 0.015 / 1000) = 7 lots
# But check margin:
margin_per_lot = 30000 # Approx, verify
total_margin_needed = lots × margin_per_lot = 7 × 30000 = ₹210,000
# Ensure margin < 50% of capital:
if total_margin_needed > 0.5 × capital:
lots = floor(0.5 × capital / margin_per_lot) # = 8 lots max
Final Position Size: 5-7 lots for ₹5L capital (moderate risk)
Hedging & Safety Rules
Delta Hedge Trigger:
- If net position delta exceeds ±0.15: Buy/sell underlying futures in 0.5 lot increments
- Hedge cost: Factor in ₹100-200 slippage per adjustment
Vega Protection:
- If VIX spikes >25% in single day → add long ATM straddle (10-15% of iron condor premium) as insurance
- Alternatively: Close position and re-enter after vol stabilizes
Protective Long Options:
- If one side threatened, add extra long wing:
- Already short 22,300 Call, buy additional 22,500 Call for protection
Margin Spike Protection:
- Maintain 40-50% capital as cash buffer
- Set broker margin alerts at 70% usage
- Pre-authorize intraday square-off if margin breached
Known Failure Modes
Gap Risk (Overnight/Weekend):
- Problem: Underlying gaps through short strike, immediate max loss
- Mitigation: Reduce position size before event risk, avoid holding over long weekends, use tighter wings
Volatility Explosion:
- Problem: VIX spikes 40%+ (e.g., geo-political event), vega losses overwhelm theta gains
- Mitigation: IV percentile filter, protective long options, exit early if VIX >75th percentile
Whipsaw (Trend Reversal):
- Problem: Price breaks out of range, hits one side, then reverses to other side
- Mitigation: Widen initial range, use ADX filter, roll aggressively on first breach
Assignment Risk (ITM Expiry):
- Problem: Short options expire ITM → futures assignment, margin explosion
- Mitigation: Exit by 2 DTE, never hold ITM options into expiry
Liquidity Crunch:
- Problem: Wide bid-ask on illiquid strikes → slippage exceeds profit
- Mitigation: Trade only NIFTY/BANKNIFTY, avoid far OTM wings (>4 standard deviations)
Serial Correlation (Bad Month):
- Problem: 4-5 losing trades in row due to sustained trend/volatility
- Mitigation: Max 3 active positions, pause after 2 consecutive losses >100% credit
Parameter Presets
Conservative (Recommended for First 3 Months):
Wing Width: ₹150-200 (NIFTY)
Delta Target: 0.12-0.15 per side
DTE Entry: 10-14 days
Profit Target: 60% max credit
Stop Loss: 150% of credit
Max Position Size: 3 lots for ₹5L capital
Entry IV Percentile: 25th-50th
Moderate (After 3 Months Profitability):
Wing Width: ₹100-150
Delta Target: 0.16-0.20 per side
DTE Entry: 7-10 days
Profit Target: 50% max credit
Stop Loss: 200% of credit
Max Position Size: 5-7 lots for ₹5L capital
Entry IV Percentile: 20th-60th
Aggressive (Experienced Traders Only):
Wing Width: ₹50-100
Delta Target: 0.20-0.25 per side
DTE Entry: 5-7 days
Profit Target: 40% max credit
Stop Loss: 250% of credit
Max Position Size: 8-10 lots for ₹5L capital
Entry IV Percentile: 15th-70th
Note: Requires active intraday monitoring
Backtest Recipe
Data Requirements:
- NIFTY Spot minute data (1-min or 5-min bars) — last 2-3 years
- NIFTY Options chain: strikes, bid/ask/last, IV, OI, volume — daily snapshots
- VIX daily close
- Interest rates (NSE published, typically 6-7% for India)
- Dividend schedule (minimal impact for index options)
Modeling Considerations:
# Pseudocode structure
def backtest_iron_condor(data, params):
capital = 500000
positions = []
for date in trading_days:
# Entry logic
if should_enter(date, data, params):
spot = data.loc[date, 'NIFTY_close']
atr = calculate_atr(data, date, period=14)
# Strike selection
short_put = round_to_strike(spot - 1.8 * atr)
long_put = short_put - params['wing_width']
short_call = round_to_strike(spot + 1.8 * atr)
long_call = short_call + params['wing_width']
# Get premiums (use mid of bid-ask or last)
credit = get_credit(date, short_put, long_put, short_call, long_call)
# Position sizing
max_loss = (params['wing_width'] - credit) * 25
lots = min(
floor(capital * params['max_risk_pct'] / max_loss),
floor(capital * 0.5 / get_margin(date))
)
position = {
'entry_date': date,
'expiry': get_next_expiry(date, params['dte']),
'strikes': [long_put, short_put, short_call, long_call],
'credit': credit,
'lots': lots,
'max_loss': max_loss * lots
}
positions.append(position)
# Exit logic (check all open positions)
for pos in open_positions:
pnl = calculate_pnl(pos, data.loc[date])
dte = (pos['expiry'] - date).days
# Exit rules
if pnl > 0.5 * pos['credit'] * pos['lots']: # Profit target
close_position(pos, date, 'profit_target')
elif pnl < -2.0 * pos['credit'] * pos['lots']: # Stop loss
close_position(pos, date, 'stop_loss')
elif dte <= 2: # Time exit
close_position(pos, date, 'time_exit')
elif breached_short_strike(pos, data.loc[date]): # Dynamic stop
close_position(pos, date, 'strike_breach')
return calculate_metrics(positions)
def calculate_pnl(position, current_data):
# MTM using Black-Scholes or mid-market prices
current_values = []
for strike, option_type in position['strikes']:
current_val = get_option_price(current_data, strike, option_type)
current_values.append(current_val)
# P&L = initial credit - current debit
current_debit = (current_values[1] - current_values[0] +
current_values[2] - current_values[3])
pnl = (position['credit'] - current_debit) * 25 * position['lots']
return pnl
Slippage & Fill Model:
- Use mid-price for entry/exit or assume 1-2 ticks slippage per leg
- For bid-ask spread: Assume 0.5-1.0% of premium for liquid strikes
- Reject fills if spread > 5% of mid price (illiquidity filter)
Synthetic P&L Calculation:
- Use Black-Scholes for Greeks and mark-to-market
- Implied volatility surface: Interpolate from available strikes
- Handle early assignment: Check if ITM amount > remaining time value
Performance Metrics (Hypothetical Thresholds):
Target Metrics (Conservative Preset):
- Win Rate: >60%
- Avg Win / Avg Loss: >0.8
- Max Drawdown: <15% of capital
- Profit Factor: >1.5
- Expectancy: >0.5% per trade
- Sharpe Ratio: >1.0 (annualized)
If backtest shows metrics below these, adjust:
- Widen wings (reduce risk)
- Tighten entry filters (ADX, IV percentile)
- Increase profit target percentage
STRATEGY CARD 2: Credit Put Spread (Bull Put Spread)
Overview
- Name: Credit Put Spread / Bull Put Spread
- Regime Fit: Neutral-to-Bullish, Low-to-Medium Volatility
- Goal: Collect premium betting price stays above short strike
- Win Rate (Typical): 70-80% (hypothetical, structure-dependent)
Intuition
Sell OTM put, buy further OTM put for protection. Profit if underlying stays above short put strike. Simpler than iron condor, capital-efficient, directional bias.
Instruments
- Primary: NIFTY/BANKNIFTY weekly options (7-14 DTE)
- Alternative: Liquid large-caps (RELIANCE, HDFCBANK, TCS) for monthly expiry
- Lot Size: NIFTY = 25, BANKNIFTY = 15
Exact Setup
Strike Selection:
Current Spot = S
Short Put Strike = S - (1.0-1.5 × ATR_14) ≈ 20-30 delta
Long Put Strike = Short Put - ₹100-150 (NIFTY)
Example (NIFTY @ 22,000):
- Sell 21,800 Put (0.25 delta)
- Buy 21,650 Put (0.15 delta)
Net Credit = ₹45/unit × 25 = ₹1,125 per lot
Max Risk = (₹150 width - ₹45 credit) × 25 = ₹2,625 per lot
Risk/Reward = 2.33:1
Position Sizing (₹5L capital):
- Conservative: 2 lots (₹5,250 risk = 1.05%)
- Moderate: 3-4 lots (₹7,875-10,500 risk = 1.6-2.1%)
- Margin: ≈₹18-25k per lot
Entry Rules
Primary Filters:
- Bullish Bias: NIFTY above 20-SMA AND RSI > 50
- Vol Environment: VIX < 60th percentile (not too high)
- Support Level: Short put strike near recent support or psychological level
- Momentum: 5-day return > 0 (recent uptrend)
Timing:
- Enter Monday-Wednesday for weekly expiry
- Avoid day-before or day-of major events (Fed, RBI, election results)
Exit Rules
Profit Target: 50-70% of max credit (₹22-32 per unit) Stop Loss: 200-250% of credit (₹90-112 per unit loss) Time Exit: Close at 2 DTE Dynamic: If short put breached → exit immediately
Greeks Profile
Delta: +0.15 to +0.25 (bullish exposure)
Gamma: -0.05 to -0.10 (short gamma)
Theta: +15 to +30 per day (time decay profit)
Vega: -5 to -10 (short volatility)
Hedging: If NIFTY falls 2%+ in session, consider buying ATM put as protection (costs ₹800-1,200, limits downside)
Failure Modes
- Sharp Selloff: Gap down through support → max loss
- Mitigation: Wider spreads, reduce size before events
- Volatility Spike: VIX jumps 30%+ → mark-to-market loss
- Mitigation: Exit if VIX enters 90th percentile
Parameter Presets
Conservative:
- Width: ₹150-200, Delta: 0.20-0.25, DTE: 10-14, Size: 2 lots per ₹5L
Moderate:
- Width: ₹100-150, Delta: 0.25-0.30, DTE: 7-10, Size: 3-4 lots per ₹5L
Aggressive:
- Width: ₹50-100, Delta: 0.30-0.35, DTE: 5-7, Size: 5-6 lots per ₹5L
Backtest Recipe
Similar to Iron Condor but:
- Only model put spread (2 legs)
- Check for bullish filter in entry (price > SMA, RSI > 50)
- Assignment simulation: If short put ITM at expiry, assume futures assignment at strike price
STRATEGY CARD 3: Short Strangle with Protective Wings
Overview
- Name: Short Strangle with Protective Wings (Modified Iron Fly variant)
- Regime Fit: Sideways, Medium-to-High Volatility (collect large premium)
- Goal: Higher credit than iron condor, tail-risk protected
- Win Rate (Typical): 60-70%
Intuition
Sell OTM put and OTM call (strangle) to collect high premium in volatile markets. Add far OTM wings (long put/call) to cap black-swan risk. Wider breakevens than iron condor.
Instruments
- Primary: NIFTY/BANKNIFTY weekly (7-14 DTE)
- High Vol Events: Earnings weeks, event-driven volatility
Exact Setup
Spot = 22,000
Short Put = 21,600 (0.25 delta)
Short Call = 22,400 (0.25 delta)
Long Put = 21,200 (0.08 delta) — 400 points away
Long Call = 22,800 (0.08 delta)
Credit (Short Strangle): ₹80/unit × 25 = ₹2,000
Cost (Long Wings): ₹15/unit × 25 = ₹375
Net Credit: ₹1,625 per lot
Max Risk (if wings hit): (400 - 65) × 25 = ₹8,375 per lot
Position Sizing (₹5L):
- Conservative: 1 lot (₹8,375 = 1.7% risk)
- Moderate: 2 lots (3.4% risk — at upper limit)
Entry Rules
- IV Rank: 40th-80th percentile (elevated vol, fat premiums)
- Range Expectation: Expect consolidation after volatility spike
- Technical: Price near middle of recent 30-day range
- Event Avoidance: No major announcements within 7 days
Exit Rules
Profit: 40-50% of net credit Stop Loss: If underlying reaches either short strike OR loss exceeds 2× credit Time: Exit by 3 DTE (gamma/assignment risk) Volatility: If VIX crashes below 25th percentile, take profits early (vol premium gone)
Greeks Profile
Delta: -0.05 to +0.05 (near neutral)
Gamma: -0.20 to -0.35 (high negative gamma, dangerous near expiry)
Theta: +50 to +80 per day (very high time decay)
Vega: -20 to -35 (high short vega, vulnerable to vol spikes)
Hedging:
- If one side threatened, close that spread or roll to next expiry
- Can dynamically add more long wings if vol explodes further
Failure Modes
- Sustained Breakout: Trend emerges, price breaches range → hit long wing
- Gamma Risk: If held to <3 DTE while ATM → uncontrollable delta swings
- Whipsaw: Breach one side, adjust, then breach other side
Mitigation: Use wider wings, never hold into last 2 days, aggressive rolling
Backtest Notes
- Model both strangle + wing costs
- Simulate wing payout if price exceeds short strike + wing distance
- Use implied volatility surface for realistic pricing (vol skew)
Manual Implementation Guide (Consolidated for All Strategies)
Pre-Trade Checklist
Market Context Check:
- Check NIFTY trend (above/below 20-SMA, 50-SMA)
- Check VIX level and percentile (use 90-day rolling window)
- Note ADX reading (trend strength)
- Review upcoming events calendar (expiry, F&O rollover, policy meetings, earnings)
Strategy Selection:
- Match current regime to strategy (use Regime Matrix)
- Confirm IV environment suitable for chosen strategy
- Verify sufficient liquidity in target strikes (OI > 1000 lots, volume > 500 lots)
Position Sizing Calculation:
Step 1: Calculate max loss per lot for chosen strategy Step 2: Risk per trade = Capital × 0.015 (1.5%) Step 3: Initial lots = floor(Risk per trade / Max loss per lot) Step 4: Margin check = Lots × Margin per lot < 50% of capital Step 5: Final lots = min(Step 3, Step 4)Strike Selection:
- Calculate ATR(14) from daily data
- Identify target delta strikes using option chain
- Verify bid-ask spread < 5% of mid-price
- Note breakeven points and probability of profit (from option chain)
Execution Checklist (Brokerage Platform)
Using Zerodha Kite / Upstox / Other Platforms:
Order Entry (Example: Iron Condor on NIFTY):
Step 1: Open Options Chain for NIFTY current week expiry Step 2: Identify 4 strikes per Strategy Card Leg 1: SELL 21,700 PE (Put) — Limit Order - Qty: 25 (1 lot) - Price: ₹32 (or better) Leg 2: BUY 21,600 PE — Limit Order - Qty: 25 - Price: ₹20 (or better) Leg 3: SELL 22,300 CE (Call) — Limit Order - Qty: 25 - Price: ₹30 (or better) Leg 4: BUY 22,400 CE — Limit Order - Qty: 25 - Price: ₹18 (or better) Target Net Credit: ₹24 per unit (₹600 total)Order Type Strategy:
- Use Limit Orders: Avoid market orders (protect against wide spreads)
- Leg Sequencing:
- Enter short legs first (collect credit)
- Then immediately enter long legs (protection)
- Or use "Basket Order" / "Strategy Builder" feature if available
- Price Adjustment: If no fill in 2 minutes, adjust limit by ₹1-2
Confirmation:
- All 4 legs filled
- Net credit received ≥ target credit (after slippage)
- Position shows correctly in "Positions" tab
- Margin blocked = expected amount
Monitoring & Management (Intraday)
Dashboard Metrics (Track in Spreadsheet or App):
| Time | NIFTY Spot | P&L (₹) | Delta | DTE | Action |
|---|---|---|---|---|---|
| 10:00 AM | 22,050 | +150 | +0.02 | 9 | Hold |
| 12:00 PM | 22,120 | +200 | +0.05 | 9 | Hold |
| 2:30 PM | 22,280 | -50 | +0.12 | 9 | Monitor (approaching call) |
| 3:15 PM | 22,310 | -180 | +0.18 | 9 | Consider adjustment |
Greeks Monitoring (Manual Calculation or Broker Dashboard):
- Check Delta: Should remain < 0.15 for neutral strategies
- If > 0.20: Consider delta hedge or close position
- Check Theta Decay: Expect ₹25-45 daily decay per lot (for iron condor)
- Check Vega Exposure: If VIX spikes >20%, recalculate position value
Adjustment Triggers (Intraday Alerts): (continued)
Price Alert: Set alerts at short strike ±25%
- Example: Short call at 22,300 → Alert at 22,225
- Short put at 21,700 → Alert at 21,775
P&L Alert: Set alerts at:
- +50% of max profit → Consider closing
- -150% of credit received → Prepare to exit
VIX Alert: If VIX jumps >15% in single session → review all positions
Manual Adjustment Procedures:
Scenario A: Price Threatens Call Side (Moving Up)
Current: NIFTY @ 22,250 (approaching 22,300 short call)
Action Options:
1. Roll Call Spread Up:
- Close 22,300/22,400 call spread
- Open 22,400/22,500 call spread
- Collect additional credit or pay small debit
2. Add Protective Long:
- Buy 22,350 CE (between current price and short strike)
- Cost: ₹400-600 per lot
3. Close Entire Position:
- If profit target not met but risk escalating
- Accept small loss to preserve capital
Execution: Place all closing orders as Limit orders first, then opening orders
Scenario B: Volatility Spike (VIX +25%)
Action:
1. Check mark-to-market P&L (will show paper loss)
2. If position still within range, consider holding (vol will revert)
3. If loss exceeds 200% credit, close position
4. Alternative: Close short strikes, keep long wings (convert to long strangle)
End-of-Day Operational Checklist
Daily Close Routine (3:20-3:30 PM):
Record Keeping:
Date: [DD-MM-YYYY] Strategy: [Iron Condor / Put Spread / etc.] Entry Date: [DD-MM-YYYY] DTE Remaining: [X days] Strikes: [21,600/21,700/22,300/22,400] Entry Credit: ₹60/unit Current MTM: ₹45/unit (₹375 profit per lot) Greeks: - Delta: +0.03 - Theta: +28/day - Vega: -12 NIFTY Close: 22,080 VIX Close: 14.2 Decision: Hold (profit = 25% of target, 9 DTE remaining)Risk Assessment:
- Calculate overnight exposure: Total position value × sensitivity to 2% gap
- Check margin utilization: Should be < 60% of available
- Review next day's calendar: Any major events?
- Set alerts for next day (price, P&L thresholds)
Position Health Check:
- All positions within acceptable delta range?
- Any position showing loss > 100% credit?
- DTE < 3 for any position? (Flag for exit)
- Aggregate portfolio delta within ±0.15 per ₹1L capital?
Transaction Log Update:
Trade_ID, Date, Strategy, Action, Strikes, Lots, Credit_Debit, Fees, Net_PnL, Notes IC_001, 01-11-2024, Iron Condor, Entry, 21600/21700/22300/22400, 3, 1800, -400, 0, "Entry clean" IC_001, 05-11-2024, Iron Condor, Hold, -, -, -, -, +900, "Day 4, profit 50%"Weekly Review (Every Friday):
- Calculate weekly P&L across all strategies
- Review win rate: # wins / # closed trades
- Compare actual vs expected theta decay
- Adjust position sizing if consecutive losses (pause or reduce)
- Update strategy performance dashboard
Position Sizing Examples with Real Numbers
Example 1: Conservative Trader with ₹5L Capital
Capital: ₹500,000
Risk per trade: 1.5%
Max risk per trade: ₹7,500
Strategy: Iron Condor (NIFTY)
Max loss per lot: ₹1,000
Max lots by risk: 7,500 / 1,000 = 7 lots
Margin per lot: ₹30,000
Max lots by margin (50% rule): 250,000 / 30,000 = 8 lots
Final position size: 7 lots (risk-constrained)
Total margin: ₹210,000 (42% utilization — safe)
Credit received: 7 × ₹1,500 = ₹10,500
Max potential loss: 7 × ₹1,000 = ₹7,000
R:R = 1.5:1
Example 2: Moderate Trader with ₹10L Capital
Capital: ₹1,000,000
Risk per trade: 2%
Max risk per trade: ₹20,000
Strategy 1: Iron Condor (NIFTY) — 15 lots
- Risk: 15 × ₹1,000 = ₹15,000
- Margin: 15 × ₹30,000 = ₹450,000
Strategy 2: Credit Put Spread (BANKNIFTY) — 4 lots
- Risk: 4 × ₹2,600 = ₹10,400
- Margin: 4 × ₹40,000 = ₹160,000
Total margin: ₹610,000 (61% utilization)
Total risk: ₹25,400 (2.54% — slightly over but diversified)
Reserve: ₹390,000 for adjustments/opportunities
Example 3: Risk Budget Allocation Across Multiple Strategies
Capital: ₹500,000
Total risk budget: 5% = ₹25,000 (across all positions)
Allocation:
- Strategy 1 (Iron Condor): 2% risk = ₹10,000 → 10 lots
- Strategy 2 (Put Spread): 1.5% risk = ₹7,500 → 3 lots
- Strategy 3 (Strangle + Wings): 1.5% risk = ₹7,500 → 1 lot
Total deployed: ₹25,000 risk
Margin used: ≈₹350,000 (70% — acceptable for diversified portfolio)
Quant / Algo Implementation Blueprint
System Architecture Overview
┌─────────────────────────────────────────────────────────┐
│ Data Layer │
│ - Historical OHLCV (underlying) │
│ - Options chain snapshots (daily/intraday) │
│ - Greeks & IV surface │
│ - VIX, interest rates, dividends │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Signal Generation Engine │
│ - Regime detection (trend/vol classification) │
│ - Entry filters (IV percentile, ADX, RSI) │
│ - Strike selection algorithm │
│ - Position sizing calculator │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Backtest Engine │
│ - Vectorized or event-driven simulation │
│ - Greeks calculation (Black-Scholes) │
│ - Transaction cost model │
│ - Walk-forward validation │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Live Execution Layer │
│ - Order management system (OMS) │
│ - Broker API integration (Kite/Upstox) │
│ - Position tracking & Greeks monitor │
│ - Risk kill-switch logic │
└─────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ Monitoring & Alerting │
│ - Real-time P&L dashboard │
│ - Greeks aggregation │
│ - Margin utilization tracker │
│ - Email/SMS alerts │
└─────────────────────────────────────────────────────────┘
Data Requirements & Schema
1. Underlying Data (NIFTY/BANKNIFTY)
# Daily OHLCV
columns = ['date', 'open', 'high', 'low', 'close', 'volume']
# Source: NSE historical data API, vendor (e.g., TrueData, Upstox)
# Intraday (for live trading)
columns = ['timestamp', 'open', 'high', 'low', 'close', 'volume']
# Frequency: 1-min or 5-min bars
2. Options Chain Data
# Daily snapshot (EOD) for backtesting
columns = [
'date', 'underlying', 'expiry_date',
'strike', 'option_type', # 'CE' or 'PE'
'ltp', 'bid', 'ask', 'volume', 'oi',
'iv', # Implied volatility
'delta', 'gamma', 'theta', 'vega' # Greeks (if available, else calculate)
]
# Live option chain (for trading)
# Fetch via broker API: kite.quote() or similar
# Frequency: Real-time or every 30-60 seconds
3. VIX Data
# India VIX (volatility index)
columns = ['date', 'vix_close']
# Source: NSE website, vendor APIs
4. Risk-Free Rate & Dividends
# India: Use NSE T-Bill rates or RBI repo rate
# Typical: 6-7% annually
# Dividends: Minimal impact for index options, fetch for stock options
Signal Generation Logic (Pseudocode)
Module 1: Regime Detection
import pandas as pd
import numpy as np
from ta.trend import ADXIndicator, SMAIndicator
from ta.momentum import RSIIndicator
def detect_regime(df, vix_df):
"""
Classify market regime for strategy selection
Returns: {'regime': 'sideways'|'bull'|'bear',
'volatility': 'low'|'medium'|'high'}
"""
# Trend detection
df['sma_20'] = SMAIndicator(df['close'], window=20).sma_indicator()
df['sma_50'] = SMAIndicator(df['close'], window=50).sma_indicator()
adx = ADXIndicator(df['high'], df['low'], df['close'], window=14)
df['adx'] = adx.adx()
current_price = df['close'].iloc[-1]
sma_20 = df['sma_20'].iloc[-1]
sma_50 = df['sma_50'].iloc[-1]
adx_val = df['adx'].iloc[-1]
# Trend classification
if adx_val < 25: # Weak trend
regime = 'sideways'
elif current_price > sma_20 > sma_50:
regime = 'bull'
elif current_price < sma_20 < sma_50:
regime = 'bear'
else:
regime = 'sideways'
# Volatility classification
vix_percentile = calculate_percentile(vix_df['vix_close'], window=90)
if vix_percentile < 33:
volatility = 'low'
elif vix_percentile < 66:
volatility = 'medium'
else:
volatility = 'high'
return {'regime': regime, 'volatility': volatility, 'vix_percentile': vix_percentile}
def calculate_percentile(series, window=90):
"""Calculate current value percentile vs rolling window"""
recent = series.tail(window)
current = series.iloc[-1]
percentile = (recent < current).sum() / len(recent) * 100
return percentile
Module 2: Entry Signal Generator (Iron Condor Example)
def generate_iron_condor_signal(df, vix_df, option_chain, params):
"""
Determine if conditions met for iron condor entry
params: {
'dte_target': 10,
'vix_percentile_min': 20,
'vix_percentile_max': 60,
'adx_max': 25,
'rsi_min': 40,
'rsi_max': 60,
'wing_width': 100,
'delta_target': 0.18
}
"""
regime = detect_regime(df, vix_df)
# Filter 1: Regime check
if regime['regime'] != 'sideways':
return None
# Filter 2: Volatility check
if not (params['vix_percentile_min'] <= regime['vix_percentile'] <= params['vix_percentile_max']):
return None
# Filter 3: ADX check
adx_val = ADXIndicator(df['high'], df['low'], df['close'], window=14).adx().iloc[-1]
if adx_val > params['adx_max']:
return None
# Filter 4: RSI check
rsi_val = RSIIndicator(df['close'], window=14).rsi().iloc[-1]
if not (params['rsi_min'] <= rsi_val <= params['rsi_max']):
return None
# Filter 5: Day of week (avoid Thursday/Friday for weekly)
current_day = df.index[-1].dayofweek # 0=Monday, 4=Friday
if current_day >= 3: # Thursday or Friday
return None
# Passed all filters - generate strike selection
spot_price = df['close'].iloc[-1]
atr_14 = calculate_atr(df, period=14)
# Find strikes in option chain with target delta
expiry = get_next_expiry(df.index[-1], params['dte_target'])
strikes = select_iron_condor_strikes(
option_chain, spot_price, atr_14, expiry,
params['delta_target'], params['wing_width']
)
if strikes is None:
return None
return {
'strategy': 'iron_condor',
'entry_date': df.index[-1],
'expiry': expiry,
'spot_price': spot_price,
'strikes': strikes, # {'short_put': 21700, 'long_put': 21600, ...}
'regime': regime
}
def calculate_atr(df, period=14):
"""Calculate Average True Range"""
high_low = df['high'] - df['low']
high_close = np.abs(df['high'] - df['close'].shift())
low_close = np.abs(df['low'] - df['close'].shift())
ranges = pd.concat([high_low, high_close, low_close], axis=1)
true_range = ranges.max(axis=1)
atr = true_range.rolling(window=period).mean().iloc[-1]
return atr
def select_iron_condor_strikes(option_chain, spot, atr, expiry, delta_target, wing_width):
"""
Select strikes for iron condor based on delta and wing width
"""
# Filter to target expiry
chain = option_chain[option_chain['expiry_date'] == expiry]
if chain.empty:
return None
# Short put: spot - 1.8*ATR, target delta ≈ delta_target
target_put_strike = round_to_strike(spot - 1.8 * atr)
puts = chain[chain['option_type'] == 'PE']
short_put_row = puts.iloc[(puts['strike'] - target_put_strike).abs().argsort()[:1]]
if short_put_row.empty or abs(short_put_row['delta'].values[0]) < delta_target * 0.8:
return None
short_put_strike = short_put_row['strike'].values[0]
long_put_strike = short_put_strike - wing_width
# Short call: spot + 1.8*ATR
target_call_strike = round_to_strike(spot + 1.8 * atr)
calls = chain[chain['option_type'] == 'CE']
short_call_row = calls.iloc[(calls['strike'] - target_call_strike).abs().argsort()[:1]]
if short_call_row.empty or abs(short_call_row['delta'].values[0]) < delta_target * 0.8:
return None
short_call_strike = short_call_row['strike'].values[0]
long_call_strike = short_call_strike + wing_width
# Get premiums
strikes_dict = {
'short_put': short_put_strike,
'long_put': long_put_strike,
'short_call': short_call_strike,
'long_call': long_call_strike
}
# Add premium values
for key, strike in strikes_dict.items():
opt_type = 'PE' if 'put' in key else 'CE'
row = chain[(chain['strike'] == strike) & (chain['option_type'] == opt_type)]
if not row.empty:
strikes_dict[f'{key}_premium'] = row['ltp'].values[0]
# Calculate credit
net_credit = (strikes_dict.get('short_put_premium', 0) -
strikes_dict.get('long_put_premium', 0) +
strikes_dict.get('short_call_premium', 0) -
strikes_dict.get('long_call_premium', 0))
strikes_dict['net_credit'] = net_credit
strikes_dict['max_loss'] = wing_width - net_credit
return strikes_dict
def round_to_strike(price, strike_interval=50):
"""Round price to nearest valid strike"""
return round(price / strike_interval) * strike_interval
def get_next_expiry(current_date, dte_target):
"""
Get next expiry date matching DTE target
For weekly: Thursdays
"""
# Simplified: assuming weekly Thursday expiries
days_until_thursday = (3 - current_date.dayofweek) % 7
next_expiry = current_date + pd.Timedelta(days=days_until_thursday)
# Adjust to match dte_target
while (next_expiry - current_date).days < dte_target - 3:
next_expiry += pd.Timedelta(days=7)
return next_expiry
Backtest Engine (Event-Driven)
class OptionsBacktester:
def __init__(self, underlying_data, option_chain, vix_data, params):
self.underlying = underlying_data
self.option_chain = option_chain
self.vix = vix_data
self.params = params
self.capital = params['initial_capital']
self.positions = []
self.closed_positions = []
self.equity_curve = []
def run(self):
"""Main backtest loop"""
for date in self.underlying.index:
# Check for new entry signals
if self.should_check_entry(date):
signal = generate_iron_condor_signal(
self.underlying.loc[:date],
self.vix.loc[:date],
self.option_chain[self.option_chain['date'] == date],
self.params
)
if signal:
position = self.enter_position(signal, date)
if position:
self.positions.append(position)
# Manage existing positions
self.manage_positions(date)
# Record equity
self.record_equity(date)
return self.generate_results()
def enter_position(self, signal, date):
"""Execute entry with position sizing"""
# Calculate position size
max_loss_per_lot = signal['strikes']['max_loss'] * 25 # NIFTY lot size
risk_per_trade = self.capital * self.params['risk_per_trade']
lots = int(risk_per_trade / max_loss_per_lot)
# Margin check
margin_per_lot = self.estimate_margin(signal)
total_margin = lots * margin_per_lot
if total_margin > self.capital * 0.5:
lots = int(self.capital * 0.5 / margin_per_lot)
if lots < 1:
return None
# Apply transaction costs
entry_cost = self.calculate_transaction_cost(signal, lots, 'entry')
position = {
'id': len(self.positions) + 1,
'entry_date': date,
'expiry': signal['expiry'],
'strikes': signal['strikes'],
'lots': lots,
'entry_credit': signal['strikes']['net_credit'] * lots * 25,
'max_loss': max_loss_per_lot * lots,
'entry_cost': entry_cost,
'status': 'open'
}
return position
def manage_positions(self, date):
"""Check exit rules for all open positions"""
for position in self.positions:
if position['status'] != 'open':
continue
# Calculate current P&L
current_pnl = self.calculate_position_pnl(position, date)
dte = (position['expiry'] - date).days
# Exit rules
exit_reason = None
# Rule 1: Profit target
if current_pnl >= position['entry_credit'] * self.params['profit_target_pct']:
exit_reason = 'profit_target'
# Rule 2: Stop loss
elif current_pnl <= -position['entry_credit'] * self.params['stop_loss_pct']:
exit_reason = 'stop_loss'
# Rule 3: Time exit
elif dte <= 2:
exit_reason = 'time_exit'
# Rule 4: Strike breach
elif self.check_strike_breach(position, date):
exit_reason = 'strike_breach'
if exit_reason:
self.exit_position(position, date, exit_reason, current_pnl)
def calculate_position_pnl(self, position, date):
"""Calculate MTM P&L using option prices"""
# Get current option prices
chain = self.option_chain[
(self.option_chain['date'] == date) &
(self.option_chain['expiry_date'] == position['expiry'])
]
if chain.empty:
# Use Black-Scholes if no market data
return self.calculate_bs_pnl(position, date)
strikes = position['strikes']
current_value = 0
# Short put value (we owe)
sp = chain[(chain['strike'] == strikes['short_put']) & (chain['option_type'] == 'PE')]
if not sp.empty:
current_value -= sp['ltp'].values[0]
# Long put value (we own)
lp = chain[(chain['strike'] == strikes['long_put']) & (chain['option_type'] == 'PE')]
if not lp.empty:
current_value += lp['ltp'].values[0]
# Short call value (we owe)
sc = chain[(chain['strike'] == strikes['short_call']) & (chain['option_type'] == 'CE')]
if not sc.empty:
current_value -= sc['ltp'].values[0]
# Long call value (we own)
lc = chain[(chain['strike'] == strikes['long_call']) & (chain['option_type'] == 'CE')]
if not lc.empty:
current_value += lc['ltp'].values[0]
# P&L = entry credit - current debit
pnl = (strikes['net_credit'] - current_value) * position['lots'] * 25
return pnl
def calculate_bs_pnl(self, position, date):
"""Fallback: Calculate P&L using Black-Scholes"""
# Implement Black-Scholes pricing
# This requires: spot, strike, time to expiry, IV, risk-free rate
# ... (implementation details)
pass
def check_strike_breach(self, position, date):
"""Check if underlying breached short strikes"""
spot = self.underlying.loc[date, 'close']
strikes = position['strikes']
if spot <= strikes['short_put'] or spot >= strikes['short_call']:
return True
return False
def exit_position(self, position, date, reason, pnl):
"""Close position and record"""
exit_cost = self.calculate_transaction_cost(position, position['lots'], 'exit')
net_pnl = pnl - position['entry_cost'] - exit_cost
position['status'] = 'closed'
position['exit_date'] = date
position['exit_reason'] = reason
position['gross_pnl'] = pnl
position['net_pnl'] = net_pnl
position['exit_cost'] = exit_cost
self.closed_positions.append(position)
self.capital += net_pnl
def calculate_transaction_cost(self, position, lots, action):
"""Calculate brokerage, STT, exchange fees, GST"""
# 4 legs for iron condor
num_orders = 4
brokerage = num_orders * self.params['brokerage_per_order']
# STT on sell side (short put + short call)
premium_sell = (position['strikes'].get('short_put_premium', 30) +
position['strikes'].get('short_call_premium', 30))
stt = premium_sell * lots * 25 * 0.0625 / 100
# Exchange + GST
misc = 100 # Simplified
total_cost = brokerage + stt + misc
return total_cost
def estimate_margin(self, signal):
"""Estimate SPAN + Exposure margin"""
# Simplified: Typically 30-40% of wing width
wing_width = signal['strikes']['short_put'] - signal['strikes']['long_put']
margin_per_lot = wing_width * 25 * 0.35
return margin_per_lot
def record_equity(self, date):
"""Record daily equity curve"""
mtm_pnl = sum([self.calculate_position_pnl(p, date) for p in self.positions if p['status'] == 'open'])
total_equity = self.capital + mtm_pnl
self.equity_curve.append({
'date': date,
'equity': total_equity,
'cash': self.capital,
'open_positions': len([p for p in self.positions if p['status'] == 'open'])
})
def generate_results(self):
"""Calculate performance metrics"""
results = pd.DataFrame(self.closed_positions)
equity = pd.DataFrame(self.equity_curve)
if results.empty:
return None
total_trades = len(results)
winning_trades = len(results[results['net_pnl'] > 0])
win_rate = winning_trades / total_trades * 100
avg_win = results[results['net_pnl'] > 0]['net_pnl'].mean()
avg_loss = results[results['net_pnl'] < 0]['net_pnl'].mean()
total_pnl = results['net_pnl'].sum()
max_drawdown = (equity['equity'].cummax() - equity['equity']).max()
# Sharpe ratio (annualized)
equity['returns'] = equity['equity'].pct_change()
sharpe = equity['returns'].mean() / equity['returns'].std() * np.sqrt(252)
metrics = {
'total_trades': total_trades,
'win_rate': win_rate,
'avg_win': avg_win,
'avg_loss': avg_loss,
'profit_factor': abs(avg_win / avg_loss) if avg_loss != 0 else np.inf,
'total_pnl': total_pnl,
'max_drawdown': max_drawdown,
'sharpe_ratio': sharpe,
'final_capital': self.capital
}
return {'metrics': metrics, 'trades': results, 'equity': equity}
Execution Layer (Broker API Integration)
Zerodha Kite Connect Example:
from kiteconnect import KiteConnect
import time
class LiveExecutor:
def __init__(self, api_key, access_token, capital):
self.kite = KiteConnect(api_key=api_key)
self.kite.set_access_token(access_token)
self.capital = capital
self.positions = []
def execute_iron_condor(self, signal, lots):
"""
Execute 4-leg iron condor using basket orders
"""
strikes = signal['strikes']
symbol = signal['underlying'] # 'NIFTY' or 'BANKNIFTY'
expiry = signal['expiry'].strftime('%y%b%d').upper() # 24DEC28
# Build trading symbols
short_put_symbol = f"{symbol}{expiry}{strikes['short_put']}PE"
long_put_symbol = f"{symbol}{expiry}{strikes['long_put']}PE"
short_call_symbol = f"{symbol}{expiry}{strikes['short_call']}CE"
long_call_symbol = f"{symbol}{expiry}{strikes['long_call']}CE"
# Get instrument tokens (required by Kite)
instruments = self.kite.instruments("NFO")
token_map = {inst['tradingsymbol']: inst['instrument_token'] for inst in instruments}
# Place orders
orders = []
try:
# Leg 1: Sell Put
order_id_1 = self.place_limit_order(
symbol=short_put_symbol,
transaction_type='SELL',
quantity=lots * 25,
price=strikes['short_put_premium']
)
```python
orders.append(('short_put', order_id_1))
# Leg 2: Buy Put
order_id_2 = self.place_limit_order(
symbol=long_put_symbol,
transaction_type='BUY',
quantity=lots * 25,
price=strikes['long_put_premium']
)
orders.append(('long_put', order_id_2))
# Leg 3: Sell Call
order_id_3 = self.place_limit_order(
symbol=short_call_symbol,
transaction_type='SELL',
quantity=lots * 25,
price=strikes['short_call_premium']
)
orders.append(('short_call', order_id_3))
# Leg 4: Buy Call
order_id_4 = self.place_limit_order(
symbol=long_call_symbol,
transaction_type='BUY',
quantity=lots * 25,
price=strikes['long_call_premium']
)
orders.append(('long_call', order_id_4))
# Wait and verify fills
time.sleep(5)
fill_status = self.verify_fills(orders)
if fill_status['all_filled']:
position = {
'id': len(self.positions) + 1,
'entry_time': pd.Timestamp.now(),
'signal': signal,
'lots': lots,
'orders': orders,
'status': 'open'
}
self.positions.append(position)
return position
else:
# Partial fill - cancel and retry or close
self.handle_partial_fill(orders, fill_status)
return None
except Exception as e:
print(f"Execution error: {e}")
# Emergency: try to close any filled legs
self.emergency_close(orders)
return None
def place_limit_order(self, symbol, transaction_type, quantity, price):
"""Place limit order with retry logic"""
max_retries = 3
for attempt in range(max_retries):
try:
order_id = self.kite.place_order(
variety=self.kite.VARIETY_REGULAR,
exchange=self.kite.EXCHANGE_NFO,
tradingsymbol=symbol,
transaction_type=transaction_type,
quantity=quantity,
product=self.kite.PRODUCT_NRML, # or PRODUCT_MIS for intraday
order_type=self.kite.ORDER_TYPE_LIMIT,
price=price,
validity=self.kite.VALIDITY_DAY
)
return order_id
except Exception as e:
print(f"Order placement failed (attempt {attempt+1}): {e}")
if attempt < max_retries - 1:
time.sleep(2)
# Adjust price by 1 tick if timeout
if transaction_type == 'BUY':
price += 0.05
else:
price -= 0.05
else:
raise
def verify_fills(self, orders):
"""Check if all orders filled"""
fill_status = {'all_filled': True, 'details': {}}
for leg_name, order_id in orders:
order_history = self.kite.order_history(order_id)
last_status = order_history[-1]['status']
fill_status['details'][leg_name] = {
'order_id': order_id,
'status': last_status,
'filled_qty': order_history[-1].get('filled_quantity', 0)
}
if last_status not in ['COMPLETE']:
fill_status['all_filled'] = False
return fill_status
def handle_partial_fill(self, orders, fill_status):
"""Handle partial fills - cancel unfilled, close filled"""
for leg_name, order_id in orders:
status = fill_status['details'][leg_name]['status']
if status == 'OPEN' or status == 'TRIGGER PENDING':
# Cancel unfilled orders
try:
self.kite.cancel_order(
variety=self.kite.VARIETY_REGULAR,
order_id=order_id
)
except:
pass
elif status == 'COMPLETE':
# Close filled legs at market
# Get leg details and reverse
# ... (implementation)
pass
def monitor_positions(self):
"""Real-time position monitoring with Greeks"""
while True:
for position in self.positions:
if position['status'] != 'open':
continue
# Get current quotes
symbols = self.get_position_symbols(position)
quotes = self.kite.quote(symbols)
# Calculate current P&L and Greeks
current_pnl = self.calculate_live_pnl(position, quotes)
current_greeks = self.calculate_live_greeks(position, quotes)
# Check exit conditions
exit_signal = self.check_exit_conditions(
position, current_pnl, current_greeks
)
if exit_signal:
self.close_position(position, exit_signal['reason'])
# Check risk thresholds
self.check_risk_limits(position, current_pnl, current_greeks)
time.sleep(30) # Check every 30 seconds
def check_exit_conditions(self, position, pnl, greeks):
"""Apply exit rules from strategy"""
signal = position['signal']
entry_credit = signal['strikes']['net_credit'] * position['lots'] * 25
# Profit target
if pnl >= entry_credit * 0.5:
return {'exit': True, 'reason': 'profit_target'}
# Stop loss
if pnl <= -entry_credit * 2.0:
return {'exit': True, 'reason': 'stop_loss'}
# Time exit
dte = (position['signal']['expiry'] - pd.Timestamp.now()).days
if dte <= 2:
return {'exit': True, 'reason': 'time_exit'}
# Delta threshold
if abs(greeks['delta']) > 0.30:
return {'exit': True, 'reason': 'delta_breach'}
return {'exit': False}
def check_risk_limits(self, position, pnl, greeks):
"""Kill-switch logic for extreme scenarios"""
# Daily loss limit
total_daily_loss = self.calculate_total_daily_pnl()
if total_daily_loss < -self.capital * 0.03: # -3% daily loss
self.emergency_close_all("DAILY_LOSS_LIMIT")
# Margin breach
margin_used = self.get_margin_used()
if margin_used > self.capital * 0.75: # 75% margin usage
print("WARNING: Margin usage high")
# Send alert
# VIX spike
vix = self.get_current_vix()
if vix > 30: # Threshold
print("WARNING: High volatility")
# Consider closing positions
def close_position(self, position, reason):
"""Close all legs of a position"""
symbols = self.get_position_symbols(position)
for symbol in symbols:
# Get current position from broker
positions_data = self.kite.positions()['net']
pos = next((p for p in positions_data if p['tradingsymbol'] == symbol), None)
if pos and pos['quantity'] != 0:
# Close with market order for speed
self.kite.place_order(
variety=self.kite.VARIETY_REGULAR,
exchange=self.kite.EXCHANGE_NFO,
tradingsymbol=symbol,
transaction_type='SELL' if pos['quantity'] > 0 else 'BUY',
quantity=abs(pos['quantity']),
product=self.kite.PRODUCT_NRML,
order_type=self.kite.ORDER_TYPE_MARKET
)
position['status'] = 'closed'
position['exit_time'] = pd.Timestamp.now()
position['exit_reason'] = reason
print(f"Position {position['id']} closed: {reason}")
def emergency_close_all(self, reason):
"""Emergency close all positions"""
print(f"EMERGENCY CLOSE: {reason}")
for position in self.positions:
if position['status'] == 'open':
self.close_position(position, f"EMERGENCY_{reason}")
# Send alert
self.send_alert(f"All positions closed: {reason}")
def calculate_live_greeks(self, position, quotes):
"""Calculate aggregate Greeks from live quotes"""
# Use quotes and Black-Scholes for Greeks
# ... (implementation using py_vollib or manual calculation)
pass
def get_current_vix(self):
"""Fetch current VIX value"""
try:
vix_quote = self.kite.quote("NSE:INDIA VIX")
return vix_quote['NSE:INDIA VIX']['last_price']
except:
return None
def send_alert(self, message):
"""Send SMS/Email/Telegram alert"""
# Integration with notification service
print(f"ALERT: {message}")
# ... (implement SMS/email via twilio/sendgrid/telegram bot)
Risk Management & Monitoring Dashboard
import streamlit as st
import plotly.graph_objects as go
class RiskDashboard:
def __init__(self, executor):
self.executor = executor
def render(self):
st.title("QuantForge Options Trading Dashboard")
# Portfolio Summary
col1, col2, col3, col4 = st.columns(4)
with col1:
st.metric("Capital", f"₹{self.executor.capital:,.0f}")
with col2:
total_pnl = self.calculate_total_pnl()
st.metric("Today's P&L", f"₹{total_pnl:,.0f}",
delta=f"{total_pnl/self.executor.capital*100:.2f}%")
with col3:
open_positions = len([p for p in self.executor.positions if p['status'] == 'open'])
st.metric("Open Positions", open_positions)
with col4:
margin_used = self.executor.get_margin_used()
margin_pct = margin_used / self.executor.capital * 100
st.metric("Margin Used", f"{margin_pct:.1f}%",
delta="⚠️" if margin_pct > 60 else "✅")
# Portfolio Greeks
st.subheader("Portfolio Greeks")
greeks = self.calculate_portfolio_greeks()
col1, col2, col3, col4 = st.columns(4)
col1.metric("Delta", f"{greeks['delta']:.2f}")
col2.metric("Gamma", f"{greeks['gamma']:.2f}")
col3.metric("Theta", f"₹{greeks['theta']:.0f}/day")
col4.metric("Vega", f"{greeks['vega']:.2f}")
# Position Details
st.subheader("Active Positions")
positions_df = self.build_positions_table()
st.dataframe(positions_df)
# Risk Gauges
st.subheader("Risk Indicators")
col1, col2 = st.columns(2)
with col1:
# Daily loss gauge
daily_loss_limit = -self.executor.capital * 0.03
fig = go.Figure(go.Indicator(
mode="gauge+number+delta",
value=total_pnl,
domain={'x': [0, 1], 'y': [0, 1]},
title={'text': "Daily P&L"},
delta={'reference': 0},
gauge={
'axis': {'range': [daily_loss_limit, -daily_loss_limit]},
'bar': {'color': "darkblue"},
'steps': [
{'range': [daily_loss_limit, 0], 'color': "lightcoral"},
{'range': [0, -daily_loss_limit], 'color': "lightgreen"}
],
'threshold': {
'line': {'color': "red", 'width': 4},
'thickness': 0.75,
'value': daily_loss_limit
}
}
))
st.plotly_chart(fig)
with col2:
# Margin gauge
fig = go.Figure(go.Indicator(
mode="gauge+number",
value=margin_pct,
domain={'x': [0, 1], 'y': [0, 1]},
title={'text': "Margin Usage (%)"},
gauge={
'axis': {'range': [0, 100]},
'bar': {'color': "darkblue"},
'steps': [
{'range': [0, 50], 'color': "lightgreen"},
{'range': [50, 70], 'color': "lightyellow"},
{'range': [70, 100], 'color': "lightcoral"}
],
'threshold': {
'line': {'color': "red", 'width': 4},
'thickness': 0.75,
'value': 75
}
}
))
st.plotly_chart(fig)
# Equity Curve
st.subheader("Equity Curve")
equity_data = self.get_equity_history()
fig = go.Figure()
fig.add_trace(go.Scatter(x=equity_data['date'], y=equity_data['equity'],
mode='lines', name='Equity'))
fig.update_layout(xaxis_title="Date", yaxis_title="Equity (₹)")
st.plotly_chart(fig)
def calculate_portfolio_greeks(self):
"""Aggregate Greeks across all positions"""
total_delta = 0
total_gamma = 0
total_theta = 0
total_vega = 0
for position in self.executor.positions:
if position['status'] == 'open':
greeks = self.executor.calculate_live_greeks(position, None)
total_delta += greeks['delta']
total_gamma += greeks['gamma']
total_theta += greeks['theta']
total_vega += greeks['vega']
return {
'delta': total_delta,
'gamma': total_gamma,
'theta': total_theta,
'vega': total_vega
}
Phased Rollout Plan (Practical Implementation)
Phase 0: Setup & Infrastructure (Days 0-14)
Objectives:
- Build data pipeline
- Implement backtest engine
- Set up paper trading environment
Deliverables Checklist:
Week 1: Data & Environment
- Open trading account (Zerodha/Upstox) — verify KYC, fund ₹5-10L
- Subscribe to data vendor (optional: TrueData, Upstox Historical) or use free NSE data
- Download 2-3 years NIFTY/BANKNIFTY daily OHLCV
- Set up Python environment (pandas, numpy, ta-lib, backtrader/vectorbt)
- Create data storage structure (CSV/SQLite/PostgreSQL)
- Build option chain scraper (daily EOD snapshots)
Week 2: Backtest Foundation
- Implement
OptionsBacktesterclass from blueprint above - Code Iron Condor signal generator
- Code 2-3 additional strategies (Put Spread, Strangle)
- Build Black-Scholes pricer for Greeks calculation
- Implement transaction cost model
- Run first backtest on 1-year data
- Document results in backtest log template (see Appendix)
Validation Criteria:
- Backtest runs without errors on 1+ year data
- Generated at least 20+ trades in backtest
- Performance metrics calculated correctly
- Can reproduce results consistently
Phase 1: Paper Trading & Validation (Days 15-60)
Objectives:
- Validate strategies in real-time without capital risk
- Refine entry/exit timing
- Test execution infrastructure
Week 3-4: Paper Trading Setup
- Set up paper trading account (most brokers offer virtual trading)
- Implement live data feed integration (WebSocket/REST API)
- Build position tracking system
- Create manual paper trading log (see template below)
- Paper trade 1-2 strategies (start with Iron Condor)
Paper Trading Log Template (CSV):
Date,Time,Strategy,Action,Symbol,Strikes,Lots,Credit_Debit,Spot,VIX,Notes
01-11-2024,10:15,Iron Condor,ENTRY,NIFTY,"21600/21700/22300/22400",3,1800,22050,14.5,"Clean fill"
02-11-2024,14:30,Iron Condor,HOLD,NIFTY,"21600/21700/22300/22400",3,900,22080,14.2,"MTM profit ₹900"
05-11-2024,15:00,Iron Condor,EXIT,NIFTY,"21600/21700/22300/22400",3,-900,22100,13.8,"Profit target hit"
Week 5-6: Iteration & Refinement
- Execute 15-20 paper trades across 2-3 strategies
- Track actual vs expected slippage
- Compare paper P&L vs backtest expectations
- Identify execution gaps (timing, fill rates, bid-ask impact)
- Refine entry filters based on false signals
Week 7-8: OOS Testing & Walk-Forward
- Run walk-forward analysis on backtest
- Train period: Jan 2023 - Jun 2024
- Test period: Jul 2024 - Oct 2024
- Compare in-sample vs out-of-sample metrics
- Stress test with 2024 data (includes high-vol periods)
- Document parameter stability
Validation Criteria (Phase 1 Gate):
- Minimum 15 completed paper trades
- Win rate ≥ 55% (or meets strategy expectations)
- Max drawdown in paper trading < 10%
- Actual slippage < 10% of backtest assumptions
- No major execution failures or missed exits
- Profit factor ≥ 1.3 (hypothetical threshold)
Go / No-Go Decision:
- GO to Phase 2 if: 4+ of 6 criteria met
- NO-GO if: Win rate < 50% or max drawdown > 15% → Return to backtest, adjust parameters
Phase 2: Small Live Pilot (Days 61-150)
Objectives:
- Deploy capital with strict risk controls
- Validate real money execution
- Build operational discipline
Week 9-10: Pre-Launch Preparation
- Transfer ₹50k-₹1.5L to trading account (10-15% of total capital)
- Set up broker API credentials (API key, access token)
- Implement live executor class with kill-switches
- Configure real-time alerts (SMS/email/Telegram)
- Test live order placement with 1 lot (micro-test)
- Document pre-trade checklist
Week 11-20: Live Trading (Months 3-5)
Position Sizing (Conservative Start):
- Capital Deployed: ₹1.5L (30% of ₹5L total)
- Max Per-Trade Risk: 1% of total capital = ₹5,000
- Strategies:
- Iron Condor: 2-3 lots max (₹2-3k risk per position)
- Put Spread: 1-2 lots (₹2-3k risk)
- Max Concurrent Positions: 2-3 (total risk ₹10-15k = 2-3% capital)
Daily Operating Rhythm:
Morning (9:00-9:30 AM):
- Review overnight news/events
- Check VIX, NIFTY gap-up/down
- Review open positions P&L
- Check margin availability
Mid-Morning (10:00-11:00 AM):
- Scan for entry signals (if < 3 positions open)
- Execute new entries if conditions met
- Adjust threatened positions
Afternoon (2:00-3:00 PM):
- Monitor P&L vs targets
- Prepare adjustment orders if needed
- Check Greeks
End of Day (3:15-3:30 PM):
- Record all positions in log
- Calculate daily P&L
- Update equity curve
- Check exit triggers for next day
Evening (6:00-7:00 PM):
- Review day's performance
- Plan next day's actions
- Weekly review (on Fridays)
Weekly Review (Every Friday):
Metrics to Track:
- Number of trades entered: [X]
- Number of trades closed: [X]
- Win rate: [X]%
- Gross P&L: ₹[X]
- Net P&L (after costs): ₹[X]
- Max position drawdown: ₹[X]
- Largest winner: ₹[X]
- Largest loser: ₹[X]
- Average hold time: [X] days
- Rules followed: [X]/[Y] checklist items
Action Items:
- Any rule violations? Document and correct
- Emotional discipline issues? Note patterns
- Execution problems? Adjust process
Risk Controls (Strictly Enforced):
- Daily Loss Limit: Stop trading if loss reaches ₹7,500 (1.5% of total capital)
- Weekly Loss Limit: Stop for 1 week if weekly loss > ₹15,000 (3% capital)
- Consecutive Losses: After 3 losing trades, reduce position size by 50% for next 3 trades
- Margin Discipline: Never exceed 60% margin utilization
- Overnight Exposure: No positions held into major events (Budget, Fed meetings, elections)
Validation Criteria (Phase 2 Gate — After 3 Months Live):
- Minimum 30 live trades completed
- Win rate ≥ 55%
- Max drawdown < 10% of deployed capital
- No daily loss limit breaches
- Positive net P&L (even ₹1 counts — prove viability)
- Operational checklist compliance ≥ 90%
Go / No-Go Decision:
- GO to Phase 3 if: 5+ of 6 criteria met, especially positive P&L
- NO-GO if: Negative P&L after 3 months OR max drawdown > 12% → Pause, analyze, potentially return to paper trading
Phase 3: Scale & Diversification (Days 151+)
Objectives:
- Increase position sizes methodically
- Add more strategies to portfolio
- Move toward semi-automation
Month 6-7: Gradual Scaling
Scaling Rules (Strict Gating):
Rule 1: Scale only after 4 consecutive profitable weeks
Rule 2: Increase position size by 25% increments (not 2x jumps)
Rule 3: Each scale-up requires 2-week observation period
Example Scaling Path:
- Months 3-5: 2-3 lots per position (base size)
- Month 6: After meeting criteria → 3-4 lots
- Month 7: After 2 weeks stable → 4-5 lots
- Month 8: After 2 weeks stable → 5-7 lots (target size for ₹5L capital)
Stop Scaling If:
- Any weekly loss > 2% of capital
- Drawdown exceeds 8% from peak
- Win rate drops below 50% for 2 consecutive weeks
Month 7-9: Strategy Diversification
Add New Strategies Sequentially:
Month 7: Add Credit Call Spread (if bearish signals available)
- Start with 1-2 lots, paper trade for 2 weeks first
Month 8: Add Short Strangle + Wings (for high-vol environments)
- Only deploy when VIX > 50th percentile
Month 9: Add Ratio Spread or Calendar Spread
- More complex, requires higher monitoring
Portfolio Target (Month 9):
- 3-4 active strategies
- 5-8 concurrent positions
- Max portfolio risk: 5% of capital = ₹25k-50k
- Margin utilization: 60-70%
Month 10+: Automation Layer
Semi-Automation Priorities:
Phase 3A: Monitoring Automation
- Real-time Greeks tracking dashboard
- Auto-alerts for exit triggers (Telegram bot)
- Automated position journaling
Phase 3B: Execution Assistance
- Pre-validated order batching (human approves, system executes)
- Automatic adjustment order generation (human approves)
Phase 3C: Full Automation (Optional, Month 12+)
- Auto-entry on confirmed signals (with daily limits)
- Auto-exit on profit targets / stop losses
- Human oversight: daily review + kill-switch access
Performance Targets (Hypothetical, Illustrative Only):
Conservative Expectations (₹5L capital, after 6 months scaling):
- Monthly return target: 2-4% (₹10k-₹20k)
- Max monthly drawdown tolerance: 8%
- Sharpe ratio target: >1.0
- Win rate target: 60-65%
Note: These are illustrative targets, not guarantees. Actual results will vary
based on market conditions, execution quality, and strategy selection.
Appendix: Templates & Code Snippets
A. Backtest Results Template (JSON)
{
"backtest_id": "IC_NIFTY_Conservative_20240101_20241015",
"strategy": "Iron Condor",
"underlying": "NIFTY",
"period": {
"start": "2024-01-01",
"end": "2024-10-15"
},
"parameters": {
"dte_target": 10,
"wing_width": 150,
"delta_target": 0.18,
"profit_target_pct": 0.5,
"stop_loss_pct": 2.0,
"risk_per_trade": 0.015,
"vix_percentile_range": [20, 60]
},
"results": {
"total_trades": 45,
"winning_trades": 29,
"losing_trades": 16,
"win_rate": 64.4,
"gross_pnl": 28500,
"transaction_costs": 6750,
"net_pnl": 21750,
"max_drawdown": 8250,
"sharpe_ratio": 1.42,
"profit_factor": 1.68,
"avg_win": 1450,
"avg_loss": -1120,
"max_win": 3200,
"max_loss": -2800,
"avg_hold_time_days": 7.2
},
"notes": "Backtest assumptions: mid-price fills, 1 tick slippage per leg, ₹350 transaction cost per round-trip"
}
B. Pre-Trade Checklist (Print & Use)
═══════════════════════════════════════════════════════════
QUANTFORGE PRE-TRADE CHECKLIST
═══════════════════════════════════════════════════════════
Trade Date: _______________ Time: _______________
MARKET CONTEXT
□ NIFTY Trend: ☐ Bull ☐ Bear ☐ Sideways
□ VIX Level: ______ (Percentile: ____%)
□ ADX Reading: ______ (< 25 for neutral strategies?)
□ Upcoming Events (next 7 days): _______________________
STRATEGY SELECTION
□ Selected Strategy: _____________________
□ Regime Match: ☐ Yes ☐ Questionable
□ IV Environment Suitable: ☐ Yes ☐ No
POSITION SIZING
□ Max Loss Per Lot: ₹__________
□ Risk Per Trade (1.5% capital): ₹__________
□ Calculated Lot Size: __________
□ Margin Required: ₹__________ (< 50% capital?)
□ Final Lot Size: __________
STRIKE SELECTION
□ Current Spot: __________
□ ATR(14): __________
□ Short Put Strike: __________ (Delta: ______)
□ Long Put Strike: __________
□ Short Call Strike: __________ (Delta: ______)
□ Long Call Strike: __________
□ Bid-Ask Spread Check: ☐ < 5% ☐ > 5% (reject)
TARGET CREDIT/DEBIT
□ Expected Credit: ₹__________ per unit
□ Min Acceptable Credit: ₹__________ (after slippage)
□ Max Risk Per Lot: ₹__________
□ Risk:Reward Ratio: __________
GREEKS EXPECTATIONS
□ Target Delta: ±__________ (near neutral?)
□ Expected Theta: +₹__________ per day
□ Vega Exposure: __________
EXIT PLAN
□ Profit Target: ₹__________ (50-60% of credit)
□ Stop Loss: ₹__________ (200% of credit)
□ Time Exit: ______ DTE
□ Alerts Set: ☐ Yes ☐ No
RISK CHECKS
□ Current Open Positions: __________
□ Total Portfolio Risk: ₹__________ (< 5% capital?)
□ Margin Utilization: ______% (< 60%?)
□ Daily Loss Limit Remaining: ₹__________
FINAL APPROVAL
□ All checklist items reviewed
□ Strategy matches regime
□ Position size appropriate
□ Risk acceptable
Trader Signature: ________________ ☐ PROCEED ☐ ABORT
═══════════════════════════════════════════════════════════
C. Black-Scholes Greeks Calculator (Python)
import numpy as np
from scipy.stats import norm
class BSMGreeks:
def __init__(self, S, K, T, r, sigma, option_type='call'):
"""
Black-Scholes-Merton Option Pricing and Greeks
S: Spot price
K: Strike price
T: Time to expiry (years)
r: Risk-free rate (annual)
sigma: Implied volatility (annual)
option_type: 'call' or 'put'
"""
self.S = S
self.K = K
self.T = T
self.r = r
self.sigma = sigma
self.option_type = option_type
self.d1 = (np.log(S/K) + (r + 0.5*sigma**2)*T) / (sigma*np.sqrt(T))
self.d2 = self.d1 - sigma*np.sqrt(T)
def price(self):
"""Calculate option price"""
if self.option_type == 'call':
price = (self.S * norm.cdf(self.d1) -
self.K * np.exp(-self.r*self.T) * norm.cdf(self.d2))
else: # put
price = (self.K * np.exp(-self.r*self.T) * norm.cdf(-self.d2) -
self.S * norm.cdf(-self.d1))
return price
def delta(self):
"""Calculate delta"""
if self.option_type == 'call':
return norm.cdf(self.d1)
else: # put
return norm.cdf(self.d1) - 1
def gamma(self):
"""Calculate gamma (same for call and put)"""
return norm.pdf(self.d1) / (self.S * self.sigma * np.sqrt(self.T))
def theta(self):
"""Calculate theta (per day)"""
term1 = -(self.S * norm.pdf(self.d1) * self.sigma) / (2 * np.sqrt(self.T))
if self.option_type == 'call':
term2 = -self.r * self.K * np.exp(-self.r*self.T) * norm.cdf(self.d2)
else: # put
term2 = self.r * self.K * np.exp(-self.r*self.T) * norm.cdf(-self.d2)
# Convert from per year to per day
theta_annual = term1 + term2
return theta_annual / 365
def vega(self):
"""Calculate vega (per 1% change in IV)"""
vega_decimal = self.S * norm.pdf(self.d1) * np.sqrt(self.T)
# Convert to per 1% IV change
return vega_decimal / 100
def rho(self):
"""Calculate rho (per 1% change in interest rate)"""
if self.option_type == 'call':
return self.K * self.T * np.exp(-self.r*self.T) * norm.cdf(self.d2) / 100
else: # put
return -self.K * self.T * np.exp(-self.r*self.T) * norm.cdf(-self.d2) / 100
def all_greeks(self):
"""Return all Greeks as dictionary"""
return {
'price': self.price(),
'delta': self.delta(),
'gamma': self.gamma(),
'theta': self.theta(),
'vega': self.vega(),
'rho': self.rho()
}
# Example usage:
def calculate_iron_condor_greeks(spot, strikes, dte, iv, r=0.07):
"""
Calculate aggregate Greeks for iron condor
strikes: dict with 'short_put', 'long_put', 'short_call', 'long_call'
dte: days to expiry
iv: implied volatility (e.g., 0.15 for 15%)
"""
T = dte / 365
# Short put (we sold it, so negative Greeks)
short_put = BSMGreeks(spot, strikes['short_put'], T, r, iv, 'put')
sp_greeks = short_put.all_greeks()
# Long put (we bought it)
long_put = BSMGreeks(spot, strikes['long_put'], T, r, iv, 'put')
lp_greeks = long_put.all_greeks()
# Short call (we sold it)
short_call = BSMGreeks(spot, strikes['short_call'], T, r, iv, 'call')
sc_greeks = short_call.all_greeks()
# Long call (we bought it)
long_call = BSMGreeks(spot, strikes['long_call'], T, r, iv, 'call')
lc_greeks = long_call.all_greeks()
# Aggregate (negative for short positions)
position_greeks = {
'delta': -sp_greeks['delta'] + lp_greeks['delta'] - sc_greeks['delta'] + lc_greeks['delta'],
'gamma': -sp_greeks['gamma'] + lp_greeks['gamma'] - sc_greeks['gamma'] + lc_greeks['gamma'],
'theta': -sp_greeks['theta'] + lp_greeks['theta'] - sc_greeks['theta'] + lc_greeks['theta'],
'vega': -sp_greeks['vega'] + lp_greeks['vega'] - sc_greeks['vega'] + lc_greeks['vega'],
'position_value': -sp_greeks['price'] + lp_greeks['price'] - sc_greeks['price'] + lc_greeks['price']
}
return position_greeks
# Test example
if __name__ == "__main__":
spot = 22000
strikes = {
'short_put': 21700,
'long_put': 21600,
'short_call': 22300,
'long_call': 22400
}
greeks = calculate_iron_condor_greeks(spot, strikes, dte=10, iv=0.15)
print("Iron Condor Greeks:")
for key, value in greeks.items():
print(f"{key}: {value:.4f}")
D. 30/60/90-Day Rollout Tracking Template (CSV)
Phase,Milestone,Target_Date,Status,Actual_Date,KPI,Target,Actual,Notes
0,Setup,2024-11-15,Pending,,"Data Pipeline",Ready,,"NSE historical + options chain"
0,Setup,2024-11-15,Pending,,"Backtest Engine",Functional,,"Test on 2-year data"
0,Setup,2024-11-20,Pending,,"Paper Trade Env",Ready,,"Virtual account setup"
1,Paper_Trading,2024-12-01,Pending,,"First Paper Trade",1,,"Iron Condor"
1,Paper_Trading,2024-12-15,Pending,,"Paper Trades Count",10,,"Across 2 strategies"
1,Paper_Trading,2024-12-31,Pending,,"Win Rate",">55%",,"Phase 1 gate"
1,Paper_Trading,2024-12-31,Pending,,"Max Drawdown","<10%",,"Phase 1 gate"
2,Live_Pilot,2025-01-05,Pending,,"First Live Trade",1,,"₹50k capital deployed"
2,Live_Pilot,2025-01-31,Pending,,"Live Trades Count",10,,"Month 1"
2,Live_Pilot,2025-02-28,Pending,,"Cumulative Trades",20,,"Month 2"
2,Live_Pilot,2025-03-31,Pending,,"Phase 2 Win Rate","≥55%",,"Phase 2 gate"
2,Live_Pilot,2025-03-31,Pending,,"Net P&L",">₹0",,"Positive after 3 months"
3,Scaling,2025-04-30,Pending,,"Position Size Increase","25%",,"After 4 profitable weeks"
3,Scaling,2025-05-31,Pending,,"Strategy Count",3,,"Add 2nd strategy"
3,Scaling,2025-06-30,Pending,,"Target Position Size","5-7 lots",,"Full scale for ₹5L"
3,Diversification,2025-07-31,Pending,,"Active Strategies",4,,"Portfolio diversified"
3,Automation,2025-09-30,Pending,,"Monitoring Dashboard",Live,,"Real-time Greeks tracking"
3,Automation,2025-12-31,Pending,,"Semi-Automation","Phase 3B",,"Execution assistance"
E. Daily Trading Journal Template
═════════════════════════════════════════════════════════════
QUANTFORGE DAILY TRADING JOURNAL
═════════════════════════════════════════════════════════════
Date: _______________ Day of Week: _______________
MARKET OVERVIEW
─────────────────────────────────────────────────────────────
NIFTY Open: ________ High: ________ Low: ________ Close: ________
NIFTY Change: _______%
VIX: ________ (Change: ______%)
Major News/Events: _________________________________________
PORTFOLIO STATUS (START OF DAY)
─────────────────────────────────────────────────────────────
Starting Equity: ₹__________
Open Positions: __________
Margin Used: ₹__________ (______%)
Available Cash: ₹__________
POSITIONS OPENED TODAY
─────────────────────────────────────────────────────────────
Position #: _____
Strategy: _____________________
Strikes: _____________________
Lots: _____ Credit/Debit: ₹_____ Max Risk: ₹_____
Entry Time: _____ Spot at Entry: _____
Entry Reasoning: ____________________________________________
Checklist Followed: ☐ Yes ☐ No (If no, explain: __________)
POSITIONS CLOSED TODAY
─────────────────────────────────────────────────────────────
Position #: _____
Strategy: _____________________
Entry Date: _________ Exit Date: _________ Hold Time: _____ days
Exit Reason: ☐ Profit Target ☐ Stop Loss ☐ Time ☐ Adjustment
Entry Credit: ₹_____ Exit Debit: ₹_____
Gross P&L: ₹_____ Costs: ₹_____ Net P&L: ₹_____
Exit Reasoning: _____________________________________________
POSITIONS HELD (End of Day Status)
─────────────────────────────────────────────────────────────
Position #1: ____________ DTE: ____ MTM P&L: ₹____ Delta: ____
Position #2: ____________ DTE: ____ MTM P&L: ₹____ Delta: ____
Position #3: ____________ DTE: ____ MTM P&L: ₹____ Delta: ____
PORTFOLIO STATUS (END OF DAY)
─────────────────────────────────────────────────────────────
Ending Equity: ₹__________
Daily P&L: ₹__________ (______%)
Closed Trades Today: _____ (Wins: _____ / Losses: _____)
Aggregate Greeks: Delta: ____ Gamma: ____ Theta: ____ Vega: ____
RISK ASSESSMENT
─────────────────────────────────────────────────────────────
Daily Loss Limit Status: ₹________ remaining (of ₹7,500)
Position Risk: ₹________ (______% of capital)
Margin Usage: ______% (Target: < 60%)
Max Portfolio Delta: ________ (Target: < 0.15 per ₹1L)
EXECUTION QUALITY
─────────────────────────────────────────────────────────────
Orders Placed: _____ Orders Filled: _____ Fill Rate: ______%
Average Slippage: ₹_____ per leg
Limit Orders Used: ☐ Yes ☐ No (Market orders)
Execution Issues: ___________________________________________
RULE ADHERENCE
─────────────────────────────────────────────────────────────
Pre-Trade Checklist: ☐ Followed ☐ Partially ☐ Skipped
Position Sizing Rules: ☐ Followed ☐ Violated
Exit Rules: ☐ Followed ☐ Emotional override
Risk Limits: ☐ Within ☐ Breached (Explain: ______________)
EMOTIONAL STATE & DISCIPLINE
─────────────────────────────────────────────────────────────
Emotional State: ☐ Calm ☐ Anxious ☐ Frustrated ☐ Euphoric
Discipline Score (1-10): _____
Mistakes Made: ______________________________________________
Lessons Learned: ____________________________________________
TOMORROW'S PLAN
─────────────────────────────────────────────────────────────
Positions to Monitor: _______________________________________
Potential Exits: ____________________________________________
Potential Entries: __________________________________________
Events to Watch: ____________________________________________
NOTES & OBSERVATIONS
─────────────────────────────────────────────────────────────
_________________________________________________________________
_________________________________________________________________
_________________________________________________________________
═════════════════════════════════════════════════════════════
F. Weekly Performance Review Template
═══════════════════════════════════════════════════════════
QUANTFORGE WEEKLY PERFORMANCE REVIEW
═══════════════════════════════════════════════════════════
Week Ending: _______________
TRADING METRICS
───────────────────────────────────────────────────────────
Total Trades: _____
- Opened: _____
- Closed: _____
- Win: _____
- Loss: _____
- Scratch: _____
Win Rate: ______%
Profit Factor: ______
FINANCIAL PERFORMANCE
───────────────────────────────────────────────────────────
Starting Capital: ₹__________
Ending Capital: ₹__________
Weekly P&L: ₹__________ (______%)
Largest Win: ₹__________
Largest Loss: ₹__________
Average Win: ₹__________
Average Loss: ₹__________
Total Transaction Costs: ₹__________
Net Profit After Costs: ₹__________
STRATEGY BREAKDOWN
───────────────────────────────────────────────────────────
Strategy 1 (Iron Condor):
Trades: _____ Win Rate: ______% P&L: ₹__________
Strategy 2 (Put Spread):
Trades: _____ Win Rate: ______% P&L: ₹__________
Strategy 3 (___________):
Trades: _____ Win Rate: ______% P&L: ₹__________
Best Performing Strategy: _______________________________
Worst Performing Strategy: _______________________________
RISK METRICS
───────────────────────────────────────────────────────────
Max Intraweek Drawdown: ₹__________ (______%)
Avg Daily Position Risk: ₹__________ (______% capital)
Avg Margin Utilization: ______%
Daily Loss Limit Breaches: _____
Weekly Loss Limit Breached: ☐ Yes ☐ No
EXECUTION QUALITY
───────────────────────────────────────────────────────────
Total Orders: _____
Fill Rate: ______%
Average Slippage: ₹_____ per leg
Execution Errors: _____
RULE ADHERENCE
───────────────────────────────────────────────────────────
Pre-Trade Checklist Compliance: ______% (_____ / _____)
Position Sizing Violations: _____
Emotional Override Exits: _____
Risk Limit Breaches: _____
Overall Discipline Score (1-10): _____
WHAT WORKED THIS WEEK
───────────────────────────────────────────────────────────
1. ________________________________________________________
2. ________________________________________________________
3. ________________________________________________________
WHAT DIDN'T WORK
───────────────────────────────────────────────────────────
1. ________________________________________________________
2. ________________________________________________________
3. ________________________________________________________
MISTAKES & LESSONS
───────────────────────────────────────────────────────────
Mistake: ___________________________________________________
Lesson: ____________________________________________________
Mistake: ___________________________________________________
Lesson: ____________________________________________________
ACTION ITEMS FOR NEXT WEEK
───────────────────────────────────────────────────────────
☐ _________________________________________________________
☐ _________________________________________________________
☐ _________________________________________________________
SCALING DECISION (If in Phase 2/3)
───────────────────────────────────────────────────────────
Consecutive Profitable Weeks: _____
Ready to Scale Position Size: ☐ Yes ☐ No
Rationale: _________________________________________________
NOTES
───────────────────────────────────────────────────────────
_____________________________________________________________
_____________________________________________________________
_____________________________________________________________
═══════════════════════════════════════════════════════════
STRATEGY CARDS 4-12 (Condensed)
STRATEGY CARD 4: Credit Call Spread
Overview: Bearish/neutral bet, sell OTM call + buy further OTM call Regime: Bear/Sideways, Low-Med Vol Setup: Sell 0.25 delta call, buy call ₹100-150 above Entry: RSI < 50, price below 20-SMA, VIX 20-60th percentile Exit: 50% profit, 200% loss, 2 DTE, breach short strike Greeks: Delta -0.20, Theta +20, Vega -8 Sizing: 3-4 lots for ₹5L (conservative)
STRATEGY CARD 5: Ratio Put Spread
Overview: Bullish, sell 2x OTM puts, buy 1x further OTM put Regime: Bull, Medium Vol (collect extra premium) Setup: Buy 1 put at 0.10 delta, sell 2 puts at 0.25 delta Entry: Strong bullish momentum, support zone, VIX 40-70th percentile Exit: 40% credit profit, loss if spot drops below lower short put Greeks: Delta +0.30, Gamma negative (risk below lower strike) Sizing: 1-2 lots max (undefined risk below breakeven) Warning: Requires close monitoring, can have large losses in crash
STRATEGY CARD 6: Calendar Spread (Time Spread)
Overview: Neutral, profit from front-month theta decay Regime: Sideways, Medium-High Vol Setup: Sell front-week ATM put/call, buy next-week same strike Entry: Spot stable, VIX elevated (front-month IV > back-month) Exit: Close before front-month expiry, profit from theta Greeks: Theta positive, Vega positive (long back-month) Sizing: 2-3 lots for ₹5L Complex: Requires IV surface understanding, inter-expiry dynamics
STRATEGY CARD 7: Jade Lizard
Overview: Bullish, no upside risk: short strangle + extra OTM call sold Regime: Neutral-Bull, Low-Med Vol Setup: Sell OTM put, sell OTM call spread (put premium ≥ call spread width) Entry: Bullish bias, high IV rank Exit: 50% profit, manage downside (put side risk) Greeks: Delta +0.10-0.20, Theta high Sizing: 2-3 lots Advantage: Undefined upside, defined downside via put
STRATEGY CARD 8: Big Lizard
Overview: Bearish version of Jade Lizard Regime: Neutral-Bear, Low-Med Vol Setup: Sell OTM call, sell OTM put spread (call premium ≥ put spread width) Entry: Bearish bias, high IV rank Exit: 50% profit, manage upside (call side risk) Greeks: Delta -0.10 to -0.20, Theta high
STRATEGY CARD 9: Diagonal Spread
Overview: Directional with time advantage Regime: Trending markets, Med Vol Setup: Sell front-month OTM option, buy back-month further OTM Entry: Expected slow move in direction Exit: Roll front-month each week, close back-month when profitable Complex: Multi-expiry management, requires experience
STRATEGY CARD 10: Iron Butterfly
Overview: Tight range bet, ATM short straddle + OTM wings Regime: Very low vol, tight range expected Setup: Sell ATM put + ATM call, buy OTM wings ₹200-300 away Entry: Bollinger Bands squeezed, low VIX Exit: 40-50% profit, tight stop loss Greeks: Gamma very high (risky near expiry), Theta very high Sizing: 1-2 lots (high risk/reward)
STRATEGY CARD 11: Covered Strangle (Cash-Secured)
Overview: Own underlying, sell OTM put + OTM call Regime: Sideways, income on holdings Setup: Hold 500 NIFTY futures/ETF, sell 0.20 delta put + call Entry: Long-term bullish on underlying, want income Exit: Roll monthly, manage assignment Capital Intensive: Requires holding underlying (₹5-10L+)
STRATEGY CARD 12: Long Butterfly (Debit)
Overview: Profit from no movement, defined risk Regime: Extremely low vol expected Setup: Buy 1 ITM, sell 2 ATM, buy 1 OTM (puts or calls) Entry: VIX < 20th percentile, expected consolidation Exit: Close when 50% of max profit reached Greeks: Theta slightly positive, Gamma high near ATM Sizing: 3-5 lots (low risk per lot)
Risk & Compliance Checklist
Regulatory & Legal Items
- SEBI Compliance: Confirm latest F&O margin rules (SPAN+Exposure)
- Tax Obligations:
- STT on sell side understood
- F&O gains taxed as business income (consult CA)
- Maintain detailed trade log for tax filing
- Broker Agreement: Terms of service reviewed
- Pattern Day Trading: Not applicable in India (no PDT rule like US)
- Leverage Limits: Understand broker's intraday vs overnight margin
- Early Assignment: Know broker's policy on ITM options near expiry
- Exchange Penalties: Understand penalties for position limit breaches (if trading large size)
Operational Risk Controls
- API Security: API keys stored securely, never in code repos
- Kill-Switch Tested: Emergency close-all function works
- Backup Internet: Have mobile hotspot for trading continuity
- Broker Redundancy: Consider second broker account for backup
- Capital Segregation: Trading capital separate from emergency funds
- Insurance: Health/life insurance in place (trading stress management)
Final Summary & Next Steps
Immediate Actions (Week 1)
- Download historical data for NIFTY (2-3 years)
- Set up Python environment with required libraries
- Implement Iron Condor backtest using provided code
- Review Strategy Cards and select 2-3 to start
- Open paper trading account if not already done
Success Principles
- Start Small, Scale Slowly: Never risk more than 2% per trade initially
- Follow the Process: Checklists exist for a reason—use them
- Track Everything: Data drives improvement
- Be Patient: Proficiency takes 6-12 months, not weeks
- Preserve Capital: Your first job is to not lose money, second job is to make money
- Adapt: Markets change, strategies must adapt
Common Pitfalls to Avoid
- ❌ Skipping paper trading phase
- ❌ Over-leveraging (using >60% margin)
- ❌ Holding positions into expiry (gamma risk)
- ❌ Ignoring stop losses (hope is not a strategy)
- ❌ Revenge trading after losses
- ❌ Adding to losing positions without plan
- ❌ Trading during high-impact events without hedge
Resources for Continuous Learning
- NSE F&O Resources: www.nseindia.com/products-services/fno-trading-resources
- Zerodha Varsity (free): zerodha.com/varsity (excellent for Indian markets)
- Option Greeks visualization: www.optionsprofitcalculator.com
- Join trading communities: r/IndianStreetBets (Reddit), TradingView India
DISCLAIMER
Information provided is for educational purposes only. Past performance does not guarantee future returns. Backtest and paper-trade before live deployment. Verify current regulatory, tax, and brokerage rules. Consult licensed financial and legal advisors as necessary.
Options trading involves substantial risk of loss and is not suitable for all investors. The strategies outlined here are hypothetical and based on theoretical models. Actual results may vary significantly due to market conditions, execution quality, slippage, transaction costs, and other factors. No representation is being made that any account will or is likely to achieve profits or losses similar to those discussed. The user assumes full responsibility for their trading decisions.
Comments
Post a Comment