Overall Statistics |
Total Trades 912 Average Win 0.04% Average Loss -0.05% Compounding Annual Return -0.948% Drawdown 2.200% Expectancy -0.093 Net Profit -1.973% Sharpe Ratio -1.476 Probabilistic Sharpe Ratio 0.016% Loss Rate 50% Win Rate 50% Profit-Loss Ratio 0.82 Alpha -0.01 Beta 0 Annual Standard Deviation 0.006 Annual Variance 0 Information Ratio -0.891 Tracking Error 0.148 Treynor Ratio -19.968 Total Fees $1839.42 |
class KeltnerMeanReversionAlgorithm(QCAlgorithm): def Initialize(self): '''Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.''' self.SetStartDate(2018, 1, 1) #Set Start Date #self.SetEndDate(2015, 1, 1) #Set End Date self.SetCash(250000) #Set Strategy Cash # Find more symbols here: http://quantconnect.com/data self.AddEquity("SPY") # create the 20 EMA self.mean = self.EMA("SPY", 20, Resolution.Daily) # create the ATR self.atr = self.ATR("SPY", 20, Resolution.Daily) self.previous = None self.marketTicket = None self.limitTicket = None self.stopTicket = None def OnData(self, data): '''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.''' # a couple things to notice in this method: # 1. We never need to 'update' our indicators with the data, the engine takes care of this for us # 2. We can use indicators directly in math expressions # 3. We can easily plot many indicators at the same time # wait for our ema to fully initialize if not self.mean.IsReady: return # only once per day if self.previous is not None and self.previous.date() == self.Time.date(): return risk_per_trade = 100 holdings = self.Portfolio["SPY"].Quantity # If there is no trades if holdings == 0: quantity = round(risk_per_trade / self.atr.Current.Value) price = self.Securities["SPY"].Price # Mean reversion when price is too low if self.Securities["SPY"].Price < self.mean.Current.Value - 2 * self.atr.Current.Value and self.marketTicket is None: self.marketTicket = self.MarketOrder("SPY", quantity) self.limitTicket = self.LimitOrder("SPY", -quantity, price + self.atr.Current.Value) self.stopTicket = self.StopMarketOrder("SPY", -quantity, price - self.atr.Current.Value) # Mean reversion when price is too high if self.Securities["SPY"].Price > self.mean.Current.Value + 2 * self.atr.Current.Value and self.marketTicket is None: self.marketTicket = self.MarketOrder("SPY", -quantity) self.limitTicket = self.LimitOrder("SPY", quantity, price - self.atr.Current.Value) self.stopTicket = self.StopMarketOrder("SPY", quantity, price + self.atr.Current.Value) self.previous = self.Time def OnOrderEvent(self, orderevent): if orderevent.Status == OrderStatus.Filled: orderId = orderevent.OrderId # If limit order has been filled, we cancel our stop loss and reset all order tickets if self.limitTicket is not None and orderId == self.limitTicket.OrderId: self.marketTicket = None self.limitTicket = None self.stopTicket.Cancel() self.stopTicket = None # If stop order has been filled, we cancel our limit order and reset all order tickets elif self.stopTicket is not None and orderId == self.stopTicket.OrderId: self.marketTicket = None self.stopTicket = None self.limitTicket.Cancel() self.limitTicket = None