Overall Statistics
Total Orders
398
Average Win
18.51%
Average Loss
-2.71%
Compounding Annual Return
48.909%
Drawdown
26.900%
Expectancy
5.184
Start Equity
10000
End Equity
90175.79
Net Profit
801.758%
Sharpe Ratio
1.388
Sortino Ratio
1.596
Probabilistic Sharpe Ratio
80.615%
Loss Rate
21%
Win Rate
79%
Profit-Loss Ratio
6.83
Alpha
0.239
Beta
0.788
Annual Standard Deviation
0.232
Annual Variance
0.054
Information Ratio
1.231
Tracking Error
0.176
Treynor Ratio
0.408
Total Fees
$43.01
Estimated Strategy Capacity
$250000000.00
Lowest Capacity Asset
WMT R735QTJ8XC9X
Portfolio Turnover
0.50%
Drawdown Recovery
507
#region import
from AlgorithmImports import *
#endregion
from Alphas.MacdAlphaModel import MacdAlphaModel

class WellDressedYellowGreenFish(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2020, 3, 11)  # Set Start Date
        self.SetCash(10000)  # Set Strategy Cash
        self.AddUniverse(self.CoarseSelectionFunction)
        self.UniverseSettings.Resolution = Resolution.Daily
        self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Cash)
        self.set_benchmark(SecurityType.Equity, "MTUM")
        self.averages = { }
        self.SetWarmUp(400)
        self.n = 0
    
    def CoarseSelectionFunction(self, universe):  
        selected = []
        universe = sorted(universe, key=lambda c: c.DollarVolume, reverse=True)
        universe = [c for c in universe if c.Price > 100][:89]

        for coarse in universe:  
            symbol = coarse.Symbol
            
            if symbol not in self.averages:
                # 1. Call history to get an array of 200 days of history data
                history = self.History(symbol, 189, Resolution.Daily)
                
                #2. Adjust SelectionData to pass in the history result
                self.averages[symbol] = SelectionData(history) 

            self.averages[symbol].update(self.Time, coarse.AdjustedPrice)
            
            if  self.averages[symbol].is_ready() and  self.averages[symbol].fast > self.averages[symbol].mid > self.averages[symbol].slow:
                selected.append(symbol)
        return selected[:4]

    def OnData(self, data):
        for symbol, symbol_data in self.averages.items():
            tolerance = 0.003
            tolerance5 = 48.87
            tolerance6 = 57.87
            tolerance7 = 67.02
            if not data.ContainsKey(symbol) or not data.Bars.ContainsKey(symbol):
                continue
            holdings = self.Portfolio[symbol].Quantity if self.Portfolio.ContainsKey(symbol) else 0
            signalDeltaPercent = (symbol_data.macd.Current.Value - symbol_data.macd.Signal.Current.Value)/symbol_data.macd.Fast.Current.Value 
            if holdings <= 0 and signalDeltaPercent >= tolerance:
                if self.n == 4: 
                    return
                elif symbol_data.macd.Histogram.Current.Value < tolerance:
                    if tolerance6 > symbol_data.mfi.Current.Value > tolerance5:
                        if symbol_data.rc.LinearRegression >= symbol_data.bb.UpperBand >= symbol_data.rc.LowerChannel:
                            if symbol_data.trading > symbol_data.rc.LowerChannel > symbol_data.bb.MiddleBand:
                                self.SetHoldings(symbol, 0.75)
                                self.n += 1
                            elif symbol_data.rc.LowerChannel > symbol_data.trading > symbol_data.bb.MiddleBand:
                                self.SetHoldings(symbol, 1)
                                self.n += 1
                elif symbol_data.macd.Histogram.Current.Value > tolerance:
                    if symbol_data.mfi.Current.Value < tolerance5:
                        if symbol_data.trading >= symbol_data.bb.MiddleBand:
                            self.SetHoldings(symbol, 0.25)
                            self.n += 1
                        elif symbol_data.trading >= symbol_data.rc.LowerChannel and symbol_data.trading < symbol_data.bb.MiddleBand:
                            self.SetHoldings(symbol, 0.5)
                            self.n += 1
                    elif tolerance6 > symbol_data.mfi.Current.Value >= tolerance5 and symbol_data.mfi.Current.Value > symbol_data.mfi.Previous.Value:
                        if symbol_data.rc.LinearRegression > symbol_data.bb.UpperBand >= symbol_data.rc.LowerChannel:
                            if symbol_data.rc.LowerChannel > symbol_data.trading > symbol_data.bb.MiddleBand:
                                self.SetHoldings(symbol, 0.25)
                                self.n += 1
                            elif symbol_data.rc.LowerChannel > symbol_data.bb.MiddleBand > symbol_data.trading:
                                self.SetHoldings(symbol, 0.25)
                                self.n += 1
                            elif symbol_data.bb.UpperBand >= symbol_data.rc.LowerChannel > symbol_data.trading > symbol_data.bb.MiddleBand:
                                self.SetHoldings(symbol, 0.5)
                                self.n += 1
                            elif symbol_data.bb.UpperBand > symbol_data.trading >= symbol_data.rc.LowerChannel > symbol_data.bb.MiddleBand:
                                self.SetHoldings(symbol, 0.75)
                                self.n += 1
                            elif symbol_data.bb.UpperBand > symbol_data.trading > symbol_data.bb.MiddleBand >= symbol_data.rc.LowerChannel:
                                self.SetHoldings(symbol, 0.15)
                                self.n += 1
                        elif symbol_data.rc.UpperChannel > symbol_data.bb.UpperBand >= symbol_data.rc.LinearRegression:
                            if symbol_data.trading >= symbol_data.bb.MiddleBand > symbol_data.rc.LinearRegression:
                                self.SetHoldings(symbol, 0.2)
                                self.n += 1
                            elif symbol_data.trading > symbol_data.rc.LinearRegression >= symbol_data.bb.MiddleBand:
                                self.SetHoldings(symbol, 0.2)
                                self.n += 1
                            elif symbol_data.rc.LinearRegression > symbol_data.trading >= symbol_data.bb.UpperBand :
                                self.SetHoldings(symbol, 0.25)
                                self.n += 1  
                    elif symbol_data.mfi.Current.Value >= tolerance6 and symbol_data.mfi.Current.Value > symbol_data.mfi.Previous.Value:
                        if symbol_data.rc.LinearRegression > symbol_data.bb.UpperBand > symbol_data.rc.LowerChannel:
                            if symbol_data.rc.LinearRegression > symbol_data.bb.UpperBand > symbol_data.trading:
                                self.SetHoldings(symbol, 0.25)
                                self.n += 1
                            elif symbol_data.rc.LinearRegression > symbol_data.trading > symbol_data.bb.UpperBand:
                                self.SetHoldings(symbol, 0.5)
                                self.n += 1
                        elif symbol_data.trading < symbol_data.rc.LowerChannel and symbol_data.bb.UpperBand.Current.Value > symbol_data.bb.UpperBand.Previous.Value:
                            if symbol_data.bb.UpperBand < symbol_data.rc.LowerChannel:
                                self.SetHoldings(symbol, 0.5)
                                self.n += 1
                            elif symbol_data.bb.UpperBand < symbol_data.rc.LinearRegression and symbol_data.bb.UpperBand >= symbol_data.rc.LowerChannel:
                                self.SetHoldings(symbol, 0.25)
                                self.n += 1
                            elif symbol_data.bb.UpperBand >= symbol_data.rc.LinearRegression and symbol_data.bb.UpperBand < symbol_data.rc.UpperChannel and symbol_data.trading < symbol_data.bb.MiddleBand:
                                self.SetHoldings(symbol, 0.2)
                                self.n += 1
                            elif symbol_data.bb.UpperBand >= symbol_data.trading >= symbol_data.rc.LowerChannel > symbol_data.bb.MiddleBand:
                                self.SetHoldings(symbol, 0.45)
                                self.n += 1
                        elif symbol_data.bb.MiddleBand <= symbol_data.rc.LowerChannel <= symbol_data.trading < symbol_data.rc.LinearRegression:
                            if  symbol_data.rc.LinearRegression > symbol_data.bb.UpperBand > symbol_data.trading :
                                self.SetHoldings(symbol, 0.25)
                                self.n += 1
                            elif symbol_data.rc.LinearRegression > symbol_data.trading >= symbol_data.bb.UpperBand:
                                self.SetHoldings(symbol, 0.25)
                                self.n += 1                         
            elif holdings >= 0 and signalDeltaPercent >= tolerance:
                if symbol_data.trading >= symbol_data.rc.UpperChannel >= symbol_data.rc.UpperChannel:
                    self.Liquidate(symbol)
                    self.n -= 1
                elif symbol_data.bb.UpperBand >= symbol_data.trading >= symbol_data.rc.UpperChannel and symbol_data.mfi.Current.Value < symbol_data.mfi.Previous.Value:
                    self.Liquidate(symbol)
                    self.n -= 1
                elif symbol_data.bb.UpperBand >= symbol_data.rc.UpperChannel >= symbol_data.trading and symbol_data.mfi.Current.Value < symbol_data.mfi.Previous.Value:
                    if tolerance7 >= symbol_data.mfi.Current.Value >= tolerance6:
                        if symbol_data.trading >= symbol_data.rc.LinearRegression >= symbol_data.bb.MiddleBand:
                            if symbol_data.MiddleBand < symbol_data.rc.LowerChannel:
                                self.Liquidate(symbol)
                                self.n -= 1
                            elif symbol_data.MiddleBand >= symbol_data.rc.LowerChannel:
                                self.SetHoldings(symbol, 0.95)
                        elif symbol_data.rc.LinearRegression >= symbol_data.trading:
                            self.Liquidate(symbol)
                            self.n -= 1
                    elif tolerance6 >= symbol_data.mfi.Current.Value >= tolerance5:
                        if symbol_data.trading > symbol_data.rc.LinearRegression:
                            if symbol_data.bb.MiddleBand < symbol_data.rc.LowerChannel:
                                self.SetHoldings(symbol, 0.95)
                            elif symbol_data.bb.MiddleBand >= symbol_data.rc.LowerChannel:
                                self.Liquidate(symbol)
                                self.n -= 1
                    elif symbol_data.mfi.Current.Value < tolerance5:
                        if symbol_data.trading >= symbol_data.bb.MiddleBand > symbol_data.rc.LinearRegression > symbol_data.bb.LowerBand >= symbol_data.rc.LowerChannel:
                            self.Liquidate(symbol)
                            self.n -= 1
                        elif symbol_data.trading >= symbol_data.rc.LinearRegression > symbol_data.bb.LowerBand >= symbol_data.rc.LowerChannel:
                            self.Liquidate(symbol)
                            self.n -= 1
                        elif symbol_data.bb.MiddleBand >= symbol_data.trading >= symbol_data.rc.LinearRegression > symbol_data.bb.LowerBand >= symbol_data.rc.LowerChannel:
                            self.Liquidate(symbol)
                            self.n -= 1
                elif symbol_data.rc.UpperChannel > symbol_data.bb.UpperBand >= symbol_data.rc.LinearRegression :
                    if symbol_data.mfi.Current.Value >= tolerance7:
                        if symbol_data.trading >= symbol_data.bb.UpperBand:
                            self.SetHoldings(symbol, 0.45)
                        elif symbol_data.bb.UpperBand > symbol_data.trading > symbol_data.rc.LinearRegression:
                            self.SetHoldings(symbol, 0.2)
                    elif symbol_data.mfi.Current.Value < tolerance7 and symbol_data.mfi.Current.Value >= tolerance6:
                        if symbol_data.trading >= symbol_data.bb.UpperBand and symbol_data.rc.LowerChannel > symbol_data.bb.MiddleBand:
                            self.SetHoldings(symbol, 0.25)
                        elif symbol_data.trading >= symbol_data.bb.UpperBand and symbol_data.rc.LowerChannel < symbol_data.bb.MiddleBand:
                            self.Liquidate(symbol)
                            self.n -= 1
                        elif symbol_data.bb.UpperBand > symbol_data.trading > symbol_data.bb.MiddleBand >= symbol_data.rc.LinearRegression:
                            self.Liquidate(symbol)
                            self.n -= 1                           
                        elif symbol_data.rc.LinearRegression >= symbol_data.trading >= symbol_data.bb.MiddleBand >= symbol_data.rc.LowerChannel:
                            self.Liquidate(symbol)
                            self.n -= 1
                        elif symbol_data.rc.LinearRegression >= symbol_data.bb.MiddleBand >= symbol_data.trading >= symbol_data.rc.LowerChannel:
                            self.Liquidate(symbol)
                            self.n -= 1                  
                    elif symbol_data.mfi.Current.Value < tolerance6:
                        if symbol_data.trading > symbol_data.bb.MiddleBand > symbol_data.rc.LinearRegression:
                            self.Liquidate(symbol)
                            self.n -= 1
                        elif symbol_data.bb.UpperBand >= symbol_data.trading > symbol_data.rc.LinearRegression > symbol_data.bb.MiddleBand:
                            if symbol_data.bb.MiddleBand >= symbol_data.rc.LowerChannel:
                                self.SetHoldings(symbol, 0.15)
                            elif symbol_data.bb.MiddleBand < symbol_data.rc.LowerChannel:
                                self.Liquidate(symbol)
                                self.n -= 1
                        elif symbol_data.bb.MiddleBand > symbol_data.rc.LinearRegression > symbol_data.trading:
                            self.Liquidate(symbol)
                            self.n -= 1
                        elif symbol_data.rc.LinearRegression > symbol_data.trading > symbol_data.bb.MiddleBand:
                            self.Liquidate(symbol)
                            self.n -= 1
                        elif symbol_data.rc.LinearRegression > symbol_data.bb.MiddleBand > symbol_data.trading:
                            self.Liquidate(symbol)
                            self.n -= 1
                elif symbol_data.rc.LinearRegression > symbol_data.bb.UpperBand >= symbol_data.rc.LowerChannel:
                    if symbol_data.mfi.Current.Value >= tolerance7:
                        if symbol_data.trading >= symbol_data.rc.LowerChannel and symbol_data.trading < symbol_data.rc.LinearRegression:
                            self.Liquidate(symbol)
                            self.n -= 1
                        elif symbol_data.bb.UpperBand >= symbol_data.trading >= symbol_data.rc.LowerChannel:
                            self.Liquidate(symbol)
                            self.n -= 1
                    elif symbol_data.mfi.Current.Value < tolerance7 and symbol_data.mfi.Current.Value >= tolerance6:
                        if symbol_data.trading >= symbol_data.rc.LinearRegression > symbol_data.bb.UpperBand >=  symbol_data.rc.LowerChannel:
                            self.Liquidate(symbol)
                            self.n -= 1
                        elif symbol_data.trading >=  symbol_data.rc.LowerChannel > symbol_data.bb.MiddleBand:
                            self.Liquidate(symbol)
                            self.n -= 1
                        elif symbol_data.bb.MiddleBand >= symbol_data.rc.LowerChannel:
                            self.Liquidate(symbol)
                            self.n -= 1
                        elif symbol_data.rc.LowerChannel > symbol_data.trading >=  symbol_data.bb.MiddleBand:
                            self.Liquidate(symbol)
                            self.n -= 1                   
                    elif symbol_data.mfi.Current.Value < tolerance6 and symbol_data.mfi.Current.Value >= tolerance5:
                        if symbol_data.rc.LinearRegression > symbol_data.bb.UpperBand >= symbol_data.trading:
                            if symbol_data.bb.MiddleBand > symbol_data.rc.LowerChannel:
                                self.SetHoldings(symbol, 0.4)
                            elif symbol_data.bb.rc.LowerChannel > symbol_data.bb.MiddleBand:
                                self.Liquidate(symbol)
                                self.n -= 1
                        elif symbol_data.rc.LowerChannel > symbol_data.trading > symbol_data.bb.MiddleBand and symbol_data.bb.MiddleBand.Current.Value < symbol_data.bb.MiddleBand.Previous.Value:
                            self.Liquidate(symbol)
                            self.n -= 1
                    elif symbol_data.mfi.Current.Value < tolerance5:
                        if symbol_data.trading < symbol_data.bb.MiddleBand:
                            self.Liquidate(symbol)
                            self.n -= 1
            elif holdings >= 0 and signalDeltaPercent < -0.0001:
                if symbol_data.rc.Current.Value >= symbol_data.rc.Previous.Value and symbol_data.mfi.Current.Value <= symbol_data.mfi.Previous.Value:
                    if symbol_data.trading >= symbol_data.bb.UpperBand >= symbol_data.rc.UpperChannel:
                        self.Liquidate(symbol)
                        self.n -= 1
                    elif symbol_data.bb.UpperBand >= symbol_data.trading >= symbol_data.rc.UpperChannel:
                        self.Liquidate(symbol)
                        self.n -= 1
                    elif symbol_data.bb.UpperBand >= symbol_data.rc.UpperChannel >= symbol_data.trading:
                        if tolerance7 >= symbol_data.mfi.Current.Value >= tolerance6:
                            if symbol_data.trading > symbol_data.rc.LinearRegression:
                                self.Liquidate(symbol)
                                self.n -= 1
                        if tolerance6 >= symbol_data.mfi.Current.Value >= tolerance5:
                            if symbol_data.trading > symbol_data.rc.LinearRegression and symbol_data.bb.MiddleBand > symbol_data.rc.LowerChannel:
                                self.Liquidate(symbol)
                                self.n -= 1
                    elif symbol_data.rc.UpperChannel > symbol_data.bb.UpperBand > symbol_data.rc.LinearRegression:
                        if tolerance6 >= symbol_data.mfi.Current.Value >= tolerance5:
                            if symbol_data.bb.UpperBand > symbol_data.trading >= symbol_data.rc.LinearRegression:
                                if symbol_data.bb.MiddleBand >= symbol_data.rc.LinearRegression and symbol_data.bb.MiddleBand < symbol_data.trading:
                                    self.SetHoldings(symbol, 0.55) 
                                elif symbol_data.rc.LinearRegression > symbol_data.bb.MiddleBand >= symbol_data.rc.LowerChannel:    
                                    self.Liquidate(symbol)
                                    self.n -= 1 
                                elif symbol_data.bb.MiddleBand >= symbol_data.trading:
                                    self.Liquidate(symbol)
                                    self.n -= 1  
                        elif symbol_data.mfi.Current.Value < tolerance5:
                            if symbol_data.bb.MiddleBand >= symbol_data.trading >= symbol_data.bb.LowerBand:
                                self.SetHoldings(symbol, 0.25)
                            elif symbol_data.rc.LinearRegression >= symbol_data.bb.MiddleBand >= symbol_data.trading >= symbol_data.bb.LowerBand >= symbol_data.rc.LowerChannel:
                                self.Liquidate(symbol)
                                self.n -= 1     
                    elif symbol_data.rc.LinearRegression >= symbol_data.bb.UpperBand and tolerance6 > symbol_data.mfi.Current.Value >= tolerance5:
                        self.Liquidate(symbol)
                        self.n -= 1 
                elif symbol_data.rc.Current.Value < symbol_data.rc.Previous.Value:
                    if symbol_data.trading >= symbol_data.bb.UpperBand >= symbol_data.rc.UpperChannel:
                        self.Liquidate(symbol)
                        self.n -= 1
                    elif symbol_data.bb.UpperBand >= symbol_data.trading >= symbol_data.rc.UpperChannel:
                        self.Liquidate(symbol)
                        self.n -= 1
                    elif symbol_data.bb.UpperBand >= symbol_data.rc.UpperChannel >= symbol_data.trading:
                        self.Liquidate(symbol)
                        self.n -= 1
                    elif symbol_data.rc.UpperChannel > symbol_data.bb.UpperBand >= symbol_data.rc.LinearRegression:
                        if symbol_data.trading >= symbol_data.bb.MiddleBand >= symbol_data.rc.LinearRegression:    
                            self.Liquidate(symbol)
                            self.n -= 1
                        elif symbol_data.rc.LinearRegression < symbol_data.trading <= symbol_data.bb.MiddleBand:
                            self.Liquidate(symbol)
                            self.n -= 1
                    elif symbol_data.rc.LinearRegression >= symbol_data.bb.UpperBand and tolerance6 > symbol_data.mfi.Current.Value > tolerance5:
                        self.Liquidate(symbol)
                        self.n -= 1 
            elif holdings > 0 and symbol_data.sma5.IsReady:
                stop_level = symbol_data.sma5.Current.Value * 0.9
                if data[symbol].Price < stop_level:
                    self.Liquidate(symbol)
                    self.n -= 1
class SelectionData():
    #3. Update the constructor to accept a history array
    def __init__(self, history):
        self.slow = ExponentialMovingAverage(335)#optimised Fib
        self.mid = ExponentialMovingAverage(233)#optimised Fib
        self.fast = ExponentialMovingAverage(136)
        self.trading = WilderMovingAverage(20)
        self.macd = MovingAverageConvergenceDivergence(145, 377, 233, MovingAverageType.Simple)
        self.mfi = RelativeStrengthIndex(50, MovingAverageType.Simple)
        self.bb = BollingerBands(50, 1.25, MovingAverageType.EXPONENTIAL)
        self.rc = RegressionChannel(100, 1)
        self.sma5 = SimpleMovingAverage(20)
        #4. Loop over the history data and update the indicators
        for bar in history.itertuples():
            self.slow.Update(bar.Index[1], bar.close)
            self.mid.Update(bar.Index[1], bar.close)
            self.fast.Update(bar.Index[1], bar.close)
            self.trading.Update(bar.Index[1], bar.close)
            self.macd.Update(bar.Index[1], bar.close)
            self.mfi.Update(bar.Index[1], bar.close)
            self.bb.Update(bar.Index[1], bar.close)
            self.rc.Update(bar.Index[1], bar.close)
            self.sma5.Update(bar.Index[1], bar.close)
    def is_ready(self):
        return (self.slow.IsReady and self.mid.IsReady and self.fast.IsReady and self.trading.IsReady and 
            self.bb.UpperBand.IsReady and self.bb.MiddleBand.IsReady and self.bb.LowerBand.IsReady and
            self.rc.UpperChannel.IsReady and self.rc.LowerChannel.IsReady and self.rc.LinearRegression.IsReady)
    def update(self, time, price):
        self.fast.Update(time, price)
        self.trading.Update(time, price)
        self.mid.Update(time, price)
        self.slow.Update(time, price)
        self.macd.Update(time, price)
        self.rc.Update(time, price)
        self.mfi.Update(time, price)
        self.sma5.Update(time, price)