536cd135cc
Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
1313 lines
52 KiB
C#
1313 lines
52 KiB
C#
//-------------------------------------------------------------
|
||
// <copyright company=’Microsoft Corporation’>
|
||
// Copyright © Microsoft Corporation. All Rights Reserved.
|
||
// </copyright>
|
||
//-------------------------------------------------------------
|
||
// @owner=alexgor, deliant
|
||
//=================================================================
|
||
// File: DataFormula.cs
|
||
//
|
||
// Namespace: DataVisualization.Charting
|
||
//
|
||
// Classes: DataFormula
|
||
//
|
||
// Purpose: DataFormula class provides properties and methods,
|
||
// which prepare series data for technical analyses
|
||
// and time series and forecasting formulas and prepare
|
||
// output data to be displayed as a chart.
|
||
//
|
||
// Reviewed: GS - August 6, 2002
|
||
// AG - August 7, 2002
|
||
// AG - Microsoft 15, 2007
|
||
//
|
||
//===================================================================
|
||
|
||
#region Used Namespace
|
||
using System;
|
||
using System.Drawing;
|
||
using System.ComponentModel;
|
||
using System.Diagnostics.CodeAnalysis;
|
||
using System.Collections.Generic;
|
||
#endregion
|
||
|
||
#if Microsoft_CONTROL
|
||
using System.Windows.Forms.DataVisualization.Charting.Formulas;
|
||
|
||
namespace System.Windows.Forms.DataVisualization.Charting
|
||
#else
|
||
using System.Web.UI.DataVisualization.Charting.Formulas;
|
||
|
||
namespace System.Web.UI.DataVisualization.Charting
|
||
#endif
|
||
{
|
||
#region Financial Formula Name enumeration
|
||
|
||
/// <summary>
|
||
/// An enumeration of financial formula names.
|
||
/// </summary>
|
||
public enum FinancialFormula
|
||
{
|
||
/// <summary>
|
||
/// Accumulation Distribution formula. This indicator uses a relationship
|
||
/// between volume and prices to estimate the strength of price movements,
|
||
/// and if volume is increased, there is a high probability that prices will go up.
|
||
/// </summary>
|
||
AccumulationDistribution,
|
||
|
||
/// <summary>
|
||
/// Average True Range indicator. It measures commitment and compares
|
||
/// the range between the High, Low and Close prices.
|
||
/// </summary>
|
||
AverageTrueRange,
|
||
|
||
/// <summary>
|
||
/// Bollinger Bands indicators. They are plotted at standard deviation levels
|
||
/// above and below a simple moving average.
|
||
/// </summary>
|
||
BollingerBands,
|
||
|
||
/// <summary>
|
||
/// Chaikin Oscillator indicator. It is the difference between a 3-day
|
||
/// exponential moving average and a 10-day exponential moving average
|
||
/// applied to the Accumulation Distribution.
|
||
/// </summary>
|
||
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Chaikin")]
|
||
ChaikinOscillator,
|
||
|
||
/// <summary>
|
||
/// Commodity Channel Index. It compares prices with their moving averages.
|
||
/// </summary>
|
||
CommodityChannelIndex,
|
||
|
||
/// <summary>
|
||
/// Detrended Price Oscillator. It attempts to remove trend from prices.
|
||
/// </summary>
|
||
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Detrended")]
|
||
DetrendedPriceOscillator,
|
||
|
||
/// <summary>
|
||
/// Ease of Movement deals with the relationship between volume and price change,
|
||
/// and uses volume to indicate how strong a trend is for prices.
|
||
/// </summary>
|
||
EaseOfMovement,
|
||
|
||
/// <summary>
|
||
/// Envelopes are plotted above and below a moving average using a specified percentage
|
||
/// as the shift.
|
||
/// </summary>
|
||
Envelopes,
|
||
|
||
/// <summary>
|
||
/// An Exponential Moving Average is an average of data calculated over a period of time
|
||
/// where the most recent days have more weight.
|
||
/// </summary>
|
||
ExponentialMovingAverage,
|
||
|
||
/// <summary>
|
||
/// Forecasting. It predicts future values using historical observations.
|
||
/// </summary>
|
||
Forecasting,
|
||
|
||
/// <summary>
|
||
/// Moving Average Convergence/Divergence indicator. It compares two
|
||
/// moving averages of prices and is used with a 9-day Exponential
|
||
/// Moving average as a signal, which indicates buying and selling moments.
|
||
/// </summary>
|
||
MovingAverageConvergenceDivergence,
|
||
|
||
/// <summary>
|
||
/// The Mass Index is used to predict trend reversal by comparing the
|
||
/// difference and range between High and Low prices.
|
||
/// </summary>
|
||
MassIndex,
|
||
|
||
/// <summary>
|
||
/// Median prices are mid-point values of daily prices and can be used
|
||
/// as a filter for trend indicators.
|
||
/// </summary>
|
||
MedianPrice,
|
||
|
||
/// <summary>
|
||
/// The Money Flow indicator compares upward changes and downward changes
|
||
/// of volume-weighted typical prices.
|
||
/// </summary>
|
||
MoneyFlow,
|
||
|
||
/// <summary>
|
||
/// The Negative Volume Index should be used together with the Positive Volume index,
|
||
/// and the Negative Volume Index only changes if the volume decreases from the previous day.
|
||
/// </summary>
|
||
NegativeVolumeIndex,
|
||
|
||
/// <summary>
|
||
/// The On Balance Volume indicator measures positive and negative volume flow.
|
||
/// </summary>
|
||
OnBalanceVolume,
|
||
|
||
/// <summary>
|
||
/// The Performance indicator compares a current closing price (or any other price) with
|
||
/// the first closing value (from the first time period).
|
||
/// </summary>
|
||
Performance,
|
||
|
||
/// <summary>
|
||
/// The Positive Volume Index should be used together with the Negative Volume index.
|
||
/// The Positive volume index only changes if the volume decreases from the previous day.
|
||
/// </summary>
|
||
PositiveVolumeIndex,
|
||
|
||
/// <summary>
|
||
/// The Price Volume Trend is a cumulative volume total that is calculated using
|
||
/// relative changes of the closing price, and should be used with other indicators.
|
||
/// </summary>
|
||
PriceVolumeTrend,
|
||
|
||
/// <summary>
|
||
/// The Rate of Change indicator compares a specified closing price with the current price.
|
||
/// </summary>
|
||
RateOfChange,
|
||
|
||
/// <summary>
|
||
/// The Relative Strength Index is a momentum oscillator that compares upward movements
|
||
/// of the closing price with downward movements, and results in values that range from 0 to 100.
|
||
/// </summary>
|
||
RelativeStrengthIndex,
|
||
|
||
/// <summary>
|
||
/// A Simple Moving Average is an average of data calculated over a period of time.
|
||
/// The moving average is the most popular price indicator used in technical analysis,
|
||
/// and can be used with any price (e.g. Hi, Low, Open and Close)
|
||
/// or it can be applied to other indicators.
|
||
/// </summary>
|
||
MovingAverage,
|
||
|
||
/// <summary>
|
||
/// Standard deviation is used to indicate volatility, and measures
|
||
/// the difference between values (e.g. closing price) and their moving average.
|
||
/// </summary>
|
||
StandardDeviation,
|
||
|
||
/// <summary>
|
||
/// The Stochastic Indicator helps to find trend reversal by searching in a period for
|
||
/// when the closing prices are close to low prices in an upward trending market
|
||
/// and for when the closing prices are close to high prices in a downward trending market.
|
||
/// </summary>
|
||
StochasticIndicator,
|
||
|
||
/// <summary>
|
||
/// A Triangular Moving Average is an average of data calculated over a period of time
|
||
/// where the middle portion of data has more weight.
|
||
/// </summary>
|
||
TriangularMovingAverage,
|
||
|
||
/// <summary>
|
||
/// The Triple Exponential Moving Average is based on a triple moving average of the closing Price.
|
||
/// Its purpose is to eliminate short cycles. This indicator keeps the closing price
|
||
/// in trends that are shorter than the specified period.
|
||
/// </summary>
|
||
TripleExponentialMovingAverage,
|
||
|
||
/// <summary>
|
||
/// Typical price is the average value of daily prices, and can be used as a filter for trend indicators.
|
||
/// </summary>
|
||
TypicalPrice,
|
||
|
||
/// <summary>
|
||
/// The Volatility Chaikins indicator measures the difference between High and Low prices,
|
||
/// and is used to indicate tops or bottoms of the market.
|
||
/// </summary>
|
||
[SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "Chaikins")]
|
||
VolatilityChaikins,
|
||
|
||
/// <summary>
|
||
/// The Volume oscillator attempts to identify trends in volume by comparing two moving averages:
|
||
/// one with a short period and another with a longer period.
|
||
/// </summary>
|
||
VolumeOscillator,
|
||
|
||
/// <summary>
|
||
/// The Weighted Close formula calculates the average value of daily prices.
|
||
/// The only difference between Typical Price and the Weighted Close is that the closing price
|
||
/// has extra weight, and is considered the most important price.
|
||
/// </summary>
|
||
WeightedClose,
|
||
|
||
/// <summary>
|
||
/// A Weighted Moving Average is an average of data calculated over a period of time,
|
||
/// where greater weight is attached to the most recent data.
|
||
/// </summary>
|
||
WeightedMovingAverage,
|
||
|
||
/// <summary>
|
||
/// William's %R is a momentum indicator, and is used to measure overbought and oversold levels.
|
||
/// </summary>
|
||
WilliamsR
|
||
}
|
||
|
||
#endregion // Financial Formula Name enumeration
|
||
|
||
/// <summary>
|
||
/// The DataFormula class provides properties and methods, which prepare series
|
||
/// data for technical analysis, apply formulas on the series data
|
||
/// and prepare output data to be displayed as a chart.
|
||
/// </summary>
|
||
#if ASPPERM_35
|
||
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
|
||
[AspNetHostingPermission(System.Security.Permissions.SecurityAction.LinkDemand, Level = AspNetHostingPermissionLevel.Minimal)]
|
||
#endif
|
||
public class DataFormula
|
||
{
|
||
#region Data Formulas fields
|
||
|
||
internal const string IndexedSeriesLabelsSourceAttr = "__IndexedSeriesLabelsSource__";
|
||
|
||
//***********************************************************
|
||
//** Private data members, which store properties values
|
||
//***********************************************************
|
||
private bool _isEmptyPointIgnored = true;
|
||
|
||
private string[] _extraParameters;
|
||
|
||
/// <summary>
|
||
/// All X values are zero.
|
||
/// </summary>
|
||
private bool _zeroXValues = false;
|
||
|
||
/// <summary>
|
||
/// Utility class for Statistical formulas
|
||
/// </summary>
|
||
private StatisticFormula _statistics;
|
||
|
||
/// <summary>
|
||
/// Reference to the Common elements
|
||
/// </summary>
|
||
internal CommonElements Common;
|
||
|
||
|
||
#endregion
|
||
|
||
#region Data Formulas methods
|
||
|
||
/// <summary>
|
||
/// Default constructor
|
||
/// </summary>
|
||
public DataFormula()
|
||
{
|
||
_statistics = new StatisticFormula(this);
|
||
|
||
_extraParameters = new string[1];
|
||
_extraParameters[0] = false.ToString(System.Globalization.CultureInfo.InvariantCulture);
|
||
}
|
||
|
||
/// <summary>
|
||
/// This method calls a method from a formula module with
|
||
/// specified name.
|
||
/// </summary>
|
||
/// <param name="formulaName">Formula Name</param>
|
||
/// <param name="parameters">Formula parameters</param>
|
||
/// <param name="inputSeries">Comma separated input data series names and optional X and Y values names.</param>
|
||
/// <param name="outputSeries">Comma separated output data series names and optional X and Y values names.</param>
|
||
internal void Formula(string formulaName, string parameters, string inputSeries, string outputSeries)
|
||
{
|
||
// Array of series
|
||
Series[] inSeries;
|
||
Series[] outSeries;
|
||
|
||
// Commented out as InsertEmptyDataPoints is currently commented out.
|
||
// This field is not used anywhere else, but we might need it if we uncomment all ---- code parts in this method. (krisztb 4/29/08)
|
||
// True if formulas are statistical
|
||
//bool statisticalFormulas = false;
|
||
|
||
// Array of Y value indexes
|
||
int[] inValueIndexes;
|
||
int[] outValueIndexes;
|
||
|
||
// Matrix with double values ( used in formula modules )
|
||
double[][] inValues;
|
||
double[][] inNoEmptyValues;
|
||
double[][] outValues = null;
|
||
string[][] outLabels = null;
|
||
|
||
// Array with parameters
|
||
string[] parameterList;
|
||
|
||
// Split comma separated parameter list in the array of strings.
|
||
SplitParameters(parameters, out parameterList);
|
||
|
||
// Split comma separated series and Y values list in the array of
|
||
// Series and indexes to Y values.
|
||
ConvertToArrays(inputSeries, out inSeries, out inValueIndexes, true);
|
||
ConvertToArrays(outputSeries, out outSeries, out outValueIndexes, false);
|
||
|
||
// Create indexes if all x values are 0
|
||
//ConvertZeroXToIndex( ref inSeries );
|
||
|
||
// Set X value AxisName for output series.
|
||
foreach (Series outSeriesItem in outSeries)
|
||
{
|
||
if (inSeries[0] != null)
|
||
{
|
||
outSeriesItem.XValueType = inSeries[0].XValueType;
|
||
}
|
||
}
|
||
|
||
// This method will convert array of Series and array of Y value
|
||
// indexes to matrix of double values.
|
||
GetDoubleArray(inSeries, inValueIndexes, out inValues);
|
||
|
||
// Remove columns with empty values from matrix
|
||
if (!DifferentNumberOfSeries(inValues))
|
||
{
|
||
RemoveEmptyValues(inValues, out inNoEmptyValues);
|
||
}
|
||
else
|
||
{
|
||
inNoEmptyValues = inValues;
|
||
}
|
||
|
||
// Call a formula from formula modules
|
||
string moduleName = null;
|
||
for (int module = 0; module < Common.FormulaRegistry.Count; module++)
|
||
{
|
||
moduleName = Common.FormulaRegistry.GetModuleName(module);
|
||
Common.FormulaRegistry.GetFormulaModule(moduleName).Formula(formulaName, inNoEmptyValues, out outValues, parameterList, _extraParameters, out outLabels);
|
||
|
||
// Commented out as InsertEmptyDataPoints is currently commented out (see next block).
|
||
// It set the statisticalFormulas field that was used to test whether to insert empty data points. (krisztb 4/29/08)
|
||
//if( outValues != null )
|
||
//{
|
||
// if (moduleName == SR.FormulaNameStatisticalAnalysis)
|
||
// {
|
||
// statisticalFormulas = true;
|
||
// }
|
||
// break;
|
||
//}
|
||
|
||
// Check if formula was found by detecting output
|
||
if (outValues != null)
|
||
{
|
||
// Exit the loop
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (outValues == null)
|
||
throw new ArgumentException(SR.ExceptionFormulaNotFound(formulaName));
|
||
|
||
// Insert empty data points
|
||
|
||
//
|
||
// This has been commented out as InsertEmptyDataPoints is currently commented out.
|
||
// In its current implementation it didn't do anything other than assign the second
|
||
// parameter to the third, so ultimately it was a no op. --Microsoft 4/21/08
|
||
//
|
||
//if( !statisticalFormulas )
|
||
//{
|
||
// InsertEmptyDataPoints( inValues, outValues, out outValues );
|
||
//}
|
||
|
||
// Fill Series with results from matrix with double values using Y value indexes.
|
||
SetDoubleArray(outSeries, outValueIndexes, outValues, outLabels);
|
||
|
||
if (_zeroXValues)
|
||
{
|
||
// we have indexed series : proceed to align output series.
|
||
foreach (Series series in outSeries)
|
||
{
|
||
if (series.Points.Count > 0)
|
||
{
|
||
// get the last xValue: the formula processing is
|
||
double topXValue = series.Points[series.Points.Count - 1].XValue;
|
||
this.Common.Chart.DataManipulator.InsertEmptyPoints(1, IntervalType.Number, 0, IntervalType.Number, 1, topXValue, series);
|
||
foreach (DataPoint point in series.Points)
|
||
{
|
||
point.XValue = 0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
// Copy axis labels from the original series into the calculated series
|
||
CopyAxisLabels(inSeries, outSeries);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Copy axis labels from the original series into the calculated series
|
||
/// </summary>
|
||
/// <param name="inSeries">array of input series</param>
|
||
/// <param name="outSeries">array of output series</param>
|
||
private void CopyAxisLabels(Series[] inSeries, Series[] outSeries)
|
||
{
|
||
//Loop through the pairs of input and output series
|
||
int seriesIndex = 0;
|
||
while (seriesIndex < inSeries.Length && seriesIndex < outSeries.Length)
|
||
{
|
||
Series inputSeries = inSeries[seriesIndex];
|
||
Series outputSeries = outSeries[seriesIndex];
|
||
|
||
//Depending on whether or not the source series has X Values we need to use two different search algorithms
|
||
if (_zeroXValues)
|
||
{ //If we have the empty XValues then the source series should have all the AxisLabels
|
||
// -- set the indexed series labels source
|
||
outputSeries[DataFormula.IndexedSeriesLabelsSourceAttr] = inputSeries.Name;
|
||
}
|
||
else
|
||
{ //If the source series has XValues - loop through the input series points looking for the points with AxisLabels set
|
||
int outIndex = 0;
|
||
foreach (DataPoint inputPoint in inputSeries.Points)
|
||
{
|
||
if (!String.IsNullOrEmpty(inputPoint.AxisLabel))
|
||
{
|
||
//If the Axis label is set we need to find the corresponding point by the X value
|
||
//Most probably the points are in the same order so lets first try the corresponding point in the output series
|
||
if (outIndex < outputSeries.Points.Count && inputPoint.XValue == outputSeries.Points[outIndex].XValue)
|
||
{ // Yes, the corresponding point in the outputSeries has the same XValue as inputPoint -> copy axis label
|
||
outputSeries.Points[outIndex].AxisLabel = inputPoint.AxisLabel;
|
||
}
|
||
else
|
||
{
|
||
//The correspong point has a different x value -> lets go through output series and find the value with the same X
|
||
outIndex = 0;
|
||
foreach (DataPoint outputPoint in outputSeries.Points)
|
||
{
|
||
if (inputPoint.XValue == outputPoint.XValue)
|
||
{ //Found the point with the same XValue - copy axis label and break
|
||
outputPoint.AxisLabel = inputPoint.AxisLabel;
|
||
break;
|
||
}
|
||
outIndex++;
|
||
}
|
||
}
|
||
}
|
||
outIndex++;
|
||
}
|
||
}
|
||
//Sync next pair of input and output series...
|
||
seriesIndex++;
|
||
}
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// This method will set series X and Y values from matrix of
|
||
/// double values.
|
||
/// </summary>
|
||
/// <param name="outputSeries">Array of output series</param>
|
||
/// <param name="valueIndex">Array of Y value indexes</param>
|
||
/// <param name="outputValues">Array of doubles which will be used to fill series</param>
|
||
/// <param name="outputLabels">Array of labels</param>
|
||
internal void SetDoubleArray(Series[] outputSeries, int[] valueIndex, double[][] outputValues, string[][] outputLabels)
|
||
{
|
||
// Validation
|
||
if (outputSeries.Length != valueIndex.Length)
|
||
{
|
||
throw new ArgumentException(SR.ExceptionFormulaDataItemsNumberMismatch);
|
||
}
|
||
|
||
// Number of output series is not correct
|
||
if (outputSeries.Length < outputValues.Length - 1)
|
||
{
|
||
throw new ArgumentException(SR.ExceptionFormulaDataOutputSeriesNumberYValuesIncorrect);
|
||
}
|
||
|
||
int seriesIndex = 0;
|
||
foreach (Series series in outputSeries)
|
||
{
|
||
if (seriesIndex + 1 > outputValues.Length - 1)
|
||
{
|
||
break;
|
||
}
|
||
|
||
// If there is different number of data points.
|
||
if (series.Points.Count != outputValues[seriesIndex].Length)
|
||
{
|
||
// Delete all points
|
||
series.Points.Clear();
|
||
}
|
||
|
||
// Set the number of y values
|
||
if (series.YValuesPerPoint < valueIndex[seriesIndex])
|
||
{
|
||
series.YValuesPerPoint = valueIndex[seriesIndex];
|
||
}
|
||
|
||
for (int pointIndex = 0; pointIndex < outputValues[0].Length; pointIndex++)
|
||
{
|
||
// Create a new series and fill data
|
||
if (series.Points.Count != outputValues[seriesIndex].Length)
|
||
{
|
||
// Add data points to series.
|
||
series.Points.AddXY(outputValues[0][pointIndex], 0);
|
||
|
||
// Set Labels
|
||
if (outputLabels != null)
|
||
{
|
||
series.Points[pointIndex].Label = outputLabels[seriesIndex][pointIndex];
|
||
}
|
||
|
||
// Set empty data points or Y values
|
||
if (Double.IsNaN(outputValues[seriesIndex + 1][pointIndex]))
|
||
series.Points[pointIndex].IsEmpty = true;
|
||
else
|
||
series.Points[pointIndex].YValues[valueIndex[seriesIndex] - 1] = outputValues[seriesIndex + 1][pointIndex];
|
||
}
|
||
// Use existing series and set Y values.
|
||
else
|
||
{
|
||
if (series.Points[pointIndex].XValue != outputValues[0][pointIndex] && !_zeroXValues)
|
||
{
|
||
throw new InvalidOperationException(SR.ExceptionFormulaXValuesNotAligned);
|
||
}
|
||
|
||
// Set empty data points or Y values
|
||
if (Double.IsNaN(outputValues[seriesIndex + 1][pointIndex]))
|
||
series.Points[pointIndex].IsEmpty = true;
|
||
else
|
||
{
|
||
series.Points[pointIndex].YValues[valueIndex[seriesIndex] - 1] = outputValues[seriesIndex + 1][pointIndex];
|
||
|
||
// Set Labels
|
||
if (outputLabels != null)
|
||
{
|
||
series.Points[pointIndex].Label = outputLabels[seriesIndex][pointIndex];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
seriesIndex++;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// This method will convert a string with information about
|
||
/// series and y values to two arrays. The first array will
|
||
/// contain series and the second array will contain
|
||
/// corresponding indexes to y values for every series.
|
||
/// The arrays have to have the same number of items.
|
||
/// </summary>
|
||
/// <param name="inputString">A string with information about series and Y values</param>
|
||
/// <param name="seiesArray">Array of Data Series</param>
|
||
/// <param name="valueArray">Array of Y value indexes</param>
|
||
/// <param name="inputSeries">Do not create new series if input series are used</param>
|
||
private void ConvertToArrays(string inputString, out Series[] seiesArray, out int[] valueArray, bool inputSeries)
|
||
{
|
||
// Split string by comma
|
||
string[] subStrings = inputString.Split(',');
|
||
|
||
// Create array of series
|
||
seiesArray = new Series[subStrings.Length];
|
||
|
||
// Create array of integers - values
|
||
valueArray = new int[subStrings.Length];
|
||
|
||
int index = 0;
|
||
|
||
foreach (string str in subStrings)
|
||
{
|
||
string[] parts = str.Split(':');
|
||
|
||
|
||
// There must be at least one and no more than two result strings
|
||
if (parts.Length < 1 && parts.Length > 2)
|
||
{
|
||
throw (new ArgumentException(SR.ExceptionFormulaDataFormatInvalid(str)));
|
||
}
|
||
|
||
// Initialize value index as first Y value (default)
|
||
int valueIndex = 1;
|
||
|
||
// Check specified value type
|
||
if (parts.Length == 2)
|
||
{
|
||
if (parts[1].StartsWith("Y", StringComparison.Ordinal))
|
||
{
|
||
parts[1] = parts[1].TrimStart('Y');
|
||
|
||
if (parts[1].Length == 0)
|
||
{
|
||
valueIndex = 1;
|
||
}
|
||
else
|
||
{
|
||
// Try to convert the rest of the string to integer
|
||
try
|
||
{
|
||
valueIndex = Int32.Parse(parts[1], System.Globalization.CultureInfo.InvariantCulture);
|
||
}
|
||
catch (System.Exception)
|
||
{
|
||
throw (new ArgumentException(SR.ExceptionFormulaDataFormatInvalid(str)));
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
throw (new ArgumentException(SR.ExceptionFormulaDataSeriesNameNotFound(str)));
|
||
}
|
||
}
|
||
|
||
// Set Y value indexes
|
||
valueArray[index] = valueIndex;
|
||
|
||
// Set series
|
||
try
|
||
{
|
||
seiesArray[index] = Common.DataManager.Series[parts[0].Trim()];
|
||
}
|
||
catch (System.Exception)
|
||
{
|
||
// Series doesn't exist.
|
||
if (!inputSeries)
|
||
{
|
||
// Create a new series if output series
|
||
Common.DataManager.Series.Add(new Series(parts[0]));
|
||
seiesArray[index] = Common.DataManager.Series[parts[0]];
|
||
}
|
||
else
|
||
throw (new ArgumentException(SR.ExceptionFormulaDataSeriesNameNotFoundInCollection(str)));
|
||
}
|
||
index++;
|
||
}
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// Returns Jagged Arrays of doubles from array of series.
|
||
/// A jagged array is merely an array of arrays and
|
||
/// it doesn't have to be square. The first item is array of
|
||
/// X values from the first series
|
||
/// </summary>
|
||
/// <param name="inputSeries">Array of Data Series</param>
|
||
/// <param name="valueIndex">Array with indexes which represent value from data point: 0 = X, 1 = Y, 2 = Y2, 3 = Y3</param>
|
||
/// <param name="output">Jagged Arrays of doubles</param>
|
||
private void GetDoubleArray(Series[] inputSeries, int[] valueIndex, out double[][] output)
|
||
{
|
||
GetDoubleArray(inputSeries, valueIndex, out output, false);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Returns Jagged Arrays of doubles from array of series.
|
||
/// A jagged array is merely an array of arrays and
|
||
/// it doesn't have to be square. The first item is array of
|
||
/// X values from the first series
|
||
/// </summary>
|
||
/// <param name="inputSeries">Array of Data Series</param>
|
||
/// <param name="valueIndex">Array with indexes which represent value from data point: 0 = X, 1 = Y, 2 = Y2, 3 = Y3</param>
|
||
/// <param name="output">Jagged Arrays of doubles</param>
|
||
/// <param name="ignoreZeroX">Ignore Zero X values</param>
|
||
private void GetDoubleArray(Series[] inputSeries, int[] valueIndex, out double[][] output, bool ignoreZeroX)
|
||
{
|
||
// Allocate a memory.
|
||
output = new double[inputSeries.Length + 1][];
|
||
|
||
// Check the length of the array of series and array of value indexes.
|
||
if (inputSeries.Length != valueIndex.Length)
|
||
{
|
||
throw new ArgumentException(SR.ExceptionFormulaDataItemsNumberMismatch2);
|
||
}
|
||
|
||
// Find Maximum number of data points
|
||
int maxNumOfPoints = int.MinValue;
|
||
Series seriesWidthMaxPoints = null;
|
||
foreach (Series series in inputSeries)
|
||
{
|
||
if (maxNumOfPoints < series.Points.Count)
|
||
{
|
||
maxNumOfPoints = series.Points.Count;
|
||
seriesWidthMaxPoints = series;
|
||
}
|
||
}
|
||
|
||
// *********************************************************
|
||
// Set X values
|
||
// *********************************************************
|
||
|
||
// Check if all X values are zero
|
||
foreach (DataPoint point in inputSeries[0].Points)
|
||
{
|
||
_zeroXValues = true;
|
||
|
||
if (point.XValue != 0.0)
|
||
{
|
||
_zeroXValues = false;
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (_zeroXValues && !ignoreZeroX)
|
||
{
|
||
// Check X values input alignment
|
||
CheckXValuesAlignment(inputSeries);
|
||
}
|
||
|
||
|
||
// Data point index
|
||
int indexPoint = 0;
|
||
|
||
// Allocate memory for X values.
|
||
output[0] = new double[maxNumOfPoints];
|
||
|
||
// Data Points loop
|
||
foreach (DataPoint point in seriesWidthMaxPoints.Points)
|
||
{
|
||
// Set X value
|
||
if (_zeroXValues)
|
||
output[0][indexPoint] = (double)indexPoint + 1.0;
|
||
else
|
||
output[0][indexPoint] = point.XValue;
|
||
|
||
// Increase data point index.
|
||
indexPoint++;
|
||
}
|
||
|
||
// *********************************************************
|
||
// Set Y values
|
||
// *********************************************************
|
||
// Data Series Loop
|
||
int indexSeries = 1;
|
||
foreach (Series series in inputSeries)
|
||
{
|
||
output[indexSeries] = new double[series.Points.Count];
|
||
indexPoint = 0;
|
||
|
||
// Data Points loop
|
||
foreach (DataPoint point in series.Points)
|
||
{
|
||
// Set Y values
|
||
if (point.IsEmpty)
|
||
// IsEmpty data point
|
||
output[indexSeries][indexPoint] = double.NaN;
|
||
else
|
||
{
|
||
try
|
||
{
|
||
output[indexSeries][indexPoint] = point.YValues[valueIndex[indexSeries - 1] - 1];
|
||
}
|
||
catch (System.Exception)
|
||
{
|
||
throw new ArgumentException(SR.ExceptionFormulaYIndexInvalid);
|
||
}
|
||
}
|
||
|
||
// Increase data point index.
|
||
indexPoint++;
|
||
}
|
||
// Increase data series index.
|
||
indexSeries++;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Merge, split or move Y values of the series.
|
||
/// </summary>
|
||
/// <param name="inputSeries">Comma separated list of input data series names and optional X and Y values names.</param>
|
||
/// <param name="outputSeries">Comma separated list of output data series names and optional X and Y values names.</param>
|
||
public void CopySeriesValues(string inputSeries, string outputSeries)
|
||
{
|
||
if (inputSeries == null)
|
||
throw new ArgumentNullException("inputSeries");
|
||
if (outputSeries == null)
|
||
throw new ArgumentNullException("outputSeries");
|
||
|
||
Series[] inSeries;
|
||
Series[] outSeries;
|
||
int[] inValueIndexes;
|
||
int[] outValueIndexes;
|
||
double[][] inValues;
|
||
double[][] outValues;
|
||
|
||
// Convert string with information about series and Y values
|
||
// to array of series and indexes to Y values.
|
||
ConvertToArrays(inputSeries, out inSeries, out inValueIndexes, true);
|
||
ConvertToArrays(outputSeries, out outSeries, out outValueIndexes, false);
|
||
|
||
// The number of input and output series are different.
|
||
if (inSeries.Length != outSeries.Length)
|
||
{
|
||
throw new ArgumentException(SR.ExceptionFormulaInputOutputSeriesMismatch);
|
||
}
|
||
|
||
// Check if output series points exist. If they do not exist
|
||
// create data points which are copy of Input series data points
|
||
for (int indexSeries = 0; indexSeries < inSeries.Length; indexSeries++)
|
||
{
|
||
Series[] series = new Series[2];
|
||
series[0] = inSeries[indexSeries];
|
||
series[1] = outSeries[indexSeries];
|
||
if (series[1].Points.Count == 0)
|
||
{
|
||
foreach (DataPoint point in series[0].Points)
|
||
{
|
||
DataPoint clonePoint = point.Clone();
|
||
clonePoint.series = series[1];
|
||
series[1].Points.Add(clonePoint);
|
||
}
|
||
}
|
||
}
|
||
|
||
// Check alignment of X values.
|
||
for (int indexSeries = 0; indexSeries < inSeries.Length; indexSeries++)
|
||
{
|
||
Series[] series = new Series[2];
|
||
series[0] = inSeries[indexSeries];
|
||
series[1] = outSeries[indexSeries];
|
||
CheckXValuesAlignment(series);
|
||
}
|
||
|
||
// Covert Series X and Y values to arrays of doubles
|
||
GetDoubleArray(inSeries, inValueIndexes, out inValues, true);
|
||
|
||
outValues = new double[inValues.Length][];
|
||
|
||
// Copy Series X and Y values.
|
||
for (int seriesIndex = 0; seriesIndex < inValues.Length; seriesIndex++)
|
||
{
|
||
outValues[seriesIndex] = new double[inValues[seriesIndex].Length];
|
||
for (int pointIndex = 0; pointIndex < inValues[seriesIndex].Length; pointIndex++)
|
||
{
|
||
outValues[seriesIndex][pointIndex] = inValues[seriesIndex][pointIndex];
|
||
}
|
||
}
|
||
|
||
// Copy Series X and Y value Types.
|
||
for (int seriesIndx = 0; seriesIndx < inSeries.Length; seriesIndx++)
|
||
{
|
||
// X value type
|
||
if (outSeries[seriesIndx].XValueType == ChartValueType.Auto)
|
||
{
|
||
outSeries[seriesIndx].XValueType = inSeries[seriesIndx].XValueType;
|
||
outSeries[seriesIndx].autoXValueType = inSeries[seriesIndx].autoXValueType;
|
||
}
|
||
|
||
// Y value type.
|
||
if (outSeries[seriesIndx].YValueType == ChartValueType.Auto)
|
||
{
|
||
outSeries[seriesIndx].YValueType = inSeries[seriesIndx].YValueType;
|
||
outSeries[seriesIndx].autoYValueType = inSeries[seriesIndx].autoYValueType;
|
||
}
|
||
|
||
seriesIndx++;
|
||
}
|
||
|
||
SetDoubleArray(outSeries, outValueIndexes, outValues, null);
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// This method will first copy input matrix to output matrix
|
||
/// then will remove columns, which have
|
||
/// one or more empty values (NaN) from the output matrix. This
|
||
/// method will set all values from column of input matrix
|
||
/// to be empty (NaN) if one or more values of that column
|
||
/// are empty.
|
||
/// </summary>
|
||
/// <param name="input">Input matrix with empty values</param>
|
||
/// <param name="output">Output matrix without empty values</param>
|
||
private void RemoveEmptyValues(double[][] input, out double[][] output)
|
||
{
|
||
// Allocate memory
|
||
output = new double[input.Length][];
|
||
int seriesIndex = 0;
|
||
|
||
int numberOfRows = 0;
|
||
|
||
// Set Nan for all data points with same index in input array
|
||
// Data point loop
|
||
for (int pointIndex = 0; pointIndex < input[0].Length; pointIndex++)
|
||
{
|
||
bool isEmpty = false;
|
||
// Series loop
|
||
// Find empty data point with same point index
|
||
for (seriesIndex = 0; seriesIndex < input.Length; seriesIndex++)
|
||
{
|
||
if (seriesIndex >= input[seriesIndex].Length)
|
||
continue;
|
||
if (Double.IsNaN(input[seriesIndex][pointIndex]))
|
||
isEmpty = true;
|
||
}
|
||
|
||
if (!isEmpty)
|
||
{
|
||
numberOfRows++;
|
||
}
|
||
|
||
// There is empty data point
|
||
if (isEmpty)
|
||
{
|
||
// Set all points with same index to be empty
|
||
for (seriesIndex = 1; seriesIndex < input.Length; seriesIndex++)
|
||
{
|
||
input[seriesIndex][pointIndex] = Double.NaN;
|
||
}
|
||
}
|
||
}
|
||
|
||
// Copy input matrix to output matrix without empty columns.
|
||
for (seriesIndex = 0; seriesIndex < input.Length; seriesIndex++)
|
||
{
|
||
output[seriesIndex] = new double[numberOfRows];
|
||
int outPointIndex = 0;
|
||
for (int pointIndex = 0; pointIndex < input[0].Length; pointIndex++)
|
||
{
|
||
if (pointIndex >= input[seriesIndex].Length)
|
||
continue;
|
||
if (!double.IsNaN(input[1][pointIndex]))
|
||
{
|
||
output[seriesIndex][outPointIndex] = input[seriesIndex][pointIndex];
|
||
outPointIndex++;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
/*
|
||
/// <summary>
|
||
/// This method will compare a input matrix with empty data
|
||
/// points and output matrix without empty data points and
|
||
/// add empty data points to output matrix according to
|
||
/// input matrix empty data point positions.
|
||
/// </summary>
|
||
/// <param name="input">Matrix With input data</param>
|
||
/// <param name="inputWithoutEmpty">Matrix without empty data points</param>
|
||
/// <param name="output">New Matrix with inserted data points</param>
|
||
*/
|
||
//private void InsertEmptyDataPoints( double [][] input, double [][] inputWithoutEmpty, out double [][] output )
|
||
//{
|
||
|
||
|
||
// *** NOTE ***
|
||
//
|
||
//
|
||
// This method is only called in one location as of this writing.
|
||
// Therefore the entire method is being commented out for now. We wish
|
||
// to preserve the code itself as it may be re-implemented in the future.
|
||
// --Microsoft 4/21/08
|
||
//
|
||
// ************
|
||
|
||
|
||
|
||
//output = inputWithoutEmpty;
|
||
//return;
|
||
|
||
//
|
||
// NOTE: Inserting empty points in the result data after applying the formula
|
||
// causes issues. The algorithm below do not cover most of the common spzces
|
||
// and as a result the formula data is completly destroyed.
|
||
//
|
||
// By removing this code the result data set will have "missing" points instaed
|
||
// of empty.
|
||
// - AG
|
||
//
|
||
|
||
/*
|
||
|
||
// Input matrix can have only empty rows. If one value
|
||
// is empty all values from a row have to be empty.
|
||
|
||
// Find the number of empty rows
|
||
int NumberOfEmptyRows = 0;
|
||
foreach( double val in input[1] )
|
||
{
|
||
if( Double.IsNaN( val ) )
|
||
{
|
||
NumberOfEmptyRows++;
|
||
}
|
||
}
|
||
|
||
if( NumberOfEmptyRows == 0 ||
|
||
inputWithoutEmpty[0].Length > input[0].Length)
|
||
{
|
||
output = inputWithoutEmpty;
|
||
return;
|
||
}
|
||
|
||
output = new double[input.Length][];
|
||
// Series loop
|
||
for( int seriesIndex = 0; seriesIndex < input.Length; seriesIndex++ )
|
||
{
|
||
int inputPointIndex = 0;
|
||
int emptyPointIndex = 0;
|
||
|
||
// Skip input index if points are not aligned .
|
||
while( input[0][inputPointIndex] != inputWithoutEmpty[0][0] && inputPointIndex < input[0].Length )
|
||
{
|
||
inputPointIndex++;
|
||
}
|
||
|
||
output[seriesIndex] = new double[inputWithoutEmpty[0].Length + NumberOfEmptyRows - inputPointIndex];
|
||
|
||
// Data Point loop
|
||
for( int pointIndex = 0; pointIndex < output[seriesIndex].Length; pointIndex++ )
|
||
{
|
||
if( inputPointIndex < input[0].Length &&
|
||
inputPointIndex < input[1].Length )
|
||
{
|
||
// If the point Y value is empty (NaN) insert empty (NaN) for all values.
|
||
if( double.IsNaN( input[1][inputPointIndex] ) )
|
||
{
|
||
output[seriesIndex][pointIndex] = input[seriesIndex][inputPointIndex];
|
||
emptyPointIndex--;
|
||
}
|
||
else if( input[0][inputPointIndex] == inputWithoutEmpty[0][emptyPointIndex] )
|
||
{
|
||
output[seriesIndex][pointIndex] = inputWithoutEmpty[seriesIndex][emptyPointIndex];
|
||
}
|
||
else
|
||
{
|
||
output[0][pointIndex] = inputWithoutEmpty[0][emptyPointIndex];
|
||
output[seriesIndex][pointIndex] = inputWithoutEmpty[seriesIndex][emptyPointIndex];
|
||
}
|
||
}
|
||
else
|
||
{
|
||
output[seriesIndex][pointIndex] = inputWithoutEmpty[seriesIndex][emptyPointIndex];
|
||
}
|
||
|
||
inputPointIndex++;
|
||
emptyPointIndex++;
|
||
}
|
||
}
|
||
*/
|
||
//}
|
||
|
||
|
||
/// <summary>
|
||
/// This method splits a string with comma separated
|
||
/// parameters to the array of strings with parameters.
|
||
/// </summary>
|
||
/// <param name="parameters">a string with comma separated parameters</param>
|
||
/// <param name="parameterList">the array of strings with parameters</param>
|
||
private void SplitParameters(string parameters, out string[] parameterList)
|
||
{
|
||
// Split string by comma
|
||
parameterList = parameters.Split(',');
|
||
|
||
for (Int32 i = 0; i < parameterList.Length; i++)
|
||
{
|
||
parameterList[i] = parameterList[i].Trim();
|
||
}
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// Check if series have different number of series.
|
||
/// </summary>
|
||
/// <param name="input">Input series.</param>
|
||
/// <returns>true if there is different number of series.</returns>
|
||
private static bool DifferentNumberOfSeries(double[][] input)
|
||
{
|
||
for (int index = 0; index < input.Length - 1; index++)
|
||
{
|
||
if (input[index].Length != input[index + 1].Length)
|
||
{
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
/// <summary>
|
||
/// This method will check if X values from different series
|
||
/// are aligned.
|
||
/// </summary>
|
||
/// <param name="series">Array of series</param>
|
||
internal void CheckXValuesAlignment(Series[] series)
|
||
{
|
||
// Check aligment only if more than 1 series provided
|
||
if (series.Length > 1)
|
||
{
|
||
// Series loop
|
||
for (int seriesIndex = 0; seriesIndex < series.Length - 1; seriesIndex++)
|
||
{
|
||
// Check the number of data points
|
||
if (series[seriesIndex].Points.Count != series[seriesIndex + 1].Points.Count)
|
||
{
|
||
throw new ArgumentException(SR.ExceptionFormulaDataSeriesAreNotAlignedDifferentDataPoints(series[seriesIndex].Name, series[seriesIndex + 1].Name));
|
||
}
|
||
|
||
// Data points loop
|
||
for (int pointIndex = 0; pointIndex < series[seriesIndex].Points.Count; pointIndex++)
|
||
{
|
||
// Check X values.
|
||
if (series[seriesIndex].Points[pointIndex].XValue != series[seriesIndex + 1].Points[pointIndex].XValue)
|
||
throw new ArgumentException(SR.ExceptionFormulaDataSeriesAreNotAlignedDifferentXValues(series[seriesIndex].Name, series[seriesIndex + 1].Name));
|
||
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
#endregion
|
||
|
||
#region Data Formulas Financial methods
|
||
/// <summary>
|
||
/// This method calls a method from a formula module with
|
||
/// specified name.
|
||
/// </summary>
|
||
/// <param name="formulaName">Formula Name</param>
|
||
/// <param name="inputSeries">Input series</param>
|
||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||
public void FinancialFormula(FinancialFormula formulaName, Series inputSeries)
|
||
{
|
||
FinancialFormula(formulaName, inputSeries, inputSeries);
|
||
}
|
||
|
||
/// <summary>
|
||
/// This method calls a method from a formula module with
|
||
/// specified name.
|
||
/// </summary>
|
||
/// <param name="formulaName">Formula Name</param>
|
||
/// <param name="inputSeries">Input series</param>
|
||
/// <param name="outputSeries">Output series</param>
|
||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||
public void FinancialFormula(FinancialFormula formulaName, Series inputSeries, Series outputSeries)
|
||
{
|
||
FinancialFormula(formulaName, "", inputSeries, outputSeries);
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// This method calls a method from a formula module with
|
||
/// specified name.
|
||
/// </summary>
|
||
/// <param name="formulaName">Formula Name</param>
|
||
/// <param name="parameters">Formula parameters</param>
|
||
/// <param name="inputSeries">Input series</param>
|
||
/// <param name="outputSeries">Output series</param>
|
||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||
public void FinancialFormula(FinancialFormula formulaName, string parameters, Series inputSeries, Series outputSeries)
|
||
{
|
||
if (inputSeries == null)
|
||
throw new ArgumentNullException("inputSeries");
|
||
if (outputSeries == null)
|
||
throw new ArgumentNullException("outputSeries");
|
||
FinancialFormula(formulaName, parameters, inputSeries.Name, outputSeries.Name);
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// This method calls a method from a formula module with
|
||
/// specified name.
|
||
/// </summary>
|
||
/// <param name="formulaName">Formula Name</param>
|
||
/// <param name="inputSeries">Comma separated list of input series names and optional X and Y values names.</param>
|
||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||
public void FinancialFormula(FinancialFormula formulaName, string inputSeries)
|
||
{
|
||
FinancialFormula(formulaName, inputSeries, inputSeries);
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// This method calls a method from a formula module with
|
||
/// specified name.
|
||
/// </summary>
|
||
/// <param name="formulaName">Formula Name</param>
|
||
/// <param name="inputSeries">Comma separated list of input series names and optional X and Y values names.</param>
|
||
/// <param name="outputSeries">Comma separated list of output series names and optional X and Y values names.</param>
|
||
[SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")]
|
||
public void FinancialFormula(FinancialFormula formulaName, string inputSeries, string outputSeries)
|
||
{
|
||
FinancialFormula(formulaName, "", inputSeries, outputSeries);
|
||
}
|
||
|
||
/// <summary>
|
||
/// This method calls a method from a formula module with
|
||
/// specified name.
|
||
/// </summary>
|
||
/// <param name="formulaName">Formula Name</param>
|
||
/// <param name="parameters">Formula parameters</param>
|
||
/// <param name="inputSeries">Comma separated list of input series names and optional X and Y values names.</param>
|
||
/// <param name="outputSeries">Comma separated list of output series names and optional X and Y values names.</param>
|
||
public void FinancialFormula(FinancialFormula formulaName, string parameters, string inputSeries, string outputSeries)
|
||
{
|
||
if (inputSeries == null)
|
||
throw new ArgumentNullException("inputSeries");
|
||
if (outputSeries == null)
|
||
throw new ArgumentNullException("outputSeries");
|
||
|
||
// Get formula info
|
||
FormulaInfo formulaInfo = FormulaHelper.GetFormulaInfo(formulaName);
|
||
|
||
// Provide default parameters if necessary
|
||
if (string.IsNullOrEmpty(parameters))
|
||
{
|
||
parameters = formulaInfo.SaveParametersToString();
|
||
}
|
||
else
|
||
{
|
||
formulaInfo.CheckParameterString(parameters);
|
||
}
|
||
|
||
// Fix the InputSeries and Outputseries for cases when the series field names are not provided
|
||
SeriesFieldList inputFields = SeriesFieldList.FromString(this.Common.Chart, inputSeries, formulaInfo.InputFields);
|
||
SeriesFieldList outputFields = SeriesFieldList.FromString(this.Common.Chart, outputSeries, formulaInfo.OutputFields);
|
||
|
||
if (inputFields != null) inputSeries = inputFields.ToString();
|
||
if (outputFields != null) outputSeries = outputFields.ToString();
|
||
|
||
Formula(formulaName.ToString(), parameters, inputSeries, outputSeries);
|
||
}
|
||
#endregion
|
||
|
||
#region Data Formulas properties
|
||
|
||
/// <summary>
|
||
/// Gets or sets a flag which indicates whether
|
||
/// empty points are ignored while performing calculations;
|
||
/// otherwise, empty points are treated as zeros.
|
||
/// </summary>
|
||
public bool IsEmptyPointIgnored
|
||
{
|
||
get
|
||
{
|
||
return _isEmptyPointIgnored;
|
||
}
|
||
set
|
||
{
|
||
_isEmptyPointIgnored = value;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/// <summary>
|
||
/// Gets or sets a flag which indicates whether
|
||
/// to start formulas like rolling average from zero.
|
||
/// </summary>
|
||
public bool IsStartFromFirst
|
||
{
|
||
get
|
||
{
|
||
return bool.Parse(_extraParameters[0]);
|
||
}
|
||
set
|
||
{
|
||
if (value)
|
||
_extraParameters[0] = true.ToString(System.Globalization.CultureInfo.InvariantCulture);
|
||
else
|
||
_extraParameters[0] = false.ToString(System.Globalization.CultureInfo.InvariantCulture);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Returns a reference to the statistical utility class.
|
||
/// </summary>
|
||
public StatisticFormula Statistics
|
||
{
|
||
get
|
||
{
|
||
return _statistics;
|
||
}
|
||
}
|
||
|
||
|
||
#endregion
|
||
}
|
||
|
||
|
||
|
||
}
|