New Version 8.1!

Supports .NET 6.0. Try it for free with our fully functional 60-day trial version.

Get from Nuget

QuickStart Samples

Variable Transformations QuickStart Sample (C#)

Illustrates how to perform a range of transformations on statistical data in C#.

Visual Basic code F# code IronPython code Back to QuickStart Samples

using System;
using System.Data;
using System.Data.OleDb;

using Extreme.Mathematics;
using Extreme.DataAnalysis;

namespace Extreme.Numerics.QuickStart.CSharp
    /// <summary>
    /// Illustrates various kinds of transformations of numerical variables
    /// by showing how to compute several financial indicators.
    /// </summary>
    class VariableTransforms
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        static void Main(string[] args)
            // We use a TimeSeriesCollection to load the data.
            var timeSeries = LoadTimeSeriesData();

            // The following are all equivalent ways of getting
            // a strongly typed vector from a data frame:
            var open = timeSeries["Open"].As<double>();
            var close = timeSeries.GetColumn("Close");
            var high = timeSeries.GetColumn<double>("High");
            var low = (Vector<double>)timeSeries["Low"];

            var volume = timeSeries["Volume"].As<double>();

            // Arithmetic operations

            // The NumericalVariable class defines the standard
            // arithmetic operators. Operands can be either
            // numerical variables or constants.

            // The Typical Price (TP) is the average of the day's high, low and close:
            var TP = (high + low + close) / 3;

            // Exponentiation is available through the Power method:
            var inverseVolume = Vector.ElementwisePow(volume, -1);

            // Simple transformations

            // By including the Extreme.Statistics namespace,
            // we've enabled a number of extension methods
            // on vectors that compute common transformations.

            // The Lag method returns a variable whose observations 
            // are moved ahead by the specified amount:
            var close1 = close.Lag(1);
            // You can get cumulative sums and products:
            var cumVolume = volume.CumulativeSum();

            // Indicators of change

            // You can get the absolute change, percent change, 
            // or (exponential) growth rate of a variable. The optional
            // parameter is the number of periods to go back.
            // The default is 1.
            var closeChange = close.Change(10);
            // You can extrapolate the change to a longer number of periods.
            // The additional argument is the number of large periods.
            var monthyChange = close.ExtrapolatedChange(10, 20);

            // Moving averages

            // You can get simple, exponential, and weighted moving averages.
            var MA20 = close.MovingAverage(20);

            // Weighted moving averages can use either a fixed array or vector
            // to specify the weight. The weights are automatically normalized.
            double[] weights = {1.0, 2.0, 3.0};
            var WMA3 = close.WeightedMovingAverage(weights);
            // You can also specify another variable for the weights.
            // In this case, the corresponding observations are used.
            // For example, to obtain the volume weighted average
            // of the close price over a 14 day period, you can write:
            var VWA14 = close.WeightedMovingAverage(14, volume);

            // Other statistics, such as maximum, minimum and standard 
            // deviation are also available.

            // Misc. transforms

            // The Box-Cox transform is often used to reduce the effects
            // of non-normality of a variable. It takes one parameter,
            // which must be between 0 and 1.
            var bcVolume = volume.BoxCoxTransform(0.4);

            // Creating more complicated indicators

            // All these transformations can be combined to create
            // more complicated transformations. We give some examples
            // of common Technical Analysis indicators.

            // The Accumulation Distribution is a leading indicator of price movements.
            // It is used in many other indicators.
            // The formula uses only arithmetic operations:
            var AD = Vector.ElementwiseMultiply(volume,
                Vector.ElementwiseDivide(close - open, high - low));
            // The Chaikin oscillator is used to monitor the flow of money into
            // and out of a market.  It is the difference between a 3 day and a 10 day
            // moving average of the Accumulation Distribution.
            // We use the GetExponentialMovingAverage method for this purpose.
            var CO = AD.ExponentialMovingAverage(3) - AD.ExponentialMovingAverage(10);

            // Bollinger bands provide an envelope around the price that indicates
            // whether the current price level is relatively high or low.
            // It uses a 20 day simple average as a central line:
            var TPMA20 = TP.MovingAverage(20);
            // The actual bands are at 2 standard deviations (over the same period)
            // from the central line. We have to pass the moving average
            // over the same period as the second parameter.
            var SD20 = TP.MovingStandardDeviation(20, TPMA20);
            var BOLU = MA20 + 2*SD20;
            var BOLD = MA20 - 2*SD20;

            // The Relative Strength Index is an index that compares 
            // the average price gain to the average loss.
            // The GetPositiveToNegativeIndex method performs this
            // calculation in one operation. The first argument is the period.
            // The second argument is the variable that determines
            // if an observation counts towards the plus or the minus side.
            var change = close.Change(1);
            var RSI = change.PositiveToNegativeIndex(14, change);

            // Finally, let's print some of our results:
            int index = timeSeries.RowIndex.Lookup(new DateTime(2002, 9, 17));
            Console.WriteLine("Data for September 17, 2002:");
            Console.WriteLine("Accumulation Distribution (in millions): {0:F2}", 
                AD[index] / 1000000);
            Console.WriteLine("Chaikin Oscillator (in millions): {0:F2}", 
                CO[index] / 1000000);
            Console.WriteLine("Bollinger Band (Upper): {0:F2}", BOLU[index]);
            Console.WriteLine("Bollinger Band (Central): {0:F2}", TPMA20[index]);
            Console.WriteLine("Bollinger Band (Lower): {0:F2}", BOLD[index]);
            Console.WriteLine("Relative Strength Index: {0:F2}", RSI[index]);

            Console.Write("Press any key to exit.");

        private static DataFrame<DateTime, string> LoadTimeSeriesData()
            string filename = @"..\..\..\..\Data\MicrosoftStock.xls";
            string connectionString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source="+filename+";Extended Properties=\"Excel 8.0;HDR=Yes;IMEX=1\"";
            OleDbConnection cnn = null;
            DataSet ds = new DataSet();
                cnn = new OleDbConnection(connectionString);
                OleDbDataAdapter adapter = new OleDbDataAdapter("Select * from [MicrosoftStock$]", cnn);
            catch (OleDbException ex)
                if (cnn != null)
            return DataFrame.FromDataTable<DateTime>(ds.Tables[0], "Date");