Overall Statistics |
Total Trades 163 Average Win 0.73% Average Loss -0.62% Compounding Annual Return 32.810% Drawdown 11.400% Expectancy 0.761 Net Profit 79.428% Sharpe Ratio 1.517 Probabilistic Sharpe Ratio 73.538% Loss Rate 20% Win Rate 80% Profit-Loss Ratio 1.19 Alpha 0 Beta 0 Annual Standard Deviation 0.152 Annual Variance 0.023 Information Ratio 1.517 Tracking Error 0.152 Treynor Ratio 0 Total Fees $163.00 Estimated Strategy Capacity $100000000.00 Lowest Capacity Asset TSM R735QTJ8XC9X |
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.15): # '''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(2022,1,1) self.SetCash(25000) self.rebalanceTime = self.Time #self.rebalanceTime = datetime.min self.activeStocks = set() #self.AddEquity("SPY", Resolution.Daily) self.AddRiskManagement(MaximumDrawdownPercentPerSecurity()) self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Cash) self.VixNegative = True self.UniverseSettings.Resolution = Resolution.Daily self.AddUniverse(self.CoarseFilter, self.FineFilter) #VIX block self.previous = 0.0 self.lastTrade = datetime(1, 1, 1) self.cboeVix = self.AddData(CBOE, "VIX").Symbol self.portfolioTargets = [] #price_plot = Chart('My Plot') #name of plot => what chart object #price_plot.AddSeries(Series('Portfolio', SeriesType.Candle, 0)) #one tab with daily prices => what series connected to #price_plot.AddSeries(Series('Monthly Open Price', SeriesType.Candle,1)) # the second series it is connected to #self.AddChart(price_plot) #two with monthly prices #Parameters timedelta = self.GetParameter("timedelta") FinalSharesAmount = self.GetParameter("FinalSharesAmount") MarketCap = self.GetParameter("MarketCap") self.PRAM_timedelta = 6 #if timedelta is None else int(timedelta) self.PRAM_FinalSharesAmount = 10# if sortedByPE is None else int(FinalSharesAmount) self.PRAM_MarketCap = 100000000 #if MarketCap is None else int(MarketCap) def CoarseFilter(self, coarse): # Rebalancing monthly if self.Time <= self.rebalanceTime: return self.Universe.Unchanged self.rebalanceTime = timedelta(self.PRAM_timedelta)+ self.Time sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True) return [x.Symbol for x in sortedByDollarVolume if x.Price > 10 and x.HasFundamentalData][:100] def FineFilter(self, fine): sortedByPE = sorted(fine, key=lambda x: x.MarketCap, reverse=True) return [x.Symbol for x in sortedByPE if x.MarketCap > self.PRAM_MarketCap][:self.PRAM_FinalSharesAmount] def OnSecuritiesChanged(self, changes): # close positions in removed securities if self.VixNegative is False: return for x in changes.RemovedSecurities: self.Liquidate(x.Symbol) self.activeStocks.remove(x.Symbol) self.lastTrade = self.Time # can't open positions here since data might not be added correctly yet for x in changes.AddedSecurities: self.activeStocks.add(x.Symbol) self.lastTrade = self.Time # adjust targets if universe has changed if self.SetRiskManagement is True: self.SetHoldings(-1) self.lastTrade = self.Time else: self.portfolioTargets = [PortfolioTarget(symbol, 1/self.PRAM_FinalSharesAmount)#len(self.activeStocks)) for symbol in self.activeStocks] self.lastTrade = self.Time def OnData(self, data): # if self.Portfolio.Invested: # self.Plot('My Plot','My Portfolio',self.activeStocks.Open) # if self.Time.day == 1: #if its the first of the month ( monthly forst day) # self.Plot('My Plot','SPY',self.Securities['SPY'].Open) if not data.ContainsKey(self.cboeVix): return vix = data.Get(CBOE, self.cboeVix) current = vix.Close if self.previous != 0: # Calculate the percentage, and if it is greater than 10% percentageChange = ((current - self.previous) / self.previous)-1 if percentageChange < 0.01: self.VixNegative is True self.lastTrade = self.Time if percentageChange > 0.1: self.Liquidate() self.VixNegative is False self.lastTrade = self.Time if self.portfolioTargets == []: return for symbol in self.activeStocks: if symbol not in data: return self.SetHoldings(self.portfolioTargets) self.portfolioTargets = [] self.previous = vix.Close def OnOrderEvent(self, orderEvent): if orderEvent.Status == OrderStatus.Filled: self.Debug(f'Processed Order: {orderEvent.Symbol}, Quantity: {orderEvent.FillQuantity}' )