Overall Statistics |
Total Trades 374 Average Win 0.58% Average Loss -0.49% Compounding Annual Return 8.715% Drawdown 6.400% Expectancy 0.144 Net Profit 13.359% Sharpe Ratio 0.07 Sortino Ratio 0.067 Probabilistic Sharpe Ratio 34.164% Loss Rate 48% Win Rate 52% Profit-Loss Ratio 1.18 Alpha -0.015 Beta 0.203 Annual Standard Deviation 0.071 Annual Variance 0.005 Information Ratio -0.753 Tracking Error 0.126 Treynor Ratio 0.024 Total Fees $585.96 Estimated Strategy Capacity $83000000.00 Lowest Capacity Asset QQQ RIWIV7K5Z9LX Portfolio Turnover 67.95% |
#region imports from AlgorithmImports import * #endregion class Strategy: def __init__(self, algo, symbol): self.algo = algo self.symbol = symbol self.day_close = None self.day_open = None self.entries_by_date = {} self.high_of_day = None self.low_of_day = None # Just to see how it's done -- not too bad. self.bb = self.algo.BB(self.symbol, self.algo.length, self.algo.nstd, Resolution.Minute) self.vwap = self.algo.VWAP(self.symbol) self.sma = self.algo.SMA(self.symbol, self.algo.length) self.sigma = self.algo.STD(self.symbol, self.algo.length) self.smas = RollingWindow[float](self.algo.n + 1) self.vwaps = RollingWindow[float](self.algo.n + 1) # Decided on a delegate method, rather than a consolidator # just simpler, less boilerplate. def OnData(self, data: Slice): data = data.Bars if not data.ContainsKey(self.symbol): return bar = data[self.symbol] tm = bar.EndTime self.UpdateWindows(bar) if self.IsReady: self.EntryLogic(bar) if self.Invested: self.ExitPackage() def UpdateWindows(self, bar): if self.sma.IsReady: self.smas.Add(self.sma.Current.Value) if self.vwap.IsReady: self.vwaps.Add(self.vwap.Current.Value) def EntryLogic(self, bar): alloc_pct = 1.0 / len(self.algo.strats) long_ok = self.algo.direction >= 0 sma_ok = bar.Close > self.sma.Current.Value sma_trend = self.smas[0] > self.smas[self.algo.n] # A bit hacked -- just using what we have available. below_lower = bar.Close < self.vwaps[0] - self.sigma.Current.Value * self.algo.nstd if long_ok and sma_ok and sma_trend and below_lower: self.algo.SetHoldings(self.symbol, alloc_pct) def ExitPackage(self): self.StopPct(self.algo.stop_pct) self.TgtPct(self.algo.tgt_pct) def StopPct(self, pct): if pct == 0.0: return urpct = self.algo.Portfolio[self.symbol].UnrealizedProfitPercent ur = self.algo.Portfolio[self.symbol].UnrealizedProfit if self.algo.Portfolio[self.symbol].UnrealizedProfitPercent < -1 * pct: self.algo.Liquidate(self.symbol, tag=f"Stop -- {ur}") def TgtPct(self, pct): if pct == 0.0: return ur = self.algo.Portfolio[self.symbol].UnrealizedProfit if self.algo.Portfolio[self.symbol].UnrealizedProfitPercent > pct: self.algo.Liquidate(self.symbol, tag=f"Tgt -- {ur}") @property def Sigma(self): if self.IsReady: return self.bb.Upper.Current.Value - self.bb.Middle.Current.Value @property def IsReady(self): return self.bb.IsReady and self.vwap.IsReady and self.sma.IsReady and self.vwaps.IsReady @property def Invested(self): return self.algo.Portfolio[self.symbol].Invested
# region imports from AlgorithmImports import * # endregion from Strategy import Strategy class SwimmingRedTermite(QCAlgorithm): tickers = ['QQQ'] entry_style_1 = True length = 50 nstd = 2 direction = 1 # Bars back, used for slope measure. n = 7 # If 0, will not set. # .01 == 1% tgt_pct = 0 stop_pct = 0 symbols = [] strats = {} def Initialize(self): self.SetStartDate(2022, 9, 1) self.SetCash(100000) # Set benchmark -- SPY (most common, need it unrelated to tickers) self.AddEquity('SPY', Resolution.Minute) self.SetBenchmark("SPY") # symbol = self.AddEquity("QQQ", Resolution.Minute).Symbol for t in self.tickers: s = self.AddEquity(t, Resolution.Minute).Symbol self.symbols.append(s) self.strats[s] = Strategy(self, s) self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 1), self.EODx) def EODx(self): self.Liquidate(tag="EOD") def OnData(self, data: Slice): gap_pcts = [] for symbol, strat in self.strats.items(): strat.OnData(data)