Overall Statistics
Total Trades
76
Average Win
1.04%
Average Loss
-0.44%
Compounding Annual Return
2.844%
Drawdown
6.400%
Expectancy
0.216
Net Profit
7.798%
Sharpe Ratio
0.605
Loss Rate
64%
Win Rate
36%
Profit-Loss Ratio
2.38
Alpha
0.03
Beta
-0.003
Annual Standard Deviation
0.048
Annual Variance
0.002
Information Ratio
-1.147
Tracking Error
0.123
Treynor Ratio
-11.629
Total Fees
$76.14
namespace QuantConnect {

    //
    //	Make sure to change "BasicTemplateAlgorithm" to your algorithm class name, and that all
    //	files use "public partial class" if you want to split up your algorithm namespace into multiple files.
    //

    /// <summary>
    /// This indicator computes Average Directional Index which measures trend strength without regard to trend direction.
    /// Firstly, it calculates the Directional Movement and the True Range value, and then the values are accumulated and smoothed
    /// using a custom smoothing method proposed by Wilder. For an n period smoothing, 1/n of each period's value is added to the total period.
    /// From these accumulated values we are therefore able to derived the 'Positive Directional Index' (+DI) and 'Negative Directional Index' (-DI)
    /// which is used to calculate the Average Directional Index.
    /// </summary>
    public class AverageDirectionalIndex : IndicatorBase<TradeBar>
    {
        private TradeBar _previousInput;

        private readonly int _period;

        private IndicatorBase<TradeBar> TrueRange { get; set; }

        private IndicatorBase<TradeBar> DirectionalMovementPlus { get; set; }

        private IndicatorBase<TradeBar> DirectionalMovementMinus { get; set; }

        private IndicatorBase<IndicatorDataPoint> SmoothedDirectionalMovementPlus { get; set; }

        private IndicatorBase<IndicatorDataPoint> SmoothedDirectionalMovementMinus { get; set; }

        private IndicatorBase<IndicatorDataPoint> SmoothedTrueRange { get; set; }

        /// <summary>
        /// Gets or sets the index of the Plus Directional Indicator
        /// </summary>
        /// <value>
        /// The  index of the Plus Directional Indicator.
        /// </value>
        public IndicatorBase<IndicatorDataPoint> PositiveDirectionalIndex { get; private set; }

        /// <summary>
        /// Gets or sets the index of the Minus Directional Indicator
        /// </summary>
        /// <value>
        /// The index of the Minus Directional Indicator.
        /// </value>
        public IndicatorBase<IndicatorDataPoint> NegativeDirectionalIndex { get; private set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="AverageDirectionalIndex"/> class.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="period">The period.</param>
        public AverageDirectionalIndex(string name, int period)
            : base(name)
        {
            _period = period;

            TrueRange = new FunctionalIndicator<TradeBar>(name + "_TrueRange",
                currentBar =>
                {
                    var value = ComputeTrueRange(currentBar);
                    return value;
                },
                isReady => _previousInput != null
                );

            DirectionalMovementPlus = new FunctionalIndicator<TradeBar>(name + "_PositiveDirectionalMovement",
                currentBar =>
                {
                    var value = ComputePositiveDirectionalMovement(currentBar);
                    return value;
                },
                isReady => _previousInput != null
                );


            DirectionalMovementMinus = new FunctionalIndicator<TradeBar>(name + "_NegativeDirectionalMovement",
                currentBar =>
                {
                    var value = ComputeNegativeDirectionalMovement(currentBar);
                    return value;
                },
                isReady => _previousInput != null
                );

            PositiveDirectionalIndex = new FunctionalIndicator<IndicatorDataPoint>(name + "_PositiveDirectionalIndex",
                input => ComputePositiveDirectionalIndex(),
                positiveDirectionalIndex => DirectionalMovementPlus.IsReady && TrueRange.IsReady,
                () =>
                {
                    DirectionalMovementPlus.Reset();
                    TrueRange.Reset();
                }
                );

            NegativeDirectionalIndex = new FunctionalIndicator<IndicatorDataPoint>(name + "_NegativeDirectionalIndex",
                input => ComputeNegativeDirectionalIndex(),
                negativeDirectionalIndex => DirectionalMovementMinus.IsReady && TrueRange.IsReady,
                () =>
                {
                    DirectionalMovementMinus.Reset();
                    TrueRange.Reset();
                }
                );

            SmoothedTrueRange = new FunctionalIndicator<IndicatorDataPoint>(name + "_SmoothedTrueRange",
                    currentBar => ComputeSmoothedTrueRange(period),
                    isReady => _previousInput != null
                );


            SmoothedDirectionalMovementPlus = new FunctionalIndicator<IndicatorDataPoint>(name + "_SmoothedDirectionalMovementPlus",
                    currentBar => ComputeSmoothedDirectionalMovementPlus(period),
                    isReady => _previousInput != null
                );

            SmoothedDirectionalMovementMinus = new FunctionalIndicator<IndicatorDataPoint>(name + "_SmoothedDirectionalMovementMinus",
                    currentBar => ComputeSmoothedDirectionalMovementMinus(period),
                    isReady => _previousInput != null
                );
        }

        /// <summary>
        /// Computes the Smoothed Directional Movement Plus value.
        /// </summary>
        /// <param name="period">The period.</param>
        /// <returns></returns>
        private decimal ComputeSmoothedDirectionalMovementPlus(int period)
        {

            decimal value;

            if (Samples < period)
            {
                value = SmoothedDirectionalMovementPlus.Current + DirectionalMovementPlus.Current;
            }
            else
            {
                value = SmoothedDirectionalMovementPlus.Current - (SmoothedDirectionalMovementPlus.Current / period) + DirectionalMovementPlus.Current;
            }

            return value;
        }

        /// <summary>
        /// Computes the Smoothed Directional Movement Minus value.
        /// </summary>
        /// <param name="period">The period.</param>
        /// <returns></returns>
        private decimal ComputeSmoothedDirectionalMovementMinus(int period)
        {
            decimal value;

            if (Samples < period)
            {
                value = SmoothedDirectionalMovementMinus.Current + DirectionalMovementMinus.Current;
            }
            else
            {
                value = SmoothedDirectionalMovementMinus.Current - (SmoothedDirectionalMovementMinus.Current / 14) + DirectionalMovementMinus.Current;
            }

            return value;
        }

        /// <summary>
        /// Computes the Smoothed True Range value.
        /// </summary>
        /// <param name="period">The period.</param>
        /// <returns></returns>
        private decimal ComputeSmoothedTrueRange(int period)
        {
            decimal value;

            if (Samples < period)
            {
                value = SmoothedTrueRange.Current + TrueRange.Current;
            }
            else
            {
                value = SmoothedTrueRange.Current - (SmoothedTrueRange.Current / period) + TrueRange.Current;
            }
            return value;
        }

        /// <summary>
        /// Gets a flag indicating when this indicator is ready and fully initialized
        /// </summary>
        public override bool IsReady
        {
            get { return Samples >= _period; }
        }

        /// <summary>
        /// Computes the True Range value.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <returns></returns>
        private decimal ComputeTrueRange(TradeBar input)
        {
            var trueRange = new decimal(0.0);

            if (_previousInput == null) return trueRange;

            trueRange = (Math.Max(Math.Abs(input.Low - _previousInput.Close), Math.Max(TrueRange.Current, Math.Abs(input.High - _previousInput.Close))));

            return trueRange;
        }

        /// <summary>
        /// Computes the positive directional movement.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <returns></returns>
        private decimal ComputePositiveDirectionalMovement(TradeBar input)
        {
            var postiveDirectionalMovement = new decimal(0.0);

            if (_previousInput == null) return postiveDirectionalMovement;

            if ((input.High - _previousInput.High) >= (_previousInput.Low - input.Low))
            {
                if ((input.High - _previousInput.High) > 0)
                {
                    postiveDirectionalMovement = input.High - _previousInput.High;
                }
            }

            return postiveDirectionalMovement;
        }

        /// <summary>
        /// Computes the negative directional movement.
        /// </summary>
        /// <param name="input">The input.</param>
        /// <returns></returns>
        private decimal ComputeNegativeDirectionalMovement(TradeBar input)
        {
            var negativeDirectionalMovement = new decimal(0.0);

            if (_previousInput == null) return negativeDirectionalMovement;

            if ((_previousInput.Low - input.Low) > (input.High - _previousInput.High))
            {
                if ((_previousInput.Low - input.Low) > 0)
                {
                    negativeDirectionalMovement = _previousInput.Low - input.Low;
                }
            }

            return negativeDirectionalMovement;
        }

        /// <summary>
        /// Computes the next value of this indicator from the given state
        /// </summary>
        /// <param name="input">The input given to the indicator</param>
        /// <returns>A new value for this indicator</returns>
        protected override decimal ComputeNextValue(TradeBar input)
        {
            TrueRange.Update(input);
            DirectionalMovementPlus.Update(input);
            DirectionalMovementMinus.Update(input);
            SmoothedTrueRange.Update(Current);
            SmoothedDirectionalMovementMinus.Update(Current);
            SmoothedDirectionalMovementPlus.Update(Current);
            if (_previousInput != null)
            {
                PositiveDirectionalIndex.Update(Current);
                NegativeDirectionalIndex.Update(Current);
            }
            var diff = Math.Abs(PositiveDirectionalIndex - NegativeDirectionalIndex);
            var sum = PositiveDirectionalIndex + NegativeDirectionalIndex;
            var value = sum == 0 ? 50 : ((_period - 1) * Current.Value + 100 * diff / sum ) / _period;
            _previousInput = input;
            return value;
        }

        /// <summary>
        /// Computes the Plus Directional Indicator (+DI period).
        /// </summary>
        /// <returns></returns>
        private decimal ComputePositiveDirectionalIndex()
        {
            if (SmoothedTrueRange == 0) return new decimal(0.0);

            var positiveDirectionalIndex = (SmoothedDirectionalMovementPlus.Current.Value / SmoothedTrueRange.Current.Value) * 100;

            return positiveDirectionalIndex;
        }

        /// <summary>
        /// Computes the Minus Directional Indicator (-DI period).
        /// </summary>
        /// <returns></returns>
        private decimal ComputeNegativeDirectionalIndex()
        {
            if (SmoothedTrueRange == 0) return new decimal(0.0);

            var negativeDirectionalIndex = (SmoothedDirectionalMovementMinus.Current.Value / SmoothedTrueRange.Current.Value) * 100;

            return negativeDirectionalIndex;
        }

        /// <summary>
        /// Resets this indicator to its initial state
        /// </summary>
        public override void Reset()
        {
            base.Reset();
            TrueRange.Reset();
            DirectionalMovementPlus.Reset();
            DirectionalMovementMinus.Reset();
            SmoothedTrueRange.Reset();
            SmoothedDirectionalMovementMinus.Reset();
            SmoothedDirectionalMovementPlus.Reset();
            PositiveDirectionalIndex.Reset();
            NegativeDirectionalIndex.Reset();
        }
    }


}
namespace QuantConnect 
{   
    /*
    *   QuantConnect University: Full Basic Template:
    *
    *   The underlying QCAlgorithm class is full of helper methods which enable you to use QuantConnect.
    *   We have explained some of these here, but the full algorithm can be found at:
    *   https://github.com/QuantConnect/QCAlgorithm/blob/master/QuantConnect.Algorithm/QCAlgorithm.cs
    */
    public class BasicTemplateAlgorithm : QCAlgorithm
    {
    	private string symbol = "SPY";
    	private ParabolicSAR psar14;
    	private ParabolicSAR psar30;
    	
        //Initialize the data and resolution you require for your strategy:
        public override void Initialize() 
        {
			//Start and End Date range for the backtest:
            SetStartDate(2013, 1, 1);         
            SetEndDate(DateTime.Now.Date.AddDays(-1));
            
            //Cash allocation
            SetCash(25000);
            
            //Add as many securities as you like. All the data will be passed into the event handler:
            AddSecurity(SecurityType.Equity, symbol, Resolution.Daily);
            
            psar14 = new ParabolicSAR("PSAR", 1);
            psar30 = new ParabolicSAR("PSAR", 30);
        }

        //Data Event Handler: New data arrives here. "TradeBars" type is a dictionary of strings so you can access it by symbol.
        public void OnData(TradeBars data) 
        {   
            // "TradeBars" object holds many "TradeBar" objects: it is a dictionary indexed by the symbol:
            // 
            //  e.g.  data["MSFT"] data["GOOG"]
            
            // update Indicators
        	decimal price = data[symbol].Close;
        	IndicatorDataPoint datum = new IndicatorDataPoint(data[symbol].Time, price);
        	psar14.Update(data[symbol]);
        	
        	//Debug("Current PSAR: " + psar14.Current.Value);
        	
        	// if
        	decimal cash = Portfolio.Cash;
            int holdings = Portfolio[symbol].Quantity;
            
            var quantity = Convert.ToInt32((cash * 0.5m) / price);
            
            if (holdings > 0 || holdings == 0) 
            {
            	if (!psar14._trend)
        		{
	        		Order(symbol, -(holdings + quantity));
        		}
            } else if (holdings < 0 || holdings == 0) 
            {
                if (psar14._trend) 
                {
                    Order(symbol, Math.Abs(holdings) + quantity);
                }
            }
            
            Plot(symbol, psar14);
        }
    }
}
namespace QuantConnect {

    //
    //	Make sure to change "BasicTemplateAlgorithm" to your algorithm class name, and that all
    //	files use "public partial class" if you want to split up your algorithm namespace into multiple files.
    //

    /// <summary>
    /// 
    /// </summary>
    public class ParabolicSAR : WindowIndicator<TradeBar>
    {
        private TradeBar _previousInput;

        public IndicatorBase<TradeBar> _psarInitial { get; private set; }

        public IndicatorBase<TradeBar> _psar { get; private set; }
        public IndicatorBase<TradeBar> _extremePoint { get; private set; }
        public IndicatorBase<TradeBar> _psarEpAcc { get; private set; }

        public IndicatorBase<TradeBar> _previousPsar { get; private set; }
        public IndicatorBase<TradeBar> _previousExtremePoint { get; private set; }
        public IndicatorBase<TradeBar> _acceleration { get; private set; }
        
		private decimal highPoint2;
        private decimal lowPoint2;
        private readonly decimal _accelerationMax;
        private readonly decimal _accelerationMin;
        private static bool _previousTrend;
        public bool _trend;

        /// <summary>
        ///     Initializes a new instance of the LogReturn class with the specified name and period
        /// </summary>
        /// <param name="name">The name of this indicator</param>
        /// <param name="period">The period of the LOGR</param>
        public ParabolicSAR(string name, int period, decimal accelerationLow = 0.02m, decimal accelerationHigh = 0.2m, bool initialTrend = false)
            : base(name, period)
        {
            _accelerationMax = accelerationHigh;
            _accelerationMin = accelerationLow;
            _acceleration = new FunctionalIndicator<TradeBar>(name + "_acceleration",
                currentBar =>
                {
                    var value = ComputeAcceleration(currentBar);
                    return value;
                },
                isReady => _previousInput != null
                ); ;
            _trend = initialTrend;
            _previousTrend = initialTrend;

            // Psar Initial Indicator
            _psarInitial = new FunctionalIndicator<TradeBar>(name + "_psar_initial",
                currentBar =>
                {
                    var value = ComputePsarInitial(currentBar);
                    return value;
                },
                isReady => _previousInput != null
                );

            // Psar Indicator
            _psar = new FunctionalIndicator<TradeBar>(name + "_psar",
                currentBar =>
                {
                    var value = ComputePsar(currentBar);
                    return value;
                },
                isReady => _previousInput != null
                );

            // Extreme Point Indicator
            _extremePoint = new FunctionalIndicator<TradeBar>(name + "_extreme_point",
                currentBar =>
                {
                    var value = ComputeExtremePoint(currentBar);
                    return value;
                },
                isReady => _previousInput != null
                );

            // (Psar - Exteme Point) * Acceleration Indicator
            _psarEpAcc = new FunctionalIndicator<TradeBar>(name + "_psar_ep_acc",
                currentBar =>
                {
                    var value = ComputePsarEpAcc(currentBar);
                    return value;
                },
                isReady => _previousInput != null
                );

            // Previous Psar Indcator
            _previousPsar = new FunctionalIndicator<TradeBar>(name + "_psar_previous",
                currentBar =>
                {
                    var value = ComputePsarPrevious(currentBar);
                    return value;
                },
                isReady => _previousInput != null
                );

            _previousExtremePoint = new FunctionalIndicator<TradeBar>(name + "_previous_extreme_point",
                currentBar =>
                {
                    var value = ComputePreviousExtremePoint(currentBar);
                    return value;
                },
                isReady => _previousInput != null
                );
        }

        /// <summary>
        ///     Initializes a new instance of the LogReturn class with the default name and period
        /// </summary>
        /// <param name="period">The period of the SMA</param>
        public ParabolicSAR(int period, decimal accelerationLow = 0.02m, decimal accelerationHigh = 0.2m, bool initialTrend = false)
            : base("PSAR" + period, period)
        {
            string name = "PSAR";
            _accelerationMax = accelerationHigh;
            _accelerationMin = accelerationLow;
            _acceleration = new FunctionalIndicator<TradeBar>(name + "_acceleration",
                currentBar =>
                {
                    var value = ComputeAcceleration(currentBar);
                    return value;
                },
                isReady => _previousInput != null
                ); ;
            _trend = initialTrend;
            _previousTrend = initialTrend;

            // Psar Initial Indicator
            _psarInitial = new FunctionalIndicator<TradeBar>(name + "_psar_initial",
                currentBar =>
                {
                    var value = ComputePsarInitial(currentBar);
                    return value;
                },
                isReady => _previousInput != null
                );

            // Psar Indicator
            _psar = new FunctionalIndicator<TradeBar>(name + "_psar",
                currentBar =>
                {
                    var value = ComputePsar(currentBar);
                    return value;
                },
                isReady => _previousInput != null
                );

            // Extreme Point Indicator
            _extremePoint = new FunctionalIndicator<TradeBar>(name + "_extreme_point",
                currentBar =>
                {
                    var value = ComputeExtremePoint(currentBar);
                    return value;
                },
                isReady => _previousInput != null
                );

            // (Psar - Exteme Point) * Acceleration Indicator
            _psarEpAcc = new FunctionalIndicator<TradeBar>(name + "_psar_ep_acc",
                currentBar =>
                {
                    var value = ComputePsarEpAcc(currentBar);
                    return value;
                },
                isReady => _previousInput != null
                );

            // Previous Psar Indcator
            _previousPsar = new FunctionalIndicator<TradeBar>(name + "_psar_previous",
                currentBar =>
                {
                    var value = ComputePsarPrevious(currentBar);
                    return value;
                },
                isReady => _previousInput != null
                );

            _previousExtremePoint = new FunctionalIndicator<TradeBar>(name + "_previous_extreme_point",
                currentBar =>
                {
                    var value = ComputePreviousExtremePoint(currentBar);
                    return value;
                },
                isReady => _previousInput != null
                );
        }

        protected override decimal ComputeNextValue(IReadOnlyWindow<TradeBar> window, TradeBar input)
        {
            //////////////////////////////////////////////////////////////////////////////////////////
            if (this.Samples == 1)
            {
                _previousInput = input;
                _extremePoint.Update(input);
                _psar.Update(input);

                //trend is set
                _acceleration.Update(input);
                _psarEpAcc.Update(input);

                _psarInitial.Update(input);
                _previousExtremePoint.Update(input);

                // set psar - ep * acc
                decimal psar = ComputePsar(input);
                _previousPsar.Current.Value = psar;

                highPoint2 = input.High;
                lowPoint2 = input.Low;
                return psar;
            }
            //_psar.Current.

            // update initial psar
            _psarInitial.Update(input);

            // update psar
            _psar.Update(input);

            // set previous trend
            _previousTrend = _trend;

            // update trend
            _trend = _psar.Current.Value <= _previousInput.Close;

            // update extreme point
            _extremePoint.Update(input);

            // update acceleration
            _acceleration.Update(input);

            // update (psar - ep) * ac
            _psarEpAcc.Update(input);

            // set highPoint2, lowPoint2, and previous input.
            highPoint2 = _previousInput.High;
            lowPoint2 = _previousInput.Low;
            _previousInput = new TradeBar(input);

            // set previous psar
            _previousPsar.Current.Value = _psar.Current.Value;

            // update previous extreme point
            _previousExtremePoint.Update(input);

            return _psar.Current.Value;
        }

        private decimal ComputeAcceleration(TradeBar input)
        {
            if (Samples == 1)
            {
                return _accelerationMin;
            }

            decimal acceleration = _acceleration.Current.Value;
            // acceleration can not be higher than the price
            if (_trend == true && _previousTrend == true)
            {
                // 
                if (_extremePoint.Current.Value > _previousExtremePoint.Current.Value && _acceleration <= _accelerationMax)
                {
                    acceleration += _accelerationMin;
                }
                else if (_extremePoint.Current.Value == _previousExtremePoint.Current.Value)
                {
                }
                else
                {
                    acceleration = _accelerationMax;
                }
            }
            // when the trend changes, reset _acceleration to _accelerationMin
            else if (_trend == false && _previousTrend == false)
            {
                if (_extremePoint.Current.Value < _previousExtremePoint.Current.Value && _acceleration <= _accelerationMax)
                {
                    acceleration += _accelerationMin;
                }
                else if (_extremePoint.Current.Value == _previousExtremePoint.Current.Value)
                {
                }    
                else
                {
                    acceleration = _accelerationMax;
                }
            }
            else if (_trend == true && _previousTrend == false)
            {
                acceleration = _accelerationMin;
            }

            if (_previousTrend != _trend)
            {
                acceleration = _accelerationMin;
            }

            return acceleration;
        }

        private decimal ComputePsar(TradeBar input)
        {
            if (Samples == 1)
            {
                return !_trend ? input.High : input.Low;
            }


            //IF(AND(L5=”falling”,C6<J6),J6,IF(AND(L5=”rising”,D6>J6),J6,IF(AND(L5=”falling”,C6>=J6),G5,IF(AND(L5=”rising”,D6<=J6),G5,””))))
            // If the trend is falling and the high price is less than the psar
            if (!_trend && input.High < _psarInitial.Current.Value)
            {
                return _psarInitial.Current.Value;
            }
            else if (_trend && input.Low > _psarInitial.Current.Value)
            {
                return _psarInitial.Current.Value;
            }
            else if (!_trend && input.High >= _psarInitial.Current.Value)
            {
                return _previousExtremePoint.Current.Value;
            }
            else if (_trend && input.Low <= _psarInitial.Current.Value)
            {
                return _previousExtremePoint.Current.Value;
            }

            return 0;
        }

        private decimal ComputePsarInitial(TradeBar input)
        {
            // If the previous trend is falling, the initial psar is the max value
            // of the previous psar - the previous psar - ep  * ac, or the 2 previous high prices
            // If the previous trend is rising, the initial psar is the min value
            // of the previous psar - the previous psar - ep * ac, or the 2 previous low prices
            // 
            //IF(L5=”falling”,MAX(K5-I5,C5,C4),IF(L5=”rising”,MIN(K5-I5,D5,D4),””))
            decimal value = 0m;
            if (Samples == 1)
            {
                return value;
            }
            if (!_trend)
            {
                value = Math.Max(_previousPsar.Current.Value - _psarEpAcc.Current.Value, _previousInput.High);
                if (Samples > 1)
                {
                    value = Math.Max(value, highPoint2);
                }
            }
            else if (_trend)
            {
                value = Math.Min(_previousPsar.Current.Value - _psarEpAcc.Current.Value, _previousInput.Low);
                if (Samples > 2)
                {
                    value = Math.Min(value, lowPoint2);
                }
            }

            return value;
        }
        
        private decimal ComputePsarEpAcc(TradeBar input)
        {
            // (K6-G6)*H6
            // (psar - ep) * acceleration
            if (Samples == 1)
            {
                return (_psar.Current.Value - _extremePoint.Current.Value) * _acceleration.Current.Value;
            }
            decimal psarEpAcc = (_psar.Current.Value - _extremePoint.Current.Value) * _acceleration.Current.Value;
        	return psarEpAcc;
        }
        
        private decimal ComputePsarPrevious(TradeBar input)
        {
            if (Samples == 1)
            {
                return !_trend ? input.Low : input.High;
            }

            decimal psarPrev = _psar.Current.Value;
        	
        	return psarPrev;
        }

        private decimal ComputeExtremePoint(TradeBar input)
        {
            // If trending 
            decimal ep;
            if (Samples == 1)
            {
                ep = !_trend ? input.Low : input.High;
                return ep;
            }
            
            ep = _trend ? Math.Max(_previousExtremePoint.Current.Value, input.High)
                        : Math.Min(_previousExtremePoint.Current.Value, input.Low);

            return ep;
        }

        private decimal ComputePreviousExtremePoint(TradeBar input)
        {
            decimal pep;
            if (Samples == 1)
            {
                pep = !_trend ? input.Low : input.High;
                return pep;
            }

            pep = _extremePoint.Current.Value;

            return pep;
        }
    }
}