User Defined Functions

Extending the analytics ecosystem through UDFs with the Analytics API


Overview

This analytic processor enables complex calculation to be executed using a provided analytical function implemented using the Analytics API. This feature also provides the ability to set a rolling number of events to be used with the calculation.

Leverage this feature for complex calculations and control the implementation complexity

Key Features

  • Pluggable

  • Analytics API

  • DSL support

Example

The analytic function ema, Exponential Moving Average, is defined inline using the standard Joule DSL

user defined function:
  ema:
    parameters:
      smoothing factor: 0.33333
  fields: [ ask ]
  event history: 12
  assign prefix: ema12

Attributes

Further example

This example demonstrates how you would combine complex calculation with a final analytic expression to trigger an alert.

processing unit:
    pipeline:
      - user defined function:
          ema:
            parameters:
              smoothing factor: 0.33333
          fields: [ ask ]
          event history: 26
          response prefix: ema26
    
      - user defined function:
          ema:
            parameters:
              smoothing factor: 0.33333
          fields: [ ask ]
          event history: 12
          response prefix: ema12
    
      - analytic:
          expression: "ema12_ask - ema26_ask"
          assign to: macd_ask_signal
      
emit:
    select: "symbol, macd_ask_signal"
    having: "macd_ask_signal > 0.05"

Example function implementation

The below is an implementation example for a custom analytics function. Further details can be found in the Analytics API documentation.

@JsonRootName(value = "ema")
public class ExponentialMovingAverage extends AnalyticsFunction<Double> {

    public static final String SMOOTH_FACTOR = "smoothing factor";
    private double smoothFactor = 0.333;

    public ExponentialMovingAverage() {
        super();
    }

    @Override
    public void setParameters(Properties parameters) {
        if (parameters != null && parameters.containsKey(SMOOTH_FACTOR)) {
            smoothFactor = Double.parseDouble(parameters.get(SMOOTH_FACTOR).toString());
        }
    }

    @Override
    public String getVariablePostFixID() {
        return "EMA";
    }

    @Override
    public Double compute(Number[] values, Number previousValue) {
        if (previousValue == null) return Double.NaN;

        if (Double.isNaN(previousValue.doubleValue())) {
            previousValue = values[values.length - 1];
            return (Double)previousValue;
        }

        for (Number d : values) {
            previousValue = (d.doubleValue() * smoothFactor) + (previousValue.doubleValue() * (1 - smoothFactor));
        }
        return previousValue.doubleValue();
    }
}

Last updated