3.4 Calculating output data

You put the results of your UDI's calculations into the output object which is passed to your UDI.onCalculate().

The output has a values member which is an array of arrays. The length, and order, of output.values depends on the plots defined for your indicator. For example:

plots: [
	{type: "channel", …}, 	// Requires 2 output series
	{type: "line", …}, 	// Requires 1 output series
	{type: "candles", …} 	// Requires 4 output series

In this example, output.values will contain 7 sub-arrays. Items [0] and [1] will be for the channel plot; item [2] will be for the line plot; and items [3] to [6] will be for the candle plot.

Each sub-array inside output.values will already have been initialised so that it contains the required number of elements (matching the number of bars on the chart). In other words, the length of each sub-array, such as output.values[0].length, will be the same as data.valueCount. (Therefore, you assign values into the sub-arrays rather than using push() to add data.)

If UDI.onCalculate() is being called for an update of the current bar only, with data.currentBarUpdateOnly set, then the contents of output.values will be the last results you passed back. Typically, you only then need to re-calculate the latest value in each sub-array. For example (not fully efficient!):

UDI.onCalculate = function(data, output)
	// Get the user-selected value of the "period" parameter
	var period = data.parameters["period"];
	if (!data.currentBarUpdateOnly) {
		// Need to do a full recalculation (repeating the example above)
		for (var i = 0; i < data.valueCount - period; i++) {
			var sum = 0;
			for (var j = 0; j < period; j++) sum += data.valueData[i + j];
			output.values[0][i] = sum / period;
	} else {
		// Only the current bar is changing, and we only need to recalculate
		// the current indicator value. (Note: the 02-udi-efficient-sma.js example
		// demonstrates a more efficient version of this which avoids having 
		// to use a loop.)
		var sum = 0;
		for (var j = 0; j < period; j++) sum += data.valueData[j];
		output.values[0][0] = sum / period;

Although the framework pre-creates and pre-populates the arrays inside output.values, it's permissible for you to replace them with new arrays instead of writing your values into the existing arrays. This is typically most relevant when working with technical analysis calculations. For example, let's say that you have used the Sway.ta library to calculate a moving average of the input values:

// Create and store a moving average calculation. (The $ has no special meaning.
// It just makes clear what is a built-in UDI function/property and what is a private 
// addition by our code.)
UDI.$myMA = new Sway.ta.EMA({period: 20});

You can then copy the moving average results into a system-provided output array such as [1]:

// Copy each EMA value into output buffer #1
for (var i = 0; i < data.valueCount; i++) {
	output.values[1][i] = UDI.$myMA.GetValue(i);

However, it is both simpler and faster just to take the array from the technical analysis calculation and use that to replace the pre-prepared buffer:

output.values[1] = UDI.$myMA.GetValueArray();  // Replaces the array, rather than writing into it

Last updated