Overall Statistics |
Total Trades 390 Average Win 0.24% Average Loss -0.21% Compounding Annual Return 18.615% Drawdown 5.300% Expectancy 0.416 Net Profit 21.933% Sharpe Ratio 1.835 Loss Rate 33% Win Rate 67% Profit-Loss Ratio 1.12 Alpha 0.129 Beta 1.967 Annual Standard Deviation 0.09 Annual Variance 0.008 Information Ratio 1.625 Tracking Error 0.09 Treynor Ratio 0.084 Total Fees $487.23 |
# Strategy : Rebalancing Portfolio on Day 1 of the Every Month based on the fundamental data and liquidity of stock # Backtest Result : Creative Red Butterfly import numpy as np import datetime as dt from datetime import datetime,timedelta class QCAlgorithm(QCAlgorithm): def Initialize(self): # Backtest Parameters self.SetStartDate(2013,12,31) self.SetEndDate(2015,3,1) self.SetCash(100000.00) # Setting Daily Resolution for all Securities in Universe. self.UniverseSettings.Resolution = Resolution.Daily #Adding Universe based on the defined filters self.AddUniverse(self.MyCoarseUniverse,self.MyFineUniverse) # Brokerage Model self.SetBrokerageModel(BrokerageName.Default, AccountType.Cash) self.SetTimeZone(TimeZones.NewYork) #reference check for the developing new portfolio while rebalancing whether securities has changed self._changes = None # Schedule Rebalancing of Portfolio on Starting of the Month at 10 AM. self.Schedule.On(self.DateRules.MonthStart(), self.TimeRules.At(10, 00), Action(self.Rebalance)) # define first filter which will filter the stocks based on the Dollervolume and if it has fundamental deta available # so that we can run those stocks through second filter. def MyCoarseUniverse(self,coarse): for x in coarse: # sorting of stocks based on dollervolume in descending order sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True) # filter if the stock has dollarvolume of more than 1000000 and has fundamentaldata filtered = [ x.Symbol for x in sortedByDollarVolume if x.DollarVolume > 1000000 and x.HasFundamentalData == True] #return first 1000 such stocks that we will feed in our second "fine" filter return filtered[:1000] # The output of the coarse function will in this function for second filter def MyFineUniverse(self,fine): #sort stocks based on the EV / EBITDA in descending order sortedByEVRatio = sorted(fine, key=lambda x: x.ValuationRatios.EVToEBITDA, reverse=True) # filter the stock list which has BookValue per share less than 1. ( These stocks's potential has not been realised due to market sentiments) filtered = [x.Symbol for x in sortedByEVRatio if x.ValuationRatios.BookValuePerShare <= 1] return filtered[:50] def OnSecuritiesChanged(self, changes): # changes in our security Universe will change the value of our reference variable defined in Initialize. # It will have the information of addedsecurity and removed security which we will use to buy and liquidate security from our existing portfolio to rebalance. self._changes = changes # ScheduledOn will triger this function on month start as defined in Initialize def Rebalance(self): # check the day of datetime object if it is first day of the month if "No", do nothing and return if self.Time.day != 1 : return self.Debug(" No Need to Rebalance, Month :" + str(self.Time.month)) else : self.Debug(" Portfolio will be Rebalanced , Month :" + str(self.Time.month) + "Day :" + str(self.Time.day)) # OnSecurityChanged will change the value of reference variable through which we get to know if there is change in our Universe #If the variable is "None" that means no security has been added and removed from our universe. It will keep our portfolio as it is. if not self._changes is None : # give equal weight to security that has been added in the universe if len(self._changes.AddedSecurities) == 0: weightage = 0.5 else : weightage = 1/len(self._changes.AddedSecurities) # liquidate portfolio if self.Portfolio.Invested: self.Liquidate() # invest in added securities based on predetermined weightage for x in self._changes.AddedSecurities: self.Debug("Security Weightage : " + str(weightage)) self.SetHoldings(x.Symbol,weightage) self.Debug("Portfolio Rebalanced") # change the value of variable again to None. self._changes = None