Overall Statistics
Total Orders
10001
Average Win
0.53%
Average Loss
-1.20%
Compounding Annual Return
21.440%
Drawdown
37.700%
Expectancy
0.205
Start Equity
100000
End Equity
490213.55
Net Profit
390.214%
Sharpe Ratio
0.732
Sortino Ratio
0.742
Probabilistic Sharpe Ratio
15.542%
Loss Rate
16%
Win Rate
84%
Profit-Loss Ratio
0.44
Alpha
0.084
Beta
0.78
Annual Standard Deviation
0.226
Annual Variance
0.051
Information Ratio
0.308
Tracking Error
0.2
Treynor Ratio
0.212
Total Fees
$3240.54
Estimated Strategy Capacity
$22000000.00
Lowest Capacity Asset
FB V6OIPNZEM8V9
Portfolio Turnover
5.26%
from AlgorithmImports import *

class EMAMovingAverageStrategy(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2009, 1, 1)
        self.SetEndDate(2022, 1, 1)
        self.SetCash(100000)

        # Add all symbols in S&P 500
        self.symbols = ["AAPL", "MSFT", "GOOGL", "AMZN", "FB", "JPM", "V", "PG", "DIS", "HD",  # Add more symbols as needed
                        "VZ", "KO", "INTC", "NFLX", "TSLA", "NVDA", "UNH", "PYPL", "PEP", "ABT", 
                        "BAC", "CMCSA", "ADBE", "XOM", "MRK", "PFE", "WMT", "NKE", "CSCO", "MCD", 
                        "MA", "ABNB", "CRM", "AVGO", "T", "ORCL", "ACN", "CVX", "LMT", "MDT",
                        "IBM", "TXN", "QCOM", "LOW", "AMGN", "SBUX", "TMO", "COST", "GILD", "UPS"]
        
        # Initialize indicators and rolling windows for each symbol
        self.indicators = {}
        self.sma60_tracks = {}

        for symbol in self.symbols:
            equity = self.AddEquity(symbol, Resolution.Daily)
            self.indicators[symbol] = {
                "ema9": self.EMA(equity.Symbol, 9, Resolution.Daily),
                "ema15": self.EMA(equity.Symbol, 15, Resolution.Daily),
                "ema65": self.EMA(equity.Symbol, 65, Resolution.Daily),
                "ema200": self.EMA(equity.Symbol, 200, Resolution.Daily),
                "sma14": self.SMA(equity.Symbol, 14, Resolution.Daily),
                "rsi": self.RSI(equity.Symbol, 14, Resolution.Daily)
            }
            self.sma60_tracks[symbol] = RollingWindow[IndicatorDataPoint](60)
        
        self.SetWarmUp(200)

    def OnData(self, data):
        if self.IsWarmingUp:
            return

        for symbol in self.symbols:
            if data.ContainsKey(symbol):
                current_data = data[symbol]
                if current_data:
                    self.sma60_tracks[symbol].Add(self.indicators[symbol]["sma14"].Current)
        
        for symbol in self.symbols:
            if self.sma60_tracks[symbol].IsReady:
                self.TradeSymbol(symbol)

    def TradeSymbol(self, symbol):
        indicators = self.indicators[symbol]
        sma60_track = self.sma60_tracks[symbol]  # Corrected attribute name

        if self.IsBuyCondition(indicators, sma60_track):  # Pass sma60_track to IsBuyCondition
            self.SetHoldings(symbol, 1.0)
        elif self.IsSellCondition(indicators, sma60_track):  # Pass sma60_track to IsSellCondition
            self.Liquidate(symbol)
        elif self.Portfolio[symbol].Invested:
            if self.IsExitBuyCondition(indicators):
                self.Liquidate(symbol)
            elif self.IsExitSellCondition(indicators):
                self.Liquidate(symbol)

    def IsBuyCondition(self, indicators, sma60_track):  # Added sma60_track parameter
        ema_condition = (indicators["ema9"].Current.Value > indicators["ema15"].Current.Value > indicators["ema65"].Current.Value > indicators["ema200"].Current.Value)
        sma_condition = all(x.Value > 60 for x in sma60_track)
        return ema_condition and sma_condition

    def IsSellCondition(self, indicators, sma60_track):  # Added sma60_track parameter
        ema_condition = (indicators["ema9"].Current.Value < indicators["ema15"].Current.Value < indicators["ema65"].Current.Value < indicators["ema200"].Current.Value)
        sma_condition = all(x.Value < 60 for x in sma60_track)
        return ema_condition and sma_condition

    def IsExitBuyCondition(self, indicators):
        ema_cross_condition = (indicators["ema9"].Current.Value < indicators["ema65"].Current.Value or indicators["ema15"].Current.Value < indicators["ema65"].Current.Value)
        rsi_condition = indicators["rsi"].Current.Value < 40
        return ema_cross_condition and rsi_condition

    def IsExitSellCondition(self, indicators):
        ema_cross_condition = (indicators["ema9"].Current.Value > indicators["ema65"].Current.Value or indicators["ema15"].Current.Value > indicators["ema65"].Current.Value)
        rsi_condition = indicators["rsi"].Current.Value > 60
        return ema_cross_condition and rsi_condition