Overall Statistics
Total Trades
2
Average Win
0.39%
Average Loss
0%
Compounding Annual Return
0.393%
Drawdown
0.200%
Expectancy
0
Net Profit
0.393%
Sharpe Ratio
0.624
Probabilistic Sharpe Ratio
27.875%
Loss Rate
0%
Win Rate
100%
Profit-Loss Ratio
0
Alpha
0.003
Beta
0.001
Annual Standard Deviation
0.005
Annual Variance
0
Information Ratio
0.188
Tracking Error
0.153
Treynor Ratio
2.801
Total Fees
$22.17
''' 
        
        
        NOTES re CT III from FUTs
                #FUCK need to add HIGHS and LOWS to ma -- so need 2 MAs
                #ha12 and la12
                
                #R1 = Average(High?! of data2-O of data2,12); 
                #S1 = Average(O of data2-L of data2,12);
                #Cent = (OpenD(0)+CloseD(1))/2; 
                #R2 = Cent + PercentRange*R1; 0 + .5 * R1
                #S2 = Cent - PercentRange*S1; 

                #if lower > upper3  #Done
                #and Close < S2 #DONE
                #and opend(0) > close //(15M Close)               #Do in OnData with TradeBar
                #Buy
        
        Simpler way -- FUCK ult osc and this bullshit trade bar fucking joke. Jesus.
        for c in sortedByVol:
            symbol = c.Symbol
            if symbol not in self.UOs:
                history = self.History(symbol, 51, Resolution.Daily)
                self.UOs[symbol] = Ultimate(symbol, history)
            self.UOs[symbol].Update(c.EndTime, c.AdjustedPrice)

            #sortedByUO = sorted(self.UOs.items(), key = lambda kv: v.uo_value, reverse=True)
            
            if self.UOs[symbol].uo_val > 100:
                self.longs += [symbol]
            
            elif self.UOs[symbol].uo_val < -100:
                self.shorts += [symbol]
            
            self.selected = self.longs + self.shorts
          
        
        
        
        FUCK UO 
        In OnData
        #U3 Version...
        for symbol in self.selected:
            if data.Bars.ContainsKey(symbol):
                if symbol not in self.U3s:
                    hist = self.History(symbol, 25, Resolution.Daily)
                    self.U3s[symbol] = U3(hist, symbol)
                self.U3s[symbol].Update(data[symbol].EndTime,data[symbol]) #data[symbol].EndTime,
        #End U3 Version...
        
        tradeBars = data.Bars
        ibmTradeBar = tradeBars['IBM']
        
        
        
        
class U3():
    
    def __init__(self,history, symbol=None):
        if symbol:
            self.symbol = symbol
        self.uo = UltimateOscillator(9,15,25)
        for time, price in history.items(): #Manual update...
            self.Update(time, price)
            
        #I think issue is -- ^^ is using history
        #whereas BELOW is using data['symbol']
        
            
    def Update(self,time, bar):
        #Accepts data[sym] as bar
        #Update in OnData w data['SPY'] AS BAR -> data["SPY"].EndTime , data["SPY"].Close, High, Low etc
        #Dont kno if I need this line ? Think I already have tradebar.
        #bar.EndTime
        #IF not work try with bar! BELOW
        bar = TradeBar(time, self.symbol, bar.open, bar.high, bar.low, bar.close, bar.Volume)
        self.uo.Update(bar) #Builtin UO Update method...
        '''
        
class DailyBars():
    
    def __init__(self, algorithm, history):
        self.dailyWindow = RollingWindow[TradeBar](10) #GENIUS
        
        #REPLACES UPDATE...
        self.dailyCons = TradeBarConsolidator(timedelta(days=1))
        algorithm.SubscriptionManager.AddConsolidator(symbol, self.dailyCons) 
        for bar in history.itertuples():
            tb = TradeBar(bar.Index[1], symbol, bar.open, bar.high, bar.low, bar.close, bar.volume)
            self.dailyWindow.Add(tb)
            
    @property
    def IsReady(self):
        return self.dailyWindow.IsReady
#from Selection.EmaCrossUniverseSelectionModel import EmaCrossUniverseSelectionModel
from System import *
from QuantConnect import *
from QuantConnect.Data import *
from QuantConnect.Algorithm import *
from QuantConnect.Securities import *
from QuantConnect import Market
from datetime import datetime
import pandas as pd

class CalibratedOptimizedInterceptor(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2018, 1, 1)  # Set Start Date
        self.SetEndDate(2019, 1, 1)
        self.SetCash(100000)  # Set Strategy Cash
        # self.AddEquity("SPY", Resolution.Minute)
        fastPeriod = 10
        slowPeriod = 30
        count = 10
        self.UOs = {}
        self.BB15s = {}
        self.U3s = {}
        self.L3s = {}
        self.DOs = {}
        #self.SetUniverseSelection(self.SelectCoarse)
        self.AddUniverse(self.SelectCoarse)
        self.UniverseSettings.Resolution = Resolution.Daily 
        
    def OnEndOfDay(self): 
        '''Where on earth is this called?'''
        self.Debug(f'{self.Time.date()} -- {len(self.ActiveSecurities)}')
        #for security in self.ActiveSecurities.Values:
        #    self.Debug(f"{self.Time.date()} -- {security.Symbol.Value}")
        
        
    def SelectCoarse(self, coarse):
        sortedByVol = sorted([c for c in coarse if c.AdjustedPrice > 10], 
                        key = lambda x: x.DollarVolume, reverse=True)[:100]
                        
        self.selected = []
        self.longs = []
        self.shorts = []
        #Alt method...
        
        new = [s.Symbol for s in sortedByVol if s.Symbol not in self.UOs]
        if new:
            history = self.History(new, 51, Resolution.Daily)
            if history.empty: return Universe.Unchanged
        
            history = history.close.unstack(0) 
            for sym in new:
                if sym in history: #Added?
                    self.UOs[sym] = DBB(history[sym].dropna())
                    
        openD, lower, upper, ma12 = 0,0,0,0
        for c in sortedByVol:
            symbol = c.Symbol
            if symbol not in new and symbol in self.UOs:
                self.UOs[symbol].Update(c.EndTime, c.AdjustedPrice)

                
            
            #New for U2
            if symbol not in self.BB15s:
                history = self.History(symbol, 25, Resolution.Daily)
                self.BB15s[symbol] = BB(symbol, self, history) 

                lower = self.BB15s[symbol].lb.Current.Value
                upper = self.BB15s[symbol].ub.Current.Value
                ma12 = self.BB15s[symbol].MA.Current.Value
                #self.Debug(f'{symbol} -- U:{upper} L:{lower}  MA:{ma12}')
                '''
                This needs to be ha12 and la12 -- 2 MAs... -- 
                can just average the highs / lows in vecs?
                '''
                
                openD = history.open.iloc[-1]                                   #-1 or 0?
                #closeYD = history.close.iloc[-2] Maybe should do windows?
                
                
            #self.Debug(f'{self.U2s[symbol].uo.Current.Value}')
            if self.UOs[symbol].IsReady and self.BB15s[symbol]:
                upper3 = self.UOs[symbol].ub3 #Uses Current.Value already!
                lower3 = self.UOs[symbol].lb3
                closeY = self.UOs[symbol].closeDs[1]
                self.Debug(f'{symbol} -- U3:{upper3} L3:{lower3}  CloseY:{closeY}')
                self.Debug(f'{symbol} -- U:{upper} L:{lower}  MA:{ma12}')
                cent = (openD + closeY) / 2
                R2 = cent + .5 * ma12
                S2 = cent - .5 * ma12

                
                if lower > upper3 and c.AdjustedPrice > (ma12):   #Added in .5 here, to make R2 S2
                    self.longs += [symbol]
                    
                if upper < lower3 and c.AdjustedPrice < (ma12):
                    self.shorts += [symbol]
            
            self.selected = self.longs + self.shorts
            self.Debug(f'{self.selected}')
            
        return self.selected
            
    
        
        
    def SelectFine(self, fine):
        pass
            
  
        
        
    def OnSecuritiesChanged(self, changes):
        self.Log(f"Added Securities: {[security.Symbol.Value for security in changes.AddedSecurities]}")
        
        insights = []
        for security in changes.RemovedSecurities:
            self.Liquidate(security.Symbol)
            #insights += [Insight.Price(security.Symbol, timedelta(weeks=99), InsightDirection.Flat)]
            #algorithm.SubscriptionManager.RemoveConsolidator(symbol, self.symbols[symbol].monthlyConsolidator)
            #algorithm.SubscriptionManager.RemoveConsolidator(symbol, self.symbols[symbol].dailyConsolidator)
        #self.EmitInsights(insights)
        
        

    def OnData(self, data):
        '''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
            Arguments:
                data: Slice object keyed by symbol containing the stock data
        '''
        
        if len(self.selected) == 0: return
    
        qty = .99 / len(self.selected)
        

        self.selected = [sym for sym in self.selected if data.ContainsKey(sym)]
        
        bar = data.Bars
        #Get daily open... For Timing the entries of longs / shorts.
        for symbol in self.selected:
            if not data.ContainsKey(symbol): continue
            sbar = bar[symbol]
            if symbol not in self.DOs:
                hist = self.History(symbol, 5, Resolution.Daily)
                self.DOs[symbol] = DailyOpen(hist)
            self.DOs[symbol].Update(sbar.Open) #Think this is right?
            todaysOpen = self.DOs[symbol].todaysOpen
        
            
        #and opend(0) > close //(15M Close) -- NEED to save OPEN of day!
        
        #Long Entries
        self.longs = [sym for sym in self.longs if sym in self.selected ]

        for symbol in self.longs:
            if self.Portfolio[symbol].IsLong: continue
            if not data.ContainsKey(symbol): continue
            sbar = bar[symbol]
            #self.Debug(f'open > close ? -- {todaysOpen} > {sbar.Close}')
            if todaysOpen > sbar.Close:
                self.SetHoldings(symbol, qty)
           
        ''' LONG ONLY   
        #Short Entries -- really just daily timing of them.
        self.shorts = [sym for sym in self.shorts if sym in self.selected]
        
        for symbol in self.shorts:
            if self.Portfolio[symbol].IsShort: continue
            if not data.ContainsKey(symbol): continue
            sbar = bar[symbol]
            #self.Debug(f'open < close ? --  {todaysOpen} < {sbar.Close}')
            if todaysOpen < sbar.Close:
                self.SetHoldings(symbol, -qty)
                #MAY need to increment entries today?
        '''

class DBB():
    #Need rolling window -- to ADD past DAILY bbs to this...
    def __init__(self,history): #symbol,
        #self.window = RollingWindow[float](50)
        self.closeDs = RollingWindow[float](2) #This is DAILY close
        #self.opens = RollingWindow[float](2) #Cannot add this, bc only closes passed.
        
        self.uppers = RollingWindow[float](5) #New Addit!
        self.lowers = RollingWindow[float](5)
        
        self.ub3 = None
        self.lb3 = None
        
        #self.uo = UltimateOscillator(9, 15, 24)   #self.symbol,
        self.bb = BollingerBands(20,2, MovingAverageType.Simple)
 
        self.ub = self.bb.UpperBand
        self.lb = self.bb.LowerBand
        #Unstacked one...
        for time, price in history.items():
            self.Update(time, price)

            
    def Update(self,time, price): #time,
        self.bb.Update(time,price)
        self.uppers.Add(self.ub.Current.Value) #Addits...
        self.lowers.Add(self.ub.Current.Value)

        self.closeDs.Add(price) 
        if self.IsReady:
            self.ub3 = self.uppers[3]
            self.lb3 = self.lowers[3]

    @property
    def IsReady(self):          #Addits...
        return self.bb.IsReady and self.uppers.IsReady and self.lowers.IsReady #self.uo.IsReady #and
        
class BB():
    '''15M BBs'''
    def __init__(self,symbol, algorithm, history):
        self.BB = BollingerBands(symbol,20,2, MovingAverageType.Simple) 
        
        # ADDED SYMBOL ^^^^ TO BB 
        self.symbol = symbol
        algorithm.AddEquity(self.symbol) #?? Need to add I guess.. OKAY!
        self.consolidator = TradeBarConsolidator(timedelta(minutes=15))
        algorithm.SubscriptionManager.AddConsolidator(symbol, self.consolidator) #NEW
        algorithm.RegisterIndicator(symbol, self.BB, self.consolidator)
        
        self.ub = self.BB.UpperBand
        self.lb = self.BB.LowerBand
        
        #MA Cons (NEW)
        self.MA = SimpleMovingAverage(12)
        self.ma_cons = TradeBarConsolidator(timedelta(days=1))
        algorithm.RegisterIndicator(symbol, self.MA, self.ma_cons)
        #self.ma = self.MA #.Current.Value
        
        #ZO ADDITS ************************
        for bar in history.itertuples(): #Manual update...
            tbar = TradeBar(bar.Index[1], symbol, bar.open, bar.high, bar.low, bar.close, bar.volume)
            self.consolidator.Update(tbar)
            self.ma_cons.Update(tbar)
            self.MA.Update(tbar.EndTime,tbar.Close) #JUST tbar input?
            self.BB.Update(tbar.EndTime,tbar.Close) 
    
        # *********************************
        #Register / Subscribe to event Don't think this is needed? ^^ that is register
        #self.consolidator.DataConsolidated += self.OnDataConsolidated
        
    @property
    def IsReady(self):
        return self.MA.IsReady and self.BB.IsReady
        
    '''
    #Dont think I need this?
    def OnDataConsolidated(self, sender, bar):
        #self.window.Add(bar.Close)
        self.BB.Update(bar.EndTime, bar.Close)   #Might JUST need to be index and bar -- if it's JUST closes?
        self.MA.Update(bar.EndTime, bar.Close)
        self.ub = self.BB.UpperBand
        self.lb = self.BB.LowerBand
        self.ma = self.MA
    '''
    
    


class DailyOpen():
    '''CAN just add TRADEBAR to window, then call w keys -- self.pastBars[0].Open, for ex'''
    def __init__(self, history):
        self.opens = RollingWindow[float](5)
        self.todaysOpen = 0
        for bar in history.itertuples():
        #for time, price in history.items(): symbol, WAS in tradeBar
            #tbar = TradeBar(bar.Index[1], bar.open, bar.high, bar.low, bar.close, bar.volume)
            #self.Update(tbar.Open)                         #Could simply do self.opens.Add(price.Open)
            self.opens.Add(bar.open)
            
            
    def Update(self, price):
        self.opens.Add(price)
        if self.opens.IsReady:
            self.todaysOpen = self.opens[0]
            
'''Better Version of ^^^^'''
class DailyBars():
    '''More efficient version of DailyOpens'''
    def __init__(self, history):
        self.daily_opens = RollingWindow[float](5)
        self.daily_closes = RollingWindow[float](5)
        self.daily_highs = RollingWindow[float](5)
        self.daily_lows = RollingWindow[float](5)
        for time, bar in history.items():
            self.Update(bar)
            
    def Update(self, bar):
        self.daily_opens.Add(bar.Open)
        self.daily_closes.Add(bar.Close)
        self.daily_highs.Add(bar.High)
        self.daily_lows.Add(bar.Low)

             
class Momentum():
    
    def __init__(self, history):
        self.window = RollingWindow[float](275)
        self.mom_yr = 0
        self.mom_mo = 0
        for row in history.itertuples():
            self.Update(row.close)
            
    def Update(self, price):
        self.window.Add(price)
        if self.window.IsReady:
            self.mom_yr = (self.window[25] - self.window[275]) / self.window[275] #Was [-252] and [-25]
            self.mom_mo = (self.window[0] - self.window[25]) / self.window[25]
            
            
class SymbolData:
    
    def __init__(self, algorithm, symbol):
        self.algorithm = algorithm
        self.symbol = symbol
        
        # Define daily and monthly rolling windows
        self.monthlyWindow = RollingWindow[TradeBar](13)
        self.dailyWindow = RollingWindow[TradeBar](280)
        
        # Define daily and monthly consolidators
        self.monthlyConsolidator = algorithm.Consolidate(symbol, Calendar.Monthly, self.OnMonthlyData)
        self.dailyConsolidator = TradeBarConsolidator(timedelta(days = 1))
        
        # Register daily consolistor to algorithm
        algorithm.SubscriptionManager.AddConsolidator(symbol, self.dailyConsolidator)
        
        # Define and register ADX indicator
        self.adxThreshold = 25
        self.adx = AverageDirectionalIndex(20)
        algorithm.RegisterIndicator(symbol, self.adx, self.dailyConsolidator)
        
        # Use historical data to warmup rolling windows, consolidators, and indicators
        history = algorithm.History(symbol, 280, Resolution.Daily)
        for bar in history.itertuples():
            tbar = TradeBar(bar.Index[1], symbol, bar.open, bar.high, bar.low, bar.close, bar.volume)
            self.dailyWindow.Add(tbar)
            self.monthlyConsolidator.Update(tbar)
            self.adx.Update(tbar)