Overall Statistics |
Total Trades 431 Average Win 2.09% Average Loss -1.38% Compounding Annual Return 81.654% Drawdown 46.100% Expectancy 0.280 Net Profit 81.952% Sharpe Ratio 1.326 Probabilistic Sharpe Ratio 47.111% Loss Rate 49% Win Rate 51% Profit-Loss Ratio 1.51 Alpha 0.891 Beta 0.155 Annual Standard Deviation 0.692 Annual Variance 0.478 Information Ratio 1.027 Tracking Error 0.729 Treynor Ratio 5.926 Total Fees $26446.20 Estimated Strategy Capacity $0 Lowest Capacity Asset MDRR WZL2JJ0Y6KPX |
from AlgorithmImports import * class MaximumDrawdownPercentPerSecurity(RiskManagementModel): '''Provides an implementation of IRiskManagementModel that limits the drawdown per holding to the specified percentage''' def __init__(self, maximumDrawdownPercent = 0.05): # '''Initializes a new instance of the MaximumDrawdownPercentPerSecurity class # Args: # maximumDrawdownPercent: The maximum percentage drawdown allowed for any single security holding''' self.maximumDrawdownPercent = -abs(maximumDrawdownPercent) def ManageRisk(self, algorithm, targets): '''Manages the algorithm's risk at each time step Args: algorithm: The algorithm instance targets: The current portfolio targets to be assessed for risk''' targets = [] for kvp in algorithm.Securities: security = kvp.Value if not security.Invested: continue pnl = security.Holdings.UnrealizedProfitPercent if pnl < self.maximumDrawdownPercent: # liquidate targets.append(PortfolioTarget(security.Symbol, 0)) return targets
from AlgorithmImports import * from MaximumDrawdownPercentPerSecurity import MaximumDrawdownPercentPerSecurity class WellDressedSkyBlueSardine(QCAlgorithm): def Initialize(self): self.SetStartDate(2020, 1, 1) self.SetEndDate(2020,12, 31) self.SetCash(100000) self.rebalanceTime = datetime.min self.activeStocks = set() self.AddUniverse(self.CoarseFilter, self.FineFilter) self.UniverseSettings.Resolution = Resolution.Daily self.AddRiskManagement(MaximumDrawdownPercentPerSecurity()) self.portfolioTargets = [] #Parameters timedelta = self.GetParameter("timedelta") sortedByPE = self.GetParameter("sortedByPE") MarketCap = self.GetParameter("MarketCap") self.PRAM_timedelta = 16 if timedelta is None else int(timedelta) self.PRAM_sortedByPE = 8 if sortedByPE is None else int(sortedByPE) self.PRAM_MarketCap = 10000000 if MarketCap is None else int(MarketCap) def CoarseFilter(self, coarse): # Rebalancing monthly if self.Time <= self.rebalanceTime: return self.Universe.Unchanged self.rebalanceTime = self.Time + timedelta(self.PRAM_timedelta) sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=False) return [x.Symbol for x in sortedByDollarVolume if x.Price < 10 and x.HasFundamentalData][:200] def FineFilter(self, fine): sortedByPE = sorted(fine, key=lambda x: x.MarketCap, reverse=False) return [x.Symbol for x in sortedByPE if x.MarketCap > self.PRAM_MarketCap][:self.PRAM_sortedByPE] def OnSecuritiesChanged(self, changes): # close positions in removed securities for x in changes.RemovedSecurities: self.Liquidate(x.Symbol) self.activeStocks.remove(x.Symbol) # can't open positions here since data might not be added correctly yet for x in changes.AddedSecurities: self.activeStocks.add(x.Symbol) self.portfolioTargets = [PortfolioTarget(symbol, 1/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 = []