Hi all,
I am backtesting a 1DTE SPXW option strategy from 2022 to 2025. For almost 50 days I am not getting option chains. I know values exist on those days but as it works on Tradestation and I get values for the same days.
below is the code
from AlgorithmImports import *
class FixedFeeModel(FeeModel):
def GetOrderFee(self, parameters):
order = parameters.Order
quantity = abs(order.Quantity)
return OrderFee(CashAmount(1.0 * quantity, "USD")) # $1 per contract
# Define custom mid price fill model
class MidPriceFillModel(FillModel):
def MarketFill(self, asset, order):
fill = super().MarketFill(asset, order)
if asset.BidPrice == 0 or asset.AskPrice == 0:
# If we don't have bid/ask data, use default fill
return fill
# Calculate the mid price
mid_price = (asset.BidPrice + asset.AskPrice) / 2
# Update the fill price to mid price
fill.FillPrice = mid_price
return fill
# Define the custom slippage model
class FixedDollarSlippageModel:
def __init__(self, slippage_amount=0.1):
self.slippage_amount = slippage_amount # Fixed dollar amount per contract
def get_slippage_approximation(self, asset, order):
# Apply slippage based on order direction
direction = 1 if order.Direction == OrderDirection.Buy else -1
# Convert dollar amount to percentage of price
if asset.Price == 0:
return 0
slippage_percent = self.slippage_amount / asset.Price
return slippage_percent * direction
class OneDteIronFlyWithPnL(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2022, 5, 2)
self.SetEndDate(2025, 3, 21)
self.SetCash(100000)
fomc_dates = [
# 2022 dates
datetime(2022, 5, 4), datetime(2022, 6, 15), datetime(2022, 7, 27),
datetime(2022, 9, 21), datetime(2022, 11, 2), datetime(2022, 12, 14),
# 2023 dates
datetime(2023, 2, 1), datetime(2023, 3, 22), datetime(2023, 5, 3),
datetime(2023, 6, 14), datetime(2023, 7, 26), datetime(2023, 9, 20),
datetime(2023, 11, 1), datetime(2023, 12, 13),
# 2024 dates
datetime(2024, 1, 31), datetime(2024, 3, 20), datetime(2024, 5, 1)
]
cpi_dates = [
# 2022 dates
datetime(2022, 5, 11), datetime(2022, 6, 10), datetime(2022, 7, 13),
datetime(2022, 8, 10), datetime(2022, 9, 13), datetime(2022, 10, 13),
datetime(2022, 11, 10), datetime(2022, 12, 13),
# 2023 dates
datetime(2023, 1, 12), datetime(2023, 2, 14), datetime(2023, 3, 14),
datetime(2023, 4, 12), datetime(2023, 5, 10), datetime(2023, 6, 13),
datetime(2023, 7, 12), datetime(2023, 8, 10), datetime(2023, 9, 13),
datetime(2023, 10, 12), datetime(2023, 11, 14), datetime(2023, 12, 12),
# 2024 dates
datetime(2024, 1, 11), datetime(2024, 2, 13), datetime(2024, 3, 12),
datetime(2024, 4, 10)
]
self.blackout_days = set((dt.date() - timedelta(days=1)) for dt in fomc_dates + cpi_dates)
# Set margin model and fill model in a single security initializer
def initialize_security(security):
security.set_margin_model(SecurityMarginModel.NULL)
security.set_fill_model(MidPriceFillModel())
return security
self.set_security_initializer(initialize_security)
self.portfolio.set_positions(SecurityPositionGroupModel.NULL)
self.AddIndex("VIX", Resolution.MINUTE)
# self.index_symbol_vix = self.AddIndex("VIX", Resolution.MINUTE).Symbol
self.index_symbol = self.AddIndex("SPX", Resolution.MINUTE).Symbol
weekly_option = self.AddIndexOption(self.index_symbol, "SPXW")
# weekly_option_symbol = self.AddIndexOption(self.index_symbol, "SPXW").Symbol
# Set pricing model
# self.Securities[weekly_option_symbol].SetPricingModel(OptionPriceModels.CrankNicolsonFD())
# self.symbol = self.AddEquity("SPY", Resolution.Minute).Symbol
# self.consolidator = TradeBarConsolidator(timedelta(1))
# self.SubscriptionManager.AddConsolidator(self.index_symbol_vix, self.consolidator)
next_trading_day = self.Time.date() + timedelta(days=1)
while not self.Securities[self.index_symbol].Exchange.DateIsOpen(next_trading_day):
next_trading_day += timedelta(days=1)
days_to_expiry = (next_trading_day - self.Time.date()).days
# weekly_option.SetFilter(lambda universe: universe.IncludeWeeklys().Strikes(-20, 20).Expiration(1,1))
weekly_option.SetFilter(lambda universe: universe.IncludeWeeklys().Expiration(days_to_expiry,days_to_expiry))
self.option_symbol = weekly_option.Symbol
self.contracts = []
self.entry_prices = {}
self.quantity = 0
self.total_credit = 0
self.credit = 0
self.invested = False
self.vix_yesterday_close = None
self.vix_today_open = None
self.change_stop_loss = 0
self.half_exit_done = 0
self.total_trades = 0
self.profitable_trades = 0
self.no_vix_count = 0
self.losing_trades = 0
self.profitable_trades_eod = 0
self.losing_trades_eod = 0
self.pnl_tracking = 0
self.total_pnl_qc = 0
# Create a custom chart
# equityChart = Chart("Equity_Compare")
# Add custom series with chosen colors
# equityChart.AddSeries(Series("QC_PortfolioValue", SeriesType.Line, "$", Color.Blue))
# equityChart.AddSeries(Series("MyPandL", SeriesType.Line, "$", Color.Red))
# equityChart.AddSeries(Series("Difference", SeriesType.Line, "$", Color.Green))
# Register the chart
# self.AddChart(equityChart)
self.entry_slippage_model = FixedDollarSlippageModel(0.1) # $0.10 slippage for entries
self.stop_loss_slippage_model = FixedDollarSlippageModel(0.1) # $0.10 slippage for stop losses
self.default_slippage_model = FixedDollarSlippageModel(0.0) # No extra slippage for other exits
# self.Schedule.On(self.DateRules.EveryDay("SPX"), self.TimeRules.At(9, 31), self.CaptureVIXClose)
self.Schedule.On(self.DateRules.EveryDay("SPX"), self.TimeRules.AfterMarketOpen("SPX", 1), self.CaptureVIXClose)
self.Schedule.On(self.DateRules.EveryDay("SPX"), self.TimeRules.At(9, 32), self.CaptureVIXOpen)
self.Schedule.On(self.DateRules.EveryDay("SPX"), self.TimeRules.At(9, 32), self.EnterStraddle)
self.Schedule.On(self.DateRules.EveryDay("SPX"), self.TimeRules.Every(TimeSpan.FromMinutes(1)), self.CheckPnL)
self.Schedule.On(self.DateRules.EveryDay("SPX"), self.TimeRules.At(15, 56), self.ExitStraddle)
Mia Alissi
Here’s diagnostic code for Parth, designed to help pinpoint why SPXW option chains are missing on certain days. Drop this inside your EnterStraddle (or similar scheduled function):
How to use:
EnterStraddle
function.OptionChainProvider
returns, regardless of your filter, showing if contracts exist at all for that day/underlying.What this tells you:
OptionChainProvider
are empty, then QuantConnect is missing data for that day/underlying.OptionChainProvider
returns lots of contracts, but your filtered chain is empty, your filter might be off.Run your backtest, then inspect the logs for any problematic date! (If necessary, you can add more details or print all contract symbols for deeper debugging.)
Sources: docs writing algorithms securities asset classes equity options requesting data individual contracts, docs writing algorithms securities asset classes index options requesting data individual contracts, Greeks and IV Implementation, Indicators - QuantConnect.com, US Equity Option Universe - QuantConnect.com
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.
Parth Thaker
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!