Implementing indicator

that uses another indicator

Sometimes it's needed to use another indicator results to implement new indicator. Here we create example indicator step by step, that outputs 3 EMA outputs in one shot

1. Create new indicator from JForex. New editor will open with example indicator in it

2. We will need IIndicatorsProvider from IIndicatorContext to get EMA indicator. onStart method is the good place to get it 

IIndicatorsProvider indicatorsProvider = context.getIndicatorsProvider();
ema = indicatorsProvider.getIndicator("EMA");

3. Now change info objects. Indicator will have one input, three parameters and three outputs

indicatorInfo = new IndicatorInfo("THREEEMA", "Shows three different EMA indicators", "My indicators",
	true, false, true, 1, 3, 3);
inputParameterInfos = new InputParameterInfo[] {new InputParameterInfo("Input data", InputParameterInfo.Type.DOUBLE)};
optInputParameterInfos = new OptInputParameterInfo[] {new OptInputParameterInfo("Time period EMA1", OptInputParameterInfo.Type.OTHER,
        new IntegerRangeDescription(5, 2, 1000, 1)), new OptInputParameterInfo("Time period EMA2", OptInputParameterInfo.Type.OTHER,
        new IntegerRangeDescription(10, 2, 1000, 1)), new OptInputParameterInfo("Time period EMA3", OptInputParameterInfo.Type.OTHER,
        new IntegerRangeDescription(20, 2, 1000, 1))};
outputParameterInfos = new OutputParameterInfo[] {new OutputParameterInfo("EMA1", OutputParameterInfo.Type.DOUBLE,
        OutputParameterInfo.DrawingStyle.LINE), new OutputParameterInfo("EMA2", OutputParameterInfo.Type.DOUBLE,
        OutputParameterInfo.DrawingStyle.LINE), new OutputParameterInfo("EMA3", OutputParameterInfo.Type.DOUBLE,
        OutputParameterInfo.DrawingStyle.LINE)};

Also change holder fields for parameters and outputs. Add field to save ema indicator

private int[] timePeriod = new int[3];
private double[][] outputs = new double[3][];
private IIndicator ema;

4. Lookback of the indicator should be biggest lookback of all three emas.

public int getLookback() {
    ema.setOptInputParameter(0, timePeriod[0]);
    int ema1Lookback = ema.getLookback();
    ema.setOptInputParameter(0, timePeriod[1]);
    int ema2Lookback = ema.getLookback();
    ema.setOptInputParameter(0, timePeriod[2]);
    int ema3Lookback = ema.getLookback();
    return Math.max(ema1Lookback, Math.max(ema2Lookback, ema3Lookback));
}

Also change method that saves time period parameters

timePeriod[index] = (Integer) value;

5. And finally write the calclulate method

First get the correct startIndex taking into account lookback

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

Set parameters to ema and calculate it's values:

ema.setInputParameter(0, inputs[0]);
 
//calculate first ema
ema.setOptInputParameter(0, timePeriod[0]);
ema.setOutputParameter(0, outputs[0]);
ema.calculate(startIndex, endIndex);
 
//calculate second ema
ema.setOptInputParameter(0, timePeriod[1]);
ema.setOutputParameter(0, outputs[1]);
ema.calculate(startIndex, endIndex);
 
//calculate third ema
ema.setOptInputParameter(0, timePeriod[2]);
ema.setOutputParameter(0, outputs[2]);
return ema.calculate(startIndex, endIndex);

IndicatorResult returned from ema is also correct for main indicator, so we just return it after last calculation

Indicator is ready!

package jforex;
 
import com.dukascopy.api.indicators.*;
 
public class TripleEMAIndicator implements IIndicator {
    private IndicatorInfo indicatorInfo;
    private InputParameterInfo[] inputParameterInfos;
    private OptInputParameterInfo[] optInputParameterInfos;
    private OutputParameterInfo[] outputParameterInfos;
    private double[][] inputs = new double[1][];
    private int[] timePeriod = new int[3];
    private double[][] outputs = new double[3][];
    private IIndicator ema;
 
    public void onStart(IIndicatorContext context) {
        IIndicatorsProvider indicatorsProvider = context.getIndicatorsProvider();
        ema = indicatorsProvider.getIndicator("EMA");
        indicatorInfo = new IndicatorInfo("THREEEMA", "Shows three different EMA indicators", "My indicators",
        		true, false, true, 1, 3, 3);
        inputParameterInfos = new InputParameterInfo[] {new InputParameterInfo("Input data", InputParameterInfo.Type.DOUBLE)};
        optInputParameterInfos = new OptInputParameterInfo[] {new OptInputParameterInfo("Time period EMA1", OptInputParameterInfo.Type.OTHER,
                new IntegerRangeDescription(5, 2, 1000, 1)), new OptInputParameterInfo("Time period EMA2", OptInputParameterInfo.Type.OTHER,
                new IntegerRangeDescription(10, 2, 1000, 1)), new OptInputParameterInfo("Time period EMA3", OptInputParameterInfo.Type.OTHER,
                new IntegerRangeDescription(20, 2, 1000, 1))};
        outputParameterInfos = new OutputParameterInfo[] {new OutputParameterInfo("EMA1", OutputParameterInfo.Type.DOUBLE,
                OutputParameterInfo.DrawingStyle.LINE), new OutputParameterInfo("EMA2", OutputParameterInfo.Type.DOUBLE,
                OutputParameterInfo.DrawingStyle.LINE), new OutputParameterInfo("EMA3", OutputParameterInfo.Type.DOUBLE,
                OutputParameterInfo.DrawingStyle.LINE)};
    }
 
    public IndicatorResult calculate(int startIndex, int endIndex) {
        //calculating startIndex taking into account lookback value
        if (startIndex - getLookback() < 0) {
            startIndex -= startIndex - getLookback();
        }
 
        ema.setInputParameter(0, inputs[0]);
 
        //calculate first ema
        ema.setOptInputParameter(0, timePeriod[0]);
        ema.setOutputParameter(0, outputs[0]);
        ema.calculate(startIndex, endIndex);
 
        //calculate second ema
        ema.setOptInputParameter(0, timePeriod[1]);
        ema.setOutputParameter(0, outputs[1]);
        ema.calculate(startIndex, endIndex);
 
        //calculate third ema
        ema.setOptInputParameter(0, timePeriod[2]);
        ema.setOutputParameter(0, outputs[2]);
        return ema.calculate(startIndex, endIndex);
    }
 
    public IndicatorInfo getIndicatorInfo() {
        return indicatorInfo;
    }
 
    public InputParameterInfo getInputParameterInfo(int index) {
        if (index <= inputParameterInfos.length) {
            return inputParameterInfos[index];
        }
        return null;
    }
 
    public int getLookback() {
        ema.setOptInputParameter(0, timePeriod[0]);
        int ema1Lookback = ema.getLookback();
        ema.setOptInputParameter(0, timePeriod[1]);
        int ema2Lookback = ema.getLookback();
        ema.setOptInputParameter(0, timePeriod[2]);
        int ema3Lookback = ema.getLookback();
        return Math.max(ema1Lookback, Math.max(ema2Lookback, ema3Lookback));
    }
 
    public int getLookforward() {
        return 0;
    }
 
    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) {
        timePeriod[index] = (Integer) value;
    }
 
    public void setOutputParameter(int index, Object array) {
        outputs[index] = (double[]) array;
    }
}