Overall Statistics |
Total Trades 5427 Average Win 0.12% Average Loss -0.05% Compounding Annual Return 11.580% Drawdown 11.400% Expectancy 0.061 Net Profit 9.258% Sharpe Ratio 0.747 Probabilistic Sharpe Ratio 39.957% Loss Rate 68% Win Rate 32% Profit-Loss Ratio 2.29 Alpha 0.122 Beta -0.119 Annual Standard Deviation 0.131 Annual Variance 0.017 Information Ratio -0.532 Tracking Error 0.189 Treynor Ratio -0.825 Total Fees $24453.80 |
from Execution.StandardDeviationExecutionModel import StandardDeviationExecutionModel from Portfolio.MeanVarianceOptimizationPortfolioConstructionModel import MeanVarianceOptimizationPortfolioConstructionModel from clr import AddReference AddReference("System") AddReference("QuantConnect.Algorithm") AddReference("QuantConnect.Algorithm.Framework") AddReference("QuantConnect.Common") AddReference("QuantConnect.Indicators") 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 from datetime import * import numpy as np import pandas as pd maximumDrawdownPercent = float(0.03) profitTargetPercent = float(0.01) executionReferencePeriod = int(60) deviations = int(2) resolution = Resolution.Minute zero = int(0) bufferBetweenOrders = int(60) #in universe resolution slices stopMarketTicket = None class CommunityTrailingStop(QCAlgorithm): def Initialize(self): stockPlot_1 = Chart('Price Vs. Stop') stockPlot_2 = Chart('Research') stockPlot_3 = Chart('Research 2') self.SetStartDate(2019, 1, 1) # Set Start Date self.SetCash(1000000) # Set Strategy Cash self.UniverseSettings.Resolution = resolution #self.SetExecution(StandardDeviationExecutionModel(executionReferencePeriod, deviations, resolution)) #self.SetPortfolioConstruction(MeanVarianceOptimizationPortfolioConstructionModel()) self.__numberOfSymbols = int(1000) self.__numberOfSymbolsFine = int(25) self.SetUniverseSelection(FineFundamentalUniverseSelectionModel(self.CoarseSelectionFunction, self.FineSelectionFunction, None, None)) self.RiskManagementDict = {} self.maximumDictionarySize = self.__numberOfSymbolsFine self.equalWeight = round(1/self.__numberOfSymbolsFine,2) self.dayEndPortfolioValue = self.Portfolio.TotalPortfolioValue self.changes = None def OnData(self, data): for Symbol in self.RiskManagementDict: if not data.ContainsKey(Symbol) or data[Symbol] is None: return if self.RiskManagementDict[Symbol].timeBuffer != zero: self.RiskManagementDict[Symbol].updateBuffer() continue self.TrailingStop(data[Symbol], Symbol) if not self.Portfolio[Symbol].Invested and self.RiskManagementDict[Symbol].timeBuffer == zero and self.RiskManagementDict[Symbol].continueTrading: self.SetHoldings(Symbol, self.equalWeight) def CoarseSelectionFunction(self, coarse): preScreen = [x for x in coarse if (x.HasFundamentalData) and (float(x.AdjustedPrice) > int(5))] sortedByDollarVolume = sorted(preScreen, key=lambda x: x.DollarVolume, reverse=True) # return the symbol objects of the top entries from our sorted collection return [ x.Symbol for x in sortedByDollarVolume[:self.__numberOfSymbols] ] def FineSelectionFunction(self, fine): fine = [x for x in fine if (float(x.FinancialStatements.BalanceSheet.CurrentAssets.Value) > zero) and (float(x.EarningReports.BasicAverageShares.Value) > zero) and (float(x.FinancialStatements.BalanceSheet.CurrentLiabilities.Value) > zero) and (float(x.FinancialStatements.BalanceSheet.TotalNonCurrentLiabilitiesNetMinorityInterest.Value) > zero) and (x.CompanyReference.IndustryTemplateCode!="B") and (x.CompanyReference.IndustryTemplateCode!="I")] for i in fine: #calculates the net current asset value per share total_liabilities = float(i.FinancialStatements.BalanceSheet.CurrentLiabilities.Value)+float(i.FinancialStatements.BalanceSheet.TotalNonCurrentLiabilitiesNetMinorityInterest.Value) i.ncav = (float(i.FinancialStatements.BalanceSheet.CurrentAssets.Value) - total_liabilities)/float(i.EarningReports.BasicAverageShares.Value) #keeps all symbols that have a NCAV/MV higher than 1.5 fineScreen = [i for i in fine if (i.ncav > float(1.5))] sortedByPeRatio = sorted(fineScreen, key=lambda x: x.ValuationRatios.PERatio, reverse=True) return [ x.Symbol for x in sortedByPeRatio[:self.__numberOfSymbolsFine] ] def OnSecuritiesChanged(self, changes): self.Plot("Research", "Active Securities", self.ActiveSecurities.Count) self.changes = changes #Securities Removed for x in changes.RemovedSecurities: self.Liquidate(x.Symbol) if x.Symbol in self.RiskManagementDict: del self.RiskManagementDict[x.Symbol]#.pop(x.Symbol) self.Plot('Research 2', 'Dictionary Size', len(self.RiskManagementDict)) #Securities Added for x in self.changes.AddedSecurities: self.RiskManagementDict[x.Symbol] = StopManagement(x.Symbol, maximumDrawdownPercent) self.Plot('Research 2', 'Dictionary Size', len(self.RiskManagementDict)) def TrailingStop(self, price, symbol): if self.Portfolio[symbol].Invested: if self.RiskManagementDict[symbol].orderID is None: self.RiskManagementDict[symbol].captureStop(self.StopMarketOrder(symbol, -self.Portfolio[symbol].Quantity, self.Securities[symbol].Holdings.AveragePrice * round(1-maximumDrawdownPercent)), self.Securities[symbol].Holdings.AveragePrice, self.Portfolio[symbol].Quantity) self.RiskManagementDict[symbol].trackStopMarketOrder(self.RiskManagementDict[symbol].stopMarketTicket.OrderId) self.RiskManagementDict[symbol].updateStopPrice(price) def OnOrderEvent(self, orderEvent): if orderEvent.Status != OrderStatus.Filled: return for Security in self.RiskManagementDict: if self.RiskManagementDict[Security].stopMarketTicket is not None and self.RiskManagementDict[Security].stopMarketTicket.OrderId == orderEvent.OrderId: self.RiskManagementDict[Security].executedStopOrder(bufferBetweenOrders) def OnEndOfDay(self): for Security in self.RiskManagementDict: self.RiskManagementDict[Security].endOfDay() self.dayEndPortfolioValue = self.Portfolio.TotalPortfolioValue class StopManagement: def __init__(self, symbol, riskTolerance): self.Symbol = symbol self.StopPrice = zero self.HighestPrice = zero self.LowestPrice = zero self.riskTolerance = round(1-riskTolerance,2) self.stopMarketTicket = None self.orderID = None self.timeBuffer = zero self.continueTrading = True self.LongEquity = True def trackStopMarketOrder(self, orderID): self.orderID = orderID def updateStopPrice(self, price): if self.LongEquity: if price.High > self.HighestPrice: self.HighestPrice = price.High self.StopPrice = self.HighestPrice * self.riskTolerance if self.stopMarketTicket is not None: updateFields = UpdateOrderFields() updateFields.StopPrice = self.StopPrice self.stopMarketTicket.Update(updateFields) if not self.LongEquity: if price.Low < self.LowestPrice: self.LowestPrice = price.Low self.StopPrice = self.LowestPrice * round(1/self.riskTolerance,2) if self.stopMarketTicket is not None: updateFields = UpdateOrderFields() updateFields.StopPrice = self.StopPrice self.stopMarketTicket.Update(updateFields) def trackOrder(self, orderID): self.orderID = orderID def captureStop(self, stopMarketTicket, avgprice, qty): if qty >= zero: self.LongEquity = True self.HighestPrice = avgprice self.StopPrice = self.HighestPrice * self.riskTolerance elif qty < zero: self.LongEquity = False self.LowestPrice = avgprice self.StopPrice = self.LowestPrice * round(1/self.riskTolerance,2) self.stopMarketTicket = stopMarketTicket def executedStopOrder(self, bufferBetweenOrders): self.stopMarketTicket = None self.orderID = None self.timeBuffer = bufferBetweenOrders self.continueTrading = False def updateBuffer(self): self.timeBuffer = self.timeBuffer - int(1) def endOfDay(self): self.continueTrading = True def reset(self): self.StopPrice = zero self.HighestPrice = zero self.LowestPrice = zero self.stopMarketTicket = None self.orderID = None self.continueTrading = True self.LongEquity = True