Overall Statistics
Total Trades
10
Average Win
17.53%
Average Loss
-17.89%
Compounding Annual Return
-15.838%
Drawdown
89.000%
Expectancy
-0.152
Net Profit
-29.167%
Sharpe Ratio
0.24
Probabilistic Sharpe Ratio
12.016%
Loss Rate
57%
Win Rate
43%
Profit-Loss Ratio
0.98
Alpha
-0.029
Beta
1.769
Annual Standard Deviation
0.646
Annual Variance
0.418
Information Ratio
0.084
Tracking Error
0.61
Treynor Ratio
0.088
Total Fees
$136.90
Estimated Strategy Capacity
$220000000.00
Lowest Capacity Asset
NQ WSVU0MELFS3L
from typing import Dict

# CONFIGS
RSI_period = 14
RSI_upper = 30
RSI_lower = 27
bar_size = timedelta(minutes=5)

portfolio_pct = .6
stoploss_dist = 20
takeprofit_dist = 20
max_losses = 2 # max number of losses in a day
debug = True  # turn off to reduce logging
# END CONFIGS

f = False
if f:
    from AlgorithmImports import *

class Consulting(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2018, 1, 1)
        self.SetEndDate(2020, 1, 1)
        self.SetCash(100000)

        future = self.AddFuture(Futures.Indices.NASDAQ100EMini, Resolution.Minute) 
        future.SetFilter(lambda x: x.FrontMonth().OnlyApplyFilterAtMarketOpen())
        
        self.rsi = RelativeStrengthIndex(RSI_period)

        self.consolidators: Dict[Symbol, QuoteBarConsolidator] = {}

        self.stoploss = None 
        self.takeprofit = None
        self.last_rsi = None

        self.loss_count = 0
        self.curr_day = -1

    def OnData(self, data:Slice):
        # new day
        if self.curr_day != self.Time.day:
            self.curr_day = self.Time.day 
            self.Reset()

        price = self.Securities[self.GetSymbol()].Price
        if self.takeprofit and price > self.takeprofit:
            self.Liquidate()
        elif self.stoploss and price < self.stoploss:
            self.loss_count += 1
            self.Liquidate()

    def GetSymbol(self) -> Symbol:
        '''
        get current front month contract
        '''
        return list(self.consolidators.keys())[0]

    def Reset(self):
        self.stoploss = None 
        self.takeprofit = None
        self.last_rsi = None

        self.loss_count = 0

    def Print(self, msg):
        if debug:
            self.Log(msg)

    def OnDataConsolidated(self, sender, quoteBar:QuoteBar):
        '''
        5 minute consolidator
        Update RSI, SetHoldings
        '''
        self.rsi.Update(self.Time, quoteBar.Close)
        if not self.rsi.IsReady:
            return 
        
        curr_rsi = self.rsi.Current.Value
        
        if self.loss_count > max_losses:
            return

        self.Plot('RSI', 'Value', curr_rsi)

        if (not self.Portfolio.Invested and self.last_rsi 
                and self.last_rsi < RSI_lower and curr_rsi > RSI_upper):
            if quoteBar.High - stoploss_dist < quoteBar.Close:
                self.stoploss = quoteBar.High - stoploss_dist
                self.takeprofit = quoteBar.High + stoploss_dist
                self.SetHoldings(self.GetSymbol(), portfolio_pct)

        self.last_rsi = curr_rsi

    def OnSecuritiesChanged(self, changes):
        '''
        register consolidator for frontmonth contract, deregister consolidator for expired contract
        '''
        for security in changes.AddedSecurities:
            consolidator = QuoteBarConsolidator(bar_size)
            consolidator.DataConsolidated += self.OnDataConsolidated
            self.SubscriptionManager.AddConsolidator(security.Symbol, consolidator)
            self.consolidators[security.Symbol] = consolidator
            
        for security in changes.RemovedSecurities:
            consolidator = self.consolidators.pop(security.Symbol)
            self.SubscriptionManager.RemoveConsolidator(security.Symbol, consolidator)
            consolidator.DataConsolidated -= self.OnDataConsolidated