| 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