Overall Statistics
Total Trades
167
Average Win
0.07%
Average Loss
-0.06%
Compounding Annual Return
17.230%
Drawdown
2.300%
Expectancy
-0.015
Net Profit
2.024%
Sharpe Ratio
1.859
Probabilistic Sharpe Ratio
61.249%
Loss Rate
56%
Win Rate
44%
Profit-Loss Ratio
1.26
Alpha
0.154
Beta
-0.015
Annual Standard Deviation
0.078
Annual Variance
0.006
Information Ratio
-3.879
Tracking Error
0.113
Treynor Ratio
-9.946
Total Fees
$167.00
'''
This strategy resolves around working with fundamentals and finding the best companies based on
- Free Cash Flow Yield 
- ROC value (Price Index)

It combines both of these values in necessary percentage to find the top 30 companies to invest in
All companies will have equal weightage
'''

from QuantConnect import Resolution, Extensions
from QuantConnect.Algorithm.Framework.Alphas import *
from QuantConnect.Algorithm.Framework.Portfolio import *
from itertools import groupby
from datetime import datetime, timedelta
class TheStrongOnes(QCAlgorithm):

    '''
    ROUGH GUIDELINES
        1.Decide on Universe (possibly Dollar volume)
        2.Sort the companies by ROC (12 monhts and then 6 monhts)
        3.Start with 1000 companies
        4.Take top 20% of the companies based on ROC
        5.Calculate the free cash flow yield for these 200 companies
        6.Sort high to Low and take the top 30 out of final 40
        7.Equal investment on all companies"

    ROUGH TRY FOR QUANTCONNECT GUIDANCE
        1. Coarse selection -  Find all with stocks with Fundamental data and price greater than $10 - DONE
        2. Fine selection - Find all stocks with Marketcap greater than 100M - DONE
        3. Check if we can run Insights generator on a monthly basis and do not run if it is not one month - NO NEED
        3.1 Calculate ROC from 1000 copmpanies and get 20% sorted high to low - DONE
        3.2 Calculate free cash flow on 200 companies now and find the top 30 out of it - DONE
        3.3 Generate Insghts Group for these 30 companies - NOT NEEDED
        4. Add Portfolio Construction to Equal weight to buy all these 30 companies - DONE
        5. Rebalance should happen automatically every month based on Insights group or may be Universe selection itself
    '''
    def Initialize(self):
        self.SetStartDate(2012, 1, 1) 
        self.SetEndDate(2012, 2, 15)
        self.SetCash(10000)
        self.UniverseSettings.Resolution = Resolution.Daily
        self.Settings.RebalancePortfolioOnSecurityChanges = True
        self.AddUniverse(self.CoarseSelectionFilter, self.FineSelectionFilter)
        self.SetPortfolioConstruction( EqualWeightingPortfolioConstructionModel() )
        self.AddAlpha(ConstantAlphaModel(InsightType.Price, InsightDirection.Up, timedelta(1)))
        self.SetExecution(ImmediateExecutionModel())
        self.numberOfSymbolsCoarse = 20
        self.numberOfSymbolsFine = 10
        self.current = self.Time - timedelta(31)
        
    def CoarseSelectionFilter(self, coarse):
        if (self.Time - self.current).days <= 30:
            return Universe.Unchanged
            
        sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True)   # sort descending by daily dollar volume
        return [ x.Symbol for x in sortedByDollarVolume if x.Price > 10 and x.HasFundamentalData][:self.numberOfSymbolsCoarse]  # return the symbol objects of the top entries from our sorted collection
    
    def FineSelectionFilter(self, fine): 
        if (self.Time - self.current).days <= 30:
            return Universe.Unchanged
        
        market_cap = {}
        
        # Calculate the market cap and add the "MarketCap" property to fine universe object
        for i in fine:
            market_cap[i] = (i.EarningReports.BasicAverageShares.ThreeMonths * i.EarningReports.BasicEPS.TwelveMonths * i.ValuationRatios.PERatio)

        filtered = [x for x in fine if market_cap[x] > 0]

        marketCapFilter = sorted(filtered, key=lambda x: market_cap[x])

        # marketCapFilter = [x for x in fine if x.Marketcap > 10000000]
        sortedByCashReturn = sorted(marketCapFilter, key=lambda x: x.ValuationRatios.CashReturn, reverse=True)[:200] 
        sortedByROIC = sorted(sortedByCashReturn, key=lambda x: x.OperationRatios.ROIC.OneYear)[:40]
        self.Debug('sortedByROIC -->'+ str(len(sortedByROIC)))
        return [ x.Symbol for x in sortedByROIC]

    def OnData(self, CoarseSelectionFilter):
        if not self.Portfolio.Invested:
            self.current = self.Time