This code is exactly the same as SMAOverRSIIndicator.java that is in the examples section of indicator docs, except that it uses STOCHRSI instead of RSI. The only things changed from the original are that the indicator has been renamed to SMAOverSTORSIIndicator (filename as well), that it uses getIndicator("STOCHRSI") instead of RSI and the description for IndicatorInfo has been changed to reflect this ("SMA over STORSI").
Unlike the original however this one throws an exception (apparently something to do with getLookback() for STORSI).
package jforex;
import com.dukascopy.api.indicators.*;
public class SMAOverSTORSIIndicator 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[2][];
private IIndicatorContext context;
private IIndicator rsiIndicator;
private IIndicator smaIndicator;
public void onStart(IIndicatorContext context) {
//getting interfaces of RSI and SMA indicators
IIndicatorsProvider indicatorsProvider = context.getIndicatorsProvider();
rsiIndicator = indicatorsProvider.getIndicator("STOCHRSI");
smaIndicator = indicatorsProvider.getIndicator("SMA");
//inicator with one input, two optional params and two outputs
indicatorInfo = new IndicatorInfo("SMA_RSI", "SMA over STORSI", "My indicators",
false, false, false, false, 1, 2, 2);
//one input array of doubles
inputParameterInfos = new InputParameterInfo[] {new InputParameterInfo("Input data", InputParameterInfo.Type.DOUBLE)};
//two optional params, one for every indicator
optInputParameterInfos = new OptInputParameterInfo[] {new OptInputParameterInfo("RSI Time Period", OptInputParameterInfo.Type.OTHER,
new IntegerRangeDescription(14, 2, 100, 1)), new OptInputParameterInfo("SMA Time Period", OptInputParameterInfo.Type.OTHER,
new IntegerRangeDescription(14, 2, 100, 1))};
//two output arrays, one for RSI and one for SMA over RSI
outputParameterInfos = new OutputParameterInfo[] {new OutputParameterInfo("RSI line", OutputParameterInfo.Type.DOUBLE,
OutputParameterInfo.LINE), new OutputParameterInfo("SMA line", OutputParameterInfo.Type.DOUBLE,
OutputParameterInfo.LINE)};
}
public IndicatorResult calculate(int startIndex, int endIndex) {
//calculating rsi
int rsiLookback = rsiIndicator.getLookback();
//first alocate buffer for rsi results
double[] rsiOutput;
if (startIndex > endIndex || rsiLookback > endIndex) {
return new IndicatorResult(0, 0);
} else {
//take the greater value (startindex/ lookback)
rsiOutput = new double[endIndex - (rsiLookback > startIndex ? rsiLookback : startIndex) + 1];
}
//init rsi indicator with input data and array for output
rsiIndicator.setInputParameter(0, inputs[0]);
rsiIndicator.setOutputParameter(0, rsiOutput);
IndicatorResult rsiResult = rsiIndicator.calculate(startIndex, endIndex);
if (rsiResult.getNumberOfElements() < smaIndicator.getLookback()) {
//not enough data to calculate sma
return new IndicatorResult(0, 0);
}
//calculating sma
smaIndicator.setInputParameter(0, rsiOutput);
smaIndicator.setOutputParameter(0, outputs[1]);
IndicatorResult smaResult = smaIndicator.calculate(0, rsiResult.getNumberOfElements() - 1);
if (smaResult.getNumberOfElements() == 0) {
//sma returned 0 values
return new IndicatorResult(0, 0);
}
//copy rsi values to output excluding first values used for sma lookback
System.arraycopy(rsiOutput, smaResult.getFirstValueIndex(), outputs[0], 0, smaResult.getNumberOfElements());
//creating result, first value index for our input is FVI for rsi + FVI for sma, because we calculated sma starting from 0 element
IndicatorResult result = new IndicatorResult(rsiResult.getFirstValueIndex() + smaResult.getFirstValueIndex(), smaResult.getNumberOfElements());
return result;
}
public IndicatorInfo getIndicatorInfo() {
return indicatorInfo;
}
public InputParameterInfo getInputParameterInfo(int index) {
if (index <= inputParameterInfos.length) {
return inputParameterInfos[index];
}
return null;
}
public int getLookback() {
return rsiIndicator.getLookback() + smaIndicator.getLookback();
}
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) {
//set optional params in indicators
switch (index) {
case 0:
rsiIndicator.setOptInputParameter(0, value);
break;
case 1:
smaIndicator.setOptInputParameter(0, value);
break;
}
}
public void setOutputParameter(int index, Object array) {
outputs[index] = (double[]) array;
}
}