1 //-------------------------------------------------------------
2 // <copyright company=’Microsoft Corporation’>
3 // Copyright © Microsoft Corporation. All Rights Reserved.
5 //-------------------------------------------------------------
6 // @owner=victark, alexgor, deliant
8 using System.Collections.Generic;
10 using System.Globalization;
11 using System.Diagnostics;
14 namespace System.Windows.Forms.DataVisualization.Charting.Formulas
16 namespace System.Web.UI.DataVisualization.Charting.Formulas
20 #region class FormulaHelper
22 /// Formula helper is a static utility class implementing common formula related routines.
24 internal static class FormulaHelper
28 /// Gets the formula info instance.
30 /// <param name="formula">The formula.</param>
31 /// <returns>FomulaInfo instance</returns>
32 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity"), System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling")]
33 internal static FormulaInfo GetFormulaInfo(FinancialFormula formula)
38 case FinancialFormula.MovingAverage:
39 return new MovingAverageFormulaInfo();
40 case FinancialFormula.ExponentialMovingAverage:
41 return new ExponentialMovingAverageFormulaInfo();
42 case FinancialFormula.WeightedMovingAverage:
43 return new WeightedMovingAverageFormulaInfo();
44 case FinancialFormula.TriangularMovingAverage:
45 return new TriangularMovingAverageFormulaInfo();
46 case FinancialFormula.TripleExponentialMovingAverage:
47 return new TripleExponentialMovingAverageFormulaInfo();
48 case FinancialFormula.BollingerBands:
49 return new BollingerBandsFormulaInfo();
50 case FinancialFormula.TypicalPrice:
51 return new TypicalPriceFormulaInfo();
52 case FinancialFormula.WeightedClose:
53 return new WeightedCloseFormulaInfo();
54 case FinancialFormula.MedianPrice:
55 return new MedianPriceFormulaInfo();
56 case FinancialFormula.Envelopes:
57 return new EnvelopesFormulaInfo();
58 case FinancialFormula.StandardDeviation:
59 return new StandardDeviationFormulaInfo();
62 case FinancialFormula.ChaikinOscillator:
63 return new ChaikinOscillatorFormulaInfo();
64 case FinancialFormula.DetrendedPriceOscillator:
65 return new DetrendedPriceOscillatorFormulaInfo();
66 case FinancialFormula.VolatilityChaikins:
67 return new VolatilityChaikinsFormulaInfo();
68 case FinancialFormula.VolumeOscillator:
69 return new VolumeOscillatorFormulaInfo();
70 case FinancialFormula.StochasticIndicator:
71 return new StochasticIndicatorFormulaInfo();
72 case FinancialFormula.WilliamsR:
73 return new WilliamsRFormulaInfo();
75 // General technical indicators
76 case FinancialFormula.AverageTrueRange:
77 return new AverageTrueRangeFormulaInfo();
78 case FinancialFormula.EaseOfMovement:
79 return new EaseOfMovementFormulaInfo();
80 case FinancialFormula.MassIndex:
81 return new MassIndexFormulaInfo();
82 case FinancialFormula.Performance:
83 return new PerformanceFormulaInfo();
84 case FinancialFormula.RateOfChange:
85 return new RateOfChangeFormulaInfo();
86 case FinancialFormula.RelativeStrengthIndex:
87 return new RelativeStrengthIndexFormulaInfo();
88 case FinancialFormula.MovingAverageConvergenceDivergence:
89 return new MovingAverageConvergenceDivergenceFormulaInfo();
90 case FinancialFormula.CommodityChannelIndex:
91 return new CommodityChannelIndexFormulaInfo();
94 case FinancialFormula.Forecasting:
95 return new ForecastingFormulaInfo();
98 case FinancialFormula.MoneyFlow:
99 return new MoneyFlowFormulaInfo();
100 case FinancialFormula.PriceVolumeTrend:
101 return new PriceVolumeTrendFormulaInfo();
102 case FinancialFormula.OnBalanceVolume:
103 return new OnBalanceVolumeFormulaInfo();
104 case FinancialFormula.NegativeVolumeIndex:
105 return new NegativeVolumeIndexFormulaInfo();
106 case FinancialFormula.PositiveVolumeIndex:
107 return new PositiveVolumeIndexFormulaInfo();
108 case FinancialFormula.AccumulationDistribution:
109 return new AccumulationDistributionFormulaInfo();
112 Debug.Fail(String.Format(CultureInfo.InvariantCulture, "{0} case is not defined", formula));
118 /// Gets the data fields of the specified chart type.
120 /// <param name="chartType">Type of the chart.</param>
121 /// <returns>Data fields</returns>
122 internal static IList<DataField> GetDataFields(SeriesChartType chartType)
126 case SeriesChartType.BoxPlot:
127 return new DataField[] {
128 DataField.LowerWisker, DataField.UpperWisker,
129 DataField.LowerBox, DataField.UpperBox,
130 DataField.Average, DataField.Median };
131 case SeriesChartType.Bubble:
132 return new DataField[] {
133 DataField.Bubble, DataField.BubbleSize };
134 case SeriesChartType.Candlestick:
135 case SeriesChartType.Stock:
136 return new DataField[] {
137 DataField.High, DataField.Low,
138 DataField.Open, DataField.Close };
139 case SeriesChartType.ErrorBar:
140 return new DataField[] {
142 DataField.LowerError, DataField.UpperError};
143 case SeriesChartType.RangeBar:
144 case SeriesChartType.Range:
145 case SeriesChartType.RangeColumn:
146 case SeriesChartType.SplineRange:
147 return new DataField[] {
148 DataField.Top, DataField.Bottom };
150 return new DataField[] { DataField.Y };
155 /// Gets the default type of the chart associated with this field name.
157 /// <param name="field">The field.</param>
158 /// <returns></returns>
159 internal static SeriesChartType GetDefaultChartType(DataField field)
165 return SeriesChartType.Line;
166 case DataField.LowerWisker:
167 case DataField.UpperWisker:
168 case DataField.LowerBox:
169 case DataField.UpperBox:
170 case DataField.Average:
171 case DataField.Median:
172 return SeriesChartType.BoxPlot;
173 case DataField.Bubble:
174 case DataField.BubbleSize:
175 return SeriesChartType.Bubble;
179 case DataField.Close:
180 return SeriesChartType.Stock;
181 case DataField.Center:
182 case DataField.LowerError:
183 case DataField.UpperError:
184 return SeriesChartType.ErrorBar;
186 case DataField.Bottom:
187 return SeriesChartType.Range;
192 /// Maps formula data field to a chart type specific data field.
194 /// <param name="chartType">Type of the chart.</param>
195 /// <param name="formulaField">The formula field to be mapped.</param>
196 /// <returns>The series field</returns>
197 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
198 internal static DataField? MapFormulaDataField(SeriesChartType chartType, DataField formulaField)
200 switch (formulaField)
206 default: return null;
207 case SeriesChartType.BoxPlot: return DataField.UpperBox;
208 case SeriesChartType.Candlestick:
209 case SeriesChartType.Stock: return DataField.High;
210 case SeriesChartType.ErrorBar: return DataField.UpperError;
211 case SeriesChartType.RangeBar:
212 case SeriesChartType.Range:
213 case SeriesChartType.RangeColumn:
214 case SeriesChartType.SplineRange: return DataField.Top;
217 case DataField.Bottom:
221 default: return null;
222 case SeriesChartType.BoxPlot: return DataField.LowerBox;
223 case SeriesChartType.Candlestick:
224 case SeriesChartType.Stock: return DataField.Low;
225 case SeriesChartType.ErrorBar: return DataField.LowerError;
226 case SeriesChartType.RangeBar:
227 case SeriesChartType.Range:
228 case SeriesChartType.RangeColumn:
229 case SeriesChartType.SplineRange: return DataField.Bottom;
235 default: return null;
236 case SeriesChartType.BoxPlot: return DataField.Average;
237 case SeriesChartType.Candlestick:
238 case SeriesChartType.Stock: return DataField.Open;
239 case SeriesChartType.ErrorBar: return DataField.Center;
240 case SeriesChartType.RangeBar:
241 case SeriesChartType.Range:
242 case SeriesChartType.RangeColumn:
243 case SeriesChartType.SplineRange: return DataField.Bottom;
246 case DataField.Close:
250 default: return DataField.Y;
251 case SeriesChartType.BoxPlot: return DataField.Average;
252 case SeriesChartType.Bubble: return DataField.Bubble;
253 case SeriesChartType.Candlestick:
254 case SeriesChartType.Stock: return DataField.Close;
255 case SeriesChartType.ErrorBar: return DataField.Center;
256 case SeriesChartType.RangeBar:
257 case SeriesChartType.Range:
258 case SeriesChartType.RangeColumn:
259 case SeriesChartType.SplineRange: return DataField.Top;
270 #region class FormulaInfo and inherited FormulaSpecific classes
273 /// This a base class of the formula metainfo classes.
275 internal abstract class FormulaInfo
278 DataField[] _inputFields;
279 DataField[] _outputFields;
280 object[] _parameters;
285 /// Gets the input data fields of the formula.
287 /// <value>The input fields.</value>
288 public DataField[] InputFields
290 get { return _inputFields; }
294 /// Gets the output data fields of the formula.
296 /// <value>The output fields.</value>
297 public DataField[] OutputFields
299 get { return _outputFields; }
303 /// Gets the parameters of the formula.
305 /// <value>The parameters.</value>
306 public object[] Parameters
308 get { return _parameters; }
314 /// Initializes a new instance of the <see cref="FormulaInfo"/> class.
316 /// <param name="inputFields">The input data fields.</param>
317 /// <param name="outputFields">The output data fields.</param>
318 /// <param name="defaultParams">The default formula params.</param>
319 public FormulaInfo(DataField[] inputFields, DataField[] outputFields, params object[] defaultParams)
321 _inputFields = inputFields;
322 _outputFields = outputFields;
323 _parameters = defaultParams;
329 /// Saves the formula parameters to a string.
331 /// <returns>Csv string with parameters</returns>
332 internal virtual string SaveParametersToString()
334 StringBuilder sb = new StringBuilder();
335 for (int i = 0; i < _parameters.Length; i++)
337 if (i > 0) sb.Append(',');
338 sb.AppendFormat(CultureInfo.InvariantCulture, "{0}", _parameters[i]);
340 return sb.ToString();
344 /// Loads the formula parameters from string.
346 /// <param name="parameters">Csv string with parameters.</param>
347 internal virtual void LoadParametersFromString(string parameters)
349 if (String.IsNullOrEmpty(parameters))
352 string[] paramStringList = parameters.Split(',');
353 int paramStringIndex = 0;
354 for (int i = 0; i < _parameters.Length && paramStringIndex < paramStringList.Length; i++)
356 string newParamValue = paramStringList[paramStringIndex++];
357 if (!String.IsNullOrEmpty(newParamValue))
359 _parameters[i] = ParseParameter(i, newParamValue);
365 /// Parses the formula parameter.
367 /// <param name="index">The param index.</param>
368 /// <param name="newParamValue">The parameter value string.</param>
369 /// <returns>Parameter value.</returns>
370 internal virtual object ParseParameter(int index, string newParamValue)
372 object param = _parameters[index];
375 return Convert.ToInt32(newParamValue, CultureInfo.InvariantCulture);
377 else if (param is bool)
379 return Convert.ToBoolean(newParamValue, CultureInfo.InvariantCulture);
381 else if (param is double)
383 return Convert.ToDouble(newParamValue, CultureInfo.InvariantCulture);
389 /// Checks the formula parameter string.
391 /// <param name="parameters">The parameters.</param>
392 internal virtual void CheckParameterString(string parameters)
394 if (String.IsNullOrEmpty(parameters))
397 string[] paramStringList = parameters.Split(',');
398 int paramStringIndex = 0;
399 for (int i = 0; i < _parameters.Length && paramStringIndex < paramStringList.Length; i++)
401 string newParamValue = paramStringList[paramStringIndex++];
402 if (!String.IsNullOrEmpty(newParamValue))
406 ParseParameter(i, newParamValue);
408 catch (FormatException)
410 throw new ArgumentException(SR.ExceptionFormulaDataFormatInvalid(parameters));
419 /// MovingAverage FormulaInfo
421 internal class MovingAverageFormulaInfo : FormulaInfo
425 /// Initializes a new instance of the <see cref="MovingAverageFormulaInfo"/> class.
427 public MovingAverageFormulaInfo()
428 : this(2, false) //Defaults
432 /// Initializes a new instance of the <see cref="MovingAverageFormulaInfo"/> class.
434 /// <param name="period">The period.</param>
435 /// <param name="startFromFirst">if set to <c>true</c> [start from first].</param>
436 public MovingAverageFormulaInfo(int period, bool startFromFirst)
438 new DataField[] { DataField.Y }, //Input fields
439 new DataField[] { DataField.Y }, //Output fields
440 period, startFromFirst)
446 /// ExponentialMoving AverageFormulaInfo
448 internal class ExponentialMovingAverageFormulaInfo : FormulaInfo
452 /// Initializes a new instance of the <see cref="ExponentialMovingAverageFormulaInfo"/> class.
454 public ExponentialMovingAverageFormulaInfo()
455 : this(2, false) //Defaults
459 /// Initializes a new instance of the <see cref="ExponentialMovingAverageFormulaInfo"/> class.
461 /// <param name="period">The period.</param>
462 /// <param name="startFromFirst">if set to <c>true</c> [start from first].</param>
463 public ExponentialMovingAverageFormulaInfo(int period, bool startFromFirst)
465 new DataField[] { DataField.Y }, //Input fields
466 new DataField[] { DataField.Y }, //Output fields
467 period, startFromFirst)
473 /// WeightedMovingAverageFormulaInfo
475 internal class WeightedMovingAverageFormulaInfo : FormulaInfo
479 /// Initializes a new instance of the <see cref="WeightedMovingAverageFormulaInfo"/> class.
481 public WeightedMovingAverageFormulaInfo()
482 : this(2, false) //Defaults
486 /// Initializes a new instance of the <see cref="WeightedMovingAverageFormulaInfo"/> class.
488 /// <param name="period">The period.</param>
489 /// <param name="startFromFirst">if set to <c>true</c> [start from first].</param>
490 public WeightedMovingAverageFormulaInfo(int period, bool startFromFirst)
492 new DataField[] { DataField.Y }, //Input fields
493 new DataField[] { DataField.Y }, //Output fields
494 period, startFromFirst)
500 /// TriangularMovingAverage FormulaInfo
502 internal class TriangularMovingAverageFormulaInfo : FormulaInfo
506 /// Initializes a new instance of the <see cref="TriangularMovingAverageFormulaInfo"/> class.
508 public TriangularMovingAverageFormulaInfo()
509 : this(2, false) //Defaults
513 /// Initializes a new instance of the <see cref="TriangularMovingAverageFormulaInfo"/> class.
515 /// <param name="period">The period.</param>
516 /// <param name="startFromFirst">if set to <c>true</c> [start from first].</param>
517 public TriangularMovingAverageFormulaInfo(int period, bool startFromFirst)
519 new DataField[] { DataField.Y }, //Input fields
520 new DataField[] { DataField.Y }, //Output fields
521 period, startFromFirst)
527 /// TripleExponentialMovingAverage FormulaInfo
529 internal class TripleExponentialMovingAverageFormulaInfo : FormulaInfo
533 /// Initializes a new instance of the <see cref="TripleExponentialMovingAverageFormulaInfo"/> class.
535 public TripleExponentialMovingAverageFormulaInfo()
536 : this(12) //Defaults
540 /// Initializes a new instance of the <see cref="TripleExponentialMovingAverageFormulaInfo"/> class.
542 /// <param name="period">The period.</param>
543 public TripleExponentialMovingAverageFormulaInfo(int period)
545 new DataField[] { DataField.Y }, //Input fields
546 new DataField[] { DataField.Y }, //Output fields
553 /// BollingerBands FormulaInfo
555 internal class BollingerBandsFormulaInfo : FormulaInfo
559 /// Initializes a new instance of the <see cref="BollingerBandsFormulaInfo"/> class.
561 public BollingerBandsFormulaInfo()
562 : this(3, 2, true) //Defaults
566 /// Initializes a new instance of the <see cref="BollingerBandsFormulaInfo"/> class.
568 /// <param name="period">The period.</param>
569 /// <param name="deviation">The deviation.</param>
570 /// <param name="startFromFirst">if set to <c>true</c> [start from first].</param>
571 public BollingerBandsFormulaInfo(int period, double deviation, bool startFromFirst)
573 new DataField[] { DataField.Y }, //Input fields
574 new DataField[] { DataField.Top, DataField.Bottom }, //Output fields
575 period, deviation, startFromFirst)
581 /// TypicalPrice FormulaInfo
583 internal class TypicalPriceFormulaInfo : FormulaInfo
587 /// Initializes a new instance of the <see cref="TypicalPriceFormulaInfo"/> class.
589 public TypicalPriceFormulaInfo()
591 new DataField[] { DataField.Close, DataField.High, DataField.Low }, //Input fields
592 new DataField[] { DataField.Y }) //Output fields
598 /// WeightedClose FormulaInfo
600 internal class WeightedCloseFormulaInfo : FormulaInfo
604 /// Initializes a new instance of the <see cref="WeightedCloseFormulaInfo"/> class.
606 public WeightedCloseFormulaInfo()
608 new DataField[] { DataField.Close, DataField.High, DataField.Low }, //Input fields
609 new DataField[] { DataField.Y }) //Output fields
615 /// MedianPrice FormulaInfo
617 internal class MedianPriceFormulaInfo : FormulaInfo
621 /// Initializes a new instance of the <see cref="MedianPriceFormulaInfo"/> class.
623 public MedianPriceFormulaInfo()
625 new DataField[] { DataField.High, DataField.Low }, //Input fields
626 new DataField[] { DataField.Y }) //Output fields
633 /// Envelopes FormulaInfo
635 internal class EnvelopesFormulaInfo : FormulaInfo
639 /// Initializes a new instance of the <see cref="EnvelopesFormulaInfo"/> class.
641 public EnvelopesFormulaInfo()
642 : this(2, 10, true) //Defaults
646 /// Initializes a new instance of the <see cref="EnvelopesFormulaInfo"/> class.
648 /// <param name="period">The period.</param>
649 /// <param name="shiftPercentage">The shift percentage.</param>
650 /// <param name="startFromFirst">if set to <c>true</c> [start from first].</param>
651 public EnvelopesFormulaInfo(int period, double shiftPercentage, bool startFromFirst)
653 new DataField[] { DataField.Y }, //Input fields
654 new DataField[] { DataField.Top, DataField.Bottom }, //Output fields
655 period, shiftPercentage, startFromFirst)
662 /// StandardDeviation FormulaInfo
664 internal class StandardDeviationFormulaInfo : FormulaInfo
668 /// Initializes a new instance of the <see cref="StandardDeviationFormulaInfo"/> class.
670 public StandardDeviationFormulaInfo()
671 : this(2, false) //Defaults
675 /// Initializes a new instance of the <see cref="StandardDeviationFormulaInfo"/> class.
677 /// <param name="period">The period.</param>
678 /// <param name="startFromFirst">if set to <c>true</c> [start from first].</param>
679 public StandardDeviationFormulaInfo(int period, bool startFromFirst)
681 new DataField[] { DataField.Y }, //Input fields
682 new DataField[] { DataField.Y }, //Output fields
683 period, startFromFirst)
689 /// ChaikinOscillatorFormulaInfo
691 internal class ChaikinOscillatorFormulaInfo : FormulaInfo
695 /// Initializes a new instance of the <see cref="ChaikinOscillatorFormulaInfo"/> class.
697 public ChaikinOscillatorFormulaInfo()
698 : this(3, 10, false) //Defaults
702 /// Initializes a new instance of the <see cref="ChaikinOscillatorFormulaInfo"/> class.
704 /// <param name="shortPeriod">The short period.</param>
705 /// <param name="longPeriod">The long period.</param>
706 /// <param name="startFromFirst">if set to <c>true</c> [start from first].</param>
707 public ChaikinOscillatorFormulaInfo(int shortPeriod, int longPeriod, bool startFromFirst)
709 new DataField[] { DataField.High, DataField.Low, DataField.Close, DataField.Y }, //Input fields
710 new DataField[] { DataField.Y }, //Output fields
711 shortPeriod, longPeriod, startFromFirst)
717 /// DetrendedPriceOscillator FormulaInfo
719 internal class DetrendedPriceOscillatorFormulaInfo : FormulaInfo
723 /// Initializes a new instance of the <see cref="DetrendedPriceOscillatorFormulaInfo"/> class.
725 public DetrendedPriceOscillatorFormulaInfo()
726 : this(2, false) //Defaults
730 /// Initializes a new instance of the <see cref="DetrendedPriceOscillatorFormulaInfo"/> class.
732 /// <param name="period">The period.</param>
733 /// <param name="startFromFirst">if set to <c>true</c> [start from first].</param>
734 public DetrendedPriceOscillatorFormulaInfo(int period, bool startFromFirst)
736 new DataField[] { DataField.Y }, //Input fields
737 new DataField[] { DataField.Y }, //Output fields
738 period, startFromFirst)
745 /// VolatilityChaikins FormulaInfo
747 internal class VolatilityChaikinsFormulaInfo : FormulaInfo
751 /// Initializes a new instance of the <see cref="VolatilityChaikinsFormulaInfo"/> class.
753 public VolatilityChaikinsFormulaInfo()
754 : this(10, 10) //Defaults
758 /// Initializes a new instance of the <see cref="VolatilityChaikinsFormulaInfo"/> class.
760 /// <param name="period">The period.</param>
761 /// <param name="signalPeriod">The signal period.</param>
762 public VolatilityChaikinsFormulaInfo(int period, int signalPeriod)
764 new DataField[] { DataField.High, DataField.Low }, //Input fields
765 new DataField[] { DataField.Y }, //Output fields
766 period, signalPeriod)
772 /// VolumeOscillator FormulaInfo
774 internal class VolumeOscillatorFormulaInfo : FormulaInfo
778 /// Initializes a new instance of the <see cref="VolumeOscillatorFormulaInfo"/> class.
780 public VolumeOscillatorFormulaInfo()
781 : this(5, 10, true) //Defaults
785 /// Initializes a new instance of the <see cref="VolumeOscillatorFormulaInfo"/> class.
787 /// <param name="shortPeriod">The short period.</param>
788 /// <param name="longPeriod">The long period.</param>
789 /// <param name="percentage">if set to <c>true</c> [percentage].</param>
790 public VolumeOscillatorFormulaInfo(int shortPeriod, int longPeriod, bool percentage)
792 new DataField[] { DataField.Y }, //Input fields
793 new DataField[] { DataField.Y }, //Output fields
794 shortPeriod, longPeriod, percentage)
800 /// StochasticIndicatorFormulaInfo
802 internal class StochasticIndicatorFormulaInfo : FormulaInfo
806 /// Initializes a new instance of the <see cref="StochasticIndicatorFormulaInfo"/> class.
808 public StochasticIndicatorFormulaInfo()
809 : this(10, 10) //Defaults
813 /// Initializes a new instance of the <see cref="StochasticIndicatorFormulaInfo"/> class.
815 /// <param name="periodD">The period D.</param>
816 /// <param name="periodK">The period K.</param>
817 public StochasticIndicatorFormulaInfo(int periodD, int periodK)
819 new DataField[] { DataField.High, DataField.Low, DataField.Close }, //Input fields
820 new DataField[] { DataField.Y, DataField.Y }, //Output fields
827 /// WilliamsRFormulaInfo
829 internal class WilliamsRFormulaInfo : FormulaInfo
833 /// Initializes a new instance of the <see cref="WilliamsRFormulaInfo"/> class.
835 public WilliamsRFormulaInfo()
836 : this(14) //Defaults
840 /// Initializes a new instance of the <see cref="WilliamsRFormulaInfo"/> class.
842 /// <param name="period">The period.</param>
843 public WilliamsRFormulaInfo(int period)
845 new DataField[] { DataField.High, DataField.Low, DataField.Close }, //Input fields
846 new DataField[] { DataField.Y }, //Output fields
853 /// AverageTrueRange FormulaInfo
855 internal class AverageTrueRangeFormulaInfo : FormulaInfo
859 /// Initializes a new instance of the <see cref="AverageTrueRangeFormulaInfo"/> class.
861 public AverageTrueRangeFormulaInfo()
862 : this(14) //Defaults
866 /// Initializes a new instance of the <see cref="AverageTrueRangeFormulaInfo"/> class.
868 /// <param name="period">The period.</param>
869 public AverageTrueRangeFormulaInfo(int period)
871 new DataField[] { DataField.High, DataField.Low, DataField.Close }, //Input fields
872 new DataField[] { DataField.Y }, //Output fields
879 /// EaseOfMovement FormulaInfo
881 internal class EaseOfMovementFormulaInfo : FormulaInfo
885 /// Initializes a new instance of the <see cref="EaseOfMovementFormulaInfo"/> class.
887 public EaseOfMovementFormulaInfo()
889 new DataField[] { DataField.High, DataField.Low, DataField.Close }, //Input fields
890 new DataField[] { DataField.Y }) //Output fields
896 /// MassIndex FormulaInfo
898 internal class MassIndexFormulaInfo : FormulaInfo
902 /// Initializes a new instance of the <see cref="MassIndexFormulaInfo"/> class.
904 public MassIndexFormulaInfo()
905 : this(25, 9) //Defaults
909 /// Initializes a new instance of the <see cref="MassIndexFormulaInfo"/> class.
911 /// <param name="period">The period.</param>
912 /// <param name="averagePeriod">The average period.</param>
913 public MassIndexFormulaInfo(int period, int averagePeriod)
915 new DataField[] { DataField.High, DataField.Low }, //Input fields
916 new DataField[] { DataField.Y }, //Output fields
917 period, averagePeriod)
923 /// Performance FormulaInfo
925 internal class PerformanceFormulaInfo : FormulaInfo
929 /// Initializes a new instance of the <see cref="PerformanceFormulaInfo"/> class.
931 public PerformanceFormulaInfo()
933 new DataField[] { DataField.Close }, //Input fields
934 new DataField[] { DataField.Y }) //Output fields
940 /// RateOfChange FormulaInfo
942 internal class RateOfChangeFormulaInfo : FormulaInfo
946 /// Initializes a new instance of the <see cref="RateOfChangeFormulaInfo"/> class.
948 public RateOfChangeFormulaInfo()
949 : this(10) //Defaults
953 /// Initializes a new instance of the <see cref="RateOfChangeFormulaInfo"/> class.
955 /// <param name="period">The period.</param>
956 public RateOfChangeFormulaInfo(int period)
958 new DataField[] { DataField.Close }, //Input fields
959 new DataField[] { DataField.Y }, //Output fields
966 /// RelativeStrengthIndex FormulaInfo
968 internal class RelativeStrengthIndexFormulaInfo : FormulaInfo
972 /// Initializes a new instance of the <see cref="RelativeStrengthIndexFormulaInfo"/> class.
974 public RelativeStrengthIndexFormulaInfo()
975 : this(10) //Defaults
979 /// Initializes a new instance of the <see cref="RelativeStrengthIndexFormulaInfo"/> class.
981 /// <param name="period">The period.</param>
982 public RelativeStrengthIndexFormulaInfo(int period)
984 new DataField[] { DataField.Close }, //Input fields
985 new DataField[] { DataField.Y }, //Output fields
992 /// MovingAverageConvergenceDivergence FormulaInfo
994 internal class MovingAverageConvergenceDivergenceFormulaInfo : FormulaInfo
998 /// Initializes a new instance of the <see cref="MovingAverageConvergenceDivergenceFormulaInfo"/> class.
1000 public MovingAverageConvergenceDivergenceFormulaInfo()
1001 : this(12, 26) //Defaults
1005 /// Initializes a new instance of the <see cref="MovingAverageConvergenceDivergenceFormulaInfo"/> class.
1007 /// <param name="shortPeriod">The short period.</param>
1008 /// <param name="longPeriod">The long period.</param>
1009 public MovingAverageConvergenceDivergenceFormulaInfo(int shortPeriod, int longPeriod)
1011 new DataField[] { DataField.Close }, //Input fields
1012 new DataField[] { DataField.Y }, //Output fields
1013 shortPeriod, longPeriod)
1019 /// CommodityChannelIndex FormulaInfo
1021 internal class CommodityChannelIndexFormulaInfo : FormulaInfo
1025 /// Initializes a new instance of the <see cref="CommodityChannelIndexFormulaInfo"/> class.
1027 public CommodityChannelIndexFormulaInfo()
1028 : this(10) //Defaults
1032 /// Initializes a new instance of the <see cref="CommodityChannelIndexFormulaInfo"/> class.
1034 /// <param name="period">The period.</param>
1035 public CommodityChannelIndexFormulaInfo(int period)
1037 new DataField[] { DataField.High, DataField.Low, DataField.Close }, //Input fields
1038 new DataField[] { DataField.Y }, //Output fields
1045 /// Forecasting FormulaInfo
1047 internal class ForecastingFormulaInfo : FormulaInfo
1054 /// Initializes a new instance of the <see cref="ForecastingFormulaInfo"/> class.
1056 public ForecastingFormulaInfo()
1057 : this(TimeSeriesAndForecasting.RegressionType.Polynomial, 2, 0, true, true) //Defaults
1061 /// Initializes a new instance of the <see cref="ForecastingFormulaInfo"/> class.
1063 /// <param name="regressionType">Type of the regression.</param>
1064 /// <param name="polynomialDegree">The polynomial degree.</param>
1065 /// <param name="forecastingPeriod">The forecasting period.</param>
1066 /// <param name="returnApproximationError">if set to <c>true</c> [return approximation error].</param>
1067 /// <param name="returnForecastingError">if set to <c>true</c> [return forecasting error].</param>
1068 public ForecastingFormulaInfo(TimeSeriesAndForecasting.RegressionType regressionType, int polynomialDegree, int forecastingPeriod, bool returnApproximationError, bool returnForecastingError)
1070 new DataField[] { DataField.Close }, //Input fields
1071 new DataField[] { DataField.Close, DataField.High, DataField.Low }, //Output fields
1072 regressionType, polynomialDegree, forecastingPeriod, returnApproximationError, returnForecastingError)
1078 /// Loads the formula parameters from string.
1080 /// <param name="parameters">Csv string with parameters.</param>
1081 internal override void LoadParametersFromString(string parameters)
1083 _parameters = parameters;
1087 /// Checks the formula parameter string.
1089 /// <param name="parameters">The parameters.</param>
1090 internal override void CheckParameterString(string parameters)
1092 if (String.IsNullOrEmpty(parameters))
1095 string[] paramStringList = parameters.Split(',');
1096 int paramStringIndex = 1;
1097 //Don't check the first param
1098 for (int i = 2; i < Parameters.Length && paramStringIndex < paramStringList.Length; i++)
1100 string newParamValue = paramStringList[paramStringIndex++];
1101 if (!String.IsNullOrEmpty(newParamValue))
1105 ParseParameter(i, newParamValue);
1107 catch (FormatException)
1109 throw new ArgumentException(SR.ExceptionFormulaDataFormatInvalid(parameters));
1116 /// Saves the formula parameters to a string.
1118 /// <returns>Csv string with parameters</returns>
1119 internal override string SaveParametersToString()
1121 if (String.IsNullOrEmpty(_parameters))
1124 return "2,0,true,true";
1129 /// MoneyFlow FormulaInfo
1131 internal class MoneyFlowFormulaInfo : FormulaInfo
1135 /// Initializes a new instance of the <see cref="MoneyFlowFormulaInfo"/> class.
1137 public MoneyFlowFormulaInfo()
1138 : this(2) //Defaults
1142 /// Initializes a new instance of the <see cref="MoneyFlowFormulaInfo"/> class.
1144 /// <param name="period">The period.</param>
1145 public MoneyFlowFormulaInfo(int period)
1147 new DataField[] { DataField.High, DataField.Low, DataField.Close, DataField.Y }, //Input fields: High,Low,Close,Volume
1148 new DataField[] { DataField.Y }, //Output fields
1155 /// PriceVolumeTrend FormulaInfo
1157 internal class PriceVolumeTrendFormulaInfo : FormulaInfo
1161 /// Initializes a new instance of the <see cref="PriceVolumeTrendFormulaInfo"/> class.
1163 public PriceVolumeTrendFormulaInfo()
1165 new DataField[] { DataField.Close, DataField.Y }, //Input=Close,Volume
1166 new DataField[] { DataField.Y }) //Output fields
1172 /// OnBalanceVolume FormulaInfo
1174 internal class OnBalanceVolumeFormulaInfo : FormulaInfo
1178 /// Initializes a new instance of the <see cref="OnBalanceVolumeFormulaInfo"/> class.
1180 public OnBalanceVolumeFormulaInfo()
1182 new DataField[] { DataField.Close, DataField.Y }, //Input=Close,Volume
1183 new DataField[] { DataField.Y }) //Output fields
1189 /// NegativeVolumeIndex FormulaInfo
1191 internal class NegativeVolumeIndexFormulaInfo : FormulaInfo
1195 /// Initializes a new instance of the <see cref="NegativeVolumeIndexFormulaInfo"/> class.
1197 public NegativeVolumeIndexFormulaInfo() //Note about parameters: Start value is mandatory so we don't provide the default
1202 /// Initializes a new instance of the <see cref="NegativeVolumeIndexFormulaInfo"/> class.
1204 /// <param name="startValue">The start value.</param>
1205 public NegativeVolumeIndexFormulaInfo(double startValue)
1207 new DataField[] { DataField.Close, DataField.Y }, //Input=Close,Volume
1208 new DataField[] { DataField.Y },
1209 startValue) //Output fields
1215 /// PositiveVolumeIndex FormulaInfo
1217 internal class PositiveVolumeIndexFormulaInfo : FormulaInfo
1221 /// Initializes a new instance of the <see cref="PositiveVolumeIndexFormulaInfo"/> class.
1223 public PositiveVolumeIndexFormulaInfo() //Note about parameters: Start value is mandatory so we don't provide the default
1228 /// Initializes a new instance of the <see cref="PositiveVolumeIndexFormulaInfo"/> class.
1230 /// <param name="startValue">The start value.</param>
1231 public PositiveVolumeIndexFormulaInfo(double startValue)
1233 new DataField[] { DataField.Close, DataField.Y }, //Input=Close,Volume
1234 new DataField[] { DataField.Y },
1235 startValue) //Output fields
1241 /// AccumulationDistribution FormulaInfo
1243 internal class AccumulationDistributionFormulaInfo : FormulaInfo
1247 /// Initializes a new instance of the <see cref="AccumulationDistributionFormulaInfo"/> class.
1249 public AccumulationDistributionFormulaInfo() //Note about parameters: Start value is mandatory so we don't provide the default
1251 new DataField[] { DataField.High, DataField.Low, DataField.Close, DataField.Y }, //Input=High, Low, Close, Volume
1252 new DataField[] { DataField.Y }) //Output fields
1259 #region enum DataField
1261 /// Chart data fields
1263 internal enum DataField
1287 #region class SeriesFieldInfo
1289 /// SeriesFieldInfo class is a OO representation formula input/output data params ("Series1:Y2")
1291 internal class SeriesFieldInfo
1294 private Series _series;
1295 private string _seriesName;
1296 private DataField _dataField;
1301 /// Gets the series.
1303 /// <value>The series.</value>
1304 public Series Series
1306 get { return _series; }
1309 /// Gets the name of the series.
1311 /// <value>The name of the series.</value>
1312 public string SeriesName
1314 get { return _series != null ? _series.Name : _seriesName; }
1317 /// Gets the data field.
1319 /// <value>The data field.</value>
1320 public DataField DataField
1322 get { return _dataField; }
1326 #region Constructors
1328 /// Initializes a new instance of the <see cref="SeriesFieldInfo"/> class.
1330 /// <param name="series">The series.</param>
1331 /// <param name="dataField">The data field.</param>
1332 public SeriesFieldInfo(Series series, DataField dataField)
1335 _dataField = dataField;
1338 /// Initializes a new instance of the <see cref="SeriesFieldInfo"/> class.
1340 /// <param name="seriesName">Name of the series.</param>
1341 /// <param name="dataField">The data field.</param>
1342 public SeriesFieldInfo(string seriesName, DataField dataField)
1344 _seriesName = seriesName;
1345 _dataField = dataField;
1351 #region class SeriesFieldList
1353 /// SeriesFieldInfo class is a OO representation formula input/output data params ("Series1:Y2,Series2.Y4")
1355 internal class SeriesFieldList : List<SeriesFieldInfo>
1358 /// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
1361 /// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
1363 public override string ToString()
1365 StringBuilder sb = new StringBuilder();
1366 for (int i = 0; i < this.Count; i++)
1368 SeriesFieldInfo info = this[i];
1373 SeriesChartType seriesChartType = info.Series != null ?
1374 info.Series.ChartType :
1375 FormulaHelper.GetDefaultChartType(info.DataField);
1377 IList<DataField> dataFields = FormulaHelper.GetDataFields(seriesChartType);
1379 int dataFieldIndex = dataFields.IndexOf(info.DataField);
1380 if (dataFieldIndex == 0)
1381 sb.AppendFormat(CultureInfo.InvariantCulture, "{0}:Y", info.SeriesName); //The string field descriptor is 1 based ;-(
1383 sb.AppendFormat(CultureInfo.InvariantCulture, "{0}:Y{1}", info.SeriesName, dataFieldIndex + 1); //The string field descriptor is 1 based ;-(
1385 return sb.ToString();
1390 /// Parse the string defining the formula's input/output series and fields.
1392 /// <param name="chart">The chart.</param>
1393 /// <param name="seriesFields">The series fields list. The series name can be followed by the field names. For example: "Series1:Y,Series1:Y3,Series2:Close"</param>
1394 /// <param name="formulaFields">The formula fields list.</param>
1395 /// <returns></returns>
1396 public static SeriesFieldList FromString(Chart chart, string seriesFields, IList<DataField> formulaFields)
1398 SeriesFieldList result = new SeriesFieldList();
1399 if (String.IsNullOrEmpty(seriesFields))
1404 List<DataField> unmappedFormulaFields = new List<DataField>(formulaFields);
1406 //Loop through the series/field pairs
1407 foreach (string seriesField in seriesFields.Split(','))
1409 //Stop processing if all the formula fields are mapped
1410 if (unmappedFormulaFields.Count == 0)
1413 //Split a pair into a series + field
1414 string[] seriesFieldParts = seriesField.Split(':');
1415 if (seriesFieldParts.Length > 2)
1417 throw new ArgumentException(SR.ExceptionFormulaDataFormatInvalid(seriesField));
1420 //Get the series and series fields
1421 string seriesName = seriesFieldParts[0].Trim();
1422 Series series = chart.Series.FindByName(seriesName);
1425 switch (seriesFieldParts.Length)
1427 case 1: //Only series name is specified: "Series1"
1428 AddSeriesFieldInfo(result, series, unmappedFormulaFields);
1430 case 2: //Series and field names are provided: "Series1:Y3"
1431 AddSeriesFieldInfo(result, series, unmappedFormulaFields, seriesFieldParts[1]);
1437 switch (seriesFieldParts.Length)
1439 case 1: //Only series name is specified: "Series1"
1440 AddSeriesFieldInfo(result, seriesName, unmappedFormulaFields);
1442 case 2: //Series and field names are provided: "Series1:Y3"
1443 AddSeriesFieldInfo(result, seriesName, unmappedFormulaFields, seriesFieldParts[1]);
1452 /// Adds the series field info.
1454 /// <param name="result">The result.</param>
1455 /// <param name="series">The series.</param>
1456 /// <param name="unmappedFormulaFields">The unmapped formula fields.</param>
1457 private static void AddSeriesFieldInfo(SeriesFieldList result, Series series, IList<DataField> unmappedFormulaFields)
1459 List<DataField> seriesFields = new List<DataField>(FormulaHelper.GetDataFields(series.ChartType));
1461 for (int i = 0; i < unmappedFormulaFields.Count && seriesFields.Count > 0; )
1463 DataField formulaField = unmappedFormulaFields[i];
1464 DataField? seriesField = null;
1466 // Case 1. Check if the formulaField is valid for this chart type
1467 if (seriesFields.Contains(formulaField))
1469 seriesField = formulaField;
1471 // Case 2. Try to map the formula field to the series field
1472 if (seriesField == null)
1474 seriesField = FormulaHelper.MapFormulaDataField(series.ChartType, formulaField);
1477 // If the seriesField is found - add it to the results
1478 if (seriesField != null)
1480 result.Add(new SeriesFieldInfo(series, (DataField)seriesField));
1481 seriesFields.Remove((DataField)formulaField);
1482 unmappedFormulaFields.Remove(formulaField);
1491 /// Adds the series field info.
1493 /// <param name="result">The result.</param>
1494 /// <param name="series">The series.</param>
1495 /// <param name="unmappedFormulaFields">The unmapped formula fields.</param>
1496 /// <param name="seriesFieldId">The series field id.</param>
1497 private static void AddSeriesFieldInfo(SeriesFieldList result, Series series, IList<DataField> unmappedFormulaFields, string seriesFieldId)
1499 IList<DataField> seriesFields = FormulaHelper.GetDataFields(series.ChartType);
1501 DataField? seriesField = null;
1503 seriesFieldId = seriesFieldId.ToUpperInvariant().Trim();
1504 if (seriesFieldId == "Y")
1506 seriesField = seriesFields[0];
1508 else if (seriesFieldId.StartsWith("Y", StringComparison.Ordinal))
1511 if (int.TryParse(seriesFieldId.Substring(1), out id))
1512 if (id - 1 < seriesFields.Count)
1514 seriesField = seriesFields[id - 1];
1518 throw (new ArgumentException(SR.ExceptionFormulaYIndexInvalid, seriesFieldId));
1523 seriesField = (DataField)Enum.Parse(typeof(DataField), seriesFieldId, true);
1526 // Add the seriesField to the results
1527 if (seriesField != null)
1529 result.Add(new SeriesFieldInfo(series, (DataField)seriesField));
1530 if (unmappedFormulaFields.Contains((DataField)seriesField))
1531 unmappedFormulaFields.Remove((DataField)seriesField);
1533 unmappedFormulaFields.RemoveAt(0);
1537 throw new ArgumentException(SR.ExceptionDataPointValueNameInvalid, seriesFieldId);
1543 /// Adds the series field info.
1545 /// <param name="result">The result.</param>
1546 /// <param name="seriesName">Name of the series.</param>
1547 /// <param name="unmappedFormulaFields">The unmapped formula fields.</param>
1548 private static void AddSeriesFieldInfo(SeriesFieldList result, string seriesName, IList<DataField> unmappedFormulaFields)
1550 SeriesChartType chartType = FormulaHelper.GetDefaultChartType(unmappedFormulaFields[0]);
1551 List<DataField> seriesFields = new List<DataField>(FormulaHelper.GetDataFields(chartType));
1553 for (int i = 0; i < unmappedFormulaFields.Count && seriesFields.Count > 0; )
1555 DataField formulaField = unmappedFormulaFields[i];
1556 DataField? seriesField = null;
1558 // Check if the formulaField is valid for this chart type
1559 if (seriesFields.Contains(formulaField))
1561 seriesField = formulaField;
1564 // If the seriesField is found - add it to the results
1565 if (seriesField != null)
1567 result.Add(new SeriesFieldInfo(seriesName, (DataField)seriesField));
1568 seriesFields.Remove((DataField)formulaField);
1569 unmappedFormulaFields.Remove(formulaField);
1578 /// Adds the series field info.
1580 /// <param name="result">The result.</param>
1581 /// <param name="seriesName">Name of the series.</param>
1582 /// <param name="unmappedFormulaFields">The unmapped formula fields.</param>
1583 /// <param name="seriesFieldId">The series field id.</param>
1584 private static void AddSeriesFieldInfo(SeriesFieldList result, string seriesName, IList<DataField> unmappedFormulaFields, string seriesFieldId)
1586 SeriesChartType chartType = FormulaHelper.GetDefaultChartType(unmappedFormulaFields[0]);
1587 IList<DataField> seriesFields = FormulaHelper.GetDataFields(chartType);
1590 DataField? seriesField = null;
1592 seriesFieldId = seriesFieldId.ToUpperInvariant().Trim();
1594 if (seriesFieldId == "Y")
1596 seriesField = seriesFields[0];
1598 else if (seriesFieldId.StartsWith("Y", StringComparison.Ordinal))
1600 int seriesFieldIndex = 0;
1601 if (int.TryParse(seriesFieldId.Substring(1), out seriesFieldIndex))
1602 if (seriesFieldIndex < seriesFields.Count)
1604 seriesField = seriesFields[seriesFieldIndex - 1];
1608 throw (new ArgumentException(SR.ExceptionFormulaYIndexInvalid, seriesFieldId));
1613 //Try parse the field name
1616 seriesField = (DataField)Enum.Parse(typeof(DataField), seriesFieldId, true);
1618 catch (ArgumentException)
1622 if (seriesField != null)
1624 result.Add(new SeriesFieldInfo(seriesName, (DataField)seriesField));
1625 unmappedFormulaFields.Remove((DataField)seriesField);
1629 throw new ArgumentException(SR.ExceptionDataPointValueNameInvalid, seriesFieldId);