| Overall Statistics |
|
Total Orders 30 Average Win 0.84% Average Loss -0.33% Compounding Annual Return 15.218% Drawdown 2.900% Expectancy 1.500 Start Equity 1000000 End Equity 1071785.37 Net Profit 7.179% Sharpe Ratio 1.21 Sortino Ratio 0.786 Probabilistic Sharpe Ratio 70.491% Loss Rate 29% Win Rate 71% Profit-Loss Ratio 2.50 Alpha 0.04 Beta 0.142 Annual Standard Deviation 0.062 Annual Variance 0.004 Information Ratio -1.569 Tracking Error 0.109 Treynor Ratio 0.529 Total Fees $1532.28 Estimated Strategy Capacity $12000000.00 Lowest Capacity Asset JNJ R735QTJ8XC9X Portfolio Turnover 6.71% |
from AlgorithmImports import *
class MomentumTrendStrategy(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2019, 1, 1)
self.SetEndDate(2019, 6, 30)
self.SetCash(1000000)
# Add AMD and JNJ (Hour resolution)
self.symbols = []
self.symbols.append(self.AddEquity("AMD", Resolution.Hour).Symbol)
self.symbols.append(self.AddEquity("JNJ", Resolution.Hour).Symbol)
# Dictionary to hold indicators for each stock
self.indicators = {}
for symbol in self.symbols:
self.indicators[symbol] = {
"sma50": self.SMA(symbol, 20, Resolution.Hour),
"sma200": self.SMA(symbol, 70, Resolution.Hour),
"rsi": self.RSI(symbol, 14, MovingAverageType.Simple, Resolution.Hour),
"bb": self.BB(symbol, 20, 2, Resolution.Hour)
}
# 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}")