Overall Statistics |
Total Trades 1733 Average Win 1.08% Average Loss -0.29% Compounding Annual Return 19.882% Drawdown 17.400% Expectancy 0.862 Net Profit 773.309% Sharpe Ratio 1.172 Probabilistic Sharpe Ratio 65.958% Loss Rate 61% Win Rate 39% Profit-Loss Ratio 3.72 Alpha 0.096 Beta 0.408 Annual Standard Deviation 0.121 Annual Variance 0.015 Information Ratio 0.217 Tracking Error 0.135 Treynor Ratio 0.347 Total Fees $14159.42 Estimated Strategy Capacity $36000.00 Lowest Capacity Asset FOR TYX3G2PC742T |
class WellDressedSkyBlueSardine(QCAlgorithm): def Initialize(self): self.SetStartDate(2010, 1, 1) # self.SetEndDate(2010, 6, 1) self.cap = 100000 self.SetCash(self.cap) self.SetBenchmark("SPY") self.rebalanceTime = datetime.min self.activeStocks = set() self.AddUniverse(self.CoarseFilter, self.FineFilter) self.UniverseSettings.Resolution = Resolution.Hour self.brokerage = BrokerageName.InteractiveBrokersBrokerage self.SetBrokerageModel(self.brokerage, AccountType.Margin) self.portfolioTargets = [] self.UniverseSettings.DataNormalizationMode=DataNormalizationMode.SplitAdjusted #how data goes into alg self.UniverseSettings.ExtendedMarketHours = False #Does not takes in account after hours data self.AddRiskManagement(MyRiskModel(.12)) self.SetAlpha(LongOnlyConstantAlphaCreationModel()) self.Settings.RebalancePortfolioOnInsightChanges = False; self.Settings.RebalancePortfolioOnSecurityChanges = False; self.MKT = self.AddEquity('SPY', Resolution.Daily).Symbol self.mkt = [] def CoarseFilter(self, coarse): if self.Time <= self.rebalanceTime: return self.Universe.Unchanged self.rebalanceTime = self.Time + timedelta(4) myuniverse = [x for x in coarse if x.Price > 5 and x.DollarVolume > 1000000] return [x.Symbol for x in myuniverse if x.Price > 5 and x.HasFundamentalData][:2000] def FineFilter(self, fine): security_filter = [x for x in fine if x.EarningReports.DilutedEPS.Value > .0 and x.ValuationRatios.PERatio < 15 and x.OperationRatios.RevenueGrowth.ThreeMonths > .05 and x.MarketCap > 100000000 and x.OperationRatios.ROA.ThreeMonths > .02 and x.OperationRatios.ROE.ThreeMonths > .03 and x.EarningRatios.DilutedEPSGrowth.ThreeMonths > .03 and x.OperationRatios.NetMargin.ThreeMonths > .1 and x.ValuationRatios.PSRatio < 1 and x.ValuationRatios.EVToEBITDA < 10 and x.ValuationRatios.EVtoRevenue < 1.5 ] sorting = sorted(security_filter, key = lambda x: x.ValuationRatios.PSRatio, reverse=False) self.Log(str([x.OperationRatios.RevenueGrowth.ThreeMonths for x in sorting[:100]])) self.Log(str([x.MarketCap for x in sorting[:100]])) self.Log(str([x.OperationRatios.ROE.ThreeMonths for x in sorting[:100]])) self.Log(str([x.OperationRatios.ROA.ThreeMonths for x in sorting[:100]])) self.Log(str([x.EarningRatios.DilutedEPSGrowth.ThreeMonths for x in sorting[:100]])) self.Log(str([x.OperationRatios.NetMargin.ThreeMonths for x in sorting[:100]])) self.Log(str([x.ValuationRatios.PSRatio for x in sorting[:100]])) self.Log(str([x.ValuationRatios.EVToEBITDA for x in sorting[:100]])) return [x.Symbol for x in sorting[:100]] def OnSecuritiesChanged(self, changes): for x in changes.RemovedSecurities: self.Liquidate(x.Symbol) if x.Symbol in self.activeStocks: self.activeStocks.remove(x.Symbol) for x in changes.AddedSecurities: self.activeStocks.add(x.Symbol) self.portfolioTargets = [PortfolioTarget(symbol, .8/(len(self.activeStocks))) for symbol in self.activeStocks] def OnData(self, data): if self.portfolioTargets == []: return for symbol in self.activeStocks: if symbol not in data: return self.SetHoldings(self.portfolioTargets) self.portfolioTargets = [] def OnEndOfDay(self): mkt_price = self.Securities[self.MKT].Close self.mkt.append(mkt_price) mkt_perf = self.mkt[-1] / self.mkt[0] * self.cap self.Plot('Strategy Equity', 'SPY', mkt_perf) class MyPortfolioModel(EqualWeightingPortfolioConstructionModel): def __init__(self): pass def CreateTargets(self, algorithm, insights): # Simple insight weighting PCM targets = [] for insight in insights: targ = PortfolioTarget(insight.Symbol, insight.Direction*insight.Weight) targets.append(targ) return targets class MyRiskModel(RiskManagementModel): def __init__(self, maxDrawdown=.12): self.maxDrawdown = maxDrawdown self.liquidatedSymbols = set() # Tracks symbols that have been liquidated self.currentTargets = [] # Tracks state of current targets def ManageRisk(self, algorithm, targets): # Reset trackers on new targets if (set(targets) != self.currentTargets) and len(targets)>0: algorithm.Log(f'New Targets. Quantity: {targets[0].Quantity}') self.liquidatedSymbols = set() self.currentTargets = set(targets) riskAdjustedTargets = [] for _ in algorithm.Securities: symbol = _.Key # Symbol object security = _.Value # Security object ticker = symbol.Value # String ticker symbolPnL = security.Holdings.UnrealizedProfitPercent # Current PnL #Liquidate if exceed drawdown if (symbolPnL < -self.maxDrawdown) or (ticker in self.liquidatedSymbols): riskAdjustedTargets.append(PortfolioTarget(symbol, 0)) if algorithm.Securities[symbol].Invested: self.liquidatedSymbols.add(ticker) algorithm.Log(f'Trailing stop loss triggered for {ticker}.') return riskAdjustedTargets class LongOnlyConstantAlphaCreationModel(AlphaModel): ''' Description: This Alpha model creates InsightDirection.Up (to go Long) for a duration of 1 day, every day for all active securities in our Universe Details: The important thing to understand here is the concept of Insight: - A prediction about the future of the security, indicating an expected Up, Down or Flat move - This prediction has an expiration time/date, meaning we think the insight holds for some amount of time - In the case of a constant long-only strategy, we are just updating every day the Up prediction for another extra day - In other words, every day we are making the conscious decision of staying invested in the security one more day ''' def __init__(self, resolution = Resolution.Daily): self.insightExpiry = Time.Multiply(Extensions.ToTimeSpan(resolution), 0.25) # insight duration self.insightDirection = InsightDirection.Up # insight direction self.securities = [] # list to store securities to consider def Update(self, algorithm, data): insights = [] # list to store the new insights to be created # loop through securities and generate insights for security in self.securities: # check if there's new data for the security or we're already invested # if there's no new data but we're invested, we keep updating the insight since we don't really need to place orders if data.ContainsKey(security.Symbol) or algorithm.Portfolio[security.Symbol].Invested: # append the insights list with the prediction for each symbol insights.append(Insight.Price(security.Symbol, self.insightExpiry, self.insightDirection)) else: algorithm.Log('excluding this security due to missing data: ' + str(security.Symbol.Value)) return insights def OnSecuritiesChanged(self, algorithm, changes): ''' Description: 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 ''' # add new securities for added in changes.AddedSecurities: self.securities.append(added) # remove securities for removed in changes.RemovedSecurities: if removed in self.securities: self.securities.remove(removed)