Overall Statistics
Total Trades
0
Average Win
0%
Average Loss
0%
Compounding Annual Return
0%
Drawdown
0%
Expectancy
0
Net Profit
0%
Sharpe Ratio
0
Probabilistic Sharpe Ratio
0%
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
0
Beta
0
Annual Standard Deviation
0
Annual Variance
0
Information Ratio
-2.149
Tracking Error
0.115
Treynor Ratio
0
Total Fees
$0.00
Estimated Strategy Capacity
$0
Lowest Capacity Asset
class FuturesIndicatorExample(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2021, 1, 1) 
        self.SetEndDate(2021, 8, 18) 
        self.SetCash(1000000) 

        self.nq = self.AddFuture(Futures.Indices.NASDAQ100EMini) 
        self.nq.SetFilter(5, 120)
        
        self.contracts = {}
        self.oi_contract = None

    def OnData(self, slice):
        for chain in slice.FutureChains:
            contracts = sorted([k for k in chain.Value if k.OpenInterest > 0],
                key=lambda k : k.OpenInterest, reverse=True)

            if not contracts:
                continue

            self.oi_contract = contracts[0]
            symbol = self.oi_contract.Symbol
            if symbol not in self.contracts:
                self.contracts[symbol] = SymbolData(self, symbol)
                self.contracts[symbol].consolidators['15M'].DataConsolidated += self.On15MData

    def OnSecuritiesChanged(self, changes):
        for security in changes.RemovedSecurities:
            symbol = security.Symbol
            symbolData = self.contracts.get(symbol, None)
            if symbolData:
                symbolData.consolidators['15M'].DataConsolidated -= self.On15MData
                for consolidator in symbolData.consolidators.values():
                    self.SubscriptionManager.RemoveConsolidator(symbol, consolidator)
            
    def On15MData(self, sender, bar):

        if not self.oi_contract or self.oi_contract.Symbol != bar.Symbol:
            return
        
        symbol = self.oi_contract.Symbol
        symbolData = self.contracts.get(symbol, None)
        if not symbolData or not symbolData.macd.IsReady:
            return

        msg = f'{symbol.Value} :: {symbolData}'
        if self.LiveMode: self.Log(msg)
        

class SymbolData:
    def __init__(self, algorithm, symbol):

        self.consolidators = {
            '1D': TradeBarConsolidator(timedelta(1)),
            '15M': TradeBarConsolidator(timedelta(minutes=15))
        }
        
        # Set up Indicators
        # Use constructor, register to consolidator, warm up with history
        self.rsi = RelativeStrengthIndex(9, MovingAverageType.Wilders)
        algorithm.RegisterIndicator(symbol, self.rsi, self.consolidators['1D'])
        
        self.macd = MovingAverageConvergenceDivergence(12, 26, 9, MovingAverageType.Exponential)
        algorithm.RegisterIndicator(symbol, self.macd, self.consolidators['15M'])

        # Need 15 days of minute-resolution data to account weekends
        history = algorithm.History(symbol, timedelta(15), Resolution.Minute)
        for index, row in history.iterrows():
            bar = TradeBar(index[2]-Time.OneMinute, symbol, row.open, row.high, row.low, row.close, row.volume)
            bar.Symbol = symbol
            for consolidator in self.consolidators.values():
                consolidator.Update(bar)

        msg = f'{symbol.Value} :: RSI.IsReady? {self.rsi.IsReady}  :: MACD.IsReady? {self.macd.IsReady} :: {self}'  
        algorithm.Log(msg)
        
    def __repr__(self):
        return f'RSI: {self.rsi.Current.Value:.4f} MACD: {self.macd.Current.Value:.4f}'