Overall Statistics
Total Trades
173
Average Win
0.02%
Average Loss
-0.01%
Compounding Annual Return
0.335%
Drawdown
0.200%
Expectancy
0.540
Net Profit
0.337%
Sharpe Ratio
0.621
Probabilistic Sharpe Ratio
30.265%
Loss Rate
49%
Win Rate
51%
Profit-Loss Ratio
2.04
Alpha
0.002
Beta
0.003
Annual Standard Deviation
0.005
Annual Variance
0
Information Ratio
-1.023
Tracking Error
0.349
Treynor Ratio
0.972
Total Fees
$89.00
# from datetime import timedelta
# import numpy as np
# from QuantConnect.Securities.Option import OptionPriceModels

class CondorAlgorithm(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2019, 6, 30)
        self.SetEndDate(2020, 6, 30)

        self.SetCash(1000000)
        equity = self.AddEquity("GOOG", Resolution.Minute)
        equity.SetDataNormalizationMode(DataNormalizationMode.Raw)
        
        self.SetSecurityInitializer(lambda x: x.SetMarketPrice(self.GetLastKnownPrice(x)))
        
        self.underlyingsymbol = equity.Symbol
        self.SetBenchmark(equity.Symbol)

    def OnData(self,slice):
        # slice.Contains(symbol)
        if self.Portfolio[self.underlyingsymbol].Quantity != 0:
            self.Liquidate()
      
        if not self.Portfolio.Invested:
            contracts = self.OptionChainProvider.GetOptionContractList(self.underlyingsymbol, self.Time.date())
            if contracts:
                self.TradeOptions(contracts, slice)

                        
    def TradeOptions(self,contracts, slice):
        filtered_contracts = self.InitialFilter(self.underlyingsymbol, contracts, -50, 50, 0, 7)
        # sorted the optionchain by expiration date and choose the furthest date
        expiry = sorted(filtered_contracts,key = lambda x: x.ID.Date)[-1].ID.Date

        # filter the call and put options from the contracts
        call = [i for i in filtered_contracts if i.ID.OptionRight == 0 and i.ID.Date == expiry]
        # put = [i for i in filtered_contracts if i.ID.OptionRight == 1 and i.ID.Date == expiry]
        # sorted the contracts according to their strike prices 
        call_contracts = sorted(call,key = lambda x: x.ID.StrikePrice)    
        # put_contracts = sorted(put,key = lambda x: x.ID.StrikePrice)
        
        
        
        # my long condor components
        itm_call_lower = call_contracts[-15]
        itm_call_upper = call_contracts[-10]
        otm_call_lower = call_contracts[-5]
        otm_call_upper = call_contracts[-1]
        
        if itm_call_lower == 0:
            return
        if itm_call_upper == 0:
            return
        if otm_call_lower == 0:
            return
        if otm_call_upper == 0:
            return
        
        self.trade_contracts = [itm_call_lower,itm_call_upper,otm_call_lower,otm_call_upper]
        for contract in self.trade_contracts:
            self.AddOptionContract(contract, Resolution.Minute) 
      
        #for contract in self.trade_contracts:
        #    if not slice.ContainsKey(contract):
        #        return
      
        self.Buy(itm_call_lower, 1) # Buy 1 ITM Call
        self.Sell(itm_call_upper, 1) # Sell 1 ITM Call 
        self.Sell(otm_call_lower, 1) # Sell 1 OTM Call 
        self.Buy(otm_call_upper, 1) # Buy 1 OTM Call
        
    
        
            
    def InitialFilter(self, underlyingsymbol, symbol_list, min_strike_rank, max_strike_rank, min_expiry, max_expiry):
        # fitler the contracts based on the expiry range
        contract_list = [i for i in symbol_list if min_expiry <= (i.ID.Date.date() - self.Time.date()).days <= max_expiry]
        
        # find the strike price of ATM option
        atm_strike = sorted(contract_list,
                            key = lambda x: abs(x.ID.StrikePrice - self.Securities[underlyingsymbol].Price))[0].ID.StrikePrice
        strike_list = sorted(set([i.ID.StrikePrice for i in contract_list]))
        
        # find the index of ATM strike in the sorted strike list
        atm_strike_rank = strike_list.index(atm_strike)
        try: 
            min_strike = strike_list[atm_strike_rank + min_strike_rank + 1]
            max_strike = strike_list[atm_strike_rank + max_strike_rank - 1]

        except:
            min_strike = strike_list[0]
            max_strike = strike_list[-1]
           
        filtered_contracts = [i for i in contract_list if i.ID.StrikePrice >= min_strike and i.ID.StrikePrice <= max_strike]

        return filtered_contracts