Skip to content

FillForwardEnumerator received data out of order #9108

@Martin-Molinero

Description

@Martin-Molinero

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

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

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions