536cd135cc
Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
687 lines
25 KiB
C#
687 lines
25 KiB
C#
//-------------------------------------------------------------
|
||
// <copyright company=’Microsoft Corporation’>
|
||
// Copyright © Microsoft Corporation. All Rights Reserved.
|
||
// </copyright>
|
||
//-------------------------------------------------------------
|
||
// @owner=alexgor, deliant
|
||
//=================================================================
|
||
// File: Oscillator.cs
|
||
//
|
||
// Namespace: System.Web.UI.WebControls[Windows.Forms].Charting.Formulas
|
||
//
|
||
// Classes: Oscillators
|
||
//
|
||
// Purpose: This class is used to calculate oscillator
|
||
// indicators used in Technical Analyses.
|
||
//
|
||
// Reviewed: GS - August 7, 2002
|
||
// AG - August 7, 2002
|
||
//
|
||
//===================================================================
|
||
|
||
|
||
using System;
|
||
using System.Globalization;
|
||
|
||
|
||
#if Microsoft_CONTROL
|
||
namespace System.Windows.Forms.DataVisualization.Charting.Formulas
|
||
#else
|
||
namespace System.Web.UI.DataVisualization.Charting.Formulas
|
||
#endif
|
||
{
|
||
/// <summary>
|
||
/// This class is used to calculate oscillator
|
||
/// indicators used in Technical Analyses.
|
||
/// </summary>
|
||
internal class Oscillators : PriceIndicators
|
||
{
|
||
#region Properties
|
||
|
||
/// <summary>
|
||
/// Formula Module name
|
||
/// </summary>
|
||
override public string Name { get{ return "Oscillators";}}
|
||
|
||
#endregion
|
||
|
||
#region Formulas
|
||
|
||
/// <summary>
|
||
/// The Chaikin Oscillator is created by subtracting a 10 period
|
||
/// exponential moving average of the Accumulation/Distribution
|
||
/// line from a 3 period moving average of the
|
||
/// Accumulation/Distribution Line.
|
||
/// ---------------------------------------------------------
|
||
/// Input:
|
||
/// - 4 Y values ( Hi, Low, Close, Volume ).
|
||
/// Output:
|
||
/// - 1 Y value Chaikin Oscillator
|
||
/// Parameters:
|
||
/// - Short Period for Exponential Moving average (default=3)
|
||
/// - Int64 Period for Exponential Moving average (default=10)
|
||
/// Extra Parameters:
|
||
/// - Start from First
|
||
/// </summary>
|
||
/// <param name="inputValues">Arrays of doubles - Input values</param>
|
||
/// <param name="outputValues">Arrays of doubles - Output values</param>
|
||
/// <param name="parameterList">Array of strings - Parameters</param>
|
||
/// <param name="extraParameterList">Array of strings - Extra parameters</param>
|
||
private void ChaikinOscillator(double [][] inputValues, out double [][] outputValues, string [] parameterList, string [] extraParameterList)
|
||
{
|
||
// There is no enough input series
|
||
if( inputValues.Length != 5 )
|
||
{
|
||
throw new ArgumentException( SR.ExceptionPriceIndicatorsFormulaRequiresFourArrays);
|
||
}
|
||
|
||
// Different number of x and y values
|
||
CheckNumOfValues( inputValues, 4 );
|
||
|
||
// Short Period for Exp moving average
|
||
int shortPeriod;
|
||
if (parameterList.Length < 1 ||
|
||
!int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out shortPeriod))
|
||
{
|
||
shortPeriod = 3;
|
||
}
|
||
|
||
// Int64 Period for Exp moving average
|
||
int longPeriod;
|
||
if (parameterList.Length < 2 ||
|
||
!int.TryParse(parameterList[1], NumberStyles.Any, CultureInfo.InvariantCulture, out longPeriod))
|
||
{
|
||
longPeriod = 10;
|
||
}
|
||
|
||
if( shortPeriod > longPeriod || longPeriod <= 0 || shortPeriod <= 0 )
|
||
{
|
||
throw new ArgumentException(SR.ExceptionOscillatorObjectInvalidPeriod);
|
||
}
|
||
|
||
// Starting average from the first data point or after period.
|
||
bool startFromFirst = bool.Parse( extraParameterList[0] );
|
||
|
||
VolumeIndicators volume = new VolumeIndicators();
|
||
|
||
double [][] outputDistribution = new double [2][];
|
||
|
||
// Accumulation Distribution
|
||
volume.AccumulationDistribution( inputValues, out outputDistribution );
|
||
|
||
double [] ExpAvgDistribution;
|
||
|
||
// Exponential Moving average of Accumulation Distribution
|
||
ExponentialMovingAverage(outputDistribution[1],out ExpAvgDistribution,longPeriod,startFromFirst);
|
||
|
||
double [] ExpAvg;
|
||
|
||
// Exponential Moving average of close
|
||
ExponentialMovingAverage(outputDistribution[1],out ExpAvg,shortPeriod,startFromFirst);
|
||
|
||
outputValues = new double [2][];
|
||
|
||
int period = Math.Min(ExpAvg.Length,ExpAvgDistribution.Length);
|
||
|
||
outputValues[0] = new double [period];
|
||
outputValues[1] = new double [period];
|
||
|
||
// Accumulation Distribution
|
||
int expIndex = 0;
|
||
for( int index = inputValues[1].Length - period; index < inputValues[1].Length; index++ )
|
||
{
|
||
// Set X values
|
||
outputValues[0][expIndex] = inputValues[0][index];
|
||
|
||
// Set Y values
|
||
if(startFromFirst)
|
||
{
|
||
// Number of items in all arays is the same and they are aligned by time.
|
||
outputValues[1][expIndex] = ExpAvg[expIndex] - ExpAvgDistribution[expIndex];
|
||
}
|
||
else if( (expIndex + longPeriod - shortPeriod) < ExpAvg.Length)
|
||
{
|
||
// Number of items in MovingAverages arrays is different and requires adjustment.
|
||
outputValues[1][expIndex] = ExpAvg[expIndex + longPeriod - shortPeriod] - ExpAvgDistribution[expIndex];
|
||
}
|
||
else
|
||
{
|
||
outputValues[1][expIndex] = Double.NaN;
|
||
}
|
||
expIndex++;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// The Detrended Price Oscillator ("DPO") attempts to
|
||
/// eliminate the trend in prices. Detrended prices allow
|
||
/// you to more easily identify cycles and overbought/oversold
|
||
/// levels. To calculate the DPO, you specify a time period.
|
||
/// Cycles longer than this time period are removed from
|
||
/// prices, leaving the shorter-term cycles.
|
||
/// ---------------------------------------------------------
|
||
/// Input:
|
||
/// - 1 Y value ( Close ).
|
||
/// Output:
|
||
/// - 1 Y value Detrended Price Oscillator
|
||
/// Parameters:
|
||
/// - Period
|
||
/// </summary>
|
||
/// <param name="inputValues">Arrays of doubles - Input values</param>
|
||
/// <param name="outputValues">Arrays of doubles - Output values</param>
|
||
/// <param name="parameterList">Array of strings - Parameters</param>
|
||
private void DetrendedPriceOscillator(double [][] inputValues, out double [][] outputValues, string [] parameterList)
|
||
{
|
||
// There is no enough input series
|
||
if( inputValues.Length != 2 )
|
||
{
|
||
throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
|
||
}
|
||
|
||
// Different number of x and y values
|
||
CheckNumOfValues( inputValues, 1 );
|
||
|
||
// Short Period for Exp 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);
|
||
|
||
double [] outputAverage;
|
||
|
||
// Moving Average
|
||
MovingAverage( inputValues[1], out outputAverage, period, false );
|
||
|
||
outputValues = new double [2][];
|
||
|
||
outputValues[0] = new double [inputValues[0].Length - period*3/2];
|
||
outputValues[1] = new double [inputValues[1].Length - period*3/2];
|
||
|
||
// Detrended Price Oscillator
|
||
for( int index = 0; index < outputValues[1].Length; index++ )
|
||
{
|
||
// Set X values
|
||
outputValues[0][index] = inputValues[0][index + period + period/2];
|
||
|
||
// Set Y values
|
||
outputValues[1][index] = inputValues[1][index + period + period/2] - outputAverage[index];
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Chaikin's Volatility indicator compares the spread
|
||
/// between a security's high and low prices.
|
||
/// It quantifies volatility as a widening of the range
|
||
/// between the high and the low price. There are two ways
|
||
/// to interpret this measure of volatility. One method
|
||
/// assumes that market tops are generally accompanied by
|
||
/// increased volatility (as investors get nervous and
|
||
/// indecisive) and that the latter stages of a market
|
||
/// bottom are generally accompanied by decreased volatility
|
||
/// (as investors get bored). Another method (Mr. Chaikin's)
|
||
/// assumes that an increase in the Volatility indicator over
|
||
/// a relatively short time period indicates that a bottom is
|
||
/// near (e.g., a panic sell-off) and that a decrease in
|
||
/// volatility over a longer time period indicates an
|
||
/// approaching top (e.g., a mature bull market). As with
|
||
/// almost all experienced investors, Mr. Chaikin recommends
|
||
/// that you do not rely on any one indicator. He suggests
|
||
/// using a moving average ----ion or trading band system
|
||
/// to confirm this (or any) indicator.
|
||
/// ---------------------------------------------------------
|
||
/// Input:
|
||
/// - 2 Y values ( Hi, Low ).
|
||
/// Output:
|
||
/// - 1 Y value Volatility Chaikins
|
||
/// Parameters:
|
||
/// - Periods (default 10)- is used to specify the Shift days, By default this property is set to 10.
|
||
/// - SignalPeriod (default 10)- is used to calculate Exponential Moving Avg of the Signal line, By default this property is set to 10.
|
||
/// </summary>
|
||
/// <param name="inputValues">Arrays of doubles - Input values</param>
|
||
/// <param name="outputValues">Arrays of doubles - Output values</param>
|
||
/// <param name="parameterList">Array of strings - Parameters</param>
|
||
private void VolatilityChaikins(double [][] inputValues, out double [][] outputValues, string [] parameterList)
|
||
{
|
||
// There is no enough input series
|
||
if( inputValues.Length != 3 )
|
||
{
|
||
throw new ArgumentException( SR.ExceptionPriceIndicatorsFormulaRequiresTwoArrays);
|
||
}
|
||
|
||
// Different number of x and y values
|
||
CheckNumOfValues( inputValues, 2 );
|
||
|
||
// Period
|
||
int period;
|
||
if (parameterList.Length < 1 ||
|
||
!int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out period))
|
||
{
|
||
period = 10;
|
||
}
|
||
|
||
if( period <= 0 )
|
||
throw new InvalidOperationException(SR.ExceptionOscillatorNegativePeriodParameter);
|
||
|
||
// Signal Period for Exp moving average
|
||
int signalPeriod;
|
||
if (parameterList.Length < 2 ||
|
||
!int.TryParse(parameterList[1], NumberStyles.Any, CultureInfo.InvariantCulture, out signalPeriod))
|
||
{
|
||
signalPeriod = 10;
|
||
}
|
||
|
||
if( signalPeriod <= 0 )
|
||
throw new InvalidOperationException(SR.ExceptionOscillatorNegativeSignalPeriod);
|
||
|
||
double [] outputAverage;
|
||
|
||
double [] hiLowInput = new double[inputValues[1].Length];
|
||
|
||
// Find Hi - Low
|
||
for( int index = 0; index < inputValues[1].Length; index++ )
|
||
{
|
||
hiLowInput[index] = inputValues[1][index] - inputValues[2][index];
|
||
}
|
||
|
||
// Exponential Moving Average
|
||
ExponentialMovingAverage( hiLowInput, out outputAverage, signalPeriod, false );
|
||
|
||
outputValues = new double [2][];
|
||
|
||
outputValues[0] = new double [outputAverage.Length - period];
|
||
outputValues[1] = new double [outputAverage.Length - period];
|
||
|
||
// Volatility Chaikins
|
||
for( int index = 0; index < outputValues[1].Length; index++ )
|
||
{
|
||
// Set X values
|
||
outputValues[0][index] = inputValues[0][index + period + signalPeriod - 1];
|
||
|
||
// Set Y values
|
||
if( outputAverage[index] != 0.0 )
|
||
outputValues[1][index] = ( outputAverage[index + period] - outputAverage[index] ) / outputAverage[index] * 100.0;
|
||
else
|
||
// Div with zero error.
|
||
outputValues[1][index] = 0.0;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// The Volume Oscillator displays the difference between two
|
||
/// moving averages of a security's volume. The difference
|
||
/// between the moving averages can be expressed in either
|
||
/// points or percentages. You can use the difference between
|
||
/// two moving averages of volume to determine if the overall
|
||
/// volume trend is increasing or decreasing. When the Volume
|
||
/// Oscillator rises above zero, it signifies that the
|
||
/// shorter-term volume moving average has risen above
|
||
/// the longer-term volume moving average, and thus, that
|
||
/// the short-term volume trend is higher (i.e., more volume)
|
||
/// than the longer-term volume trend.
|
||
/// ---------------------------------------------------------
|
||
/// Input:
|
||
/// - 1 Y values ( Volume ).
|
||
/// Output:
|
||
/// - 1 Y value VolumeOscillator
|
||
/// Parameters:
|
||
/// - ShortPeriod (Default 5)= is used to configure the short period.
|
||
/// - LongPeriod (Default 10)= is used to configure the Int64 period.
|
||
/// - Percentage (Default true)= The Volume Oscillator can display the difference between the two moving averages as either points or percentages.
|
||
/// </summary>
|
||
/// <param name="inputValues">Arrays of doubles - Input values</param>
|
||
/// <param name="outputValues">Arrays of doubles - Output values</param>
|
||
/// <param name="parameterList">Array of strings - Parameters</param>
|
||
private void VolumeOscillator(double [][] inputValues, out double [][] outputValues, string [] parameterList)
|
||
{
|
||
// There is no enough input series
|
||
if( inputValues.Length != 2 )
|
||
{
|
||
throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
|
||
}
|
||
|
||
// Different number of x and y values
|
||
CheckNumOfValues( inputValues, 1 );
|
||
|
||
// Short Period
|
||
int shortPeriod;
|
||
if (parameterList.Length < 1 ||
|
||
!int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out shortPeriod))
|
||
{
|
||
shortPeriod = 5;
|
||
}
|
||
|
||
// Int64 Period
|
||
int longPeriod;
|
||
if (parameterList.Length < 2 ||
|
||
!int.TryParse(parameterList[1], NumberStyles.Any, CultureInfo.InvariantCulture, out longPeriod))
|
||
{
|
||
longPeriod = 10;
|
||
}
|
||
|
||
if( shortPeriod > longPeriod || longPeriod <= 0 || shortPeriod <= 0 )
|
||
throw new ArgumentException(SR.ExceptionOscillatorObjectInvalidPeriod);
|
||
|
||
// percentage
|
||
bool percentage;
|
||
if (parameterList.Length < 3 ||
|
||
!bool.TryParse(parameterList[2], out percentage))
|
||
{
|
||
percentage = true;
|
||
}
|
||
|
||
double [] shortAverage;
|
||
double [] longAverage;
|
||
|
||
// Find Short moving average
|
||
MovingAverage( inputValues[1], out shortAverage, shortPeriod, false );
|
||
|
||
// Find Int64 moving average
|
||
MovingAverage( inputValues[1], out longAverage, longPeriod, false );
|
||
|
||
outputValues = new double [2][];
|
||
|
||
outputValues[0] = new double [longAverage.Length];
|
||
outputValues[1] = new double [longAverage.Length];
|
||
|
||
// Volume Oscillator
|
||
for( int index = 0; index < longAverage.Length; index++ )
|
||
{
|
||
// Set X values
|
||
outputValues[0][index] = inputValues[0][index + longPeriod-1];
|
||
|
||
// Set Y values
|
||
outputValues[1][index] = shortAverage[index + shortPeriod] - longAverage[index];
|
||
|
||
// RecalculateAxesScale difference in %
|
||
if( percentage )
|
||
{
|
||
// Div by zero error.
|
||
if( longAverage[index] == 0.0 )
|
||
outputValues[1][index]=0.0;
|
||
else
|
||
outputValues[1][index] = outputValues[1][index] / shortAverage[index + shortPeriod] * 100;
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// The Stochastic Indicator is based on the observation that
|
||
/// as prices increase, closing prices tend to accumulate ever
|
||
/// closer to the highs for the period. Conversely, as prices
|
||
/// decrease, closing prices tend to accumulate ever closer to
|
||
/// the lows for the period. Trading decisions are made with
|
||
/// respect to divergence between % of "D" (one of the two
|
||
/// lines generated by the study) and the item's price. For
|
||
/// example, when a commodity or stock makes a high, reacts,
|
||
/// and subsequently moves to a higher high while corresponding
|
||
/// peaks on the % of "D" line make a high and then a lower
|
||
/// high, a bearish divergence is indicated. When a commodity
|
||
/// or stock has established a new low, reacts, and moves to a
|
||
/// lower low while the corresponding low points on the % of
|
||
/// "D" line make a low and then a higher low, a bullish
|
||
/// divergence is indicated. Traders act upon this divergence
|
||
/// when the other line generated by the study (K) crosses on
|
||
/// the right-hand side of the peak of the % of "D" line in the
|
||
/// case of a top, or on the right-hand side of the low point
|
||
/// of the % of "D" line in the case of a bottom. The Stochastic
|
||
/// Oscillator is displayed as two lines. The main line is
|
||
/// called "%K." The second line, called "%D," is a moving
|
||
/// average of %K.
|
||
/// ---------------------------------------------------------
|
||
/// Input:
|
||
/// - 3 Y values ( Hi, Low, Close ).
|
||
/// Output:
|
||
/// - 2 Y value ( %K, %D )
|
||
/// Parameters:
|
||
/// - PeriodD (Default 10) = is used for %D calculation as SMA of %K.
|
||
/// - PeriodK (Default 10) = is used to calculate %K.
|
||
/// </summary>
|
||
/// <param name="inputValues">Arrays of doubles - Input values</param>
|
||
/// <param name="outputValues">Arrays of doubles - Output values</param>
|
||
/// <param name="parameterList">Array of strings - Parameters</param>
|
||
internal void StochasticIndicator(double [][] inputValues, out double [][] outputValues, string [] parameterList)
|
||
{
|
||
// There is no enough input series
|
||
if( inputValues.Length != 4 )
|
||
{
|
||
throw new ArgumentException( SR.ExceptionPriceIndicatorsFormulaRequiresThreeArrays);
|
||
}
|
||
|
||
// Different number of x and y values
|
||
CheckNumOfValues( inputValues, 3 );
|
||
|
||
// PeriodD for moving average
|
||
int periodD;
|
||
if (parameterList.Length < 2 ||
|
||
!int.TryParse(parameterList[1], NumberStyles.Any, CultureInfo.InvariantCulture, out periodD))
|
||
{
|
||
periodD = 10;
|
||
}
|
||
|
||
if( periodD <= 0 )
|
||
throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
|
||
|
||
// PeriodK for moving average
|
||
int periodK;
|
||
if (parameterList.Length < 1 ||
|
||
!int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out periodK))
|
||
{
|
||
periodK = 10;
|
||
}
|
||
|
||
if( periodK <= 0 )
|
||
throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
|
||
|
||
// Output arrays
|
||
outputValues = new double [3][];
|
||
|
||
// X
|
||
outputValues[0] = new double [inputValues[0].Length - periodK - periodD + 2];
|
||
|
||
// K%
|
||
outputValues[1] = new double [inputValues[0].Length - periodK - periodD + 2];
|
||
|
||
// D%
|
||
outputValues[2] = new double [inputValues[0].Length - periodK - periodD + 2];
|
||
|
||
double [] K = new double [inputValues[0].Length - periodK + 1];
|
||
|
||
// Find K%
|
||
for( int index = periodK - 1; index < inputValues[0].Length; index++ )
|
||
{
|
||
// Find Lowest Low and Highest High
|
||
double minLow = double.MaxValue;
|
||
double maxHi = double.MinValue;
|
||
for( int indexHL = index - periodK + 1; indexHL <= index; indexHL++ )
|
||
{
|
||
if( minLow > inputValues[2][indexHL] )
|
||
minLow = inputValues[2][indexHL];
|
||
|
||
if( maxHi < inputValues[1][indexHL] )
|
||
maxHi = inputValues[1][indexHL];
|
||
}
|
||
// Find K%
|
||
K[index - periodK + 1] = ( inputValues[3][index] - minLow ) / ( maxHi - minLow ) * 100;
|
||
|
||
// Set X and Y K output
|
||
if( index >= periodK + periodD - 2 )
|
||
{
|
||
outputValues[0][index - periodK - periodD + 2] = inputValues[0][index];
|
||
outputValues[1][index - periodK - periodD + 2] = K[index - periodK + 1];
|
||
}
|
||
}
|
||
|
||
// Find D%
|
||
MovingAverage( K, out outputValues[2], periodD, false );
|
||
}
|
||
|
||
/// <summary>
|
||
/// Williams’ %R (pronounced "percent R") is a momentum
|
||
/// indicator that measures overbought/oversold levels.
|
||
/// Williams’ %R was developed by Larry Williams. The
|
||
/// interpretation of Williams' %R is very similar to that
|
||
/// of the Stochastic Oscillator except that %R is plotted
|
||
/// upside-down and the Stochastic Oscillator has internal
|
||
/// smoothing. To display the Williams’ %R indicator on an
|
||
/// upside-down scale, it is usually plotted using negative
|
||
/// values (e.g., -20%). Readings in the range of 80 to 100%
|
||
/// indicate that the security is oversold while readings in
|
||
/// the 0 to 20% range suggest that it is overbought.
|
||
/// As with all overbought/oversold indicators, it is best to
|
||
/// wait for the security's price to change direction before
|
||
/// placing your trades. For example, if an overbought/oversold
|
||
/// indicator (such as the Stochastic Oscillator or Williams'
|
||
/// %R) is showing an overbought condition, it is wise to wait
|
||
/// for the security's price to turn down before selling the
|
||
/// security. (The MovingAverageConvergenceDivergence is a good indicator to monitor change
|
||
/// in a security's price.) It is not unusual for
|
||
/// overbought/oversold indicators to remain in an
|
||
/// overbought/oversold condition for a long time period as
|
||
/// the security's price continues to climb/fall. Selling
|
||
/// simply because the security appears overbought may take
|
||
/// you out of the security long before its price shows signs
|
||
/// of deterioration.
|
||
/// ---------------------------------------------------------
|
||
/// Input:
|
||
/// - 3 Y values ( Hi, Low, Close ).
|
||
/// Output:
|
||
/// - 2 Y value ( %R )
|
||
/// Parameters:
|
||
/// - Period (Default 14) = is used to configure the number of periods to calculate the WilliamsR
|
||
/// </summary>
|
||
/// <param name="inputValues">Arrays of doubles - Input values</param>
|
||
/// <param name="outputValues">Arrays of doubles - Output values</param>
|
||
/// <param name="parameterList">Array of strings - Parameters</param>
|
||
internal void WilliamsR(double [][] inputValues, out double [][] outputValues, string [] parameterList)
|
||
{
|
||
// There is no enough input series
|
||
if( inputValues.Length != 4 )
|
||
throw new ArgumentException( SR.ExceptionPriceIndicatorsFormulaRequiresThreeArrays);
|
||
|
||
// Different number of x and y values
|
||
CheckNumOfValues( inputValues, 3 );
|
||
|
||
// PeriodD for moving average
|
||
int period;
|
||
if (parameterList.Length < 1 ||
|
||
!int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out period))
|
||
{
|
||
period = 14;
|
||
}
|
||
|
||
if( period <= 0 )
|
||
throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
|
||
|
||
// Output arrays
|
||
outputValues = new double [2][];
|
||
|
||
// X
|
||
outputValues[0] = new double [inputValues[0].Length - period + 1];
|
||
|
||
// R%
|
||
outputValues[1] = new double [inputValues[0].Length - period + 1];
|
||
|
||
// Find R%
|
||
for( int index = period - 1; index < inputValues[0].Length; index++ )
|
||
{
|
||
// Find Lowest Low and Highest High
|
||
double minLow = double.MaxValue;
|
||
double maxHi = double.MinValue;
|
||
for( int indexHL = index - period + 1; indexHL <= index; indexHL++ )
|
||
{
|
||
if( minLow > inputValues[2][indexHL] )
|
||
minLow = inputValues[2][indexHL];
|
||
|
||
if( maxHi < inputValues[1][indexHL] )
|
||
maxHi = inputValues[1][indexHL];
|
||
}
|
||
// Set X value
|
||
outputValues[0][index - period + 1] = inputValues[0][index];
|
||
|
||
// Find R%
|
||
outputValues[1][index - period + 1] = ( maxHi - inputValues[3][index] ) / ( maxHi - minLow ) * (-100.0);
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
#region Methods
|
||
|
||
/// <summary>
|
||
/// Constructor
|
||
/// </summary>
|
||
public Oscillators()
|
||
{
|
||
}
|
||
|
||
|
||
/// <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>
|
||
override public void Formula( string formulaName, double [][] inputValues, out double [][] outputValues, string [] parameterList, string [] extraParameterList, out string [][] outLabels )
|
||
{
|
||
string name;
|
||
outputValues = null;
|
||
|
||
// Not used for these formulas.
|
||
outLabels = null;
|
||
|
||
name = formulaName.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
|
||
try
|
||
{
|
||
switch( name )
|
||
{
|
||
case "STOCHASTICINDICATOR":
|
||
StochasticIndicator( inputValues, out outputValues, parameterList );
|
||
break;
|
||
case "CHAIKINOSCILLATOR":
|
||
ChaikinOscillator( inputValues, out outputValues, parameterList, extraParameterList );
|
||
break;
|
||
case "DETRENDEDPRICEOSCILLATOR":
|
||
DetrendedPriceOscillator( inputValues, out outputValues, parameterList );
|
||
break;
|
||
case "VOLATILITYCHAIKINS":
|
||
VolatilityChaikins( inputValues, out outputValues, parameterList );
|
||
break;
|
||
case "VOLUMEOSCILLATOR":
|
||
VolumeOscillator( inputValues, out outputValues, parameterList );
|
||
break;
|
||
case "WILLIAMSR":
|
||
WilliamsR( inputValues, out outputValues, parameterList );
|
||
break;
|
||
default:
|
||
outputValues = null;
|
||
break;
|
||
}
|
||
}
|
||
catch( IndexOutOfRangeException )
|
||
{
|
||
throw new InvalidOperationException( SR.ExceptionFormulaInvalidPeriod( name ) );
|
||
}
|
||
catch( OverflowException )
|
||
{
|
||
throw new InvalidOperationException( SR.ExceptionFormulaNotEnoughDataPoints( name ) );
|
||
}
|
||
}
|
||
|
||
#endregion
|
||
|
||
}
|
||
}
|