#include "sierrachart.h"
#include "scstudyfunctions.h"

/*****************************************************************************

	User note: The functions in this file are intermediate level functions you can
	copy and call from your primary scsf_ functions.  These functions are not
	complete study functions. They are used by primary study functions to
	perform calculations.  Where you see _S at the end, this means that the
	function is a single step function, and only fills in the array element
	at the index specified by the Index parameter.  

*****************************************************************************/

/*==========================================================================*/
SCFloatArrayRef CCI_S(SCFloatArrayRef In, SCFloatArrayRef MAOut, SCFloatArrayRef CCIOut, int Index, int Length, float Multiplier, unsigned int MovingAverageType)
{
	if (Length < 1)
		return CCIOut;

	switch (MovingAverageType)
	{
	case MOVAVGTYPE_EXPONENTIAL:
		ExponentialMovingAverage_S(In, MAOut, Index, Length);
		break;

	case MOVAVGTYPE_LINEARREGRESSION:
		LinearRegressionIndicator_S(In, MAOut, Index, Length);
		break;

	default:  // Unknown moving average type
	case MOVAVGTYPE_SIMPLE:
		SimpleMovAvg_S(In, MAOut, Index, Length);
		break;

	case MOVAVGTYPE_WEIGHTED:
		WeightedMovingAverage_S(In, MAOut, Index, Length);
		break;

	case MOVAVGTYPE_WILDERS:
		WildersMovingAverage_S(In, MAOut, Index, Length);
		break;

	case MOVAVGTYPE_SIMPLE_SKIP_ZEROS:
		SimpleMovAvgSkipZeros_S(In, MAOut, Index, Length);
		break;

	case MOVAVGTYPE_SMOOTHED:
		SmoothedMovingAverage_S(In, MAOut, Index, Length, 0);
		break;
	}

	float Num0 = 0;
	for (int j = Index; j > Index - Length && j >= 0; j--)
		Num0 += fabs(MAOut[Index] - In[j]);

	Num0 /= Length;

	CCIOut[Index] = (In[Index] - MAOut[Index]) / (Num0 * Multiplier);

	return CCIOut;
}

/*==========================================================================*/
SCFloatArrayRef CCISMA_S(SCFloatArrayRef In, SCFloatArrayRef SMAOut, SCFloatArrayRef CCIOut, int Index, int Length, float Multiplier)
{
	return CCI_S(In, SMAOut, CCIOut, Index, Length, Multiplier, MOVAVGTYPE_SIMPLE);
}

/*==========================================================================*/
float GetHighest(SCFloatArrayRef In, int StartIndex, int Length)
{
	float High = -FLT_MAX;
	
	// Get the high from the last Length indexes in the In array
	for (int SrcIndex = StartIndex; SrcIndex > StartIndex - Length; --SrcIndex)
	{
		if (SrcIndex < 0 || SrcIndex >= In.GetArraySize())
			continue;
		
		if (In[SrcIndex] > High)
			High = In[SrcIndex];
	}
	
	return High;
}

/*==========================================================================*/
SCFloatArrayRef Highest_S(SCFloatArrayRef In, SCFloatArrayRef Out, int Index, int Length)
{
	// Get the high from the last Length indexes in the In array
	float High = GetHighest(In, Index, Length);
	
	// Put the high in the Out array
	if (High == -FLT_MAX)
		Out[Index] = 0.0f;
	else
		Out[Index] = High;
	
	return Out;
}

/*==========================================================================*/
float GetLowest(SCFloatArrayRef In, int StartIndex, int Length)
{
	float Low = FLT_MAX;
	
	// Get the low from the last Length indexes in the In array
	for (int SrcIndex = StartIndex; SrcIndex > StartIndex - Length; --SrcIndex)
	{
		if (SrcIndex < 0 || SrcIndex >= In.GetArraySize())
			continue;
		
		if (In[SrcIndex] < Low)
			Low = In[SrcIndex];
	}
	
	return Low;
}

/*==========================================================================*/
SCFloatArrayRef Lowest_S(SCFloatArrayRef In, SCFloatArrayRef Out, int Index, int Length)
{
	// Get the low from the last Length indexes in the In array
	float Low = GetLowest(In, Index, Length);
	
	// Put the low in the Out array
	if (Low == FLT_MAX)
		Out[Index] = 0.0f;
	else
		Out[Index] = Low;
	
	return Out;
}

/*==========================================================================*/
float TrueRange(SCBaseDataRef BaseDataIn, int Index)
{
	if (Index == 0)
		return BaseDataIn[SC_HIGH][0] - BaseDataIn[SC_LOW][0];
	
	float HighLowRange = BaseDataIn[SC_HIGH][Index] - BaseDataIn[SC_LOW][Index];
	float HighToPreviousCloseDifference = fabs(BaseDataIn[SC_HIGH][Index] - BaseDataIn[SC_LAST][Index - 1]);
	float LowToPreviousCloseDifference = fabs(BaseDataIn[SC_LOW][Index] - BaseDataIn[SC_LAST][Index - 1]);
	
	return  max(HighLowRange, max(HighToPreviousCloseDifference, LowToPreviousCloseDifference));
	
}

/*==========================================================================*/
SCFloatArrayRef TrueRange_S(SCBaseDataRef BaseDataIn, SCFloatArrayRef Out, int Index)
{
	Out[Index] = TrueRange(BaseDataIn, Index);
	
	return Out;
}

/*==========================================================================*/
SCFloatArrayRef AverageTrueRange_S(SCBaseDataRef BaseDataIn, SCFloatArrayRef TROut, SCFloatArrayRef ATROut, int Index, int Length, unsigned int MovingAverageType)
{
	// True Range
	TrueRange_S(BaseDataIn, TROut, Index);
	
	// Average
	MovingAverage_S(TROut, ATROut, MovingAverageType, Index, Length);
	
	return ATROut;
}

/*==========================================================================*/
SCFloatArrayRef OnBalanceVolume_S(SCBaseDataRef BaseDataIn, SCFloatArrayRef Out, int Index)
{
	// Min index of 1
	if (Index < 1)
		return Out;
	
	if (BaseDataIn[SC_LAST][Index] > BaseDataIn[SC_LAST][Index - 1])
		Out[Index] = Out[Index - 1] + BaseDataIn[SC_VOLUME][Index];
	else if (BaseDataIn[SC_LAST][Index] < BaseDataIn[SC_LAST][Index - 1])
		Out[Index] = Out[Index - 1] - BaseDataIn[SC_VOLUME][Index];
	else  // Equal
		Out[Index] = Out[Index - 1];
	
	return Out;
}

/*==========================================================================*/
SCFloatArrayRef OnBalanceVolumeShortTerm_S(SCBaseDataRef BaseDataIn, SCFloatArrayRef Out, SCFloatArrayRef OBVTemp, int Index, int Length)
{
	// Need at least two bars in chart
	if (Index < 1)
		return Out;
	
	// OBV
	if (BaseDataIn[SC_LAST][Index - 1] > BaseDataIn[SC_LAST][Index])
	{
		// Since current close is less than previous, subtract
		OBVTemp[Index] = -BaseDataIn[SC_VOLUME][Index];
	}
	else if (BaseDataIn[SC_LAST][Index - 1] < BaseDataIn[SC_LAST][Index])
	{
		// Add
		OBVTemp[Index] = BaseDataIn[SC_VOLUME][Index];
	}
	else  // Equal
	{
		// Do not change
		OBVTemp[Index] = 0;
	}
	
	// Prevent looking back into a negative array index
	if (Index < Length)
	{
		// Regular OBV for first N terms
		Out[Index] = Out[Index -1] + OBVTemp[Index];
	}
	else
	{
		// Adjust current OBV by subtracting what we did to get the
		// previous OBV.  Example, if at position 11, data was added to OBV, then
		// at position 12, that data would be subtracted to make it a
		// 'zero' start.
		Out[Index] = Out[Index - 1] + OBVTemp[Index] - OBVTemp[Index - Length];
	}
	
	return Out;
}

/*==========================================================================*/
SCFloatArrayRef MovingAverage_S(SCFloatArrayRef In, SCFloatArrayRef Out, unsigned int MovingAverageType, int Index, int Length)
{
	switch (MovingAverageType)
	{
		case MOVAVGTYPE_EXPONENTIAL:
		return ExponentialMovingAverage_S(In, Out, Index, Length);
		
		case MOVAVGTYPE_LINEARREGRESSION:
		return LinearRegressionIndicator_S(In, Out, Index, Length);
		
		default:  // Unknown moving average type
		case MOVAVGTYPE_SIMPLE:
		return SimpleMovAvg_S(In, Out, Index, Length);
		
		case MOVAVGTYPE_WEIGHTED:
		return WeightedMovingAverage_S(In, Out, Index, Length);
		
		case MOVAVGTYPE_WILDERS:
		return WildersMovingAverage_S(In, Out, Index, Length);

		case MOVAVGTYPE_SIMPLE_SKIP_ZEROS:
		return SimpleMovAvgSkipZeros_S(In, Out, Index, Length);

		case MOVAVGTYPE_SMOOTHED:
		return SmoothedMovingAverage_S(In, Out, Index, Length,0);

	}
}

/*==========================================================================*/
void Stochastic_S(SCBaseDataRef BaseDataIn, SCFloatArrayRef FastKOut, SCFloatArrayRef FastDOut, SCFloatArrayRef SlowDOut, int Index, int FastKLength, int FastDLength, int SlowDLength, unsigned int MovingAverageType)
{
	Stochastic2_S(BaseDataIn[SC_HIGH], BaseDataIn[SC_LOW], BaseDataIn[SC_LAST],  FastKOut,  FastDOut,  SlowDOut,  Index,  FastKLength,  FastDLength,  SlowDLength, MovingAverageType);
}

/*==========================================================================*/
void Stochastic2_S(SCFloatArrayRef InputDataHigh, SCFloatArrayRef InputDataLow, SCFloatArrayRef InputDataLast, SCFloatArrayRef FastKOut, SCFloatArrayRef FastDOut, SCFloatArrayRef SlowDOut, int Index, int FastKLength, int FastDLength, int SlowDLength, unsigned int MovingAverageType)
{
	float High = GetHighest(InputDataHigh, Index, FastKLength);
	float Low = GetLowest(InputDataLow, Index, FastKLength);

	float Range = High - Low;
	if (Range == 0)
		FastKOut[Index] = 100.0f;
	else
		FastKOut[Index] = 100.0f * (InputDataLast[Index] - Low) / Range;

	MovingAverage_S(FastKOut, FastDOut, MovingAverageType, Index, FastDLength);
	MovingAverage_S(FastDOut, SlowDOut, MovingAverageType, Index, SlowDLength);
}

/*============================================================================
	This function calculates an exponential moving average of the In array
	and puts the results in the Out array.
----------------------------------------------------------------------------*/
SCFloatArrayRef ExponentialMovingAverage_S(SCFloatArrayRef In, SCFloatArrayRef Out, int Index, int Length)
{
	if (Index >= In.GetArraySize())
		return Out;

	if(Index < 1 || Length < 1)
		return Out;

	if (Index < Length -1)
		Length = Index+1;

	
	double Multiplier1 = 2.0f / (Length + 1);
	double Multiplier2 = 1.0f - Multiplier1;
	double PreviousMovingAverageValue = Out[Index - 1 ];

	//Check for a previous moving average value of 0 so we can properly initialize the previous value, and also check for out of range values.
	if (PreviousMovingAverageValue == 0.0f
		|| !((PreviousMovingAverageValue > -FLT_MAX) && (PreviousMovingAverageValue < FLT_MAX)))
	{
		Out[Index - 1] = In[Index - 1];
	}
	

	float Average = (float)((Multiplier1 * In[Index]) + (Multiplier2 * Out[Index - 1]));
	Out[Index] = Average;
	
	
	return  Out;
}
/*==========================================================================*/
void CalculateRegressionStatistics(SCFloatArrayRef In, double &Slope, double &Y_Intercept, int Index, int Length)
{
	double sum_y=0, sum_x=0, sum_x2=0, sum_x_2=0, sum_xy=0;
	
	if (Index < ( Length - 1 ) )
	{
		Index = Length - 1;
	}


	sum_x = (float)((Length * (Length+1)) / 2.0);
	sum_x_2 =  sum_x * sum_x;
	sum_y = GetSummation(In, Index, Length);
	for(int Offset=0; Offset < Length; Offset++)
	{	

		sum_xy +=	In[Index-Offset]  * (Length-Offset);				
	}

	sum_x2=(Length+1)*Length*(2*Length+1)/6.0f; 

	double b_numerator		= (Length * sum_xy - sum_x * sum_y);
	double b_denominator	= Length * sum_x2 - sum_x_2;
	Slope	= b_numerator / b_denominator;
	Y_Intercept = (sum_y - Slope * sum_x) / Length;
	


}
/*==========================================================================*/
void CalculateLogLogRegressionStatistics(SCFloatArrayRef In, double &Slope, double &Y_Intercept, int Index, int Length)
{

	if (Index <= (Length - 1)) //This prevents processing if there is insufficient data and prevents processing of index 0 which is not possible in order to avoid taking the logarithm of 0.
		return;

	double sum_y = 0, sum_x = 0, sum_x2 = 0, sum_x_2 = 0, sum_xy = 0;

	for (int Offset = 0; Offset < Length; Offset++)
	{
		float ValueAtIndex = In[Index - Offset];
		int XCoordinate = Index - Offset;

		sum_x += log(XCoordinate);

		sum_x2 += log(XCoordinate) * log(XCoordinate);

		if (ValueAtIndex != 0)
		{
			sum_y += log(ValueAtIndex);

			sum_xy += log(XCoordinate)  * log(ValueAtIndex);
		}
	}

	sum_x_2 = sum_x * sum_x;

	double b_numerator = (Length * sum_xy - sum_x * sum_y);
	double b_denominator = Length * sum_x2 - sum_x_2;
	Slope = b_numerator / b_denominator;
	Y_Intercept = (sum_y - Slope * sum_x) / Length;
}

/*==========================================================================*/
SCFloatArrayRef LinearRegressionIndicator_S(SCFloatArrayRef In, SCFloatArrayRef Out, int Index, int Length)
{
	if (Index >= In.GetArraySize())
		return Out;

	double Slope = 0;
	double Y_Intercept = 0;
	CalculateRegressionStatistics(In, Slope, Y_Intercept, Index, Length);

	//compute the end point of the linear regression trendline == linear regression indicator.
	Out[Index] = (float)(Y_Intercept + Slope * Length);

	return Out;
}

/*==========================================================================*/
// Calculates the Linear Regression Indicator. Also computes standard error which is the last value of a linear regression trend line.

SCFloatArrayRef LinearRegressionIndicatorAndStdErr_S(SCFloatArrayRef In, SCFloatArrayRef Out, SCFloatArrayRef StdErr, int Index, int Length)
{
	if (Index >= In.GetArraySize())
		return Out;
	
	double Slope = 0;
	double Y_Intercept = 0;
	double sum_y = 0, sum_x = 0, sum_x2 = 0, sum_y2 = 0, sum_x_2 = 0, sum_y_2 = 0, sum_xy = 0;

	if (Index < (Length - 1))
	{
		Index = Length - 1;
	}


	sum_x = (float)((Length * (Length + 1)) / 2.0);
	sum_x_2 = sum_x * sum_x;
	sum_y = GetSummation(In, Index, Length);
	sum_y_2 = sum_y * sum_y;
	for (int nn = 0; nn < Length; nn++)
	{

		sum_y2 += In[Index - nn] * In[Index - nn];

		sum_xy += In[Index - nn] * (Length - nn);
	}

	sum_x2 = (Length + 1)*Length*(2 * Length + 1) / 6.0f;

	double Slope_numerator = (Length * sum_xy - sum_x * sum_y);
	double Slope_denominator = Length * sum_x2 - sum_x_2;
	Slope = Slope_numerator / Slope_denominator;
	Y_Intercept = (sum_y - Slope * sum_x) / Length;

	//compute the end point of the linear regression trendline == linear regression indicator.
	Out[Index] = (float)(Y_Intercept + Slope * Length);

	// compute the standard error
	double temp = (1.0 / (Length * (Length-2.0))) * ( Length * sum_y2 - sum_y_2 - Slope * Slope_numerator);
	
	// Check to ensure the data is non-negative before performing the square root operation.
	if(temp > 0)
	{
		StdErr[Index] = (float)sqrt(temp);
	}
	else
	{
		StdErr[Index]	= 0;
	}

	return Out;
}

/*============================================================================
	This function calculates an adaptive moving average of the In array and
	puts the results in the Out array.
----------------------------------------------------------------------------*/
SCFloatArrayRef AdaptiveMovAvg_S(SCFloatArrayRef In, SCFloatArrayRef Out, int Index, int Length, float FastSmoothConst, float SlowSmoothConst)
{
	if (Index >= In.GetArraySize())
		return Out;
	
	if (Length < 1)
		return Out;
	
	FastSmoothConst = 2 / (FastSmoothConst + 1);
	SlowSmoothConst = 2 / (SlowSmoothConst + 1);
	
	int StartIndex = max(Length, Index);

	float Direction = (In[StartIndex] - In[StartIndex - Length]);
	float InputArrayDiffSum = 0.0f;
	
	for (int SumIndex = StartIndex - (Length - 1); SumIndex <= StartIndex; SumIndex++)
	{
		InputArrayDiffSum += fabs(In[SumIndex] - In[SumIndex - 1]);
	}

	float Volatility = InputArrayDiffSum;
	
	if (Volatility == 0.0f)
		Volatility = .000001f;
		
	float DirectionVolatilityRatio = fabs(Direction / Volatility);

	float Multiplier = DirectionVolatilityRatio * (FastSmoothConst - SlowSmoothConst) + SlowSmoothConst;

	Multiplier = Multiplier * Multiplier;
	
	if (Out[StartIndex - 1]==0.0f)
		Out[StartIndex] = In[StartIndex - 1] + Multiplier * (In[StartIndex] - In[StartIndex - 1]);
	else
		Out[StartIndex] = Out[StartIndex - 1] + Multiplier * (In[StartIndex] - Out[StartIndex - 1]);

	return Out;
}

/*============================================================================
	This function calculates a simple moving average of the In array and puts
	the results in the Out array.
----------------------------------------------------------------------------*/
SCFloatArrayRef SimpleMovAvg_S(SCFloatArrayRef In, SCFloatArrayRef Out, int Index, int Length)
{
	
	if (Length < 1)
		return Out;
	
	float sum = 0;

	if (Index < Length -1)
		Length = Index+1;
		
	for(int InputIndex = Index - Length + 1; InputIndex <= Index; InputIndex++)
		sum = sum + In[InputIndex]; 
	
	Out[Index] = sum / Length;

	return Out;
}

/*==========================================================================*/
SCFloatArrayRef MovingMedian_S(SCFloatArrayRef In, SCFloatArrayRef Out, SCFloatArrayRef Temp, int Index, int Length)
{
	//Adjust the Length
	if (Index + 1 < Length)
		Length = Index + 1;

	int BaseIndex = Index - Length + 1;

	if (BaseIndex < 0)//Unnecessary but for safety.
		return Out;

	// Make a copy of the elements to be sorted
	for (int a = BaseIndex; a <= Index; ++a)
		Temp[a] = In[a];

	// This section of code sorts the temporary array just enough to figure
	// out what the middle element is, which is what we need to know to get
	// the median.
	{
		int MiddleIndex = BaseIndex + Length / 2;

		int Bottom = BaseIndex, Top = Index;
		while (Bottom < Top)
		{
			float MiddleValue = Temp[MiddleIndex];

			int NextBottom = Bottom;
			int NextTop = Top;
			do
			{
				while (Temp[NextBottom] < MiddleValue)
					++NextBottom;

				while (Temp[NextTop] > MiddleValue)
					--NextTop;

				if (NextBottom <= NextTop)
				{
					float SwapTemp = Temp[NextBottom];
					Temp[NextBottom] = Temp[NextTop];
					Temp[NextTop] = SwapTemp;

					++NextBottom;
					--NextTop;
				}
			} while (NextBottom <= NextTop);

			if (NextBottom > MiddleIndex)
				Top = NextTop;

			if (NextTop < MiddleIndex)
				Bottom = NextBottom;
		}
	}

	if (Length % 2 != 0)//Has a remainder
	{
		Out[Index] = Temp[BaseIndex + Length / 2];
	}
	else
	{
		Out[Index] = (Temp[BaseIndex + Length / 2 - 1] + Temp[BaseIndex + Length / 2]) / 2;
	}

	return Out;
}

/*==========================================================================*/
SCFloatArrayRef SimpleMovAvgSkipZeros_S(SCFloatArrayRef In, SCFloatArrayRef Out, int Index, int Length)
{
	int count = 0;
	float Sum = 0.0f;

	if (Length > Index + 1)
		Length = Index + 1;

	for(int ArrayIndex= Index - Length + 1; ArrayIndex <= Index; ArrayIndex++)
	{
		float Value = In[ArrayIndex];

		if (Value != 0.0f)
		{
			Sum += Value;
			count++;
		}
	}

	if (count > 0)
	{
		Out[Index] = Sum / count;
	}
	else
	{
		Out[Index] = 0.0f;
	}

	return Out;
}

/*==========================================================================*/
SCFloatArrayRef WildersMovingAverage_S(SCFloatArrayRef In, SCFloatArrayRef Out, int Index, int Length)
{
	
	if (Index < 1)
		return Out;


	if (Out[Index - 1] == 0.0)
	{
		SimpleMovAvgSkipZeros_S(In, Out, Index - 1, Length);
	}

	if (Out[Index - 1] != 0.0)
	{
		Out[Index] = Out[Index - 1]
			+ (
			(1.0f / (float)Length)
				*(In[Index] - Out[Index - 1])
				);
	}
	
	return Out;
}

/*==========================================================================*/
SCFloatArrayRef WeightedMovingAverage_S(SCFloatArrayRef In, SCFloatArrayRef Out, int Index, int Length)
{
	if (Length < 1)
		return Out;

	// Adjust Length based on Index in the case where the Length is greater the available number of array elements.
	if (Length - 1 > Index)
		Length = Index + 1;
	
	double Sum = 0;
	double Divider = (Length * (Length+1.0) / 2.0);

	int CurrentWeight = Length;
	for(int PriorIndex=Index; PriorIndex > Index - Length; PriorIndex--)
	{
		Sum += In[PriorIndex] * (float)(CurrentWeight);
		CurrentWeight--;
	}

	Out[Index] = (float) (Sum /  Divider);
	
	return Out;
}

/*==========================================================================*/
SCFloatArrayRef HullMovingAverage_S(SCFloatArrayRef In, SCFloatArrayRef Out, SCFloatArrayRef InternalArray1, SCFloatArrayRef InternalArray2, SCFloatArrayRef InternalArray3, int Index, int Length)
{

	int HalfLength = Length/2;  // integer of Length/2

	WeightedMovingAverage_S(In, InternalArray1, Index, HalfLength);
	WeightedMovingAverage_S(In, InternalArray2, Index, Length);

	float WeightedAverage1AtIndex = InternalArray1[Index];
	float WeightedAverage2AtIndex = InternalArray2[Index];
	InternalArray3[Index] = 2*WeightedAverage1AtIndex - WeightedAverage2AtIndex;

	int RoundedSquareRootOfLength = int(sqrt((double)Length) + 0.5);  // rounded square root of Length
	WeightedMovingAverage_S(InternalArray3, Out, Index, RoundedSquareRootOfLength); // HMA

	return Out;
}

/*==========================================================================*/
SCFloatArrayRef TriangularMovingAverage_S(SCFloatArrayRef In, SCFloatArrayRef Out, SCFloatArrayRef InternalArray1, int Index, int Length)
{


	int Length1, Length2;

	if(Length % 2)
	{
		Length1 = Length2 = Length/2 + 1;
	}
	else
	{
		Length1 = Length/2;
		Length2 = Length1 + 1;
	}

	SimpleMovAvg_S(In,  InternalArray1, Index, Length1);
	SimpleMovAvg_S( InternalArray1, Out, Index, Length2);

	return Out;
}

/*==========================================================================*/
SCFloatArrayRef VolumeWeightedMovingAverage_S(SCFloatArrayRef InPrice, SCFloatArrayRef InVolume, SCFloatArrayRef Out, int Index, int Length)
{


	float summPV = 0;
	float summV = 0;

	for(int i = max(0, Index - Length + 1); i<=Index; i++)
	{
		summPV += InPrice[i]*InVolume[i];
		summV  += InVolume[i];
	}

	if (summV!=0.0f)
	{
		Out[Index] = summPV/summV;
	}
	else
	{
		Out[Index] = 0;
	}

	return Out;
}
/*==========================================================================*/
void GetStandardDeviation(SCFloatArrayRef In, float& Out, int StartIndex, int Length)
{
	double Variance = 0;	

	Variance = GetVariance(In, StartIndex, Length);

	if(Variance < 0)
	{
		Out = 0;
	}
	else
	{
		Out = (float)sqrt(Variance);	
	}
}

/*==========================================================================*/
SCFloatArrayRef StandardDeviation_S(SCFloatArrayRef In, SCFloatArrayRef Out, int Index, int Length)
{	
	GetStandardDeviation(In, Out[Index], Index, Length);
	
	return Out;
}

/*==========================================================================*/
SCFloatArrayRef Ergodic_S(SCFloatArrayRef In, SCFloatArrayRef Out, int Index, int LongEMALength, int ShortEMALength, float Multiplier,
	SCFloatArrayRef InternalArray1, SCFloatArrayRef InternalArray2, SCFloatArrayRef InternalArray3, SCFloatArrayRef InternalArray4, SCFloatArrayRef InternalArray5, SCFloatArrayRef InternalArray6)
{
	// Formula:
	// Numerator = EMA( EMA(Price - LastPrice, LongEMALength), ShortEMALength)
	// Denominator = EMA( EMA( Abs(Price - LastPrice), LongEMALength), ShortEMALength)
	// TSI = Multiplier * Numerator / Denominator
	
	if (Index < 1)
		return Out;  // Not enough elements
	
	// Internal array names
	SCFloatArrayRef PriceChangeArray = InternalArray1;
	//InternalArray2
	SCFloatArrayRef NumeratorArray = InternalArray3;
	SCFloatArrayRef AbsPriceChangeArray = InternalArray4;
	//InternalArray5
	SCFloatArrayRef DenominatorArray = InternalArray6;
	
	float PriceChange = In[Index] - In[Index - 1];  // Price - LastPrice
	
	// Numerator
	PriceChangeArray[Index] = PriceChange;
	ExponentialMovingAverage_S(PriceChangeArray, InternalArray2, Index, LongEMALength);
	ExponentialMovingAverage_S(InternalArray2, NumeratorArray, Index, ShortEMALength);
	float Numerator = NumeratorArray[Index];
	
	// Denominator
	AbsPriceChangeArray[Index] = abs(PriceChange);
	ExponentialMovingAverage_S(AbsPriceChangeArray, InternalArray5, Index, LongEMALength);
	ExponentialMovingAverage_S(InternalArray5, DenominatorArray, Index, ShortEMALength);
	float Denominator = DenominatorArray[Index];
	
	Out[Index] = Multiplier * Numerator / Denominator;
	
	return Out;
}


/*==========================================================================*/
SCFloatArrayRef Keltner_S(SCBaseDataRef BaseDataIn, SCFloatArrayRef In, SCFloatArrayRef KeltnerAverageOut, SCFloatArrayRef TopBandOut, SCFloatArrayRef BottomBandOut, int Index, int KeltnerMALength, unsigned int KeltnerMAType, int TrueRangeMALength, unsigned int TrueRangeMAType, float TopBandMultiplier, float BottomBandMultiplier, SCFloatArrayRef InternalArray1, SCFloatArrayRef InternalArray2)
{
	MovingAverage_S(In, KeltnerAverageOut, KeltnerMAType, Index, KeltnerMALength);
	
	AverageTrueRange_S(BaseDataIn, InternalArray1, InternalArray2, Index, TrueRangeMALength, TrueRangeMAType);
	
	TopBandOut[Index] = KeltnerAverageOut[Index] + InternalArray2[Index] * TopBandMultiplier;
	BottomBandOut[Index] = KeltnerAverageOut[Index] - InternalArray2[Index] * BottomBandMultiplier;
	
	return KeltnerAverageOut;
}

/*==========================================================================*/
float WellesSum(float In, int Index, int Length, SCFloatArrayRef Out)
{
	if (Index == 0)
	{
		Out[0] = In;
	}
	else
	{
		if (Index < Length)
			Out[Index] = Out[Index - 1] + In;
		else
			Out[Index] = Out[Index - 1] - (Out[Index - 1] / Length) + In;
	}
	
	return Out[Index];
}

/*==========================================================================*/
SCFloatArrayRef WellesSum_S(SCFloatArrayRef In, SCFloatArrayRef Out, int Index, int Length)
{
	WellesSum(In[Index], Index, Length, Out);
	
	return Out;
}

/*============================================================================
	Local function
	This function is used by DMI, ADX, and ADXR.
----------------------------------------------------------------------------*/
void DirectionalMovementTrueRangeSummation(SCBaseDataRef BaseDataIn, int Index, int Length,
	SCFloatArrayRef InternalTrueRangeSummation, SCFloatArrayRef InternalPosDM, SCFloatArrayRef InternalNegDM)
{
	if (Index < 1)
		return;
	
	float HighChange = BaseDataIn[SC_HIGH][Index] - BaseDataIn[SC_HIGH][Index - 1];
	float LowChange = BaseDataIn[SC_LOW][Index - 1] - BaseDataIn[SC_LOW][Index];

	float PercentDifference = fabs(1-(HighChange / LowChange));//.001 = .1%
	
	{
		float Positive = 0.0f;
		if (HighChange > LowChange && HighChange > 0 && PercentDifference >= 0.001)
			Positive = HighChange;
		
		WellesSum(Positive, Index, Length, InternalPosDM);
	}
	
	{
		float Negative = 0.0f;
		if (LowChange > HighChange && LowChange > 0 && PercentDifference >= 0.001)
			Negative = LowChange;
		
		WellesSum(Negative, Index, Length, InternalNegDM);
	}
	
	float TrueRangeValue = TrueRange(BaseDataIn, Index);
	WellesSum(TrueRangeValue, Index, Length, InternalTrueRangeSummation);
}

/*==========================================================================*/
void DMI_S(SCBaseDataRef BaseDataIn, int Index, int Length, int DisableRounding,
	SCFloatArrayRef PosDMIOut, SCFloatArrayRef NegDMIOut, SCFloatArrayRef DiffDMIOut, SCFloatArrayRef InternalTrueRangeSummation, SCFloatArrayRef InternalPosDM, SCFloatArrayRef InternalNegDM)
{
	DirectionalMovementTrueRangeSummation(BaseDataIn, Index, Length,
		InternalTrueRangeSummation, InternalPosDM, InternalNegDM);
	
	if (InternalTrueRangeSummation[Index] == 0.0f)  // Simple prevention of dividing by zero
	{
		PosDMIOut[Index] = PosDMIOut[Index - 1];
		NegDMIOut[Index] = NegDMIOut[Index -1];
	}
	else
	{
		PosDMIOut[Index] = 100.0f * InternalPosDM[Index] / InternalTrueRangeSummation[Index];
		NegDMIOut[Index] = 100.0f * InternalNegDM[Index] / InternalTrueRangeSummation[Index];
		
	}

	DiffDMIOut[Index] = fabs(PosDMIOut[Index] - NegDMIOut[Index]);
}

/*============================================================================*/
SCFloatArrayRef DMIDiff_S(SCBaseDataRef BaseDataIn,
	int Index,
	int Length,
	SCFloatArrayRef Out,
	SCFloatArrayRef InternalTrueRangeSummation, SCFloatArrayRef InternalPosDM, SCFloatArrayRef InternalNegDM)
{
	
	if (Index <= Length - 1)
	{
		Out[Index] = 0.0f;
		return Out;
	}


	DirectionalMovementTrueRangeSummation(BaseDataIn, Index, Length,
		InternalTrueRangeSummation, InternalPosDM, InternalNegDM);
	
	
	float TrueRangeSum = InternalTrueRangeSummation[Index];

	if (TrueRangeSum == 0.0f)
	{
		Out[Index] = Out[Index-1];
	}
	else
	{
		float PosDMI = 100.0f * InternalPosDM[Index] / TrueRangeSum;
		float NegDMI = 100.0f * InternalNegDM[Index] / TrueRangeSum;
		Out[Index] = PosDMI - NegDMI;
	}
	
	
	
	return Out;
}

/*==========================================================================*/
SCFloatArrayRef ADX_S(SCBaseDataRef BaseDataIn,
	int Index,
	int DXLength, int DXMovAvgLength,
	SCFloatArrayRef Out,
	SCFloatArrayRef InternalTrueRangeSummation, 
	SCFloatArrayRef InternalPosDM,
	SCFloatArrayRef InternalNegDM, 
	SCFloatArrayRef InternalDX)
{
	DirectionalMovementTrueRangeSummation(BaseDataIn, Index, DXLength,
		InternalTrueRangeSummation, InternalPosDM, InternalNegDM);
	
	// Compute +DMI and -DMI identically to how it is done in DMI without rounding
	float PosDMI = 100.0f, NegDMI = 100.0f;
	float TrueRangeSum = InternalTrueRangeSummation[Index];

	if (TrueRangeSum != 0.0f)
	{
		PosDMI *= InternalPosDM[Index] / TrueRangeSum;
		NegDMI *= InternalNegDM[Index] / TrueRangeSum;
	}
	
// 	if (PosDMI - NegDMI == 0.0f)  // Quick zero (also preventing potential divide by zero)
// 		InternalDX[Index] = 0.0f;
// 	else if (PosDMI + NegDMI == 0.0f)  // Simple prevention of dividing by zero
// 		InternalDX[Index] = 100.0f;
// 	else
// 		InternalDX[Index] = 100.0f * fabs(PosDMI - NegDMI) / (PosDMI + NegDMI);

	if (PosDMI + NegDMI == 0.0f)  // Simple prevention of dividing by zero
		InternalDX[Index] = InternalDX[Index - 1];
	else
		InternalDX[Index] = 100.0f * fabs(PosDMI - NegDMI) / (PosDMI + NegDMI);
	
	if (Index < DXLength - 1)
		return Out;
	
	if (Index == DXLength + DXMovAvgLength - 1)
	{
		Out[Index] = 0.0f;
		for (int IDXIndex = 0; IDXIndex < DXMovAvgLength; ++IDXIndex)
			Out[Index] += InternalDX[Index - IDXIndex];
		
		Out[Index] = Out[Index] / ( DXMovAvgLength); //DXLength +
	}
	else if (Index > DXLength + DXMovAvgLength - 1)
	{
		// Take the average of DX to get ADX
		WildersMovingAverage_S(InternalDX, Out, Index, DXMovAvgLength);
	}
	
	return Out;
}

/*============================================================================
	Note: The InternalADX array does not contain the same values as the
	output of ADX.
----------------------------------------------------------------------------*/
SCFloatArrayRef ADXR_S(SCBaseDataRef BaseDataIn,
	int Index,
	int DXLength, int DXMovAvgLength, int ADXRInterval,
	SCFloatArrayRef Out,
	SCFloatArrayRef InternalTrueRangeSummation, SCFloatArrayRef InternalPosDM, SCFloatArrayRef InternalNegDM, SCFloatArrayRef InternalDX, SCFloatArrayRef InternalADX)
{
	if (Index < 1)
		return Out;

	DirectionalMovementTrueRangeSummation(BaseDataIn, Index, DXLength,
		InternalTrueRangeSummation, InternalPosDM, InternalNegDM);
	
	// Compute +DMI and -DMI identically to how it is done in DMI without rounding
	float PosDMI = 100.0f, NegDMI = 100.0f;
	float TrueRangeSum = InternalTrueRangeSummation[Index];
	if (TrueRangeSum != 0.0f)
	{
		PosDMI *= InternalPosDM[Index] / TrueRangeSum;
		NegDMI *= InternalNegDM[Index] / TrueRangeSum;
	}
	

	if (PosDMI + NegDMI == 0.0f)  // Simple prevention of dividing by zero
		InternalDX[Index] = InternalDX[Index - 1];
	else
		InternalDX[Index] = 100.0f * fabs(PosDMI - NegDMI) / (PosDMI + NegDMI);
	
	if (Index < DXLength - 1)
		return Out;
	
	if (Index == DXLength + DXMovAvgLength - 1)
	{
		InternalADX[Index] = 0.0f;

		for (int IDXIndex = 0; IDXIndex < DXMovAvgLength; ++IDXIndex)
			InternalADX[Index] += InternalDX[Index - IDXIndex];
		
		InternalADX[Index] = InternalADX[Index] / DXMovAvgLength;
	}
	else if (Index > DXLength + DXMovAvgLength - 1)
	{
		// Take the average of DX to get ADX
		WildersMovingAverage_S(InternalDX, InternalADX, Index, DXMovAvgLength);
	}
	
	if (Index < DXLength + DXMovAvgLength + ADXRInterval - 2)
		return Out;
	
	Out[Index] = (InternalADX[Index] + InternalADX[Index - ADXRInterval + 1]) * 0.5f;
	
	return Out;
}

/*==========================================================================*/
SCFloatArrayRef RSI_S(SCFloatArrayRef In, 
								SCFloatArrayRef RSIOut, 
								SCFloatArrayRef UpSumsTemp, 
								SCFloatArrayRef DownSumsTemp, 
								SCFloatArrayRef SmoothedUpSumsTemp, 
								SCFloatArrayRef SmoothedDownSumsTemp,
								int Index, unsigned int AveragingType, int Length)
{
	if (Length < 1 || Index < 1)
		return RSIOut;

	// calculate Up/Down sums
	float PreviousValue = In[Index - 1];
	float CurrentValue = In[Index];

	if (CurrentValue>PreviousValue) 
	{
		// upward change
		UpSumsTemp[Index] = CurrentValue - PreviousValue;
		DownSumsTemp[Index] = 0;
	}
	else
	{
		UpSumsTemp[Index] = 0;
		DownSumsTemp[Index] = PreviousValue - CurrentValue;
	}

	// smooth the up/down sums
	MovingAverage_S(UpSumsTemp, SmoothedUpSumsTemp, AveragingType, Index, Length);
	MovingAverage_S(DownSumsTemp, SmoothedDownSumsTemp, AveragingType, Index, Length);

	// compute RSI
	if (SmoothedDownSumsTemp[Index] != 0.0f)//avoid division by zero
	{
		RSIOut[Index] = 100.0f - 100.0f / (1 + SmoothedUpSumsTemp[Index] / (SmoothedDownSumsTemp[Index]) );
	}
	else
	{
		RSIOut[Index] = 100; // RSIOut[Index - 1];
	}

	return RSIOut;
}

/*==========================================================================*/
SCFloatArrayRef SmoothedMovingAverage_S(SCFloatArrayRef In, SCFloatArrayRef SmoothedAverageOut, int Index, int Length, int Offset)
{
	if (Length < 1 || Offset < 0)
		return SmoothedAverageOut;
	
	int InputIndex = Index - Offset; 
	
	if (Index == 0)
		return SmoothedAverageOut;

	//Adjust Length down based on the available number of bars
	if (Index < Length - 1)
		Length = Index + 1;
	
	// Initialize the prior Smoothed moving average value to a simple moving average value if it is not set
	if (SmoothedAverageOut[Index-1] == 0)
		SimpleMovAvg_S(In, SmoothedAverageOut, InputIndex - 1, Length);


	float PriorSummation = GetSummation(In, InputIndex-1 , Length);

	float InputValueAtInputIndex = In[InputIndex];


	SmoothedAverageOut[Index] = (PriorSummation -  SmoothedAverageOut[Index - 1] + InputValueAtInputIndex) / Length;


	return SmoothedAverageOut;
}

/*==========================================================================*/
SCFloatArrayRef MACD_S(SCFloatArrayRef In, SCFloatArrayRef FastMAOut, SCFloatArrayRef SlowMAOut, SCFloatArrayRef MACDOut, SCFloatArrayRef MACDMAOut, SCFloatArrayRef MACDDiffOut, int Index, int FastMALength, int SlowMALength, int MACDMALength, int MovAvgType)
{

	MovingAverage_S(In,FastMAOut,MovAvgType,Index,FastMALength);
	MovingAverage_S(In,SlowMAOut,MovAvgType,Index,SlowMALength);

		
	MACDOut[Index] = FastMAOut[Index] - SlowMAOut[Index];

	if(Index< max(SlowMALength,FastMALength) + MACDMALength)
		return MACDOut;

	MovingAverage_S(MACDOut,MACDMAOut,MovAvgType,Index,MACDMALength);


	MACDDiffOut[Index] = MACDOut[Index] - MACDMAOut[Index];

	return MACDOut;
}

/*==========================================================================*/
SCFloatArrayRef TEMA_S(SCFloatArrayRef In, SCFloatArrayRef Out, SCFloatArrayRef InternalArray1,SCFloatArrayRef InternalArray2,SCFloatArrayRef InternalArray3, int Index, int  Length)
{

	ExponentialMovingAverage_S(In, InternalArray1, Index, Length);
	ExponentialMovingAverage_S(InternalArray1, InternalArray2, Index, Length);
	ExponentialMovingAverage_S(InternalArray2, InternalArray3, Index, Length);

	Out[Index] = 3.0f*InternalArray1[Index] - 3.0f*InternalArray2[Index] + InternalArray3[Index];
	return Out;
}


/*==========================================================================*/
SCFloatArrayRef BollingerBands_S(SCFloatArrayRef In, SCFloatArrayRef Avg, SCFloatArrayRef TopBand, SCFloatArrayRef BottomBand, SCFloatArrayRef StdDev, int Index, int  Length, float Multiplier, int MovAvgType)
{
	if(Length < 1)
	{

		return Avg;
	}

	StandardDeviation_S( In, StdDev,  Index,  Length);
	
	MovingAverage_S( In,  Avg, MovAvgType,  Index,  Length);

	TopBand[Index] = (float)((double)Avg[Index]+ ((double)StdDev[Index] * (double)Multiplier));
	BottomBand[Index] = (float)((double)Avg[Index]- ((double)StdDev[Index] * (double)Multiplier));
	return Avg;
}


/*==========================================================================*/
//This calculates the Bollinger Bands using a different method. The difference is the standard deviation is calculated on the moving average rather than the underlying chart data.
SCFloatArrayRef BollingerBands_StandardDeviationOfAverage_S(SCFloatArrayRef In, SCFloatArrayRef Avg, SCFloatArrayRef TopBand, SCFloatArrayRef BottomBand, SCFloatArrayRef StdDev, int Index, int  Length, float Multiplier, int MovAvgType)
{
	if(Length < 1)
	{

		return Avg;
	}

	MovingAverage_S( In,  Avg, MovAvgType,  Index,  Length);

	StandardDeviation_S(Avg, StdDev,  Index,  Length);

	TopBand[Index] = Avg[Index]+ (StdDev[Index] * Multiplier);
	BottomBand[Index] = Avg[Index]- (StdDev[Index] * Multiplier);
	return Avg;
}
/*==========================================================================*/

void Summation(SCFloatArrayRef in, float& out, int start_indx, int length)
{
	float sum=0;
	out = 0;
	if (start_indx < ( length - 1 ) )
	{
		start_indx = length - 1;
	}


	
	if (start_indx >= in.GetArraySize())
		return;

	for(int nn=0;nn<length;nn++)
	{
		sum += in[start_indx-nn];
	}
	out = sum;
}

/*==========================================================================*/
float GetSummation(SCFloatArrayRef In,int Index,int Length)
{

float Sum = 0 ;


for (int i = 0; i < Length; i++)
	Sum = Sum + In[Index - i];

return Sum;
}

/*==========================================================================*/
SCFloatArrayRef  AccumulationDistribution_S(SCBaseDataRef BaseDataIn, SCFloatArrayRef Out, int Index)
{
		
	const float BIAS_DIVISION_FLOAT = (float)10e-10;
	SCFloatArrayRef phigh = BaseDataIn[SC_HIGH]; 
	SCFloatArrayRef plow = BaseDataIn[SC_LOW];
	SCFloatArrayRef pvolume = BaseDataIn[SC_VOLUME];
	SCFloatArrayRef pclose = BaseDataIn[SC_LAST];
	
	if (Index == 0)
	{
		Out[Index] = ( (pclose[Index] - plow[Index]) - (phigh[Index] - pclose[Index]) ) / (phigh[Index] - plow[Index] + BIAS_DIVISION_FLOAT) * pvolume[Index];
	}
	else
	{
		Out[Index] = ( (pclose[Index] - plow[Index]) - (phigh[Index] - pclose[Index]) ) / (phigh[Index] - plow[Index] + BIAS_DIVISION_FLOAT) * pvolume[Index] + Out[Index-1];
	}

	return Out;
}
/************************************************************************/


double GetMovingAverage(SCFloatArrayRef In, int start_indx, int length)
{
	double sum= 0;
	double out = 0;
	
	if (start_indx < length - 1 )
	{
		start_indx = length - 1;
	}
	if (start_indx >= In.GetArraySize())
		return 0;

	for(int nn=0;nn < length;nn++)
	{
		sum += (double)In[start_indx-nn];
	}
	out = sum / (double)length;

	return out;
}

/************************************************************
* Method				- Variance
* Description	- Computes the Variance
* shortcut to computing the variance V(x) = E[x^2] - E[x]^2


************************************************************/
double GetVariance(SCFloatArrayRef InData, int StartIndex, int Length)
{	
	double mean1 =0; // E[X^2]
	double mean2 =0; // E[X]^2

	for(int Offset = 0; Offset < Length; Offset++)
	{ 
		// compute X^2
		if (StartIndex-Offset < 0)
			break;
		
		double value = (double)InData[StartIndex-Offset];
		mean1 += value * value;
	}

	// compute E[X^2]
	mean1 = mean1 / Length;

	// compute E[X]^2
	mean2 = GetMovingAverage(InData,StartIndex, Length);
	mean2 *= mean2;

	//Compute V(x)
	return mean1 - mean2;
}

/*==========================================================================*/
SCFloatArrayRef CumulativeSummation_S(SCFloatArrayRef In, SCFloatArrayRef Out, int Index)
{
	if(Index==0)
		Out[Index] = In[Index];
	else
		Out[Index] = Out[Index-1] + In[Index];

	return Out;
}

/*==========================================================================*/
SCFloatArrayRef ArmsEaseOfMovement_S(SCBaseDataRef BaseDataIn, SCFloatArrayRef Out, int VolumeDivisor, int Index)
{
	float   PriceRange = 0;               
	float   BoxRatio = 0;               
	float   MidpointMove = 0;             
	float   Volume = 0;              

	if(Index == 0)
		Out[Index] = 0;
	else if (BaseDataIn[SC_VOLUME][Index] <= 0 || BaseDataIn[SC_HIGH][Index] == BaseDataIn[SC_LOW][Index])
		Out[Index] = 0;
	else
	{
		PriceRange = BaseDataIn[SC_HIGH][Index] - BaseDataIn[SC_LOW][Index];
		Volume = BaseDataIn[SC_VOLUME][Index];
		Volume /= VolumeDivisor;
		BoxRatio = Volume / PriceRange;
		MidpointMove = ((BaseDataIn[SC_HIGH][Index] + BaseDataIn[SC_LOW][Index]) / 2) -
			((BaseDataIn[SC_HIGH][Index - 1] + BaseDataIn[SC_LOW][Index - 1]) / 2);
		Out[Index] = MidpointMove / BoxRatio;
	}

	return Out;
}

/*==========================================================================*/
SCFloatArrayRef ChaikinMoneyFlow_S(SCBaseDataRef BaseDataIn, SCFloatArrayRef Out, SCFloatArrayRef InternalArray, int Index, int Length)
{
	SCFloatArrayRef MoneyFlowVolume = InternalArray;
	SCFloatArrayRef CMF = Out;

	float MoneyFlowMultiplier = 0;

	if (BaseDataIn[SC_HIGH][Index] == BaseDataIn[SC_LOW][Index])
	{
		if (Index <= 0 || BaseDataIn[SC_LAST][Index] >= BaseDataIn[SC_LAST][Index - 1])
			MoneyFlowMultiplier = 1.0f;
		else
			MoneyFlowMultiplier = -1.0f;
	}
	else
	{
		MoneyFlowMultiplier	= 
			( (BaseDataIn[SC_LAST][Index] - BaseDataIn[SC_LOW][Index]) - (BaseDataIn[SC_HIGH][Index] - BaseDataIn[SC_LAST][Index]) )
			/ (BaseDataIn[SC_HIGH][Index] - BaseDataIn[SC_LOW][Index]);
	}

	MoneyFlowVolume[Index] = MoneyFlowMultiplier * BaseDataIn[SC_VOLUME][Index];

	if (Index < Length-1)
	{
		CMF[Index] = 0;
		return CMF;
	}
	
	float SumMoneyFlowVolume = 0;
	float SumVolume = 0;

	for(int SumIndex = Index - Length + 1; SumIndex <= Index; SumIndex++)
	{
		SumVolume += BaseDataIn[SC_VOLUME][SumIndex];
		SumMoneyFlowVolume += MoneyFlowVolume[SumIndex];
	}

	if (SumVolume == 0)
		CMF[Index] = 0;
	else
		CMF[Index] = SumMoneyFlowVolume / SumVolume;
	
	return CMF;
}

/*==========================================================================*/
SCFloatArrayRef Summation_S(SCFloatArrayRef In, SCFloatArrayRef Out, int Index, int Length)
{
	float    sum = 0;

	if (Index < Length - 1 )
	{
		Out[Index] = 0;
	}
	else
	{
		for(int pos = Index-Length+1; pos <= Index; pos++)
		{
			sum += In[pos];
		}
	}
	Out[Index] = sum;
	
	return Out;
}

/*==========================================================================*/
SCFloatArrayRef Dispersion_S(SCFloatArrayRef In, SCFloatArrayRef Out, int Index, int Length)
{
	Out[Index] = GetDispersion(In, Index, Length);
	return Out;
}

/*==========================================================================*/
float GetDispersion(SCFloatArrayRef In, int Index, int Length)
{
	if(Index < Length - 1)
		return 0;


	float accum = 0;
	float mean = 0;
	for (int pos = Index - Length + 1; pos <= Index; pos ++ )
	{
		accum += In[pos];
	}
	mean = accum / Length;

	accum = 0;
	float curr = 0;
	for (int pos = Index - Length + 1; pos <= Index; pos ++ )
	{
		curr = ((mean - In[pos]) * (mean - In[pos])) / Length;
		accum += curr;
	}

	return accum;
}

/*==========================================================================*/
SCFloatArrayRef EnvelopePercent_S(SCFloatArrayRef In, SCFloatArrayRef Out1, SCFloatArrayRef Out2,  float Percent, int Index)
{
	Out1[Index] = In[Index] + In[Index] * Percent;
	Out2[Index] = In[Index] - In[Index] * Percent;
	
	return Out1;
}

/*==========================================================================*/
SCFloatArrayRef EnvelopeFixed_S(SCFloatArrayRef In, SCFloatArrayRef Out1, SCFloatArrayRef Out2,  float FixedValue, int Index)
{
	Out1[Index] = In[Index] + FixedValue;
	Out2[Index] = In[Index] - FixedValue;
	
	return Out1;
}


/*==========================================================================*/
SCFloatArrayRef VerticalHorizontalFilter_S(SCFloatArrayRef In, SCFloatArrayRef Out, int Index, int Length)
{

	float    Sum = 0;       
	float    HighestValue;         
	float    LowestValue;         
							

	for (int pos = Index - Length + 1; pos <= Index; pos++)
	{
		Sum += fabs((In[pos] - In[pos - 1]));
	}

	LowestValue = GetLowest(In,Index,Length);
	HighestValue = GetHighest(In,Index,Length);
	
	Out[Index] = (HighestValue - LowestValue) / Sum;

	return Out;
}

/*==========================================================================*/
SCFloatArrayRef RWI_S(SCBaseDataRef BaseDataIn, SCFloatArrayRef HighRWI, SCFloatArrayRef LowRWI,  SCFloatArrayRef TrueRangeArray, SCFloatArrayRef LookBackLowArray, SCFloatArrayRef LookBackHighArray, int Index, int Length) 
{
	TrueRange_S(BaseDataIn, TrueRangeArray, Index);

	HighRWI[Index] = 0;
	LowRWI[Index] = 0;

	if (Index >= Length)
	{
		float ATRSum = 0;

		for (int Iteration = 1; Iteration <= Length; Iteration++)
		{
			ATRSum += TrueRangeArray[Index-Iteration];

			float ATR = ATRSum / Iteration;

			float HighRWIValue = 0;
			float LowRWIValue = 0;

			float Denom = ATR * sqrt((float)Iteration);
			if (Denom != 0)
			{
				HighRWIValue = (BaseDataIn[SC_HIGH][Index] - BaseDataIn[SC_LOW][Index-Iteration]) / Denom;
				LowRWIValue  = (BaseDataIn[SC_HIGH][Index-Iteration] - BaseDataIn[SC_LOW][Index]) / Denom;
			}

			if (HighRWIValue > HighRWI[Index])
				HighRWI[Index] = HighRWIValue;
	
			if (LowRWIValue > LowRWI[Index])
				LowRWI[Index] = LowRWIValue;
		}
	}

	return HighRWI;
}

/*==========================================================================*/
SCFloatArrayRef UltimateOscillator_S(SCBaseDataRef BaseDataIn, 
									SCFloatArrayRef Out, 
									SCFloatArrayRef CalcE,
									SCFloatArrayRef CalcF,
									SCFloatArrayRef CalcG,
									SCFloatArrayRef CalcH,
									SCFloatArrayRef CalcI,
									SCFloatArrayRef CalcJ,
									SCFloatArrayRef CalcK,
									SCFloatArrayRef CalcL,
									SCFloatArrayRef CalcM,
									SCFloatArrayRef CalcN,
									SCFloatArrayRef CalcO,
									SCFloatArrayRef CalcP,
									SCFloatArrayRef CalcQ,

									int Index, int Length1, int Length2, int Length3)//7,14,28
{
/*	
-Column E calculates the True High, which is the greater of Today's High and Yesterday's Close.								
-		Column F calculates the True Low, which is the lesser of Today's Low and Yesterday's Close.								
-		Column G subtracts the True Low (column F) from the True High (column E) to get the Range (also called Total Activity).								
-		Column H is a 7-day summation of the Range (column G).								
-		Column I subtracts the True Low (column F) from the Close, to get the Buying Units (also called Buying Pressure).								
-		Column J is a 7-day summation of the Buying Units (column I).								
-		Column K divides Buying Units (column J) by Range (column H).								
-		Column L is a 14-day summation of the Range (column G).								
-		Column M is a 14-day summation of the Buying Units (column I).								
-		Column N divides Buying Units (column M) by Range (column L).								
-		Column O is a 28-day summation of the Range (column G).								
-		Column P is a 28-day summation of the Buying Units (column I).								
-		Column Q divides Buying Units (column P) by Range (column O)								
		Column R is the Ultimate Oscillator, which is four times the 7-day division (column K) + 2 times the 14-day division (column N) plus the 28-day division (column Q), divided by 7 and multiplied by 100. Formula: =((4*K40)+(2*N40)+Q40)/7*100	*/							
	CalcE[Index] = GetTrueHigh(BaseDataIn,Index);
	CalcF[Index] = GetTrueLow(BaseDataIn,Index);
	CalcG[Index] = CalcE[Index]  - CalcF[Index] ;
	Summation_S(CalcG,CalcH,Index,Length1);
	CalcI[Index] = BaseDataIn[SC_LAST][Index] - CalcF[Index];
	Summation_S(CalcI,CalcJ,Index,Length1);
	CalcK[Index] = CalcJ[Index] / CalcH[Index];
	Summation_S(CalcG,CalcL, Index, Length2);
	Summation_S(CalcI,CalcM, Index, Length2);
	CalcN[Index] = CalcM[Index] / CalcL[Index];
	Summation_S(CalcG,CalcO, Index, Length3);
	Summation_S(CalcI,CalcP, Index, Length3);
	CalcQ[Index] = CalcP[Index] / CalcO[Index];

	Out[Index] = ((4*CalcK[Index])+(2*CalcN[Index])+CalcQ[Index])/7*100;


	return Out;
}

/*==========================================================================*/
SCFloatArrayRef WilliamsAD_S(SCBaseDataRef BaseDataIn, SCFloatArrayRef Out, int Index)
{
	if(Index > 0)
	{
		if (BaseDataIn[SC_LAST][Index] > BaseDataIn[SC_LAST][Index - 1])
			Out[Index] = Out[Index - 1] + (BaseDataIn[SC_LAST][Index] - min(BaseDataIn[SC_LOW][Index], BaseDataIn[SC_LAST][Index - 1]));

		else if (BaseDataIn[SC_LAST][Index] == BaseDataIn[SC_LAST][Index - 1])
			Out[Index] = Out[Index - 1];

		else if (BaseDataIn[SC_LAST][Index] < BaseDataIn[SC_LAST][Index - 1])
			Out[Index] = Out[Index - 1] +
			( BaseDataIn[SC_LAST][Index] - max(BaseDataIn[SC_HIGH][Index], BaseDataIn[SC_LAST][Index - 1]) );
	}
	else
		Out[Index] = 0;
	
	return Out;
}



/*==========================================================================*/
SCFloatArrayRef WilliamsR_S(SCBaseDataRef BaseDataIn, SCFloatArrayRef Out, int Index, int Length)
{
	return WilliamsR2_S(BaseDataIn[SC_HIGH], BaseDataIn[SC_LOW], BaseDataIn[SC_LAST], Out, Index, Length);
}
/*==========================================================================*/

SCFloatArrayRef WilliamsR2_S(SCFloatArrayRef InputDataHigh, SCFloatArrayRef InputDataLow, SCFloatArrayRef InputDataLast, SCFloatArrayRef Out, int Index, int Length)
{
	if(Index < Length)
		Out[Index]=0;
	else
	{
		float High = GetHighest(InputDataHigh,Index, Length); 
		float Low = GetLowest(InputDataLow,Index,Length);
		Out[Index] = 100 * ( High-InputDataLast[Index]) / (High - Low);
	}

	return Out;
}

/*==========================================================================*/
float GetArrayValueAtNthOccurrence(SCFloatArrayRef TrueFalseIn, SCFloatArrayRef ValueArrayIn, int Index, int NthOccurrence )
{
	int Occurrence = 0;
	int CurrentIndex = Index;

	while(Occurrence < NthOccurrence)
	{
		if(TrueFalseIn[CurrentIndex] != 0)
			Occurrence++;
	
		CurrentIndex--;

		if(CurrentIndex < 0)
			break;
	}

	if((CurrentIndex < 0) && (Occurrence < NthOccurrence))
		return 0;

	return ValueArrayIn[CurrentIndex+1];
}

/*==========================================================================*/
SCFloatArrayRef Parabolic_S(s_Parabolic& ParabolicData)
{
	SCBaseDataRef BaseDataIn = ParabolicData._BaseDataIn;
	int BaseDataIndex = ParabolicData._Index;
	SCSubgraphRef Out = ParabolicData._Out;
	SCDateTimeArrayRef BaseDateTimeIn = ParabolicData._BaseDateTimeIn;
	float InStartAccelFactor = ParabolicData._InStartAccelFactor;
	float InAccelIncrement = ParabolicData._InAccelIncrement;
	float InMaxAccelFactor = ParabolicData._InMaxAccelFactor;
	unsigned int InAdjustForGap = ParabolicData._InAdjustForGap;

	SCFloatArrayRef AccelerationFactor = Out.Arrays[0];
	SCFloatArrayRef ExtremeHighOrLowDuringTrend = Out.Arrays[1];
	SCFloatArrayRef InitialCalculationsLow = Out.Arrays[2];
	SCFloatArrayRef InitialCalculationsHigh = Out.Arrays[3];
	SCFloatArrayRef CurrentParabolicDirection = Out.Arrays[4];

	const int PARABOLIC_LONG = 2;
	const int PARABOLIC_SHORT= 1;

	if (BaseDataIndex < 1)//Reset
	{
		CurrentParabolicDirection[0] = 0;
		AccelerationFactor[0] = 0;
		ExtremeHighOrLowDuringTrend[0] = 0;

		InitialCalculationsLow[0] = ParabolicData.BaseDataLow(0);
		InitialCalculationsHigh[0] = ParabolicData.BaseDataHigh(0);

		return Out;
	}

	//Carry forward persistent values
	ExtremeHighOrLowDuringTrend[BaseDataIndex] = ExtremeHighOrLowDuringTrend[BaseDataIndex - 1];
	AccelerationFactor[BaseDataIndex] = AccelerationFactor[BaseDataIndex - 1];

	InitialCalculationsLow[BaseDataIndex] = InitialCalculationsLow[BaseDataIndex - 1];
	InitialCalculationsHigh[BaseDataIndex] = InitialCalculationsHigh[BaseDataIndex - 1];

	if (CurrentParabolicDirection[BaseDataIndex - 1] == 0) // The CurrentParabolicDirection is unknown.
	{
		AccelerationFactor[BaseDataIndex] = InStartAccelFactor;

		if (InitialCalculationsLow[BaseDataIndex ] > ParabolicData.BaseDataLow(BaseDataIndex))
			InitialCalculationsLow[BaseDataIndex] = ParabolicData.BaseDataLow(BaseDataIndex);

		if (InitialCalculationsHigh[BaseDataIndex] < ParabolicData.BaseDataHigh(BaseDataIndex))
			InitialCalculationsHigh[BaseDataIndex] = ParabolicData.BaseDataHigh(BaseDataIndex);

		if (ParabolicData.BaseDataHigh(BaseDataIndex) > ParabolicData.BaseDataHigh(BaseDataIndex-1) && ParabolicData.BaseDataLow(BaseDataIndex) > ParabolicData.BaseDataLow(BaseDataIndex-1))
		{
			ExtremeHighOrLowDuringTrend[BaseDataIndex] = ParabolicData.BaseDataHigh(BaseDataIndex);
			Out[BaseDataIndex] = InitialCalculationsLow[BaseDataIndex];
			CurrentParabolicDirection[BaseDataIndex] = PARABOLIC_LONG;
			//LastPriceAtReversalIndex[BaseDataIndex] = BaseDataIn[SC_LAST][BaseDataIndex];

			return Out;
		}

		if (ParabolicData.BaseDataHigh(BaseDataIndex) < ParabolicData.BaseDataHigh(BaseDataIndex-1) && ParabolicData.BaseDataLow(BaseDataIndex) < ParabolicData.BaseDataLow(BaseDataIndex-1))
		{
			ExtremeHighOrLowDuringTrend[BaseDataIndex] = ParabolicData.BaseDataLow(BaseDataIndex);
			Out[BaseDataIndex] =InitialCalculationsHigh[BaseDataIndex];
			//LastPriceAtReversalIndex[BaseDataIndex] = BaseDataIn[SC_LAST][BaseDataIndex];
			CurrentParabolicDirection[BaseDataIndex] = PARABOLIC_SHORT;

			return Out;
		}
	}
	else
	{
		if (CurrentParabolicDirection[BaseDataIndex -1] == PARABOLIC_LONG) 
		{
			if (ExtremeHighOrLowDuringTrend[BaseDataIndex - 1] < ParabolicData.BaseDataHigh(BaseDataIndex-1))
			{
				ExtremeHighOrLowDuringTrend[BaseDataIndex] = ParabolicData.BaseDataHigh(BaseDataIndex-1);

				AccelerationFactor[BaseDataIndex] = AccelerationFactor[BaseDataIndex -1] + InAccelIncrement;
			}

			CurrentParabolicDirection[BaseDataIndex] = CurrentParabolicDirection[BaseDataIndex - 1];

		}
		else if (CurrentParabolicDirection[BaseDataIndex - 1] == PARABOLIC_SHORT) 
		{
			if (ExtremeHighOrLowDuringTrend[BaseDataIndex - 1] > ParabolicData.BaseDataLow(BaseDataIndex-1))
			{
				ExtremeHighOrLowDuringTrend[BaseDataIndex] = ParabolicData.BaseDataLow(BaseDataIndex-1);

				AccelerationFactor[BaseDataIndex] = AccelerationFactor[BaseDataIndex] + InAccelIncrement;
			}

			CurrentParabolicDirection[BaseDataIndex] = CurrentParabolicDirection[BaseDataIndex - 1];

		}

		if (AccelerationFactor[BaseDataIndex] > InMaxAccelFactor)
			AccelerationFactor[BaseDataIndex] = InMaxAccelFactor;


		float CalcResult= AccelerationFactor[BaseDataIndex] * (ExtremeHighOrLowDuringTrend[BaseDataIndex] - Out[BaseDataIndex - 1]);

		Out[BaseDataIndex] = Out[BaseDataIndex - 1] +  CalcResult;

		float Gap = 0.0;
		float PreviousTrueHigh = 0;
		if ((BaseDataIndex < 2) || (ParabolicData.BaseDataHigh(BaseDataIndex-1) >= ParabolicData.BaseDataLow(BaseDataIndex-2)))
			PreviousTrueHigh = ParabolicData.BaseDataHigh(BaseDataIndex-1);
		else
			PreviousTrueHigh = ParabolicData.BaseDataLow(BaseDataIndex-2);

		if (InAdjustForGap
			&& BaseDataIn[SC_OPEN][BaseDataIndex] > PreviousTrueHigh
			&& BaseDateTimeIn.DateAt(BaseDataIndex) != BaseDateTimeIn.DateAt(BaseDataIndex - 1)
			)
		{
			Gap = (BaseDataIn[SC_OPEN][BaseDataIndex] - BaseDataIn[SC_LAST][BaseDataIndex - 1]);
			Out[BaseDataIndex] = Out[BaseDataIndex - 1] + Gap;
			ExtremeHighOrLowDuringTrend[BaseDataIndex] = ExtremeHighOrLowDuringTrend[BaseDataIndex - 1] + Gap;
		}

		float PreviousTrueLow = 0;
		if ((BaseDataIndex < 2) || (ParabolicData.BaseDataLow(BaseDataIndex-1) <= ParabolicData.BaseDataHigh(BaseDataIndex-2)))
			PreviousTrueLow = ParabolicData.BaseDataLow(BaseDataIndex-1);
		else 
			PreviousTrueLow = ParabolicData.BaseDataHigh(BaseDataIndex-2);

		if (InAdjustForGap
			&& BaseDataIn[SC_OPEN][BaseDataIndex] < PreviousTrueLow
			&& BaseDateTimeIn.DateAt(BaseDataIndex) != BaseDateTimeIn.DateAt(BaseDataIndex - 1)
			)
		{
			Gap = BaseDataIn[SC_LAST][BaseDataIndex - 1] - BaseDataIn[SC_OPEN][BaseDataIndex];
			Out[BaseDataIndex] = Out[BaseDataIndex - 1] - Gap;

			ExtremeHighOrLowDuringTrend[BaseDataIndex] = ExtremeHighOrLowDuringTrend[BaseDataIndex - 1] - Gap;
		}


		if (Gap == 0.0f && CurrentParabolicDirection[BaseDataIndex] == PARABOLIC_LONG
			&&  (Out[BaseDataIndex] > ParabolicData.BaseDataLow(BaseDataIndex-1) ||  Out[BaseDataIndex] > ParabolicData.BaseDataLow(BaseDataIndex-2))
			)
			Out[BaseDataIndex] = min(ParabolicData.BaseDataLow(BaseDataIndex-1), ParabolicData.BaseDataLow(BaseDataIndex-2));

		else if (Gap == 0.0f && CurrentParabolicDirection[BaseDataIndex] == PARABOLIC_SHORT 
			&& (Out[BaseDataIndex] < ParabolicData.BaseDataHigh(BaseDataIndex-1) || Out[BaseDataIndex] < ParabolicData.BaseDataHigh(BaseDataIndex-2))
		)
			Out[BaseDataIndex] = max(ParabolicData.BaseDataHigh(BaseDataIndex-1), ParabolicData.BaseDataHigh(BaseDataIndex-2));

		//Check to see if we need to reverse

		if (CurrentParabolicDirection[BaseDataIndex] == PARABOLIC_LONG &&
			Out[BaseDataIndex] >= ParabolicData.BaseDataLow(BaseDataIndex))
		{
			CurrentParabolicDirection[BaseDataIndex] = PARABOLIC_SHORT;

			Out[BaseDataIndex] = ExtremeHighOrLowDuringTrend[BaseDataIndex];


			AccelerationFactor[BaseDataIndex] = InStartAccelFactor;
			ExtremeHighOrLowDuringTrend[BaseDataIndex] = ParabolicData.BaseDataLow(BaseDataIndex);

			return Out;
		}
		else if (CurrentParabolicDirection[BaseDataIndex] == PARABOLIC_SHORT &&
			Out[BaseDataIndex] <= ParabolicData.BaseDataHigh(BaseDataIndex))
		{
			CurrentParabolicDirection[BaseDataIndex] = PARABOLIC_LONG;


			Out[BaseDataIndex] = ExtremeHighOrLowDuringTrend[BaseDataIndex];

			AccelerationFactor[BaseDataIndex] = InStartAccelFactor;
			ExtremeHighOrLowDuringTrend[BaseDataIndex] = ParabolicData.BaseDataHigh(BaseDataIndex);

			return Out;
		}
	}

	return Out;
}
/*==========================================================================*/
int GetIslandReversal_S(SCBaseDataRef BaseDataIn, int Index)
{

	if (Index == 0)
		return 0;

	float Range =	(BaseDataIn[SC_HIGH][Index] - BaseDataIn[SC_LOW][Index]) ;

	if (
		BaseDataIn[SC_HIGH][Index] < BaseDataIn[SC_LOW][Index - 1]	
		&&
		(BaseDataIn[SC_LAST][Index] > (BaseDataIn[SC_LOW][Index] +
		(Range * .70f)))
		)
		return 1;

	if (
		BaseDataIn[SC_LOW][Index] > BaseDataIn[SC_HIGH][Index - 1]
		&& 
		(BaseDataIn[SC_LAST][Index] < (BaseDataIn[SC_HIGH][Index] - 
		(Range* .70f)))
		)
		return -1;

	return 0;
}

/*==========================================================================*/
SCFloatArrayRef Oscillator_S(SCFloatArrayRef In1, SCFloatArrayRef In2, SCFloatArrayRef Out, int Index)
{
	Out[Index] = In1[Index] - In2[Index];
	
	return Out;
}

/*==========================================================================*/
float GetTrueHigh(SCBaseDataRef BaseDataIn, int Index)
{
	if (Index == 0 || BaseDataIn[SC_HIGH][Index] > BaseDataIn[SC_LAST][Index - 1])
		return (BaseDataIn[SC_HIGH][Index]);
	else
		return (BaseDataIn[SC_LAST][Index - 1]);
}

/*==========================================================================*/
float GetTrueLow(SCBaseDataRef BaseDataIn, int Index)
{
	if (Index == 0 || BaseDataIn[SC_LOW][Index] < BaseDataIn[SC_LAST][Index - 1])
		return (BaseDataIn[SC_LOW][Index]);
	else
		return (BaseDataIn[SC_LAST][Index - 1]);
}

/*==========================================================================*/
float GetTrueRange(SCBaseDataRef BaseDataIn, int Index)
{
	return (GetTrueHigh(BaseDataIn, Index) - GetTrueLow(BaseDataIn, Index));
}
/*==========================================================================*/
float GetRange(SCBaseDataRef BaseDataIn, int Index) 
{ 
	return BaseDataIn[SC_HIGH][Index] - BaseDataIn[SC_LOW][Index]; 

} 

/*==========================================================================*/


float GetCorrelationCoefficient(SCFloatArrayRef In1, SCFloatArrayRef In2, int Index, int Length)
{
	float result;
	int i;
	float xmean;
	float ymean;
	float s;
	float xv;
	float yv;
	float t1;
	float t2;

	xv = 0;
	yv = 0;
	if (Length<=1 )
	{
		result = 0;
		return result;
	}

	//
	// Mean
	//
	xmean = 0;
	ymean = 0;
	for(i = 0; i < Length; i++)
	{
		xmean += In1[Index-i];
		ymean += In2[Index-i];
	}
	xmean = xmean/Length;
	ymean = ymean/Length;

	//
	// numerator and denominator
	//
	s = 0;
	xv = 0;
	yv = 0;

	for(i = 0; i <= Length-1; i++)
	{
		t1 = In1[Index-i]-xmean;
		t2 = In2[Index-i]-ymean;
		xv = xv+(t1*t1);
		yv = yv+(t2*t2);
		s = s+t1*t2;
	}
	if (xv==0||yv==0 )
	{
		result = 0;
	}
	else
	{
		result = s/(sqrt(xv)*sqrt(yv));
	}

	return result;
}

/*==========================================================================*/
int NumberOfBarsSinceHighestValue(SCFloatArrayRef In, int Index, int Length)
{
	float max = In[Index];
	int maxIndex = Index;
	for(int i = Index; i > Index - Length && i >= 0; i--)
	{
		if(In[i] > max)
		{
			max = In[i];
			maxIndex = i;
		}
	}
	return Index - maxIndex;
}

/*==========================================================================*/
int NumberOfBarsSinceLowestValue(SCFloatArrayRef In, int Index, int Length)
{
	float min = In[Index];
	int minIndex = Index;

	for(int i = Index; i > Index - Length && i >= 0; i--)
	{
		if(In[i] < min)
		{
			min = In[i];
			minIndex = i;
		}
	}
	return Index - minIndex;
}

/*==========================================================================*/
SCFloatArrayRef PriceVolumeTrend_S(SCBaseDataRef BaseDataIn, SCFloatArrayRef Out, int Index)
{
	if(Index==0)
	{
		Out[Index] = 0;
		return Out;
	}
	
	Out[Index] = ( (BaseDataIn[SC_LAST][Index] - BaseDataIn[SC_LAST][Index-1]) / BaseDataIn[SC_LAST][Index-1] )
		* BaseDataIn[SC_VOLUME][Index] + Out[Index-1];
	
	return Out;
}

/*==========================================================================*/
SCFloatArrayRef Momentum_S(SCFloatArrayRef In, SCFloatArrayRef Out, int Index, int Length)
{
	Out[Index] = (In[Index]/In[Index-Length])*100;
	return Out;
}

/*==========================================================================*/
SCFloatArrayRef TRIX_S(SCFloatArrayRef In, SCFloatArrayRef Out, SCFloatArrayRef InternalEma_1,  SCFloatArrayRef InternalEma_2, SCFloatArrayRef InternalEma_3, int Index, int Length)
{
	const double BIAS_DIVISION_DOUBLE = (double)10e-20;

	ExponentialMovingAverage_S(In,			InternalEma_1, Index, Length);
	ExponentialMovingAverage_S(InternalEma_1, InternalEma_2, Index, Length);
	ExponentialMovingAverage_S(InternalEma_2, InternalEma_3, Index, Length);

	Out[Index] = (float)(100 * (InternalEma_3[Index] - InternalEma_3[Index-1]) / (InternalEma_3[Index-1] + BIAS_DIVISION_DOUBLE));

	return Out;
}

/*==========================================================================*/
SCFloatArrayRef Demarker_S(SCBaseDataRef BaseDataIn, SCFloatArrayRef Out, SCFloatArrayRef DemMax, SCFloatArrayRef DemMin, SCFloatArrayRef SmaDemMax, SCFloatArrayRef SmaDemMin, int Index, int Length)
{
	if(Index > 0)
	{
		float high = BaseDataIn[SC_HIGH][Index];
		float highOld = BaseDataIn[SC_HIGH][Index-1];

		if (high > highOld)
		{
			DemMax[Index] = high - highOld;
		}
		else
		{
			DemMax[Index] = 0.0f;
		}

		float low = BaseDataIn[SC_LOW][Index];
		float lowOld = BaseDataIn[SC_LOW][Index-1];

		if (low < lowOld)
		{
			DemMin[Index] = lowOld - low;
		}
		else
		{
			DemMin[Index] = 0.0f;
		}
	}
	else
	{
		DemMax[Index] = 0.0f;
		DemMin[Index] = 0.0f;
	}

	SimpleMovAvg_S(DemMax, SmaDemMax, Index, Length);
	SimpleMovAvg_S(DemMin, SmaDemMin, Index, Length);

	float summ = SmaDemMax[Index] + SmaDemMin[Index];
	if (summ != 0.0f)
	{        
		Out[Index] = SmaDemMax[Index] / summ;
	}
	else
	{
		Out[Index] = Out[Index-1];
	}

	return Out;
}

/*==========================================================================*/
SCFloatArrayRef Old_AroonIndicator_S(SCFloatArrayRef In, SCFloatArrayRef OutUp, SCFloatArrayRef OutDown, int Index, int Length)
{
	int BarsSinceHighest = 0;
	float Highest = In[Index];

	int BarsSinceLowest = 0;
	float Lowest = In[Index];

	for (int i = 1; i <= Length ; i++)
	{
		if (In[Index - i] > Highest)
		{
			Highest = In[Index - i];
			BarsSinceHighest = i;
		}
		if (In[Index - i] < Lowest)
		{
			Lowest = In[Index - i];
			BarsSinceLowest = i;
		}
	}

	OutUp[Index] = ((Length - (float)BarsSinceHighest) / Length) * 100.0f;
	OutDown[Index] = ((Length - (float)BarsSinceLowest) / Length) * 100.0f;

	return OutUp;
}

/*==========================================================================*/
SCFloatArrayRef AroonIndicator_S(SCFloatArrayRef FloatArrayInHigh, SCFloatArrayRef FloatArrayInLow, SCFloatArrayRef OutUp, SCFloatArrayRef OutDown, SCFloatArrayRef OutOscillator, int Index, int Length)
{
	int BarsSinceHighest = 0;
	float Highest = FloatArrayInHigh[Index];

	int BarsSinceLowest = 0;
	float Lowest =FloatArrayInLow[Index];

	for (int i = 1; i <= Length ; i++)
	{
		if (FloatArrayInHigh[Index - i] > Highest)
		{
			Highest = FloatArrayInHigh[Index - i];
			BarsSinceHighest = i;
		}

		if (FloatArrayInLow[Index - i] < Lowest)
		{
			Lowest = FloatArrayInLow[Index - i];
			BarsSinceLowest = i;
		}
	}

	OutUp[Index] = ((Length - (float)BarsSinceHighest) / Length) * 100.0f;
	OutDown[Index] = ((Length - (float)BarsSinceLowest) / Length) * 100.0f;


	OutOscillator [Index] =OutUp[Index] -OutDown[Index];

	return OutUp;
}
/*==========================================================================*/
int IsSwingHighAllowEqual_S(SCStudyInterfaceRef sc, int AllowEqual, int Index, int Length)
{
	for(int i = 1; i <= Length; i++)
	{

		if (AllowEqual)
		{
			if (sc.FormattedEvaluate(sc.BaseData [SC_HIGH][Index] , sc.BasedOnGraphValueFormat, LESS_OPERATOR, sc.BaseData [SC_HIGH][Index-i], sc.BasedOnGraphValueFormat)
				||
				sc.FormattedEvaluate(sc.BaseData [SC_HIGH][Index] , sc.BasedOnGraphValueFormat, LESS_OPERATOR, sc.BaseData [SC_HIGH][Index+i], sc.BasedOnGraphValueFormat)
				)
				return 0;


		}
		else
		{
			if (sc.FormattedEvaluate(sc.BaseData [SC_HIGH][Index] , sc.BasedOnGraphValueFormat, LESS_EQUAL_OPERATOR, sc.BaseData [SC_HIGH][Index-i], sc.BasedOnGraphValueFormat)
				||
				sc.FormattedEvaluate(sc.BaseData [SC_HIGH][Index] , sc.BasedOnGraphValueFormat, LESS_EQUAL_OPERATOR, sc.BaseData [SC_HIGH][Index+i], sc.BasedOnGraphValueFormat)
				)
				return 0;


		}
	}

	return 1;
}

/*==========================================================================*/
int IsSwingLowAllowEqual_S(SCStudyInterfaceRef sc, int AllowEqual, int Index, int Length)
{
	for(int i = 1; i <= Length; i++)
	{

		if (AllowEqual)
		{
			if (sc.FormattedEvaluate(sc.BaseData [SC_LOW][Index] , sc.BasedOnGraphValueFormat, GREATER_OPERATOR, sc.BaseData [SC_LOW][Index-i], sc.BasedOnGraphValueFormat)
				||
				sc.FormattedEvaluate(sc.BaseData [SC_LOW][Index] , sc.BasedOnGraphValueFormat, GREATER_OPERATOR, sc.BaseData [SC_LOW][Index+i], sc.BasedOnGraphValueFormat)
				)
				return 0;


		}
		else
		{
			if (sc.FormattedEvaluate(sc.BaseData [SC_LOW][Index] , sc.BasedOnGraphValueFormat, GREATER_EQUAL_OPERATOR, sc.BaseData [SC_LOW][Index-i], sc.BasedOnGraphValueFormat)
				||
				sc.FormattedEvaluate(sc.BaseData [SC_LOW][Index] , sc.BasedOnGraphValueFormat, GREATER_EQUAL_OPERATOR, sc.BaseData [SC_LOW][Index+i], sc.BasedOnGraphValueFormat)
				)
				return 0;


		}
	}

	return 1;
}

/*==========================================================================*/
SCFloatArrayRef AwesomeOscillator_S(SCFloatArrayRef In, SCFloatArrayRef Out, SCFloatArrayRef TempMA1, SCFloatArrayRef TempMA2, int Index, int Length1, int Length2)
{
	SimpleMovAvg_S(In, TempMA1, Index, Length1);
	SimpleMovAvg_S(In, TempMA2, Index, Length2);

	Out[Index] = TempMA2[Index] - TempMA1[Index];

	return Out;
}

/*==========================================================================*/
int CalculatePivotPoints
( float PriorOpen
, float PriorHigh
, float PriorLow
, float PriorClose
, float CurrentOpen
, float& PivotPoint
, float& R_5
, float& R1, float& R1_5
, float& R2, float& R2_5
, float& R3
, float& S_5
, float& S1, float& S1_5
, float& S2, float& S2_5
, float& S3
, float& R3_5
, float& S3_5
, float& R4
, float& R4_5
, float& S4
, float& S4_5
, float& R5
, float& S5
, float& R6
, float& S6
, float& R7
, float& S7
, float& R8
, float& S8
, float& R9
, float& S9
, float& R10
, float& S10
, int FormulaType
)
{
	if (FormulaType == 0)
	{
		PivotPoint = (PriorHigh + PriorLow + PriorClose) / 3;
		R1 = (PivotPoint * 2) - PriorLow;
		R_5 = (PivotPoint + R1) / 2;
		R2 = PivotPoint + (PriorHigh - PriorLow);
		R1_5 = (R1 + R2) / 2;
		S1 = (2 * PivotPoint) - PriorHigh;
		S_5 = (PivotPoint + S1) / 2;
		S2 = PivotPoint - (PriorHigh - PriorLow);
		S1_5 = (S1 + S2) / 2;
		R3 = 2 * PivotPoint + (PriorHigh - 2*PriorLow); 
		R2_5 = (R2 + R3) / 2;
		S3 = 2 * PivotPoint - (2 * PriorHigh - PriorLow);
		S2_5 = (S2 + S3) / 2;
		R4 = 3 * PivotPoint + (PriorHigh - 3 * PriorLow);
		S4 = 3 * PivotPoint - (3 * PriorHigh - PriorLow);
		R3_5 =  (R3 + R4) / 2;
		S3_5 = (S3 + S4) / 2;
		R5 = 4 * PivotPoint + (PriorHigh - 4 * PriorLow);
		S5 = 4 * PivotPoint - (4 * PriorHigh - PriorLow);
		R6 = 5 * PivotPoint + (PriorHigh - 5 * PriorLow);
		S6 = 5 * PivotPoint - (5 * PriorHigh - PriorLow);
		R7 = 6 * PivotPoint + (PriorHigh - 6 * PriorLow);
		S7 = 6 * PivotPoint - (6 * PriorHigh - PriorLow);
		R8 = 7 * PivotPoint + (PriorHigh - 7 * PriorLow);
		S8 = 7 * PivotPoint - (7 * PriorHigh - PriorLow);
		R9 = 8 * PivotPoint + (PriorHigh - 8 * PriorLow);
		S9 = 8 * PivotPoint - (8 * PriorHigh - PriorLow);
		R10 = 9 * PivotPoint + (PriorHigh - 9 * PriorLow);
		S10 = 9 * PivotPoint - (9 * PriorHigh - PriorLow);

		/*

		R3.5 = (R3 + R4)/2
		S3.5 = (S3 + S4)/2
		R5 = 4 * PivotPoint + (Yesterday's High - (4 * Yesterday's Low))
		S5 = (4 * PivotPoint) - ((4 * Yesterday's High) - Yesterday's Low)
		R4.5 = (R4 + R5)/2
		S4.5 = (S4 + S5)/2
		*/
	}

	else if (FormulaType == 1)
	{
		float YesterdaysRange;

		PivotPoint = (PriorHigh + PriorLow + PriorClose) / 3;
		R1 = (PivotPoint * 2) - PriorLow;
		R_5 = (PivotPoint + R1) / 2;
		R2 = PivotPoint + (PriorHigh-PriorLow);
		R1_5 = (R1 + R2) / 2;
		S1 = (2 * PivotPoint) - PriorHigh;
		S_5 = (PivotPoint + S1) / 2;
		S2 = PivotPoint - (PriorHigh - PriorLow);
		S1_5 = (S1 + S2) / 2;
		YesterdaysRange = (PriorHigh - PriorLow);

		// This is R3 Pattern Trapper
		R3 = PriorHigh + YesterdaysRange; // 2 * High - Low
		R2_5 = (R2 + R3)/2;

		// This is S3 Pattern Trapper
		S3 = 2*PivotPoint - PriorHigh - YesterdaysRange; // 2 * PivotPoint - (2 * High + Low)
		S2_5 = (S2 + S3) / 2;

		R4 = PivotPoint + 3 * (PriorHigh - PriorLow);
		S4 = PivotPoint - 3 * (PriorHigh - PriorLow);
	}
	else if (FormulaType == 2)
	{
		PivotPoint = (CurrentOpen + PriorHigh + PriorLow + PriorClose) / 4;
		R1 = (PivotPoint * 2) - PriorLow;
		R_5 = (PivotPoint + R1) / 2;
		R2 = PivotPoint + (PriorHigh - PriorLow);
		R1_5 = (R1 + R2) / 2;
		S1 = (2 * PivotPoint) - PriorHigh;
		S_5 = (PivotPoint + S1) / 2;
		S2 = PivotPoint - (PriorHigh - PriorLow);
		S1_5 = (S1 + S2) / 2;
		R3 = 2*PivotPoint + (PriorHigh - 2*PriorLow); // R3 std
		R2_5 = (R2 + R3) / 2;
		S3 = 2*PivotPoint - (2*PriorHigh - PriorLow); // S3 std
		S2_5 = (S2 + S3) / 2;
		R4 = 3 * PivotPoint + (PriorHigh - 3 * PriorLow);
		S4 = 3 * PivotPoint - (3 * PriorHigh - PriorLow);
	}
	else if (FormulaType == 3)
	{
		PivotPoint = (PriorHigh + PriorLow + CurrentOpen+CurrentOpen) / 4;
		R1 = (PivotPoint * 2) - PriorLow;
		R_5 = (PivotPoint + R1) / 2;
		R2 = PivotPoint + (PriorHigh - PriorLow);
		R1_5 = (R1 + R2) / 2;
		S1 = (2 * PivotPoint) - PriorHigh;
		S_5 = (PivotPoint + S1) / 2;
		S2 = PivotPoint - (PriorHigh - PriorLow);
		S1_5 = (S1 + S2) / 2;
		R3 = 2 * PivotPoint + (PriorHigh - 2*PriorLow); // R3 std
		R2_5 = (R2 + R3) / 2;
		S3 = 2 * PivotPoint - (2 * PriorHigh - PriorLow); // S3 std
		S2_5 = (S2 + S3) / 2;
		R4 = 3 * PivotPoint + (PriorHigh - 3 * PriorLow);
		S4 = 3 * PivotPoint - (3 * PriorHigh - PriorLow);
	}
	else if (FormulaType == 4)
	{
		PivotPoint = (PriorHigh + PriorLow + PriorClose) / 3;
		R1 = (PivotPoint * 2) - PriorLow;
		R_5 = (PivotPoint + R1) / 2;
		R2 = PivotPoint + (PriorHigh - PriorLow);
		R1_5 = (R1 + R2) / 2;
		S1 = (2 * PivotPoint) - PriorHigh;
		S_5 = (PivotPoint + S1) / 2;
		S2 = PivotPoint - (PriorHigh - PriorLow);
		S1_5 = (S1 + S2) / 2;
		R3 = PivotPoint + 2 * (PriorHigh - PriorLow); 
		R2_5 = (R2 + R3) / 2;
		S3 = PivotPoint - 2 * (PriorHigh - PriorLow); 
		S2_5 = (S2 + S3) / 2;
		R4 = PivotPoint + 3 * (PriorHigh - PriorLow);
		S4 = PivotPoint - 3 * (PriorHigh - PriorLow);
	}
	else if (FormulaType == 5) // Camarilla Pivot Points
	{
		float Range = PriorHigh - PriorLow;
		PivotPoint = (PriorHigh + PriorLow + PriorClose) / 3;

		R_5 = PriorClose + Range * 1.1f/18;
		R1 = PriorClose + Range * 1.1f/12;
		R1_5 = PriorClose + Range * 1.1f/9;
		R2 = PriorClose + Range * 1.1f/6;
		R2_5 = PriorClose + Range * 1.1f/5;
		R3 = PriorClose + Range * 1.1f/4;
		R3_5 = PriorClose + Range * 1.1f/3;
		R4 = PriorClose + Range * 1.1f/2;
		R4_5 = PriorClose + Range * 1.1f / 1.33f;

		S_5 = PriorClose - Range * 1.1f/18;
		S1 = PriorClose - Range * 1.1f/12;
		S1_5 = PriorClose - Range * 1.1f/9;
		S2 = PriorClose - Range * 1.1f/6;
		S2_5 = PriorClose - Range * 1.1f/5;
		S3 = PriorClose - Range * 1.1f/4;
		S3_5 = PriorClose - Range * 1.1f/3;
		S4 = PriorClose - Range * 1.1f/2;
		S4_5 = PriorClose - Range * 1.1f / 1.33f;
		R5 = (PriorHigh/PriorLow) *PriorClose;
		S5 = PriorClose -(R5-PriorClose);
	}
	else if (FormulaType == 6)  // Tom DeMark's Pivot Points
	{
		float X = 0;
		if (PriorClose < PriorOpen)
			X = PriorHigh + PriorLow + PriorLow + PriorClose;
		else if (PriorClose > PriorOpen)
			X = PriorHigh + PriorHigh + PriorLow + PriorClose;
		else if (PriorClose == PriorOpen)
			X = PriorHigh + PriorLow + PriorClose + PriorClose;

		PivotPoint = X / 4;
		R1 = X / 2 - PriorLow;
		S1 = X / 2 - PriorHigh;
		R_5 = R2 = R1_5 = S_5 = S2 = S1_5 = R3 = 
			R2_5 = S3 = S2_5 = R4 = S4 = 0;
	}
	else if (FormulaType == 7) // Frank Dilernia Pivots
	{
		PivotPoint = (PriorHigh + PriorLow + PriorClose) / 3;
		R1 = PivotPoint + (PriorHigh - PriorLow)/2;
		R2 = PivotPoint + (PriorHigh - PriorLow) * 0.618f;
		R3 = PivotPoint + (PriorHigh - PriorLow);
		S1 = PivotPoint - (PriorHigh - PriorLow)/2;
		S2 = PivotPoint - (PriorHigh - PriorLow) * 0.618f;
		S3 = PivotPoint - (PriorHigh - PriorLow);

		S2_5 = (S3 + S2)/2;				
		S1_5 = (S2 + S1)/2;				
		S_5 = (S1 + PivotPoint)/2;			
		R_5 = (R1 + PivotPoint)/2;			
		R1_5 = (R2 + R1)/2;				
		R2_5 = (R3 + R2)/2;				
	}
	else if (FormulaType == 8) // Shadow Trader. www.shadowtrader.net
	{
		PivotPoint = (PriorHigh + PriorLow + PriorClose) / 3; 
		R1 = (2 * PivotPoint) - PriorLow; 
		R3 = 2*(PivotPoint - PriorLow) + PriorHigh; 
		R4 = PriorHigh + 3*(PivotPoint - PriorLow);

		S1 = (2 * PivotPoint) - PriorHigh; 
		S2 = PivotPoint - (R1 - S1); 
		S3 = PriorLow - 2 * (PriorHigh - PivotPoint); 
		S4 = PriorLow - 3 * (PriorHigh - PivotPoint);

		R2 = PivotPoint + (R1 - S1); 

		S3_5 = (S3 + S4)/2;
		S2_5 = (S3 + S2)/2;				
		S1_5 = (S2 + S1)/2;				
		S_5 = (S1 + PivotPoint)/2;			
		R_5 = (R1 + PivotPoint)/2;			
		R1_5 = (R2 + R1)/2;				
		R2_5 = (R3 + R2)/2;		
		R3_5 = (R3 + R4)/2;

	}
	else if (FormulaType == 9)
	{

		PivotPoint = (PriorHigh + PriorLow + PriorClose)/3; //PP = H + L + C /3
		float PPSquareRoot = sqrt(sqrt(PivotPoint));
		R1 = PivotPoint + PPSquareRoot; //R1 = PP + SQRT(SQRT(PP))
		R2 = R1 + PPSquareRoot; //R2 = R1 + SQRT(SQRT(PP))
		R3 = R2 + PPSquareRoot; //R3 = R2 + SQRT(SQRT(PP))
		S1 = PivotPoint - PPSquareRoot; //S1 = PP - SQRT(SQRT(PP))
		S2 = S1 - PPSquareRoot; //S2 = S1 - SQRT(SQRT(PP))
		S3 = S2 - PPSquareRoot; //S3 = S2 - SQRT(SQRT(PP))

		S2_5 = (S3 + S2)/2;				
		S1_5 = (S2 + S1)/2;				
		S_5 = (S1 + PivotPoint)/2;			
		R_5 = (R1 + PivotPoint)/2;			
		R1_5 = (R2 + R1)/2;				
		R2_5 = (R3 + R2)/2;				

	}
	else if (FormulaType == 10)
	{
		PivotPoint = (PriorHigh + PriorLow + PriorClose)/3;
		R1 = 2 * PivotPoint - PriorLow;
		R2 = PivotPoint + PriorHigh - PriorLow;
		R3 = R1 + PriorHigh - PriorLow;
		R4 = R3 + (R2 - R1);
			
		S1 = 2 * PivotPoint - PriorHigh;
		S2 = PivotPoint - (PriorHigh - PriorLow);
		S3 = S1 - (PriorHigh - PriorLow);
		S4 = S3 - (S1 - S2);

		S3_5 = (S4 + S3)/2;
		S2_5 = (S3 + S2)/2;
		S1_5 = (S2 + S1)/2;
		S_5 = (S1 + PivotPoint)/2;
		R_5 = (R1 + PivotPoint)/2;
		R1_5 = (R2 + R1)/2;
		R2_5 = (R3 + R2)/2;
		R3_5 = (R4 + R3)/2;
	}
	else if (FormulaType == 11)
	{
		PivotPoint = (PriorHigh + PriorLow + PriorClose)/3;
		float DailyRange = PriorHigh - PriorLow;

		R_5 = PivotPoint + 0.5f*DailyRange;
		R1 = PivotPoint + 0.618f*DailyRange;
		R1_5 = PivotPoint + DailyRange;
		R2 = PivotPoint + 1.272f*DailyRange;
		R2_5 = PivotPoint + 1.618f*DailyRange;
		R3 = PivotPoint + 2*DailyRange;
		R4 = PivotPoint + 2.618f*DailyRange;

		S_5 = PivotPoint - 0.5f*DailyRange;
		S1 = PivotPoint - 0.618f*DailyRange;
		S1_5 = PivotPoint - DailyRange;
		S2 = PivotPoint - 1.272f*DailyRange;
		S2_5 = PivotPoint - 1.618f*DailyRange;
		S3 = PivotPoint - 2*DailyRange;
		S4 = PivotPoint - 2.618f*DailyRange;

	
	}
	else if (FormulaType == 12)
	{
		PivotPoint = CurrentOpen;

		R_5 = PivotPoint;
		R1 = PivotPoint;
		R1_5 = PivotPoint;
		R2 = PivotPoint;
		R2_5 = PivotPoint;
		R3 = PivotPoint;
		R4 = PivotPoint;

		S_5 = PivotPoint;
		S1 = PivotPoint;
		S1_5 = PivotPoint;
		S2 = PivotPoint;
		S2_5 = PivotPoint;
		S3 = PivotPoint;
		S4 = PivotPoint;
	}
	else if (FormulaType == 13) // Fibonacci Pivot Points
	{
		PivotPoint = (PriorHigh + PriorLow + PriorClose)/3;
		float DailyRange = PriorHigh - PriorLow;

	
		R1 = PivotPoint + 0.382f*DailyRange;
		R2 = PivotPoint + 0.618f*DailyRange;
		R3 = PivotPoint + 1*DailyRange;

		S1 = PivotPoint - 0.382f*DailyRange;
		S2 = PivotPoint - 0.618f*DailyRange;
		S3 = PivotPoint - 1*DailyRange;

		S2_5 = (S3 + S2)/2;				
		S1_5 = (S2 + S1)/2;				
		S_5 = (S1 + PivotPoint)/2;			
		R_5 = (R1 + PivotPoint)/2;			
		R1_5 = (R2 + R1)/2;				
		R2_5 = (R3 + R2)/2;				


	}
	else if (FormulaType == 14) 
	{
		PivotPoint = (PriorHigh + PriorLow + PriorClose) / 3;
		
		S1 = (2 * PivotPoint) - PriorHigh;
		R1 = (2 * PivotPoint) - PriorLow;
		
		S2 = PivotPoint - (R1 - S1);
		R2 = (PivotPoint - S1) + R1;
		
		S3 = PivotPoint - (R2 - S1) ;
		R3 = (PivotPoint - S1) + R2;
	}
	else if (FormulaType == 15) // Fibonacci Zone Pivots
	{
		PivotPoint = (PriorHigh + PriorLow + PriorClose) / 3;

		R1 = PivotPoint + (PriorHigh - PriorLow)/2;
		R2 = PivotPoint + (PriorHigh - PriorLow);

		S1 = PivotPoint - (PriorHigh - PriorLow)/2;
		S2 = PivotPoint - (PriorHigh - PriorLow);

		// 0.5 to 0.618 defines resistance/support band 1
		// 1.0 to 1.382 defines resistance/support band 2
		// the bands could start as lines and if the user 
		// wishes they can use Fill Rect top and bottom
		// or the transparent versions.
		R1_5 = PivotPoint + (PriorHigh - PriorLow)*0.618f;
		R2_5 = PivotPoint + (PriorHigh - PriorLow)*1.382f;

		S1_5 = PivotPoint - (PriorHigh - PriorLow)*0.618f;
		S2_5 = PivotPoint - (PriorHigh - PriorLow)*1.382f;
	}
	else if (FormulaType == 16)
	{
		/*
		THE CENTRAL PIVOT RANGE FORMULA:

		TC (TOPCENTRAL) = (PIVOT-BC)+PIVOT
		PIVOT = (HIGH+LOW+CLOSE)/3
		BC (BOTTOM CENTRAL) =(HIGH+LOW)/2
		*/
		PivotPoint = (PriorHigh + PriorLow + PriorClose) / 3;
		S1 = (PriorHigh + PriorLow) / 2;
		R1 = (PivotPoint - S1) + PivotPoint;
	}
	else if (FormulaType == 17)
	{
		PivotPoint = (PriorHigh + PriorLow + PriorClose) / 3; // 	PP = (H+L+C)/3


		// H: high, L: low, C: close
			

		// Previous Day H: high, L: low, C: close
		R3 = PriorHigh+2*(PivotPoint- PriorLow); //R3 = H+2*(PP-L)
		R2 = PivotPoint+(PriorHigh-PriorLow);  //R2 = PP+(H-L)
		R2_5 = (R2+R3)/2; //M5 = (R2+R3)/2

		S1 = 2*PivotPoint - PriorHigh; //	S1 = (2*PP)-H
		
		S2 = PivotPoint - (PriorHigh - PriorLow); //	S2 = PP-(H-L)

		S3 = PriorLow - 2 * (PriorHigh - PivotPoint);//	S3 = L-2*(H-PP) 

		S2_5 = (S2 + S3)/2; //	M0 = (S2+S3)/2
		
		
		R1 = 2*PivotPoint - PriorLow; //	R1 = (2*PP)-L
		R_5 = (PivotPoint + R2)/2; //	M3 = (PP+R2)/2
		R1_5 = (R_5 + R2)/2; //	M4 = (M3+R2)/2
		S_5 = (PivotPoint + S2)/2; //	M2 = (PP+S2)/2
		S1_5 = (S_5 + S2)/2; //	M1 = (M2+S2)/2
	}
	else if (FormulaType == 18)
	{
		PivotPoint = (PriorHigh + PriorLow + PriorClose) / 3;

		R1 = PivotPoint + (PriorHigh - PriorLow) * 0.75f;
		S1 = PivotPoint -  (PriorHigh - PriorLow) * 0.75f;
	}
	else if (FormulaType == 19)
	{
/*		Pivot Point (PP) = (Yesterday's High + Yesterday's Low + Current Open + Current Open) / 4

			Resistance Level (R1) = PivotPoint + 2 * (Yesterday's High - Yesterday's Low)

			Support Level (S1) = PivotPoint - 2 * (Yesterday's High - Yesterday's Low)
*/
		PivotPoint = (PriorHigh + PriorLow + 2 * CurrentOpen) / 4;
		R1 = PivotPoint + 2 * (PriorHigh - PriorLow);
		S1 = PivotPoint - 2 * (PriorHigh - PriorLow);
	}
	else if (FormulaType ==20)
	{
		/* Calculations for ACD method
		*/
		PivotPoint = (PriorHigh + PriorLow + PriorClose) / 3;
		float HighLowAverage = (PriorHigh + PriorLow)/2;
		float Difference = fabs (HighLowAverage -  PivotPoint);
		S1 = PivotPoint -Difference;
		R1 =PivotPoint  +Difference;
	}
	else if (FormulaType == 21)
	{
		////////////Fibonacci Calculation///////////////////////////////////////////

		//R10 = OP + ((HighD(1) - LowD(1)) * 3.618);
		//R9 = OP + ((HighD(1) - LOWD(1))* 3.00);
		//R8 = OP + ((HighD(1) - LowD(1)) * 2.618);
		//R7 = OP + ((HighD(1) - LOWD(1))* 2.00);
		//R6 = OP + ((HighD(1) - LowD(1)) * 1.618);
		//R5 = OP + ((HighD(1) - LowD(1)) * 1.27);
		//R4 = OP + ((HighD(1) - LowD(1)) * 1.000);
		//R3 = OP + ((HighD(1) - LowD(1)) * .786);
		//R2 = OP + ((HighD(1) - LowD(1)) * .618);
		//R1 = OP + ((HighD(1) - LowD(1)) * .382);
		//OP = (OpenD(0));// (HighD(1) + LowD(1) + CloseD(1)) / 3;
		//S1 = OP - ((HighD(1) - LowD(1)) * .382);
		//S2 = OP - ((HighD(1) - LowD(1)) * .618);
		//S3 = OP - ((HighD (1) - LowD (1)) * .786);
		//S4 = OP - ((HighD(1) - LowD(1)) * 1.000);
		//S5 = OP - ((HighD(1) - LowD(1)) * 1.27);
		//S6 = OP - ((HighD(1) - LowD(1)) * 1.618);
		//S7 = OP - ((HighD(1) - LowD(1)) * 2.00);
		//S8 = OP - ((HighD(1) - LowD(1)) * 2.618);
		//S9 = OP - ((HighD(1) - LowD(1)) * 3.00);
		//S10 = OP - ((HighD(1) - LowD(1)) * 3.618); 

		PivotPoint = CurrentOpen;
		
		R_5 = (float)(PivotPoint + ((PriorHigh - PriorLow) * 0.382));
		R1 = (float)( PivotPoint + ((PriorHigh - PriorLow) * 0.618));
		R1_5 = (float)( PivotPoint + ((PriorHigh - PriorLow) * 0.786));
		R2 = (float)( PivotPoint + ((PriorHigh - PriorLow) * 1.0));
		R2_5 = (float)(PivotPoint + ((PriorHigh - PriorLow) * 1.27));
		R3 = (float)( PivotPoint + ((PriorHigh - PriorLow) * 1.618));
		R3_5 = (float)( PivotPoint + ((PriorHigh - PriorLow) * 2.0));
		R4 = (float)( PivotPoint + ((PriorHigh - PriorLow) * 2.618));
		R5 = (float)( PivotPoint + ((PriorHigh - PriorLow) * 3.0));

		S_5 = (float)( PivotPoint - ((PriorHigh - PriorLow) * 0.382));
		S1 = (float)( PivotPoint - ((PriorHigh - PriorLow) * 0.618));
		S1_5 = (float)( PivotPoint - ((PriorHigh - PriorLow) * 0.786));
		S2 = (float)(  PivotPoint - ((PriorHigh - PriorLow) * 1.0));
		S2_5 = (float)(  PivotPoint - ((PriorHigh - PriorLow) * 1.27));
		S3 = (float)(  PivotPoint - ((PriorHigh - PriorLow) * 1.618));
		S3_5 = (float)(  PivotPoint - ((PriorHigh - PriorLow) * 2.0));
		S4 = (float)(  PivotPoint - ((PriorHigh - PriorLow) * 2.618));
		S5 = (float)(  PivotPoint - ((PriorHigh - PriorLow) * 3.0));
	}
	else if (FormulaType == 22)
	{
		PivotPoint = (PriorHigh + PriorLow + PriorClose) / 3;
		float UDIFF = PriorHigh - PivotPoint;
		float LDIFF = PivotPoint - PriorLow;

		R1 = PivotPoint + .382f * LDIFF;
		R2 = PivotPoint + .618f * LDIFF;
		R3 = PivotPoint + LDIFF;    
		R4 = PivotPoint + 1.272f * LDIFF;
		R5 = PivotPoint + 1.382f * LDIFF;
		R6 = PivotPoint + 1.618f * LDIFF;
		R7 = PivotPoint + 2.0f * LDIFF;
		R8 = PivotPoint + 2.272f * LDIFF;
		R9 = PivotPoint + 2.382f * LDIFF;
		R10 = PivotPoint + 2.618f * LDIFF;

		S1 = PivotPoint - .382f * UDIFF;
		S2 = PivotPoint - .618f * UDIFF;
		S3 = PivotPoint - UDIFF;    
		S4 = PivotPoint - 1.272f * UDIFF;
		S5 = PivotPoint - 1.382f * UDIFF;
		S6 = PivotPoint - 1.618f * UDIFF;
		S7 = PivotPoint - 2.0f * UDIFF;
		S8 = PivotPoint - 2.272f * UDIFF;
		S9 = PivotPoint - 2.382f * UDIFF;    
		S10 = PivotPoint - 2.618f * UDIFF;

	}
	else if (FormulaType == 23)
	{
		// Fibonacci Zone Pivot Points calculation
		PivotPoint = (PriorHigh + PriorLow + PriorClose) / 3;
		// Daily Range
		const float DR = PriorHigh - PriorLow;

		R1 = PivotPoint + .5f * DR;
		R2 = PivotPoint + .618f * DR;
		R3 = PivotPoint + DR;
		R4 = PivotPoint + 1.382f * DR;
		R5 = PivotPoint + 1.618f * DR;
		R6 = PivotPoint + 2 * DR;
		R7 = PivotPoint + 2.618f * DR;

		S1 = PivotPoint - 0.5f * DR;
		S2 = PivotPoint - 0.618f * DR;
		S3 = PivotPoint - DR;
		S4 = PivotPoint - 1.382f * DR;
		S5 = PivotPoint - 1.618f * DR;
		S6 = PivotPoint - 2 * DR;
		S7 = PivotPoint - 2.618f * DR;
	}
	else if (FormulaType == 24)// Advanced Camarilla Pivot Points calculation
	{
		const float DailyRange = PriorHigh - PriorLow;

		R1 = PriorClose + .0916f * DailyRange;
		R2 = PriorClose + .183f * DailyRange;
		R3 = PriorClose + .275f * DailyRange;
		R4 = PriorClose + .555f * DailyRange;
		R5 = PriorClose + .8244f * DailyRange;
		R6 = PriorClose + 1.0076f * DailyRange;
		PivotPoint = PriorClose;
		S1 = PriorClose - .0916f * DailyRange;
		S2 = PriorClose - .183f * DailyRange;
		S3 = PriorClose - .275f * DailyRange;
		S4 = PriorClose - .55f * DailyRange;
		S5 = PriorClose - .8244f * DailyRange;
		S6 = PriorClose - 1.0992f * DailyRange;
	}
	else if (FormulaType == 25)
	{

		PivotPoint = (PriorHigh + PriorLow + PriorClose) / 3;
		S1 = (PriorHigh + PriorLow) / 2;
		R1 = PivotPoint + (PivotPoint - S1);
		S2 = PriorLow - (PriorHigh - PriorLow)*0.25f;
		S3 = PriorLow - (PriorHigh - PriorLow)*0.5f;
		S4 = PriorLow - (PriorHigh - PriorLow)*0.75f;
		S5 = PriorLow - (PriorHigh - PriorLow)*1.0f;
		R2 = PriorHigh + (PriorHigh - PriorLow)*0.25f;
		R3 = PriorHigh + (PriorHigh - PriorLow)*0.5f;
		R4 = PriorHigh + (PriorHigh - PriorLow)*0.75f;
		R5 = PriorHigh + (PriorHigh - PriorLow);
	}
	else if (FormulaType == 26)
	{

		PivotPoint = (PriorHigh + PriorLow + PriorClose) / 3;
		const float DailyRange = PriorHigh - PriorLow;
		R1 = PivotPoint + 0.382f*(DailyRange);
		R2 = PivotPoint + 0.618f*(DailyRange);
		R3 = PivotPoint + 0.786f*(DailyRange);
		R4 = PivotPoint + 1.00f*(DailyRange);
		R5 = PivotPoint + 1.382f*(DailyRange);
		R6 = PivotPoint + 1.618f*(DailyRange);
		R7 = PivotPoint + 2.00f*(DailyRange);
		S1 = PivotPoint - 0.382f*(DailyRange);
		S2 = PivotPoint - 0.618f*(DailyRange);
		S3 = PivotPoint - 0.786f*(DailyRange);
		S4 = PivotPoint - 1.00f*(DailyRange);
		S5 = PivotPoint - 1.382f*(DailyRange);
		S6 = PivotPoint - 1.618f*(DailyRange);
		S7 = PivotPoint - 2.00f*(DailyRange);
	}
	else if (FormulaType == 27)
	{
	
		PivotPoint = CurrentOpen;

		R_5 = (float)(PivotPoint + ((PriorHigh - PriorLow) * 0.236));
		R1 = (float)(PivotPoint + ((PriorHigh - PriorLow) * 0.382));
		R1_5 = (float)(PivotPoint + ((PriorHigh - PriorLow) * 0.5));
		R2 = (float)( PivotPoint + ((PriorHigh - PriorLow) * 0.618));
		R2_5 = (float)( PivotPoint + ((PriorHigh - PriorLow) * 0.786));
		R3 = (float)( PivotPoint + ((PriorHigh - PriorLow) * 1.0));
		R3_5 = (float)(PivotPoint + ((PriorHigh - PriorLow) * 1.27));
		R4 = (float)( PivotPoint + ((PriorHigh - PriorLow) * 1.618));
		R5 = (float)( PivotPoint + ((PriorHigh - PriorLow) * 2.0));
		R6 = (float)( PivotPoint + ((PriorHigh - PriorLow) * 2.618));
		R7 = (float)( PivotPoint + ((PriorHigh - PriorLow) * 3.0));

		S_5 = (float)( PivotPoint - ((PriorHigh - PriorLow) * 0.236));
		S1 = (float)( PivotPoint - ((PriorHigh - PriorLow) * 0.382));
		S1_5 = (float)( PivotPoint - ((PriorHigh - PriorLow) * 0.5));
		S2 = (float)( PivotPoint - ((PriorHigh - PriorLow) * 0.618));
		S2_5 = (float)( PivotPoint - ((PriorHigh - PriorLow) * 0.786));
		S3 = (float)(  PivotPoint - ((PriorHigh - PriorLow) * 1.0));
		S3_5 = (float)(  PivotPoint - ((PriorHigh - PriorLow) * 1.27));
		S4 = (float)(  PivotPoint - ((PriorHigh - PriorLow) * 1.618));
		S5 = (float)(  PivotPoint - ((PriorHigh - PriorLow) * 2.0));
		S6 = (float)(  PivotPoint - ((PriorHigh - PriorLow) * 2.618));
		S7 = (float)(  PivotPoint - ((PriorHigh - PriorLow) * 3.0));
	}

	return 1;
}

/*==========================================================================*/
int CalculateDailyOHLC
( SCStudyInterfaceRef sc
, int IntradayChartDate
, int InNumberOfDaysBack
, int InNumberOfDaysToCalculate
, int InUseSaturdayData
, int InUseThisIntradayChart
, int InDailyChartNumber
, SCGraphData& DailyChartData
, SCDateTimeArray& DailyChartDateTimes
, int UseDaySessionOnly
, float& Open
, float& High
, float& Low
, float& Close
, float& Volume
, int InIncludeFridayEveningSessionWithSundayEveningSession
)
{
	if (InUseThisIntradayChart) // Use this Chart
	{
		int ArraySize = sc.ArraySize;
		if (ArraySize < 2)
			return 0;
		
		int LastIndex = ArraySize - 1;
		
		int LastDateInChart = sc.GetTradingDayDate(sc.BaseDateTimeIn[LastIndex]);
		
		// Return and do not calculate if IntradayChartDate is further back than the number of days to calculate from the last date in the chart.
		if (LastDateInChart - InNumberOfDaysToCalculate >= IntradayChartDate)
			return 0;
		
		
		// Look for the last good date (not a weekend and has data)
		int FirstIndexOfReferenceDay = 0;
		int ReferenceDay = IntradayChartDate;
		while (InNumberOfDaysBack > 0)
		{
			--ReferenceDay;
			
			
			if (IsWeekend(ReferenceDay, InUseSaturdayData != 0))
				continue;
			
			// It is not a weekend

			FirstIndexOfReferenceDay = sc.GetFirstIndexForDate(sc.ChartNumber, ReferenceDay);
			SCDateTime FirstIndexOfReferenceDayTradingDayDate = sc.GetTradingDayDate(sc.BaseDateTimeIn[FirstIndexOfReferenceDay]);

			if (FirstIndexOfReferenceDayTradingDayDate == ReferenceDay)
				--InNumberOfDaysBack;//Found a match. Decrement the number of days back being referenced.
			
			if (InNumberOfDaysBack <= 0)
			{
				if (FirstIndexOfReferenceDayTradingDayDate != ReferenceDay)// Prior day not found
					return 0;
				
				break;
			}
			
			if (FirstIndexOfReferenceDay == 0)
			{
				if (FirstIndexOfReferenceDayTradingDayDate != ReferenceDay)// Prior day not found
					return 0;

				// At the beginning of the date array, so we can not look back any further
				break;
			}
		}
		
		if(!UseDaySessionOnly)
		{
			if (!sc.GetOpenHighLowCloseVolumeForDate(ReferenceDay, Open, High, Low, Close, Volume, InIncludeFridayEveningSessionWithSundayEveningSession))
				return 0;
		}
		else
		{
			SCDateTime StartDateTime;
			SCDateTime EndDateTime;

			if(sc.StartTime1 <= sc.EndTime1)
			{
				StartDateTime.SetDate(ReferenceDay);
				StartDateTime.SetTime(sc.StartTime1);

				EndDateTime.SetDate(ReferenceDay);
				EndDateTime.SetTime(sc.EndTime1);
			}
			else
			{
				StartDateTime.SetDate(ReferenceDay - 1);
				StartDateTime.SetTime(sc.StartTime1);

				EndDateTime.SetDate(ReferenceDay);
				EndDateTime.SetTime(sc.EndTime1);
			}

			float NextOpen = 0;

			if(!sc.GetOHLCOfTimePeriod(StartDateTime, EndDateTime, Open, High, Low, Close, NextOpen))
				return 0;
		}
	}
	else // Use Daily Chart
	{
		
		int LastDateInDestinationChart = sc.GetTradingDayDate(sc.BaseDateTimeIn[sc.ArraySize - 1]);
		
		// Return and do not calculate if the IntradayChartDate to be calculated is further back than the number of days to calculate
		if (IntradayChartDate <= LastDateInDestinationChart - InNumberOfDaysToCalculate )
			return 0;
		
		
		// Look for a matching date that is not a weekend

		int FirstIndexOfReferenceDay = 0;
		int ReferenceDay = IntradayChartDate - InNumberOfDaysBack;

		if (InNumberOfDaysBack == 0)
		{
			FirstIndexOfReferenceDay = sc.GetFirstNearestIndexForTradingDayDate(InDailyChartNumber, ReferenceDay);
		}
		else
		{
			while (IsWeekend(ReferenceDay, InUseSaturdayData != 0))
			{
				--ReferenceDay;
			}

			FirstIndexOfReferenceDay = sc.GetFirstNearestIndexForTradingDayDate(InDailyChartNumber, ReferenceDay);

			if (sc.GetTradingDayDate(DailyChartDateTimes[FirstIndexOfReferenceDay]) == IntradayChartDate
				&& FirstIndexOfReferenceDay >= 1)
				--FirstIndexOfReferenceDay;

#ifdef _DEBUG
			SCString DateString1 = sc.DateTimeToString(ReferenceDay, FLAG_DT_COMPLETE_DATETIME);
			SCString DateString2 = sc.DateTimeToString(DailyChartDateTimes[FirstIndexOfReferenceDay], FLAG_DT_COMPLETE_DATETIME);
			SCString LogMessage;
			LogMessage.Format("%s, %s", DateString1.GetChars(), DateString2.GetChars());
			sc.AddMessageToLog(LogMessage, 0);
#endif
		}

		
		Open = DailyChartData[SC_OPEN][FirstIndexOfReferenceDay];
		High = DailyChartData[SC_HIGH][FirstIndexOfReferenceDay];
		Low = DailyChartData[SC_LOW][FirstIndexOfReferenceDay];
		Close = DailyChartData[SC_LAST][FirstIndexOfReferenceDay];
	}
	
	return 1;
}

/*==========================================================================*/
int CalculateDailyPivotPoints
( SCStudyInterfaceRef sc
, int IntradayChartDate
, int FormulaType
, int DailyChartNumber
, SCGraphData& DailyChartData
, SCDateTimeArray& DailyChartDateTime
, int NumberOfDays
, int UseSaturdayData
, int UseThisChart
, int UseManualValues
, float UserOpen
, float UserHigh
, float UserLow
, float UserClose
, int  UseDaySessionOnly
, float& PivotPoint
, float& R_5
, float& R1, float& R1_5
, float& R2, float& R2_5
, float& R3
, float& S_5
, float& S1, float& S1_5
, float& S2, float& S2_5
, float& S3
, float& R3_5
, float& S3_5
, float& R4
, float& R4_5
, float& S4
, float& S4_5
, float& R5
, float& S5
, float& R6
, float& S6
, float& R7
, float& S7
, float& R8
, float& S8
, float& R9
, float& S9
, float& R10
, float& S10
)
{

	float Open = 0.0, High = 0.0, Low = 0.0, Close = 0.0, NextOpen = 0.0;

	if (UseThisChart != 0) // Use this Chart
	{
		int ArraySize = sc.BaseDateTimeIn.GetArraySize();
		if (ArraySize < 2)
			return 0;

		int LastIndex = ArraySize - 1;

		int CurrentDate = sc.GetTradingDayDate(sc.BaseDateTimeIn[LastIndex]);
		
		// Return and do not calculate pivots if the current bar to be calculated is further back than the number of days to calculate
		if (CurrentDate - NumberOfDays >= IntradayChartDate)
			return 0;


		// Look for the last good date which is not a weekend and has data
		int FirstIndexOfPriorDay;
		int PreviousDay = IntradayChartDate;
		while (true)
		{
			--PreviousDay;

		
			if (IsWeekend(PreviousDay, UseSaturdayData != 0))
				continue;

			// It is not a weekend
			FirstIndexOfPriorDay = sc.GetFirstIndexForDate(sc.ChartNumber, PreviousDay);
			if (sc.GetTradingDayDate(sc.BaseDateTimeIn[FirstIndexOfPriorDay]) == PreviousDay)
				break;

			if (FirstIndexOfPriorDay == 0)
			{
				// At the beginning of the date array, so we can't look back any farther
				break;
			}
		}

		if (sc.GetTradingDayDate(sc.BaseDateTimeIn[FirstIndexOfPriorDay]) != PreviousDay)
		{
			// Previous day not found
			return 0;
		}


		if(!UseDaySessionOnly)
		{


			if (!sc.GetOHLCForDate(PreviousDay, Open, High, Low, Close))
				return 0;

			float NextHigh, NextLow, NextClose;  // The values returned for these are unused
			if (!sc.GetOHLCForDate(IntradayChartDate, NextOpen, NextHigh, NextLow, NextClose))
				NextOpen = Close;  // If there is a failure, use the prior Close
		}
		else
		{
			SCDateTime StartDateTime;
			SCDateTime EndDateTime;

			if(sc.StartTime1 <= sc.EndTime1)
			{
				StartDateTime.SetDate(PreviousDay);
				StartDateTime.SetTime(sc.StartTime1);

				EndDateTime.SetDate(PreviousDay);
				EndDateTime.SetTime(sc.EndTime1);
			}
			else
			{
				StartDateTime.SetDate(PreviousDay - 1);
				StartDateTime.SetTime(sc.StartTime1);

				EndDateTime.SetDate(PreviousDay);
				EndDateTime.SetTime(sc.EndTime1);
			}


			
			if(!sc.GetOHLCOfTimePeriod(StartDateTime, EndDateTime, Open, High, Low, Close, NextOpen))
				return 0;
		}
	}
	else // Use Daily Chart
	{
		if (DailyChartData[0].GetArraySize() < 2)
			return 0;

		int DailyChartBarIndex = -1; 
		int CountBack = DailyChartData[SC_OPEN].GetArraySize() - NumberOfDays - 1;
		for(int CurrentIndex = DailyChartData[SC_OPEN].GetArraySize() - 1; CurrentIndex >= CountBack && CurrentIndex >= 0; CurrentIndex-- )
		{
			if (sc.GetTradingDayDateForChartNumber(DailyChartNumber, DailyChartDateTime[CurrentIndex]) < IntradayChartDate)
			{
				DailyChartBarIndex = CurrentIndex;
				break;
			}
		}

		if(DailyChartBarIndex == -1)
			return 0;

		Open = DailyChartData[SC_OPEN][DailyChartBarIndex];
		High = DailyChartData[SC_HIGH][DailyChartBarIndex];
		Low = DailyChartData[SC_LOW][DailyChartBarIndex];
		Close = DailyChartData[SC_LAST][DailyChartBarIndex];

		if (DailyChartBarIndex == DailyChartData[0].GetArraySize() - 1 )
			NextOpen = DailyChartData[SC_LAST][DailyChartBarIndex];
		else
			NextOpen = DailyChartData[SC_OPEN][DailyChartBarIndex+1];
	}
	
	// If we are calculating the last day, and the user has manually entered OHLC values, then use those
	if (UseManualValues)
	{
		int ArraySize = sc.BaseDateTimeIn.GetArraySize();

		int LastIndex = ArraySize - 1;

		int CurrentDate = sc.GetTradingDayDate(sc.BaseDateTimeIn[LastIndex]);

		if (CurrentDate == IntradayChartDate)
		{
			Open = (UserHigh + UserLow + UserClose) / 3.0f;  // This is not normally used, but we need to set it to something reasonable
			High = UserHigh;
			Low = UserLow;
			Close = UserClose;
			NextOpen = UserOpen;
		}
	}

	return CalculatePivotPoints
		(  Open
		,  High
		,  Low
		,  Close
		,  NextOpen
		,  PivotPoint
		,  R_5
		,  R1,  R1_5
		,  R2,  R2_5
		,  R3
		,  S_5
		,  S1,  S1_5
		,  S2,  S2_5
		,  S3
		,  R3_5
		,  S3_5
		,  R4
		,  R4_5
		,  S4
		,  S4_5
		,  R5
		,  S5
		,  R6
		,  S6
		,  R7
		,  S7
		,  R8
		,  S8
		,  R9
		,  S9
		,  R10
		,  S10
		,  FormulaType
		);
}

/*==========================================================================*/
SCFloatArrayRef Slope_S(SCFloatArrayRef In, SCFloatArrayRef Out, int Index)
{
	Out[Index] = In[Index] - In[Index - 1];

	return Out;
}
/*==========================================================================*/
SCFloatArrayRef CalculateAngle_S(SCFloatArrayRef InputArray, SCFloatArrayRef OutputArray, int Index, int Length, float ValuePerPoint)
{	
	if (ValuePerPoint == 0)
		ValuePerPoint = 1;

	float BackValue = InputArray[Index - Length];
	float CurrentValue = InputArray[Index];

	float PointChange = (CurrentValue - BackValue) / ValuePerPoint;

	OutputArray[Index] = (float)(atan2((double)PointChange, (double)Length) * 180.0 / M_PI);

	return OutputArray;
}

/*==========================================================================*/
SCFloatArrayRef DoubleStochastic_S(SCBaseDataRef BaseDataIn, SCFloatArrayRef Out, SCFloatArrayRef MovAvgIn, SCFloatArrayRef MovAvgOut, SCFloatArrayRef MovAvgIn2, SCFloatArrayRef Unused, int Index, int Length, int MovAvgLength, int MovAvgType)
{
	/*-------------------------------
	MovingAvgX ((((Pl - Lowest (Pl , 10)) / Deler2) * 100) , 3 , False)

	where:

	PL= MovingAvgX (((Close - Lowest Low (10)) / Deler) * 100 , 3 , False)
	Deler= IFF (highest_minus_lowest > 0 , highest_minus_lowest , 1)
	Deler2= IFF (highest_minus_lowest#2 > 0 , highest_minus_lowest#2 , 1)
	Highest_minus_lowest= Highest High (10) - Lowest Low (10)
	Highest_minus_lowest#2= Highest High (5) - Lowest Low (5)
	-----------------------------*/

	float HighestMinusLowest1 = GetHighest(BaseDataIn[SC_HIGH], Index, Length) - GetLowest(BaseDataIn[SC_LOW], Index, Length);
	float Calc1 = HighestMinusLowest1 > 0 ? HighestMinusLowest1 : 1;

	MovAvgIn[Index] = (BaseDataIn[SC_LAST][Index] - GetLowest(BaseDataIn[SC_LOW], Index, Length))/Calc1*100.0f;


	MovingAverage_S(MovAvgIn, MovAvgOut,MovAvgType, Index, MovAvgLength); 

	float HighestMinusLowest2 = GetHighest(MovAvgOut, Index, Length) - GetLowest(MovAvgOut, Index, Length);
	float Calc2 = HighestMinusLowest2 > 0 ? HighestMinusLowest2 : 1;


	MovAvgIn2[Index]= (MovAvgOut[Index] - GetLowest(MovAvgOut, Index, Length))/Calc2*100.0f;

	MovingAverage_S(MovAvgIn2, Out, MovAvgType, Index, MovAvgLength);

	return Out;
}

/*==========================================================================*/
double GetStandardError(SCFloatArrayRef In, int Index, int Length)
{
	if (Length <= 1)
		return 0.0;

	if (Index < Length - 1)
		return 0.0;

	double  AvgX = (Length - 1) * 0.5f;

	double AvgY = 0;
	for (int Offset = 0; Offset < Length; Offset++)
		AvgY += In[Index - Offset];

	AvgY /= Length;

	double SumDxSqr = 0;
	double SumDySqr = 0;
	double SumDxDy = 0;
	for (int Offset = 0; Offset < Length; Offset++)
	{
		double Dx = Offset - AvgX;
		double Dy =  In[Offset + Index - Length + 1] - AvgY;
		SumDxSqr += Dx * Dx;
		SumDySqr += Dy * Dy;
		SumDxDy += Dx * Dy;
	}

	return sqrt((SumDySqr - (SumDxDy * SumDxDy) / SumDxSqr) / (Length - 2));
}

/*==========================================================================*/
SCFloatArray& StandardError_S(SCFloatArrayRef In, SCFloatArray& Out, int Index, int Length)
{
	Out[Index] = (float) GetStandardError(In,Index,Length);

	return Out;
}

/*==========================================================================*/
int CrossOver(SCFloatArrayRef First, SCFloatArrayRef Second, int Index)
{
	float X1 = First[Index-1];
	float X2 = First[Index];
	float Y1 = Second[Index-1];
	float Y2 = Second[Index];

	if (X2 != Y2)  // The following is not useful if X2 and Y2 are equal
	{
		// Find non-equal values for prior values
		int PriorIndex = Index - 1;
		while (X1 == Y1 && PriorIndex > 0 && PriorIndex > Index - 100)
		{
			--PriorIndex;
			X1 = First[PriorIndex];
			Y1 = Second[PriorIndex];
		}
	}

	if (X1 > Y1 && X2 < Y2)
		return CROSS_FROM_TOP;
	else if (X1 < Y1 && X2 > Y2)
		return CROSS_FROM_BOTTOM;
	else
		return NO_CROSS;
}

/*==========================================================================*/
SCFloatArrayRef CumulativeDeltaVolume_S(SCBaseDataRef BaseDataIn, SCFloatArrayRef Open, SCFloatArrayRef High, SCFloatArrayRef Low, SCFloatArrayRef Close, int Index, int ResetCumulativeCalculation)
{
	SCFloatArrayRef BidVolume      = BaseDataIn[SC_BIDVOL];
	SCFloatArrayRef AskVolume      = BaseDataIn[SC_ASKVOL];
	SCFloatArrayRef DifferenceHigh = BaseDataIn[SC_ASKBID_DIFF_HIGH];
	SCFloatArrayRef DifferenceLow  = BaseDataIn[SC_ASKBID_DIFF_LOW];

	if (Index == 0 || ResetCumulativeCalculation)
	{
		Open[Index]  = 0;
		High[Index]  = DifferenceHigh[Index];
		Low[Index]   = DifferenceLow[Index];
		Close[Index] = AskVolume[Index] - BidVolume[Index];

		if (Open[Index] > High[Index]) 
			Open[Index] = High[Index];

		if (Open[Index] < Low[Index])
			Open[Index] = Low[Index];
	}
	else
	{
		Open[Index]  = Close[Index-1];
		High[Index]  = Close[Index-1] + DifferenceHigh[Index];
		Low[Index]   = Close[Index-1] + DifferenceLow[Index];
		Close[Index] = Close[Index-1] + (AskVolume[Index] - BidVolume[Index]);

		if (Open[Index] > High[Index]) 
			Open[Index] = High[Index];

		if (Open[Index] < Low[Index])
			Open[Index] = Low[Index];
	}

	return Close;
}

/*==========================================================================*/
SCFloatArrayRef CumulativeDeltaTicks_S(SCBaseDataRef BaseDataIn, SCFloatArrayRef Open, SCFloatArrayRef High, SCFloatArrayRef Low, SCFloatArrayRef Close, int Index, int ResetCumulativeCalculation)
{
	SCFloatArrayRef BidNumberTrades = BaseDataIn[SC_BIDNT];
	SCFloatArrayRef AskNumberTrades = BaseDataIn[SC_ASKNT];
	SCFloatArrayRef DifferenceHigh  = BaseDataIn[SC_ASKBID_NUM_TRADES_DIFF_HIGH];
	SCFloatArrayRef DifferenceLow   = BaseDataIn[SC_ASKBID_NUM_TRADES_DIFF_LOW];

	if (Index == 0 || ResetCumulativeCalculation)
	{
		Open[Index]  = 0;
		High[Index]  = DifferenceHigh[Index];
		Low[Index]   = DifferenceLow[Index];
		Close[Index] = AskNumberTrades[Index] - BidNumberTrades[Index];

		if (Open[Index] > High[Index]) 
			Open[Index] = High[Index];

		if (Open[Index] < Low[Index])
			Open[Index] = Low[Index];
	}
	else
	{
		Open[Index]  = Close[Index-1];
		High[Index]  = Close[Index-1] + DifferenceHigh[Index];
		Low[Index]   = Close[Index-1] + DifferenceLow[Index];
		Close[Index] = Close[Index-1] + (AskNumberTrades[Index] - BidNumberTrades[Index]);

		if (Open[Index] > High[Index]) 
			Open[Index] = High[Index];

		if (Open[Index] < Low[Index])
			Open[Index] = Low[Index];
	}

	return Close;
}

/*==========================================================================*/
SCFloatArrayRef CumulativeDeltaTickVolume_S(SCBaseDataRef BaseDataIn, SCFloatArrayRef Open, SCFloatArrayRef High, SCFloatArrayRef Low, SCFloatArrayRef Close, int Index, int ResetCumulativeCalculation)
{
	SCFloatArrayRef UpTickVolume   = BaseDataIn[SC_UPVOL];
	SCFloatArrayRef DownTickVolume = BaseDataIn[SC_DOWNVOL];
	SCFloatArrayRef DifferenceHigh = BaseDataIn[SC_UPDOWN_VOL_DIFF_HIGH];
	SCFloatArrayRef DifferenceLow  = BaseDataIn[SC_UPDOWN_VOL_DIFF_LOW];

	if (Index == 0 || ResetCumulativeCalculation)
	{
		Open[Index]  = 0;
		High[Index]  = DifferenceHigh[Index];
		Low[Index]   = DifferenceLow[Index];
		Close[Index] = UpTickVolume[Index] - DownTickVolume[Index];

		if (Open[Index] > High[Index]) 
			Open[Index] = High[Index];

		if (Open[Index] < Low[Index])
			Open[Index] = Low[Index];
	}
	else
	{
		Open[Index]  = Close[Index-1];
		High[Index]  = Close[Index-1] + DifferenceHigh[Index];
		Low[Index]   = Close[Index-1] + DifferenceLow[Index];
		Close[Index] = Close[Index-1] + (UpTickVolume[Index] - DownTickVolume[Index]);

		if (Open[Index] > High[Index]) 
			Open[Index] = High[Index];

		if (Open[Index] < Low[Index])
			Open[Index] = Low[Index];
	}

	return Close;
}


/*==========================================================================*/
//  ZigZagValues: value of zig zag line
//  ZigZagPeakType: +1=high peak, -1=low peak, 0=not peak
//  ZigZagPeakIndex: index of current peak, -1=no peak yet
SCFloatArrayRef ResettableZigZag_S(SCFloatArrayRef InputDataHigh, SCFloatArrayRef InputDataLow, SCFloatArrayRef ZigZagValues, SCFloatArrayRef ZigZagPeakType, SCFloatArrayRef ZigZagPeakIndex, int StartIndex, int Index, float ReversalPercent, float ReversalAmount, SCStudyInterfaceRef sc)
{
	if (Index == StartIndex)
	{
		for(int ZeroIndex = StartIndex ; ZeroIndex < ZigZagValues.GetArraySize(); ZeroIndex++)
		{
			ZigZagValues[ZeroIndex] = 0;
			ZigZagPeakType[ZeroIndex] = 0;
			ZigZagPeakIndex[ZeroIndex] = 0;
		}
		ZigZagPeakIndex[StartIndex] = -1;
		return ZigZagValues;
	}


	if (ZigZagPeakIndex[Index] == 0)
	{		
		if (ZigZagPeakIndex[Index-1] != -1)
		{
			// new bar, copy values forward
			ZigZagPeakIndex[Index] = ZigZagPeakIndex[Index-1];
			ZigZagValues[Index] = 0;
			ZigZagPeakType[Index] = 0;
		}
		else
		{
			// still looking for initial trend
			if (InputDataHigh[Index] > InputDataHigh[StartIndex] && InputDataLow[Index] > InputDataLow[StartIndex]) //bullish trend
			{
				ZigZagPeakIndex[Index] = (float)Index;
				ZigZagValues[Index] = InputDataHigh[Index];
				ZigZagPeakType[Index] = 1;

				ZigZagPeakIndex[StartIndex] = (float)StartIndex;
				ZigZagValues[StartIndex] = InputDataLow[StartIndex];
				ZigZagPeakType[StartIndex] = -1;

				float Increment = (InputDataHigh[Index] - InputDataLow[StartIndex])/(Index-StartIndex);

				for (int ArrayIndex=StartIndex+1, Count=1; ArrayIndex<Index; ArrayIndex++, Count++)
				{
					ZigZagValues[ArrayIndex] = InputDataLow[StartIndex] + Count*Increment;
					ZigZagPeakIndex[ArrayIndex] = (float)StartIndex;
					ZigZagPeakType[ArrayIndex] = 0;
				}
			}
			else if (InputDataHigh[Index] < InputDataHigh[StartIndex] && InputDataLow[Index] < InputDataLow[StartIndex]) //bearish trend
			{
				ZigZagPeakIndex[Index] = (float)Index;
				ZigZagValues[Index] = InputDataLow[Index];
				ZigZagPeakType[Index] = -1;

				ZigZagPeakIndex[StartIndex] = (float)StartIndex;
				ZigZagValues[StartIndex] = InputDataHigh[StartIndex];
				ZigZagPeakType[StartIndex] = 1;

				float Increment = (InputDataHigh[StartIndex] - InputDataLow[Index])/(Index-StartIndex);

				for (int ArrayIndex=StartIndex+1, Count=1; ArrayIndex<Index; ArrayIndex++, Count++)
				{
					ZigZagValues[ArrayIndex] = InputDataHigh[StartIndex] - Count*Increment;
					ZigZagPeakIndex[ArrayIndex] = (float)StartIndex;
					ZigZagPeakType[ArrayIndex] = 0;
				}
			}
			else
			{
				ZigZagPeakIndex[Index] = -1;
				ZigZagValues[Index] = 0;
				ZigZagPeakType[Index] = 0;
			}

			return ZigZagValues;
		}
	}


	int   CurrentPeakIndex = (int)ZigZagPeakIndex[Index];
	
	if (CurrentPeakIndex > 0)
	{
		int   CurrentPeakType  = (int)ZigZagPeakType[CurrentPeakIndex];
		float CurrentPeakValue = ZigZagValues[CurrentPeakIndex];

		int   PriorPeakIndex   = (int)ZigZagPeakIndex[CurrentPeakIndex-1];
		float PriorPeakValue   = ZigZagValues[PriorPeakIndex];

		bool CurrentBarIsPeak = Index == CurrentPeakIndex;

		float BarLow = InputDataLow[Index];
		float BarHigh = InputDataHigh[Index];


		if (CurrentPeakType > 0)
		{
			float ReversalPrice;
			if (ReversalPercent == 0.0f)
				ReversalPrice = CurrentPeakValue - ReversalAmount;
			else
				ReversalPrice = CurrentPeakValue - (CurrentPeakValue*ReversalPercent);

			//if (!CurrentBarIsPeak && BarLow < ReversalPrice)
			if (!CurrentBarIsPeak && sc.FormattedEvaluate(BarLow, sc.BaseGraphValueFormat, LESS_OPERATOR, ReversalPrice, sc.BaseGraphValueFormat))
			{
				ZigZagPeakIndex[Index] = (float)Index;
				ZigZagValues[Index] = BarLow;
				ZigZagPeakType[Index] = -1;

				float Increment = (CurrentPeakValue - BarLow)/(Index - CurrentPeakIndex);

				for (int n = CurrentPeakIndex+1, Count=1; n < Index; n++, Count++)
				{
					ZigZagValues[n] = CurrentPeakValue - Count*Increment;
				}
			}
			//else if (BarHigh > CurrentPeakValue)
			else if (sc.FormattedEvaluate(BarHigh, sc.BaseGraphValueFormat, GREATER_EQUAL_OPERATOR, CurrentPeakValue, sc.BaseGraphValueFormat))
			{
				ZigZagPeakIndex[Index] = (float)Index;
				ZigZagValues[Index] = BarHigh;
				ZigZagPeakType[Index] = 1;

				float Increment = (BarHigh - PriorPeakValue)/(Index - PriorPeakIndex);

				for (int n = PriorPeakIndex+1, Count=1; n < Index; n++, Count++)
				{
					ZigZagValues[n] = PriorPeakValue + Count*Increment;
					ZigZagPeakIndex[n] = (float)PriorPeakIndex;
					ZigZagPeakType[n] = 0;
				}
			}
		}
		else if (CurrentPeakType < 0)
		{
			float ReversalPrice;
			if (ReversalPercent == 0.0f)
				ReversalPrice = CurrentPeakValue + ReversalAmount;
			else
				ReversalPrice = CurrentPeakValue + (CurrentPeakValue*ReversalPercent);

			//if (!CurrentBarIsPeak && BarHigh > ReversalPrice)
			if (!CurrentBarIsPeak && sc.FormattedEvaluate(BarHigh, sc.BaseGraphValueFormat, GREATER_OPERATOR, ReversalPrice, sc.BaseGraphValueFormat))
			{
				ZigZagPeakIndex[Index] = (float)Index;
				ZigZagValues[Index] = BarHigh;
				ZigZagPeakType[Index] = 1;

				float Increment = (BarHigh - CurrentPeakValue)/(Index - CurrentPeakIndex);

				for (int n = CurrentPeakIndex+1, Count=1; n < Index; n++, Count++)
				{
					ZigZagValues[n] = CurrentPeakValue + Count*Increment;
				}
			}
			//else if (BarLow < CurrentPeakValue)
			else if (sc.FormattedEvaluate(BarLow, sc.BaseGraphValueFormat, LESS_EQUAL_OPERATOR, CurrentPeakValue, sc.BaseGraphValueFormat))
			{
				ZigZagPeakIndex[Index] = (float)Index;
				ZigZagValues[Index] = BarLow;
				ZigZagPeakType[Index] = -1;

				float Increment = (PriorPeakValue - BarLow)/(Index - PriorPeakIndex);

				for (int n = PriorPeakIndex+1, Count=1; n < Index; n++, Count++)
				{
					ZigZagValues[n] = PriorPeakValue - Count*Increment;
					ZigZagPeakIndex[n] = (float)PriorPeakIndex;
					ZigZagPeakType[n] = 0;
				}
			}
		}
	}

	return ZigZagValues;
}


/*==========================================================================*/
// ZigZagPeakType : +1=high peak, -1=low peak, 0=not peak
// ZigZagPeakIndex: index of current peak, -1=no peak yet
SCFloatArrayRef ResettableZigZag2_S(SCFloatArrayRef InputDataHigh, SCFloatArrayRef InputDataLow, SCFloatArrayRef ZigZagValues, SCFloatArrayRef ZigZagPeakType, SCFloatArrayRef ZigZagPeakIndex, int StartIndex, int Index, int NumberOfBars, float ReversalAmount, SCStudyInterfaceRef sc)
{
	if (Index == StartIndex)
	{
		for(int ZeroIndex = StartIndex ; ZeroIndex < ZigZagValues.GetArraySize(); ZeroIndex++)
		{
			ZigZagValues[ZeroIndex] = 0;
			ZigZagPeakType[ZeroIndex] = 0;
			ZigZagPeakIndex[ZeroIndex] = 0;
		}
		ZigZagPeakIndex[StartIndex] = -1;
		return ZigZagValues;
	}

	
	if (ZigZagPeakIndex[Index] == 0)
	{		
		if (ZigZagPeakIndex[Index-1] != -1)
		{
			// new bar, copy values forward
			ZigZagPeakIndex[Index] = ZigZagPeakIndex[Index-1];
			ZigZagValues[Index] = 0;
			ZigZagPeakType[Index] = 0;
		}
		else
		{
			// still looking for initial trend
			if (InputDataHigh[Index] > InputDataHigh[StartIndex] && InputDataLow[Index] > InputDataLow[StartIndex]) //bullish trend
			{
				ZigZagPeakIndex[Index] = (float)Index;
				ZigZagValues[Index] = InputDataHigh[Index];
				ZigZagPeakType[Index] = 1;

				ZigZagPeakIndex[StartIndex] = (float)StartIndex;
				ZigZagValues[StartIndex] = InputDataLow[StartIndex];
				ZigZagPeakType[StartIndex] = -1;

				float Increment = (InputDataHigh[Index] - InputDataLow[StartIndex])/(Index-StartIndex);

				for (int n=StartIndex+1, Count=1; n<Index; n++, Count++)
				{
					ZigZagValues[n] = InputDataLow[StartIndex] + Count*Increment;
					ZigZagPeakIndex[n] = (float)StartIndex;
					ZigZagPeakType[n] = 0;
				}
			}
			else if (InputDataHigh[Index] < InputDataHigh[StartIndex] && InputDataLow[Index] < InputDataLow[StartIndex]) //bearish trend
			{
				ZigZagPeakIndex[Index] = (float)Index;
				ZigZagValues[Index] = InputDataLow[Index];
				ZigZagPeakType[Index] = -1;

				ZigZagPeakIndex[StartIndex] = (float)StartIndex;
				ZigZagValues[StartIndex] = InputDataHigh[StartIndex];
				ZigZagPeakType[StartIndex] = 1;

				float Increment = (InputDataHigh[StartIndex] - InputDataLow[Index])/(Index-StartIndex);

				for (int n=StartIndex+1, Count=1; n<Index; n++, Count++)
				{
					ZigZagValues[n] = InputDataHigh[StartIndex] - Count*Increment;
					ZigZagPeakIndex[n] = (float)StartIndex;
					ZigZagPeakType[n] = 0;
				}
			}
			else
			{
				ZigZagPeakIndex[Index] = -1;
				ZigZagValues[Index] = 0;
				ZigZagPeakType[Index] = 0;
			}
			return ZigZagValues;
		}
	}


	int   CurrentPeakIndex = (int)ZigZagPeakIndex[Index];
	
	if (CurrentPeakIndex > 0)
	{
		int   CurrentPeakType  = (int)ZigZagPeakType[CurrentPeakIndex];
		float CurrentPeakValue = ZigZagValues[CurrentPeakIndex];

		int   PriorPeakIndex   = (int)ZigZagPeakIndex[CurrentPeakIndex-1];
		float PriorPeakValue   = ZigZagValues[PriorPeakIndex];

		bool CurrentBarIsPeak = Index == CurrentPeakIndex;

		float BarLow = InputDataLow[Index];
		float BarHigh = InputDataHigh[Index];


		if (CurrentPeakType > 0)
		{
			//if (BarHigh >= CurrentPeakValue)
			if (sc.FormattedEvaluate(BarHigh, sc.BaseGraphValueFormat, GREATER_EQUAL_OPERATOR, CurrentPeakValue, sc.BaseGraphValueFormat))
			{
				ZigZagPeakIndex[Index] = (float)Index;
				ZigZagValues[Index] = BarHigh;
				ZigZagPeakType[Index] = 1;

				float Increment = (BarHigh - PriorPeakValue)/(Index - PriorPeakIndex);

				for (int n = PriorPeakIndex+1, Count=1; n < Index; n++, Count++)
				{
					ZigZagValues[n] = PriorPeakValue + Count*Increment;
					ZigZagPeakIndex[n] = (float)PriorPeakIndex;
					ZigZagPeakType[n] = 0;
				}
			}
			else
			{
				int SkipCount = Index - CurrentPeakIndex;

				if (
					//BarLow < PriorPeakValue ||
					sc.FormattedEvaluate(BarLow, sc.BaseGraphValueFormat, LESS_OPERATOR, PriorPeakValue, sc.BaseGraphValueFormat) ||

					//(SkipCount >= NumberOfBars && CurrentPeakValue - BarLow > ReversalAmount)
					(SkipCount >= NumberOfBars && sc.FormattedEvaluate(CurrentPeakValue - BarLow, sc.BaseGraphValueFormat, GREATER_OPERATOR, ReversalAmount, sc.BaseGraphValueFormat))
					
					) //change to bearish
				{
					ZigZagPeakIndex[Index] = (float)Index;
					ZigZagValues[Index] = BarLow;
					ZigZagPeakType[Index] = -1;

					float Increment = (CurrentPeakValue - BarLow)/(Index - CurrentPeakIndex);

					for (int n = CurrentPeakIndex+1, Count=1; n < Index; n++, Count++)
					{
						ZigZagValues[n] = CurrentPeakValue - Count*Increment;
					}
				}
			}
		}
		else if (CurrentPeakType < 0)
		{
			//if (BarLow <= CurrentPeakValue)
			if (sc.FormattedEvaluate(BarLow, sc.BaseGraphValueFormat, LESS_EQUAL_OPERATOR, CurrentPeakValue, sc.BaseGraphValueFormat))
			{
				ZigZagPeakIndex[Index] = (float)Index;
				ZigZagValues[Index] = BarLow;
				ZigZagPeakType[Index] = -1;

				float Increment = (PriorPeakValue - BarLow)/(Index - PriorPeakIndex);

				for (int n = PriorPeakIndex+1, Count=1; n < Index; n++, Count++)
				{
					ZigZagValues[n] = PriorPeakValue - Count*Increment;
					ZigZagPeakIndex[n] = (float)PriorPeakIndex;
					ZigZagPeakType[n] = 0;
				}
			}
			else
			{
				int SkipCount = Index - CurrentPeakIndex;

				if (
					//BarHigh > PriorPeakValue ||
					sc.FormattedEvaluate(BarHigh, sc.BaseGraphValueFormat, GREATER_OPERATOR, PriorPeakValue, sc.BaseGraphValueFormat) ||

					//(SkipCount >= NumberOfBars && BarHigh - CurrentPeakValue > ReversalAmount)
					(SkipCount >= NumberOfBars && sc.FormattedEvaluate(BarHigh - CurrentPeakValue, sc.BaseGraphValueFormat, GREATER_OPERATOR, ReversalAmount, sc.BaseGraphValueFormat))
					
					) //change to bullish
				{
					ZigZagPeakIndex[Index] = (float)Index;
					ZigZagValues[Index] = BarHigh;
					ZigZagPeakType[Index] = 1;

					float Increment = (BarHigh - CurrentPeakValue)/(Index - CurrentPeakIndex);

					for (int n = CurrentPeakIndex+1, Count=1; n < Index; n++, Count++)
					{
						ZigZagValues[n] = CurrentPeakValue + Count*Increment;
					}
				}
			}
		}
	}
	return ZigZagValues;
}

/*==========================================================================*/
void Vortex_S(SCBaseDataRef BaseDataIn, SCFloatArrayRef TrueRangeOut, SCFloatArrayRef VortexMovementUpOut, SCFloatArrayRef VortexMovementDownOut, SCFloatArrayRef VMPlusOut, SCFloatArrayRef VMMinusOut, int Index, int VortexLength)
{
	TrueRange_S(BaseDataIn, TrueRangeOut, Index);

	if (Index == 0)
		return;

	VortexMovementUpOut[Index] = abs(BaseDataIn[SC_HIGH][Index] - BaseDataIn[SC_LOW][Index-1]);

	VortexMovementDownOut[Index] = abs(BaseDataIn[SC_LOW][Index] - BaseDataIn[SC_HIGH][Index-1]);

	float VMUpSum = 0;
	float VMDownSum = 0;
	float TrueRangeSum = 0;

	for (int Iteration = 0; Iteration < VortexLength && Index >= Iteration; ++Iteration)
	{
		VMUpSum += VortexMovementUpOut[Index - Iteration];
		VMDownSum += VortexMovementDownOut[Index - Iteration];
		TrueRangeSum += TrueRangeOut[Index - Iteration];
	}

	if (TrueRangeSum != 0)
	{
		VMPlusOut[Index] = VMUpSum / TrueRangeSum;
		VMMinusOut[Index] = VMDownSum / TrueRangeSum;
	}
}
/*==========================================================================*/
void HeikinAshi_S(SCBaseDataRef BaseDataIn,
	int Index,
	int Length, 
	SCFloatArrayRef OpenOut, 
	SCFloatArrayRef HighOut, 
	SCFloatArrayRef LowOut, 
	SCFloatArrayRef LastOut
	, int SetCloseToCurrentPriceAtLastBar)
{
	float OpenVal = BaseDataIn[SC_OPEN][Index];
	float HighVal = BaseDataIn[SC_HIGH][Index];
	float LowVal = BaseDataIn[SC_LOW][Index];
	float LastVal = BaseDataIn[SC_LAST][Index];

	if (Index == BaseDataIn.GetArraySize() - 1 && SetCloseToCurrentPriceAtLastBar != 0)
		LastOut[Index] = LastVal;
	else
		LastOut[Index] = (OpenVal + HighVal + LowVal + LastVal) / 4.0f;

	if (Index == 0)
		OpenOut[Index] = OpenVal;
	else
	{
		OpenOut[Index] = (OpenOut[Index -1] + LastOut[Index -1]) / 2.0f;
	}
}

/*==========================================================================*/
void  InverseFisherTransform_S(SCFloatArrayRef In, SCFloatArrayRef Out, SCFloatArrayRef CalcArray1, SCFloatArrayRef CalcArray2, int Index, int HighestLowestLength, int MovingAverageLength, int MovAvgType)
{

	float Highest = GetHighest(In, Index, HighestLowestLength);
	float Lowest = GetLowest(In, Index, HighestLowestLength);
	float Range = (Highest - Lowest);

	if (Range != 0)
	{
		float Ratio = 10.0f / Range;
		float CalcValue2 = ((In[Index] - Lowest) * Ratio) - 5.0f;
		CalcArray2[Index] = CalcValue2;

		MovingAverage_S(CalcArray2, CalcArray1, MovAvgType, Index, MovingAverageLength);
		float CalcValue1 = CalcArray1[Index];
		float RefData = CalcValue1;

		//http://en.wikipedia.org/wiki/Exponential_function
		Out[Index] = (exp(2 * RefData) - 1) / (exp(2 * RefData) + 1);

		if (_isnan(Out[Index]))
		{
			int A = 1;
		}
	}
	else
		Out[Index] = Out[Index - 1];


}

/*==========================================================================*/
void  InverseFisherTransformRSI_S(SCFloatArrayRef In, SCFloatArrayRef Out, SCFloatArrayRef RSIArray1, SCFloatArrayRef RSIArray2, SCFloatArrayRef RSIArray3, SCFloatArrayRef RSIArray4, SCFloatArrayRef RSIArray5, SCFloatArrayRef CalcArray1,SCFloatArrayRef CalcArray2, int Index, int RSILength, int  InternalRSIMovAvgType, int RSIMovingAverageLength, int  MovingAverageOfRSIType)
{

	RSI_S(In, RSIArray1, RSIArray2, RSIArray3, RSIArray4, RSIArray5, Index, InternalRSIMovAvgType, RSILength);

	//put RSI calculation into an Array to be used with the moving average, since an array is required.
	CalcArray1[Index] = (float)((RSIArray1[Index] - 50)*0.1);
	
	MovingAverage_S(CalcArray1, CalcArray2, MovingAverageOfRSIType, Index, RSIMovingAverageLength);

	float WMA = CalcArray2[Index];

	Out[Index] = (exp(2 * WMA) - 1) / (exp(2 * WMA) + 1);

}

/*==========================================================================*/
void  MovingAverageCumulative_S(SCFloatArrayRef In, SCFloatArrayRef Out, int Index)
{
	if (Index == 0)
	{
		Out[0] = In[0];
		return;
	}


	Out[Index] = (In[Index] + Index * Out[Index - 1]) / (Index + 1);
}
/*==========================================================================*/
void CalculateCumulativeLogLogRegressionStatistics_S(SCFloatArrayRef In, double &Slope, double &Y_Intercept, SCFloatArrayRef Array_Sum_x, SCFloatArrayRef Array_Sum_x2, SCFloatArrayRef Array_Sum_x_2, SCFloatArrayRef Array_Sum_y, SCFloatArrayRef Array_Sum_xy, int Index)
{

	if (Index == 0 || Index == 1) //The slope is not defined until Index = 2. 
		return;

	//The sums are not defined at Index = 0, so we will simply define them to be 0 there.
	if (Index == 0)
	{
		Array_Sum_x[0] = 0;
		Array_Sum_x2[0] = 0;
		Array_Sum_x_2[0] = 0;
		Array_Sum_y[0] = 0;
		Array_Sum_xy[0] = 0;
	}

	//Initialize the sums at Index = 1. Since x[1] = 1, and log(1) = 0, all sums involving x are 0 at Index = 1.
	if (Index == 1)
	{
		Array_Sum_x[1] = 0;
		Array_Sum_x2[1] = 0;
		Array_Sum_x_2[1] = 0;
		Array_Sum_y[1] = log(In[1]);
		Array_Sum_xy[1] = 0;
	}

	//Compute the sums recursively.    
	Array_Sum_x[Index] = (float) (log(Index) + Array_Sum_x[Index - 1]);
	Array_Sum_x2[Index] = (float)(log(Index)*log(Index) + Array_Sum_x2[Index - 1]);
	Array_Sum_x_2[Index] = Array_Sum_x[Index]*Array_Sum_x[Index];
	Array_Sum_y[Index] = log(In[Index]) + Array_Sum_y[Index - 1];
	Array_Sum_xy[Index] = (float)(log(Index)*log(In[Index]) + Array_Sum_xy[Index - 1]);

	//Compute the log-log regression statistics.
	double b_numerator = (Index * Array_Sum_xy[Index] - Array_Sum_x[Index] * Array_Sum_y[Index]);
	double b_denominator = Index * Array_Sum_x2[Index] - Array_Sum_x_2[Index];
	Slope = b_numerator / b_denominator;

	//Y-Intercept is at Index == 0.
	Y_Intercept = (Array_Sum_y[Index] - Slope * Array_Sum_x[Index]) / Index;
}


/*==========================================================================*/
SCFloatArrayRef CumulativeStdDev_S(SCFloatArrayRef In, SCFloatArrayRef Out, SCFloatArrayRef Array_XSquared, SCFloatArrayRef Array_Mean, SCFloatArrayRef Array_MeanOfSquares, int Index)
{
	Array_XSquared[Index] = In[Index] * In[Index];

	MovingAverageCumulative_S(In, Array_Mean, Index);
	MovingAverageCumulative_S(Array_XSquared, Array_MeanOfSquares, Index);

	float CumulativeVariance = Array_MeanOfSquares[Index] - Array_Mean[Index]*Array_Mean[Index];

	Out[Index] = sqrt(CumulativeVariance);

	return Out;
}

/*==========================================================================*/
SCFloatArrayRef CumulativeHurstExponent_S(SCFloatArrayRef In, SCFloatArrayRef Out, SCFloatArrayRef Array_Average, SCFloatArrayRef Array_MeanAdjustedData, SCFloatArrayRef Array_CumulativeDeviation, SCFloatArrayRef Array_MinMax, SCFloatArrayRef Array_StdDev, SCFloatArrayRef Array_RescaledRange, SCFloatArrayRef Array_XSquared, SCFloatArrayRef Array_Mean, SCFloatArrayRef Array_MeanOfSquares, 
SCFloatArrayRef Array_Sum_x, SCFloatArrayRef Array_Sum_x2, SCFloatArrayRef Array_Sum_x_2, SCFloatArrayRef Array_Sum_y, SCFloatArrayRef Array_Sum_xy,	int Index)
{

	//Calculate the mean-adjusted data.
	MovingAverageCumulative_S(In, Array_Average, Index);

	
	Array_MeanAdjustedData[Index] = In[Index] - Array_Average[Index];


	//Calculate the cumulative deviations Z_i.
	if (Index == 0)
	{
		Array_CumulativeDeviation[Index] = Array_MeanAdjustedData[Index];
		Array_MinMax[0] = FLT_MAX;//Minimum cumulative deviation value
		Array_MinMax[1] = -FLT_MAX;//Maximum cumulative deviation value
	}
	else
		Array_CumulativeDeviation[Index] = Array_MeanAdjustedData[Index] + Array_CumulativeDeviation[Index - 1];

	if(Array_CumulativeDeviation[Index] > Array_MinMax[1])
	{

		Array_MinMax[1]=Array_CumulativeDeviation[Index];
	}

	if(Array_CumulativeDeviation[Index] < Array_MinMax[0])
	{

		Array_MinMax[0] = Array_CumulativeDeviation[Index];
	}
	//Calcuate the ranges R_t = max{Z_0,Z_1,...,Z_t} - min{Z_0,Z_1,...,Z_t}.

	float Range = Array_MinMax[1] - Array_MinMax[0];


	//Calculate the standard deviations. THE INPUT NEEDS TO BE THE BASE DATA.
	CumulativeStdDev_S(In, Array_StdDev,  Array_XSquared, Array_Mean, Array_MeanOfSquares, Index);

	//Calculate the rescaled ranges.
	if (Array_StdDev[Index] != 0)
		Array_RescaledRange[Index] = Range / Array_StdDev[Index];

	//Calculate the log-log slope, which is the Hurst exponent.
	double slope = 0;
	double y_intercept = 0;

	if(Index >= 2) //The Hurst exponent is only defined when Index >= 2.
	{
		CalculateCumulativeLogLogRegressionStatistics_S(Array_RescaledRange, slope, y_intercept, Array_Sum_x, Array_Sum_x2, Array_Sum_x_2, Array_Sum_y, Array_Sum_xy, Index);
	}

	Out[Index] = (float)slope;

	return Out;
}

/*==========================================================================*/
void CalculateHurstExponent(SCFloatArrayRef In_X, SCFloatArrayRef In_Y, double &HurstExponent, int Index, int Length)
{
	HurstExponent = 0.0;

	double sum_y = 0, sum_x = 0, sum_x2 = 0, sum_x_2 = 0, sum_xy = 0;

	if (Index < (Length - 1))
	{
		Index = Length - 1;
	}

	sum_x = GetSummation(In_X, Index, Length);
	sum_x_2 = sum_x * sum_x;
	sum_y = GetSummation(In_Y, Index, Length);
	for (int Offset = 0; Offset < Length; Offset++)
	{
		sum_x2 += In_X[Index - Offset] * In_X[Index - Offset];
		sum_xy += In_X[Index - Offset] * In_Y[Index - Offset];
	}

	double H_numerator = (Length * sum_xy - sum_x * sum_y);
	double H_denominator = Length * sum_x2 - sum_x_2;

	if (H_denominator != 0)
		HurstExponent = H_numerator / H_denominator;
}
/*==========================================================================*/ 
SCFloatArrayRef HurstExponentNew_S(SCFloatArrayRef In, SCFloatArrayRef Out, int Index, int LengthIndex)
{
	int CalculationStartIndex = 0;

	int ArrayIterations = 0;
	int CurrentSubsetLength = 8;//This is set to the initial subset length and is doubled with each iteration.
	int CurrentNumberOfSubsets = 0;
	if (LengthIndex == 0)//32
	{

		if (Index < 31)
			return Out;

		CalculationStartIndex = Index - 31;

		ArrayIterations = 3;
		CurrentNumberOfSubsets = 32 / CurrentSubsetLength;//Starts with 4 subsets of 8, then 2 subsets of 16, then 1  subset of 32
	}
	else if (LengthIndex == 1)//64
	{
		if (Index < 63)
			return Out;

		CalculationStartIndex = Index - 63;

		ArrayIterations = 4;
		CurrentNumberOfSubsets = 64 / CurrentSubsetLength;//8
	}
	else if (LengthIndex == 2)//128
	{
		if (Index < 127)
			return Out;

		CalculationStartIndex = Index - 127;

		ArrayIterations = 5;
		CurrentNumberOfSubsets = 128 / CurrentSubsetLength;
	}
	else
		return Out;

	float MeanAdjustedSeries[128] = { 0 };
	float CumulativeVariateSeries[128] = { 0 };

	//This is five pairs of values. Each pair is 'subsets per iteration' and 'rescaled range average'
	float RescaledRangeAverageDataPairForIteration[5][2] = { 0 };

	for (int IterationIndex = 0; IterationIndex < ArrayIterations; IterationIndex++)
	{
		float RescaledRangeSum = 0;
		for (int SubsetIndex = 0; SubsetIndex < CurrentNumberOfSubsets; SubsetIndex++)
		{
			const int SubsetStartBarIndex = CalculationStartIndex + (CurrentSubsetLength * SubsetIndex);

			float Sum = 0;
			for (int BarIndex = SubsetStartBarIndex; BarIndex < SubsetStartBarIndex + CurrentSubsetLength; BarIndex++)
			{
				Sum += In[BarIndex];

			}

			float Mean = Sum / CurrentSubsetLength;

			int SeriesIndex = 0;
			for (int BarIndex = SubsetStartBarIndex; BarIndex < SubsetStartBarIndex + CurrentSubsetLength; BarIndex++)
			{
				MeanAdjustedSeries[SeriesIndex] = In[BarIndex] - Mean;
				SeriesIndex++;
			}

			//calculate the cumulative variate series
			SeriesIndex = 0;
			for (int SeriesIndex = 0; SeriesIndex < CurrentSubsetLength; SeriesIndex++)
			{
				float Sum = 0;
				for (int MeanAdjustedSeriesIndex = 0; MeanAdjustedSeriesIndex < SeriesIndex + 1; MeanAdjustedSeriesIndex++)
				{ 
					Sum += MeanAdjustedSeries[MeanAdjustedSeriesIndex];
				}

				CumulativeVariateSeries[SeriesIndex] = Sum;

			}

			//calculate the range of the subset
			float MinValue;
			float MaxValue;
			GetMinMaxValuesFromArray(CumulativeVariateSeries, CurrentSubsetLength, MinValue, MaxValue);
		
			float Range = MaxValue - MinValue;

			float StandardDeviationOutput = 0;
			int StandardDeviationStartIndex = SubsetStartBarIndex + CurrentSubsetLength - 1;
			GetStandardDeviation(In, StandardDeviationOutput, StandardDeviationStartIndex, CurrentSubsetLength);

			float RescaledRange = 0;
			if(StandardDeviationOutput != 0)
			RescaledRange = Range / StandardDeviationOutput;

			RescaledRangeSum += RescaledRange;
		}

		float RescaledRangeAverage = RescaledRangeSum / CurrentNumberOfSubsets;
		RescaledRangeAverageDataPairForIteration[IterationIndex][0] = (float)CurrentSubsetLength;
		RescaledRangeAverageDataPairForIteration[IterationIndex][1] = RescaledRangeAverage;


		CurrentSubsetLength *= 2;
		CurrentNumberOfSubsets /= 2;

	}


	float SubsetLengthLogArray[5] = { 0 };
	float RescaledRangeAverageLogArray[5] = { 0 };
	for (int IterationIndex = 0; IterationIndex < ArrayIterations; IterationIndex++)
	{
		SubsetLengthLogArray[IterationIndex] = log(RescaledRangeAverageDataPairForIteration[IterationIndex][0]);// CurrentSubsetLength;

		RescaledRangeAverageLogArray[IterationIndex] = log(RescaledRangeAverageDataPairForIteration[IterationIndex][1]);// RescaledRangeAverage;


	}

	SCFloatArray SubsetLengthLogSCFloatArray;
	SubsetLengthLogSCFloatArray.InternalSetArray(SubsetLengthLogArray, ArrayIterations);

	SCFloatArray RescaledRangeAverageLogArraySCFloatArray;
	RescaledRangeAverageLogArraySCFloatArray.InternalSetArray(RescaledRangeAverageLogArray, ArrayIterations);
	
	double HurstExponent;
	CalculateHurstExponent(SubsetLengthLogSCFloatArray, RescaledRangeAverageLogArraySCFloatArray,  HurstExponent, ArrayIterations - 1, ArrayIterations);

	if (isnan(HurstExponent))
	{
		HurstExponent = 0;
	}

	Out[Index] = (float)HurstExponent;

	return Out;
}

/*==========================================================================*/
void GetMinMaxValuesFromArray(float* Array, int ArrayLength, float &MinValue, float &MaxValue)
{
	MinValue = FLT_MAX;
	MaxValue = -FLT_MAX;

	for (int Index = 0; Index < ArrayLength; Index++)
	{
		if (MinValue > Array[Index])
			MinValue = Array[Index];

		if (MaxValue < Array[Index])
			MaxValue = Array[Index];

	}

}

/*==========================================================================*/
SCFloatArrayRef T3MovingAverage_S
( SCFloatArrayRef InputArray
, SCFloatArrayRef OutputArray
, SCFloatArrayRef CalcArray0
, SCFloatArrayRef CalcArray1
, SCFloatArrayRef CalcArray2
, SCFloatArrayRef CalcArray3
, SCFloatArrayRef CalcArray4
, SCFloatArrayRef CalcArray5
, float Multiplier
, int Index
, int Length)
{
	MovingAverage_S(InputArray, CalcArray0, MOVAVGTYPE_EXPONENTIAL, Index, Length);

	MovingAverage_S(CalcArray0, CalcArray1, MOVAVGTYPE_EXPONENTIAL, Index, Length);

	MovingAverage_S(CalcArray1, CalcArray2, MOVAVGTYPE_EXPONENTIAL, Index, Length);

	MovingAverage_S(CalcArray2, CalcArray3, MOVAVGTYPE_EXPONENTIAL, Index, Length);

	MovingAverage_S(CalcArray3, CalcArray4, MOVAVGTYPE_EXPONENTIAL, Index, Length);

	MovingAverage_S(CalcArray4, CalcArray5, MOVAVGTYPE_EXPONENTIAL, Index, Length);

	float Mult2 = Multiplier * Multiplier;  // s^2

	float Mult3 = Mult2 * Multiplier;  // s^3

	float c1 = -Mult3;  // -s^3

	float c2 = 3 * Mult3 + 3 * Mult2;  // 3s^3 + 3s^2

	float c3 = -3 * Mult3 - 6 * Mult2 - 3 * Multiplier;  // -3s^3 - 6s^2 - 3^s

	float c4 = Mult3 + 3 * Mult2 + 3 * Multiplier + 1;  // s^3 + 3s^2 + 3s + 1

	OutputArray[Index] = c1*CalcArray5[Index] + c2*CalcArray4[Index] +
		c3*CalcArray3[Index] + c4*CalcArray2[Index];

	return OutputArray;
}