| Overall Statistics |
|
Total Trades 1 Average Win 0% Average Loss 0% Compounding Annual Return 0.002% Drawdown 0.000% Expectancy 0 Net Profit 0.000% Sharpe Ratio 0.688 Probabilistic Sharpe Ratio 45.870% Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha -0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio -8.116 Tracking Error 0.077 Treynor Ratio 0.544 Total Fees $0.00 Estimated Strategy Capacity $410000000.00 Lowest Capacity Asset XAGUSD 8I |
# the main idea is to determine the slope of an indicator and in this alpha it is the Donchian indicator
class IndicatorSlopeAlphaModel(AlphaModel):
def __init__(self, period):
self.period = period
self.resolution = Resolution.Daily
self.predictionInterval = Time.Multiply(Extensions.ToTimeSpan(self.resolution), self.period)
self.symbolData = {}
def Update(self, context, data):
insights = []
for symbol, symbolData in self.symbolData.items():
if not context.Portfolio[symbol].Invested:
if symbolData.CanEmit:
if data.ContainsKey(symbol):
close = symbolData.QuoteBar.Close
if symbolData.IndicatorSlope >= 0:
direction = InsightDirection.Up
insights.append(Insight.Price(symbol, self.predictionInterval, direction, None, None))
elif symbolData.IndicatorSlope < 0:
direction = InsightDirection.Down
insights.append(Insight.Price(symbol, self.predictionInterval, direction, None, None))
return insights
def OnSecuritiesChanged(self, context, changes):
for removed in changes.RemovedSecurities:
symbol = removed.Symbol
if removed in self.symbolData:
symbolData = self.symbolData.pop(symbol, None)
if symbolData is not None:
symbolData.RemoveConsolidators(context)
# initialize data for added securities
symbols = [x.Symbol for x in changes.AddedSecurities]
history = context.History(symbols, self.period, self.resolution)
if history.empty: return
tickers = history.index.levels[0]
context.Debug("{} -- {} Added to Alpha Model".format(context.Time,
[str(added.Symbol) for added in changes.AddedSecurities]))
for added in changes.AddedSecurities:
symbol = added.Symbol
if symbol not in self.symbolData:
context.Debug("{} -- {} Added to Alpha Model Symbol Data".format(context.Time, str(symbol)))
data = SymbolData(context, added, self.period)
self.symbolData[symbol] = data
data.RegisterIndicators(context, self.resolution)
if symbol not in tickers:
continue
else:
data.WarmUpIndicators(history.loc[symbol])
class SymbolData:
def __init__(self, context, security, lookback):
self.context = context
self.Security = security
self.Symbol = security.Symbol
self.TestIndicator = DonchianChannel(self.Symbol, 20, Resolution.Daily)
self.IndicatorSlope = 0
# Try rolling windows to access previous indicator values to subtract it to determine the slope
self.dchWindow = RollingWindow[IndicatorDataPoint](5)
'''
#####~~ indicator extensions begin ~~ uncomment the 3's
#Tried to get the slope of the Chanel indicater by using the ROC of the indictor
# the indicator extensions seems NOT working on these two indicators below
self.ROC = RateOfChange(18)
self.meanDCH = float(self.TestIndicator.Current.Value)
self.IndicatorSlope = IndicatorExtensions.Of(self.ROC, self.meanDCH )
#####~~ indicator extensions end ~~ uncomment the 3's below and one line further on line 95
'''
self.Consolidator = None
self.QuoteBar = None
self.Previous = None
self.print = True
def RegisterIndicators(self, context, resolution):
self.Consolidator = context.ResolveConsolidator(self.Symbol, Resolution.Daily)
self.Consolidator.DataConsolidated += self.OnDataConsolidated
context.RegisterIndicator(self.Symbol, self.TestIndicator, self.Consolidator)
#####~~ indicator extensions begin ~~ uncomment the # below
#context.RegisterIndicator(self.Symbol, self.IndicatorSlope, self.Consolidator) #Uncomment to get the IndicatorExtensions working
#####~~ indicator extensions end ~~
context.Debug("Indicator registered for {} @ {}".format(self.Symbol, context.Time))
def OnDataConsolidated(self, sender, bar):
'''
#####~~ Rolling Window begin ~~ uncomment the 3's above and below codesnipet
# Try Rolling Window to determine the slope of the testindicztor
self.dchWindow.Add(self.TestIndicator.Current.Value)
currentDch = self.dchWindow[0]
previousDch = self.dchWindow[1]
self.IndicatorSlope = currentDch - previousDch
#####~~ Rolling Window end ~~ uncomment the 3's below
'''
if self.print:
self.context.Debug("{} -- Data Consol. for {}: {}, Ending: {}".format(self.context.Time, self.Symbol, bar.Close, bar.EndTime))
self.context.Debug("{} -- for symbol {} and ROC ON Channel value: ROC value {} and Ending: {}".format(self.context.Time, self.Symbol, self.IndicatorSlope, bar.EndTime))
self.print = False
self.QuoteBar = bar
@property
def CanEmit(self):
# this will be getting checked at a higher freq. than the consolidator, check if a new Daily bar is available
if self.Previous == self.QuoteBar:
return False
self.Previous = self.QuoteBar
return self.TestIndicator.IsReady
def RemoveConsolidators(self, context):
if self.Consolidator is not None:
conext.SubscriptionManager.RemoveConsolidator(self.Symbol, self.Consolidator)
def WarmUpIndicators(self, history):
for index, tuple in history.iterrows():
tradeBar = TradeBar()
tradeBar.Close = tuple['close']
self.TestIndicator.Update(tradeBar)
class IndicatorSlopePortfolioConstructionModel(PortfolioConstructionModel):
def CreateTargets(self, context, insights):
targets = []
for insight in insights:
targets.append(PortfolioTarget(insight.Symbol, insight.Direction))
return targets
from Alpha import IndicatorSlopeAlphaModel
from Portfolio import IndicatorSlopePortfolioConstructionModel
from Universe import IndicatorSlopeUniverseModel
class IndicatorSlope(QCAlgorithm):
def Initialize(self):
# Set Start Date for backtest
self.SetStartDate(2018, 1, 1)
self.SetEndDate(2018, 2, 1)
# Set $100k Strategy Cash
self.SetCash(100000)
self.SetExecution( ImmediateExecutionModel() )
self.SetPortfolioConstruction( IndicatorSlopePortfolioConstructionModel() )
self.AddAlpha( IndicatorSlopeAlphaModel(period=20) )
self.UniverseSettings.Resolution = Resolution.Minute
self.AddUniverseSelection( IndicatorSlopeUniverseModel() )
def OnData(self, data):
'''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here.
Arguments:
data: Slice object keyed by symbol containing the stock data
'''
from QuantConnect import *
from Selection.ManualUniverseSelectionModel import ManualUniverseSelectionModel
class IndicatorSlopeUniverseModel(ManualUniverseSelectionModel):
def __init__(self):
metals = ["XAGUSD"]
universe = metals
super().__init__([Symbol.Create(x, SecurityType.Cfd, Market.Oanda) for x in universe])