The frequency of a time series determines the time period covered by each observation. It is possible to derive a
new time series from an existing one so that each observation in the new series covers a longer time period.
Transforming the frequency of a time series involves combining the observations into groups corresponding to the
longer time frame, and for each group calculating one value that represents all observations in the group. For
example, the daily volume of a stock can be combined into the monthly volume by adding all the observations for the
month. An object that calculates a new value from a group of observations is called an aggregator.
An aggregator combines a group of observations into a single observation. When a TimeSeriesCollection is converted to a new,
longer time frame, each of the member variables of the collection is transformed by applying an aggregator function
to the observations over each time interval. The Aggregator class
serves as the abstract base class for aggregator functions.
The Aggregator class has one instance method, Apply()()()() with two overloads. The first overload applies the
aggregator to a variable. It takes two parameters. The first is a Variable object that represents the variable that is to be aggregated. The
second parameter is an integer array that contains the indexes into the variable of the boundaries of each interval.
This method returns a new Variable that contains the aggregated data. The type of the variable is
determined by the actual aggregator implementation.
The second overload contains the actual implementation of the aggregator function. It calculates the aggregated
value for an interval of observations of the variable. It takes three parameters. The first is once again the
variable to be aggregated. The second and third parameters are the indexes of the first and last observation to be
The Aggregator class has a number of static fields and methods
that return ready-to-use aggregators. The Count aggregator
returns the number of observations in each interval. The resulting variable is always a The NumericalVariable.
The First and Last fields represent an aggregator that returns the first or last
observation in each interval. The Nth(Int32) method returns an
aggregator that returns the observation at the specified position in the interval. It takes one parameter: the
zero-based position of the observation. A value of zero corresponds to the first element. For these aggregators, the
type of variable is the same as the variable being aggregated.
The Minimum and Maximum fields represent an aggregator that returns the minimum or
maximum value of the observations in the interval. It is only meaningful for numerical and date/time variables, and
for categorical variables whose scale is ordered. In all other cases, the aggregator returns a missing value.
Some aggregators can be applied only to numerical variables. These aggregators calculate the Average, Sum,
StandardDeviation, or Variance of the observations in each interval.
Finally, the WeightedAverage(NumericalVariable) method returns an
aggregator that uses the observations of another variable to compute a weighted average of the observations in each
interval. This type of aggregator can be used, for example, to calculate the volume-weighted average of stock
Transforming the frequency
To transform the frequency of a TimeSeriesCollection , every variable in the
collection that you wish to transform must have its Aggregator property set. Most commonly, this is one of the static
(Shared in Visual Basic) members of the Aggregator class.
Once these properties have been set, you can call the TransformFrequency()()()()
method. This method has three overloads. The first takes just one parameter: a DateTimeUnit value that specifies the frequency of the new time series
collection. The example below transforms a daily series into a monthly series:
TimeSeriesCollection daily =
TimeSeriesCollection monthly = daily.TransformFrequency(DateTimeUnit.Monthly);
Dim daily As TimeSeriesCollection = ' ...
Dim monthly As TimeSeriesCollection = daily.TransformFrequency(DateTimeUnit.Monthly)
The second overload takes three parameters. The first and second parameters are DateTime values that
specify the lower bound and the upper bound of the new time series. The new time series will only contain
observations from the specified period. The third parameter is once again a DateTimeUnit value that specifies the frequency of the new time series
The third overload takes a total of seven parameters. As before, the first three specify the upper and lower bound
of the time period, and the time unit of the new time series collection. The fourth and fifth parameters are
BoundaryIntervalBehavior values that specify how the
first and last boundary intervals are to be handled if the interval does not correspond to a complete time unit. The
possible values are listed in the table below:
The entire interval is excluded.
The interval is included.
The interval is extended to a full larger interval and the extended interval is included.
A value of Exclude means that a partial interval is to be excluded from the time series. There is no
observation corresponding to the interval in the new time series. A value of Include means that a
partial interval is included as it is. The aggregated value will cover only a partial time period. A value of
CompleteAndInclude means that a partial interval is to be extended towards the past (if it is the first)
or towards the future (if it is the last) so that it covers a complete time unit. The aggregated observations based
on this entire interval are then included in the time series.
The last two parameters are an integer and a DateTimeUnit value that together specify an offset of
the time periods within the larger time unit. For instance, a time series with a quarterly frequency may have the
quarter start at the 2nd month of the quarter (February, May, August, November). In this case, the sixth parameter is
set to one, and the seventh is set to DateTimeUnit.Month.
The following example loads data from an Excel worksheet into a TimeSeriesCollection. The data
contains price information for a stock (open, close, high, low, and volume). Appropriate aggregators are set and a
new TimeSeriesCollection object is created that contains the monthly data for the year 1996:
Defining custom aggregators
We conclude this section by discussing how to create a custom aggregator. To create a custom aggregator, take the
- Create a new class that inherits from Aggregator.
- In the class constructor, call the base constructor with the type of variable that will be returned by the
aggregator. If the type can only be determined at runtime, call the base constructor with no arguments.
- Override the Apply()()()() method.
The following example creates an aggregator that returns the midpoint between the first and the last observation
in the interval. (For the sake of clarity, handling of special cases and argument validation have been omitted.)
public class MidpointAggregator : Aggregator
public MidpointAggregator() : base(typeof(NumericalVariable))
public override object Apply(Variable variable,
int startIndex, int endIndex)
NumericalVariable var = variable as NumericalVariable;
if (var == null)
return 0.5*(var[startIndex] + var[endIndex]);
Public Class MidpointAggregator Inherits Aggregator
Public Sub New()
Public Overrides Function Apply(var As Variable, _
startIndex As Integer, endIndex As Integer) As Object
If Not var.GetType() Is GetType(NumericalVariable)
Dim nvar As NumericalVariable = CType(var, NumericalVariable)
Return 0.5 * (nvar.Item(startIndex) + nvar.Item(endIndex))