1 //-------------------------------------------------------------
2 // <copyright company=
\92Microsoft Corporation
\92>
3 // Copyright © Microsoft Corporation. All Rights Reserved.
5 //-------------------------------------------------------------
6 // @owner=alexgor, deliant
7 //=================================================================
8 // File: TechGeneralIndicators.cs
10 // Namespace: System.Web.UI.WebControls[Windows.Forms].Charting.Formulas
12 // Classes: TechGeneralIndicators
14 // Purpose: This class is used for calculations of
15 // general technical analyses indicators.
17 // Reviewed: GS - August 7, 2002
18 // AG - August 7, 2002
20 //===================================================================
24 using System.Globalization;
29 namespace System.Windows.Forms.DataVisualization.Charting.Formulas
31 namespace System.Web.UI.DataVisualization.Charting.Formulas
35 /// This class is used for calculations of general
36 /// technical analyses indicators.
38 internal class GeneralTechnicalIndicators : PriceIndicators
43 /// Formula Module name
45 override public string Name { get { return SR.FormulaNameGeneralTechnicalIndicators; } }
52 /// Standard Deviation is a statistical measure of volatility.
53 /// Standard Deviation is typically used as a component of
54 /// other indicators, rather than as a stand-alone indicator.
55 /// For example, Bollinger Bands are calculated by adding
56 /// a security's Standard Deviation to a moving average.
57 /// High Standard Deviation values occur when the data item
58 /// being analyzed (e.g., prices or an indicator) is changing
59 /// dramatically. Similarly, low Standard Deviation values
60 /// occur when prices are stable.
61 /// ---------------------------------------------------------
65 /// - 1 Y value Standard Deviation
67 /// - Periods for standard deviation ( used for moving average )
71 /// <param name="inputValues">Arrays of doubles - Input values</param>
72 /// <param name="outputValues">Arrays of doubles - Output values</param>
73 /// <param name="parameterList">Array of strings - Parameters</param>
74 /// <param name="extraParameterList">Array of strings - Extra parameters</param>
75 private void StandardDeviation(double [][] inputValues, out double [][] outputValues, string [] parameterList, string [] extraParameterList)
77 int length = inputValues.Length;
79 // Period for standard deviation ( used for moving average )
82 {period = int.Parse( parameterList[0], System.Globalization.CultureInfo.InvariantCulture );}
85 if (e.Message == SR.ExceptionObjectReferenceIsNull)
86 throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing);
88 throw new InvalidOperationException(SR.ExceptionPriceIndicatorsPeriodMissing + e.Message);
92 throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
94 // Starting average from the first data point or after period.
95 bool startFromFirst = bool.Parse( extraParameterList[0] );
97 // There is no enough series
99 throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
101 // Different number of x and y values
102 if( inputValues[0].Length != inputValues[1].Length )
103 throw new ArgumentException(SR.ExceptionPriceIndicatorsSameXYNumber);
105 // Not enough values for moving average in Standard deviation.
106 if( inputValues[0].Length < period )
107 throw new ArgumentException(SR.ExceptionPriceIndicatorsNotEnoughPoints);
109 outputValues = new double [2][];
111 StandardDeviation( inputValues[1], out outputValues[1], period, startFromFirst );
114 outputValues[0] = new double [outputValues[1].Length];
115 for( int index = 0; index < outputValues[1].Length; index++ )
118 outputValues[0][index] = inputValues[0][index];
120 outputValues[0][index] = inputValues[0][index+period-1];
125 /// The Average True Range ("ATR") is a measure of volatility. It was introduced
126 /// by Welles Wilder in his book, New Concepts in Technical Trading Systems, and
127 /// has since been used as a component of many indicators and trading systems. Wilder
128 /// has found that high ATR values often occur at market bottoms following a "panic"
129 /// sell-off. Low Average True Range values are often found during extended sideways
130 /// periods, such as those found at tops and after consolidation periods. The Average
131 /// True Range can be interpreted using the same techniques that are used with
132 /// the other volatility indicators.
133 /// ---------------------------------------------------------
135 /// - 3 Y values ( High, Low, Close ).
137 /// - 1 Y value AverageTrueRange
139 /// - Periods (Default 14) = is used to configure the number of periods to calculate the ATR
141 /// <param name="inputValues">Arrays of doubles - Input values</param>
142 /// <param name="outputValues">Arrays of doubles - Output values</param>
143 /// <param name="parameterList">Array of strings - Parameters</param>
144 private void AverageTrueRange(double [][] inputValues, out double [][] outputValues, string [] parameterList)
146 // There is no enough input series
147 if( inputValues.Length != 4 )
148 throw new ArgumentException( SR.ExceptionPriceIndicatorsFormulaRequiresThreeArrays);
150 // Different number of x and y values
151 CheckNumOfValues( inputValues, 3 );
155 if (parameterList.Length < 1 ||
156 !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out period))
162 throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
164 // The distance from today's high to today's low
167 // The distance from yesterday's close to today's high
170 // The distance from yesterday's close to today's low
173 double [] trueRange = new double [inputValues[0].Length - 1];
176 for( int index = 1; index < inputValues[0].Length; index++ )
178 // The distance from today's high to today's low
179 distanceOne = Math.Abs( inputValues[1][index] - inputValues[2][index] );
181 // The distance from yesterday's close to today's high
182 distanceTwo = Math.Abs( inputValues[3][index-1] - inputValues[1][index] );
184 // The distance from yesterday's close to today's low
185 distanceTree = Math.Abs( inputValues[3][index-1] - inputValues[2][index] );
188 trueRange[index-1] = Math.Max( Math.Max( distanceOne, distanceTwo ), distanceTree );
191 outputValues = new double [2][];
193 outputValues[0] = new double [inputValues[0].Length-period];
195 // Moving average of true range
196 MovingAverage( trueRange, out outputValues[1], period, false );
199 for( int index = period; index < inputValues[0].Length; index++ )
201 outputValues[0][index-period] = inputValues[0][index];
206 /// The Ease of Movement indicator shows the relationship between volume and price
207 /// change. This indicator shows how much volume is required to move prices. The Ease
208 /// of Movement indicator was developed Richard W. Arms, Jr., the creator of Equivolume.
209 /// High Ease of Movement values occur when prices are moving upward on lightStyle volume.
210 /// Low Ease of Movement values occur when prices are moving downward on lightStyle volume.
211 /// If prices are not moving, or if heavy volume is required to move prices, then
212 /// indicator will also be near zero.
213 /// ---------------------------------------------------------
215 /// - 3 Y values ( High, Low, Volume ).
217 /// - 1 Y value Ease Of Movement
219 /// <param name="inputValues">Arrays of doubles - Input values</param>
220 /// <param name="outputValues">Arrays of doubles - Output values</param>
221 private void EaseOfMovement(double [][] inputValues, out double [][] outputValues)
223 // There is no enough input series
224 if( inputValues.Length != 4 )
225 throw new ArgumentException( SR.ExceptionPriceIndicatorsFormulaRequiresThreeArrays);
227 // Different number of x and y values
228 CheckNumOfValues( inputValues, 3 );
233 outputValues = new double [2][];
235 outputValues[0] = new double [inputValues[0].Length - 1];
236 outputValues[1] = new double [inputValues[0].Length - 1];
239 for( int index = 1; index < inputValues[0].Length; index++ )
242 outputValues[0][index - 1] = inputValues[0][index];
244 // Calculate the Mid-point Move for each day:
245 MidPointMove = ( inputValues[1][index] + inputValues[2][index] ) / 2 - ( inputValues[1][index - 1] + inputValues[2][index - 1] ) / 2;
247 // The Box Ratio determines the ratio between height and width of the Equivolume box:
248 BoxRattio = ( inputValues[3][index] ) / (( inputValues[1][index] - inputValues[2][index] ) );
250 // Ease of Movement is then calculated as:
251 outputValues[1][index - 1] = MidPointMove / BoxRattio;
256 /// The Mass Index was designed to identify trend reversals by measuring the narrowing
257 /// and widening of the range between the high and low prices. As this range widens, the
258 /// Mass Index increases; as the range narrows the Mass Index decreases.
259 /// The Mass Index was developed by Donald Dorsey. According to Mr. Dorsey, the most
260 /// significant pattern to watch for is a "reversal bulge." A reversal bulge occurs when
261 /// a 25-period Mass Index rises above 27.0 and subsequently falls below 26.5. A reversal
262 /// in price is then likely. The overall price trend (i.e., trending or trading range)
264 /// ---------------------------------------------------------
266 /// - 2 Y values ( High, Low ).
268 /// - 1 Y value Mass Index
270 /// - Period = is used to calculate the accumulation, By default this property is set to 25.
271 /// - AveragePeriod = is used to calculate Simple Moving Avg, By default this property is set to 9.
273 /// <param name="inputValues">Arrays of doubles - Input values</param>
274 /// <param name="outputValues">Arrays of doubles - Output values</param>
275 /// <param name="parameterList">Array of strings - Parameters</param>
276 private void MassIndex(double [][] inputValues, out double [][] outputValues, string [] parameterList)
278 // There is no enough input series
279 if( inputValues.Length != 3 )
280 throw new ArgumentException( SR.ExceptionPriceIndicatorsFormulaRequiresTwoArrays);
282 // Different number of x and y values
283 CheckNumOfValues( inputValues, 2 );
287 if (parameterList.Length < 1 ||
288 !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out period))
294 throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
298 if (parameterList.Length < 2 ||
299 !int.TryParse(parameterList[1], NumberStyles.Any, CultureInfo.InvariantCulture, out averagePeriod))
305 throw new InvalidOperationException(SR.ExceptionPeriodAverageParameterIsNegative);
307 double [] highLow = new double [inputValues[0].Length];
309 double [] secondAverage;
311 for( int index = 0; index < inputValues[0].Length; index++ )
313 highLow[index] = inputValues[1][index] - inputValues[2][index];
316 // Find exponential moving average
317 ExponentialMovingAverage( highLow, out average, averagePeriod, false );
319 // Find exponential moving average of exponential moving average
320 ExponentialMovingAverage( average, out secondAverage, averagePeriod, false );
322 outputValues = new double [2][];
324 outputValues[0] = new double [secondAverage.Length - period + 1];
325 outputValues[1] = new double [secondAverage.Length - period + 1];
330 for( int index = 2 * averagePeriod - 3 + period; index < inputValues[0].Length; index++ )
333 outputValues[0][outIndex] = inputValues[0][index];
336 for( int indexSum = index - period + 1; indexSum <= index; indexSum++ )
338 sum += average[indexSum - averagePeriod + 1] / secondAverage[indexSum - 2 * averagePeriod + 2];
342 outputValues[1][outIndex] = sum;
349 /// The Performance indicator displays a security's price performance as
350 /// a percentage. This is sometimes called a "normalized" chart. The
351 /// Performance indicator displays the percentage that the security
352 /// has increased since the first period displayed. For example, if
353 /// the Performance indicator is 10, it means that the security's
354 /// price has increased 10% since the first period displayed on the
355 /// left side of the chart. Similarly, a value of -10% means that
356 /// the security's price has fallen by 10% since the first period
358 /// ---------------------------------------------------------
360 /// - 1 Y value ( Close ).
362 /// - 1 Y value Performance
364 /// <param name="inputValues">Arrays of doubles - Input values</param>
365 /// <param name="outputValues">Arrays of doubles - Output values</param>
366 private void Performance(double [][] inputValues, out double [][] outputValues)
368 // There is no enough input series
369 if( inputValues.Length != 2 )
370 throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
372 // Different number of x and y values
373 CheckNumOfValues( inputValues, 1 );
375 outputValues = new double [2][];
377 outputValues[0] = new double [inputValues[0].Length];
378 outputValues[1] = new double [inputValues[0].Length];
380 // Performance indicator
381 for( int index = 0; index < inputValues[0].Length; index++ )
384 outputValues[0][index] = inputValues[0][index];
387 outputValues[1][index] = ( inputValues[1][index] - inputValues[1][0] ) / inputValues[1][0] * 100;
392 /// Rate of Change is used to monitor momentum by making direct comparisons between current
393 /// and past prices on a continual basis. The results can be used to determine the strength
394 /// of price trends. Note: This study is the same as the Momentum except that Momentum uses
395 /// subtraction in its calculations while Rate of Change uses division. The resulting lines
396 /// of these two studies operated over the same data will look exactly the same - only the
397 /// scale values will differ. The Price Rate-of-Change ("----") indicator displays the
398 /// difference between the current price and the price x-time periods ago. The difference
399 /// can be displayed in either points or as a percentage. The Momentum indicator displays
400 /// the same information, but expresses it as a ratio. When the Rate-of-Change displays
401 /// the price change in points, it subtracts the price x-time periods ago from today
\92s price.
402 /// When the Rate-of-Change displays the price change as a percentage, it divides
403 /// the price change by price x-time period
\92s ago.
404 /// ---------------------------------------------------------
406 /// - 1 Y value ( Close ).
408 /// - 1 Y value Rate of Change
410 /// - Periods = is used to configure the number of periods to calculate the rate of Change. By default the Periods property is set to 10.
412 /// <param name="inputValues">Arrays of doubles - Input values</param>
413 /// <param name="outputValues">Arrays of doubles - Output values</param>
414 /// <param name="parameterList">Array of strings - Parameters</param>
415 private void RateOfChange(double [][] inputValues, out double [][] outputValues, string [] parameterList)
417 // There is no enough input series
418 if( inputValues.Length != 2 )
419 throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
421 // Different number of x and y values
422 CheckNumOfValues( inputValues, 1 );
426 if (parameterList.Length < 1 ||
427 !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out period))
433 throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
435 outputValues = new double [2][];
437 outputValues[0] = new double [inputValues[0].Length - period];
438 outputValues[1] = new double [inputValues[0].Length - period];
441 for( int index = period; index < inputValues[0].Length; index++ )
444 outputValues[0][index - period] = inputValues[0][index];
447 outputValues[1][index - period] = ( inputValues[1][index] - inputValues[1][index - period] ) / inputValues[1][index - period] * 100;
452 /// This indicator was developed by Welles Wilder Jr. Relative Strength is often
453 /// used to identify price tops and bottoms by keying on specific levels
454 /// (usually "30" and "70") on the RSI chart which is scaled from from 0-100.
455 /// The study is also useful to detect the following:
456 /// - Movement which might not be as readily apparent on the bar chart
457 /// - Failure swings above 70 or below 30 which can warn of coming reversals
458 /// - Support and resistance levels
459 /// - Divergence between the RSI and price which is often a useful reversal indicator
460 /// ---------------------------------------------------------
462 /// - 1 Y value ( Close ).
464 /// - 1 Y value RelativeStrengthIndex
466 /// - Periods = is used to configure the number of periods to calculate the RSI indicator. By default the Periods property is set to 10.
468 /// <param name="inputValues">Arrays of doubles - Input values</param>
469 /// <param name="outputValues">Arrays of doubles - Output values</param>
470 /// <param name="parameterList">Array of strings - Parameters</param>
471 private void RelativeStrengthIndex(double [][] inputValues, out double [][] outputValues, string [] parameterList)
473 // There is no enough input series
474 if( inputValues.Length != 2 )
475 throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
477 // Different number of x and y values
478 CheckNumOfValues( inputValues, 1 );
482 if (parameterList.Length < 1 ||
483 !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out period))
489 throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
491 double [] upward = new double[inputValues[0].Length-1];
492 double [] downward = new double[inputValues[0].Length-1];
494 for( int index = 1; index < inputValues[0].Length; index++ )
496 // Upward - price is going up
497 if( inputValues[1][index - 1] < inputValues[1][index] )
499 upward[index-1] = inputValues[1][index] - inputValues[1][index - 1];
500 downward[index-1] = 0.0;
502 // Downward - price is going down
503 if( inputValues[1][index - 1] > inputValues[1][index] )
505 upward[index-1] = 0.0;
506 downward[index-1] = inputValues[1][index - 1] - inputValues[1][index];
510 double [] averageUpward = new double[inputValues[0].Length];
511 double [] averageDownward = new double[inputValues[0].Length];
513 ExponentialMovingAverage(downward, out averageDownward, period, false );
514 ExponentialMovingAverage(upward, out averageUpward, period, false );
516 outputValues = new double [2][];
518 outputValues[0] = new double [averageDownward.Length];
519 outputValues[1] = new double [averageDownward.Length];
522 for( int index = 0; index < averageDownward.Length; index++ )
525 outputValues[0][index] = inputValues[0][index + period];
527 // Calculate the Relative Strength Index (RSI):
528 outputValues[1][index] = 100 - 100 / ( 1 + averageUpward[index] / averageDownward[index] );
533 /// TripleExponentialMovingAverage is a momentum indicator that displays the percent rate-of-change of a triple
534 /// exponentially smoothed moving average of the security's closing price. It is designed
535 /// to keep you in trends equal to or shorter than the number of periods you specify.
536 /// The TripleExponentialMovingAverage indicator oscillates around a zero line. Its triple exponential smoothing is
537 /// designed to filter out "insignificant" cycles (i.e., those that are shorter than
538 /// the number of periods you specify). Trades should be placed when the indicator changes
539 /// direction (i.e., buy when it turns up and sell when it turns down). You may want to
540 /// plot a 9-period moving average of the TripleExponentialMovingAverage to create a "signal" line (similar to the
541 /// MovingAverageConvergenceDivergence indicator, and then buy when the TripleExponentialMovingAverage rises above its signal, and sell when it
542 /// falls below its signal. Divergences between the security and the TripleExponentialMovingAverage can also help
543 /// identify turning points.
544 /// ---------------------------------------------------------
546 /// - 1 Y values ( Close ).
548 /// - 1 Y value ( TripleExponentialMovingAverage ).
550 /// - Period = is used to calculate the Exponential Moving Avg, By default this property is set to 12.
552 /// <param name="inputValues">Arrays of doubles - Input values</param>
553 /// <param name="outputValues">Arrays of doubles - Output values</param>
554 /// <param name="parameterList">Array of strings - Parameters</param>
555 private void Trix(double [][] inputValues, out double [][] outputValues, string [] parameterList)
557 // There is no enough input series
558 if( inputValues.Length != 2 )
559 throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
561 // Different number of x and y values
562 CheckNumOfValues( inputValues, 1 );
566 if (parameterList.Length < 1 ||
567 !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out period))
573 throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
575 double [] exp1; // Exponential Moving average of input values
576 double [] exp2; // Exponential Moving average of exp1
577 double [] exp3; // Exponential Moving average of exp2
579 // Find exponential moving average
580 ExponentialMovingAverage( inputValues[1], out exp1, period, false );
582 // Find exponential moving average
583 ExponentialMovingAverage( exp1, out exp2, period, false );
585 // Find exponential moving average
586 ExponentialMovingAverage( exp2, out exp3, period, false );
588 outputValues = new double [2][];
590 outputValues[0] = new double [inputValues[0].Length - period * 3 + 2];
591 outputValues[1] = new double [inputValues[0].Length - period * 3 + 2];
593 // Calculate TripleExponentialMovingAverage
595 for( int index = period * 3 - 2; index < inputValues[0].Length; index++ )
598 outputValues[0][outIndex] = inputValues[0][index];
601 outputValues[1][outIndex] = ( exp3[outIndex+1] - exp3[outIndex] ) / exp3[outIndex];
608 /// The MovingAverageConvergenceDivergence is used to determine overbought or oversold conditions in the market. Written
609 /// for stocks and stock indices, MovingAverageConvergenceDivergence can be used for commodities as well. The MovingAverageConvergenceDivergence line
610 /// is the difference between the long and short exponential moving averages of the chosen
611 /// item. The signal line is an exponential moving average of the MovingAverageConvergenceDivergence line. Signals are
612 /// generated by the relationship of the two lines. As with RSI and Stochastics,
613 /// divergences between the MovingAverageConvergenceDivergence and prices may indicate an upcoming trend reversal. The MovingAverageConvergenceDivergence
614 /// is a trend following momentum indicator that shows the relationship between two
615 /// moving averages of prices. The MovingAverageConvergenceDivergence is the difference between a 26-day and 12-day
616 /// exponential moving average. A 9-day exponential moving average, called the "signal"
617 /// (or "trigger") line is plotted on top of the MovingAverageConvergenceDivergence to show buy/sell opportunities. The
618 /// MovingAverageConvergenceDivergence is calculated by subtracting the value of a 26-day exponential moving average
619 /// from a 12-day exponential moving average. A 9-day dotted exponential moving average of
620 /// the MovingAverageConvergenceDivergence (the "signal" line) is then plotted on top of the MovingAverageConvergenceDivergence.
621 /// ---------------------------------------------------------
623 /// - 1 Y value ( Close ).
625 /// - 1 Y value ( MovingAverageConvergenceDivergence ).
627 /// - ShortPeriod = is used to configure the short Exponential Moving Average, By default this property is set to 12.
628 /// - LongPeriod = is used to configure the Int64 Exponential Moving Average, By default this property is set to 26.
630 /// <param name="inputValues">Arrays of doubles - Input values</param>
631 /// <param name="outputValues">Arrays of doubles - Output values</param>
632 /// <param name="parameterList">Array of strings - Parameters</param>
633 private void Macd(double [][] inputValues, out double [][] outputValues, string [] parameterList)
635 // There is no enough input series
636 if( inputValues.Length != 2 )
637 throw new ArgumentException(SR.ExceptionPriceIndicatorsFormulaRequiresOneArray);
639 // Different number of x and y values
640 CheckNumOfValues( inputValues, 1 );
644 if (parameterList.Length < 1 ||
645 !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out shortPeriod))
650 if( shortPeriod <= 0 )
651 throw new InvalidOperationException(SR.ExceptionPeriodShortParameterIsNegative);
655 if (parameterList.Length < 2 ||
656 !int.TryParse(parameterList[1], NumberStyles.Any, CultureInfo.InvariantCulture, out longPeriod))
661 if( longPeriod <= 0 )
662 throw new InvalidOperationException(SR.ExceptionPeriodLongParameterIsNegative);
664 if( longPeriod <= shortPeriod )
665 throw new InvalidOperationException(SR.ExceptionIndicatorsLongPeriodLessThenShortPeriod);
667 double [] longAverage; // Int64 Average
668 double [] shortAverage; // Short Average
670 // Find Int64 exponential moving average
671 ExponentialMovingAverage( inputValues[1], out longAverage, longPeriod, false );
673 // Find Short exponential moving average
674 ExponentialMovingAverage( inputValues[1], out shortAverage, shortPeriod, false );
676 outputValues = new double [2][];
678 outputValues[0] = new double [inputValues[0].Length - longPeriod + 1];
679 outputValues[1] = new double [inputValues[0].Length - longPeriod + 1];
681 // Calculate MovingAverageConvergenceDivergence
683 for( int index = longPeriod - 1; index < inputValues[0].Length; index++ )
686 outputValues[0][outIndex] = inputValues[0][index];
689 outputValues[1][outIndex] = shortAverage[ outIndex + longPeriod - shortPeriod ] - longAverage[outIndex];
696 /// The CCI is a timing system that is best applied to commodity contracts which
697 /// have cyclical or seasonal tendencies. CCI does not determine the length of
698 /// cycles - it is designed to detect when such cycles begin and end through
699 /// the use of a statistical analysis which incorporates a moving average and a divisor
700 /// reflecting both the possible and actual trading ranges. Although developed primarily
701 /// for commodities, the CCI could conceivably be used to analyze stocks as well. The
702 /// Commodity Channel Index ("CCI") measures the variation of a security
\92s price from
703 /// its statistical mean. High values show that prices are unusually high compared to
704 /// average prices whereas low values indicate that prices are unusually low.
705 /// 1. Calculate today's Typical Price (TP) = (H+L+C)/3 where H = high; L = low, and C = close.
706 /// 2. Calculate today's 20-day Simple Moving Average of the Typical Price (SMATP).
707 /// 3. Calculate today's Mean Deviation. First, calculate the absolute value of the difference
708 /// between today's SMATP and the typical price for each of the past 20 days.
709 /// Add all of these absolute values together and divide by 20 to find the Mean Deviation.
710 /// 4. The final step is to apply the Typical Price (TP), the Simple Moving Average of the
711 /// Typical Price (SMATP), the Mean Deviation and a Constant (.015).
712 /// ---------------------------------------------------------
714 /// - 3 Y values ( Hi, Low, Close ).
716 /// - 1 Y value ( CCI ).
718 /// - Periods = is used to configure the number of periods to calculate the CCI. By default the Periods property is set to 10.
720 /// <param name="inputValues">Arrays of doubles - Input values</param>
721 /// <param name="outputValues">Arrays of doubles - Output values</param>
722 /// <param name="parameterList">Array of strings - Parameters</param>
723 private void CommodityChannelIndex(double [][] inputValues, out double [][] outputValues, string [] parameterList)
725 // There is no enough input series
726 if( inputValues.Length != 4 )
727 throw new ArgumentException( SR.ExceptionPriceIndicatorsFormulaRequiresThreeArrays);
729 // Different number of x and y values
730 CheckNumOfValues( inputValues, 3 );
734 if (parameterList.Length < 1 ||
735 !int.TryParse(parameterList[0], NumberStyles.Any, CultureInfo.InvariantCulture, out period))
741 throw new InvalidOperationException(SR.ExceptionPeriodParameterIsNegative);
744 double [] typicalPrice = new double[inputValues[0].Length];
746 // Typical Price loop
747 for( int index = 0; index < inputValues[0].Length; index++ )
749 typicalPrice[index] = ( inputValues[1][index] + inputValues[2][index] + inputValues[3][index] ) / 3.0;
753 double [] movingAverage;
755 // Simple Moving Average of the Typical Price
756 MovingAverage( typicalPrice, out movingAverage, period, false );
758 // Calculate today's Mean Deviation. First, calculate the absolute value
759 // of the difference between today's SMATP and the typical price for each
760 // of the past 20 days. Add all of these absolute values together and
761 // divide by 20 to find the Mean Deviation.
764 double [] meanDeviation = new double[movingAverage.Length];
767 for( int index = 0; index < movingAverage.Length; index++ )
770 for( int indexSum = index; indexSum < index + period; indexSum++ )
772 sum += Math.Abs( movingAverage[index] - typicalPrice[indexSum] );
774 meanDeviation[index] = sum / period;
777 outputValues = new double [2][];
779 outputValues[0] = new double [meanDeviation.Length];
780 outputValues[1] = new double [meanDeviation.Length];
783 for( int index = 0; index < meanDeviation.Length; index++ )
786 outputValues[0][index] = inputValues[0][index + period - 1];
789 outputValues[1][index] = ( typicalPrice[index + period - 1] - movingAverage[index] ) / ( 0.015 * meanDeviation[index] );
799 /// Default constructor
801 public GeneralTechnicalIndicators()
806 /// The first method in the module, which converts a formula
807 /// name to the corresponding private method.
809 /// <param name="formulaName">String which represent a formula name</param>
810 /// <param name="inputValues">Arrays of doubles - Input values</param>
811 /// <param name="outputValues">Arrays of doubles - Output values</param>
812 /// <param name="parameterList">Array of strings - Formula parameters</param>
813 /// <param name="extraParameterList">Array of strings - Extra Formula parameters from DataManipulator object</param>
814 /// <param name="outLabels">Array of strings - Used for Labels. Description for output results.</param>
815 override public void Formula( string formulaName, double [][] inputValues, out double [][] outputValues, string [] parameterList, string [] extraParameterList, out string [][] outLabels )
820 name = formulaName.ToUpper(System.Globalization.CultureInfo.InvariantCulture);
822 // Not used for these formulas.
829 case "STANDARDDEVIATION":
830 StandardDeviation( inputValues, out outputValues, parameterList, extraParameterList );
832 case "AVERAGETRUERANGE":
833 AverageTrueRange( inputValues, out outputValues, parameterList );
835 case "EASEOFMOVEMENT":
836 EaseOfMovement( inputValues, out outputValues );
839 MassIndex( inputValues, out outputValues, parameterList );
842 Performance( inputValues, out outputValues );
845 RateOfChange( inputValues, out outputValues, parameterList );
847 case "RELATIVESTRENGTHINDEX":
848 RelativeStrengthIndex( inputValues, out outputValues, parameterList );
850 case "TRIPLEEXPONENTIALMOVINGAVERAGE":
851 Trix( inputValues, out outputValues, parameterList );
853 case "MOVINGAVERAGECONVERGENCEDIVERGENCE":
854 Macd( inputValues, out outputValues, parameterList );
856 case "COMMODITYCHANNELINDEX":
857 CommodityChannelIndex( inputValues, out outputValues, parameterList );
864 catch( IndexOutOfRangeException )
866 throw new InvalidOperationException( SR.ExceptionFormulaInvalidPeriod( name ) );
868 catch( OverflowException )
870 throw new InvalidOperationException( SR.ExceptionFormulaNotEnoughDataPoints( name ) );