Overall Statistics |
Total Orders 108 Average Win 0.14% Average Loss -0.20% Compounding Annual Return -13.167% Drawdown 1.600% Expectancy -0.106 Start Equity 1000000 End Equity 988590.17 Net Profit -1.141% Sharpe Ratio -2.596 Sortino Ratio -2.817 Probabilistic Sharpe Ratio 14.531% Loss Rate 48% Win Rate 52% Profit-Loss Ratio 0.72 Alpha -0.148 Beta 0.03 Annual Standard Deviation 0.048 Annual Variance 0.002 Information Ratio -5.848 Tracking Error 0.158 Treynor Ratio -4.128 Total Fees $7032.03 Estimated Strategy Capacity $1800000.00 Lowest Capacity Asset JNJ R735QTJ8XC9X Portfolio Turnover 176.46% |
from AlgorithmImports import * class MomentumTrendStrategy(QCAlgorithm): def Initialize(self): self.SetStartDate(2019, 1, 1) self.SetEndDate(2019, 1, 30) self.SetCash(1000000) # Add AMD and JNJ (Minute resolution) self.symbols = [] self.symbols.append(self.AddEquity("AMD", Resolution.Minute).Symbol) self.symbols.append(self.AddEquity("JNJ", Resolution.Minute).Symbol) # Dictionary to hold indicators for each stock self.indicators = {} for symbol in self.symbols: self.indicators[symbol] = { "sma50": self.SMA(symbol, 20, Resolution.Minute), "sma200": self.SMA(symbol, 70, Resolution.Minute), "rsi": self.RSI(symbol, 14, MovingAverageType.Simple, Resolution.Minute), "bb": self.BB(symbol, 20, 2, Resolution.Minute) } # Warm up indicators self.SetWarmUp(200) def OnData(self, data): if self.IsWarmingUp: return for symbol in self.symbols: if symbol not in data: continue ind = self.indicators[symbol] if not all([ind["sma50"].IsReady, ind["sma200"].IsReady, ind["rsi"].IsReady, ind["bb"].IsReady]): continue price = self.Securities[symbol].Price sma50 = ind["sma50"].Current.Value sma200 = ind["sma200"].Current.Value rsi = ind["rsi"].Current.Value bb = ind["bb"] upperBB = bb.UpperBand.Current.Value middleBB = bb.MiddleBand.Current.Value lowerBB = bb.LowerBand.Current.Value # Define base position (trend-following component) # baseWeight = 0.25 if sma50 > sma200 else -0.25 # Adjust exposure based on momentum signals ShortSignal = sma50 < sma200 and price > upperBB and rsi > 75 LongSignal = sma50 > sma200 and price < lowerBB and rsi < 25 targetWeight = 0 if LongSignal: targetWeight = 0.5 elif ShortSignal: targetWeight = -0.5 # Exit all positions when momentum weakens if self.Portfolio[symbol].IsLong and (price > middleBB and rsi > 60): self.Liquidate(symbol) # Close entire long position targetWeight = 0 # Optional: Explicitly set weight to zero elif self.Portfolio[symbol].IsShort and (price < middleBB and rsi < 40): self.Liquidate(symbol) # Close entire short position targetWeight = 0 # Optional: Explicitly set weight to zero # Only set holdings if not liquidating if targetWeight != 0: self.SetHoldings(symbol, targetWeight) # Debugging output self.Debug(f"{self.Time} {symbol.Value}: Price={price:.2f}, SMA50={sma50:.2f}, SMA200={sma200:.2f}, " f"RSI={rsi:.2f}, UpperBB={upperBB:.2f}, MiddleBB={middleBB:.2f}, LowerBB={lowerBB:.2f}, " f"Target Weight={targetWeight:.2f}")