Overall Statistics
Total Trades
183
Average Win
0.39%
Average Loss
-0.02%
Compounding Annual Return
1.823%
Drawdown
13.200%
Expectancy
3.768
Net Profit
1.823%
Sharpe Ratio
0.162
Probabilistic Sharpe Ratio
15.597%
Loss Rate
82%
Win Rate
18%
Profit-Loss Ratio
25.52
Alpha
-0.144
Beta
0.755
Annual Standard Deviation
0.13
Annual Variance
0.017
Information Ratio
-1.764
Tracking Error
0.112
Treynor Ratio
0.028
Total Fees
$253.15
Estimated Strategy Capacity
$26000000.00
Lowest Capacity Asset
AGNC U2N08SGALPWL
Portfolio Turnover
2.13%
from AlgorithmImports import *
from Selection.FundamentalUniverseSelectionModel import FundamentalUniverseSelectionModel

class EquitiesFundamentalSelectionModel(FundamentalUniverseSelectionModel):

    def __init__(self, universe_settings: UniverseSettings = None) -> None:
        self.nextRefreshTimeUtc = datetime.min
        self.month = 0
        self.num_coarse = 500
        self.sectors = [MorningstarSectorCode.FinancialServices, MorningstarSectorCode.RealEstate,
                        MorningstarSectorCode.Healthcare, MorningstarSectorCode.Utilities, MorningstarSectorCode.Technology]
        super().__init__(True, universe_settings)

    '''
    Required method for all fundamental selection model
    The coarse fundamental selection relies on the CoarseFundamental data
    '''
    def SelectCoarse(self, algorithm: QCAlgorithm, coarse: List[CoarseFundamental]) -> List[Symbol]:
        self.nextRefreshTimeUtc = Expiry.EndOfQuarter(algorithm.UtcTime)
        selected = sorted([x for x in coarse if x.Price > 5], 
                          key=lambda x: x.DollarVolume, 
                          reverse=True)

        return [x.Symbol for x in selected[:self.num_coarse]]

    '''
    Optional method for a fundamental selection model
    The fine fundamental selection relies on the FineFundamental data
    '''
    def SelectFine(self, algorithm: QCAlgorithm, fine: List[FineFundamental]) -> List[Symbol]:
        filtered_fine = [x.Symbol for x in fine
                         if x.SecurityReference.IPODate + timedelta(5*365) < algorithm.Time and
                         x.AssetClassification.MorningstarSectorCode in self.sectors and
                         x.OperationRatios.ROE.Value > 0 and
                         x.OperationRatios.NetMargin.Value > 0 and
                         x.ValuationRatios.PERatio > 0]

        return filtered_fine

    '''
    Ensure that this model selection only runs once each quarter
    '''
    def GetNextRefreshTimeUtc(self):
        return self.nextRefreshTimeUtc
from AlgorithmImports import *

class FundamentalFactorAlphaModel(AlphaModel):

    def __init__(self) -> None:
        self.rebalanceTime = datetime.min
        self.sectors = {}

    def Update(self, algorithm: QCAlgorithm, data: Slice) -> Iterable[Insight]:
        insights = []

        if algorithm.Time < self.rebalanceTime:
            return insights
        self.rebalanceTime = Expiry.EndOfQuarter(algorithm.Time)

        for sector in self.sectors:
            securities = self.sectors[sector]
            sortedByROE = sorted(cast(
                Iterable[Security], securities), key=lambda x: x.Fundamentals.OperationRatios.ROE.Value, reverse=True)
            sortedByPM = sorted(cast(
                Iterable[Security], securities), key=lambda x: x.Fundamentals.OperationRatios.NetMargin.Value, reverse=True)
            sortedByPE = sorted(cast(
                Iterable[Security], securities), key=lambda x: x.Fundamentals.ValuationRatios.PERatio, reverse=True)

        scores = {}

        for security in cast(Iterable[Security], securities):
            score = sum([sortedByROE.index(security), sortedByPM.index(
                security), sortedByPE.index(security)])
            scores[security] = score

        length = max(int(len(scores)/5), 1)
        for security in sorted(scores.items(), key=lambda x: x[1], reverse=False)[:length]:
            symbol = security[0].Symbol
            insights.append(Insight.Price(
                symbol, Expiry.EndOfQuarter, InsightDirection.Up))

        return insights

    def OnSecuritiesChanged(self, algorithm: QCAlgorithm, changes: SecurityChanges) -> None:
        for security in changes.RemovedSecurities:
            for sector in self.sectors:
                if security in self.sectors[sector]:
                    self.sectors[sector].remove(security)

        for security in changes.AddedSecurities:
            sector = security.Fundamentals.AssetClassification.MorningstarSectorCode
            if sector not in self.sectors:
                self.sectors[sector] = set()
            self.sectors[sector].add(security)
from AlgorithmImports import *
from EquitiesFundamentalSelectionModel import *
from FundamentalFactorAlphaModel import *

class EquitiesTemplate(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2013, 1, 1)  # Set Start Date
        self.SetEndDate(2014, 1, 1)  # Set End Date
        self.SetCash(100000)  # Set Strategy Cash

        self.UniverseSettings.Resolution = Resolution.Daily
        self.AddUniverseSelection(EquitiesFundamentalSelectionModel(self.UniverseSettings))
        
        self.AddAlpha(FundamentalFactorAlphaModel())
        
        self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel(lambda t: Expiry.EndOfQuarter(t)))