Overall Statistics
Total Trades
287
Average Win
0.10%
Average Loss
-0.10%
Compounding Annual Return
-10.524%
Drawdown
2.000%
Expectancy
-0.100
Net Profit
-1.452%
Sharpe Ratio
-3.026
Probabilistic Sharpe Ratio
2.619%
Loss Rate
54%
Win Rate
46%
Profit-Loss Ratio
0.95
Alpha
-0.113
Beta
0.123
Annual Standard Deviation
0.028
Annual Variance
0.001
Information Ratio
-3.732
Tracking Error
0.081
Treynor Ratio
-0.701
Total Fees
$530.95
Estimated Strategy Capacity
$2500000000.00
Lowest Capacity Asset
NQ XRX5ODZTG8OX
# example - https://www.quantconnect.com/forum/discussion/5257/futures-algorithm-with-indicator-and-consolidator-for-python/p1

# add MACD cross for close or lower TP/SL to see how it handles new order

# entries are going off not on the cross because it's waiting for open order to close. 
# Once closed it then sees if MACD & RSI match and enters, often not right after a MACD cross


# compare RSI and MACD values with SSE & ToS for most recent contract
    # MACD does not line up with SSE or ToS at all. SEE & ToS MACD match up 
    # RSI is using closing value of the day before. does keep one value for different trades on the same day & only buys/sells on >/< 50 as it should. 
        # SSE uses reg. avg for RSI and ToS uses Wilders avg for RSI. 
        ### mostly just about matches SSE/Tos, a few days really far off in the beginning. Warm up probably didn't work. 
    # NQ17U21 prices matches NQU21



from System.Drawing import Color

class FocusedApricotAlpaca(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2021, 7, 1) 
        self.SetEndDate(2021, 8, 18) 
        self.SetCash(1000000) 
        self.SetWarmUp(timedelta(days = 15))
        self.nq = self.AddFuture(Futures.Indices.NASDAQ100EMini) 
        self.nq.SetFilter(5, 120)
        
        self.oi_contract = None
        self.macd = None
        
        self.takeProfit = None
        self.stopLoss = None
        
        stockPlot = Chart('Price Plot')
        stockPlot.AddSeries(Series('Price', SeriesType.Line, '$', Color.Green))
        self.AddChart(stockPlot)
        
        
      
    def OnData(self, slice):
        for chain in slice.FutureChains:
            contracts = [contract for contract in chain.Value]
            if len(contracts) == 0:
                self.oi_contract = None
                self.macd = None
                break
            
            contract = sorted(contracts, key=lambda k : k.OpenInterest, reverse=True)[0]
            
            if self.oi_contract is not None and contract.Symbol == self.oi_contract.Symbol:
                break
            
            self.oi_contract = contract
            
            #set up consolidators
            fifteenMinute = TradeBarConsolidator(timedelta(minutes=15)) 
            fifteenMinute.DataConsolidated += self.fifteenMinuteBarHandler #need to def fifteenMinuteBarHandler
            
            self.SubscriptionManager.AddConsolidator(contract.Symbol, fifteenMinute) 
            
            # Set up Indicators
            self.macd = self.MACD(contract.Symbol, 12, 26, 9, MovingAverageType.Exponential)
            self.RegisterIndicator(contract.Symbol, self.macd, fifteenMinute)  
            
            self.rsi = self.RSI(contract.Symbol, 9, MovingAverageType.Wilders, Resolution.Daily)
            
           
            
        
        
            
    def fifteenMinuteBarHandler(self, sender, bar):
        
        
        
        if self.macd is None or not self.macd.IsReady:
            return
        
        symbol = self.oi_contract.Symbol
        security = self.Securities[symbol]
        price = security.Price
        
        
        # Only new positions not invested 
        if security.Invested:
            # Look to exit position
            return
        
        tolerance = 0.003
        signalDeltaPercent = self.macd.Current.Value - self.macd.Signal.Current.Value
        
        if signalDeltaPercent > tolerance and self.rsi.Current.Value > 50:
            #Go long
            self.MarketOrder(symbol, 1)
            self.takeProfit = self.LimitOrder(symbol, -1, price+50)   # 1% is too far for day trades
            self.stopLoss = self.StopMarketOrder(symbol, -1, price-50)
            self.Log(str(self.Time) + " buy " + str(price) + " MACD Current: " + str(self.macd.Current.Value) + " MACD Signal:" + str(self.macd.Signal.Current.Value) + " RSI: " + str(self.rsi.Current.Value))
        if signalDeltaPercent < -tolerance and self.rsi.Current.Value < 50:
            #Go short
            self.MarketOrder(symbol, -1)
            self.takeProfit = self.LimitOrder(symbol, 1, price-50)
            self.stopLoss = self.StopMarketOrder(symbol, 1, price+50)
            self.Log(str(self.Time) + " sell " + str(price) + " MACD Current: " + str(self.macd.Current.Value) + " MACD Signal:" + str(self.macd.Signal.Current.Value) + " RSI: " + str(self.rsi.Current.Value))
    
        self.Log(str(self.Time) + " Price: " + str(price))
    
        
        
        
    def OnOrderEvent(self, orderEvent):
        if orderEvent.Status != OrderStatus.Filled:
            return
        self.Cancel(orderEvent.OrderId)
    
    def Cancel(self, id):
        '''cancel one order if the other was filled'''
        if self.takeProfit is not None and id == self.takeProfit.OrderId:
            self.stopLoss.Cancel()
        elif self.stopLoss is not None and id == self.stopLoss.OrderId:
            self.takeProfit.Cancel()
        else:
            return
        self.takeProfit = None
        self.stopLoss = None