# User defined functions

## Objective

This analytic processor enables complex calculation to be executed using a provided analytical function implemented using the [Analytics API](/joule/developer-guides/builder-sdk/analytics-api.md). This feature also provides the **ability to set a rolling number** of events to be used with the calculation.

{% hint style="info" %}
Leverage this feature for complex calculations and to control the implementation
{% endhint %}

Learn different average functions which can be applied in Joule.

{% content-ref url="/pages/S466JF3EVQkcfyHLeXLp" %}
[Average function library](/joule/components/analytics/analytic-tools/user-defined-analytics/user-defined-functions/average-function-library.md)
{% endcontent-ref %}

## Key Features

* Pluggable
* Analytics API
* DSL support

## Example & DSL attributes

The analytic function `ema` (Exponential Moving Average) is defined inline using the standard Joule DSL fragment.

```yaml
user defined function:
  function:
    exponential moving average:
      parameters:
        smoothing factor: 0.33333
  fields: [ ask ]
  event history: 12
  assign prefix: ema12
```

### Attributes schema

<table><thead><tr><th width="144">Attribute</th><th width="367">Description</th><th width="128">Data Type</th><th data-type="checkbox">Required</th></tr></thead><tbody><tr><td>fields</td><td>Fields to calculated from the event</td><td>String[]</td><td>true</td></tr><tr><td>event history</td><td>Number of rolling events to stored and used for the calculation</td><td>Integer</td><td>false</td></tr><tr><td>assign prefix</td><td>Prefix to use for the result assignment. This is used to allow the same function to be used multiple times. If this is not provided the function postfix will be applied e.g. ask_EMA</td><td>String<br>Default: Function postfix </td><td>false</td></tr></tbody></table>

### Further example

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

```yaml
processing unit:
    pipeline:
      - user defined function:
          function:
            exponential moving average:
                parameters:
                  smoothing factor: 0.33333
          fields: [ ask ]
          event history: 26
          response prefix: ema26
    
      - user defined function:
          function:
            exponential moving average:
                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

This is an implementation example for a custom analytics function.

Further details can be found in the [Analytics API](/joule/developer-guides/builder-sdk/analytics-api.md) documentation.

```java
@JsonRootName(value = "exponential moving average")
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();
    }
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.fractalworks.io/joule/components/analytics/analytic-tools/user-defined-analytics/user-defined-functions.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
