#include "stdafx.h"		//Precompiled header file

#include "CalcLibEMA.h"
/// <summary>
/// Class:	ExponentialMovingAverage
/// 
/// In order to reduce the lag in simple moving averages, technicians 
/// sometimes use exponential moving averages, or exponentially 
/// weighted moving averages. Exponential moving averages reduce 
/// the lag by applying more weight to recent prices relative to 
/// older prices. The weighting applied to the most recent price 
/// depends on the length of the moving average. The shorter the 
/// exponential moving average is, the more weight that will be 
/// applied to the most recent price. For example: a 10-period 
/// exponential moving average weighs the most recent price 18.18% 
/// and a 20-period exponential moving average weighs the most 
/// recent price 9.52%. The method for calculating the exponential 
/// moving average is fairly complicated. The important thing to 
/// remember is that the exponential moving average puts more 
/// weight on recent prices. As such, it will react quicker to 
/// recent price changes than a simple moving average. 
/// 
///	Exponential Moving Average Calculation
/// The formula for an exponential moving average is:
///	X = (K x (C - P)) + P
///	X = Current EMA 
/// C = Current Price
/// P = Previous period's EMA*
///	K = Smoothing constant
/// (*A SMA is used for first period's calculation)
/// 
/// The smoothing constant applies the appropriate weighting to the 
/// most recent price relative to the previous exponential moving 
/// average. The formula for the smoothing constant is:
///
/// K = 2/(1+N)
/// N = Number of periods for EMA
/// For a 10-period EMA, the smoothing constant would be .1818.


CalcLibEMA::CalcLibEMA(DOUBLEVECTOR values, DATEVECTOR dates, int period) : m_sma(values, dates, period)
{
	initValues(values, dates);							//Initialize the values for this object
	m_period = period;
	m_smoothingConstant = calcSmoothingConstant(m_period);
}

double CalcLibEMA::calcSmoothingConstant(int period)
{
	double k = (double) 2 / ( 1 + period);
	return k;
}

int	CalcLibEMA::doCalc()
{
	int retval = getOK();

	// First calculate the SMA for the use for the first point
	
	m_sma.doCalc();
	//Get first defined data point
	//1/21/03 -- now first check the value of sma.getFirstDefinedPoint()
	CalcLibData d;
	if (m_sma.getFirstDefinedPoint(d))
	{
		double simpleMovingAverage = d.getValue();

		///	X = (K x (C - P)) + P
		///	X = Current EMA 
		/// C = Current Price
		/// P = Previous period's EMA*
		///	K = Smoothing constant
		/// (*A SMA is used for first period's calculation)
		bool first = true;
		int length = m_input.size();
		for (int j = 0; j < length; j++)
		{
			CalcLibData d = m_input.at(j);
			if (j >= m_period - 1 && d.getValue() != d.getInvalid())
			{
				if (first)
				{
					m_output.at(j).setValue(simpleMovingAverage);
					first = false;
				}
				else
				{
					//output[j].val = (smoothingConstant * (input[j].val - output[j - 1].val)) + output[j - 1].val;
					m_output.at(j) = (m_smoothingConstant * 
										(m_input.at(j).getValue() - 
										 m_output.at(j - 1).getValue())) + 
										 m_output.at(j - 1).getValue();
				}
			}
			else
			{
				//output[j].val = 0;
				//output[j].status = Data.Undefined;
				m_output.at(j).setValue(0);
				m_output.at(j).setStatus(d.getUndefined());
			}
		}
	}
	else
	{
		//retval = (int)Calc.status.bad;
		retval = getBad();
	}

	return retval;
}

