Overall Statistics |
Total Trades 444 Average Win 1.80% Average Loss -1.17% Compounding Annual Return 16.770% Drawdown 23.600% Expectancy 0.717 Net Profit 543.397% Sharpe Ratio 1.054 Probabilistic Sharpe Ratio 45.457% Loss Rate 32% Win Rate 68% Profit-Loss Ratio 1.54 Alpha 0.146 Beta 0.368 Annual Standard Deviation 0.177 Annual Variance 0.031 Information Ratio 0.376 Tracking Error 0.202 Treynor Ratio 0.506 Total Fees $7633.37 Estimated Strategy Capacity $23000.00 |
class DefensiveAssetAllocation(QCAlgorithm): def Initialize(self): self.SetStartDate(2008, 1, 1) # Set Start Date self.SetEndDate(2020,1,1) # Set End Date self.SetCash(100000) # Set Strategy Cash self.numberOfGrowth = 4 self.AddEquity("SPY", Resolution.Minute) self.SetBenchmark("SPY") # Set Brokerage Model self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin) # These are the growth symbol(s) we choose from #self.growthSymbols = ["SPY","QQQ","IWN","VGK","EWJ","VWO","GSG","GLD","VNQ","HYG","TLT","LQD"] self.growthSymbols = ["SSO","QLD","UWM","VGK","EWJ","VWO","GSG","GLD","VNQ","HYG","UBT","LQD"] # These are the safety symbol(s) we choose from # self.safetySymbols = ["IEF","SHY"] self.safetySymbols = ["IEF","SHY"] # These are the canary universe symbols self.canarySymbols = ["VWO", "BND"] # Combine all tickers self.allSymbols = self.growthSymbols + self.safetySymbols + self.canarySymbols self.Schedule.On(self.DateRules.MonthStart("SPY"), \ self.TimeRules.AfterMarketOpen("SPY", 10), \ self.Rebalance) # Storing data in the SymbolData object self.GrowthData = [] for symbol in list(self.growthSymbols): self.AddSecurity(SecurityType.Equity, symbol, Resolution.Minute) self.oneMonthPerformance = self.MOMP(symbol, 21, Resolution.Daily) self.threeMonthPerformance = self.MOMP(symbol, 63, Resolution.Daily) self.sixMonthPerformance = self.MOMP(symbol, 126, Resolution.Daily) self.twelveMonthPerformance = self.MOMP(symbol, 252, Resolution.Daily) self.GrowthData.append([symbol, self.oneMonthPerformance, self.threeMonthPerformance, self.sixMonthPerformance, self.twelveMonthPerformance]) self.SafetyData = [] for symbol in list(self.safetySymbols): self.AddSecurity(SecurityType.Equity, symbol, Resolution.Minute) self.oneMonthPerformance = self.MOMP(symbol, 21, Resolution.Daily) self.threeMonthPerformance = self.MOMP(symbol, 63, Resolution.Daily) self.sixMonthPerformance = self.MOMP(symbol, 126, Resolution.Daily) self.twelveMonthPerformance = self.MOMP(symbol, 252, Resolution.Daily) self.SafetyData.append([symbol, self.oneMonthPerformance, self.threeMonthPerformance, self.sixMonthPerformance, self.twelveMonthPerformance]) self.CanaryData = [] for symbol in list(self.canarySymbols): self.AddSecurity(SecurityType.Equity, symbol, Resolution.Minute) self.oneMonthPerformance = self.MOMP(symbol, 21, Resolution.Daily) self.threeMonthPerformance = self.MOMP(symbol, 63, Resolution.Daily) self.sixMonthPerformance = self.MOMP(symbol, 126, Resolution.Daily) self.twelveMonthPerformance = self.MOMP(symbol, 252, Resolution.Daily) self.CanaryData.append([symbol, self.oneMonthPerformance, self.threeMonthPerformance, self.sixMonthPerformance, self.twelveMonthPerformance]) self.SetWarmUp(252, Resolution.Daily) 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 ''' pass def Rebalance(self): if self.IsWarmingUp: return # Rank all the Growth and Safety symbol groups by momentum score orderedGrowthScores = sorted(self.GrowthData, key=lambda x: Score(x[1].Current.Value,x[2].Current.Value,x[3].Current.Value,x[4].Current.Value).ObjectiveScore(), reverse=True) bestGrowth = orderedGrowthScores[0:self.numberOfGrowth] bestGrowth = [x[0] for x in bestGrowth] orderedSafetyScores = sorted(self.SafetyData, key=lambda x: Score(x[1].Current.Value,x[2].Current.Value,x[3].Current.Value,x[4].Current.Value).ObjectiveScore(), reverse=True) bestSafety = orderedSafetyScores[0][0] # Calculate the momentum score of the Canary symbols CanaryScores = [Score(x[1].Current.Value,x[2].Current.Value,x[3].Current.Value,x[4].Current.Value).ObjectiveScore() for x in self.CanaryData] # check if orderedCanaryScores are both negative if CanaryScores[0] <0 or CanaryScores[1] <0: # We are in safety mode. Liquidate any positions and invest in the best safety symbol self.Log(f'Safety mode - {CanaryScores}') # Check that we are not already invested in the correct Safety symbol # If we are invested, return if self.Securities[bestSafety].Invested: return self.Liquidate() self.SetHoldings(orderedSafetyScores[0][0],1) return # Canary Symbol gives positive signal # We are in Growth Mode self.Log(f'Growth mode - {CanaryScores}') # Check each symbol we own to see if it is in the bestGrowth list. If not, Liquidate it. invested = [x.Symbol.Value for x in self.Portfolio.Values if x.Invested] for x in invested: if x not in bestGrowth: self.Liquidate(x) # Check each symbol in bestGrowth list to see if we own it. If not, then buy it. for symbol in bestGrowth: if not self.Securities[symbol].Invested: self.SetHoldings(symbol, 1/self.numberOfGrowth) class Score(object): def __init__(self,oneMonthPerformanceValue,threeMonthPerformanceValue,sixMonthPerformanceValue,twelveMonthPerformanceValue): self.oneMonthPerformance = oneMonthPerformanceValue self.threeMonthPerformance = threeMonthPerformanceValue self.sixMonthPerformance = sixMonthPerformanceValue self.twelveMonthPerformance = twelveMonthPerformanceValue def ObjectiveScore(self): weight1 = 12 weight2 = 4 weight3 = 2 return (weight1 * self.oneMonthPerformance) + (weight2 * self.threeMonthPerformance) + (weight3 * self.sixMonthPerformance) + self.twelveMonthPerformance class FRED(PythonQuandl): '''Custom quandl data type for setting customized value column name. Value column is used for the primary trading calculations and charting.''' def __init__(self): self.ValueColumnName = "Value"