Overall Statistics |
Total Trades 0 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Net Profit 0% Sharpe Ratio 0 Probabilistic Sharpe Ratio 0% Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio 0 Tracking Error 0 Treynor Ratio 0 Total Fees $0.00 Estimated Strategy Capacity $0 Lowest Capacity Asset |
from AlgorithmImports import * from datetime import timedelta class Alpha(AlphaModel): '''Alpha - Determine equities we should trade. This is a warping of the Alpha model purpose, but we can get the AroonOscillator to work in this module. Insights are evaluated every week, but this method is called every day. The indicator is likewise updated every day. ''' def __init__(self, config): self.config = config self.symbolDataBySymbol = {} def Update(self, algorithm, data): ''' Update - Scan symbol data to calculate Aroon Score Called every day. ''' # List of Insights to emit. # Non-null insights are only emitted on selection day. insights = [] # Update Aroon Score for all equities. for s, sd in self.symbolDataBySymbol.items(): if data.Bars.ContainsKey(sd.symbol): sd.Update(data.Bars[sd.symbol]) # Check for selection day. if self.config.selectionDay == algorithm.Time.weekday(): # Sort all the equities by Aroon Score. sortedByAroon = sorted(self.symbolDataBySymbol.keys(), key=lambda s: self.symbolDataBySymbol[s].aroonScore, reverse=True) # Trim the universe to maxUniverse, if necessary. universe = sortedByAroon[:self.config.maxUniverse] if len(sortedByAroon) > self.config.maxUniverse else sortedByAroon # Emit an insight for the qualifying entities in the universe. for s in universe: if self.symbolDataBySymbol[s].aroonScore > 0: # Aroon Score must be greater than zero. insights.append(Insight.Price(s, timedelta(days=1), InsightDirection.Up)) # Reset the Aroon Score for all equities. for s, sd in self.symbolDataBySymbol.items(): sd.Reset() return insights def OnSecuritiesChanged(self, algorithm, changes): for added in changes.AddedSecurities: symbol = self.symbolDataBySymbol.get(added.Symbol) if symbol is None: # algorithm.Debug("Adding ticker {}".format(added.Symbol.Value)) self.symbolDataBySymbol[added.Symbol] = SymbolData(self.config, algorithm, added.Symbol) else: # algorithm.Debug("Resetting ticker {}".format(symbol.Value)) symbol.aroon.Reset() for removed in changes.RemovedSecurities: # algorithm.Debug("Removing ticker {}".format(removed.Symbol.Value)) self.symbolDataBySymbol.pop(removed.Symbol, None) class SymbolData: ''' Indicator for one symbol of our universe. The indicator is updated and warmed-up manually. ''' def __init__(self, config, algorithm, symbol): self.config = config self.symbol = symbol self.aroonScore = 0 # Create Aroon Oscillator indicator. self.aroon = AroonOscillator(self.config.aroonPeriod, self.config.aroonPeriod) # Warm up Aroon Oscillator with history data reaching back from now. daysAgo = algorithm.Time - timedelta(days=(self.config.aroonPeriod*2)) now = algorithm.Time history = algorithm.History([self.symbol], daysAgo, now, Resolution.Daily) for time, row in history.loc[self.symbol].iterrows(): tradebar = self.tradebarFromRow(time, row) self.aroon.Update(tradebar) @property def IsReady(self): ''' The symbol data is ready when the AroonOscillator indicator is ready, which means we have completed warm up. ''' return self.aroon.IsReady def tradebarFromRow(self, time, row): ''' Convert a history row to a tradebar ''' tradebar = TradeBar() tradebar.EndTime=time tradebar.Close=Decimal(row["close"]) tradebar.High=Decimal(row["high"]) tradebar.Low=Decimal(row["low"]) tradebar.Open=Decimal(row["open"]) tradebar.Volume=Decimal(row["volume"]) return tradebar def Update(self, bar): self.aroon.Update(bar) if self.IsReady: if self.aroon.Current.Value >= self.config.aroonThreshold: self.aroonScore += 1 elif self.aroon.Current.Value <= -self.config.aroonThreshold: self.aroonScore += 1 def Reset(self): self.aroonScore = 0
# # Portfolio Construction # from clr import AddReference AddReference("QuantConnect.Common") AddReference("QuantConnect.Algorithm.Framework") from QuantConnect import Resolution, Extensions from QuantConnect.Algorithm.Framework.Alphas import * from QuantConnect.Algorithm.Framework.Portfolio import * class PortfolioConstruction(PortfolioConstructionModel): ''' PortfolioConstruction - Emit log messages with the desired universe of equities based on the insights received. ''' def __init__(self, config): self.config = config def CreateTargets(self, algorithm, insights): ''' CreateTargets Each insight constitutes a tradable equity in our universe. Emit a log message for each equity. ''' targets = [] for insight in insights: algorithm.Log("Equity {}".format(insight.Symbol.Value)) return targets
from datetime import datetime, timedelta from QuantConnect.Data.UniverseSelection import * from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel class UniverseSelection(FundamentalUniverseSelectionModel): '''Select a new universe of equities''' def __init__(self, config, filterFineData=True, universeSettings=None): super().__init__(filterFineData, universeSettings) self.config = config def SelectCoarse(self, algorithm, coarse): '''Initial universe selection by looking for tickers with fundamental data, and then testing for desirable qualities. The resulting selection is sorted for price to enhance leverage. ''' # Only run on the selected day at midnight. # Otherwise, the universe has not changed. if self.config.selectionDay != algorithm.Time.weekday(): return Universe.Unchanged algorithm.Debug("SelectCoarse: start " + str(algorithm.Time.strftime("%Y-%m-%d %H:%M:%S"))) # Must have fundamental data. # Must be an equity. # Must be in a US market. # Equity price must be above the minimum. # Equity market volume must be above the minimum. # Sort for price, because price movements for a low priced equity # offer greater leverage over more expensive equities. sortedByPrice = sorted([x for x in coarse if x.HasFundamentalData and x.Symbol.SecurityType == SecurityType.Equity and x.Symbol.ID.Market == Market.USA and x.AdjustedPrice >= self.config.minPrice and x.DollarVolume >= self.config.minVolume], key=lambda x: x.Price) universe = [x.Symbol for x in sortedByPrice] algorithm.Debug("SelectCoarse: universe length: " + str(len(universe))) #if len(universe) == 0: # return Universe.Unchanged return universe def SelectFine(self, algorithm, fine): '''Refine universe selection by ensuring equities are at least a configured time past their IPO. ''' algorithm.Debug("SelectFine: start at {}".format(algorithm.Time.strftime("%Y-%m-%d %H:%M:%S"))) universe = [] for f in fine: # Equity IPO must have happened some time ago. if int((algorithm.Time - f.SecurityReference.IPODate).days) < self.config.minDaysSinceIPO: continue universe.append(f.Symbol) algorithm.Debug("SelectFine: universe length {}: ".format(len(universe))) if len(universe) == 0: return Universe.Unchanged # There is a new universe return universe
from datetime import datetime, timedelta from QuantConnect.Data.UniverseSelection import * from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel from config import Config from universe import UniverseSelection from alpha import Alpha from portfolio import PortfolioConstruction class AroonSieve(QCAlgorithm): ''' AroonSieve Find a universe of equities which are definitely moving up or moving down according to the Aroon indicator. We speculate that these equities will do well in an Opening Range Breakout algorithm. The universe is written to a log file, suitable for further processing with an aim to support upload or local backtesting. ''' def Initialize(self): # Configuration parameters controlling this algorithm self.config = Config() # Backtesting self.SetStartDate(2021, 6, 1) # Set backtest Start Date self.SetEndDate(2021, 8, 30) # Set backtest End Date self.SetCash(10000) # Set backtest Strategy Cash # Brokerage self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin) # Universe Construction # Discover prelimary universe of tradable equities. self.UniverseSettings.Resolution = Resolution.Daily self.AddUniverseSelection(UniverseSelection(self.config)) self.SetWarmup(self.config.aroonPeriod) # Alpha Model # Refine tradable universe by Aroon Score. self.SetAlpha(Alpha(self.config)) # Portfolio Construction # Log tradable universe. self.SetPortfolioConstruction(PortfolioConstruction(self.config))
# Since QuantConnect doesn't support config files, let's do this kludge. class Config(): def __init__(self): # # Coarse Selection Parameters # # Saturday night at midnight self.selectionDay = 4 # Minimum price self.minPrice = 1.00 # Minimum dollar volume # 10 million dollars a day self.minVolume = 1e7 # # Fine Selection Parameters # # Minimum days since IPO self.minDaysSinceIPO = 60 # Maximum size of the universe self.maxUniverse = 20 # Aroon Oscillator period self.aroonPeriod = 25 # Threshold for up and down trends self.aroonThreshold = 90