Overall Statistics |
Total Trades 287 Average Win 0.10% Average Loss -0.10% Compounding Annual Return -10.524% Drawdown 2.000% Expectancy -0.100 Net Profit -1.452% Sharpe Ratio -3.026 Probabilistic Sharpe Ratio 2.619% Loss Rate 54% Win Rate 46% Profit-Loss Ratio 0.95 Alpha -0.113 Beta 0.123 Annual Standard Deviation 0.028 Annual Variance 0.001 Information Ratio -3.732 Tracking Error 0.081 Treynor Ratio -0.701 Total Fees $530.95 Estimated Strategy Capacity $2500000000.00 Lowest Capacity Asset NQ XRX5ODZTG8OX |
# example - https://www.quantconnect.com/forum/discussion/5257/futures-algorithm-with-indicator-and-consolidator-for-python/p1 # add MACD cross for close or lower TP/SL to see how it handles new order # entries are going off not on the cross because it's waiting for open order to close. # Once closed it then sees if MACD & RSI match and enters, often not right after a MACD cross # compare RSI and MACD values with SSE & ToS for most recent contract # MACD does not line up with SSE or ToS at all. SEE & ToS MACD match up # RSI is using closing value of the day before. does keep one value for different trades on the same day & only buys/sells on >/< 50 as it should. # SSE uses reg. avg for RSI and ToS uses Wilders avg for RSI. ### mostly just about matches SSE/Tos, a few days really far off in the beginning. Warm up probably didn't work. # NQ17U21 prices matches NQU21 from System.Drawing import Color class FocusedApricotAlpaca(QCAlgorithm): def Initialize(self): self.SetStartDate(2021, 7, 1) self.SetEndDate(2021, 8, 18) self.SetCash(1000000) self.SetWarmUp(timedelta(days = 15)) self.nq = self.AddFuture(Futures.Indices.NASDAQ100EMini) self.nq.SetFilter(5, 120) self.oi_contract = None self.macd = None self.takeProfit = None self.stopLoss = None stockPlot = Chart('Price Plot') stockPlot.AddSeries(Series('Price', SeriesType.Line, '$', Color.Green)) self.AddChart(stockPlot) def OnData(self, slice): for chain in slice.FutureChains: contracts = [contract for contract in chain.Value] if len(contracts) == 0: self.oi_contract = None self.macd = None break contract = sorted(contracts, key=lambda k : k.OpenInterest, reverse=True)[0] if self.oi_contract is not None and contract.Symbol == self.oi_contract.Symbol: break self.oi_contract = contract #set up consolidators fifteenMinute = TradeBarConsolidator(timedelta(minutes=15)) fifteenMinute.DataConsolidated += self.fifteenMinuteBarHandler #need to def fifteenMinuteBarHandler self.SubscriptionManager.AddConsolidator(contract.Symbol, fifteenMinute) # Set up Indicators self.macd = self.MACD(contract.Symbol, 12, 26, 9, MovingAverageType.Exponential) self.RegisterIndicator(contract.Symbol, self.macd, fifteenMinute) self.rsi = self.RSI(contract.Symbol, 9, MovingAverageType.Wilders, Resolution.Daily) def fifteenMinuteBarHandler(self, sender, bar): if self.macd is None or not self.macd.IsReady: return symbol = self.oi_contract.Symbol security = self.Securities[symbol] price = security.Price # Only new positions not invested if security.Invested: # Look to exit position return tolerance = 0.003 signalDeltaPercent = self.macd.Current.Value - self.macd.Signal.Current.Value if signalDeltaPercent > tolerance and self.rsi.Current.Value > 50: #Go long self.MarketOrder(symbol, 1) self.takeProfit = self.LimitOrder(symbol, -1, price+50) # 1% is too far for day trades self.stopLoss = self.StopMarketOrder(symbol, -1, price-50) self.Log(str(self.Time) + " buy " + str(price) + " MACD Current: " + str(self.macd.Current.Value) + " MACD Signal:" + str(self.macd.Signal.Current.Value) + " RSI: " + str(self.rsi.Current.Value)) if signalDeltaPercent < -tolerance and self.rsi.Current.Value < 50: #Go short self.MarketOrder(symbol, -1) self.takeProfit = self.LimitOrder(symbol, 1, price-50) self.stopLoss = self.StopMarketOrder(symbol, 1, price+50) self.Log(str(self.Time) + " sell " + str(price) + " MACD Current: " + str(self.macd.Current.Value) + " MACD Signal:" + str(self.macd.Signal.Current.Value) + " RSI: " + str(self.rsi.Current.Value)) self.Log(str(self.Time) + " Price: " + str(price)) def OnOrderEvent(self, orderEvent): if orderEvent.Status != OrderStatus.Filled: return self.Cancel(orderEvent.OrderId) def Cancel(self, id): '''cancel one order if the other was filled''' if self.takeProfit is not None and id == self.takeProfit.OrderId: self.stopLoss.Cancel() elif self.stopLoss is not None and id == self.stopLoss.OrderId: self.takeProfit.Cancel() else: return self.takeProfit = None self.stopLoss = None