Overall Statistics Total Trades912Average Win0.04%Average Loss-0.05%Compounding Annual Return-0.948%Drawdown2.200%Expectancy-0.093Net Profit-1.973%Sharpe Ratio-1.476Probabilistic Sharpe Ratio0.016%Loss Rate50%Win Rate50%Profit-Loss Ratio0.82Alpha-0.01Beta0Annual Standard Deviation0.006Annual Variance0Information Ratio-0.891Tracking Error0.148Treynor Ratio-19.968Total 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

# 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
return

# only once per day
if self.previous is not None and self.previous.date() == self.Time.date():
return

holdings = self.Portfolio["SPY"].Quantity

# If there is no trades
if holdings == 0:
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