Calculate arbitrary indicator

JForex API makes accessible all necessary indicator metadata for calculation of an arbitrary indicator by usage of universal indicator calculation methods. By this approach one can calculate both platform and custom indicators. This section contains examples which show how to do this.

Calculate by shift

Consider a strategy which on its start calculates an indicator by name and prints its outputs. Note that if the user chooses a custom indicator file indFile then the custom indicator gets used. In either case, whether it's a platform or a custom indicator, the user has to assign the correct indicator name indName. In the given example indicator works with its default optional input values, see Retrieve optional input value ranges example for elaborated logging of those values.

package jforex;

import java.io.File;
import java.util.Arrays;

import com.dukascopy.api.*;
import com.dukascopy.api.indicators.*;
import com.dukascopy.api.IIndicators.AppliedPrice;

@RequiresFullAccess
public class CalculateArbitraryIndicator implements IStrategy {

    private IConsole console;
    private IIndicators indicators;
    @Configurable(value = "Custom indicator .jfx file",
            description = "Only for custom indicators. For platform indicators leave it empty.")
    public File indFile;
    @Configurable("Indicator name")
    public String indName = "ALLIGATOR";
    @Configurable("Instrument")
    public Instrument instrument = Instrument.EURUSD;
    @Configurable("period")
    public Period period = Period.ONE_MIN;
    @Configurable("AppliedPrice")
    public AppliedPrice appliedPrice = AppliedPrice.CLOSE;
    @Configurable("OfferSide")
    public OfferSide side = OfferSide.BID;

    public void onStart(IContext context) throws JFException {
        this.console = context.getConsole();
        this.indicators = context.getIndicators();

        // load from file if there is such
        if (indFile != null && indFile.exists()) {
            indName = indicators.registerCustomIndicator(indFile);
        }

        IIndicator indicator = indicators.getIndicator(indName);

        // retrieve indicator metadata
        IndicatorInfo info = indicator.getIndicatorInfo();
        int inputCount = info.getNumberOfInputs();
        int optInputCount = info.getNumberOfOptionalInputs();
        int outputCount = info.getNumberOfOutputs();
        print("inputCount=%s, optInputCount=%s, outputCount=%s", inputCount, optInputCount, outputCount);
        print(indicator.getInputParameterInfo(0).getType());

        // 1 - input related parameters

        // assume close price for all inputs
        AppliedPrice[] inputTypes = new AppliedPrice[inputCount];
        Arrays.fill(inputTypes, appliedPrice);

        // assume bid side for all inputs
        OfferSide[] offerSides = new OfferSide[inputCount];
        Arrays.fill(offerSides, side);

        // 2 - optional input related parameters
        Object[] optParams = new Object[optInputCount];
        for (int i = 0; i < optInputCount; i++) {
            optParams[i] = indicator.getOptInputParameterInfo(i).getDescription().getOptInputDefaultValue();
            print("Set default opt input: %s=%s", indicator.getOptInputParameterInfo(i).getName(), optParams[i]);
        }

        int shift = 0;
        Object[] outputs = indicators.calculateIndicator(
                instrument, period, offerSides, indName, inputTypes, optParams, shift);

        // 3 - process outputs

        print("indicator outputs: ");
        for (int i = 0; i < outputCount; i++) {
            OutputParameterInfo outputInfo = indicator.getOutputParameterInfo(i);
            String outputName = outputInfo.getName();
            if (outputInfo.getType() == OutputParameterInfo.Type.DOUBLE) {
                print("%s=%.7f", outputName, (Double) outputs[i]);
            } else if (outputInfo.getType() == OutputParameterInfo.Type.INT) {
                print("%s=%s", outputName, outputs[i]);
            } else {
                print("%s type is Object - %s, which needs customized processing.",
                      outputName, outputs[i].getClass());
            }
        }

    }

    private void print(String format, Object... args) {
        print(String.format(format, args));
    }

    private void print(Object message) {
        console.getOut().println(message);
    }

    public void onAccount(IAccount account) throws JFException {    }
    public void onMessage(IMessage message) throws JFException {    }
    public void onStop() throws JFException {   }
    public void onTick(Instrument instrument, ITick tick) throws JFException {  }
    public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {  }
}

CalculateArbitraryIndicator.java

Apply to particular indicator

Assume that we just ran the strategy on Alligator indicator and obtained the following output on console:

Alligator Lips=1.34102
Alligator Teeth=1.34112
Alligator Jaw=1.34121
indicator outputs:
Set default opt input: Lips Time Period=5
Set default opt input: Teeth Time Period=8
Set default opt input: Jaw Time Period=13
inputCount=1, optInputCount=3, outputCount=3 

One can find here all necessary data to simplify the indicator call to:

public void onStart(IContext context) throws JFException {
    this.console = context.getConsole();
    this.indicators = context.getIndicators();        

    IIndicator indicator = indicators.getIndicator(indName); 

    //1 - input related parameters - we make arrays of 1 element since we have 1 input
    AppliedPrice[] inputTypes = new AppliedPrice[] {appliedPrice};
    OfferSide[] offerSides = new OfferSide[] {side};

    //2 - optional inputs - we have three of them -
        // Jaw Time Period, Teeth Time Period, Lips Time Period. Use default values.
    Object[] optParams = new Object[] {13, 8, 5};

    int shift = 0;
    Object[] outputs = indicators.calculateIndicator(
            instrument, period, offerSides, indName, inputTypes, optParams, shift);

    //3 - outputs - we have 3 outputs and all of them are of type DOUBLE
    for(int i = 0; i < 3; i++){
        String outputName = indicator.getOutputParameterInfo(i).getName();
        print("%s=%.5f", outputName, (Double)outputs[i]);
    }       
}

CalculateParticularIndicator.java

Calculate by candle interval

Consider modifying the previous example to calculate indicator values over the last 10 candle sticks. Change the calculation method:

long currBarTime = history.getBar(instrument, period, side, 0).getTime();
Object[] outputs = indicators.calculateIndicator(instrument, period, offerSides, indName, inputTypes, optParams, 
    Filter.NO_FILTER, 10, currBarTime, 0);

Adjust the output logging:

if(outputInfo.getType() == OutputParameterInfo.Type.DOUBLE){
    print("%s=%s", outputName, arrayToString((double[])outputs[i]));  
} else if(outputInfo.getType() == OutputParameterInfo.Type.INT){
    print("%s=%s", outputName, Arrays.asList((int[])outputs[i]));
} else {
    print("%s type is Object - %s, which needs customized processing.", outputName, outputs[i].getClass());
}

where the arrayToString method is implemented as follows:

public static String arrayToString(double[] arr) {
    String str = "";
    for (int r = 0; r < arr.length; r++) {
        str += String.format("[%s] %.5f; ", r, arr[r]);
    }
    return str;
}

CalculateArbIndCandleInterval.java

Calculate on a feed

Consider adjusting the example strategy to calculate the indicator on a custom price feed:

IFeedDescriptor feedDescriptor = new RangeBarFeedDescriptor(
    Instrument.EURUSD, PriceRange.valueOf(2), OfferSide.BID);   
long currBarTime = history.getBar(instrument, period, side, 0).getTime();
Object[] outputs = indicators.calculateIndicator(
    feedDescriptor, offerSides, indName, inputTypes, optParams, candleCount, currBarTime, 0);

CalculateArbIndFeed.java

Apply to Price channel indicator

Assume that we just ran the strategy on Price channel (parameter indName = PCHANNEL) indicator and obtained the following output on console:

Low=[0] 1.33240; [1] 1.33238; [2] 1.33238; [3] 1.33238; [4] 1.33238; [5] 1.33238; [6] 1.33238; 
    [7] 1.33238; [8] 1.33238; [9] 1.33238;
Up=[0] 1.33330; [1] 1.33330; [2] 1.33330; [3] 1.33330; [4] 1.33330; [5] 1.33330; [6] 1.33330;
    [7] 1.33307; [8] 1.33306; [9] 1.33306;
indicator outputs:
Set default opt input: Time period=14
inputCount=1, optInputCount=1, outputCount=2

One can find here all necessary data to simplify the indicator call to:

public void onStart(IContext context) throws JFException {
    this.console = context.getConsole();
    this.indicators = context.getIndicators();      
    this.history = context.getHistory();

    //1 - input related parameters
    AppliedPrice[] inputTypes = new AppliedPrice[] {AppliedPrice.CLOSE};
    OfferSide[] offerSides = new OfferSide[] {OfferSide.BID};

    //2 - optional input related parameters - 0=TimePeriod       
    Object[] optParams = new Object[] { 14 };

    //3 - set up feed and calculate
    IFeedDescriptor feedDescriptor = new RangeBarFeedDescriptor(
        Instrument.EURUSD, PriceRange.valueOf(2),OfferSide.BID);   
    long currBarTime = history.getBar(instrument, period, side, 0).getTime();
    Object[] outputs = indicators.calculateIndicator(
        feedDescriptor, offerSides, indName, inputTypes, optParams, candleCount, currBarTime, 0);

    //4 - process outputs: 0=Up, 1=Down
    double [] ups = (double[])outputs[1];
    double [] lows = (double[])outputs[0];
    print("Up=%s", arrayToString(ups));  
    print("Down=%s", arrayToString(lows));         
}

CalculateIndFeedPChannel.java

The information on this web site is provided only as general information, which may be incomplete or outdated. Click here for full disclaimer.