687 lines
25 KiB
C#
687 lines
25 KiB
C#
|
//-------------------------------------------------------------
|
|||
|
// <copyright company=<3D>Microsoft Corporation<6F>>
|
|||
|
// Copyright <20> 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<6D> %R (pronounced "percent R") is a momentum
|
|||
|
/// indicator that measures overbought/oversold levels.
|
|||
|
/// Williams<6D> %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<6D> %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
|
|||
|
|
|||
|
}
|
|||
|
}
|