Implementing simple indicator

Creating indicator with JForex starts with selecting Strategies node in the tree, right clicking on it and selecting New Indicator. New tab will open, that already contains example indicator. It's easier to start with already available template, than implementing the IIndicator interface from the start. Example indicator sums some number of previous prices and outputs them on the separate panel under the chart

Lets follow the steps needed to implement the same indicator starting from the empty class:

package jforex;
 
import com.dukascopy.api.indicators.*;
 
public class SimpleIndicator implements IIndicator {
 
    public void onStart(IIndicatorContext context) {
    }
 
    public IndicatorResult calculate(int startIndex, int endIndex) {
    }
 
    public IndicatorInfo getIndicatorInfo() {
    }
 
    public InputParameterInfo getInputParameterInfo(int index) {
    }
 
    public int getLookback() {
    }
 
    public int getLookforward() {
    }
 
    public OptInputParameterInfo getOptInputParameterInfo(int index) {
    }
 
    public OutputParameterInfo getOutputParameterInfo(int index) {
    }
 
    public void setInputParameter(int index, Object array) {
    }
 
    public void setOptInputParameter(int index, Object value) {
    }
 
    public void setOutputParameter(int index, Object array) {
    }
}

1. First step would be implementing getters and setter, it's rather simple operation and looks the same for almost every indicator

package jforex;
 
import com.dukascopy.api.indicators.*;
 
public class SimpleIndicator implements IIndicator {
    private IndicatorInfo indicatorInfo;
    private InputParameterInfo[] inputParameterInfos;
    private OptInputParameterInfo[] optInputParameterInfos;
    private OutputParameterInfo[] outputParameterInfos;
    private double[][] inputs = new double[1][];
    private double[][] outputs = new double[1][];
 
    public void onStart(IIndicatorContext context) {
    }
 
    public IndicatorResult calculate(int startIndex, int endIndex) {
    }
 
    public IndicatorInfo getIndicatorInfo() {
        return indicatorInfo;
    }
 
    public InputParameterInfo getInputParameterInfo(int index) {
        if (index <= inputParameterInfos.length) {
            return inputParameterInfos[index];
        }
        return null;
    }
 
    public int getLookback() {
    }
 
    public int getLookforward() {
    }
 
    public OptInputParameterInfo getOptInputParameterInfo(int index) {
        if (index <= optInputParameterInfos.length) {
            return optInputParameterInfos[index];
        }
        return null;
    }
 
    public OutputParameterInfo getOutputParameterInfo(int index) {
        if (index <= outputParameterInfos.length) {
            return outputParameterInfos[index];
        }
        return null;
    }
 
    public void setInputParameter(int index, Object array) {
        inputs[index] = (double[]) array;
    }
 
    public void setOptInputParameter(int index, Object value) {
    }
 
    public void setOutputParameter(int index, Object array) {
        outputs[index] = (double[]) array;
    }
}

 Here we created fields that will hold the info objects and input output arrays

2. Second step would be creating info objects

indicatorInfo = new IndicatorInfo("EXAMPIND", "Sums previous values", "My indicators",
        false, false, false, 1, 1, 1);

Indicator name is EXAMPIND, it has title, group, not over chart, not over volumes, doesn't have unstable period, and has one input, one parameter and one output

inputParameterInfos = new InputParameterInfo[] {new InputParameterInfo("Input data", InputParameterInfo.Type.DOUBLE)};

Input has name and type double

optInputParameterInfos = new OptInputParameterInfo[] {new OptInputParameterInfo("Time period", OptInputParameterInfo.Type.OTHER,
                new IntegerRangeDescription(2, 2, 100, 1))};

Parameter has name, it's not percent or degree, and defined as integer with range from 2 to 100

3. It's very important to define correct lookback for indicator. In this example lookback will depend on time period parameter, which means how many previous values we will sum

public void setOptInputParameter(int index, Object value) {
    timePeriod = (Integer) value;
}

Saves time period in class variable

public int getLookback() {
    return timePeriod;
}

 and returned by getLookback method. getLookforward will return 0;

4. Now it's time to implement calculate method

First it's needed to find the first index of the input, for which we can calculate value. We can't do this for index 0, because we need some candles before current to sum them

//calculating startIndex taking into account lookback value
if (startIndex - getLookback() < 0) {
    startIndex -= startIndex - getLookback();
}

 Now when startIndex has the correct starting index, we can start the calculation cycle

int i, j;
for (i = startIndex, j = 0; i <= endIndex; i++, j++) {
    double value = 0;
    for (int k = timePeriod; k > 0; k--) {
        value += inputs[0][i - k];
    }
    outputs[0][j] = value;
}

Cycle has two variables i and j. First one iterates over the input array, second over the output. Inner cycle sums number of previous values defined by the timePeriod in value variable and finally saves it in output

Last step is to create IndicatorResult

return new IndicatorResult(startIndex, j);

First parameter is first calculated index of input array, and second is the number of calculated outputs

Indicator is ready for compilation and use, resulting code can be found by creating new indicator in jforex