Overall Statistics |
Total Trades 3162 Average Win 0.12% Average Loss -0.02% Compounding Annual Return 14.226% Drawdown 17.600% Expectancy 5.714 Net Profit 364.239% Sharpe Ratio 1.569 Probabilistic Sharpe Ratio 96.006% Loss Rate 11% Win Rate 89% Profit-Loss Ratio 6.52 Alpha 0.094 Beta 0.187 Annual Standard Deviation 0.076 Annual Variance 0.006 Information Ratio -0.101 Tracking Error 0.144 Treynor Ratio 0.636 Total Fees $3162.50 Estimated Strategy Capacity $11000000.00 Lowest Capacity Asset TLT SGNKIKYGE9NP |
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. # 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 clr import AddReference AddReference("QuantConnect.Common") AddReference("QuantConnect.Algorithm.Framework") from QuantConnect.Algorithm.Framework.Alphas import * from Portfolio.EqualWeightingPortfolioConstructionModel import * class AccumulativeInsightPortfolioConstructionModel(EqualWeightingPortfolioConstructionModel): '''Provides an implementation of IPortfolioConstructionModel that allocates percent of account to each insight, defaulting to 3%. For insights of direction InsightDirection.Up, long targets are returned and for insights of direction InsightDirection.Down, short targets are returned. By default, no rebalancing shall be done. Rules: 1. On active Up insight, increase position size by percent 2. On active Down insight, decrease position size by percent 3. On active Flat insight, move by percent towards 0 4. On expired insight, and no other active insight, emits a 0 target''' def __init__(self, rebalance = None, portfolioBias = PortfolioBias.Long, percent = 0.04): '''Initialize a new instance of AccumulativeInsightPortfolioConstructionModel 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) percent: percent of portfolio to allocate to each position''' super().__init__(rebalance) self.portfolioBias = portfolioBias self.percent = abs(percent) self.sign = lambda x: -1 if x < 0 else (1 if x > 0 else 0) def DetermineTargetPercent(self, activeInsights): '''Will determine the target percent for each insight Args: activeInsights: The active insights to generate a target for''' percentPerSymbol = {} insights = sorted(self.InsightCollection.GetActiveInsights(self.currentUtcTime), key=lambda insight: insight.GeneratedTimeUtc) for insight in insights: targetPercent = 0 if insight.Symbol in percentPerSymbol: targetPercent = percentPerSymbol[insight.Symbol] if insight.Direction == InsightDirection.Flat: # We received a Flat # if adding or subtracting will push past 0, then make it 0 if abs(targetPercent) < self.percent: targetPercent = 0 else: # otherwise, we flatten by percent targetPercent += (-self.percent if targetPercent > 0 else self.percent) targetPercent += self.percent * insight.Direction # adjust to respect portfolio bias if self.portfolioBias != PortfolioBias.Long and self.sign(targetPercent) != self.portfolioBias: targetPercent = 0 percentPerSymbol[insight.Symbol] = targetPercent return dict((insight, percentPerSymbol[insight.Symbol]) for insight in activeInsights) def CreateTargets(self, algorithm, insights): '''Create portfolio targets from the specified insights Args: algorithm: The algorithm instance insights: The insights to create portfolio targets from Returns: An enumerable of portfolio targets to be sent to the execution model''' self.currentUtcTime = algorithm.UtcTime return super().CreateTargets(algorithm, insights)
from sklearn.ensemble import RandomForestRegressor from sklearn.model_selection import train_test_split import numpy as np from itertools import groupby class AlphaFiveUSTreasuries(QCAlgorithm): def Initialize(self): #1. Required: Five years of backtest history self.SetStartDate(2005, 1, 1) self.SetStartDate(2010, 1, 1) #2. Required: Alpha Streams Models: # self.SetBrokerageModel(BrokerageName.AlphaStreams) #3. Required: Significant AUM Capacity self.SetCash(25000) #4. Required: Benchmark to SPY self.AddEquity("SPY", Resolution.Daily) self.SetBenchmark("SPY") Benchmark = "QQQ" #self.SetPortfolioConstruction(AccumulativeInsightPortfolioConstructionModel()) self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel()) # self.SetExecution(TradeExecution())) #Market Indicators self.spy = "SPY" self.iwm = "IWM" self.mdy = "MDY" self.qqq = "QQQ" self.vix = "VIX" self.assets = ["QQQ","TLT"] #self.assets = ['QQQ', 'FDN', 'TLT', 'TLH'] self.symbols = {} self.portfolioValue = RollingWindow[Decimal](500) self.timeDelta = int(self.GetParameter("timeDelta")) self.SetWarmup(500) # Add Equity ------------------------------------------------ for i in range(len(self.assets)): self.symbols[self.assets[i]] = self.AddEquity(self.assets[i],Resolution.Minute).Symbol self.Schedule.On(self.DateRules.Every(DayOfWeek.Monday), self.TimeRules.AfterMarketOpen(Benchmark, 30), self.EveryDayAfterMarketOpen) # Stock Selector # self.AddUniverse(self.Coarse, self.Fine) # self.activelyTrading = [] # self.weight = 0 # self.numberOfSymbolsCoarse = 500 # self.exposureToSector = 2 self.lastMonth = -1 def Coarse(self, coarse): if self.Time.month == self.lastMonth: return Universe.Unchanged self.lastMonth = self.Time.month allCoarse = [x for x in coarse if x.HasFundamentalData and x.Price > 1 and x.Volume > 1] finalCoarse = sorted(allCoarse, key = lambda x: x.DollarVolume, reverse = True) return [x.Symbol for x in finalCoarse][:self.numberOfSymbolsCoarse] def Fine(self, fine): filteredSymbols = [] sortedBySector = [x for x in fine] for code, g in groupby(sortedBySector, lambda x: x.AssetClassification.MorningstarSectorCode): for x in sorted(g, key = lambda x: x.ValuationRatios.PERatio, reverse = True)[:self.exposureToSector]: filteredSymbols.append(x.Symbol) return filteredSymbols[:2] def EveryDayAfterMarketOpen(self): if not self.Portfolio.Invested: insights = [] for ticker, symbol in self.symbols.items(): insights.append( Insight.Price(symbol, timedelta(days=(int(self.GetParameter("timeDelta")))), InsightDirection.Up, 0.01, None, None, 1/len(self.symbols)) ) self.EmitInsights(insights) else: qb = self #============================== # Initialize instance of Random Forest Regressor regressor = RandomForestRegressor(n_estimators=100, min_samples_split=5, random_state = 1990) # Fetch history on our universe df = qb.History(qb.Securities.Keys, 500, Resolution.Hour) # Get train/test data returns = df.unstack(level=1).close.transpose().pct_change().dropna() X = returns y = [x for x in qb.portfolioValue][-X.shape[0]:] X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 1990) # Fit regressor regressor.fit(X_train, y_train) # Get long-only predictions weights = regressor.feature_importances_ symbols = returns.columns[np.where(weights)] selected = zip(symbols, weights) # ============================== insights = [] for symbol, weight in selected: insights.append( Insight.Price(symbol, timedelta(days=(int(self.GetParameter("timeDelta")))), InsightDirection.Up, 0.01, None, None, weight) ) self.EmitInsights(insights) def OnData(self, data): self.portfolioValue.Add(self.Portfolio.TotalPortfolioValue)
from clr import AddReference AddReference("System") AddReference("QuantConnect.Common") AddReference("QuantConnect.Algorithm") AddReference("QuantConnect.Algorithm.Framework") from QuantConnect import * from QuantConnect.Algorithm import * from QuantConnect.Algorithm.Framework import * from QuantConnect.Algorithm.Framework.Portfolio import PortfolioTarget from QuantConnect.Algorithm.Framework.Risk import RiskManagementModel class TrailingStopRiskManagementModel(RiskManagementModel): '''Provides an implementation of IRiskManagementModel that limits the maximum possible loss measured from the highest unrealized profit''' def __init__(self, maximumDrawdownPercent = 0.04): '''Initializes a new instance of the TrailingStopRiskManagementModel class Args: maximumDrawdownPercent: The maximum percentage drawdown allowed for algorithm portfolio compared with the highest unrealized profit, defaults to 5% drawdown''' self.maximumDrawdownPercent = -abs(maximumDrawdownPercent) self.trailingHighs = dict() self.lastDay = -1 self.percentGain = 0.005 def ManageRisk(self, algorithm, targets): '''Manages the algorithm's risk at each time step Args: algorithm: The algorithm instance targets: The current portfolio targets to be assessed for risk''' if algorithm.Time.day == self.lastDay: return [] self.lastDay = algorithm.Time.day riskAdjustedTargets = list() for kvp in algorithm.Securities: symbol = kvp.Key security = kvp.Value percentChange = algorithm.Securities[symbol].Holdings.UnrealizedProfitPercent / 0.01 # Add newly invested securities if symbol not in self.trailingHighs: self.trailingHighs[symbol] = security.Close # Set to average holding cost continue # Remove if not invested if not security.Invested and symbol in self.trailingHighs: try: self.trailingHighs.pop(symbol, None) except: continue continue if percentChange.is_integer() and percentChange > 0: self.trailingHighs[symbol] = security.Close # Check for new highs and update - set to tradebar high # if self.trailingHighs[symbol] < security.High: # self.trailingHighs[symbol] = security.High # continue # Check for securities past the drawdown limit securityHigh = self.trailingHighs[symbol] if securityHigh == 0: riskAdjustedTargets.append(PortfolioTarget(symbol, 0)) continue drawdown = (security.Low / securityHigh) - 1 if drawdown < self.maximumDrawdownPercent: # liquidate riskAdjustedTargets.append(PortfolioTarget(symbol, 0)) return riskAdjustedTargets
from clr import AddReference AddReference("System") AddReference("QuantConnect.Common") AddReference("QuantConnect.Indicators") AddReference("QuantConnect.Algorithm") AddReference("QuantConnect.Algorithm.Framework") from System import * from QuantConnect import * from QuantConnect.Indicators import * from QuantConnect.Data import * from QuantConnect.Data.Market import * from QuantConnect.Orders import * from QuantConnect.Algorithm import * from QuantConnect.Algorithm.Framework import * from QuantConnect.Algorithm.Framework.Execution import * from QuantConnect.Algorithm.Framework.Portfolio import * import numpy as np from datetime import datetime class VolumeWeightedAveragePriceExecutionModel(ExecutionModel): '''Execution model that submits orders while the current market price is more favorable that the current volume weighted average price.''' def __init__(self): '''Initializes a new instance of the VolumeWeightedAveragePriceExecutionModel class''' self.targetsCollection = PortfolioTargetCollection() self.symbolData = {} # Gets or sets the maximum order quantity as a percentage of the current bar's volume. # This defaults to 0.01m = 1%. For example, if the current bar's volume is 100, # then the maximum order size would equal 1 share. self.MaximumOrderQuantityPercentVolume = 0.02 def Execute(self, algorithm, targets): '''Executes market orders if the standard deviation of price is more than the configured number of deviations in the favorable direction. Args: algorithm: The algorithm instance targets: The portfolio targets''' # update the complete set of portfolio targets with the new targets self.targetsCollection.AddRange(targets) # for performance we check count value, OrderByMarginImpact and ClearFulfilled are expensive to call if self.targetsCollection.Count > 0: for target in self.targetsCollection.OrderByMarginImpact(algorithm): symbol = target.Symbol # calculate remaining quantity to be ordered unorderedQuantity = OrderSizing.GetUnorderedQuantity(algorithm, target) # fetch our symbol data containing our VWAP indicator data = self.symbolData.get(symbol, None) if data is None: return # check order entry conditions if self.PriceIsFavorable(data, unorderedQuantity): # adjust order size to respect maximum order size based on a percentage of current volume orderSize = OrderSizing.GetOrderSizeForPercentVolume(data.Security, self.MaximumOrderQuantityPercentVolume, unorderedQuantity) if orderSize != 0: algorithm.MarketOrder(symbol, orderSize) self.targetsCollection.ClearFulfilled(algorithm) def OnSecuritiesChanged(self, algorithm, changes): '''Event fired each time the we add/remove securities from the data feed Args: algorithm: The algorithm instance that experienced the change in securities changes: The security additions and removals from the algorithm''' for removed in changes.RemovedSecurities: # clean up removed security data if removed.Symbol in self.symbolData: if self.IsSafeToRemove(algorithm, removed.Symbol): data = self.symbolData.pop(removed.Symbol) algorithm.SubscriptionManager.RemoveConsolidator(removed.Symbol, data.Consolidator) for added in changes.AddedSecurities: if added.Symbol not in self.symbolData: self.symbolData[added.Symbol] = SymbolData(algorithm, added) def PriceIsFavorable(self, data, unorderedQuantity): '''Determines if the current price is more than the configured number of standard deviations away from the mean in the favorable direction.''' if unorderedQuantity > 0: if data.Security.BidPrice < data.VWAP: return True else: if data.Security.AskPrice > data.VWAP: return True return False def IsSafeToRemove(self, algorithm, symbol): '''Determines if it's safe to remove the associated symbol data''' # confirm the security isn't currently a member of any universe return not any([kvp.Value.ContainsMember(symbol) for kvp in algorithm.UniverseManager]) class SymbolData: def __init__(self, algorithm, security): self.Security = security self.Consolidator = algorithm.ResolveConsolidator(security.Symbol, security.Resolution) name = algorithm.CreateIndicatorName(security.Symbol, "VWAP", security.Resolution) self.vwap = IntradayVwap(name) algorithm.RegisterIndicator(security.Symbol, self.vwap, self.Consolidator) @property def VWAP(self): return self.vwap.Value class IntradayVwap: '''Defines the canonical intraday VWAP indicator''' def __init__(self, name): self.Name = name self.Value = 0.0 self.lastDate = datetime.min self.sumOfVolume = 0.0 self.sumOfPriceTimesVolume = 0.0 @property def IsReady(self): return self.sumOfVolume > 0.0 def Update(self, input): '''Computes the new VWAP''' success, volume, averagePrice = self.GetVolumeAndAveragePrice(input) if not success: return self.IsReady # reset vwap on daily boundaries if self.lastDate != input.EndTime.date(): self.sumOfVolume = 0.0 self.sumOfPriceTimesVolume = 0.0 self.lastDate = input.EndTime.date() # running totals for Σ PiVi / Σ Vi self.sumOfVolume += volume self.sumOfPriceTimesVolume += averagePrice * volume if self.sumOfVolume == 0.0: # if we have no trade volume then use the current price as VWAP self.Value = input.Value return self.IsReady self.Value = self.sumOfPriceTimesVolume / self.sumOfVolume return self.IsReady def GetVolumeAndAveragePrice(self, input): '''Determines the volume and price to be used for the current input in the VWAP computation''' if type(input) is Tick: if input.TickType == TickType.Trade: return True, float(input.Quantity), float(input.LastPrice) if type(input) is TradeBar: if not input.IsFillForward: averagePrice = float(input.High + input.Low + input.Close) / 3 return True, float(input.Volume), averagePrice return False, 0.0, 0.0