| Overall Statistics |
|
Total Trades 2388 Average Win 0.71% Average Loss -0.32% Compounding Annual Return 25.608% Drawdown 60.800% Expectancy 1.341 Net Profit 12410.150% Sharpe Ratio 1.024 Probabilistic Sharpe Ratio 32.039% Loss Rate 28% Win Rate 72% Profit-Loss Ratio 2.25 Alpha 0.242 Beta -0.071 Annual Standard Deviation 0.231 Annual Variance 0.054 Information Ratio 0.558 Tracking Error 0.299 Treynor Ratio -3.363 Total Fees $73801.59 |
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.coarse_count = 3000
# 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)]
fine = [x for x in fine if x.EarningReports.BasicAverageShares.ThreeMonths > 0 and x.MarketCap != 0 and x.ValuationRatios.WorkingCapitalPerShare != 0]
sorted_by_market_cap = sorted(fine, key = lambda x:x.MarketCap, reverse=True)
top_by_market_cap = [x for x in sorted_by_market_cap[:self.coarse_count]]
# NCAV/MV calc.
# self.filtered_fine = [x.Symbol for x in top_by_market_cap if ((x.ValuationRatios.WorkingCapitalPerShare * x.EarningReports.BasicAverageShares.ThreeMonths) / x.MarketCap) > 1.5]
self.filtered_fine = [x.Symbol for x in top_by_market_cap if ((x.FinancialStatements.BalanceSheet.CurrentAssets.TwelveMonths - x.FinancialStatements.BalanceSheet.TotalLiabilitiesAsReported.TwelveMonths) / x.MarketCap) > 1.5]
return self.filtered_fine
else:
return []
def rebalance(self):
#yearly rebalance
if self.Time.month == 6:
self.Debug("Rebalance" + str(self.Time))
self.yearly_rebalance = True
def OnData(self, data):
if not self.yearly_rebalance: return
stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested]
for symbol in stocks_invested:
if symbol not in self.filtered_fine:
self.Liquidate(symbol)
for symbol in self.filtered_fine:
if self.Securities[symbol].Price != 0 and self.Securities[symbol].IsTradable: # Prevent error message.
self.SetHoldings(symbol, 1 / len(self.filtered_fine))
self.yearly_rebalance = False