Overall Statistics
Total Trades
1229
Average Win
0.02%
Average Loss
-0.02%
Compounding Annual Return
-2.751%
Drawdown
7.800%
Expectancy
-0.363
Net Profit
-2.766%
Sharpe Ratio
-0.575
Probabilistic Sharpe Ratio
4.867%
Loss Rate
74%
Win Rate
26%
Profit-Loss Ratio
1.49
Alpha
0.001
Beta
-0.107
Annual Standard Deviation
0.038
Annual Variance
0.001
Information Ratio
-0.688
Tracking Error
0.337
Treynor Ratio
0.204
Total Fees
$1229.42
# https://quantpedia.com/Screener/Details/25
from System.Drawing import Color
from Alphas.EmaCrossAlphaModel import EmaCrossAlphaModel

class SmallCapInvestmentAlgorithm(QCAlgorithm):

    def Initialize(self):

        self.SetStartDate(2020, 1, 8)
        self.SetEndDate(2021, 1, 10)
        self.SetCash(100000)

        self.lastMonth = -1
        
        self.emaLongestWindow = 200
        self.UniverseSettings.MinimumTimeInUniverse = self.emaLongestWindow
        self.SetWarmUp(self.emaLongestWindow)
        
        self.coarseCount = 100
        self.fineCount = 10

        self.indicators = {}

        self.UniverseSettings.Resolution = Resolution.Hour
        self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)

    def CoarseSelectionFunction(self, coarse):
        if self.lastMonth == self.Time.month:
            return Universe.Unchanged
        self.lastMonth = self.Time.month
        sortedByDollarVolume = sorted(coarse, key=lambda x: x.DollarVolume, reverse=True)
        self.symbols = [ x.Symbol for x in sortedByDollarVolume[:self.coarseCount] ]
        return self.symbols
 
 
    def FineSelectionFunction(self, fine):
        sortedByPeRatio = sorted(fine, key=lambda x: x.ValuationRatios.PERatio, reverse=True)
        self.symbols = [ x.Symbol for x in sortedByPeRatio[:self.fineCount] ]
        return self.symbols


    def OnData(self, data):

        for symbol in self.symbols:
            if not data.ContainsKey(symbol):
                continue
            if data[symbol] is None:
                continue

            self.indicators[symbol].update_value(self.Time, data[symbol].Price)
            
            if self.IsWarmingUp: continue
            
            sym_price = data[symbol].Price
            
            longestEMA = self.indicators[symbol].get_longestEMA()
            if longestEMA != 0.0:
                if longestEMA > sym_price:
                    self.SetHoldings(symbol, -0.01)
                else:
                    self.Liquidate(symbol)


    def OnSecuritiesChanged(self, changes):
        for security in changes.AddedSecurities:
            symbol = security.Symbol
            self.indicators[symbol] = SymbolData(symbol, self, self.emaLongestWindow)
        
        for security in changes.RemovedSecurities:
            symbol = security.Symbol
            if self.Portfolio[symbol].Invested:
                self.Liquidate(symbol, 'Removed from Universe')
                # clean up
                del self.indicators[security.Symbol]

class SymbolData(object):
    def __init__(self, symbol, context, window):
        self.symbol = symbol

        self.window    = window
        self.indicator = context.EMA(symbol, self.window)
        self.longestEMA = 0.0

    def update_bar(self, bar):
        self.indicator.Update(bar)
        
    def update_value(self, time, value):
        self.indicator.Update(time, value)
            
    def get_longestEMA(self):
        return self.indicator.Current.Value