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();
        }
    }

}