hello support,
i try to create an indicator following this article :
https://www.dukascopy.com/wiki/#Indicato ... _indicatori would like to integrate a tenkanSen line over a Rsi indicator.
i call this indicator for the tenkanSen
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package jforex.indicators;
import com.dukascopy.api.indicators.IIndicator;
import com.dukascopy.api.indicators.IIndicatorContext;
import com.dukascopy.api.indicators.IndicatorInfo;
import com.dukascopy.api.indicators.IndicatorResult;
import com.dukascopy.api.indicators.InputParameterInfo;
import com.dukascopy.api.indicators.IntegerRangeDescription;
import com.dukascopy.api.indicators.OptInputParameterInfo;
import com.dukascopy.api.indicators.OutputParameterInfo;
import java.awt.Color;
/**
*
* @author eric
*/
public class Tenkanind 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[1][];
private IIndicator tenkanMax;
private IIndicator tenkanMin;
private int tenkanPeriod = 9;
public void onStart(IIndicatorContext context) {
tenkanMax = context.getIndicatorsProvider().getIndicator("MAX");
tenkanMin = context.getIndicatorsProvider().getIndicator("MIN");
indicatorInfo = new IndicatorInfo("TENKAN", "TenkanSen", "My indicators", true, false, false, 1, 1, 1);
inputParameterInfos = new InputParameterInfo[] {
new InputParameterInfo("Prices", InputParameterInfo.Type.PRICE)
};
optInputParameterInfos = new OptInputParameterInfo[] {
new OptInputParameterInfo("Tenkan period",
OptInputParameterInfo.Type.OTHER,
new IntegerRangeDescription(tenkanPeriod, 2, 100, 1)),
};
outputParameterInfos = new OutputParameterInfo[] {
new OutputParameterInfo("TENKAN",
OutputParameterInfo.Type.DOUBLE,
OutputParameterInfo.DrawingStyle.LINE) {
{
this.setColor(Color.BLUE);
}
}
};
}
public IndicatorResult calculate(int startIndex, int endIndex) {
if (startIndex - getLookback() < 0) {
startIndex -= startIndex - getLookback();
}
if (startIndex > endIndex) {
return new IndicatorResult(0, 0);
}
double[] tenkanMaxD = new double[endIndex - startIndex + 2 + getLookback()];
double[] tenkanMinD = new double[endIndex - startIndex + 2 + getLookback()];
tenkanMax.setInputParameter(0, inputs[0][2]);
tenkanMin.setInputParameter(0, inputs[0][3]);
tenkanMax.setOptInputParameter(0, tenkanPeriod);
tenkanMin.setOptInputParameter(0, tenkanPeriod);
tenkanMax.setOutputParameter(0, tenkanMaxD);
tenkanMin.setOutputParameter(0, tenkanMinD);
IndicatorResult dtenkanMaxResult = tenkanMax.calculate(startIndex - 1, endIndex);
IndicatorResult dtenkanMinResult = tenkanMin.calculate(startIndex - 1, endIndex);
int i, k;
for (i = 1, k = dtenkanMaxResult.getNumberOfElements(); i < k; i++) {
outputs[0][i - 1] = (tenkanMaxD[i] + tenkanMinD[i]) / 2;
}
return new IndicatorResult(startIndex, i - 1);
}
public IndicatorInfo getIndicatorInfo() {
return indicatorInfo;
}
public InputParameterInfo getInputParameterInfo(int index) {
if (index <= inputParameterInfos.length) {
return inputParameterInfos[index];
}
return null;
}
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) {
switch (index) {
case 0:
tenkanPeriod = (Integer) value;
break;
default:
throw new ArrayIndexOutOfBoundsException(index);
}
}
public void setOutputParameter(int index, Object array) {
outputs[index] = (double[]) array;
}
public int getLookback() {
return tenkanPeriod;
}
public int getLookforward() {
return 0;
}
}
this is the indicator tenkanOverRsi
package jforex.indicators;
import com.dukascopy.api.IConsole;
import com.dukascopy.api.indicators.DoubleRangeDescription;
import com.dukascopy.api.indicators.IIndicator;
import com.dukascopy.api.indicators.IIndicatorContext;
import com.dukascopy.api.indicators.IndicatorInfo;
import com.dukascopy.api.indicators.IndicatorResult;
import com.dukascopy.api.indicators.InputParameterInfo;
import com.dukascopy.api.indicators.IntegerListDescription;
import com.dukascopy.api.indicators.IntegerRangeDescription;
import com.dukascopy.api.indicators.OptInputParameterInfo;
import com.dukascopy.api.indicators.OutputParameterInfo;
import java.awt.Color;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
public class TenkanOverRsi implements IIndicator {
public static final int OPEN = 0;
public static final int CLOSE = 1;
public static final int LOW= 2;
public static final int HIGH = 3;
public static final int AVE = 4;
private IndicatorInfo indicatorInfo;
// INPUTS
private InputParameterInfo[] inputParameterInfos;
private double[][] inputs = new double[1][];
// OPT INPUTS
private OptInputParameterInfo[] optInputParameterInfos;
private int rsiPeriod;
private int tenkanPeriod;
// OUTPUTS
private OutputParameterInfo[] outputParameterInfos;
private double[][] outputs = new double[2][];
// CONTEXT
private IConsole console;
private IIndicator rsi;
private IIndicator tenkan;
public int getLookback() {
return rsi.getLookback()+tenkan.getLookback();
}
public int getLookforward() {
return 0;
}
/**************
* CALCULATE
**************/
public IndicatorResult calculate(int startIndex, int endIndex) {
int rsiLookback = rsi.getLookback();
double[] rsiOutput;
if (startIndex - getLookback() < 0) {
startIndex -= startIndex - getLookback();
}
if (startIndex > endIndex || rsi.getLookback()>endIndex) {
return new IndicatorResult(0, 0);
}else{
rsiOutput = new double[endIndex - (rsiLookback > startIndex ? rsiLookback : startIndex) + 1];
}
// rsi
rsi.setInputParameter(0, inputs);
rsi.setOptInputParameter(0, rsiPeriod);
rsi.setOutputParameter(0, rsiOutput);
IndicatorResult rsiResult = rsi.calculate(startIndex, endIndex);
if (rsiResult.getNumberOfElements() < tenkan.getLookback()) {
//not enough data to calculate tenkan
return new IndicatorResult(0, 0);
}
// tenkan
tenkan.setInputParameter(0, rsiOutput);
tenkan.setOptInputParameter(0, tenkanPeriod);
tenkan.setOutputParameter(0, outputs[0]);
IndicatorResult tenkanResult = tenkan.calculate(0, rsiResult.getNumberOfElements() - 1);
if (tenkanResult.getNumberOfElements() == 0) {
//tenkan returned 0 values
return new IndicatorResult(0, 0);
}
System.arraycopy(rsiOutput, tenkanResult.getFirstValueIndex(), outputs[0], 0, tenkanResult.getNumberOfElements());
IndicatorResult result = new IndicatorResult(rsiResult.getFirstValueIndex() + tenkanResult.getFirstValueIndex(), tenkanResult.getNumberOfElements());
return result;
}
public void onStart(IIndicatorContext context) {
this.console = context.getConsole();
int[] priceValues = new int[]{0,1,2,3,4};
String[] priceNames = new String[]{"Open","Close","High","Low","Volume"};
inputParameterInfos = new InputParameterInfo[] {
new InputParameterInfo("prices", InputParameterInfo.Type.PRICE)
};
optInputParameterInfos = new OptInputParameterInfo[] {
new OptInputParameterInfo("Tenkan period",
OptInputParameterInfo.Type.OTHER,
new IntegerRangeDescription(9, 2, 100, 1)),
new OptInputParameterInfo("Rsi period",
OptInputParameterInfo.Type.OTHER,
new IntegerRangeDescription(9, 2, 100, 1))
};
outputParameterInfos = new OutputParameterInfo[] {
new OutputParameterInfo("TENKAN",
OutputParameterInfo.Type.DOUBLE,
OutputParameterInfo.DrawingStyle.LINE) {
{
this.setColor(Color.ORANGE);
}
},
new OutputParameterInfo("RSI",
OutputParameterInfo.Type.DOUBLE,
OutputParameterInfo.DrawingStyle.LINE) {
{
this.setColor(Color.BLACK);
}
}
};
rsi = context.getIndicatorsProvider().getIndicator("RSI");
tenkan = context.getIndicatorsProvider().getIndicator("TENKAN");
indicatorInfo = new IndicatorInfo("TENKAN_RSI", "Tenkan over RSI", "My indicators", false, false, false, inputParameterInfos.length, optInputParameterInfos.length, outputParameterInfos.length);
}
public IndicatorInfo getIndicatorInfo() {
return indicatorInfo;
}
public InputParameterInfo getInputParameterInfo(int index) {
if (index <= inputParameterInfos.length) {
return inputParameterInfos[index];
}
return null;
}
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) {
switch (index) {
case 0:
rsiPeriod = (Integer) value;
break;
case 1:
tenkanPeriod = (Integer) value;
break;
}
}
public void setOutputParameter(int index, Object array) {
outputs[index] = (double[]) array;
}
// ________________________________
// Support: Some helper methods for printing
private void print(Object... o) {
for (Object ob : o) {
console.getOut().print(ob + " ");
}
console.getOut().println();
}
private void print(Object o) {
console.getOut().println(o);
}
private void print(double[] arr) {
print(arrayToString(arr));
}
private void print(double[][] arr) {
print(arrayToString(arr));
}
private void printIndicatorInfos(IIndicator ind) {
for (int i = 0; i < ind.getIndicatorInfo().getNumberOfInputs(); i++) {
print(ind.getIndicatorInfo().getName() + " Input " + ind.getInputParameterInfo(i).getName() + " " + ind.getInputParameterInfo(i).getType());
}
for (int i = 0; i < ind.getIndicatorInfo().getNumberOfOptionalInputs(); i++) {
print(ind.getIndicatorInfo().getName() + " Opt Input " + ind.getOptInputParameterInfo(i).getName() + " " + ind.getOptInputParameterInfo(i).getType());
}
for (int i = 0; i < ind.getIndicatorInfo().getNumberOfOutputs(); i++) {
print(ind.getIndicatorInfo().getName() + " Output " + ind.getOutputParameterInfo(i).getName() + " " + ind.getOutputParameterInfo(i).getType());
}
}
public static String arrayToString(double[] arr) {
String str = "";
for (int r = 0; r < arr.length; r++) {
str += "[" + r + "] " + (new DecimalFormat("#.#######")).format(arr[r]) + "; ";
}
return str;
}
public static String arrayToString(double[][] arr) {
String str = "";
if (arr == null)
return "null";
for (int r = 0; r < arr.length; r++) {
for (int c = 0; c < arr[r].length; c++) {
str += "[" + r + "][" + c + "] " + (new DecimalFormat("#.#######")).format(arr[r][c]);
}
str += "; ";
}
return str;
}
public String toDecimalToStr(double d) {
return (new DecimalFormat("#.#######")).format(d);
}
public String dateToStr(long time) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") {
{
setTimeZone(TimeZone.getTimeZone("GMT"));
}
};
return sdf.format(time);
}
// ________________________________
}
compilation is successfull but when i apply it i have this message :
java.lang.ClassCastException: [[D cannot be cast to [D
at jforex.indicators.TenkanOverRsi.setInputParameter(TenkanOverRsi.java:175)
at com.dukascopy.charts.math.a.a.a(Unknown Source)
at com.dukascopy.charts.math.dataprovider.AbstractDataProvider$e.c(Unknown Source)
at com.dukascopy.charts.math.dataprovider.AbstractDataProvider$e.run(Unknown Source)
so, i believe the problem come from the different array for the inputs for tenkanind and the inputs of tenkanOverRsi but i'm not sure.
i turn around the problem but i don't find the solution.
can please help me?