| Overall Statistics |
|
Total Trades 499 Average Win 1.32% Average Loss -0.57% Compounding Annual Return 34.229% Drawdown 19.500% Expectancy 0.364 Net Profit 58.484% Sharpe Ratio 1.358 Probabilistic Sharpe Ratio 60.313% Loss Rate 59% Win Rate 41% Profit-Loss Ratio 2.33 Alpha 0.304 Beta 0.006 Annual Standard Deviation 0.225 Annual Variance 0.05 Information Ratio 0.331 Tracking Error 0.335 Treynor Ratio 47.744 Total Fees $501.99 |
class EMVIndicatorAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2019, 1, 1)
self.SetEndDate(2020, 7, 24)
self.SetCash(100000)
self.tickers = ["SPY", "TSLA"]
self.emv_by_symbol = {}
for ticker in self.tickers:
symbol = self.AddEquity(ticker, Resolution.Daily).Symbol
self.emv_by_symbol[symbol] = EMV(symbol, self)
self.portfolioPercentage = 1/len(self.tickers)
self.lastday = None
EMVPlot = Chart("EMV Plot")
EMVPlot.AddSeries(Series("Buy", SeriesType.Scatter, 0))
EMVPlot.AddSeries(Series("Short", SeriesType.Scatter, 0))
EMVPlot.AddSeries(Series("Sell", SeriesType.Scatter, 0))
EMVPlot.AddSeries(Series("Price", SeriesType.Line, 0))
self.AddChart(EMVPlot)
EMVValuePlot = Chart("EMV Value Plot")
EMVValuePlot.AddSeries(Series("EMV", SeriesType.Line, 0))
self.AddChart(EMVValuePlot)
def OnData(self, data):
for symbol, emv in self.emv_by_symbol.items():
if not data.ContainsKey(symbol) or data[symbol] is None:
continue
close = data[symbol].Close
invested = self.Portfolio[symbol].Invested
if not emv.IsReady:
return
'''Enters a long or short position'''
if emv.value > 0 and not invested:
self.SetHoldings(symbol, self.portfolioPercentage)
self.Plot("EMV Plot", "Buy", close)
if emv.value < 0 and not invested:
self.SetHoldings(symbol, -(self.portfolioPercentage)/20) #Allows 5% of portfolioPercentage to short
self.Plot("EMV Plot", "Short", close)
'''Liquidates a long or short position'''
if emv.value < 0 and self.Portfolio[symbol].IsLong:
self.Liquidate(symbol)
self.Plot("EMV Plot", "Sell", close)
if emv.value > 0 and self.Portfolio[symbol].IsShort:
self.Liquidate(symbol)
self.Plot("EMV Plot", "Sell", close)
self.Plot("EMV Plot", "Price", close)
self.Plot("EMV Value Plot", "EMV", emv.value)
class EMV:
def __init__(self, symbol, algorithm):
self.symbol = symbol
self.algorithm = algorithm
self.value = None
self.highs = RollingWindow[float](2)
self.lows = RollingWindow[float](2)
self.volume = None
# Warm up indicator
history = algorithm.History(symbol, 2, Resolution.Daily)
for idx, row in history.iterrows():
self.highs.Add(row.high)
self.lows.Add(row.low)
self.volume = row.volume
self.update_value()
# Setup daily consolidator
self.consolidator = TradeBarConsolidator(timedelta(hours=24))
self.consolidator.DataConsolidated += self.DailyHandler
algorithm.SubscriptionManager.AddConsolidator(symbol, self.consolidator)
@property
def IsReady(self):
return self.highs.IsReady and \
self.lows.IsReady and \
self.volume is not None and \
self.value is not None
def update_value(self):
mov_mid_today = (self.highs[0] + self.lows[0]) / 2
mov_mid_yesterday = (self.highs[1] + self.lows[1]) / 2
MID = mov_mid_today - mov_mid_yesterday
if self.volume/10000 == 0 or self.highs[0] - self.lows[0] == 0:
self.value = None
return
ratio = (self.volume/10000) / (self.highs[0] - self.lows[0])
self.value = MID/ratio
def DailyHandler(self, sender, consolidated):
self.highs.Add(consolidated.High)
self.lows.Add(consolidated.Low)
self.volume = consolidated.Volume
self.update_value()