Overall Statistics
Total Trades
4320
Average Win
0.43%
Average Loss
-0.34%
Compounding Annual Return
10.452%
Drawdown
28.600%
Expectancy
0.078
Net Profit
172.523%
Sharpe Ratio
0.746
Loss Rate
53%
Win Rate
47%
Profit-Loss Ratio
1.27
Alpha
0.215
Beta
-7.209
Annual Standard Deviation
0.123
Annual Variance
0.015
Information Ratio
0.608
Tracking Error
0.123
Treynor Ratio
-0.013
Total Fees
$12778.12
 
 
class AssetGrowth(QCAlgorithm):

    def Initialize(self):
        #rebalancing should occur in July
        self.SetStartDate(2008,6,15)  #Set Start Date
        self.SetEndDate(2018,7,15)    #Set End Date
        self.SetCash(1000000)           #Set Strategy Cash
        self.UniverseSettings.Resolution = Resolution.Daily
        self.previous_fine = None
        self.filtered_fine = None
        self.AddUniverse(self.CoarseSelectionFunction,self.FineSelectionFunction)
        self.AddEquity("SPY", Resolution.Daily)
        #monthly scheduled event but will only rebalance once a year
        self.Schedule.On(self.DateRules.MonthEnd("SPY"), self.TimeRules.At(23, 0), self.rebalance)
        self.months = -1
        self.yearly_rebalance = False
        
    def CoarseSelectionFunction(self, coarse):
        if self.yearly_rebalance:
            # drop stocks which have no fundamental data
            filtered_coarse = [x.Symbol for x in coarse if (x.HasFundamentalData)
                                                            and (x.Market == "usa")]
            return filtered_coarse
        else: 
            return []

    def FineSelectionFunction(self, fine):
        if self.yearly_rebalance:
            fine = [x for x in fine if x.FinancialStatements.BalanceSheet.TotalAssets.Value > 0
                    and ((x.SecurityReference.ExchangeId == "NYS") or (x.SecurityReference.ExchangeId == "NAS") or (x.SecurityReference.ExchangeId == "ASE"))
                    and (x.CompanyReference.IndustryTemplateCode!="B")
                    and (x.CompanyReference.IndustryTemplateCode!="I")]
            if not self.previous_fine:
                #will wait one year in order to have the historical fundamental data
                self.previous_fine = fine
                self.yearly_rebalance = False
                return []
            else:
                #will calculate and sort the stocks on asset growth
                self.filtered_fine = self.Calculate(fine,self.previous_fine)
                sorted_filter = sorted(self.filtered_fine, key=lambda x: x.delta_assets)
                self.filtered_fine = [i.Symbol for i in sorted_filter]
                #we save the fine data for the next year's analysis
                self.previous_fine = fine
                return self.filtered_fine
        else:
            return []
    
    def Calculate(self, current, previous):
        growth = []
        for stock_data in current:
            #compares this and last year's fine fundamental objects
            try:
                prev_data = None
                for x in previous:
                    if x.Symbol == stock_data.Symbol:
                        prev_data = x
                        break
                #growth = (tota_assets(t)-total_assets(t-1))/total_assets(t-1)    
                stock_data.delta_assets = (float(stock_data.FinancialStatements.BalanceSheet.TotalAssets.Value)-float(prev_data.FinancialStatements.BalanceSheet.TotalAssets.Value))/float(prev_data.FinancialStatements.BalanceSheet.TotalAssets.Value) 
                growth.append(stock_data)
            except:
                #value in current universe does not exist in the previous universe
                pass
        return growth
    
    def rebalance(self):
        #yearly rebalance
        self.months+=1
        if self.months%12 == 0:
            self.yearly_rebalance = True
            self.Debug("true")

    def OnData(self, data):
        if not self.yearly_rebalance: return 
        if self.filtered_fine:
            self.Debug("inside")
            portfolio_size = int(len(self.filtered_fine)/10)
            #pick the upper decile to short and the lower decile to long
            short_stocks = self.filtered_fine[-portfolio_size:]
            long_stocks = self.filtered_fine[:portfolio_size]
            stocks_invested = [x.Key for x in self.Portfolio]
            for i in stocks_invested:
                if i not in self.filtered_fine:
                    self.Liquidate(i) 
                #long the stocks in the list
                elif i in long_stocks:
                    self.SetHoldings(i, 1/(portfolio_size*2))
                #short the stocks in the list
                elif i in short_stocks:
                    self.SetHoldings(i,-1/(portfolio_size*2))
            self.yearly_rebalance = False
            self.filtered_fine = False