| Overall Statistics |
|
Total Trades 3219 Average Win 0.07% Average Loss -0.11% Compounding Annual Return -25.639% Drawdown 56.700% Expectancy -0.215 Net Profit -25.759% Sharpe Ratio -0.385 Probabilistic Sharpe Ratio 6.629% Loss Rate 51% Win Rate 49% Profit-Loss Ratio 0.60 Alpha 0.08 Beta -1.111 Annual Standard Deviation 0.398 Annual Variance 0.158 Information Ratio -0.538 Tracking Error 0.675 Treynor Ratio 0.138 Total Fees $3408.03 |
# 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)
stockPlot = Chart("Trade Plot")
stockPlot.AddSeries(Series('Price', SeriesType.Line, '$', Color.Blue))
stockPlot.AddSeries(Series(" 200EMAIndicator", SeriesType.Line, '$', Color.Yellow))
stockPlot = Chart("Diamonds")
stockPlot.AddSeries(Series('coarseSelect', SeriesType.Scatter, '$', Color.Gold, ScatterMarkerSymbol.Diamond))
stockPlot.AddSeries(Series('fineSelect', SeriesType.Scatter, '$', Color.Purple, ScatterMarkerSymbol.Diamond))
stockPlot.AddSeries(Series('Above220EMA', SeriesType.Scatter, '$', Color.Green, ScatterMarkerSymbol.Diamond))
self.AddChart(stockPlot)
coarseSelectAction = 0
self.Plot("Diamonds", "coarseSelect", coarseSelectAction)
fineSelectAction = 0
self.Plot("Diamonds", "fineSelect", fineSelectAction)
def CoarseSelectionFunction(self, coarse):
''' Drop stocks which have no fundamental data or have low price '''
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] ]
coarseSelectAction = 45
self.Plot("Diamonds", "coarseSelect", coarseSelectAction)
return self.symbols
def FineSelectionFunction(self, fine):
''' Selects the stocks by lowest market cap '''
sortedByPeRatio = sorted(fine, key=lambda x: x.ValuationRatios.PERatio, reverse=True)
self.symbols = [ x.Symbol for x in sortedByPeRatio[:self.fineCount] ]
fineSelectAction = 50
self.Plot("Diamonds", "fineSelect", fineSelectAction)
#return [x.Symbol for x in sorted_market_cap[:self.count]]
return self.symbols
def OnData(self, data):
for symbol in self.symbols:
if not data.ContainsKey(symbol):
continue
if data[symbol] is None:
continue
if symbol not in self.indicators:
self.indicators[symbol] = SymbolData(symbol, self, self.emaLongestWindow)
# update by bar
#self.indicators[symbol].update_bar(data[symbol])
#update by value
self.indicators[symbol].update_value(self.Time, data[symbol].Price)
if self.IsWarmingUp: continue
self.Log(str(symbol) + " : " + str(self.indicators[symbol].get_longestEMA()))
sym_price = data[symbol].Price
#self.EMAreq = self.EMA(symbol, 220, Resolution.Hour);
#self.PlotIndicator('Trade Plot', self.EMAreq);
self.Plot('Trade Plot',symbol.Value + " " + 'Price', data.Bars[symbol].Close)
longestEMA = self.indicators[symbol].get_longestEMA()
self.Plot("Trade Plot", (symbol.Value + " " + "200EMAIndicator"), self.indicators[symbol].get_longestEMA());
if longestEMA != 0.0:
if longestEMA > sym_price:
self.SetHoldings(symbol, -0.1)
emaclear = 0
self.Plot("Diamonds", "Above220EMA", emaclear)
else:
self.Liquidate(symbol)
def OnSecuritiesChanged(self, changes):
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