Overall Statistics
Total Trades
11
Average Win
9.92%
Average Loss
-2.25%
Compounding Annual Return
7.539%
Drawdown
8.900%
Expectancy
2.245
Net Profit
71.510%
Sharpe Ratio
0.97
Probabilistic Sharpe Ratio
43.054%
Loss Rate
40%
Win Rate
60%
Profit-Loss Ratio
4.41
Alpha
0.066
Beta
-0.018
Annual Standard Deviation
0.066
Annual Variance
0.004
Information Ratio
-0.36
Tracking Error
0.173
Treynor Ratio
-3.512
Total Fees
$147.74
Estimated Strategy Capacity
$3300000000.00
Lowest Capacity Asset
SPY R735QTJ8XC9X
class SmoothOrangeWhale(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2014, 1, 1)  # Set Start Date
        self.SetCash(1000000)  # Set Strategy Cash
        self.SetBrokerageModel(BrokerageName.AlphaStreams)
        self.spy = self.AddEquity("SPY",Resolution.Daily).Symbol
        self.zzhl = ZigZagHighLow(self,"custom",100,0.1,0.5)
        self.RegisterIndicator(self.spy,self.zzhl,Resolution.Daily)
        self.SetWarmUp(100)
       
        


    def OnData(self, data):
        if not self.zzhl.IsReady:
            return
        
        if self.zzhl.Value>0 and not self.Portfolio.Invested:
            self.SetHoldings(self.spy,0.5)
        else:
             if self.zzhl.Value<0   and self.Portfolio.Invested:
               self.Liquidate()

class ZigZagHighLow(PythonIndicator):
    def __init__(self,algorithm,symbol,length = 100 ,percent_change = 0.02 ,atr_reversal = 0 ):
        self.algorithm = algorithm
        self.name = symbol
        self.high_index = 0
        self.low_index = 0
        self.dir = False
        self.Value = 0
        self.Period = length
        self.percent_change = percent_change
        self.atr_reversal = atr_reversal
        self.high_window = RollingWindow[float](length)
        self.low_window = RollingWindow[float](length)
        self.atr = AverageTrueRange(10,MovingAverageType.Simple)
       
    def Update(self,bar):
         
        self.high_window.Add(bar.High)
        self.low_window.Add(bar.Low)
        self.high_index = max(0,min(self.high_index+1,self.high_window.Count-1))
        self.low_index = max(0,min(self.low_index+1,self.low_window.Count-1))
        self.atr.Update(bar)
        
        
        if not self.dir:
            
            if(bar.Low<((self.getHigh()*(1-self.percent_change))-(self.atr.Current.Value*self.atr_reversal))):
                self.dir = True
                self.low_index = 0
        else:
            if(bar.High>((self.getLow()*(1+self.percent_change))+(self.atr.Current.Value*self.atr_reversal))):
                self.dir = False
                self.high_index = 0
            
        IsReady = self.high_window.IsReady and self.low_window.IsReady and self.atr.IsReady    
        if IsReady:
            if self.low_index>self.high_index:
                self.Value = 1
            elif self.low_index==self.high_index:
                self.Value = 0
            else:
                self.Value = -1
        return IsReady
        
    def getHigh(self):
        
        high = self.high_window[self.high_index]
        for i in range(self.high_index,-1,-1):
            if self.high_window[i]>high:
                high = self.high_window[i]
                self.high_index = i
        return high
   
    def getLow(self):
       
        low = self.low_window[self.low_index]
        for i in range(self.low_index,-1,-1):
            if self.low_window[i]<low:
                low = self.low_window[i]
                self.low_index = i
        return low