Overall Statistics
Total Trades
94
Average Win
0.37%
Average Loss
-0.09%
Compounding Annual Return
1.848%
Drawdown
1.600%
Expectancy
0.222
Net Profit
0.912%
Sharpe Ratio
0.451
Probabilistic Sharpe Ratio
32.884%
Loss Rate
77%
Win Rate
23%
Profit-Loss Ratio
4.22
Alpha
0.016
Beta
0.002
Annual Standard Deviation
0.035
Annual Variance
0.001
Information Ratio
-1.994
Tracking Error
0.128
Treynor Ratio
9.243
Total Fees
$94.00
Estimated Strategy Capacity
$7800000.00
Lowest Capacity Asset
SPCE 324FMVN88B9T2|SPCE X91R7VLCNM91
class AlgoSeekDataDemoAlgorithm(QCAlgorithm):

    max_option_contract_expiry = timedelta(days=30)
    profit_target = 5000
    option_contract_symbol_by_equity_symbol = {}
    hit_profit_target_symbols = []

    def Initialize(self):
        self.SetStartDate(2021, 1, 1)
        self.SetEndDate(2021, 6, 30)
        self.SetCash(1000000) 
        
        self.UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw
        self.UniverseSettings.Resolution = Resolution.Daily
        self.AddUniverse(self.Universe.DollarVolume.Top(5))


    def OnData(self, data):
        
        # Subscribe to an Option contract for each underlying Equity if one isn't currently selected
        for symbol, option_contract in self.option_contract_symbol_by_equity_symbol.items():
            if option_contract is not None or symbol in self.hit_profit_target_symbols:
                continue
            
            # Fetch the contracts from the OptionChainProvider
            contract_symbols = self.OptionChainProvider.GetOptionContractList(symbol, data.Time)
            
            # Find the latest contract expiry
            expiries = [symbol.ID.Date for symbol in contract_symbols if symbol.ID.Date.date() > data.Time.date() + self.max_option_contract_expiry]
            if len(expiries) == 0:
                continue
            furthest_expiry = max(expiries)
            
            # Select the put Option contracts with the furthest expiry and in the money
            selected_contract_symbols = []
            for contract_symbol in contract_symbols:
                if contract_symbol.ID.Date == furthest_expiry and \
                    contract_symbol.ID.OptionRight == OptionRight.Put and \
                    contract_symbol.ID.StrikePrice < self.Securities[symbol].Price:
                        selected_contract_symbols.append(contract_symbol)
            if len(selected_contract_symbols) == 0:
                continue
            
            # Select the put Option contract with the lowest strike price
            contract_symbol = sorted(selected_contract_symbols, key=lambda contract: contract.ID.StrikePrice)[0]
            self.option_contract_symbol_by_equity_symbol[symbol] = contract_symbol
            
            # Subscribe to the Option contract
            self.AddOptionContract(contract_symbol)
            
            
        # Place entry orders
        for symbol, option_contract in self.option_contract_symbol_by_equity_symbol.items():
            if symbol in self.hit_profit_target_symbols:
                continue
            
            # Buy underlying Equity if not already invested
            if data.ContainsKey(symbol) and data[symbol] is not None and \
                not self.Portfolio[symbol].Invested and not data[symbol].IsFillForward:
                    self.MarketOrder(symbol, 100)
            
            # Buy the put Option 
            if option_contract is not None and \
                data.ContainsKey(option_contract) and \
                data[option_contract] is not None and \
                not self.Portfolio[option_contract].Invested and \
                self.Securities[option_contract].IsTradable:
                    self.MarketOrder(option_contract, 1)
                
                
        # Close the position if we've hit the take-profit level
        for symbol, option_contract in self.option_contract_symbol_by_equity_symbol.items():
            if self.Portfolio[symbol].Invested and \
                self.Portfolio[symbol].UnrealizedProfit > self.profit_target and \
                symbol not in self.hit_profit_target_symbols:
                    self.hit_profit_target_symbols.append(symbol)
                    self.Liquidate(symbol)
                    self.Liquidate(option_contract)
                
        
            
    def OnOrderEvent(self, order_event):
        # Remove the selected Option contract from our dictionary if it has expired
        if order_event.Status == OrderStatus.Filled and \
            order_event.Symbol in self.option_contract_symbol_by_equity_symbol.values() and \
            order_event.Direction == OrderDirection.Sell:
                self.option_contract_symbol_by_equity_symbol[order_event.Symbol.Underlying] = None
           
    def OnSecuritiesChanged(self, changes):
        for security in changes.AddedSecurities:
            if security.Type == SecurityType.Equity:
                self.option_contract_symbol_by_equity_symbol[security.Symbol] = None
        
        for security in changes.RemovedSecurities:
            if security.Type == SecurityType.Equity:
                if security.Symbol in self.hit_profit_target_symbols:
                    self.hit_profit_target_symbols.remove(security.Symbol)
                self.Liquidate(security.Symbol)
                option_contract = self.option_contract_symbol_by_equity_symbol.pop(security.Symbol, None)
                if option_contract:
                    self.Liquidate(option_contract)