Overall Statistics |
Total Trades 6897 Average Win 0.12% Average Loss -0.19% Compounding Annual Return -87.036% Drawdown 87.700% Expectancy -0.313 Net Profit -87.106% Sharpe Ratio -2.54 Probabilistic Sharpe Ratio 0.000% Loss Rate 58% Win Rate 42% Profit-Loss Ratio 0.65 Alpha -0.794 Beta 1.066 Annual Standard Deviation 0.339 Annual Variance 0.115 Information Ratio -3.298 Tracking Error 0.242 Treynor Ratio -0.808 Total Fees $79624.36 Estimated Strategy Capacity $560000.00 Lowest Capacity Asset AAPL R735QTJ8XC9X |
dev_mode = False # for Shile's use, keep False if dev_mode: from AlgorithmImports import * resolution = Resolution.Hour # ---indicies--- market = 'SPY' silver = 'SLV' gold = 'GLD' utility = 'XLU' industrial = 'XLI' safe = 'FXF' # safe currency risk = 'FXA' # risk currency debt_short = 'SHY' debt_inflation = 'TIP' metal = 'DBB' inp = 'IGE' # input cash = 'UUP' # ---equities CHANGEABLE equities = ['SPY', 'QQQ', 'AAPL'] # ---safeties CHANGEABLE safeties = ['GLD', 'FXF'] # ---in and out parameters # parameters found from file from you bull = True # set False for bear inOutLookbackBull = 252 inOutLookbackBear = 126 waitDaysConstant = 80 # WAITD_CONSTANT from your file iniWaitDays = 15 # INI_WAIT_DAYS from your file minWaitDays = 60 # 60 from the `min(60, self.WDadjvar)` from your file # ---supertrend parameters CHANGEABLE superTrendPeriod = 10 superTrendMultiple = 3 # ---squeeze parameters CHANGEABLE squeezeTrendPeriod = 20 squeezeBBMultiple = 2 # BollingerBands squeezeKeltMultiple = 1.5 # Kelter Channel # ---portfolio parameters # for the returns based portfolio allocation max_drawdown = .1 # max drawdown allowed before liquidation is signaled max_alloc = .4 # max allocation to any given stock returns_lookback = 100 # lookback for returns/drawdown calculations #from configs import * if dev_mode: from AlgorithmImports import * from collections import deque from datetime import datetime class AdaptableRedSnake(QCAlgorithm): def Initialize(self): self.SetStartDate(2000, 1, 11) self.SetCash(100000) self.supertrends = {} self.squeezes = {} for equity in equities: sym = self.AddEquity(equity, resolution).Symbol superTrend = MySuperTrend(self, superTrendPeriod, superTrendMultiple) self.RegisterIndicator(sym, superTrend, resolution) self.supertrends[sym] = superTrend squeeze = Squeeze(squeezeTrendPeriod, bollinger_multiple=squeezeBBMultiple, kelt_multiple=squeezeKeltMultiple) self.RegisterIndicator(sym, squeeze, resolution) self.squeezes[sym] = squeeze self.SetWarmUp(20) self.safeties = [self.AddEquity(symbol, resolution) for symbol in safeties] def OnData(self, data): ''' OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here. Arguments: data: Slice object keyed by symbol containing the stock data ''' if self.IsWarmingUp: return for symbol in self.supertrends: if not data.Bars.ContainsKey(symbol): return if self.supertrends[symbol].Value < data[symbol].Close and self.squeezes[symbol]: self.SetHoldings(symbol, 1 / len(self.supertrends)) else: self.Liquidate(symbol) for safety in self.safeties: self.SetHoldings(symbol, 1 / len(self.supertrends) / len(self.safeties)) class MySuperTrend: def __init__(self, algorithm, period, multiple, movingAverageType=MovingAverageType.Simple): self.Name = "Custom Indicator" self.Time = datetime.min self.Value = 0 self.multiplier = multiple self.atr = AverageTrueRange(period, movingAverageType) self.values = deque(maxlen=period) self.previousTrailingLowerBand = 0 self.previousTrailingUpperBand = 0 self.previousClose = 0 self.previousTrend = 0 def __repr__(self): return "{0} -> IsReady: {1}. Time: {2}. Value: {3}".format(self.Name, self.IsReady, self.Time, self.Value) def Update(self, input:TradeBar): self.Time = input.EndTime self.atr.Update(input) superTrend = 0 currentClose = input.Close currentBasicLowerBand = (input.Low + input.High) / 2 - self.multiplier * self.atr.Current.Value currentBasicUpperBand = (input.Low + input.High) / 2 + self.multiplier * self.atr.Current.Value if self.previousClose > self.previousTrailingLowerBand: currentTrailingLowerBand = max(currentBasicLowerBand, self.previousTrailingLowerBand) else: currentTrailingLowerBand = currentBasicLowerBand if self.previousClose < self.previousTrailingUpperBand: currentTrailingUpperBand = min(currentBasicUpperBand, self.previousTrailingUpperBand) else: currentTrailingUpperBand = currentBasicUpperBand if currentClose > currentTrailingUpperBand: currentTrend = 1 elif currentClose < currentTrailingLowerBand: currentTrend = -1 else: currentTrend = self.previousTrend if currentTrend == 1: superTrend = currentTrailingLowerBand elif currentTrend == -1: superTrend = currentTrailingUpperBand self.previousTrailingLowerBand = currentTrailingLowerBand self.previousTrailingUpperBand = currentTrailingUpperBand self.previousClose = currentClose self.previousTrend = currentTrend if not self.atr.IsReady: return 0 self.Value = superTrend return self.IsReady @property def IsReady(self): return self.atr.IsReady and self.Value != 0 class Squeeze: ''' .Value = 1 iff "squeezed" else .Value = 0 Tells us if we are in or out of squeeze Is Squeeze: lower BB > lower Keltner and upper BB < upper Keltner ''' def __init__(self, period, bollinger_multiple=2, kelt_multiple=1.5, movingAverageType=MovingAverageType.Simple): ''' .Value = 1 iff "squeezed" else .Value = 0 ''' self.Name = "SuperTrend" self.Time = datetime.min self.Value = 0 self.bb = BollingerBands(period, bollinger_multiple, movingAverageType) self.kelt = KeltnerChannels(period, kelt_multiple, movingAverageType) def __repr__(self): return "{0} -> IsReady: {1}. Time: {2}. Value: {3}".format(self.Name, self.IsReady, self.Time, self.Value) def Update(self, input:TradeBar): self.Time = input.EndTime self.kelt.Update(input) self.bb.Update(input.EndTime, input.Close) isSqueeze = self.bb.LowerBand.Current.Value > self.kelt.LowerBand.Current.Value and self.bb.UpperBand.Current.Value < self.kelt.UpperBand.Current.Value self.Value = int(isSqueeze) return self.IsReady @property def IsReady(self): return self.kelt.IsReady and self.bb.IsReady