| Overall Statistics |
|
Total Trades 0 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Net Profit 0% Sharpe Ratio 0 Probabilistic Sharpe Ratio 0% Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio -22.03 Tracking Error 0.11 Treynor Ratio 0 Total Fees $0.00 Estimated Strategy Capacity $0 Lowest Capacity Asset |
from AlgorithmImports import *
from datetime import timedelta, time, datetime
from QuantConnect import Algorithm
class MomentumFrameworkAlgo(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2011, 1, 1)
self.SetEndDate(2011, 1, 3)# Set End Date
self.SetCash(100000) # Set Strategy Cash
self.UniverseSettings.Resolution = Resolution.Hour
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
self.SetWarmup(timedelta(360))
self.SetBenchmark('SPY')
self.spy = self.AddEquity('SPY')
self.AddUniverse(self.CoarseUniverse)
self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel(rebalance = Expiry.EndOfMonth, portfolioBias = PortfolioBias.Long))
self.SetExecution(ImmediateExecutionModel())
self.AddAlpha(MomentumAlphaModel(lookback=420, resolution=Resolution.Daily))
self.AddRiskManagement(RiskModelWithSpy(self.spy))
self.num_coarse = 100
self.lastMonth = -1
def CoarseUniverse(self, coarse):
if self.Time.month == self.lastMonth:
return Universe.Unchanged
self.lastMonth = self.Time.month
selected = sorted([x for x in coarse if x.HasFundamentalData and x.Price > 10], key = lambda x: x.DollarVolume, reverse=True)
return [x.Symbol for x in selected[:self.num_coarse]]
def OnEndOfDay(self):
self.Plot("Positions", "Num", len([x.Symbol for x in self.Portfolio.Values if self.Portfolio[x.Symbol].Invested]))
self.Plot(f"Margin", "Used", self.Portfolio.TotalMarginUsed)
self.Plot(f"Margin", "Remaning", self.Portfolio.MarginRemaining)
self.Plot(f"Cash", "Remaining", self.Portfolio.Cash)
class MomentumAlphaModel(AlphaModel):
def __init__(self, lookback = 420, resolution = Resolution.Daily):
self.lookback = lookback
self.resolution = resolution
self.predictionInterval = Expiry.EndOfMonth
self.symbolDataBySymbol = {}
self.num_insights = 10
self.lastMonth = -1
def Update(self, algorithm, data):
if algorithm.Time.month == self.lastMonth:
return []
self.lastMonth = algorithm.Time.month
insights = []
for symbol, symbolData in self.symbolDataBySymbol.items():
if symbolData.CanEmit:
direction = InsightDirection.Flat
magnitude = symbolData.Return
if magnitude > 0:
direction = InsightDirection.Up
if magnitude < 0:
continue
insights.append(Insight.Price(symbol, self.predictionInterval, direction, magnitude, None))
insights1 = sorted([x for x in insights], key = lambda x: x.Magnitude, reverse=True)
return [x for x in insights1[:self.num_insights]]
def OnSecuritiesChanged(self, algorithm, changes):
# clean up data for removed securities
for removed in changes.RemovedSecurities:
symbolData = self.symbolDataBySymbol.pop(removed.Symbol, None)
if symbolData is not None:
symbolData.RemoveConsolidators(algorithm)
# initialize data for added securities
symbols = [ x.Symbol for x in changes.AddedSecurities ]
history = algorithm.History(symbols, self.lookback, self.resolution)
if history.empty: return
tickers = history.index.levels[0]
for ticker in tickers:
symbol = SymbolCache.GetSymbol(ticker)
if symbol not in self.symbolDataBySymbol:
symbolData = SymbolData(symbol, self.lookback)
self.symbolDataBySymbol[symbol] = symbolData
symbolData.RegisterIndicators(algorithm, self.resolution)
symbolData.WarmUpIndicators(history.loc[ticker])
class RiskModelWithSpy(RiskManagementModel):
def __init__(self, spy, maximumDrawdown= 0.05, lookback = 100, resolution = Resolution.Daily):
self.spy = spy
self.maximumDrawdown = -abs(maximumDrawdown)
self.lookback = lookback
self.resolution = resolution
self.symboldata = {}
#Flag so we only instanciate it once
self.init = False
def ManageRisk(self, algorithm, targets):
targets = []
if self.init == False:
#Takes in spy, our lookback and resolution
self.symboldata[self.spy.Symbol] = EMASymbolData(algorithm, self.spy, self.lookback, self.resolution)
self.init = True
for symbol, symboldata in self.symboldata.items():
#logic. If price is below the current value for EMA, we send a portfoliotarget of 0
spyValue = self.spy.Price
emaValue = symboldata.SMA.Current.Value
for kvp in algorithm.Securities:
security = kvp.Value
if not security.Invested:
continue
if spyValue <= emaValue:
targets.append(PortfolioTarget(security.Symbol, 0))
return targets
class EMASymbolData:
def __init__(self, algorithm, security, lookback, resolution):
symbol = security.Symbol
self.Security = symbol
self.Consolidator = algorithm.ResolveConsolidator(symbol, resolution)
smaName = algorithm.CreateIndicatorName(symbol, f"SMA{lookback}", resolution)
self.SMA = SimpleMovingAverage(smaName, lookback)
algorithm.RegisterIndicator(symbol, self.SMA, self.Consolidator)
history = algorithm.History(symbol, lookback, resolution)
if 'close' in history:
history = history.close.unstack(0).squeeze()
for time, value in history.iteritems():
self.SMA.Update(time, value)
class SymbolData:
def __init__(self, symbol, lookback):
self.Symbol = symbol
self.ROC = RateOfChange('{}.ROC({})'.format(symbol, lookback), lookback)
self.Consolidator = None
self.previous = 0
def RegisterIndicators(self, algorithm, resolution):
self.Consolidator = algorithm.ResolveConsolidator(self.Symbol, resolution)
algorithm.RegisterIndicator(self.Symbol, self.ROC, self.Consolidator)
def RemoveConsolidators(self, algorithm):
if self.Consolidator is not None:
algorithm.SubscriptionManager.RemoveConsolidator(self.Symbol, self.Consolidator)
def WarmUpIndicators(self, history):
for tuple in history.itertuples():
self.ROC.Update(tuple.Index, tuple.close)
@property
def Return(self):
return float(self.ROC.Current.Value)
@property
def CanEmit(self):
if self.previous == self.ROC.Samples:
return False
self.previous = self.ROC.Samples
return self.ROC.IsReady
def __str__(self, **kwargs):
return '{}: {:.2%}'.format(self.ROC.Name, (1 + self.Return)**252 - 1)