Overall Statistics
import numpy as np



class CalibratedTransdimensionalComputer(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2018, 10, 1)  # Set Start Date
        self.SetEndDate(2018,11,1)

        self.SetCash(1000000)  # Set Strategy Cash
        self.UniverseSettings.Resolution = Resolution.Daily
        self.AddUniverse(self.CoarseSelectionFunction)
        self.symbols = []
        #store the maximum prices
        self.historicalhigh = {}
        self.ma10 = {}
        self.init_flag = True
        
        
    def OnData(self, data):
        long_list = []
        for symbol in self.symbols:
            if data.ContainsKey(symbol) and data[symbol] is not None and symbol in self.ma10.keys():
                
                self.ma10[symbol].Add(data[symbol].Close)
                
                if data[symbol].Close > self.historicalhigh[symbol][0]:
                
                    self.historicalhigh[symbol].Add(data[symbol].Close)
                    long_list.append(symbol)
 
        self.Log(f'{self.Time}: rollling updated')    
        
        if self.Portfolio.Invested:
            for symbol in self.Portfolio.Keys:
                if symbol in self.ma10.keys() and self.Portfolio[symbol].Invested:
                    ma10 = 0.0
                    for i in range(0,10):
                        ma10 += self.ma10[symbol][i]
                    ma10 = ma10/10
                    if self.ma10[symbol][0] <= ma10:
                        self.Liquidate(symbol)


        self.Log(f'{self.Time}: liquidation finished')

        for symbol in long_list:
            if not self.Portfolio[symbol].Invested and self.Portfolio.MarginRemaining > 1/len(long_list)*self.Portfolio.TotalPortfolioValue:
                self.SetHoldings(symbol, 1/len(long_list))
        self.Log(f'{self.Time}: order placement finished')    
        
    def CoarseSelectionFunction(self, coarse):
        self.Log(f'{self.Time}: Coarse begins')
        selected = [x for x in coarse if x.HasFundamentalData and x.Price > 3]
        filtered = sorted(selected, key=lambda x: x.DollarVolume, reverse=True)
        if len(coarse) == 0:
            self.Log(f'{self.Time}: No data for coarse!')
            return self.symbols
        else:
            self.symbols = [x.Symbol for x in filtered[:30]]
            

        
        if self.init_flag:
            #I don't know why hist.fillna() doesn't work so I have to address NaN at line:90/91
            self.inti_flag = False
            hist = self.History(self.symbols, 252*5, Resolution.Daily).fillna(method= 'pad')
            hist = hist.fillna(hist.sum(axis = 0)/hist.notnull().sum())
            hist = hist.fillna(0)
            hist = hist.close.unstack(level=0)
            self.Log(f'Numbers of NaN: {hist.isnull().sum().sum()}')
            for symbol in self.symbols:
                if not symbol in self.historicalhigh.keys():
                    self.historicalhigh[symbol] = RollingWindow[Decimal](1)
    
                if str(symbol) in hist.columns and symbol in self.historicalhigh.keys():
                    self.historicalhigh[symbol].Add(np.max(hist[str(symbol)]))
                else:
                    self.symbols.remove(symbol)
                    
            for symbol in self.symbols:
                if not symbol in self.ma10.keys():
                    self.ma10[symbol] = RollingWindow[Decimal](10)
    
                if str(symbol) in hist.columns and symbol in self.ma10.keys():
                    self.Log(f'{str(symbol)} begin to be added into self.ma10')
                    for i in range(-1,-11,-1):
                        self.Log(f'{i}: {hist[str(symbol)][i]}')
                        if np.isnan(hist[str(symbol)][i]):
                            hist[str(symbol)][i] = 0
                        self.ma10[symbol].Add(hist[str(symbol)][i])
                    self.Log(f'{str(symbol)} finish to be added into self.ma10')

          
                
        self.Log(f'{self.Time}: CoarseSelection finished')
        return self.symbols