Overall Statistics |
Total Trades 102439 Average Win 0.02% Average Loss -0.01% Compounding Annual Return 0.504% Drawdown 12.900% Expectancy 0.013 Net Profit 5.608% Sharpe Ratio 0.105 Probabilistic Sharpe Ratio 0.019% Loss Rate 67% Win Rate 33% Profit-Loss Ratio 2.04 Alpha 0.002 Beta 0.146 Annual Standard Deviation 0.042 Annual Variance 0.002 Information Ratio -0.081 Tracking Error 0.152 Treynor Ratio 0.03 Total Fees $381500.92 Estimated Strategy Capacity $9400000.00 Lowest Capacity Asset VMW TV48B2UVK8RP |
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.https://www.quantconnect.com/project/5624489#code-tab-EqualWeightingClone_py # Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from AlgorithmImports import * class PortfolioModelJGG(PortfolioConstructionModel): '''Provides an implementation of IPortfolioConstructionModel that gives equal weighting to all securities. The target percent holdings of each security is 1/N where N is the number of securities. For insights of direction InsightDirection.Up, long targets are returned and for insights of direction InsightDirection.Down, short targets are returned.''' def __init__(self, rebalance = Resolution.Daily, portfolioBias = PortfolioBias.LongShort): '''Initialize a new instance of EqualWeightingPortfolioConstructionModel Args: rebalance: Rebalancing parameter. If it is a timedelta, date rules or Resolution, it will be converted into a function. If None will be ignored. The function returns the next expected rebalance time for a given algorithm UTC DateTime. The function returns null if unknown, in which case the function will be called again in the next loop. Returning current time will trigger rebalance. portfolioBias: Specifies the bias of the portfolio (Short, Long/Short, Long)''' self.portfolioBias = portfolioBias self.activeInsights = [] # If the argument is an instance of Resolution or Timedelta # Redefine rebalancingFunc rebalancingFunc = rebalance if isinstance(rebalance, int): rebalance = Extensions.ToTimeSpan(rebalance) if isinstance(rebalance, timedelta): rebalancingFunc = lambda dt: dt + rebalance if rebalancingFunc: self.SetRebalancingFunc(rebalancingFunc) def CreateTargets(self, algorithm, newInsights): '''Will determine the target percent for each insight Args: activeInsights: The active insights to generate a target for''' timeDateString = format(algorithm.Time) timeString = timeDateString.split() maxTargets = {} targets = [] if timeString[1] == "10:00:00": self.activeInsights.extend(newInsights) equity=algorithm.Portfolio.TotalPortfolioValue percentRisk = 0.0006*100 dollarRisk = equity*percentRisk/100 #try: for insight in self.activeInsights: if insight.Symbol not in maxTargets: maxTargets[insight.Symbol] = 0 volatilityRisk = insight.Magnitude/(1 + insight.Magnitude) biasMultiplier = 1 if self.RespectPortfolioBias(insight) else 0 if insight.ReferenceValue > 0 and volatilityRisk > 0: # The block of code below only works for long positions! maxTargets[insight.Symbol] = max(maxTargets[insight.Symbol],(algorithm.UtcTime<insight.CloseTimeUtc)*biasMultiplier*dollarRisk/volatilityRisk/insight.ReferenceValue) #else: #algorithm.Log('insight.ReferenceValue = 0 for ' + str(insight.Symbol)) if algorithm.UtcTime>insight.CloseTimeUtc: priorLength=len(self.activeInsights) self.activeInsights.remove(insight) #lgorithm.Debug(str(priorLength)+'-->'+str(len(self.activeInsights))) for symbol in maxTargets: targets.append(PortfolioTarget(symbol,maxTargets[symbol])) #algorithm.Log(str(symbol)+' '+str(maxTargets[symbol])) #except: #algorithm.Debug('Portfolio model error') #for '+str(insight.Symbol)) #algorithm.Debug(str(len(self.activeInsights))+' '+str(len(targets))) return targets def RespectPortfolioBias(self, insight): '''Method that will determine if a given insight respects the portfolio bias Args: insight: The insight to create a target for ''' return self.portfolioBias == PortfolioBias.LongShort or insight.Direction == self.portfolioBias
from AlgorithmImports import * class RsiAlphaModelJGG(AlphaModel): def __init__(self, period = 14, resolution = Resolution.Daily): self.period = period self.resolution = resolution self.symbolDataBySymbol = {} self.openWindows = {} self.highWindows = {} self.lowWindows = {} self.closeWindows = {} self.rsiWindows = {} resolutionString = Extensions.GetEnumString(resolution, Resolution) self.Name = '{}({},{})'.format(self.__class__.__name__, period, resolutionString) def Update(self, algorithm, data): self.rsiOversold = float(algorithm.GetParameter("rsiOversold")) self.rsiOverbought = float(algorithm.GetParameter("rsiOverbought")) self.minHiccup = float(algorithm.GetParameter("minHiccup")) self.periodLength = int(algorithm.GetParameter("periodLength")) #algorithm.Schedule.On(algorithm.DateRules.On(1998,3,3), algorithm.TimeRules.At(9,30),algorithm.Debug(" rsiOversold="+str(self.rsiOversold)))#+" rsiOverbought="+str(self.rsiOverbought)+" minHiccup="+str(self.minHiccup)+" periodLength="+str(self.periodLength))) timeDateString = format(algorithm.Time) timeString = timeDateString.split() if timeDateString == "1998-03-02 10:00:00": algorithm.Debug(" rsiOversold="+str(self.rsiOversold)+" rsiOverbought="+str(self.rsiOverbought)+" minHiccup="+str(self.minHiccup)+" periodLength="+str(self.periodLength)) insights = [] for symbol, symbolData in self.symbolDataBySymbol.items(): if data.ContainsKey(symbol) and data[symbol] is not None and timeString[1] == "16:00:00": self.openWindows[symbol].Add(data[symbol].Open) self.highWindows[symbol].Add(data[symbol].High) self.lowWindows[symbol].Add(data[symbol].Low) self.closeWindows[symbol].Add(data[symbol].Close) rsi = symbolData.RSI if rsi.IsReady and timeString[1] == "10:00:00": try: self.rsiWindows[symbol].Add(rsi.Current.Value) #self.rsiHiccup = self.rsiWindows[symbol][0] - self.rsiWindows[symbol][1] #if self.rsiWindows[symbol][1] < self.rsiOversold and self.rsiHiccup >= self.minHiccup: if self.rsiWindows[symbol][0] < self.rsiOversold and self.rsiWindows[symbol][0] > self.rsiOversold - 5: for periodIter in [self.periodLength]: highList = list(self.highWindows[symbol]) lowList = list(self.lowWindows[symbol]) recentMax = max(highList[0:periodIter-1]) recentMin = min(lowList[0:periodIter-1]) Mag = (recentMax - recentMin)/recentMin self.insightPeriod = Time.Multiply(Extensions.ToTimeSpan(self.resolution), periodIter) insights.append(Insight.Price(symbol, self.insightPeriod, InsightDirection.Up,Mag,None,None,None)) highList = [] lowList = [] #if self.rsiWindows[symbol][1] > self.rsiOverbought and self.rsiHiccup <= -1*self.minHiccup: # for periodIter in [self.periodLength]: # highList = list(self.highWindows[symbol]) # lowList = list(self.lowWindows[symbol]) # recentMax = max(highList[0:periodIter-1]) # recentMin = min(lowList[0:periodIter-1]) # Mag = (recentMax - recentMin)/recentMin # #Mag = (recentMin - recentMax)/recentMax #self.insightPeriod = Time.Multiply(Extensions.ToTimeSpan(self.resolution), periodIter) #insights.append(Insight.Price(symbol, self.insightPeriod, InsightDirection.Up,Mag,None,None,None)) ##insights.append(Insight.Price(symbol, self.insightPeriod, InsightDirection.Down,Mag,None,None,None)) #highList = [] #lowList = [] except: algorithm.Log('Alpha model error for '+str(symbol)+': '+ timeDateString) return insights def OnSecuritiesChanged(self, algorithm, changes): # clean up data for removed securities symbols = [ x.Symbol for x in changes.RemovedSecurities ] if len(symbols) > 0: for subscription in algorithm.SubscriptionManager.Subscriptions: if subscription.Symbol in symbols: self.symbolDataBySymbol.pop(subscription.Symbol, None) subscription.Consolidators.Clear() # initialize data for added securities addedSymbols = [ x.Symbol for x in changes.AddedSecurities if x.Symbol not in self.symbolDataBySymbol] if len(addedSymbols) == 0: return history = algorithm.History(addedSymbols, self.period + 20, self.resolution) for symbol in addedSymbols: #algorithm.Securities[symbol].FeeModel = ConstantFeeModel(0) #algorithm.Securities[symbol].SetSlippageModel(ConstantSlippageModel(0)) rsi = algorithm.RSI(symbol, self.period, MovingAverageType.Wilders, self.resolution) self.rsiWindows[symbol] = RollingWindow[float](20) self.openWindows[symbol] = RollingWindow[float](self.period) self.highWindows[symbol] = RollingWindow[float](self.period) self.lowWindows[symbol] = RollingWindow[float](self.period) self.closeWindows[symbol] = RollingWindow[float](self.period) for tuple in history.loc[symbol].itertuples(): self.openWindows[symbol].Add(tuple.open) self.highWindows[symbol].Add(tuple.high) self.lowWindows[symbol].Add(tuple.low) self.closeWindows[symbol].Add(tuple.close) rsi.Update(tuple.Index, tuple.close) if rsi.IsReady: self.rsiWindows[symbol].Add(rsi.Current.Value) self.symbolDataBySymbol[symbol] = SymbolData(symbol, rsi) #def printParameters(self): #algorithm.Debug(" rsiOversold="+str(self.rsiOversold)+" rsiOverbought="+str(self.rsiOverbought)+" minHiccup="+str(self.minHiccups)+" periodLength="+str(self.periodLength)) class SymbolData: def __init__(self, symbol, rsi): self.Symbol = symbol self.RSI = rsi
from Execution.ImmediateExecutionModel import ImmediateExecutionModel from Execution.NullExecutionModel import NullExecutionModel from Portfolio.EqualWeightingPortfolioConstructionModel import EqualWeightingPortfolioConstructionModel from Portfolio.NullPortfolioConstructionModel import NullPortfolioConstructionModel from Risk.MaximumDrawdownPercentPerSecurity import MaximumDrawdownPercentPerSecurity from Selection.QC500UniverseSelectionModel import QC500UniverseSelectionModel from RsiAlphaModelJGG import RsiAlphaModelJGG from PortfolioModelJGG import PortfolioModelJGG from AlgorithmImports import * class SimpleRSITestQC500Universe(QCAlgorithm): def Initialize(self): self.SetStartDate(1998,3,1) # Set Start Date self.SetEndDate(2008,12,31) # Set End Date self.SetCash(10e6/6*2/1.5) # Set Strategy Cash self.SetBenchmark("SPY") self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage) self.SetExecution(ImmediateExecutionModel()) self.SetPortfolioConstruction(PortfolioModelJGG(Time.Multiply(Extensions.ToTimeSpan(Resolution.Hour), 1))) self.SetRiskManagement(NullRiskManagementModel()) #symbols = [ Symbol.Create("CUM", SecurityType.Equity, Market.USA) ] #self.SetUniverseSelection(ManualUniverseSelectionModel(symbols)) self.UniverseSettings.Resolution = Resolution.Hour self.AddUniverse(self.Universe.QC500) self.AddAlpha(RsiAlphaModelJGG(resolution = Resolution.Hour))