Overall Statistics |
Total Trades 937 Average Win 0.16% Average Loss -0.09% Compounding Annual Return 3.655% Drawdown 2.700% Expectancy 0.409 Net Profit 19.707% Sharpe Ratio 1.593 Probabilistic Sharpe Ratio 90.800% Loss Rate 49% Win Rate 51% Profit-Loss Ratio 1.75 Alpha 0.029 Beta 0.047 Annual Standard Deviation 0.022 Annual Variance 0 Information Ratio -0.506 Tracking Error 0.181 Treynor Ratio 0.747 Total Fees $937.00 |
from decimal import Decimal class FibonacciOptionStraddle(QCAlgorithm): def Initialize(self): self.SetStartDate(2015, 7, 29) # Set Start Date self.SetCash(30000) # Set Strategy Cash self.SetBenchmark("SPY") #Ticker list self.tickers = ["MSFT", "GS", "V", "CSCO", "PG", "VZ", "TGT", "COST", "PEP", "WMT", "AAPL", "NEE"] self.maxBySymbol = {} self.totalPercentInv = 1/len(self.tickers) self.EnableAutomaticIndicatorWarmUp = True for ticker in self.tickers: symbol = self.AddEquity(ticker, Resolution.Hour).Symbol self.Securities[ticker].SetDataNormalizationMode(DataNormalizationMode.Raw) self.maxBySymbol[symbol] = self.MAX(symbol, 5, Resolution.Daily) self.SetBrokerageModel(BrokerageName.AlphaStreams) #create empy dictionary for purchase price of equity self.purchasedPrice = {} self.running = False #Runs strategy self.Schedule.On(self.DateRules.EveryDay(), self.TimeRules.Every(timedelta(hours=2)), self.runAlg) def runAlg(self): self.running = True def OnData(self, data): if not self.running: return for symbol, max_indicator in self.maxBySymbol.items(): #gets first option contract contract = self.GetContract(symbol) #if there is no contract then continue to next symbol if contract == None: continue fib100 = max_indicator.Current.Value #BufferFib subtracts 30% from the max Fibonacci Retracement to reach a 70% retracement bufferFib = self.Securities[symbol].Price * 0.3 #checks if equity price is below its maximum retracement. If equity price is above then strategy will automatically buy with no rational if self.Securities[symbol].Price < fib100: #if option premium is within a range between 130% and 70% of the Fibonacci Retracement continue if (fib100+bufferFib) >= self.Securities[contract].BidPrice >= (fib100-bufferFib): #If portfolio holds equity, move to next symbol if self.Portfolio[symbol].Invested: continue #saves price to priceSec right before purchase priceSec = self.Securities[symbol].Price self.SetHoldings(symbol, self.totalPercentInv, False, "Set Holdings") if self.Portfolio[symbol].Quantity == 0: continue self.LimitOrder(symbol, -(self.Portfolio[symbol].Quantity), round(round(priceSec, 2) * 1.03, 2)) #conducts an accurate rounding of priceSec to 2 decimal points and saves the purchase price to a dictionary numDec = Decimal(str(priceSec)) self.purchasedPrice[symbol] = round(numDec, 2) else: #if portfolio is invested and Bid Price and Fibonacci Retracement cross over a second time, sell if self.Portfolio[symbol].Invested: numDec2 = Decimal(str(self.Securities[symbol].Price)) #ensure equity is not sold at the same price if round(numDec2, 2) != self.purchasedPrice[symbol]: self.Liquidate(symbol) #stops alg self.running = False def GetContract(self, symbol): #pulls contract data for select equity at current time contracts = self.OptionChainProvider.GetOptionContractList(symbol, self.Time) #selects the type of option to be Put contract calls = [x for x in contracts if x.ID.OptionRight == OptionRight.Call] if len(calls) == 0: return None #sorts contracts by closet expiring date date and closest strike price (sorts in ascending order) calls = sorted(sorted(calls, key = lambda x: x.ID.Date), key = lambda x: x.ID.StrikePrice) #then selects all contracts that meet our expiration criteria contract = calls[0] #adds contract self.AddOptionContract(contract, Resolution.Minute) #return the call contract return contract