I'm looking to backtest a strategy using futures options strangles but it has been a long time since I coded anything using Lean. When trying to examine the option chain for options that are within the delta range I am looking for, I can't get it to stop complaining that there is no data in OptionsChain. I presume I'm initializing something incorrectly but I can't quite figure out what. Any help would be appreciated….


namespace QuantConnect.Algorithm.CSharp
{
    public class FuturesStranglesTrader : QCAlgorithm
    {
		DateTime startDate			= new(month: 1, day: 1, year: 2022); 
		//TODO: make deltas optimization variables, for now, just way out of the money
		decimal deltaMin 			= 2; //absolute value
		decimal deltaMax 			= 3; //absolute value
		decimal startingCash        = 100000;
		BrokerageName brokerageName = BrokerageName.Default;
		string symbol				= Futures.Metals.Gold;
		Resolution resolution		= Resolution.Hour;
		//Intentionally a single DTE
		TimeSpan minDTE = TimeSpan.FromDays(7);
		TimeSpan maxDTE = TimeSpan.FromDays(7);
		Future future;
	
        public override void Initialize()
        {
			SetBenchmark("QQQ");
			SetStartDate(startDate);  
			SetCash(startingCash);
			SetBrokerageModel(brokerageName, AccountType.Margin);
			
			// Chart - Master Container for the Chart:
			var stockPlot = new Chart("Trade Plot");
			// On the Trade Plotter Chart we want 3 series: trades and price:
			var buyOrders = new Series("Buy", SeriesType.Scatter, 0);
			var sellOrders = new Series("Sell", SeriesType.Scatter, 0);
			var assetPrice = new Series("Price", SeriesType.Line, 0);

			// future = 
			// 	AddFuture
			// 	(
			// 		symbol,
			// 		Resolution.Hour, //TODO: switch to minute or tick when things generally working
			// 		dataNormalizationMode: DataNormalizationMode.BackwardsRatio,
            //         dataMappingMode: DataMappingMode.OpenInterest,
            //         contractDepthOffset: 0
			// 	);

			future = AddFuture(symbol);
			//TODO: SHOULDN'T need to set filter anymore due to new continuous contract mode			
			//https://www.quantconnect.com/forum/discussion/12644/continuous-futures-support/p1
			future.SetFilter(0, 90); //TODO: What's the minimum I need to get 7 DTE options working?
			AddFutureOption(future.Symbol, FuturesOptionsSelector);
			SetWarmup(TimeSpan.FromDays(8), resolution); //TODO: do I need a warmup if I'm not using any indicators?
        }

		//TODO: Can filter to abs(delta) be applied here to speedup test?	
		//Filter down to options that have a specific DTE
		private OptionFilterUniverse FuturesOptionsSelector(OptionFilterUniverse filter) =>
			filter.IncludeWeeklys().Expiration(minDTE, maxDTE);

        public override void OnData(Slice data)
        {
			if (!IsReady(data))
				return;
				
			Plot("Price Plot", "Price", data.Bars[future.Symbol].Price);
			    
			foreach (var changedEvent in data.SymbolChangedEvents.Values)
        		Log($"Underlying futures contract changed: {changedEvent.OldSymbol} -> {changedEvent.NewSymbol}"); //log futures contract rollovers

//TODO: check for options assignments and close position if assigned
				
			if (!Portfolio.Invested) 
				EnterPosition(data);
			else
				ExitPosition(data);
        }

		private bool IsReady(Slice data) =>
			data.HasData && !IsWarmingUp;
			
		private void EnterPosition(Slice data)
		{
			if (Portfolio.Invested)
				return; //Only allow one position at a time

			if (!data.OptionChains.Any() && !data.FutureChains.Any())
				return; //don't have anything to work with

			//Select the calls and puts that are within the delta range	
//TODO: THIS LINE ALWAYS FAILS THE BACKTEST AND BREAKPOINT ON IT DOESN'T WORK
			var availableContracts = data.OptionChains[future.Symbol].Where(contract => Math.Abs(contract.Greeks.Delta) >= deltaMin && Math.Abs(contract.Greeks.Delta) < deltaMax);
			//TODO: make sure I have these +/- deltas right for identifying contract type or use a different method
			//TODO: Preferrable to order available contracts by volume and/or open interest?
			var availablePuts = availableContracts.Where(contract => contract.Greeks.Delta < 0).OrderByDescending(contract => Math.Abs(contract.Greeks.Delta));
			var availableCalls = availableContracts.Where(contract => contract.Greeks.Delta > 0).OrderByDescending(contract => Math.Abs(contract.Greeks.Delta));
			
			var callLeg = availableCalls.FirstOrDefault();
			var putLeg = availablePuts.FirstOrDefault();
			
			if (callLeg is not null && putLeg is not null)
			{
				var optionStrategy = OptionStrategies.Strangle(future.Symbol, callLeg.Strike, putLeg.Strike, putLeg.Expiry);
				var order = Sell(optionStrategy, 1); //TODO: how to set as a limit order? How do I do max size with a specified margin buffer?
				Debug($"Sold strangle: {order}");
			}
		}	
		
		private void ExitPosition(Slice data)
		{
			//For now, just letting it expire. I suspect a sell will only trigger every other week because we effectively look to open on the day one is expiring
		}	
    }
}

Author