1175 lines
41 KiB
C#
1175 lines
41 KiB
C#
|
//-------------------------------------------------------------
|
|||
|
// <copyright company=<3D>Microsoft Corporation<6F>>
|
|||
|
// Copyright <20> Microsoft Corporation. All Rights Reserved.
|
|||
|
// </copyright>
|
|||
|
//-------------------------------------------------------------
|
|||
|
// @owner=alexgor, deliant
|
|||
|
//=================================================================
|
|||
|
// File: PriceIndicators.cs
|
|||
|
//
|
|||
|
// Namespace: System.Web.UI.WebControls[Windows.Forms].Charting.Formulas
|
|||
|
//
|
|||
|
// Classes: PriceIndicators
|
|||
|
//
|
|||
|
// Purpose: This class is used to calculate Price
|
|||
|
// indicators used in Technical Analyses.
|
|||
|
//
|
|||
|
// Reviewed: GS - August 7, 2002
|
|||
|
// AG - August 7, 2002
|
|||
|
//
|
|||
|
//===================================================================
|
|||
|
|
|||
|
|
|||
|
using System;
|
|||
|
|
|||
|
|
|||
|
#if Microsoft_CONTROL
|
|||
|
namespace System.Windows.Forms.DataVisualization.Charting.Formulas
|
|||
|
#else
|
|||
|
namespace System.Web.UI.DataVisualization.Charting.Formulas
|
|||
|
#endif
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// Price indicator is module with mathematical calculations
|
|||
|
/// that apply to a security's price.
|
|||
|
/// </summary>
|
|||
|
internal class PriceIndicators : IFormula
|
|||
|
{
|
|||
|
#region Error strings
|
|||
|
|
|||
|
// Error strings
|
|||
|
//internal string inputArrayStart = "Formula requires";
|
|||
|
//internal string inputArrayEnd = "arrays";
|
|||
|
//internal string SR.ExceptionPriceIndicatorsSameYNumber = "Formula requires the same number of Y values for each input data point";
|
|||
|
//internal string SR.ExceptionPriceIndicatorsFormulaRequiresFourArrays = "Formula requires the same number of X and Y values for each input data point";
|
|||
|
//internal string periodMissing = "Formula error - Period parameter is missing. ";
|
|||
|
//internal string SR.ExceptionPriceIndicatorsFormulaRequiresFourArrays = "Formula error - There are not enough data points for the Period. ";
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region Properties
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Formula Module name
|
|||
|
/// </summary>
|
|||
|
virtual public string Name { get { return SR.FormulaNamePriceIndicators; } }
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region Formulas
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// A Moving Average is an indicator that shows the average
|
|||
|
/// value of a security's price over a period of time. When
|
|||
|
/// calculating a moving average, a mathematical analysis of
|
|||
|
/// the security's average value over a predetermined time
|
|||
|
/// period is made. As the security's price changes,
|
|||
|
/// its average price moves up or down.
|
|||
|
/// A simple, or arithmetic, moving average is calculated by
|
|||
|
/// adding the closing price of the security for a number of
|
|||
|
/// time periods (e.g., 12 days) and then dividing this total
|
|||
|
/// by the number of time periods. The result is the average
|
|||
|
/// price of the security over the time period. Simple moving
|
|||
|
/// averages give equal weight to each daily price.
|
|||
|
/// ---------------------------------------------------------
|
|||
|
/// Input:
|
|||
|
/// - Y values.
|
|||
|
/// Output:
|
|||
|
/// - Moving Average.
|
|||
|
/// Parameters:
|
|||
|
/// - Period
|
|||
|
/// Extra Parameters:
|
|||
|
/// - Start from First
|
|||
|
///
|
|||
|
/// </summary>
|
|||
|
/// <param name="inputValues">Array of doubles: Y values</param>
|
|||
|
/// <param name="outputValues">Arrays of doubles: Moving average</param>
|
|||
|
/// <param name="period">Period</param>
|
|||
|
/// <param name="FromFirst">Start from first value</param>
|
|||
|
internal void MovingAverage(double [] inputValues, out double [] outputValues, int period, bool FromFirst )
|
|||
|
{
|
|||
|
double [][] tempInput = new double [2][];
|
|||
|
double [][] tempOutput = new double [2][];
|
|||
|
string [] parList = new string [1];
|
|||
|
string [] extList = new string [1];
|
|||
|
|
|||
|
parList[0] = period.ToString(System.Globalization.CultureInfo.InvariantCulture);
|
|||
|
extList[0] = FromFirst.ToString(System.Globalization.CultureInfo.InvariantCulture);
|
|||
|
|
|||
|
tempInput[0] = new double[inputValues.Length];
|
|||
|
tempInput[1] = inputValues;
|
|||
|
|
|||
|
MovingAverage( tempInput, out tempOutput, parList, extList );
|
|||
|
|
|||
|
outputValues = tempOutput[1];
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// A Moving Average is an indicator that shows the average
|
|||
|
/// value of a security's price over a period of time. When
|
|||
|
/// calculating a moving average, a mathematical analysis of
|
|||
|
/// the security's average value over a predetermined time
|
|||
|
/// period is made. As the security's price changes,
|
|||
|
/// its average price moves up or down.
|
|||
|
/// A simple, or arithmetic, moving average is calculated by
|
|||
|
/// adding the closing price of the security for a number of
|
|||
|
/// time periods (e.g., 12 days) and then dividing this total
|
|||
|
/// by the number of time periods. The result is the average
|
|||
|
/// price of the security over the time period. Simple moving
|
|||
|
/// averages give equal weight to each daily price.
|
|||
|
/// ---------------------------------------------------------
|
|||
|
/// Input:
|
|||
|
/// - Y values.
|
|||
|
/// Output:
|
|||
|
/// - Moving Average.
|
|||
|
/// Parameters:
|
|||
|
/// - Period
|
|||
|
/// Extra Parameters:
|
|||
|
/// - Start from First
|
|||
|
///
|
|||
|
/// </summary>
|
|||
|
/// <param name="inputValues">Arrays of doubles: 1. row - X values, 2. row - Y values</param>
|
|||
|
/// <param name="outputValues">Arrays of doubles: 1. row - X values, 2. row - Moving average</param>
|
|||
|
/// <param name="parameterList">Array of strings: 1. Period</param>
|
|||
|
/// <param name="extraParameterList">Array of strings: 1. Start from zero</param>
|
|||
|
private void MovingAverage(double [][] inputValues, out double [][] outputValues, string [] parameterList, string [] extraParameterList)
|
|||
|
{
|
|||
|
int length = inputValues.Length;
|
|||
|
|
|||
|
// Period for moving average
|
|||
|
int period;
|
|||
|
try
|
|||
|
{period = int.Parse( parameterList[0], System.Globalization.CultureInfo.InvariantCulture );}
|
|||
|
catch( Exception e )
|
|||
|
{
|
|||
|
if (e.Message == SR.ExceptionObjectReferenceIsNull)
|
|||
|
throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing);
|
|||
|
else
|
|||
|
throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing + e.Message);
|
|||
|
}
|
|||
|
|
|||
|
if( period <= 0 )
|
|||
|
throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
|
|||
|
|
|||
|
// Starting average from the first data point or after period.
|
|||
|
bool startFromFirst = bool.Parse( extraParameterList[0]);
|
|||
|
|
|||
|
// There is no enough series
|
|||
|
if( length != 2 )
|
|||
|
throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
|
|||
|
|
|||
|
// Different number of x and y values
|
|||
|
if( inputValues[0].Length != inputValues[1].Length )
|
|||
|
throw new ArgumentException(SR.ExceptionPriceIndicatorsSameXYNumber);
|
|||
|
|
|||
|
// Not enough values for moving average.
|
|||
|
if( inputValues[0].Length < period )
|
|||
|
throw new ArgumentException(SR.ExceptionPriceIndicatorsNotEnoughPoints);
|
|||
|
|
|||
|
outputValues = new double [2][];
|
|||
|
|
|||
|
if( startFromFirst )
|
|||
|
{
|
|||
|
// X values
|
|||
|
outputValues[0] = new double [inputValues[0].Length];
|
|||
|
|
|||
|
// Y values
|
|||
|
outputValues[1] = new double [inputValues[1].Length];
|
|||
|
|
|||
|
for( int point = 0; point < inputValues[0].Length; point++ )
|
|||
|
{
|
|||
|
// Set X value
|
|||
|
outputValues[0][point] = inputValues[0][point];
|
|||
|
|
|||
|
// Find sum of Y values
|
|||
|
double sum = 0;
|
|||
|
int startSum = 0;
|
|||
|
|
|||
|
// Find the begining of the period
|
|||
|
if( point - period + 1 > 0 )
|
|||
|
{
|
|||
|
startSum = point - period + 1;
|
|||
|
}
|
|||
|
|
|||
|
// Find sum fro real period.
|
|||
|
for( int pointSum = startSum; pointSum <= point; pointSum++ )
|
|||
|
{
|
|||
|
sum += inputValues[1][pointSum];
|
|||
|
}
|
|||
|
|
|||
|
// Find real period if start from first data point.
|
|||
|
int realPeriod = period;
|
|||
|
if( period > point + 1 )
|
|||
|
{
|
|||
|
realPeriod = point + 1;
|
|||
|
}
|
|||
|
|
|||
|
outputValues[1][point] = sum / realPeriod;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// X values
|
|||
|
outputValues[0] = new double [inputValues[0].Length - period + 1];
|
|||
|
|
|||
|
// Y values
|
|||
|
outputValues[1] = new double [inputValues[1].Length - period + 1];
|
|||
|
|
|||
|
// Find sum of Y values for the period
|
|||
|
double sum = 0;
|
|||
|
for( int pointSum = 0; pointSum < period; pointSum++ )
|
|||
|
{
|
|||
|
sum += inputValues[1][pointSum];
|
|||
|
}
|
|||
|
|
|||
|
for( int point = 0; point < outputValues[0].Length; point++ )
|
|||
|
{
|
|||
|
// Set X value
|
|||
|
outputValues[0][point] = inputValues[0][point + period - 1];
|
|||
|
|
|||
|
outputValues[1][point] = sum / period;
|
|||
|
|
|||
|
// Change Sum
|
|||
|
if( point < outputValues[0].Length - 1 )
|
|||
|
{
|
|||
|
sum -= inputValues[1][point];
|
|||
|
sum += inputValues[1][point + period];
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// An exponential (or exponentially weighted) moving average
|
|||
|
/// is calculated by applying a percentage of today<61>s closing
|
|||
|
/// price to yesterday<61>s moving average value. Exponential
|
|||
|
/// moving averages place more weight on recent prices. For
|
|||
|
/// example, to calculate a 9% exponential moving average
|
|||
|
/// of IBM, you would first take today<61>s closing price and
|
|||
|
/// multiply it by 9%. Next, you would add this product to
|
|||
|
/// the value of yesterday<61>s moving average multiplied by
|
|||
|
/// 91% (100% - 9% = 91%).
|
|||
|
/// ---------------------------------------------------------
|
|||
|
/// Input:
|
|||
|
/// - Y values.
|
|||
|
/// Output:
|
|||
|
/// - Exponential Moving Average.
|
|||
|
/// Parameters:
|
|||
|
/// - Period
|
|||
|
/// Extra Parameters:
|
|||
|
/// - Start from First
|
|||
|
///
|
|||
|
/// </summary>
|
|||
|
/// <param name="inputValues">Array of doubles: Y values</param>
|
|||
|
/// <param name="outputValues">Arrays of doubles: Exponential Moving average</param>
|
|||
|
/// <param name="period">Period</param>
|
|||
|
/// <param name="startFromFirst">Start from first value</param>
|
|||
|
internal void ExponentialMovingAverage(double []inputValues, out double []outputValues, int period, bool startFromFirst)
|
|||
|
{
|
|||
|
double [][] tempInput = new double [2][];
|
|||
|
double [][] tempOutput = new double [2][];
|
|||
|
string [] parList = new string [1];
|
|||
|
string [] extList = new string [1];
|
|||
|
|
|||
|
parList[0] = period.ToString(System.Globalization.CultureInfo.InvariantCulture);
|
|||
|
extList[0] = startFromFirst.ToString(System.Globalization.CultureInfo.InvariantCulture);
|
|||
|
|
|||
|
tempInput[0] = new double[inputValues.Length];
|
|||
|
tempInput[1] = inputValues;
|
|||
|
|
|||
|
ExponentialMovingAverage( tempInput, out tempOutput, parList, extList );
|
|||
|
|
|||
|
outputValues = tempOutput[1];
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// An exponential (or exponentially weighted) moving average
|
|||
|
/// is calculated by applying a percentage of today<61>s closing
|
|||
|
/// price to yesterday<61>s moving average value. Exponential
|
|||
|
/// moving averages place more weight on recent prices. For
|
|||
|
/// example, to calculate a 9% exponential moving average
|
|||
|
/// of IBM, you would first take today<61>s closing price and
|
|||
|
/// multiply it by 9%. Next, you would add this product to
|
|||
|
/// the value of yesterday<61>s moving average multiplied by
|
|||
|
/// 91% (100% - 9% = 91%).
|
|||
|
/// ---------------------------------------------------------
|
|||
|
/// Input:
|
|||
|
/// - Y values.
|
|||
|
/// Output:
|
|||
|
/// - Exponential Moving Average.
|
|||
|
/// Parameters:
|
|||
|
/// - Period
|
|||
|
/// Extra Parameters:
|
|||
|
/// - Start from First
|
|||
|
///
|
|||
|
/// </summary>
|
|||
|
/// <param name="inputValues">Arrays of doubles: 1. row - X values, 2. row - Y values</param>
|
|||
|
/// <param name="outputValues">Arrays of doubles: 1. row - X values, 2. row - Moving average</param>
|
|||
|
/// <param name="parameterList">Array of strings: 1. Period</param>
|
|||
|
/// <param name="extraParameterList">Array of strings: 1. Start from zero</param>
|
|||
|
private void ExponentialMovingAverage(double [][] inputValues, out double [][] outputValues, string [] parameterList, string [] extraParameterList)
|
|||
|
{
|
|||
|
int length = inputValues.Length;
|
|||
|
|
|||
|
// Period for moving average
|
|||
|
int period;
|
|||
|
try
|
|||
|
{period = int.Parse( parameterList[0], System.Globalization.CultureInfo.InvariantCulture );}
|
|||
|
catch( Exception e )
|
|||
|
{
|
|||
|
if (e.Message == SR.ExceptionObjectReferenceIsNull)
|
|||
|
throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing);
|
|||
|
else
|
|||
|
throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing + e.Message);
|
|||
|
}
|
|||
|
|
|||
|
if( period <= 0 )
|
|||
|
throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
|
|||
|
|
|||
|
// Formula for converting period to percentage
|
|||
|
double exponentialPercentage = 2.0 / ( period + 1.0 );
|
|||
|
|
|||
|
// Starting average from the first data point or after period.
|
|||
|
bool startFromFirst = bool.Parse( extraParameterList[0] );
|
|||
|
|
|||
|
// There is no enough series
|
|||
|
if( length != 2 )
|
|||
|
throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
|
|||
|
|
|||
|
// Different number of x and y values
|
|||
|
if( inputValues[0].Length != inputValues[1].Length )
|
|||
|
throw new ArgumentException(SR.ExceptionPriceIndicatorsSameXYNumber);
|
|||
|
|
|||
|
// Not enough values for moving average.
|
|||
|
if( inputValues[0].Length < period )
|
|||
|
throw new ArgumentException(SR.ExceptionPriceIndicatorsNotEnoughPoints);
|
|||
|
|
|||
|
outputValues = new double [2][];
|
|||
|
|
|||
|
if( startFromFirst )
|
|||
|
{
|
|||
|
// X values
|
|||
|
outputValues[0] = new double [inputValues[0].Length];
|
|||
|
|
|||
|
// Y values
|
|||
|
outputValues[1] = new double [inputValues[1].Length];
|
|||
|
|
|||
|
for( int point = 0; point < inputValues[0].Length; point++ )
|
|||
|
{
|
|||
|
// Set X value
|
|||
|
outputValues[0][point] = inputValues[0][point];
|
|||
|
|
|||
|
// Find sum of Y values
|
|||
|
double sum = 0;
|
|||
|
int startSum = 0;
|
|||
|
|
|||
|
if( point - period + 1 > 0 )
|
|||
|
{
|
|||
|
startSum = point - period + 1;
|
|||
|
}
|
|||
|
|
|||
|
for( int pointSum = startSum; pointSum < point; pointSum++ )
|
|||
|
{
|
|||
|
sum += inputValues[1][pointSum];
|
|||
|
}
|
|||
|
|
|||
|
int realPeriod = period;
|
|||
|
if( period > point + 1 )
|
|||
|
realPeriod = point + 1;
|
|||
|
|
|||
|
double movingAvr;
|
|||
|
|
|||
|
// Find real period if start from first data point.
|
|||
|
if( realPeriod <= 1 )
|
|||
|
movingAvr = 0;
|
|||
|
else
|
|||
|
movingAvr = sum / ( realPeriod - 1 );
|
|||
|
|
|||
|
// Formula for converting period to percentage
|
|||
|
exponentialPercentage = 2.0 / ( realPeriod + 1.0 );
|
|||
|
|
|||
|
// Exponential influence
|
|||
|
outputValues[1][point] = movingAvr * (1 - exponentialPercentage ) + inputValues[1][point] * exponentialPercentage;
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// X values
|
|||
|
outputValues[0] = new double [inputValues[0].Length - period + 1];
|
|||
|
|
|||
|
// Y values
|
|||
|
outputValues[1] = new double [inputValues[1].Length - period + 1];
|
|||
|
|
|||
|
for( int point = 0; point < outputValues[0].Length; point++ )
|
|||
|
{
|
|||
|
// Set X value
|
|||
|
outputValues[0][point] = inputValues[0][point + period - 1];
|
|||
|
|
|||
|
double movingAvr;
|
|||
|
// if point is less than period calulate simple moving average
|
|||
|
if( point == 0 )
|
|||
|
{
|
|||
|
// Find sum of Y values
|
|||
|
double sum = 0;
|
|||
|
for( int pointSum = point; pointSum < point + period; pointSum++ )
|
|||
|
{
|
|||
|
sum += inputValues[1][pointSum];
|
|||
|
}
|
|||
|
|
|||
|
movingAvr = sum / ( period );
|
|||
|
}
|
|||
|
// else use previos day exponential moving average
|
|||
|
else
|
|||
|
movingAvr = outputValues[1][point-1];
|
|||
|
|
|||
|
// Exponential influence
|
|||
|
outputValues[1][point] = movingAvr * (1 - exponentialPercentage ) + inputValues[1][point + period - 1] * exponentialPercentage;
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Triangular moving averages place the majority of the weight
|
|||
|
/// on the middle portion of the price series. They are actually
|
|||
|
/// double-smoothed simple moving averages. The periods used
|
|||
|
/// in the simple moving averages varies depending on if you
|
|||
|
/// specify an odd or even number of time periods.
|
|||
|
/// ---------------------------------------------------------
|
|||
|
/// Input:
|
|||
|
/// - Y values.
|
|||
|
/// Output:
|
|||
|
/// - Moving Average.
|
|||
|
/// Parameters:
|
|||
|
/// - Period
|
|||
|
/// Extra Parameters:
|
|||
|
/// - Start from First
|
|||
|
///
|
|||
|
/// </summary>
|
|||
|
/// <param name="inputValues">Arrays of doubles: 1. row - X values, 2. row - Y values</param>
|
|||
|
/// <param name="outputValues">Arrays of doubles: 1. row - X values, 2. row - Moving average</param>
|
|||
|
/// <param name="parameterList">Array of strings: 1. Period</param>
|
|||
|
/// <param name="extraParameterList">Array of strings: 1. Start from zero</param>
|
|||
|
private void TriangularMovingAverage(double [][] inputValues, out double [][] outputValues, string [] parameterList, string [] extraParameterList)
|
|||
|
{
|
|||
|
int length = inputValues.Length;
|
|||
|
|
|||
|
// Period for moving average
|
|||
|
int period;
|
|||
|
try
|
|||
|
{period = int.Parse( parameterList[0], System.Globalization.CultureInfo.InvariantCulture );}
|
|||
|
catch( Exception e )
|
|||
|
{
|
|||
|
if (e.Message == SR.ExceptionObjectReferenceIsNull)
|
|||
|
throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing);
|
|||
|
else
|
|||
|
throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing + e.Message);
|
|||
|
}
|
|||
|
|
|||
|
if( period <= 0 )
|
|||
|
throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
|
|||
|
|
|||
|
// Starting average from the first data point or after period.
|
|||
|
bool startFromFirst = bool.Parse( extraParameterList[0] );
|
|||
|
|
|||
|
// There is no enough series
|
|||
|
if( length != 2 )
|
|||
|
throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
|
|||
|
|
|||
|
// Different number of x and y values
|
|||
|
if( inputValues[0].Length != inputValues[1].Length )
|
|||
|
throw new ArgumentException(SR.ExceptionPriceIndicatorsSameXYNumber);
|
|||
|
|
|||
|
// Not enough values for moving average.
|
|||
|
if( inputValues[0].Length < period )
|
|||
|
throw new ArgumentException(SR.ExceptionPriceIndicatorsNotEnoughPoints);
|
|||
|
|
|||
|
outputValues = new double [2][];
|
|||
|
|
|||
|
// Find triangular period
|
|||
|
double tempPeriod = ((double)period + 1.0) / 2.0;
|
|||
|
tempPeriod = Math.Round(tempPeriod);
|
|||
|
double [] tempOut;
|
|||
|
double [] tempIn = inputValues[1];
|
|||
|
|
|||
|
// Call moving averages first time
|
|||
|
MovingAverage( tempIn, out tempOut, (int)tempPeriod, startFromFirst );
|
|||
|
// Call moving averages second time (Moving average of moving average)
|
|||
|
MovingAverage( tempOut, out tempOut, (int)tempPeriod, startFromFirst );
|
|||
|
|
|||
|
outputValues[1] = tempOut;
|
|||
|
|
|||
|
// X values
|
|||
|
outputValues[0] = new double [outputValues[1].Length];
|
|||
|
|
|||
|
// Set X values
|
|||
|
if( startFromFirst )
|
|||
|
outputValues[0] = inputValues[0];
|
|||
|
else
|
|||
|
{
|
|||
|
for( int index = 0; index < outputValues[1].Length; index++ )
|
|||
|
outputValues[0][index] = inputValues[0][((int)(tempPeriod)-1) * 2 + index];
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// A weighted moving average is designed to put more weight on
|
|||
|
/// recent data and less weight on past data. A weighted moving
|
|||
|
/// average is calculated by multiplying each of the previous
|
|||
|
/// day<61>s data by a weight. The following table shows the calculation
|
|||
|
/// of a 5-day weighted moving average.
|
|||
|
/// ---------------------------------------------------------
|
|||
|
/// Input:
|
|||
|
/// - Y values.
|
|||
|
/// Output:
|
|||
|
/// - Moving Average.
|
|||
|
/// Parameters:
|
|||
|
/// - Period
|
|||
|
/// Extra Parameters:
|
|||
|
/// - Start from First
|
|||
|
///
|
|||
|
/// </summary>
|
|||
|
/// <param name="inputValues">Arrays of doubles: 1. row - X values, 2. row - Y values</param>
|
|||
|
/// <param name="outputValues">Arrays of doubles: 1. row - X values, 2. row - Moving average</param>
|
|||
|
/// <param name="parameterList">Array of strings: 1. Period</param>
|
|||
|
/// <param name="extraParameterList">Array of strings: 1. Start from zero</param>
|
|||
|
private void WeightedMovingAverage(double [][] inputValues, out double [][] outputValues, string [] parameterList, string [] extraParameterList)
|
|||
|
{
|
|||
|
int length = inputValues.Length;
|
|||
|
|
|||
|
// Period for moving average
|
|||
|
int period;
|
|||
|
try
|
|||
|
{period = int.Parse( parameterList[0], System.Globalization.CultureInfo.InvariantCulture );}
|
|||
|
catch( Exception e )
|
|||
|
{
|
|||
|
if (e.Message == SR.ExceptionObjectReferenceIsNull)
|
|||
|
throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing);
|
|||
|
else
|
|||
|
throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing + e.Message);
|
|||
|
}
|
|||
|
|
|||
|
if( period <= 0 )
|
|||
|
throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
|
|||
|
|
|||
|
// Starting average from the first data point or after period.
|
|||
|
bool startFromFirst = bool.Parse( extraParameterList[0] );
|
|||
|
|
|||
|
// There is no enough series
|
|||
|
if( length != 2 )
|
|||
|
throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
|
|||
|
|
|||
|
// Different number of x and y values
|
|||
|
if( inputValues[0].Length != inputValues[1].Length )
|
|||
|
throw new ArgumentException(SR.ExceptionPriceIndicatorsSameXYNumber);
|
|||
|
|
|||
|
// Not enough values for moving average.
|
|||
|
if( inputValues[0].Length < period )
|
|||
|
throw new ArgumentException(SR.ExceptionPriceIndicatorsNotEnoughPoints);
|
|||
|
|
|||
|
outputValues = new double [2][];
|
|||
|
|
|||
|
if( startFromFirst )
|
|||
|
{
|
|||
|
// X values
|
|||
|
outputValues[0] = new double [inputValues[0].Length];
|
|||
|
|
|||
|
// Y values
|
|||
|
outputValues[1] = new double [inputValues[1].Length];
|
|||
|
|
|||
|
for( int point = 0; point < inputValues[0].Length; point++ )
|
|||
|
{
|
|||
|
// Set X value
|
|||
|
outputValues[0][point] = inputValues[0][point];
|
|||
|
|
|||
|
// Find sum of Y values
|
|||
|
double sum = 0;
|
|||
|
int startSum = 0;
|
|||
|
|
|||
|
if( point - period + 1 > 0 )
|
|||
|
{
|
|||
|
startSum = point - period + 1;
|
|||
|
}
|
|||
|
|
|||
|
int index = 1;
|
|||
|
int indexSum = 0;
|
|||
|
for( int pointSum = startSum; pointSum <= point; pointSum++ )
|
|||
|
{
|
|||
|
sum += inputValues[1][pointSum] * index;
|
|||
|
indexSum += index;
|
|||
|
index++;
|
|||
|
}
|
|||
|
|
|||
|
double movingAvr;
|
|||
|
|
|||
|
// Avoid division by zero.
|
|||
|
if( point == 0 )
|
|||
|
movingAvr = inputValues[1][0];
|
|||
|
else
|
|||
|
movingAvr = sum / indexSum;
|
|||
|
|
|||
|
// Weighted average
|
|||
|
outputValues[1][point] = movingAvr;
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// X values
|
|||
|
outputValues[0] = new double [inputValues[0].Length - period + 1];
|
|||
|
|
|||
|
// Y values
|
|||
|
outputValues[1] = new double [inputValues[1].Length - period + 1];
|
|||
|
|
|||
|
for( int point = 0; point < outputValues[0].Length; point++ )
|
|||
|
{
|
|||
|
// Set X value
|
|||
|
outputValues[0][point] = inputValues[0][point + period - 1];
|
|||
|
|
|||
|
// Find sum of Y values
|
|||
|
double sum = 0;
|
|||
|
|
|||
|
int index = 1;
|
|||
|
int indexSum = 0;
|
|||
|
for( int pointSum = point; pointSum < point + period; pointSum++ )
|
|||
|
{
|
|||
|
sum += inputValues[1][pointSum] * index;
|
|||
|
indexSum += index;
|
|||
|
index++;
|
|||
|
}
|
|||
|
|
|||
|
double movingAvr = sum / indexSum;
|
|||
|
|
|||
|
// Weighted average
|
|||
|
outputValues[1][point] = movingAvr;
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Bollinger Bands plot trading bands above and below
|
|||
|
/// a simple moving average. The standard deviation of
|
|||
|
/// closing prices for a period equal to the moving
|
|||
|
/// average employed is used to determine the band width.
|
|||
|
/// This causes the bands to tighten in quiet markets and
|
|||
|
/// loosen in volatile markets. The bands can be used to
|
|||
|
/// determine overbought and oversold levels, locate
|
|||
|
/// reversal areas, project targets for market moves, and
|
|||
|
/// determine appropriate stop levels. The bands are used
|
|||
|
/// in conjunction with indicators such as RSI, MovingAverageConvergenceDivergence
|
|||
|
/// histogram, CCI and Rate of Change. Divergences between
|
|||
|
/// Bollinger bands and other indicators show potential
|
|||
|
/// action points.
|
|||
|
/// ---------------------------------------------------------
|
|||
|
/// Input:
|
|||
|
/// - 1 Y value.
|
|||
|
/// Output:
|
|||
|
/// - 2 Y values (Bollinger Band Hi and Low).
|
|||
|
/// Parameters:
|
|||
|
/// - period
|
|||
|
/// Extra Parameters:
|
|||
|
/// - startFromFirst
|
|||
|
///
|
|||
|
/// </summary>
|
|||
|
/// <param name="inputValues">Arrays of doubles: 1. row - X values, 2. row - Y values</param>
|
|||
|
/// <param name="outputValues">Arrays of doubles: 1. row - X values, 2. row - Bollinger Band Up, 3. row - Bollinger Band Down</param>
|
|||
|
/// <param name="parameterList">Array of strings: 1. Period</param>
|
|||
|
/// <param name="extraParameterList">Array of strings: 1. Start from zero</param>
|
|||
|
private void BollingerBands(double [][] inputValues, out double [][] outputValues, string [] parameterList, string [] extraParameterList)
|
|||
|
{
|
|||
|
int length = inputValues.Length;
|
|||
|
|
|||
|
// Period for moving average
|
|||
|
int period;
|
|||
|
try
|
|||
|
{period = int.Parse( parameterList[0], System.Globalization.CultureInfo.InvariantCulture );}
|
|||
|
catch( Exception e )
|
|||
|
{
|
|||
|
if (e.Message == SR.ExceptionObjectReferenceIsNull)
|
|||
|
throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing);
|
|||
|
else
|
|||
|
throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing + e.Message);
|
|||
|
}
|
|||
|
|
|||
|
if( period <= 0 )
|
|||
|
throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
|
|||
|
|
|||
|
// Standard deviation
|
|||
|
double deviation;
|
|||
|
try
|
|||
|
{deviation = double.Parse( parameterList[1], System.Globalization.CultureInfo.InvariantCulture );}
|
|||
|
catch(System.Exception)
|
|||
|
{ throw new InvalidOperationException(SR.ExceptionIndicatorsDeviationMissing); }
|
|||
|
|
|||
|
// Starting average from the first data point or after period.
|
|||
|
bool startFromFirst = bool.Parse( extraParameterList[0] );
|
|||
|
|
|||
|
// There is no enough series
|
|||
|
if( length != 2 )
|
|||
|
throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
|
|||
|
|
|||
|
// Different number of x and y values
|
|||
|
if( inputValues[0].Length != inputValues[1].Length )
|
|||
|
throw new ArgumentException(SR.ExceptionPriceIndicatorsSameXYNumber);
|
|||
|
|
|||
|
// Not enough values for moving average.
|
|||
|
if( inputValues[0].Length < period )
|
|||
|
throw new ArgumentException(SR.ExceptionPriceIndicatorsNotEnoughPoints);
|
|||
|
|
|||
|
outputValues = new double [3][];
|
|||
|
|
|||
|
if( startFromFirst )
|
|||
|
{
|
|||
|
// X values
|
|||
|
outputValues[0] = new double [inputValues[0].Length];
|
|||
|
|
|||
|
// Y values
|
|||
|
outputValues[1] = new double [inputValues[1].Length];
|
|||
|
outputValues[2] = new double [inputValues[1].Length];
|
|||
|
|
|||
|
// average
|
|||
|
double [] average = new double [inputValues[1].Length];
|
|||
|
|
|||
|
MovingAverage( inputValues[1], out average, period, true );
|
|||
|
|
|||
|
for( int point = 0; point < outputValues[0].Length; point++ )
|
|||
|
{
|
|||
|
// Set X value
|
|||
|
outputValues[0][point] = inputValues[0][point];
|
|||
|
|
|||
|
// Find sum of Y values
|
|||
|
double sum = 0;
|
|||
|
int startSum = 0;
|
|||
|
|
|||
|
// Find the begining of the period
|
|||
|
if( point - period + 1 > 0 )
|
|||
|
{
|
|||
|
startSum = point - period + 1;
|
|||
|
}
|
|||
|
|
|||
|
for( int pointSum = startSum; pointSum <= point; pointSum++ )
|
|||
|
{
|
|||
|
sum += ((inputValues[1][pointSum] - average[point])*(inputValues[1][pointSum] - average[point]));
|
|||
|
}
|
|||
|
|
|||
|
outputValues[1][point] = average[point] + Math.Sqrt(sum / period) * deviation;
|
|||
|
outputValues[2][point] = average[point] - Math.Sqrt(sum / period) * deviation;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
// X values
|
|||
|
outputValues[0] = new double [inputValues[0].Length - period + 1];
|
|||
|
|
|||
|
// Y values
|
|||
|
outputValues[1] = new double [inputValues[1].Length - period + 1];
|
|||
|
outputValues[2] = new double [inputValues[1].Length - period + 1];
|
|||
|
|
|||
|
// average
|
|||
|
double [] average = new double [inputValues[1].Length - period + 1];
|
|||
|
|
|||
|
MovingAverage( inputValues[1], out average, period, false );
|
|||
|
|
|||
|
for( int point = 0; point < outputValues[0].Length; point++ )
|
|||
|
{
|
|||
|
// Set X value
|
|||
|
outputValues[0][point] = inputValues[0][point + period - 1];
|
|||
|
|
|||
|
// Find sum of Y values
|
|||
|
double sum = 0;
|
|||
|
|
|||
|
for( int pointSum = point; pointSum < point + period; pointSum++ )
|
|||
|
{
|
|||
|
sum += ((inputValues[1][pointSum] - average[point])*(inputValues[1][pointSum] - average[point]));
|
|||
|
}
|
|||
|
|
|||
|
outputValues[1][point] = average[point] + Math.Sqrt(sum / period) * deviation;
|
|||
|
outputValues[2][point] = average[point] - Math.Sqrt(sum / period) * deviation;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// The Typical Price indicator is simply an average of each
|
|||
|
/// day's price. The Median Price and Weighted Close are
|
|||
|
/// similar indicators. The Typical Price indicator provides
|
|||
|
/// a simple, single-line plot of the day's average price.
|
|||
|
/// Some investors use the Typical Price rather than the
|
|||
|
/// closing price when creating moving average ----ion
|
|||
|
/// systems.
|
|||
|
/// ---------------------------------------------------------
|
|||
|
/// Input:
|
|||
|
/// - 3 Y values ( Close, High, Low ).
|
|||
|
/// Output:
|
|||
|
/// - 1 Y value Weighted Close Indicator.
|
|||
|
/// </summary>
|
|||
|
/// <param name="inputValues">Arrays of doubles: 1. row - X values, 2. row - Y values (Close), 3. row - Y values (High), 4. row - Y values (Low)</param>
|
|||
|
/// <param name="outputValues">Arrays of doubles: 1. row - X values, 2. row - Weighted Close</param>
|
|||
|
private void TypicalPrice(double [][] inputValues, out double [][] outputValues)
|
|||
|
{
|
|||
|
int length = inputValues.Length;
|
|||
|
|
|||
|
// There is no enough series
|
|||
|
if( length != 4 )
|
|||
|
throw new ArgumentException( SR.ExceptionPriceIndicatorsFormulaRequiresThreeArrays);
|
|||
|
|
|||
|
// Different number of x and y values
|
|||
|
CheckNumOfValues( inputValues, 3 );
|
|||
|
|
|||
|
outputValues = new double [2][];
|
|||
|
|
|||
|
outputValues[0] = new double [inputValues[0].Length];
|
|||
|
outputValues[1] = new double [inputValues[1].Length];
|
|||
|
|
|||
|
for( int index = 0; index < inputValues[1].Length; index++ )
|
|||
|
{
|
|||
|
// Set X values
|
|||
|
outputValues[0][index] = inputValues[0][index];
|
|||
|
|
|||
|
// Set median price
|
|||
|
outputValues[1][index] = (inputValues[1][index] + inputValues[2][index] + inputValues[3][index])/3.0;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// The Median Price indicator is simply the midpoint of each
|
|||
|
/// day's price. The Typical Price and Weighted Close are
|
|||
|
/// similar indicators. The Median Price indicator provides
|
|||
|
/// a simple, single-line chart of the day's "average price."
|
|||
|
/// This average price is useful when you want a simpler
|
|||
|
/// scaleView of prices.
|
|||
|
/// ---------------------------------------------------------
|
|||
|
/// Input:
|
|||
|
/// - 2 Y values ( High, Low ).
|
|||
|
/// Output:
|
|||
|
/// - 1 Y value Median Price Indicator.
|
|||
|
/// </summary>
|
|||
|
/// <param name="inputValues">Arrays of doubles: 1. row - X values, 2. row - Y values (High), 3. row - Y values (Low)</param>
|
|||
|
/// <param name="outputValues">Arrays of doubles: 1. row - X values, 2. row - Median Price</param>
|
|||
|
private void MedianPrice(double [][] inputValues, out double [][] outputValues)
|
|||
|
{
|
|||
|
int length = inputValues.Length;
|
|||
|
|
|||
|
// There is no enough series
|
|||
|
if( length != 3 )
|
|||
|
throw new ArgumentException( SR.ExceptionPriceIndicatorsFormulaRequiresTwoArrays);
|
|||
|
|
|||
|
// Different number of x and y values
|
|||
|
CheckNumOfValues( inputValues, 2 );
|
|||
|
|
|||
|
outputValues = new double [2][];
|
|||
|
|
|||
|
outputValues[0] = new double [inputValues[0].Length];
|
|||
|
outputValues[1] = new double [inputValues[1].Length];
|
|||
|
|
|||
|
for( int index = 0; index < inputValues[1].Length; index++ )
|
|||
|
{
|
|||
|
// Set X values
|
|||
|
outputValues[0][index] = inputValues[0][index];
|
|||
|
|
|||
|
// Set median price
|
|||
|
outputValues[1][index] = (inputValues[1][index] + inputValues[2][index])/2.0;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// The Weighted Close indicator is simply an average of each day's
|
|||
|
/// price. It gets its name from the fact that extra weight is
|
|||
|
/// given to the closing price. The Median Price and Typical Price
|
|||
|
/// are similar indicators. When plotting and back-testing moving
|
|||
|
/// averages, indicators, trendlines, etc, some investors like
|
|||
|
/// the simplicity that a line chart offers. However, line
|
|||
|
/// charts that only show the closing price can be misleading
|
|||
|
/// since they ignore the high and low price. A Weighted Close
|
|||
|
/// chart combines the simplicity of the line chart with the
|
|||
|
/// scope of a bar chart, by plotting a single point for each
|
|||
|
/// day that includes the high, low, and closing price.
|
|||
|
/// ---------------------------------------------------------
|
|||
|
/// Input:
|
|||
|
/// - 3 Y values ( Close, High, Low ).
|
|||
|
/// Output:
|
|||
|
/// - 1 Y value Weighted Close Indicator.
|
|||
|
/// </summary>
|
|||
|
/// <param name="inputValues">Arrays of doubles: 1. row - X values, 2. row - Y values (Close), 3. row - Y values (High), 4. row - Y values (Low)</param>
|
|||
|
/// <param name="outputValues">Arrays of doubles: 1. row - X values, 2. row - Weighted Close</param>
|
|||
|
private void WeightedClose(double [][] inputValues, out double [][] outputValues)
|
|||
|
{
|
|||
|
int length = inputValues.Length;
|
|||
|
|
|||
|
// There is no enough series
|
|||
|
if( length != 4 )
|
|||
|
throw new ArgumentException( SR.ExceptionPriceIndicatorsFormulaRequiresThreeArrays);
|
|||
|
|
|||
|
// Different number of x and y values
|
|||
|
CheckNumOfValues( inputValues, 3 );
|
|||
|
|
|||
|
outputValues = new double [2][];
|
|||
|
|
|||
|
outputValues[0] = new double [inputValues[0].Length];
|
|||
|
outputValues[1] = new double [inputValues[1].Length];
|
|||
|
|
|||
|
for( int index = 0; index < inputValues[1].Length; index++ )
|
|||
|
{
|
|||
|
// Set X values
|
|||
|
outputValues[0][index] = inputValues[0][index];
|
|||
|
|
|||
|
// Set median price
|
|||
|
outputValues[1][index] = (inputValues[1][index] + inputValues[2][index] + inputValues[3][index] * 2)/4.0;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// An envelope is comprised of two moving averages. One moving
|
|||
|
/// average is shifted upward and the second moving average
|
|||
|
/// is shifted downward. Envelopes define the upper and lower
|
|||
|
/// boundaries of a security's normal trading range. A sell
|
|||
|
/// signal is generated when the security reaches the upper
|
|||
|
/// band whereas a buy signal is generated at the lower band.
|
|||
|
/// The optimum percentage shift depends on the volatility of
|
|||
|
/// the security--the more volatile, the larger the percentage.
|
|||
|
/// The logic behind envelopes is that overzealous buyers and
|
|||
|
/// sellers push the price to the extremes (i.e., the upper
|
|||
|
/// and lower bands), at which point the prices often stabilize
|
|||
|
/// by moving to more realistic levels. This is similar to the
|
|||
|
/// interpretation of Bollinger Bands.
|
|||
|
/// ---------------------------------------------------------
|
|||
|
/// Input:
|
|||
|
/// - 1 Y value.
|
|||
|
/// Output:
|
|||
|
/// - 2 Y values (Envelope Hi and Low).
|
|||
|
/// Parameters:
|
|||
|
/// - period
|
|||
|
/// - shift in percentages
|
|||
|
/// Extra Parameters:
|
|||
|
/// - startFromFirst
|
|||
|
///
|
|||
|
/// </summary>
|
|||
|
/// <param name="inputValues">Arrays of doubles: 1. row - X values, 2. row - Y values</param>
|
|||
|
/// <param name="outputValues">Arrays of doubles: 1. row - X values, 2. row - Envelopes Up, 3. row - Envelopes Down</param>
|
|||
|
/// <param name="parameterList">Array of strings: parameters</param>
|
|||
|
/// <param name="extraParameterList">Array of strings: Extra parameters </param>
|
|||
|
private void Envelopes(double [][] inputValues, out double [][] outputValues, string [] parameterList, string [] extraParameterList)
|
|||
|
{
|
|||
|
int length = inputValues.Length;
|
|||
|
|
|||
|
// Period for moving average
|
|||
|
int period;
|
|||
|
try
|
|||
|
{period = int.Parse( parameterList[0], System.Globalization.CultureInfo.InvariantCulture );}
|
|||
|
catch( Exception e )
|
|||
|
{
|
|||
|
if (e.Message == SR.ExceptionObjectReferenceIsNull)
|
|||
|
throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing);
|
|||
|
else
|
|||
|
throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing + e.Message);
|
|||
|
}
|
|||
|
|
|||
|
if( period <= 0 )
|
|||
|
throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
|
|||
|
|
|||
|
// Shift
|
|||
|
double shift;
|
|||
|
try
|
|||
|
{shift = double.Parse( parameterList[1], System.Globalization.CultureInfo.InvariantCulture );}
|
|||
|
catch(System.Exception)
|
|||
|
{ throw new InvalidOperationException(SR.ExceptionPriceIndicatorsShiftParameterMissing); }
|
|||
|
|
|||
|
// There is no enough series
|
|||
|
if( length != 2 )
|
|||
|
throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
|
|||
|
|
|||
|
// Different number of x and y values
|
|||
|
if( inputValues[0].Length != inputValues[1].Length )
|
|||
|
throw new ArgumentException(SR.ExceptionPriceIndicatorsSameXYNumber);
|
|||
|
|
|||
|
double [][] movingAverage;
|
|||
|
|
|||
|
MovingAverage( inputValues, out movingAverage, parameterList, extraParameterList );
|
|||
|
|
|||
|
outputValues = new double[3][];
|
|||
|
outputValues[0] = new double[movingAverage[0].Length];
|
|||
|
outputValues[1] = new double[movingAverage[0].Length];
|
|||
|
outputValues[2] = new double[movingAverage[0].Length];
|
|||
|
|
|||
|
for( int index = 0; index < movingAverage[0].Length; index++ )
|
|||
|
{
|
|||
|
outputValues[0][index] = movingAverage[0][index];
|
|||
|
outputValues[1][index] = movingAverage[1][index] + shift*movingAverage[1][index]/100.0;
|
|||
|
outputValues[2][index] = movingAverage[1][index] - shift*movingAverage[1][index]/100.0;
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Standard Deviation is a statistical measure of volatility.
|
|||
|
/// Standard Deviation is typically used as a component of
|
|||
|
/// other indicators, rather than as a stand-alone indicator.
|
|||
|
/// For example, Bollinger Bands are calculated by adding
|
|||
|
/// a security's Standard Deviation to a moving average.
|
|||
|
/// High Standard Deviation values occur when the data item
|
|||
|
/// being analyzed (e.g., prices or an indicator) is changing
|
|||
|
/// dramatically. Similarly, low Standard Deviation values
|
|||
|
/// occur when prices are stable.
|
|||
|
/// </summary>
|
|||
|
/// <param name="inputValues">Input Y values</param>
|
|||
|
/// <param name="outputValues">Output standard deviation</param>
|
|||
|
/// <param name="period">Period</param>
|
|||
|
/// <param name="startFromFirst">Start calculation from the first Y value</param>
|
|||
|
internal void StandardDeviation(double [] inputValues, out double [] outputValues, int period, bool startFromFirst )
|
|||
|
{
|
|||
|
double [] movingOut;
|
|||
|
|
|||
|
// Start calculation from the first Y value
|
|||
|
if( startFromFirst )
|
|||
|
{
|
|||
|
outputValues = new double[inputValues.Length];
|
|||
|
double sum;
|
|||
|
MovingAverage( inputValues, out movingOut, period, startFromFirst );
|
|||
|
int outIndex = 0;
|
|||
|
for( int index = 0; index < inputValues.Length; index++ )
|
|||
|
{
|
|||
|
sum = 0;
|
|||
|
int startSum = 0;
|
|||
|
|
|||
|
// Find the begining of the period
|
|||
|
if( index - period + 1 > 0 )
|
|||
|
{
|
|||
|
startSum = index - period + 1;
|
|||
|
}
|
|||
|
for( int indexDev = startSum; indexDev <= index; indexDev++ )
|
|||
|
{
|
|||
|
sum += (inputValues[indexDev] - movingOut[outIndex])*(inputValues[indexDev] - movingOut[outIndex]);
|
|||
|
}
|
|||
|
outputValues[outIndex] = Math.Sqrt( sum / period );
|
|||
|
outIndex++;
|
|||
|
}
|
|||
|
}
|
|||
|
// Do not start calculation from the first Y value
|
|||
|
else
|
|||
|
{
|
|||
|
outputValues = new double[inputValues.Length - period + 1];
|
|||
|
double sum;
|
|||
|
MovingAverage( inputValues, out movingOut, period, startFromFirst );
|
|||
|
int outIndex = 0;
|
|||
|
for( int index = period - 1; index < inputValues.Length; index++ )
|
|||
|
{
|
|||
|
sum = 0;
|
|||
|
for( int indexDev = index - period + 1; indexDev <= index; indexDev++ )
|
|||
|
{
|
|||
|
sum += (inputValues[indexDev] - movingOut[outIndex])*(inputValues[indexDev] - movingOut[outIndex]);
|
|||
|
}
|
|||
|
outputValues[outIndex] = Math.Sqrt( sum / period );
|
|||
|
outIndex++;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
|
|||
|
#region Methods
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Default constructor
|
|||
|
/// </summary>
|
|||
|
public PriceIndicators()
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// This methods checks the number of X and Y values and
|
|||
|
/// fire exception if the numbers are different.
|
|||
|
/// </summary>
|
|||
|
/// <param name="inputValues">Input X and Y values</param>
|
|||
|
/// <param name="numOfYValues">The number of Y values</param>
|
|||
|
public void CheckNumOfValues( double [][] inputValues, int numOfYValues )
|
|||
|
{
|
|||
|
// Different number of x and y values
|
|||
|
if( inputValues[0].Length != inputValues[1].Length )
|
|||
|
{
|
|||
|
throw new ArgumentException(SR.ExceptionPriceIndicatorsSameXYNumber);
|
|||
|
}
|
|||
|
|
|||
|
// Different number of y values
|
|||
|
for( int index = 1; index < numOfYValues; index++ )
|
|||
|
{
|
|||
|
if( inputValues[index].Length != inputValues[index+1].Length )
|
|||
|
{
|
|||
|
throw new ArgumentException( SR.ExceptionPriceIndicatorsSameYNumber );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// The first method in the module, which converts a formula
|
|||
|
/// name to the corresponding private method.
|
|||
|
/// </summary>
|
|||
|
/// <param name="formulaName">String which represent a formula name</param>
|
|||
|
/// <param name="inputValues">Arrays of doubles - Input values</param>
|
|||
|
/// <param name="outputValues">Arrays of doubles - Output values</param>
|
|||
|
/// <param name="parameterList">Array of strings - Formula parameters</param>
|
|||
|
/// <param name="extraParameterList">Array of strings - Extra Formula parameters from DataManipulator object</param>
|
|||
|
/// <param name="outLabels">Array of strings - Used for Labels. Description for output results.</param>
|
|||
|
virtual public void Formula( string formulaName, double [][] inputValues, out double [][] outputValues, string [] parameterList, string [] extraParameterList, out string [][] outLabels )
|
|||
|
{
|
|||
|
string name;
|
|||
|
|
|||
|
name = formulaName.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
|
|||
|
|
|||
|
// Not used for these formulas.
|
|||
|
outLabels = null;
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
switch( name )
|
|||
|
{
|
|||
|
case "MOVINGAVERAGE":
|
|||
|
MovingAverage( inputValues, out outputValues, parameterList, extraParameterList );
|
|||
|
break;
|
|||
|
case "EXPONENTIALMOVINGAVERAGE":
|
|||
|
ExponentialMovingAverage( inputValues, out outputValues, parameterList, extraParameterList );
|
|||
|
break;
|
|||
|
case "TRIANGULARMOVINGAVERAGE":
|
|||
|
TriangularMovingAverage( inputValues, out outputValues, parameterList, extraParameterList );
|
|||
|
break;
|
|||
|
case "WEIGHTEDMOVINGAVERAGE":
|
|||
|
WeightedMovingAverage( inputValues, out outputValues, parameterList, extraParameterList );
|
|||
|
break;
|
|||
|
case "BOLLINGERBANDS":
|
|||
|
BollingerBands( inputValues, out outputValues, parameterList, extraParameterList );
|
|||
|
break;
|
|||
|
case "MEDIANPRICE":
|
|||
|
MedianPrice( inputValues, out outputValues );
|
|||
|
break;
|
|||
|
case "TYPICALPRICE":
|
|||
|
TypicalPrice( inputValues, out outputValues );
|
|||
|
break;
|
|||
|
case "WEIGHTEDCLOSE":
|
|||
|
WeightedClose( inputValues, out outputValues );
|
|||
|
break;
|
|||
|
case "ENVELOPES":
|
|||
|
Envelopes( inputValues, out outputValues, parameterList, extraParameterList );
|
|||
|
break;
|
|||
|
default:
|
|||
|
outputValues = null;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
catch( IndexOutOfRangeException )
|
|||
|
{
|
|||
|
throw new InvalidOperationException(SR.ExceptionFormulaInvalidPeriod( name ) );
|
|||
|
}
|
|||
|
catch( OverflowException )
|
|||
|
{
|
|||
|
throw new InvalidOperationException( SR.ExceptionFormulaNotEnoughDataPoints( name ) );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#endregion
|
|||
|
}
|
|||
|
}
|