Overall Statistics |
Total Trades 6139 Average Win 0.13% Average Loss -0.06% Compounding Annual Return 9.831% Drawdown 54.000% Expectancy 0.285 Net Profit 30.461% Sharpe Ratio 0.367 Probabilistic Sharpe Ratio 4.551% Loss Rate 58% Win Rate 42% Profit-Loss Ratio 2.07 Alpha 0.283 Beta -0.012 Annual Standard Deviation 0.768 Annual Variance 0.59 Information Ratio 0.245 Tracking Error 0.777 Treynor Ratio -23.386 Total Fees $6378.08 |
from Execution.ImmediateExecutionModel import ImmediateExecutionModel from Portfolio.EqualWeightingPortfolioConstructionModel import EqualWeightingPortfolioConstructionModel class NetNet(QCAlgorithm): def Initialize(self): self.SetStartDate(2015, 1, 1) # Set Start Date self.SetEndDate(2017, 10, 31) self.SetCash(100000) # Set Strategy Cash self.SetUniverseSelection(FineFundamentalUniverseSelectionModel(self.CoarseSelectionFunction, self.FineSelectionFunction, None, None)) self.UniverseSettings.Resolution = Resolution.Daily self.SetAlpha(ConstantAlphaModelSellEOY(InsightType.Price, InsightDirection.Up, timedelta(days=365))) self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel(lambda time: None)) self.SetExecution(ImmediateExecutionModel()) self.SetBenchmark("SPY") self.year = -1 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 not self.Portfolio.Invested: # self.SetHoldings("SPY", 1) # on 15 Jan, filter for securities with fundamental data def CoarseSelectionFunction(self, coarse): if self.Time.year == self.year: return Universe.Unchanged self.year = self.Time.year return [ x.Symbol for x in coarse if x.HasFundamentalData ][:1000] # on 15 Jan, filter first for securities with shares and then filter a second time for net net stocks def FineSelectionFunction(self, fine): filtered = [ x for x in fine if ((x.FinancialStatements.BalanceSheet.CurrentAssets.ThreeMonths - x.FinancialStatements.BalanceSheet.TotalLiabilitiesAsReported.ThreeMonths - x.FinancialStatements.BalanceSheet.PreferredStock.ThreeMonths) > 0) and (x.FinancialStatements.BalanceSheet.OrdinarySharesNumber.ThreeMonths > 0) ] # filtered = [ x for x in filtered if (x.FinancialStatements.BalanceSheet.OrdinarySharesNumber.ThreeMonths > 0) ] # filtered = [ x for x in filtered if (x.FinancialStatements.BalanceSheet.PreferredStock.ThreeMonths > 0) ] filtered = [ x.Symbol for x in filtered if (x.Price / ((x.FinancialStatements.BalanceSheet.CurrentAssets.ThreeMonths - x.FinancialStatements.BalanceSheet.TotalLiabilitiesAsReported.ThreeMonths - x.FinancialStatements.BalanceSheet.PreferredStock.ThreeMonths) / x.FinancialStatements.BalanceSheet.OrdinarySharesNumber.ThreeMonths)) <= 0.66 ] # for x in filtered: # self.Log("Symbol: " + str(x.Symbol)) # self.Log("Name: " + x.CompanyReference.LegalName) # self.Log(str(self.Time.month) + str(self.Time.day) + str(self.Time.year)) # self.Log("Price: " + str(x.Price)) # self.Log("Current Assets: " + str(x.FinancialStatements.BalanceSheet.CurrentAssets.ThreeMonths)) # self.Log("Total Liabilities: " + str(x.FinancialStatements.BalanceSheet.TotalLiabilitiesAsReported.ThreeMonths)) # self.Log("Preferred Stock: " + str(x.FinancialStatements.BalanceSheet.PreferredStock.ThreeMonths)) # self.Log("Shares: " + str(x.FinancialStatements.BalanceSheet.OrdinarySharesNumber.ThreeMonths)) # filtered = [ x.Symbol for x in filtered ] return filtered[:100] class ConstantAlphaModelSellEOY(AlphaModel): ''' Provides an implementation of IAlphaModel that always returns the same insight for each security''' def __init__(self, type, direction, period, magnitude = None, confidence = None): '''Initializes a new instance of the ConstantAlphaModel class Args: type: The type of insight direction: The direction of the insight period: The period over which the insight with come to fruition magnitude: The predicted change in magnitude as a +- percentage confidence: The confidence in the insight''' self.type = type self.direction = direction self.period = period self.magnitude = magnitude self.confidence = confidence self.securities = [] typeString = Extensions.GetEnumString(type, InsightType) directionString = Extensions.GetEnumString(direction, InsightDirection) self.Name = '{}({},{},{}'.format(self.__class__.__name__, typeString, directionString, strfdelta(period)) if magnitude is not None: self.Name += ',{}'.format(magnitude) if confidence is not None: self.Name += ',{}'.format(confidence) self.Name += ')' def Update(self, algorithm, data): ''' Creates a constant insight for each security as specified via the constructor Args: algorithm: The algorithm instance data: The new data available Returns: The new insights generated''' insights = [] for security in self.securities: # security price could be zero until we get the first data point. e.g. this could happen # when adding both forex and equities, we will first get a forex data point if security.Price != 0: if algorithm.Time.month == 12 and algorithm.Time.day > 20: insights.append(Insight(security.Symbol, self.period, self.type, InsightDirection.Flat, self.magnitude, self.confidence)) elif not algorithm.Securities[security.Symbol].Invested: insights.append(Insight(security.Symbol, self.period, self.type, self.direction, self.magnitude, self.confidence)) return insights 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 added in changes.AddedSecurities: self.securities.append(added) # this will allow the insight to be re-sent when the security re-joins the universe for removed in changes.RemovedSecurities: if removed in self.securities: self.securities.remove(removed) def strfdelta(tdelta): d = tdelta.days h, rem = divmod(tdelta.seconds, 3600) m, s = divmod(rem, 60) return "{}.{:02d}:{:02d}:{:02d}".format(d,h,m,s)