Created with Highcharts 12.1.2EquityJan 1Jan 3Jan 5Jan 7Jan 9Jan 11Jan 13Jan 15Jan 17Jan 19Jan 21Jan 23Jan 25Jan 27Jan 29Jan 31960k980k1,000k1,020k-2-100510-1-0.5005M025M50M24.92525.1
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}")