Overall Statistics
Total Trades
3908
Average Win
0.08%
Average Loss
-0.06%
Compounding Annual Return
16.414%
Drawdown
31.900%
Expectancy
0.776
Net Profit
113.987%
Sharpe Ratio
0.637
Probabilistic Sharpe Ratio
14.063%
Loss Rate
28%
Win Rate
72%
Profit-Loss Ratio
1.46
Alpha
0.025
Beta
1.049
Annual Standard Deviation
0.209
Annual Variance
0.044
Information Ratio
0.262
Tracking Error
0.116
Treynor Ratio
0.127
Total Fees
$3967.87
Estimated Strategy Capacity
$120000.00
Lowest Capacity Asset
FORTY R735QTJ8XC9X
# g score investing updated

from AlgorithmImports import *
import statistics as stat
from collections import deque

class DynamicCalibratedGearbox(QCAlgorithm):

    def Initialize(self):        
        self.tech_ROA_key = 'TECH_ROA'
        self.SetStartDate(2017, 6, 1)  
        self.SetEndDate(2022, 6, 1)        
        self.SetCash(100000)        
        self.SetBrokerageModel(AlphaStreamsBrokerageModel())
        self.SetAlpha(ConstantAlphaModel(InsightType.Price, InsightDirection.Up, timedelta(days=31)))
        self.SetExecution(ImmediateExecutionModel())
        self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel(lambda time:None))        
        self.AddUniverseSelection(FineFundamentalUniverseSelectionModel(self.CoarseFilter, self.FineFilter))
        self.UniverseSettings.Resolution = Resolution.Daily        
        self.curr_month = -1
        self.tech_ROA = {}        
        self.symbols = None           
        self.quarters = 0    
        self.SetWarmUp(756, Resolution.Daily)
    

    
    def CoarseFilter(self, coarse):       

        if self.curr_month == self.Time.month:
            return Universe.Unchanged
        
        self.curr_month = self.Time.month
        if self.Time.month % 3 != 1:
            return Universe.Unchanged        
        self.quarters += 1
        
        return [c.Symbol for c in coarse if c.HasFundamentalData]

      
    def FineFilter(self, fine):
       
        tech_securities = [f for f in fine if f.AssetClassification.MorningstarSectorCode == MorningstarSectorCode.Technology and
                                                f.OperationRatios.ROA.ThreeMonths]
        
        for security in tech_securities:
            symbol = security.Symbol
            if symbol not in self.tech_ROA:
                self.tech_ROA[symbol] = deque(maxlen=12)
            self.tech_ROA[symbol].append(security.OperationRatios.ROA.ThreeMonths)

        if self.Time.month != 4 or (self.quarters < 12 ):
            return Universe.Unchanged

        tech_securities = [x for x in tech_securities if x.OperationRatios.ROA.OneYear and
                                                        x.FinancialStatements.CashFlowStatement.OperatingCashFlow.TwelveMonths and
                                                        x.FinancialStatements.BalanceSheet.TotalAssets.TwelveMonths and
                                                        x.FinancialStatements.IncomeStatement.ResearchAndDevelopment.TwelveMonths and
                                                        x.FinancialStatements.CashFlowStatement.CapExReported.TwelveMonths and
                                                        x.FinancialStatements.IncomeStatement.SellingGeneralAndAdministration.TwelveMonths and
                                                        x.MarketCap]

        tech_VARROA = {symbol:stat.variance(ROA) for symbol, ROA in self.tech_ROA.items() if len(ROA) == ROA.maxlen}
        
        if len(tech_VARROA) < 2:
            return Universe.Unchanged
        
        tech_VARROA_median = stat.median(tech_VARROA.values())
        tech_ROA1Y = {x.Symbol:x.OperationRatios.ROA.OneYear for x in tech_securities}
        tech_ROA1Y_median = stat.median(tech_ROA1Y.values())
        tech_CFROA = {x.Symbol: (
            x.FinancialStatements.CashFlowStatement.OperatingCashFlow.TwelveMonths 
            / x.FinancialStatements.BalanceSheet.TotalAssets.TwelveMonths
            ) for x in tech_securities}
        tech_CFROA_median = stat.median(tech_CFROA.values())

        tech_RD2MktCap = {x.Symbol: (
            x.FinancialStatements.IncomeStatement.ResearchAndDevelopment.TwelveMonths / x.MarketCap
            ) for x in tech_securities}
        tech_RD2MktCap_median = stat.median(tech_RD2MktCap.values()) 

        tech_CaPex2MktCap = {x.Symbol: (
            x.FinancialStatements.CashFlowStatement.CapExReported.TwelveMonths / x.MarketCap
            ) for x in tech_securities}
        tech_CaPex2MktCap_median = stat.median(tech_CaPex2MktCap.values())  

        tech_Ad2MktCap = {x.Symbol: (
            x.FinancialStatements.IncomeStatement.SellingGeneralAndAdministration.TwelveMonths / x.MarketCap
            ) for x in tech_securities}
        tech_Ad2MktCap_median = stat.median(tech_Ad2MktCap.values())

        has_book = [f for f in fine if f.FinancialStatements.BalanceSheet.NetTangibleAssets.TwelveMonths and f.MarketCap]
        sorted_by_BM = sorted(has_book, key=lambda x: x.FinancialStatements.BalanceSheet.NetTangibleAssets.TwelveMonths / x.MarketCap)[:len(has_book)//4]
        tech_symbols = [f.Symbol for f in sorted_by_BM if f in tech_securities]
        
        ratioDicts_medians = [(tech_ROA1Y, tech_ROA1Y_median), 
                                (tech_CFROA, tech_CFROA_median), (tech_RD2MktCap, tech_RD2MktCap_median),
                                (tech_CaPex2MktCap, tech_CaPex2MktCap_median), (tech_Ad2MktCap, tech_Ad2MktCap_median)]
        
        def compute_g_score(symbol):
            g_score = 0
            if tech_CFROA[symbol] > tech_ROA1Y[symbol]:
                g_score += 1
            if symbol in tech_VARROA and tech_VARROA[symbol] < tech_VARROA_median:
                g_score += 1
            for ratio_dict, median in ratioDicts_medians:
                if symbol in ratio_dict and ratio_dict[symbol] > median:
                    g_score += 1
            return g_score
 
        g_scores = {symbol:compute_g_score(symbol) for symbol in tech_symbols}
        
        return [symbol for symbol, g_score in g_scores.items() if g_score >= 5]