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])