Overall Statistics
Total Trades
15
Average Win
50.53%
Average Loss
-10.43%
Compounding Annual Return
15.555%
Drawdown
32.500%
Expectancy
4.008
Net Profit
759.832%
Sharpe Ratio
0.638
Probabilistic Sharpe Ratio
6.463%
Loss Rate
14%
Win Rate
86%
Profit-Loss Ratio
4.84
Alpha
0
Beta
0
Annual Standard Deviation
0.169
Annual Variance
0.029
Information Ratio
0.714
Tracking Error
0.169
Treynor Ratio
0
Total Fees
$19.67
Estimated Strategy Capacity
$43000000.00
Lowest Capacity Asset
ISRG RVIFYB6Z92LH
Portfolio Turnover
0.14%
#region import
from AlgorithmImports import *
#endregion
from Alphas.MacdAlphaModel import MacdAlphaModel

class WellDressedYellowGreenFish(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2009, 1, 1)  # Set Start Date
        #self.SetEndDate(2023, 6, 2)
        self.SetCash(10000)  # Set Strategy Cash
        self.AddUniverse(self.CoarseSelectionFunction)
        self.UniverseSettings.Resolution = Resolution.Daily
        self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Cash)
        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[:2]
        
    def OnData(self, data):
        for symbol, symbol_data in self.averages.items():
            tolerance = 0.0101
            tolerance3 = 0.87
            tolerance4 = 11.53
            tolerance5 = 50.38
            tolerance6 = 52.18
            tolerance7 = 56.31
            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:  # 0.01%
                if self.n == 2: return
                # longterm says buy as well
                if symbol_data.macd.Histogram.Current.Value > 0:
                    if symbol_data.mfi.Current.Value > tolerance5:
                        if symbol_data.trading >= symbol_data.bb.LowerBand:
                            self.SetHoldings(symbol, 0.45)
                            self.n += 1
                    elif symbol_data.mfi.Current.Value > tolerance6:
                        if symbol_data.trading >= symbol_data.bb.MiddleBand:
                            self.SetHoldings(symbol, 0.45)
                            self.n += 1
                    elif symbol_data.rc.LowerChannel < symbol_data.trading and symbol_data.rc.LinearRegression > symbol_data.trading:
                        if symbol_data.trading > symbol_data.bb.LowerBand and symbol_data.trading < symbol_data.bb.MiddleBand:
                            self.SetHoldings(symbol, 0.25)
                            self.n += 0.5
            elif holdings >= 0 and signalDeltaPercent < -0.0021:
                if symbol_data.mfi.Current.Value >= symbol_data.mfi.Previous.Value:
                    if symbol_data.mfi.Current.Value <= tolerance5:
                        if symbol_data.trading >= symbol_data.bb.MiddleBand and symbol_data.trading <= symbol_data.bb.UpperBand:
                            self.Liquidate(symbol)
                            self.n -= 1
                        elif symbol_data.trading >= symbol_data.bb.LowerBand and symbol_data.trading <= symbol_data.bb.MiddleBand:
                            if symbol_data.trading > symbol_data.rc.LowerChannel:
                                self.Liquidate(symbol)
                                self.n -= 1
                        elif symbol_data.trading <= symbol_data.bb.LowerBand:
                            self.Liquidate(symbol)
                            self.n -= 1
                    elif tolerance5 < symbol_data.mfi.Current.Value <= tolerance6:
                        if symbol_data.trading >= symbol_data.rc.LowerChannel and symbol_data.trading <= symbol_data.rc.LinearRegression:
                            if symbol_data.trading >= symbol_data.bb.MiddleBand and symbol_data.trading <= symbol_data.bb.UpperBand:
                                self.MarketOrder(symbol, -((self.Portfolio[symbol].Quantity)/2))
                                self.n -= 0.5
                        elif symbol_data.trading >= symbol_data.bb.UpperBand:
                            self.Liquidate(symbol)
                            self.n -= 1
                    elif tolerance6 < symbol_data.mfi.Current.Value < tolerance7:
                        if symbol_data.trading > symbol_data.bb.MiddleBand and symbol_data.trading < symbol_data.bb.UpperBand:
                            self.MarketOrder(symbol, -((self.Portfolio[symbol].Quantity)/2))
                            self.n -= 0.5
                    elif symbol_data.mfi.Current.Value >= tolerance7:
                        if symbol_data.trading > symbol_data.rc.UpperChannel:
                            if symbol_data.trading > symbol_data.bb.UpperBand:
                                self.Liquidate(symbol)
                                self.n -= 1
                elif symbol_data.mfi.Current.Value <= symbol_data.mfi.Previous.Value:
                    if symbol_data.mfi.Current.Value >= tolerance7:
                        if symbol_data.trading > symbol_data.rc.UpperChannel:
                            self.Liquidate(symbol)
                            self.n -= 1
                        elif symbol_data.trading > symbol_data.bb.UpperBand:
                            self.Liquidate(symbol)
                            self.n -= 1
                        elif symbol_data.trading > symbol_data.rc.LinearRegression and symbol_data.trading < symbol_data.rc.UpperChannel:
                            self.Liquidate(symbol)
                            self.n -= 1
                    elif tolerance6 < symbol_data.mfi.Current.Value <= tolerance7:
                        if symbol_data.trading >= symbol_data.rc.LinearRegression and symbol_data.trading <= symbol_data.rc.UpperChannel:
                            self.MarketOrder(symbol, -((self.Portfolio[symbol].Quantity)/2))
                            self.n -= 0.5
                        elif symbol_data.trading <= symbol_data.bb.UpperBand and symbol_data.trading >= symbol_data.bb.MiddleBand:
                            self.MarketOrder(symbol, -((self.Portfolio[symbol].Quantity)/2))
                            self.n -= 0.5
                    elif tolerance5 < symbol_data.mfi.Current.Value <= tolerance6:
                        if symbol_data.trading >= symbol_data.bb.UpperBand:
                            self.Liquidate(symbol)
                            self.n -= 1 
                        elif symbol_data.trading <= symbol_data.bb.UpperBand and symbol_data.trading >= symbol_data.bb.MiddleBand:
                            self.Liquidate(symbol)
                            self.n -= 1                       
                    elif symbol_data.mfi.Current.Value <= tolerance5:
                        if symbol_data.trading > symbol_data.bb.LowerBand:
                            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.macd = MovingAverageConvergenceDivergence(144, 377, 233, MovingAverageType.Exponential)
        self.mfi = RelativeStrengthIndex(145, MovingAverageType.Simple)
        self.bb = BollingerBands(55, 0.6)
        self.trading = WilderMovingAverage(14)
        self.rc = RegressionChannel(200, 1.0)
        #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)
    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
        return 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)