This bug applies to all indicators that explicitly define instruments using setInstrument() where the instrument is different to the chart that is shown on the JForex platform. Under these circumstances the indicator is called upon with every tick to update the entire data set, not just the last datum. For simple indicators this is not a serious problem, but in some cases this creates calculation errors, not to mention the excessive computational load for complex indicators.
At the bottom of this post is a code example that reproduces this bug. It is the default "new indicator", which has been modified to explicitly use EUR/USD and to print to the console the number of input and output datums with each call to calculate().
If either the
setInstrument(Instrument.EURUSD) line is commented out
OR the chart is set to show
EUR/USD then the indicator is called correctly, i.e. only to update the most recent output datums in response to new tick data. In this case the console shows something like:
20:50:20 output length = 1
20:50:20 input length = 3
20:50:20 output length = 1
20:50:20 input length = 3
20:50:15 output length = 1
20:50:15 input length = 3
20:50:15 output length = 1
20:50:15 input length = 3
20:50:01 output length = 1296
20:50:01 input length = 1298
However if the
setInstrument(Instrument.EURUSD) line is NOT commented out
AND the chart is NOT showing
EUR/USD then the indicator is called to update the entire output with every tick. In this case the console shows something like:
20:51:31 output length = 776
20:51:31 input length = 780
20:51:31 output length = 1
20:51:31 input length = 3
20:51:31 output length = 776
20:51:31 input length = 780
20:51:30 output length = 1
20:51:30 input length = 3
20:51:30 output length = 776
20:51:30 input length = 780
20:51:29 output length = 776
20:51:29 input length = 780
The example code is:
package jforex;
import com.dukascopy.api.IConsole;
import com.dukascopy.api.Instrument;
import com.dukascopy.api.indicators.*;
public class TestInputs implements IIndicator {
private IndicatorInfo indicatorInfo;
private IConsole console;
private InputParameterInfo[] inputParameterInfos;
private OptInputParameterInfo[] optInputParameterInfos;
private OutputParameterInfo[] outputParameterInfos;
private double[][] inputs = new double[1][];
private int timePeriod = 2;
private double[][] outputs = new double[1][];
public void onStart(IIndicatorContext context) {
this.console = context.getConsole();
indicatorInfo = new IndicatorInfo("EXAMPIND", "Sums previous values", "My indicators",
false, false, false, 1, 1, 1);
inputParameterInfos = new InputParameterInfo[] {new InputParameterInfo("Input data", InputParameterInfo.Type.DOUBLE)};
// problematic line
inputParameterInfos[0].setInstrument(Instrument.EURUSD);
optInputParameterInfos = new OptInputParameterInfo[] {new OptInputParameterInfo("Time period", OptInputParameterInfo.Type.OTHER,
new IntegerRangeDescription(2, 2, 100, 1))};
outputParameterInfos = new OutputParameterInfo[] {new OutputParameterInfo("out", OutputParameterInfo.Type.DOUBLE,
OutputParameterInfo.DrawingStyle.LINE)};
}
public IndicatorResult calculate(int startIndex, int endIndex) {
// print input / output lengths
for (int i=0; i<inputs.length; i++) {
console.getOut().println("input " + i + ": length = " + inputs[i].length);
}
console.getOut().println("outputs length = " + outputs[0].length);
//calculating startIndex taking into account lookback value
if (startIndex - getLookback() < 0) {
startIndex -= startIndex - getLookback();
}
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;
}
return new IndicatorResult(startIndex, j);
}
public IndicatorInfo getIndicatorInfo() {
return indicatorInfo;
}
public InputParameterInfo getInputParameterInfo(int index) {
if (index <= inputParameterInfos.length) {
return inputParameterInfos[index];
}
return null;
}
public int getLookback() {
return timePeriod;
}
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 = (Integer) value;
}
public void setOutputParameter(int index, Object array) {
outputs[index] = (double[]) array;
}
}
I hope this is clear enough...
Cheers
