Overall Statistics |
Total Trades 68 Average Win 6.93% Average Loss -0.83% Compounding Annual Return 383.712% Drawdown 29.500% Expectancy 5.328 Net Profit 449.830% Sharpe Ratio 7.486 Probabilistic Sharpe Ratio 94.664% Loss Rate 32% Win Rate 68% Profit-Loss Ratio 8.38 Alpha 3.302 Beta 2.702 Annual Standard Deviation 0.689 Annual Variance 0.475 Information Ratio 8.128 Tracking Error 0.55 Treynor Ratio 1.91 Total Fees $331.48 Estimated Strategy Capacity $70000000.00 |
class StatisticalArbitrage(QCAlgorithm): def Initialize(self): self.SetStartDate(2020, 4, 1) self.SetCash(100000) data = self.AddEquity("SPY", Resolution.Minute) data.SetLeverage(20) self.symbol = data.Symbol option = self.AddOption("SPY", Resolution.Minute) option.SetFilter(-20, 20, 25, 35) self.last_day = -1 def OnData(self,slice): # Check once a day. if self.Time.day == self.last_day: return self.last_day = self.Time.day for i in slice.OptionChains: chains = i.Value if not self.Portfolio.Invested: # divide option chains into call and put options calls = list(filter(lambda x: x.Right == OptionRight.Call, chains)) puts = list(filter(lambda x: x.Right == OptionRight.Put, chains)) # if lists are empty return if not calls or not puts: return underlying_price = self.Securities[self.symbol].Price expiries = [i.Expiry for i in puts] # determine expiration date nearly one month expiry = min(expiries, key=lambda x: abs((x.date()-self.Time.date()).days-30)) strikes = [i.Strike for i in puts] # determine at-the-money strike strike = min(strikes, key=lambda x: abs(x-underlying_price)) # determine 15% out-of-the-money strike otm_strike = min(strikes, key = lambda x:abs(x - float(0.85) * underlying_price)) atm_call = [i for i in calls if i.Expiry == expiry and i.Strike == strike] atm_put = [i for i in puts if i.Expiry == expiry and i.Strike == strike] otm_put = [i for i in puts if i.Expiry == expiry and i.Strike == otm_strike] if atm_call and atm_put and otm_put: options_q = int(self.Portfolio.MarginRemaining / (underlying_price * 100)) # Set max leverage. self.Securities[atm_call[0].Symbol].MarginModel = BuyingPowerModel(20) self.Securities[atm_put[0].Symbol].MarginModel = BuyingPowerModel(20) self.Securities[otm_put[0].Symbol].MarginModel = BuyingPowerModel(20) # sell at-the-money straddle self.Sell(atm_call[0].Symbol, options_q) self.Sell(atm_put[0].Symbol, options_q) # buy 15% out-of-the-money put self.Buy(otm_put[0].Symbol, options_q) # buy index. self.SetHoldings(self.symbol, 5) invested = [x.Key for x in self.Portfolio if x.Value.Invested] if len(invested) == 1: self.Liquidate(self.symbol)
class StatisticalArbitrage(QCAlgorithm): def Initialize(self): self.SetStartDate(2020, 4, 1) self.SetCash(100000) data = self.AddEquity("SPY", Resolution.Minute) data.SetLeverage(20) self.symbol = data.Symbol option = self.AddOption("SPY", Resolution.Minute) option.SetFilter(-20, 20, 25, 35) self.last_day = -1 def OnData(self,slice): # Check once a day. if self.Time.day == self.last_day: return self.last_day = self.Time.day for i in slice.OptionChains: chains = i.Value if not self.Portfolio.Invested: # divide option chains into call and put options calls = list(filter(lambda x: x.Right == OptionRight.Call, chains)) puts = list(filter(lambda x: x.Right == OptionRight.Put, chains)) # if lists are empty return if not calls or not puts: return underlying_price = self.Securities[self.symbol].Price expiries = [i.Expiry for i in puts] # determine expiration date nearly one month expiry = min(expiries, key=lambda x: abs((x.date()-self.Time.date()).days-30)) strikes = [i.Strike for i in puts] # determine at-the-money strike strike = min(strikes, key=lambda x: abs(x-underlying_price)) # determine 15% out-of-the-money strike otm_strike = min(strikes, key = lambda x:abs(x - float(0.85) * underlying_price)) atm_call = [i for i in calls if i.Expiry == expiry and i.Strike == strike] atm_put = [i for i in puts if i.Expiry == expiry and i.Strike == strike] otm_put = [i for i in puts if i.Expiry == expiry and i.Strike == otm_strike] if atm_call and atm_put and otm_put: options_q = int(self.Portfolio.MarginRemaining / (underlying_price * 100)) # Set max leverage. self.Securities[atm_call[0].Symbol].MarginModel = BuyingPowerModel(20) self.Securities[atm_put[0].Symbol].MarginModel = BuyingPowerModel(20) self.Securities[otm_put[0].Symbol].MarginModel = BuyingPowerModel(20) # sell at-the-money straddle self.Sell(atm_call[0].Symbol, options_q) self.Sell(atm_put[0].Symbol, options_q) # buy 15% out-of-the-money put self.Buy(otm_put[0].Symbol, options_q) # buy index. self.SetHoldings(self.symbol, 5) invested = [x.Key for x in self.Portfolio if x.Value.Invested] if len(invested) == 1: self.Liquidate(self.symbol)