Options Trading System
Integrate all the theory from previous chapters into a working trading system.
๐ฅ Vibe Prompt
"Build an options trading system in Python: real-time stock prices, Black-Scholes pricing, Greeks calculation, strategy signal generation, and risk monitoring alerts. Output buy/sell recommendations and risk metrics."
System Architecture
Market Data โ Pricing Engine โ Strategy Signals โ Risk Control โ Trade Execution
โ โ
โโโโโโโโโโโโโโโโโโโ Feedback Loop (Performance) โโโโโโโโโโโโโโโ
Practice Exercise
๐ก Vibe Coding Practice: Ask AI to build a "Complete Options Trading Platform":
- Real-time stock price feed (yfinance or API)
- Option pricing and Greeks calculation
- Strategy signal generator
- Risk monitoring dashboard
- Trade history and performance analysis
- Streamlit or Gradio web interface
Visualizing Option Prices
import matplotlib.pyplot as plt
import numpy as np
stock_prices = np.linspace(50, 150, 100)
prices = [black_scholes(S, 100, 0.5, 0.05, 0.2, 'call') for S in stock_prices]
plt.plot(stock_prices, prices)
plt.axvline(100, color='gray', linestyle='--', alpha=0.5)
plt.title('Call Option Price vs Stock Price')
plt.xlabel('Stock Price')
plt.ylabel('Option Price')
plt.grid(True, alpha=0.3)
plt.show()
Sensitivity Analysis
Impact of Volatility
vols = [0.1, 0.2, 0.3, 0.4, 0.5]
S, K, T, r = 100, 100, 0.5, 0.05
for sigma in vols:
call = black_scholes(S, K, T, r, sigma, 'call')
put = black_scholes(S, K, T, r, sigma, 'put')
print(f'Vol {sigma:.0%}: Call ${call:.2f}, Put ${put:.2f}')
Time Decay
- As expiration approaches, time value decreases
- Theta accelerates in the final 30 days
- ATM options have the highest time value
Practical Applications
Real-World Use Cases
- Portfolio Insurance: Buy OTM puts to protect against market crashes
- Income Generation: Sell covered calls on stocks you already own
- Volatility Trading: Trade options based on volatility expectations
- Earnings Play: Trade options around earnings announcements
Greeks in Practice
| Greek | Trader's Focus | |-------|---------------| | Delta | Directional risk, hedge ratio | | Gamma | Convexity, risk of large moves | | Theta | Time decay, option seller's friend | | Vega | Volatility risk, earnings plays | | Rho | Interest rate risk, long-dated options |
Common Issues & Solutions
| Problem | Cause | Solution | |---------|-------|----------| | Unexpected results | Wrong parameters | Check defaults and edge cases | | Slow execution | Inefficient algorithm | Use better data structures | | Out of memory | Too much data | Use batch processing | | Hard to debug | No logging | Add detailed logging |
Further Learning
- Read official documentation
- Browse open-source examples on GitHub
- Join community discussions
- Practice by modifying code and observing results
Trading System Architecture
A complete trading system has four layers.
Layer 1: Data Acquisition
import yfinance as yf
import pandas as pd
from datetime import datetime, timedelta
def fetch_options_chain(symbol: str, expiry: str = None):
"""Fetch options data for a given symbol."""
ticker = yf.Ticker(symbol)
# Get all available expiries
expirations = ticker.options[:5]
chains = {}
for exp in expirations:
opt = ticker.option_chain(exp)
chains[exp] = {
"calls": opt.calls,
"puts": opt.puts
}
return chains
# Example: Fetch Apple options
chains = fetch_options_chain("AAPL")
for exp, chain in chains.items():
print(f"Expiry: {exp}")
print(f" Calls: {len(chain['calls'])} strikes")
print(f" Puts: {len(chain['puts'])} strikes")
Layer 2: Signal Generation
def generate_momentum_signals(data: pd.DataFrame, symbol: str, chain: dict):
"""Generate trading signals based on technical indicators."""
signals = []
# Calculate 20-day moving average
data['SMA_20'] = data['Close'].rolling(20).mean()
data['SMA_50'] = data['Close'].rolling(50).mean()
latest = data.iloc[-1]
# Golden cross (bullish)
if latest['SMA_20'] > latest['SMA_50']:
# Find ATM call
atm_strike = round(latest['Close'] / 5) * 5
for _, option in chain['calls'].iterrows():
if abs(option['strike'] - atm_strike) < 2.5:
signals.append({
'type': 'BUY_CALL',
'symbol': symbol,
'strike': option['strike'],
'expiry': expiry,
'mid_price': (option['bid'] + option['ask']) / 2,
'reason': 'Golden cross, bullish momentum'
})
break
return signals
Layer 3: Risk Management
class RiskManager:
def __init__(self, max_daily_loss: float = 500, max_position_size: float = 2000):
self.max_daily_loss = max_daily_loss
self.max_position_size = max_position_size
self.daily_pnl = 0
self.positions = []
def can_open_position(self, cost: float, delta: float) -> bool:
"""Check if a new position meets risk criteria."""
checks = [
(cost <= self.max_position_size, "Exceeds max position size"),
(abs(delta) <= 20, "Delta too high"),
(len(self.positions) < 5, "Max 5 concurrent positions"),
(self.daily_pnl > -self.max_daily_loss, "Max daily loss exceeded")
]
for passed, reason in checks:
if not passed:
print(f"Blocked: {reason}")
return False
return True
def update_pnl(self, pnl: float):
self.daily_pnl += pnl
if self.daily_pnl < -self.max_daily_loss:
print("โ ๏ธ STOP LOSS TRIGGERED! Close all positions.")
self.close_all()
Layer 4: Execution
import time
from typing import Optional
class PaperExecutor:
def __init__(self, initial_capital: float = 10000):
self.capital = initial_capital
self.positions = []
self.trades = []
def execute_signal(self, signal: dict):
"""Execute a trading signal (paper trading)."""
cost = signal['mid_price'] * 100 # 1 contract = 100 shares
if cost > self.capital:
print(f"Insufficient capital: need ${cost:.2f}, have ${self.capital:.2f}")
return None
trade = {
'timestamp': datetime.now(),
'symbol': signal['symbol'],
'type': signal['type'],
'strike': signal['strike'],
'entry_price': signal['mid_price'],
'cost': cost,
'status': 'open'
}
self.capital -= cost
self.positions.append(trade)
self.trades.append(trade)
print(f"Executed: {trade['type']} {trade['symbol']} @ ${trade['entry_price']}")
return trade
Backtesting Framework
def backtest_strategy(symbol: str, days: int = 60):
"""Run a simple backtest of the momentum strategy."""
ticker = yf.Ticker(symbol)
hist = ticker.history(period=f"{days}d")
executor = PaperExecutor(initial_capital=10000)
wins = 0
losses = 0
for i in range(20, len(hist)):
data = hist.iloc[:i]
signal = generate_signals(data)
if signal and executor.capital > signal['cost']:
trade = executor.execute_signal(signal)
if trade:
# Simulate closing after 5 days
exit_price = hist.iloc[i]['Close'] if i < len(hist)-1 else signal['entry_price']
pnl = (exit_price - signal['entry_price']) * 100
if pnl > 0:
wins += 1
else:
losses += 1
print(f"Win Rate: {wins/(wins+losses)*100:.1f}%")
print(f"Total PnL: ${executor.capital - 10000:.2f}")
Summary
A trading system needs four layers: data, signals, risk management, and execution. Backtest thoroughly before trading with real money.
Key takeaways:
- Four layers: data acquisition โ signal generation โ risk โ execution |
- Paper trading validates strategies without financial risk |
- Risk manager enforces max position size, max loss, and delta limits |
- Backtesting measures win rate and total PnL over historical data |
- yfinance provides free options chain and price data |
- Always test on multiple symbols and time periods |
- Track every trade for post-analysis and improvement |
What's Next: Risk Management
The next chapter covers advanced risk management techniques.