Overall Statistics |
Total Orders 122 Average Win 33.07% Average Loss -9.32% Compounding Annual Return 16.678% Drawdown 43.400% Expectancy 0.848 Net Profit 766.999% Sharpe Ratio 0.524 Sortino Ratio 0.554 Probabilistic Sharpe Ratio 1.948% Loss Rate 59% Win Rate 41% Profit-Loss Ratio 3.55 Alpha 0.039 Beta 1.135 Annual Standard Deviation 0.26 Annual Variance 0.067 Information Ratio 0.252 Tracking Error 0.203 Treynor Ratio 0.12 Total Fees $122.20 Estimated Strategy Capacity $25000000.00 Lowest Capacity Asset CAT R735QTJ8XC9X Portfolio Turnover 0.80% |
from AlgorithmImports import * class GrowthStocksAlgorithm(QCAlgorithm): def Initialize(self): self.SetStartDate(2010, 1, 1) # Set Start Date self.SetEndDate(2024, 1, 1) # Set End Date self.SetCash(10000) # Set Strategy Cash self.UniverseSettings.Resolution = Resolution.Daily self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction) self.Schedule.On(self.DateRules.MonthStart(), self.TimeRules.At(10, 0), self.RebalancePortfolio) self.trailingStopLossPercent = 0.17 # 15% trailing stop self.highWaterMarks = dict() # Dictionary to store high water marks for symbols self.changes = [] # To track added securities def CoarseSelectionFunction(self, coarse): filtered_coarse = [x for x in coarse if x.DollarVolume > 1e6 and x.Price > 5] sorted_by_liquidity = sorted(filtered_coarse, key=lambda x: x.DollarVolume, reverse=True) selected_symbols = [x.Symbol for x in sorted_by_liquidity if x.Price * x.DollarVolume / x.Price > 2e9] return selected_symbols[:100] def FineSelectionFunction(self, fine): filtered_fine = [x for x in fine if x.OperationRatios.RevenueGrowth.OneYear > 0.0 and x.OperationRatios.NetIncomeGrowth.OneYear > 0.0 and x.EarningReports.BasicEPS.TwelveMonths > 0 and (x.ValuationRatios.PEGRatio > 0 and x.ValuationRatios.PEGRatio < 1.5) and x.FinancialStatements.BalanceSheet.TotalEquity.Value > 0] sorted_by_growth = sorted(filtered_fine, key=lambda x: x.OperationRatios.RevenueGrowth.OneYear, reverse=True) return [x.Symbol for x in sorted_by_growth[:10]] def RebalancePortfolio(self): if self.changes is None or len(self.changes) == 0: return weight_per_security = 1.0 / len(self.changes) for symbol in self.changes: if not self.Securities[symbol].Invested: self.SetHoldings(symbol, weight_per_security) self.highWaterMarks[symbol] = self.Securities[symbol].Price self.changes = [] # Reset the changes after rebalancing def OnSecuritiesChanged(self, changes): self.changes = [x.Symbol for x in changes.AddedSecurities] def OnData(self, data): symbolsToLiquidate = [] for symbol, highWaterMark in self.highWaterMarks.items(): # Check if the symbol has data before accessing its Close price if symbol in data and data[symbol] is not None: currentPrice = data[symbol].Close if currentPrice > highWaterMark: self.highWaterMarks[symbol] = currentPrice trailingStopPrice = highWaterMark * (1 - self.trailingStopLossPercent) if currentPrice < trailingStopPrice: symbolsToLiquidate.append(symbol) for symbol in symbolsToLiquidate: self.Liquidate(symbol) del self.highWaterMarks[symbol]