Overall Statistics |
Total Trades 1109 Average Win 0.09% Average Loss -0.08% Compounding Annual Return -16.449% Drawdown 16.800% Expectancy -0.406 Net Profit -16.737% Sharpe Ratio -2.048 Probabilistic Sharpe Ratio 0.000% Loss Rate 72% Win Rate 28% Profit-Loss Ratio 1.13 Alpha 0 Beta 0 Annual Standard Deviation 0.056 Annual Variance 0.003 Information Ratio -2.048 Tracking Error 0.056 Treynor Ratio 0 Total Fees $1486.59 Estimated Strategy Capacity $8300000.00 Lowest Capacity Asset P R735QTJ8XC9X |
#region imports from AlgorithmImports import * #endregion import numpy as np from trend0 import * class UglyBrownDolphin(QCAlgorithm): def Initialize(self): self.SetStartDate(2021, 5, 25) self.SetCash(100000) self.stopLossPercentLong = .99 self.takeProfitPercentLong = 1.02 self.stopLossPercentShort = 1.004 self.takeProfitPercentShort = .995 self.UniverseSettings.Resolution = Resolution.Minute self.AddUniverse(self.CoarseSelectionFunction) self.SetCash(100000) self.SetTimeZone("America/New_York") self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin) self.averages = {} self.symbolData = {} ##################################################################### # 100 stocks 10$ and up, highest dollar volume def CoarseSelectionFunction(self, universe): selected = [] universe = sorted(universe, key = lambda c: c.DollarVolume, reverse=True) universe = [c for c in universe if c.Price > 10][:100] for coarse in universe: selectionSymbol = coarse.Symbol if selectionSymbol not in self.averages: history = self.History(selectionSymbol, 30, Resolution.Daily) self.averages[selectionSymbol] = SelectionData(history) self.averages[selectionSymbol].update(self.Time, coarse.AdjustedPrice) if self.averages[selectionSymbol].fast > self.averages[selectionSymbol].slow: if self.averages[selectionSymbol].is_ready(): selected.append(selectionSymbol) return selected[:10] ##################################################################### # Create SymbolData object for each stock added to universe def OnSecuritiesChanged(self, changes): for ticker in changes.AddedSecurities: symbol = ticker.Symbol if symbol not in self.symbolData: indicatorHistory = self.History(symbol, 90, Resolution.Minute) self.symbolData[symbol] = SymbolData(self, symbol, indicatorHistory) ##################################################################### def OnData(self, slice): for symbol, data in self.symbolData.items(): price = self.Securities[symbol].Price if not data.indicator.IsReady: return if data.indicator.Current.Value > 1 and data.openTrade: self.SetHoldings(symbol, 0.1) data.stopmarketorderticket = self.StopMarketOrder(symbol, -self.Portfolio[symbol].Quantity, price * .995) data.limitorderticket = self.LimitOrder(symbol, -self.Portfolio[symbol].Quantity, price * 1.01) data.openTrade = False #ignore '''self.SetHoldings(symbol, -1.0) self.stopmarketorderticketshort = self.StopMarketOrder(symbol, -self.Portfolio[self.symbol].Quantity, price * 1.005) self.limitorderticketshort = self.LimitOrder(symbol, -self.Portfolio[self.symbol].Quantity, price * .99)''' ##################################################################### def OnOrderEvent(self, orderEvent): data = self.symbolData.get(orderEvent.Symbol, None) if not data or orderEvent.Status != OrderStatus.Filled: return for symbol, data in self.symbolData.items(): price = self.Securities[symbol].Price if orderEvent.Status != OrderStatus.Filled: return if data.stopmarketorderticket != None and data.stopmarketorderticket.OrderId == orderEvent.OrderId: data.limitorderticket.Cancel() data.openTrade = True if data.limitorderticket != None and data.limitorderticket.OrderId == orderEvent.OrderId: data.stopmarketorderticket.Cancel() data.openTrade = True if data.stopmarketorderticketshort != None and data.stopmarketorderticketshort == orderEvent.OrderId: data.limitorderticketshort.Cancel() data.openTrade = True if data.limitorderticketshort != None and data.limitorderticketshort == orderEvent.OrderId: data.stopmarketorderticketshort.Cancel() data.openTrade = True ##################################################################### # instantiate and initialize symbols, feed with history request class SymbolData: def __init__(self, algorithm, symbol, indicatorHistory): #algorithm.Securities[symbol].SetLeverage(2.0) self.stopmarketorderticket = None self.limitorderticket = None self.stopmarketorderticketshort = None self.limitorderticketshort = None self.openTrade = True self.indicator = MomentumPercent(90) if indicatorHistory.empty: return for bar in indicatorHistory.itertuples(): self.indicator.Update(bar.Index[1], bar.close) def is__ready(self): return self.indicator.IsReady def update_(self, time, price): self.indicator.Update(time, price) self.RegisterIndicator = algorithm.RegisterIndicator(symbol, self.indicator, Resolution.Minute) # Is this how I should update indictor with fresh data, or DIY an update method within OnData? ##################################################################### # Only add stocks to universe that are trending up the past 10 days class SelectionData: def __init__(self, history): self.slow = ExponentialMovingAverage(30) self.fast = ExponentialMovingAverage(10) for bar in history.itertuples(): self.slow.Update(bar.Index[1], bar.close) self.fast.Update(bar.Index[1], bar.close) def is_ready(self): return self.slow.IsReady and self.fast.IsReady def update(self, time, price): self.fast.Update(time, price) self.slow.Update(time, price)
#region imports from AlgorithmImports import * #endregion # 11613 trend0 custom python indicator by Derek Melchin # inspired by Warren Harding https://www.quantconnect.com/forum/discussion/11613/algo-trend0/p1 class Trend0(PythonIndicator): def __init__(self, name, period, power): self.Name = name self.period = period self.power = power self.Time = datetime.min self.Value = 0 self.prices = np.array([]) def Update(self, time, close): self.prices = np.append(self.prices, close)[-self.period:] if len(self.prices) != self.period: self.Value = 0 return False self.Value = self.calc_trend() return True def calc_trend(self): changes = np.array([]) for i in range(len(self.prices) - 1): _return = (self.prices[i + 1] - self.prices[i]) / self.prices[i] changes = np.append(changes, _return) return self.power_weighted_moving_average(changes) def power_weighted_moving_average(self, changes): return self.weighted_average(changes, self.power_weights(len(changes))) def power_weights(self, length): weights = np.array([]) for i in range(length): w = i + 1 weights = np.append(weights, w**self.power) return weights def weighted_average(self, changes, weights): products = [] for i in range(len(changes)): products.append(changes[i] * weights[i]) return sum(products) / sum(weights)