Overall Statistics |
Total Trades 772 Average Win 0.07% Average Loss -0.04% Compounding Annual Return -4.360% Drawdown 4.800% Expectancy -0.464 Net Profit -4.640% Sharpe Ratio -3.056 Probabilistic Sharpe Ratio 0.001% Loss Rate 81% Win Rate 19% Profit-Loss Ratio 1.75 Alpha -0.041 Beta -0.012 Annual Standard Deviation 0.015 Annual Variance 0 Information Ratio -2.618 Tracking Error 0.124 Treynor Ratio 3.591 Total Fees $777.25 |
class MyAlgorithm(QCAlgorithm): def Initialize(self): self.SetStartDate(2019,1,1) self.SetCash(100000) self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage) tickers = ["SPY", "TLT", "BND"] # Creates empty dictionary to later hold daily Tradebar price rolling windows self.symbolData = {} for ticker in tickers: self.equity = self.AddEquity(ticker, Resolution.Hour) self.equity.SetDataNormalizationMode(DataNormalizationMode.Raw) self.equity.SetLeverage(1.0) symbol = self.equity.Symbol self.symbolData[symbol] = SymbolData(self, symbol) self.SetWarmUp(1000) def OnData(self, data): for symbol, value in self.symbolData.items(): if not data.ContainsKey(symbol): return value.window4.Add(data[symbol]) value.window3.Add(data[symbol]) value.window2.Add(data[symbol]) if self.IsWarmingUp or not value.IsReady: return for symbol, value in self.symbolData.items(): shares_to_buy = 50 if value.window3[0].Close > value.window3[1].Close > value.window3[2].Close: if value.stopbuys == None: value.stopbuys = self.StopMarketOrder(symbol, shares_to_buy, round(value.window3[0].High, 2)) else: updateSettings = UpdateOrderFields() updateSettings.StopPrice = round(value.window3[0].High, 2) updateSettings.Quantity = round(shares_to_buy) updateSettings.Tag = "Stop Buy Updated for {}".format(symbol) value.stopbuys.Update(updateSettings) else: if self.Portfolio[symbol].Invested: if value.stopsells == None: value.stopsells = self.StopMarketOrder(symbol, -self.Portfolio[symbol].Quantity, round(value.window3[0].Low, 2)) else: updateSettings = UpdateOrderFields() updateSettings.StopPrice = round(value.window3[0].Low, 2) updateSettings.Quantity = -self.Portfolio[symbol].Quantity updateSettings.Tag = "Stop Sell Updated for {}".format(symbol) value.stopsells.Update(updateSettings) # Is this the time a stop buy was entered or updated ? Or is it the time it was filled?? # How do we get the time a stopbuy was filled instead? # if (self.Time - self.stopbuys_time[symbol]).days == 0: # do something def OnOrderEvent(self, orderEvent): # Event when the order is filled. Debug log the order fill. :OrderEvent: #if OrderEvent.FillQuantity == 0: if orderEvent.Status != OrderStatus.Filled: return fetched = self.Transactions.GetOrderById(orderEvent.OrderId) self.Debug("{} was filled. Symbol: {}. Quantity: {}. Direction: {}" .format(str(fetched.Type), str(orderEvent.Symbol), str(orderEvent.FillQuantity), str(orderEvent.Direction))) if self.symbolData[orderEvent.Symbol].stopbuys is not None and self.symbolData[orderEvent.Symbol].stopbuys.OrderId == orderEvent.OrderId: self.symbolData[orderEvent.Symbol].stopbuys = None self.symbolData[orderEvent.Symbol].stopbuys_time = self.Time self.Debug(str(self.symbolData[orderEvent.Symbol].stopbuys_time)) if self.symbolData[orderEvent.Symbol].stopsells is not None and self.symbolData[orderEvent.Symbol].stopsells.OrderId == orderEvent.OrderId: self.symbolData[orderEvent.Symbol].stopsells = None self.symbolData[orderEvent.Symbol].stopsells_time = self.Time self.Debug(str(self.symbolData[orderEvent.Symbol].stopsells_time)) class SymbolData: def __init__(self, algorithm, symbol): self.algorithm = algorithm self.symbol = symbol # Creates empty dictionary to later hold stop buy values self.stopbuys = None # Creates empty dictionary to later hold stop sell values self.stopsells = None # Creates empty dictionary to later hold time of buy breakout occurrence self.stopbuys_time = datetime.min # Creates empty dictionary to later hold time of sell breakout occurrence self.stopsells_time = datetime.min self.window4 = RollingWindow[TradeBar](4) self.window3 = RollingWindow[TradeBar](3) self.window2 = RollingWindow[TradeBar](2) consolidator_daily = TradeBarConsolidator(timedelta(days = 1)) consolidator_daily.DataConsolidated += self.OnDailyData algorithm.SubscriptionManager.AddConsolidator(symbol, consolidator_daily) # Adding daily bar data to 3,2,1 etc.. rolling windows def OnDailyData(self, sender, bar): self.window4.Add(bar) self.window3.Add(bar) self.window2.Add(bar) @property def IsReady(self): return (self.window4.IsReady and self.window3.IsReady and self.window2.IsReady)