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);
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));
}