Hello Everyone,
I am absolutely struggling to get the options to work on this platform, I seem to find absolutely no tutorials on options and its really annoying to work through.
I have my code below:
+ Expand
from AlgorithmImports import *
from collections import deque
import numpy as np
from datetime import timedelta
class SPYOptionsBot(QCAlgorithm):
def Initialize(self):
# Algorithm Settings
self.SetStartDate(2023, 1, 1)
self.SetEndDate(2023, 12, 31)
self.SetCash(100000)
# Add SPY Equity
self.spy = self.AddEquity("SPY", Resolution.Minute).Symbol
self.SetBenchmark(self.spy)
# Add SPY Options
self.option = self.AddOption("SPY", Resolution.Minute)
# ---- Expiration changed to 1 to 2 weeks ----
self.min_days_to_expiry = 7 # 1 week out
self.max_days_to_expiry = 14 # 2 weeks out
self.option.SetFilter(self.FilterOptions)
# Parameters
self.lookback_period = 252 # daily bars for volatility calc
self.required_bullish_days = 3 # consecutive bullish candles
self.std_dev_multiplier = 1.0
self.max_positions = 3 # max concurrent positions
self.position_size = 0.1 # 10% of portfolio value per trade
# Track closing prices for bullish pattern detection
self.previous_closes = deque(maxlen=self.required_bullish_days)
# Keep track of open positions
self.open_positions = {}
# Schedule position management daily at 15:30
self.Schedule.On(self.DateRules.EveryDay(),
self.TimeRules.At(15, 30),
self.ManagePositions)
def FilterOptions(self, universe):
"""
Filter for strikes near the current price, with expiration
between 1-2 weeks (7 to 14 days).
"""
return (universe
.Strikes(-3, 3)
.Expiration(self.min_days_to_expiry, self.max_days_to_expiry))
def OnData(self, data):
# We need SPY bar data to detect bullish pattern
if self.spy not in data.Bars:
return
# Track consecutive bullish closes
bar = data.Bars[self.spy]
self.previous_closes.append(bar.Close)
# Check for bullish pattern and capacity for new trades
if (len(self.previous_closes) == self.required_bullish_days
and all(self.previous_closes[i] > self.previous_closes[i - 1]
for i in range(1, self.required_bullish_days))
and len(self.open_positions) < self.max_positions):
self.Log(f"Detected {self.required_bullish_days} bullish candles. Looking for put options to sell.")
# Check if we have any option chain data in this slice
if self.spy in data.OptionChains and len(data.OptionChains[self.spy]) > 0:
option_chain = data.OptionChains[self.spy]
self.SellPutOption(option_chain)
else:
self.Log("No option chain data is available for SPY at this moment.")
def SellPutOption(self, option_chain):
# Current price of the underlying equity
underlying_price = self.Securities[self.spy].Price
# Calculate historical volatility (std dev) over specified lookback
history = self.History(self.spy, self.lookback_period, Resolution.Daily)
if history.empty:
self.Log("No historical data available to compute volatility.")
return
close_col = 'close' if 'close' in history.columns else 'Close'
stddev = np.std(history[close_col])
strike_price = underlying_price - (stddev * self.std_dev_multiplier)
# Filter for put options that are out-of-the-money (<= strike_price)
puts = [
contract for contract in option_chain
if contract.Right == OptionRight.Put
and contract.Strike <= strike_price
and (self.Time + timedelta(days=self.min_days_to_expiry)
<= contract.Expiry
<= self.Time + timedelta(days=self.max_days_to_expiry))
]
if not puts:
self.Log(f"No suitable put options found. Target strike: {strike_price}")
return
# Sort by "closeness" to strike, then volume (descending), then bid price
puts.sort(key=lambda x: (
abs(x.Strike - strike_price),
-(x.Volume or 0),
x.BidPrice
))
selected_put = puts[0]
max_position_value = self.Portfolio.TotalPortfolioValue * self.position_size
# Each contract represents 100 shares
if selected_put.BidPrice > 0:
quantity = int(max_position_value // (selected_put.BidPrice * 100))
else:
quantity = 0
if quantity > 0:
self.Sell(selected_put.Symbol, quantity)
self.open_positions[selected_put.Symbol] = {
'entry_price': selected_put.BidPrice,
'quantity': quantity,
'entry_time': self.Time,
'strike': selected_put.Strike
}
self.Log(f"Sold {quantity} contracts of {selected_put.Symbol} at {selected_put.BidPrice}")
else:
self.Log("Calculated position size is zero; not placing any order.")
def ManagePositions(self):
"""
Manage open positions daily at 15:30. Closes positions if:
1) 50% profit is reached (option price <= 50% of entry)
2) 100% loss is reached (option price >= 2x entry)
3) Position is held longer than 15 days
"""
positions_to_close = []
for symbol, position in list(self.open_positions.items()):
if symbol not in self.Securities:
self.Log(f"Symbol {symbol} not found in Securities.")
continue
current_price = self.Securities[symbol].Price
entry_price = position['entry_price']
days_held = (self.Time - position['entry_time']).days
# Closing conditions
if (current_price <= entry_price * 0.5 # 50% profit
or current_price >= entry_price * 2 # 100% loss
or days_held >= 15): # Time-based exit
self.Buy(symbol, position['quantity'])
positions_to_close.append(symbol)
self.Log(f"Closing position {symbol} after {days_held} days. "
f"Entry: {entry_price}, Exit: {current_price}")
# Remove closed positions from tracking
for symbol in positions_to_close:
del self.open_positions[symbol]
def OnOrderEvent(self, orderEvent):
if orderEvent.Status == OrderStatus.Filled:
self.Log(f"Order {orderEvent.OrderId} filled: "
f"{orderEvent.Symbol} at {orderEvent.FillPrice}")
def OnEndOfAlgorithm(self):
self.Log(f"Algorithm ended. Final portfolio value: "
f"${self.Portfolio.TotalPortfolioValue:,.2f}")
Any help would be so appreciated!
Domenico Bezuidenhout
I keep getting chain wont load errors
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
Mia Alissi
Sources: Upcoming Holiday Momentum for Amazon, Index Option Bull Put Spread Algorithm, Automating the Wheel Strategy, Index Option Bear Put Spread Algorithm, Head & Shoulders TA Pattern Detection
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
To unlock posting to the community forums please complete at least 30% of Boot Camp.
You can continue your Boot Camp training progress from the terminal. We hope to see you in the community soon!