123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859 |
- // Licensed to the .NET Foundation under one or more agreements.
- // The .NET Foundation licenses this file to you under the MIT license.
- // See the LICENSE file in the project root for more information.
- //
- // Purpose: This class is used for calculations of
- // general technical analyses indicators.
- //
- using System;
- using System.Globalization;
- namespace FastReport.DataVisualization.Charting.Formulas
- {
- /// <summary>
- /// This class is used for calculations of general
- /// technical analyses indicators.
- /// </summary>
- internal class GeneralTechnicalIndicators : PriceIndicators
- {
- #region Properties
- /// <summary>
- /// Formula Module name
- /// </summary>
- override public string Name { get { return SR.FormulaNameGeneralTechnicalIndicators; } }
- #endregion
- #region Formulas
- /// <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.
- /// ---------------------------------------------------------
- /// Input:
- /// - 1 Y value.
- /// Output:
- /// - 1 Y value Standard Deviation
- /// Parameters:
- /// - Periods for standard deviation ( used for moving average )
- /// Extra Parameters:
- /// -
- /// </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 StandardDeviation(double [][] inputValues, out double [][] outputValues, string [] parameterList, string [] extraParameterList)
- {
- int length = inputValues.Length;
- // Period for standard deviation ( used 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 in Standard deviation.
- if( inputValues[0].Length < period )
- throw new ArgumentException(SR.ExceptionPriceIndicatorsNotEnoughPoints);
- outputValues = new double [2][];
- StandardDeviation( inputValues[1], out outputValues[1], period, startFromFirst );
- // Set X values
- outputValues[0] = new double [outputValues[1].Length];
- for( int index = 0; index < outputValues[1].Length; index++ )
- {
- if( startFromFirst )
- outputValues[0][index] = inputValues[0][index];
- else
- outputValues[0][index] = inputValues[0][index+period-1];
- }
- }
- /// <summary>
- /// The Average True Range ("ATR") is a measure of volatility. It was introduced
- /// by Welles Wilder in his book, New Concepts in Technical Trading Systems, and
- /// has since been used as a component of many indicators and trading systems. Wilder
- /// has found that high ATR values often occur at market bottoms following a "panic"
- /// sell-off. Low Average True Range values are often found during extended sideways
- /// periods, such as those found at tops and after consolidation periods. The Average
- /// True Range can be interpreted using the same techniques that are used with
- /// the other volatility indicators.
- /// ---------------------------------------------------------
- /// Input:
- /// - 3 Y values ( High, Low, Close ).
- /// Output:
- /// - 1 Y value AverageTrueRange
- /// Parameters:
- /// - Periods (Default 14) = is used to configure the number of periods to calculate the ATR
- /// </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 AverageTrueRange(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 );
-
- // Period
- 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);
- // The distance from today's high to today's low
- double distanceOne;
- // The distance from yesterday's close to today's high
- double distanceTwo;
- // The distance from yesterday's close to today's low
- double distanceTree;
- double [] trueRange = new double [inputValues[0].Length - 1];
- // True Range
- for( int index = 1; index < inputValues[0].Length; index++ )
- {
- // The distance from today's high to today's low
- distanceOne = Math.Abs( inputValues[1][index] - inputValues[2][index] );
- // The distance from yesterday's close to today's high
- distanceTwo = Math.Abs( inputValues[3][index-1] - inputValues[1][index] );
- // The distance from yesterday's close to today's low
- distanceTree = Math.Abs( inputValues[3][index-1] - inputValues[2][index] );
- // True Range
- trueRange[index-1] = Math.Max( Math.Max( distanceOne, distanceTwo ), distanceTree );
- }
- outputValues = new double [2][];
- outputValues[0] = new double [inputValues[0].Length-period];
- // Moving average of true range
- MovingAverage( trueRange, out outputValues[1], period, false );
- // Set X values
- for( int index = period; index < inputValues[0].Length; index++ )
- {
- outputValues[0][index-period] = inputValues[0][index];
- }
- }
- /// <summary>
- /// The Ease of Movement indicator shows the relationship between volume and price
- /// change. This indicator shows how much volume is required to move prices. The Ease
- /// of Movement indicator was developed Richard W. Arms, Jr., the creator of Equivolume.
- /// High Ease of Movement values occur when prices are moving upward on lightStyle volume.
- /// Low Ease of Movement values occur when prices are moving downward on lightStyle volume.
- /// If prices are not moving, or if heavy volume is required to move prices, then
- /// indicator will also be near zero.
- /// ---------------------------------------------------------
- /// Input:
- /// - 3 Y values ( High, Low, Volume ).
- /// Output:
- /// - 1 Y value Ease Of Movement
- /// </summary>
- /// <param name="inputValues">Arrays of doubles - Input values</param>
- /// <param name="outputValues">Arrays of doubles - Output values</param>
- private void EaseOfMovement(double [][] inputValues, out double [][] outputValues)
- {
- // 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 );
-
- double MidPointMove;
- double BoxRattio;
- outputValues = new double [2][];
- outputValues[0] = new double [inputValues[0].Length - 1];
- outputValues[1] = new double [inputValues[0].Length - 1];
- // Ease Of Movement
- for( int index = 1; index < inputValues[0].Length; index++ )
- {
- // Set X values
- outputValues[0][index - 1] = inputValues[0][index];
- // Calculate the Mid-point Move for each day:
- MidPointMove = ( inputValues[1][index] + inputValues[2][index] ) / 2 - ( inputValues[1][index - 1] + inputValues[2][index - 1] ) / 2;
- // The Box Ratio determines the ratio between height and width of the Equivolume box:
- BoxRattio = ( inputValues[3][index] ) / (( inputValues[1][index] - inputValues[2][index] ) );
- // Ease of Movement is then calculated as:
- outputValues[1][index - 1] = MidPointMove / BoxRattio;
- }
- }
- /// <summary>
- /// The Mass Index was designed to identify trend reversals by measuring the narrowing
- /// and widening of the range between the high and low prices. As this range widens, the
- /// Mass Index increases; as the range narrows the Mass Index decreases.
- /// The Mass Index was developed by Donald Dorsey. According to Mr. Dorsey, the most
- /// significant pattern to watch for is a "reversal bulge." A reversal bulge occurs when
- /// a 25-period Mass Index rises above 27.0 and subsequently falls below 26.5. A reversal
- /// in price is then likely. The overall price trend (i.e., trending or trading range)
- /// is unimportant.
- /// ---------------------------------------------------------
- /// Input:
- /// - 2 Y values ( High, Low ).
- /// Output:
- /// - 1 Y value Mass Index
- /// Parameters:
- /// - Period = is used to calculate the accumulation, By default this property is set to 25.
- /// - AveragePeriod = is used to calculate Simple Moving Avg, By default this property is set to 9.
- /// </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 MassIndex(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 = 25;
- }
- if( period <= 0 )
- throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
- // Average Period
- int averagePeriod;
- if (parameterList.Length < 2 ||
- !int.TryParse(parameterList[1], NumberStyles.Any, CultureInfo.InvariantCulture, out averagePeriod))
- {
- averagePeriod = 9;
- }
- if( period <= 0 )
- throw new InvalidOperationException(SR.ExceptionPeriodAverageParameterIsNegative);
-
- double [] highLow = new double [inputValues[0].Length];
- double [] average;
- double [] secondAverage;
- for( int index = 0; index < inputValues[0].Length; index++ )
- {
- highLow[index] = inputValues[1][index] - inputValues[2][index];
- }
- // Find exponential moving average
- ExponentialMovingAverage( highLow, out average, averagePeriod, false );
- // Find exponential moving average of exponential moving average
- ExponentialMovingAverage( average, out secondAverage, averagePeriod, false );
- outputValues = new double [2][];
- outputValues[0] = new double [secondAverage.Length - period + 1];
- outputValues[1] = new double [secondAverage.Length - period + 1];
- // Mass Index
- int outIndex = 0;
- double sum = 0;
- for( int index = 2 * averagePeriod - 3 + period; index < inputValues[0].Length; index++ )
- {
- // Set X values
- outputValues[0][outIndex] = inputValues[0][index];
- sum = 0;
- for( int indexSum = index - period + 1; indexSum <= index; indexSum++ )
- {
- sum += average[indexSum - averagePeriod + 1] / secondAverage[indexSum - 2 * averagePeriod + 2];
- }
- // Set Y values
- outputValues[1][outIndex] = sum;
- outIndex++;
- }
- }
- /// <summary>
- /// The Performance indicator displays a security's price performance as
- /// a percentage. This is sometimes called a "normalized" chart. The
- /// Performance indicator displays the percentage that the security
- /// has increased since the first period displayed. For example, if
- /// the Performance indicator is 10, it means that the security's
- /// price has increased 10% since the first period displayed on the
- /// left side of the chart. Similarly, a value of -10% means that
- /// the security's price has fallen by 10% since the first period
- /// displayed.
- /// ---------------------------------------------------------
- /// Input:
- /// - 1 Y value ( Close ).
- /// Output:
- /// - 1 Y value Performance
- /// </summary>
- /// <param name="inputValues">Arrays of doubles - Input values</param>
- /// <param name="outputValues">Arrays of doubles - Output values</param>
- private void Performance(double [][] inputValues, out double [][] outputValues)
- {
- // 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 );
-
- outputValues = new double [2][];
- outputValues[0] = new double [inputValues[0].Length];
- outputValues[1] = new double [inputValues[0].Length];
-
- // Performance indicator
- for( int index = 0; index < inputValues[0].Length; index++ )
- {
- // Set X values
- outputValues[0][index] = inputValues[0][index];
- // Set Y values
- outputValues[1][index] = ( inputValues[1][index] - inputValues[1][0] ) / inputValues[1][0] * 100;
- }
- }
- /// <summary>
- /// Rate of Change is used to monitor momentum by making direct comparisons between current
- /// and past prices on a continual basis. The results can be used to determine the strength
- /// of price trends. Note: This study is the same as the Momentum except that Momentum uses
- /// subtraction in its calculations while Rate of Change uses division. The resulting lines
- /// of these two studies operated over the same data will look exactly the same - only the
- /// scale values will differ. The Price Rate-of-Change indicator displays the
- /// difference between the current price and the price x-time periods ago. The difference
- /// can be displayed in either points or as a percentage. The Momentum indicator displays
- /// the same information, but expresses it as a ratio. When the Rate-of-Change displays
- /// the price change in points, it subtracts the price x-time periods ago from today’s price.
- /// When the Rate-of-Change displays the price change as a percentage, it divides
- /// the price change by price x-time period’s ago.
- /// ---------------------------------------------------------
- /// Input:
- /// - 1 Y value ( Close ).
- /// Output:
- /// - 1 Y value Rate of Change
- /// Parameters:
- /// - Periods = is used to configure the number of periods to calculate the rate of Change. By default the Periods 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 RateOfChange(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 );
-
- // 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.ExceptionPeriodParameterIsNegative);
- outputValues = new double [2][];
- outputValues[0] = new double [inputValues[0].Length - period];
- outputValues[1] = new double [inputValues[0].Length - period];
-
- // Rate Of Change
- for( int index = period; index < inputValues[0].Length; index++ )
- {
- // Set X values
- outputValues[0][index - period] = inputValues[0][index];
- // Set Y values
- outputValues[1][index - period] = ( inputValues[1][index] - inputValues[1][index - period] ) / inputValues[1][index - period] * 100;
- }
- }
- /// <summary>
- /// This indicator was developed by Welles Wilder Jr. Relative Strength is often
- /// used to identify price tops and bottoms by keying on specific levels
- /// (usually "30" and "70") on the RSI chart which is scaled from from 0-100.
- /// The study is also useful to detect the following:
- /// - Movement which might not be as readily apparent on the bar chart
- /// - Failure swings above 70 or below 30 which can warn of coming reversals
- /// - Support and resistance levels
- /// - Divergence between the RSI and price which is often a useful reversal indicator
- /// ---------------------------------------------------------
- /// Input:
- /// - 1 Y value ( Close ).
- /// Output:
- /// - 1 Y value RelativeStrengthIndex
- /// Parameters:
- /// - Periods = is used to configure the number of periods to calculate the RSI indicator. By default the Periods 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 RelativeStrengthIndex(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 );
-
- // 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.ExceptionPeriodParameterIsNegative);
-
- double [] upward = new double[inputValues[0].Length-1];
- double [] downward = new double[inputValues[0].Length-1];
- for( int index = 1; index < inputValues[0].Length; index++ )
- {
- // Upward - price is going up
- if( inputValues[1][index - 1] < inputValues[1][index] )
- {
- upward[index-1] = inputValues[1][index] - inputValues[1][index - 1];
- downward[index-1] = 0.0;
- }
- // Downward - price is going down
- if( inputValues[1][index - 1] > inputValues[1][index] )
- {
- upward[index-1] = 0.0;
- downward[index-1] = inputValues[1][index - 1] - inputValues[1][index];
- }
- }
- double [] averageUpward = new double[inputValues[0].Length];
- double [] averageDownward = new double[inputValues[0].Length];
- ExponentialMovingAverage(downward, out averageDownward, period, false );
- ExponentialMovingAverage(upward, out averageUpward, period, false );
- outputValues = new double [2][];
- outputValues[0] = new double [averageDownward.Length];
- outputValues[1] = new double [averageDownward.Length];
- // Find RSI
- for( int index = 0; index < averageDownward.Length; index++ )
- {
- // Set X values
- outputValues[0][index] = inputValues[0][index + period];
- // Calculate the Relative Strength Index (RSI):
- outputValues[1][index] = 100 - 100 / ( 1 + averageUpward[index] / averageDownward[index] );
- }
- }
- /// <summary>
- /// TripleExponentialMovingAverage is a momentum indicator that displays the percent rate-of-change of a triple
- /// exponentially smoothed moving average of the security's closing price. It is designed
- /// to keep you in trends equal to or shorter than the number of periods you specify.
- /// The TripleExponentialMovingAverage indicator oscillates around a zero line. Its triple exponential smoothing is
- /// designed to filter out "insignificant" cycles (i.e., those that are shorter than
- /// the number of periods you specify). Trades should be placed when the indicator changes
- /// direction (i.e., buy when it turns up and sell when it turns down). You may want to
- /// plot a 9-period moving average of the TripleExponentialMovingAverage to create a "signal" line (similar to the
- /// MovingAverageConvergenceDivergence indicator, and then buy when the TripleExponentialMovingAverage rises above its signal, and sell when it
- /// falls below its signal. Divergences between the security and the TripleExponentialMovingAverage can also help
- /// identify turning points.
- /// ---------------------------------------------------------
- /// Input:
- /// - 1 Y values ( Close ).
- /// Output:
- /// - 1 Y value ( TripleExponentialMovingAverage ).
- /// Parameters:
- /// - Period = is used to calculate the Exponential Moving Avg, By default this property is set to 12.
- /// </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 Trix(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 );
-
- // Period
- int period;
- if (parameterList.Length < 1 ||
- !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out period))
- {
- period = 12;
- }
- if( period <= 0 )
- throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
-
- double [] exp1; // Exponential Moving average of input values
- double [] exp2; // Exponential Moving average of exp1
- double [] exp3; // Exponential Moving average of exp2
- // Find exponential moving average
- ExponentialMovingAverage( inputValues[1], out exp1, period, false );
- // Find exponential moving average
- ExponentialMovingAverage( exp1, out exp2, period, false );
- // Find exponential moving average
- ExponentialMovingAverage( exp2, out exp3, period, false );
- outputValues = new double [2][];
- outputValues[0] = new double [inputValues[0].Length - period * 3 + 2];
- outputValues[1] = new double [inputValues[0].Length - period * 3 + 2];
- // Calculate TripleExponentialMovingAverage
- int outIndex = 0;
- for( int index = period * 3 - 2; index < inputValues[0].Length; index++ )
- {
- // set X value
- outputValues[0][outIndex] = inputValues[0][index];
- // set Y value
- outputValues[1][outIndex] = ( exp3[outIndex+1] - exp3[outIndex] ) / exp3[outIndex];
- outIndex++;
- }
- }
- /// <summary>
- /// The MovingAverageConvergenceDivergence is used to determine overbought or oversold conditions in the market. Written
- /// for stocks and stock indices, MovingAverageConvergenceDivergence can be used for commodities as well. The MovingAverageConvergenceDivergence line
- /// is the difference between the long and short exponential moving averages of the chosen
- /// item. The signal line is an exponential moving average of the MovingAverageConvergenceDivergence line. Signals are
- /// generated by the relationship of the two lines. As with RSI and Stochastics,
- /// divergences between the MovingAverageConvergenceDivergence and prices may indicate an upcoming trend reversal. The MovingAverageConvergenceDivergence
- /// is a trend following momentum indicator that shows the relationship between two
- /// moving averages of prices. The MovingAverageConvergenceDivergence is the difference between a 26-day and 12-day
- /// exponential moving average. A 9-day exponential moving average, called the "signal"
- /// (or "trigger") line is plotted on top of the MovingAverageConvergenceDivergence to show buy/sell opportunities. The
- /// MovingAverageConvergenceDivergence is calculated by subtracting the value of a 26-day exponential moving average
- /// from a 12-day exponential moving average. A 9-day dotted exponential moving average of
- /// the MovingAverageConvergenceDivergence (the "signal" line) is then plotted on top of the MovingAverageConvergenceDivergence.
- /// ---------------------------------------------------------
- /// Input:
- /// - 1 Y value ( Close ).
- /// Output:
- /// - 1 Y value ( MovingAverageConvergenceDivergence ).
- /// Parameters:
- /// - ShortPeriod = is used to configure the short Exponential Moving Average, By default this property is set to 12.
- /// - LongPeriod = is used to configure the Int64 Exponential Moving Average, By default this property is set to 26.
- /// </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 Macd(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 = 12;
- }
- if( shortPeriod <= 0 )
- throw new InvalidOperationException(SR.ExceptionPeriodShortParameterIsNegative);
- // Int64 Period
- int longPeriod;
- if (parameterList.Length < 2 ||
- !int.TryParse(parameterList[1], NumberStyles.Any, CultureInfo.InvariantCulture, out longPeriod))
- {
- longPeriod = 26;
- }
- if( longPeriod <= 0 )
- throw new InvalidOperationException(SR.ExceptionPeriodLongParameterIsNegative);
- if( longPeriod <= shortPeriod )
- throw new InvalidOperationException(SR.ExceptionIndicatorsLongPeriodLessThenShortPeriod);
-
- double [] longAverage; // Int64 Average
- double [] shortAverage; // Short Average
-
- // Find Int64 exponential moving average
- ExponentialMovingAverage( inputValues[1], out longAverage, longPeriod, false );
- // Find Short exponential moving average
- ExponentialMovingAverage( inputValues[1], out shortAverage, shortPeriod, false );
-
- outputValues = new double [2][];
- outputValues[0] = new double [inputValues[0].Length - longPeriod + 1];
- outputValues[1] = new double [inputValues[0].Length - longPeriod + 1];
-
- // Calculate MovingAverageConvergenceDivergence
- int outIndex = 0;
- for( int index = longPeriod - 1; index < inputValues[0].Length; index++ )
- {
- // set X value
- outputValues[0][outIndex] = inputValues[0][index];
- // set Y value
- outputValues[1][outIndex] = shortAverage[ outIndex + longPeriod - shortPeriod ] - longAverage[outIndex];
- outIndex++;
- }
- }
- /// <summary>
- /// The CCI is a timing system that is best applied to commodity contracts which
- /// have cyclical or seasonal tendencies. CCI does not determine the length of
- /// cycles - it is designed to detect when such cycles begin and end through
- /// the use of a statistical analysis which incorporates a moving average and a divisor
- /// reflecting both the possible and actual trading ranges. Although developed primarily
- /// for commodities, the CCI could conceivably be used to analyze stocks as well. The
- /// Commodity Channel Index ("CCI") measures the variation of a security’s price from
- /// its statistical mean. High values show that prices are unusually high compared to
- /// average prices whereas low values indicate that prices are unusually low.
- /// 1. Calculate today's Typical Price (TP) = (H+L+C)/3 where H = high; L = low, and C = close.
- /// 2. Calculate today's 20-day Simple Moving Average of the Typical Price (SMATP).
- /// 3. Calculate today's Mean Deviation. First, calculate the absolute value of the difference
- /// between today's SMATP and the typical price for each of the past 20 days.
- /// Add all of these absolute values together and divide by 20 to find the Mean Deviation.
- /// 4. The final step is to apply the Typical Price (TP), the Simple Moving Average of the
- /// Typical Price (SMATP), the Mean Deviation and a Constant (.015).
- /// ---------------------------------------------------------
- /// Input:
- /// - 3 Y values ( Hi, Low, Close ).
- /// Output:
- /// - 1 Y value ( CCI ).
- /// Parameters:
- /// - Periods = is used to configure the number of periods to calculate the CCI. By default the Periods 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 CommodityChannelIndex(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 );
-
- // 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.ExceptionPeriodParameterIsNegative);
- // Typical Price
- double [] typicalPrice = new double[inputValues[0].Length];
-
- // Typical Price loop
- for( int index = 0; index < inputValues[0].Length; index++ )
- {
- typicalPrice[index] = ( inputValues[1][index] + inputValues[2][index] + inputValues[3][index] ) / 3.0;
- }
- // Moving Average
- double [] movingAverage;
-
- // Simple Moving Average of the Typical Price
- MovingAverage( typicalPrice, out movingAverage, period, false );
- // Calculate today's Mean Deviation. First, calculate the absolute value
- // of the difference between today's SMATP and the typical price for each
- // of the past 20 days. Add all of these absolute values together and
- // divide by 20 to find the Mean Deviation.
- // Mean Deviation
- double [] meanDeviation = new double[movingAverage.Length];
- double sum =0;
- for( int index = 0; index < movingAverage.Length; index++ )
- {
- sum = 0;
- for( int indexSum = index; indexSum < index + period; indexSum++ )
- {
- sum += Math.Abs( movingAverage[index] - typicalPrice[indexSum] );
- }
- meanDeviation[index] = sum / period;
- }
- outputValues = new double [2][];
- outputValues[0] = new double [meanDeviation.Length];
- outputValues[1] = new double [meanDeviation.Length];
-
- for( int index = 0; index < meanDeviation.Length; index++ )
- {
- // Set X values
- outputValues[0][index] = inputValues[0][index + period - 1];
- // Set Y values
- outputValues[1][index] = ( typicalPrice[index + period - 1] - movingAverage[index] ) / ( 0.015 * meanDeviation[index] );
-
- }
- }
- #endregion
- #region Methods
- /// <summary>
- /// Default constructor
- /// </summary>
- public GeneralTechnicalIndicators()
- {
- }
- /// <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;
- name = formulaName.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
- // Not used for these formulas.
- outLabels = null;
- try
- {
- switch( name )
- {
- case "STANDARDDEVIATION":
- StandardDeviation( inputValues, out outputValues, parameterList, extraParameterList );
- break;
- case "AVERAGETRUERANGE":
- AverageTrueRange( inputValues, out outputValues, parameterList );
- break;
- case "EASEOFMOVEMENT":
- EaseOfMovement( inputValues, out outputValues );
- break;
- case "MASSINDEX":
- MassIndex( inputValues, out outputValues, parameterList );
- break;
- case "PERFORMANCE":
- Performance( inputValues, out outputValues );
- break;
- case "RATEOFCHANGE":
- RateOfChange( inputValues, out outputValues, parameterList );
- break;
- case "RELATIVESTRENGTHINDEX":
- RelativeStrengthIndex( inputValues, out outputValues, parameterList );
- break;
- case "TRIPLEEXPONENTIALMOVINGAVERAGE":
- Trix( inputValues, out outputValues, parameterList );
- break;
- case "MOVINGAVERAGECONVERGENCEDIVERGENCE":
- Macd( inputValues, out outputValues, parameterList );
- break;
- case "COMMODITYCHANNELINDEX":
- CommodityChannelIndex( 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
- }
- }
|