Overall Statistics |
Total Trades 210 Average Win 0.06% Average Loss -0.06% Compounding Annual Return 216.373% Drawdown 1.200% Expectancy 0.642 Net Profit 3.206% Sharpe Ratio 6.366 Loss Rate 17% Win Rate 83% Profit-Loss Ratio 0.97 Alpha 1.161 Beta -1.518 Annual Standard Deviation 0.126 Annual Variance 0.016 Information Ratio 3.849 Tracking Error 0.148 Treynor Ratio -0.529 Total Fees $1408.42 |
namespace QuantConnect.Algorithm.CSharp { public class ValuedSecurity { public FineFundamental sec; public decimal roc; public decimal EY; public int rocRank; public int EYRank; } public class LittleBookAlgorithm : QCAlgorithm { public override void Initialize() { SetStartDate(2019, 9, 10); //Set Start Date 1998 is the minimum start date SetCash(1000000); //Set Strategy Cash // AddEquity("SPY", Resolution.Minute); SetAlpha(new ConstantAlphaModel(InsightType.Price, InsightDirection.Up, TimeSpan.FromDays(365))); SetExecution(new ImmediateExecutionModel()); SetPortfolioConstruction(new EqualWeightingPortfolioConstructionModel()); //SetRiskManagement(new MaximumDrawdownPercentPerSecurity(0.01m)); SetUniverseSelection(new FineFundamentalUniverseSelectionModel(CoarseSelectionFunction, FineSelectionFunction)); } /// OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here. /// Slice object keyed by symbol containing the stock data public override void OnData(Slice data) { // if (!Portfolio.Invested) // { // SetHoldings(_spy, 1); // Debug("Purchased Stock"); //} } // sort the data by daily dollar volume and take the top 'NumberOfSymbols' public IEnumerable<Symbol> CoarseSelectionFunction(IEnumerable<CoarseFundamental> coarse) { var numberOfSymbolsCoarse = 3500; // select only symbols with fundamental data and sort descending by daily dollar volume var sortedByDollarVolume = coarse .Where(x => x.HasFundamentalData && !x.Symbol.Value.EndsWith("ADR")) .OrderByDescending(x => x.DollarVolume); // take the top entries from our sorted collection var top5 = sortedByDollarVolume.Take(numberOfSymbolsCoarse); // we need to return only the symbol objects return top5.Select(x => x.Symbol); } // sort by roc + earning_yield, take the top 20 public IEnumerable<Symbol> FineSelectionFunction(IEnumerable<FineFundamental> fine) { var numberOfSymbolsFine = 30; // take the top entries from our sorted collection var topFine = ValueSecurities(fine).Take(numberOfSymbolsFine); // we need to return only the symbol objects return topFine.Select(x => x.sec.Symbol); } public IEnumerable<ValuedSecurity> ValueSecurities(IEnumerable<FineFundamental> fine) { // first calculate the values for each var valuedList = fine //ensure all the needed variables exist .Where(x => x.FinancialStatements.IncomeStatement.EBIT != 0.0m && x.FinancialStatements.BalanceSheet.WorkingCapital != 0.0m && x.FinancialStatements.BalanceSheet.NetTangibleAssets != 0.0m && x.ValuationRatios.EarningYield != 0.0m // some limits set by the book && x.OperationRatios.ROA > 0.25m && x.ValuationRatios.PERatio >= 5m && x.AssetClassification.MorningstarIndustryGroupCode != MorningstarSectorCode.Utilities && x.AssetClassification.MorningstarIndustryGroupCode != MorningstarSectorCode.FinancialServices ) .Select((x) => new ValuedSecurity() { sec = x, roc = (x.FinancialStatements.IncomeStatement.EBIT / (x.FinancialStatements.BalanceSheet.WorkingCapital + x.FinancialStatements.BalanceSheet.NetTangibleAssets) ), EY = x.ValuationRatios.EarningYield }); // next get the rank number for each valuedList = valuedList.OrderByDescending((v) => v.roc).Select((val, i) => { val.rocRank = i; return val; }); valuedList = valuedList.OrderByDescending((v) => v.EY).Select((val, i) => { val.EYRank = i; return val; }); return valuedList.OrderBy(v => v.rocRank + v.EYRank).ToList(); } } }