Overall Statistics
Total Trades
10001
Average Win
0.04%
Average Loss
-0.03%
Compounding Annual Return
2.659%
Drawdown
12.900%
Expectancy
0.120
Net Profit
18.544%
Sharpe Ratio
0.568
Loss Rate
52%
Win Rate
48%
Profit-Loss Ratio
1.32
Alpha
-0.006
Beta
1.695
Annual Standard Deviation
0.04
Annual Variance
0.002
Information Ratio
0.15
Tracking Error
0.04
Treynor Ratio
0.013
Total Fees
$10683.04
import operator
from math import ceil,floor


class CoarseFineFundamentalComboAlgorithm(QCAlgorithm):

    def Initialize(self):

        self.SetStartDate(2000,9,9)  # Set Start Date
        self.SetEndDate(2018,9,9)    # Set End Date
        self.SetCash(100000)          # Set Strategy Cash
        self.flag1 = 1
        self.flag2 = 0
        self.flag3 = 0
        self.UniverseSettings.Resolution = Resolution.Minute        
        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)
        self.AddEquity("SPY")
        self.numberOfSymbols = 300
        self.numberOfSymbolsFine = 10
        self.num_portfolios = 6
        self._changes = None
        self.Schedule.On(self.DateRules.MonthStart("SPY"), self.TimeRules.AfterMarketOpen("SPY"), Action(self.Rebalancing))
        self.window = RollingWindow[TradeBar](2)
        self.SetWarmUp(20)
        
        

    def CoarseSelectionFunction(self, coarse):
        if self.flag1:
            CoarseWithFundamental = [x for x in coarse if x.HasFundamentalData]
            sortedByDollarVolume = sorted(CoarseWithFundamental, key=lambda x: x.DollarVolume, reverse=True) 
            top = sortedByDollarVolume[:self.numberOfSymbols]
            return [i.Symbol for i in top]
        else:
            return []


    def FineSelectionFunction(self, fine):
        if self.flag1:
            self.flag1 = 0
            self.flag2 = 1
        
            filtered_fine = [x for x in fine if x.FinancialStatements.IncomeStatement.EBIT.ThreeMonths
                                            and x.FinancialStatements.BalanceSheet.InvestedCapital.ThreeMonths
                                            and x.FinancialStatements.BalanceSheet.PreferredStock.ThreeMonths]
        

            
            
            sortedByROIC = sorted(filtered_fine, key=lambda x: (x.FinancialStatements.IncomeStatement.EBIT.ThreeMonths)/((x.FinancialStatements.BalanceSheet.InvestedCapital.ThreeMonths)+(x.FinancialStatements.BalanceSheet.PreferredStock.ThreeMonths)), reverse=True)
           
            # The FinancialStatements is the property of elements in filtered_fine, so you need to basically say "from the data in filtered_fine, take x, y and z and do this function, and return the answer as sortedbyROIC.
            
            #financial data comes in quaters i.e Three Month periods, therefore make sure it is three months so that there is no 0 on denominator. 
            
            return [i.Symbol for i in sortedByROIC]
          
            num_stocks = floor(len(filtered_fine)/self.num_portfolios)
        
            stock_dict = {}
            
            for i,ele in enumerate(ROIC):
                rank1 = i
                
                score = [ceil(rank1/num_stocks)]
                score = sum(score)
                stock_dict[ele] = score
        
            self.sorted_stock = sorted(stock_dict.items(), key=lambda d:d[1],reverse=True)
            sorted_symbol = [self.sorted_stock[i][0] for i in range(len(self.sorted_stock))]
            topFine = sorted_symbol[:self.numberOfSymbolsFine]
            
            self.flag3 = self.flag3 + 1
            
            return [i.Symbol for i in topFine]


        else:
            return [] 
            




    def OnData(self, data):
        
        if self.flag3 > 0:
            if self.flag2 == 1:
                self.flag2 = 0
    
        if self._changes == None: return
                
        for security in self._changes.RemovedSecurities:
            if security.Invested:
                self.Liquidate(security.Symbol)
                 
        for security in self._changes.AddedSecurities:
            self.SetHoldings(security.Symbol, 0.8/float(len(self._changes.AddedSecurities)))    
         
        self._changes = None
                    
        


    def OnSecuritiesChanged(self, changes):
        self._changes = changes
    
    def Rebalancing(self):
        self.flag1 = 1