Overall Statistics |
Total Trades 6366 Average Win 0.01% Average Loss 0.00% Compounding Annual Return 29.905% Drawdown 5.200% Expectancy 0.305 Net Profit 6.897% Sharpe Ratio 1.323 Probabilistic Sharpe Ratio 54.826% Loss Rate 43% Win Rate 57% Profit-Loss Ratio 1.27 Alpha -0.272 Beta 0.972 Annual Standard Deviation 0.163 Annual Variance 0.027 Information Ratio -2.505 Tracking Error 0.114 Treynor Ratio 0.223 Total Fees $6366.00 Estimated Strategy Capacity $7400000.00 Lowest Capacity Asset TSM R735QTJ8XC9X |
#region imports from AlgorithmImports import * #endregion class StockSelectionStrategyBasedOnFundamentalFactorsAlgorithm(QCAlgorithm): def Initialize(self): self.SetStartDate(2020, 11, 1) # Set Start Date self.SetEndDate(2021, 2, 1) # Set End Date self.SetCash(100000) # Set Strategy Cash self.coarse_count = 10 #Num Equity Fund self.fund_count = 30 #Num Equity End self.end_count = 10 period=21 # for Indikators self.nextRebalance = self.Time # next balance time self.rebalanceDays = 90 # Rebalance quarterly self.Settings.RebalancePortfolioOnInsightChanges = False self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction) self.SetAlpha(ConstantAlphaModel(InsightType.Price, InsightDirection.Up, timedelta(90))) self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel(lambda time:self.nextRebalance)) self.Settings.RebalancePortfolioOnInsightChanges = False def CoarseSelectionFunction(self, coarse): if self.Time < self.nextRebalance: return Universe.Unchanged HasFundData = [x for x in coarse if x.HasFundamentalData] return [x.Symbol for x in HasFundData] def FineSelectionFunction(self, fine): if self.Time < self.nextRebalance: return Universe.Unchanged #Fundamental #sorting Fundamental sortedByMarketCap = sorted(fine, key=lambda x: x.MarketCap, reverse=True)[:self.coarse_count] return [i.Symbol for i in sortedByMarketCap] fine = [x for x in fine if x.ValuationRatios.SustainableGrowthRate >0.0001 and x.ValuationRatios.PERatio>0.0001 and x.ValuationRatios.FCFYield>0.0001] sortedByfactor1 = sorted(fine, key=lambda x: x.ValuationRatios.SustainableGrowthRate, reverse=True) sortedByfactor2 = sorted(fine, key=lambda x: x.ValuationRatios.PERatio, reverse=False) sortedByfactor3 = sorted(fine, key=lambda x: x.ValuationRatios.FCFYield, reverse=True) stock_dict = {} #ranking Fundamental for rank1, ele in enumerate(sortedByfactor1): rank2 = sortedByfactor2.index(ele) rank3 = sortedByfactor3.index(ele) stock_dict[ele] = rank1 + rank2 + rank3 fund_sorted_stock = sorted(stock_dict.items(), key=lambda d:d[1], reverse=True)[:self.fund_count] return [i.Symbol for i in fund_sorted_stock] #technical #prep technical filter self.SerWarmUp(period) for symbol in fund_sorted_stock: self.AddEquity(symbol, Resolution.Daily) self.dataSMA[symbol] = self.SMA(symbol, period, Resolution.Daily) self.dataMom[symbol] = self.MOM(symbol, period, Resolution.Daily) price = self.Securities[symbol].Price faktorSMA = price/dataSMA #technical filter sortedBySMA = sorted(fine, key=lambda x: x.faktorSMA, reverse=True) sortedByMom = sorted(fine, key=lambda x: x.dataMom, reverse=False) stock_dict = {} #renking technsicher Filter for rank1, ele in enumerate(sortedBySMA): rank2 = sortedByMom.index(ele) stock_dict[ele] = rank1 + rank2 sorted_stock = sorted(stock_dict.items(), key=lambda d:d[1], reverse=True)[:self.end_count] return [i.Symbol for i in sorted_stock] def rebalance(self): # if this month the stock are not going to be long/short, liquidate it. for i in self.Portfolio.Values: if (i.Invested) and (i not in sorted_stock): self.Liquidate(i.Symbol) # Assign each stock equally. Alternatively you can design your own portfolio construction method for i in sorted_stock: self.SetHoldings(i, 0.9/self.end_count) #for i in self.short: self.nextRebalance += timedelta(self.rebalanceDays)