| Overall Statistics |
|
Total Orders 150 Average Win 6.48% Average Loss -3.59% Compounding Annual Return 10.720% Drawdown 29.800% Expectancy 0.585 Net Profit 316.201% Sharpe Ratio 0.507 Sortino Ratio 0.41 Probabilistic Sharpe Ratio 3.010% Loss Rate 43% Win Rate 57% Profit-Loss Ratio 1.80 Alpha 0.052 Beta 0.192 Annual Standard Deviation 0.134 Annual Variance 0.018 Information Ratio -0.097 Tracking Error 0.176 Treynor Ratio 0.354 Total Fees $223.91 Estimated Strategy Capacity $15000000.00 Lowest Capacity Asset MRK R735QTJ8XC9X Portfolio Turnover 1.69% |
from AlgorithmImports import *
class GrowthStocksAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2010, 1, 1) # Start Date
self.SetEndDate(2024, 1, 1) # End Date
self.SetCash(10000) # Strategy Cash
# Universe and Resolution Settings
self.UniverseSettings.Resolution = Resolution.Daily
self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)
# Schedule rebalance
self.Schedule.On(self.DateRules.MonthStart(), self.TimeRules.At(10, 0), self.RebalancePortfolio)
# Trailing stop loss percentage and dictionary for high water marks
self.trailingStopLossPercent = 0.07
self.highWaterMarks = dict()
# Changes tracker
self.changes = None
# Add VIX for market volatility
self.vix = self.AddData(CBOE, "VIX").Symbol
self.vixHighVolatilityThreshold = 20 # Define high volatility threshold
self.canBuyEquities = True # Flag to control equity buying
def CoarseSelectionFunction(self, coarse):
if not self.canBuyEquities:
return []
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]
# VIX-based market volatility handling
if data.ContainsKey(self.vix):
currentVixValue = data[self.vix].Close
isHighVolatility = currentVixValue > self.vixHighVolatilityThreshold
if isHighVolatility:
self.AdjustEquityExposure(False) # Adjust for high volatility
else:
self.AdjustEquityExposure(True) # Reset for normal conditions
def AdjustEquityExposure(self, canBuy):
self.canBuyEquities = canBuy
if not canBuy:
# Exit profitable positions during high volatility
for symbol, security in self.Securities.items():
if security.Invested:
currentPrice = security.Price
buyPrice = security.Holdings.AveragePrice
if currentPrice > buyPrice:
self.Liquidate(symbol)