Overall Statistics
Total Trades
764
Average Win
0.73%
Average Loss
-0.39%
Compounding Annual Return
8.255%
Drawdown
41.500%
Expectancy
1.057
Net Profit
436.208%
Sharpe Ratio
0.618
Probabilistic Sharpe Ratio
1.797%
Loss Rate
29%
Win Rate
71%
Profit-Loss Ratio
1.88
Alpha
0.077
Beta
-0.023
Annual Standard Deviation
0.122
Annual Variance
0.015
Information Ratio
0.023
Tracking Error
0.218
Treynor Ratio
-3.317
Total Fees
$2677.14
from QuantConnect import Resolution
from QuantConnect.Algorithm import QCAlgorithm


class NCAVsimple(QCAlgorithm):
    def Initialize(self):
        #rebalancing should occur in July
        self.SetStartDate(2000, 1, 1)  
        self.SetCash(100000) 
        self.UniverseSettings.Resolution = Resolution.Daily

        self.filtered_fine = None
        self.filtered_coarse = None
        self.symbol = self.AddEquity('SPY', Resolution.Daily).Symbol

        # self.SetSecurityInitializer(lambda x: x.SetMarketPrice(self.GetLastKnownPrice(x)))
        
        self.yearly_rebalance = False
        self.AddUniverse(self.CoarseSelectionFunction,self.FineSelectionFunction)
        self.Schedule.On(self.DateRules.MonthEnd(self.symbol), self.TimeRules.AfterMarketOpen(self.symbol), self.rebalance)
        
    def CoarseSelectionFunction(self, coarse):
        if self.yearly_rebalance:
            # drop stocks which have no fundamental data or have low price
            self.filtered_coarse = [x.Symbol for x in coarse if (x.HasFundamentalData) and x.Market == 'usa']
            return self.filtered_coarse
        else: 
            return Universe.Unchanged      
    
    def FineSelectionFunction(self, fine):
        if self.yearly_rebalance:
            #calculate the NCAV/MV and add the property to fine universe object
            #filters out the companies in the financial sector as suggested
            fine = [x for x in fine if (float(x.FinancialStatements.BalanceSheet.CurrentAssets.Value) > 0) 
                                    and (float(x.EarningReports.BasicAverageShares.Value) > 0)
                                    and (float(x.FinancialStatements.BalanceSheet.CurrentLiabilities.Value) > 0)
                                    and (float(x.MarketCap) > 0)
                                    #  This indicator will denote which one of the six industry data collection templates applies to the company. 
                                    # Each industry data collection template includes data elements that are commonly reported by companies in that industry. 
                                    # N=Normal (Manufacturing), M=Mining, U=Utility, T=Transportation, B=Bank, I=Insurance 
                                    and (x.CompanyReference.IndustryTemplateCode!="B")
                                    and (x.CompanyReference.IndustryTemplateCode!="I")]
            fine = sorted(fine, key = lambda x:x.MarketCap, reverse=True)
            self.Debug("fine len: " + str(len(fine)))
            
            for i in fine:
                #calculates the net current asset value per share
                self.Debug(i.Symbol)
                total_liabilities = i.FinancialStatements.BalanceSheet.TotalLiabilitiesAsReported.TwelveMonths
                current_assets = i.FinancialStatements.BalanceSheet.CurrentAssets.TwelveMonths
                i.ncav = (current_assets - total_liabilities)/float(i.MarketCap)
                if i.ncav > 1.5:
                    self.Debug("-total_liabilities: " + str(total_liabilities))
                    self.Debug("-current_assets: " + str(current_assets))
                    self.Debug("-market_cap: " + str(i.MarketCap))
                    self.Debug("-ncav: " + str(i.ncav))
                    
            # keeps all symbols that have a NCAV/MV higher than 1.5
            # sorted_fine = sorted(fine, lambda x: x.ncav)
            self.filtered_fine = [i.Symbol for i in fine if (i.ncav > 1.5)]
            return self.filtered_fine[:25]
        else:
            return []
    
    def rebalance(self):
        #yearly rebalance
        if self.Time.month == 7:
            self.Debug("Rebalance" + str(self.Time))
            self.yearly_rebalance = True
        
    def OnData(self, data):
        if not self.yearly_rebalance: return 
        if self.filtered_fine:
            stocks_invested = [x.Key for x in self.Portfolio]
            for i in stocks_invested:
                #liquidate the stocks not in the filtered NCAV/MV list
                if i not in self.filtered_fine:
                    self.Liquidate(i) 
                #purchase the stocks in the list
                elif i in self.filtered_fine:
                    self.SetHoldings(i, 1/len(self.filtered_fine))
            self.yearly_rebalance = False