Overall Statistics
Total Trades
17
Average Win
1.80%
Average Loss
-0.62%
Compounding Annual Return
8.018%
Drawdown
13.000%
Expectancy
0.306
Net Profit
8.018%
Sharpe Ratio
0.544
Probabilistic Sharpe Ratio
28.632%
Loss Rate
67%
Win Rate
33%
Profit-Loss Ratio
2.92
Alpha
-0.012
Beta
0.37
Annual Standard Deviation
0.113
Annual Variance
0.013
Information Ratio
-1.081
Tracking Error
0.126
Treynor Ratio
0.167
Total Fees
$17.87
Estimated Strategy Capacity
$61000000.00
Lowest Capacity Asset
EBAY REC37LGZ79T1
# region imports
from AlgorithmImports import *
# endregion

class CGPT(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2021, 1, 1)  # Set Start Date
        self.SetEndDate(2022, 1, 1)  # Set End Date
        self.SetCash(100000)  # Set Strategy Cash

        self.UniverseSettings.Resolution = Resolution.Daily

        filter_function = lambda constituents: [x.Symbol for x in constituents]
        universe = self.Universe.ETF("QQQ", Market.USA, self.UniverseSettings, filter_function)
        self.AddUniverse(universe)

        # list_equities = ['AAPL','MSFT']
        # for ticker in list_equities:
        #     self.AddEquity(ticker, Resolution.Daily)

        self.lookback = 50
        self.SetWarmup(100)

        self.rolling_closes = dict()
        self.sma = dict()
        
        self.open_positions = 0
        self.target_positions = 5
    
    def OnSecuritiesChanged(self, changes):
        for security in changes.AddedSecurities:
            symbol = security.Symbol
            self.rolling_closes[symbol] = RollingWindow[float](self.lookback)
            self.sma[symbol] = self.SMA(symbol, 200)

        
    def OnData(self, data: Slice):

        if self.open_positions < self.target_positions:
            for symbol in self.ActiveSecurities.Keys:
                if data.ContainsKey(symbol) and data[symbol] is not None:
                    try:
                        self.rolling_closes[symbol].Add(data[symbol].Close)
                    except:
                        self.temp = 1

                    if (self.rolling_closes[symbol].Count < 50) or self.IsWarmingUp:
                        return
                    
                    momentum = self.rolling_closes[symbol][0] - self.rolling_closes[symbol][49]

                    long_entry = momentum > 0
                    short_entry = momentum < 0
                    proportion = round(1/self.target_positions,2)

                    if long_entry and not self.Portfolio[symbol].Invested:
                        self.SetHoldings(symbol,proportion,tag='Momentum > 0')
                        self.open_positions += 1
                    elif short_entry and not self.Portfolio[symbol].Invested:
                        self.SetHoldings(symbol,-1*proportion,tag='Momentum < 0')
                        self.open_positions += 1
        else:
            for symbol in self.Portfolio.Keys:
                if (self.Portfolio[symbol].Quantity > 0):
                    if (self.rolling_closes[symbol][0] < self.sma[symbol].Current.Value):
                        self.SetHoldings(symbol,0,tag='Price below SMA')
                        self.open_positions -= 1
                elif (self.Portfolio[symbol].Quantity < 0):
                    if (self.rolling_closes[symbol][0] > self.sma[symbol].Current.Value):
                        self.SetHoldings(symbol,0,tag='Price above SMA')
                        self.open_positions -= 1