Lean icon indicating copy to clipboard operation
Lean copied to clipboard

FillForwardEnumerator received data out of order

Open Martin-Molinero opened this issue 1 month ago • 0 comments

Expected Behavior

  • Warmup does not trigger FillForwardEnumerator received data out of order

Actual Behavior

  • FF triggering FillForwardEnumerator received data out of order

Potential Solution

N/A

Reproducing the Problem


class BasicTemplateAlgorithm(QCAlgorithm):
    def initialize(self):
        self.set_start_date(2024, 9, 1)
        self.set_end_date(2024, 12, 1)
        
        self.spy = self.add_equity("SPY", Resolution.MINUTE).symbol
        
        option = self.add_option("SPY", Resolution.MINUTE)
        self.spy_option = option.symbol
        
        option.set_filter(lambda u: u.strikes(-5, 5).expiration(20, 45))
        
        self.set_warm_up(200, Resolution.DAILY)
        
        self.current_contract = None
        self.days_to_expiration_threshold = 5
        
        self.schedule.on(self.date_rules.every_day("SPY"),
                        self.time_rules.after_market_open("SPY", 30),
                        self.manage_options)

    def manage_options(self):
        if self.current_contract is not None:
            if self.current_contract in self.securities:
                days_to_expiry = (self.current_contract.id.date - self.time).days
                if days_to_expiry <= self.days_to_expiration_threshold:
                    self.liquidate(self.current_contract)
                    self.current_contract = None
                    return
                    
                if self.portfolio[self.current_contract].invested:
                    unrealized_profit_pct = self.portfolio[self.current_contract].unrealized_profit_percent
                    if unrealized_profit_pct >= 0.5 or unrealized_profit_pct <= -2.0:
                        self.liquidate(self.current_contract)
                        self.current_contract = None
                        return
        if self.current_contract is None or not self.portfolio[self.current_contract].invested:
            self.sell_put()
    
    def sell_put(self):
        chain = self.current_slice.option_chains.get(self.spy_option)
        if chain is None or len(chain) == 0:
            return
        
        # Filter for put options
        puts = [x for x in chain if x.right == OptionRight.PUT]
        if len(puts) == 0:
            return
        
        # Get current SPY price
        spy_price = self.securities[self.spy].price
        
        # Select put with strike around 5-10% out of the money
        target_strike = spy_price * 0.95
        
        # Find the put closest to our target strike with 30-45 DTE
        selected_put = sorted(puts, 
                            key=lambda x: abs(x.strike - target_strike) + abs((x.expiry - self.time).days - 35))
        
        if len(selected_put) == 0:
            return
            
        contract = selected_put[0]
        
        # Sell 1 put contract (100 shares per contract)
        # Use margin carefully - each contract requires cash/margin equal to strike * 100
        quantity = 1
        
        self.market_order(contract.symbol, -quantity)
        self.current_contract = contract.symbol
        
        self.debug(f"Sold put: {contract.symbol}, Strike: {contract.strike}, "
                  f"Expiry: {contract.expiry}, Premium: {contract.bid_price}")
    
    def on_data(self, data: Slice):
        # Store slice for access in scheduled functions
        self.current_slice = data

System Information

N/A

Checklist

  • [x] I have completely filled out this template
  • [x] I have confirmed that this issue exists on the current master branch
  • [x] I have confirmed that this is not a duplicate issue by searching issues
  • [x] I have provided detailed steps to reproduce the issue

Martin-Molinero avatar Dec 04 '25 17:12 Martin-Molinero