Overall Statistics |
Total Orders 4144 Average Win 0.25% Average Loss -0.25% Compounding Annual Return 8.663% Drawdown 39.400% Expectancy 0.154 Net Profit 129.512% Sharpe Ratio 0.341 Sortino Ratio 0.309 Probabilistic Sharpe Ratio 1.728% Loss Rate 43% Win Rate 57% Profit-Loss Ratio 1.02 Alpha -0.004 Beta 0.799 Annual Standard Deviation 0.164 Annual Variance 0.027 Information Ratio -0.157 Tracking Error 0.12 Treynor Ratio 0.07 Total Fees $4008.00 Estimated Strategy Capacity $270000000.00 Lowest Capacity Asset AVGO UEW4IOBWVPT1 Portfolio Turnover 4.71% |
from AlgorithmImports import * class MinerviniSEPAStrategy(QCAlgorithm): def Initialize(self): self.SetStartDate(2014, 1, 1) # Start date self.SetEndDate(2024, 1, 1) # End date self.SetCash(10000) # Starting cash self.UniverseSettings.Resolution = Resolution.Daily self.AddUniverse(self.CoarseSelectionFunction) self.ma_short = 150 self.ma_long = 200 self.volume_multiplier = 1.5 self.symbols = {} def CoarseSelectionFunction(self, coarse): sorted_coarse = sorted([x for x in coarse if x.HasFundamentalData], key=lambda x: x.DollarVolume, reverse=True)[:100] return [x.Symbol for x in sorted_coarse] def OnSecuritiesChanged(self, changes): for security in changes.RemovedSecurities: if security.Symbol in self.symbols: self.Liquidate(security.Symbol) del self.symbols[security.Symbol] for security in changes.AddedSecurities: symbol = security.Symbol if symbol not in self.symbols: self.symbols[symbol] = { "150MA": self.SMA(symbol, self.ma_short, Resolution.Daily), "200MA": self.SMA(symbol, self.ma_long, Resolution.Daily), "VolumeSMA": self.SMA(symbol, 30, Resolution.Daily) } def OnData(self, data): for symbol, indicators in self.symbols.items(): if not (indicators["150MA"].IsReady and indicators["200MA"].IsReady): continue if symbol not in data or not data[symbol]: continue if self.IsStage2(indicators, data[symbol].Price, data[symbol].Volume, indicators["VolumeSMA"].Current.Value): if self.MeetsEntryCriteria(symbol, indicators, data[symbol]): size = self.PositionSizing(symbol) self.SetHoldings(symbol, size) else: if self.Portfolio[symbol].Invested: self.Liquidate(symbol) def IsStage2(self, indicators, price, volume, avg_volume): avg150 = indicators["150MA"].Current.Value avg200 = indicators["200MA"].Current.Value return price > avg150 > avg200 and volume > avg_volume * self.volume_multiplier def MeetsEntryCriteria(self, symbol, indicators, security_data): # Expand this method to include more sophisticated checks as needed return indicators["200MA"].Current.Value > indicators["200MA"].Current.Value * (1 - 0.01) def PositionSizing(self, symbol): # Implement your volatility calculation here. This is a simplified example. history = self.History(symbol, 30, Resolution.Daily) if not history.empty: daily_returns = history['close'].pct_change().dropna() volatility = daily_returns.std() size = min(0.1, 1 / volatility) # Simplified risk-adjusted sizing return size return 0.1 def RebalancePortfolio(self): # Implement your rebalance logic. This is triggered quarterly in the example. if self.Time.month % 3 == 0 and self.Time.day == 1: for symbol in self.symbols: if symbol in self.Portfolio: self.AdjustPosition(symbol) # Placeholder for AdjustPosition. Define based on your rebalancing strategy. def AdjustPosition(self, symbol): # Adjust position based on updated criteria or indicators pass