| 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