Overall Statistics
Total Trades
9454
Average Win
0.02%
Average Loss
-0.07%
Compounding Annual Return
-31.288%
Drawdown
23.200%
Expectancy
-0.075
Net Profit
-17.040%
Sharpe Ratio
-0.953
Probabilistic Sharpe Ratio
3.937%
Loss Rate
29%
Win Rate
71%
Profit-Loss Ratio
0.29
Alpha
-0.148
Beta
0.691
Annual Standard Deviation
0.213
Annual Variance
0.045
Information Ratio
-0.634
Tracking Error
0.194
Treynor Ratio
-0.294
Total Fees
$11099.67
Estimated Strategy Capacity
$710000.00
Lowest Capacity Asset
SOXL UKTSIYPJHFMT
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
# Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from AlgorithmImports import *

class EmaCrossMagnitudeAlphaModel(AlphaModel):
    '''Alpha model that uses an EMA cross to create insights'''

    def __init__(self,
                 fastPeriod = 12,
                 slowPeriod = 26,
                 resolution = Resolution.Daily):
        '''Initializes a new instance of the EmaCrossAlphaModel class
        Args:
            fastPeriod: The fast EMA period
            slowPeriod: The slow EMA period'''
        self.fastPeriod = fastPeriod
        self.slowPeriod = slowPeriod
        self.resolution = resolution
        self.predictionInterval = Time.Multiply(Extensions.ToTimeSpan(resolution), fastPeriod)
        self.symbolDataBySymbol = {}

        resolutionString = Extensions.GetEnumString(resolution, Resolution)
        self.Name = '{}({},{},{})'.format(self.__class__.__name__, fastPeriod, slowPeriod, resolutionString)


    def Update(self, algorithm, data):
        '''Updates this alpha model with the latest data from the algorithm.
        This is called each time the algorithm receives data for subscribed securities
        Args:
            algorithm: The algorithm instance
            data: The new data available
        Returns:
            The new insights generated'''
        insights = []
        for symbol, symbolData in self.symbolDataBySymbol.items():
            price = symbolData.algorithm.Securities[symbol].Close

            magnitude = 100.0 * price * (symbolData.Fast.Current.Value - symbolData.Slow.Current.Value) / (symbolData.Fast.Current.Value + symbolData.Slow.Current.Value) 
            direction = InsightDirection.Flat
            if symbolData.FastIsOverSlow:
                if symbolData.Slow > symbolData.Fast:
                    direction = InsightDirection.Down
                    magnitude = -magnitude

            elif symbolData.SlowIsOverFast:
                if symbolData.Fast > symbolData.Slow:
                    direct = InsightDirection.Up

            else:
                direction = InsightDirection.Flat

            insight = Insight.Price(symbol, self.predictionInterval, direction, magnitude=magnitude)
            symbolData.FastIsOverSlow = symbolData.Fast > symbolData.Slow
            insights.append(insight)

        algorithm.Debug("EMA INSIGHT LENGTH " + str(len(insights)))

        return insights

    def OnSecuritiesChanged(self, algorithm, changes):
        '''Event fired each time the we add/remove securities from the data feed
        Args:
            algorithm: The algorithm instance that experienced the change in securities
            changes: The security additions and removals from the algorithm'''

        # 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.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, algorithm, self.slowPeriod, self.fastPeriod, self.resolution)
                self.symbolDataBySymbol[symbol] = symbolData
                
        
        algorithm.Debug("EMA LENGTH")        
        algorithm.Debug(str(len(self.symbolDataBySymbol)))


class SymbolData:
    '''Contains data specific to a symbol required by this model'''
    def __init__(self, symbol, algorithm, slowPeriod, fastPeriod, resolution):
        self.Symbol = symbol
        self.algorithm = algorithm
        self.slowPeriod = slowPeriod
        self.fastPeriod = fastPeriod
        self.resolution = resolution
        self.Slow = algorithm.EMA(self.Symbol, self.slowPeriod, self.resolution)
        self.Fast = algorithm.EMA(self.Symbol, self.fastPeriod, self.resolution)

        # True if the fast is above the slow, otherwise false.
        # This is used to prevent emitting the same signal repeatedly
        self.FastIsOverSlow = False

    @property
    def SlowIsOverFast(self):
        return not self.FastIsOverSlow
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
# Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from AlgorithmImports import *

class MacdMagnitudeAlphaModel(AlphaModel):
    '''Defines a custom alpha model that uses MACD crossovers. The MACD signal line
    is used to generate up/down insights if it's stronger than the bounce threshold.
    If the MACD signal is within the bounce threshold then a flat price insight is returned.'''

    def __init__(self,
                 fastPeriod = 12,
                 slowPeriod = 26,
                 signalPeriod = 9,
                 movingAverageType = MovingAverageType.Exponential,
                 resolution = Resolution.Daily):
        ''' Initializes a new instance of the MacdAlphaModel class
        Args:
            fastPeriod: The MACD fast period
            slowPeriod: The MACD slow period</param>
            signalPeriod: The smoothing period for the MACD signal
            movingAverageType: The type of moving average to use in the MACD'''
        self.fastPeriod = fastPeriod
        self.slowPeriod = slowPeriod
        self.signalPeriod = signalPeriod
        self.movingAverageType = movingAverageType
        self.resolution = resolution
        self.insightPeriod = Time.Multiply(Extensions.ToTimeSpan(resolution), fastPeriod)
        self.bounceThresholdPercent = 0.01
        self.symbolDataBySymbol = {}

        resolutionString = Extensions.GetEnumString(resolution, Resolution)
        movingAverageTypeString = Extensions.GetEnumString(movingAverageType, MovingAverageType)
        self.Name = '{}({},{},{},{},{})'.format(self.__class__.__name__, fastPeriod, slowPeriod, signalPeriod, movingAverageTypeString, resolutionString)


    def Update(self, algorithm, data):
        ''' Determines an insight for each security based on it's current MACD signal
        Args:
            algorithm: The algorithm instance
            data: The new data available
        Returns:
            The new insights generated'''
        insights = []

        for symbol, symbolData in self.symbolDataBySymbol.items():
            close = symbolData.algorithm.Securities[symbol].Close
            direction = InsightDirection.Flat
            normalized_signal = symbolData.MACD.Signal.Current.Value / close
            magnitude = (abs(symbolData.MACD.Histogram.Current.Value * symbolData.MACD.Signal.Current.Value))**0.5 / close**2

            if normalized_signal > self.bounceThresholdPercent:
                direction = InsightDirection.Up
            elif normalized_signal < -self.bounceThresholdPercent:
                direction = InsightDirection.Down
                magnitude *= -1.0 #Placeholder magnitudes

            # ignore signal for same direction as previous signal
            if direction == symbolData.PreviousDirection:
                magnitude/= 10.0

            insight = Insight.Price(symbol, self.insightPeriod, direction, magnitude=magnitude) #Placeholder magnitudes
            symbolData.PreviousDirection = insight.Direction
            insights.append(insight)
            
        
        
        algorithm.Debug("MACD INSIGHT LENGTH " + str(len(insights)))
        return insights


    def OnSecuritiesChanged(self, algorithm, changes):
        '''Event fired each time the we add/remove securities from the data feed.
        This initializes the MACD for each added security and cleans up the indicator for each removed security.
        Args:
            algorithm: The algorithm instance that experienced the change in securities
            changes: The security additions and removals from the algorithm'''
        for removed in changes.RemovedSecurities:
            data = self.symbolData.pop(removed.Symbol, None)
            if data is not None:
                # clean up our consolidator
                algorithm.SubscriptionManager.RemoveConsolidator(removed.Symbol, data.Consolidator)
                
        # clean up data for removed securities
        for removed in changes.RemovedSecurities:
            symbolData = self.symbolDataBySymbol.pop(removed.Symbol, None)

        # initialize data for added securities
        symbols = [ x.Symbol for x in changes.AddedSecurities ]
        history = algorithm.History(symbols,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(algorithm, symbol, self.fastPeriod, self.slowPeriod, self.signalPeriod, self.movingAverageType, self.resolution)
                self.symbolDataBySymbol[symbol] = symbolData
        
        algorithm.Debug("MACD LENGTH")        
        algorithm.Debug(str(len(self.symbolDataBySymbol)))

class SymbolData:
    def __init__(self, algorithm, symbol, fastPeriod, slowPeriod, signalPeriod, movingAverageType, resolution):
        self.Symbol = symbol
        self.MACD = MovingAverageConvergenceDivergence(fastPeriod, slowPeriod, signalPeriod, movingAverageType)
        self.algorithm = algorithm

        self.Consolidator = algorithm.ResolveConsolidator(symbol, resolution)
        algorithm.RegisterIndicator(symbol, self.MACD, self.Consolidator)
        algorithm.WarmUpIndicator(symbol, self.MACD, resolution)

        self.PreviousDirection = None
from Execution.ImmediateExecutionModel import ImmediateExecutionModel
from Portfolio.BlackLittermanOptimizationPortfolioConstructionModel import BlackLittermanOptimizationPortfolioConstructionModel
from Risk.MaximumDrawdownPercentPerSecurity import MaximumDrawdownPercentPerSecurity

from MacdMagnitudeAlphaModel import MacdMagnitudeAlphaModel
from EmaCrossMagnitudeAlphaModel import EmaCrossMagnitudeAlphaModel

class BlackLittermanDebugging(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2021, 9, 7)  # Set Start Date
        self.SetCash(100000)  # Set Strategy Cash
        
        self.SetBrokerageModel(BrokerageName.AlphaStreams)
        
        self.AddAlpha(EmaCrossMagnitudeAlphaModel(50, 200, Resolution.Minute))

        self.AddAlpha(MacdMagnitudeAlphaModel(12, 26, 9, MovingAverageType.Simple, Resolution.Minute))
                
                
        self.SetExecution(ImmediateExecutionModel())

        self.SetPortfolioConstruction(BlackLittermanOptimizationPortfolioConstructionModel())

        
        self.SetRiskManagement(MaximumDrawdownPercentPerSecurity(0.01))

        self.UniverseSettings.Resolution = Resolution.Minute

        symbols = [ 
        Symbol.Create("SPY", SecurityType.Equity, Market.USA), 
        Symbol.Create("AAPL", SecurityType.Equity, Market.USA), 
        Symbol.Create("UVXY", SecurityType.Equity, Market.USA), 
        Symbol.Create("SOXL", SecurityType.Equity, Market.USA),
        Symbol.Create("FB", SecurityType.Equity, Market.USA)
        ]
        self.AddUniverseSelection(ManualUniverseSelectionModel(symbols))
        





    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
        '''