Overall Statistics
Total Trades
98
Average Win
1.31%
Average Loss
-0.68%
Compounding Annual Return
21.661%
Drawdown
10.400%
Expectancy
0.894
Net Profit
38.086%
Sharpe Ratio
1.383
Probabilistic Sharpe Ratio
66.664%
Loss Rate
35%
Win Rate
65%
Profit-Loss Ratio
1.93
Alpha
0.034
Beta
0.472
Annual Standard Deviation
0.11
Annual Variance
0.012
Information Ratio
-0.856
Tracking Error
0.114
Treynor Ratio
0.322
Total Fees
$2771.30
Estimated Strategy Capacity
$690000.00
Lowest Capacity Asset
NQ XUERCWA6EWAP
# region imports
from AlgorithmImports import *
# endregion

class CryingYellowGreenCrocodile(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2020, 1, 1)  # Set Start Date
        self.SetCash(100000)            # Set Strategy Cash

        self.nq = self.AddFuture("NQ", Resolution.Daily)   # is the same as:
        self.nq.SetFilter(0, 240)
        # self.AddFuture(Futures.Indices.NASDAQ100EMini)
        
        # self.min = self.MIN(self.nq, 14, Resolution.Minute)
        # self.max = self.MAX(self.nq, 14, Resolution.Minute)

        self.symbols = []
        self.count = 0
        self.day_count = 0


    def OnData(self, data):
        chains_count = 0
        for chain in data.FutureChains:
            self.day_count += 1
            chains_count += 1
            self.count += 1
            contracts = [contract for contract in chain.Value if contract.Expiry > self.Time + timedelta(days=8)]
            sorted_contracts = sorted(contracts, key=lambda x: x.Expiry)
            if len(sorted_contracts) == 0:
                continue
            
            # for x in contracts:
            self.symbols.append(str(sorted_contracts[0].Symbol))

        if self.count < 20:
            self.Debug(f'{chains_count}, @{self.Time}')

    def OnEndOfAlgorithm(self):
        self.Debug(f'Day amount; {self.day_count}')
        self.Debug(f'len(symbols) = {len(self.symbols)}')
        self.Debug(f'{self.symbols}')

# conclusion: yes, it selects the correct one
# region imports
from AlgorithmImports import *
# endregion

class CryingYellowGreenCrocodile(QCAlgorithm):

    def Initialize(self):
        
        self.SetStartDate(2020, 5, 10)  
        self.SetEndDate(2022, 1, 1) 
        self.SetCash(10000000)            

        self.nq = self.AddFuture(Futures.Indices.NASDAQ100EMini, Resolution.Minute)   
        self.nq.SetFilter(8, 240)

        self.Indicators = {
            'sma': SimpleMovingAverage(11),
            'ema_fast': ExponentialMovingAverage(100),
            'ema_slow': ExponentialMovingAverage(300),
            'min': Minimum(14),
            'max': Maximum(14),
        }
        
        self.tolerance = 0.001
        self.symbol = []
        self.consolidator = None
                

    def OnSecuritiesChanged(self, changes):
        for security in changes.RemovedSecurities:
            if len(changes.RemovedSecurities) > 0:
                # Remove the consolidator for the previous contract
                # and reset the indicators
                if self.symbol is not None and self.consolidator is not None:
                    if self.symbol == security.Symbol:
                        self.SubscriptionManager.RemoveConsolidator(self.symbol, self.consolidator)
                        for indicator in self.Indicators:
                            self.Indicators[indicator].Reset()

            # We don't need to call Liquidate(_symbol),
            # since its positions are liquidated because the contract has expired.
            
        for security in changes.AddedSecurities:
            if len(changes.AddedSecurities) == 0: return
            # Only one security will be added: the new front contract
            self.symbol = changes.AddedSecurities[0].Symbol

            # Create a new consolidator and register the indicators to it
            self.consolidator = self.ResolveConsolidator(self.symbol, Resolution.Minute)

            for indicator in self.Indicators:
                self.RegisterIndicator(self.symbol, self.Indicators[indicator], self.consolidator)
                self.WarmUpIndicator(self.symbol, self.Indicators[indicator], Resolution.Minute)
        

    def OnData(self, data):
        if not (self.Time.hour == 10 and self.Time.minute == 1): return
        holding = None if self.symbol is None else self.Portfolio.get(self.symbol)
        # if holding is None: return 
        if not data.Bars.ContainsKey(self.symbol): return
    
        if not holding.Invested:
            if self.Indicators['ema_fast'].Current.Value > (1 + self.tolerance)*self.Indicators['ema_slow'].Current.Value:
                self.SetHoldings(self.symbol, 0.025)

        elif holding.Invested:
            if self.Indicators['ema_fast'].Current.Value < (1 - self.tolerance)*self.Indicators['ema_slow'].Current.Value:
                self.Liquidate(self.symbol)