Hi,
Quote:
it is possible to implement Multiple Instrument indicator in JForex?
Yes, it's possible. Indicator can define additional inputs and set specific instruments for them. Take a look at this example code:
package jforex;
import com.dukascopy.api.*;
import java.awt.*;
import java.awt.geom.*;
import java.util.*;
import com.dukascopy.api.indicators.*;
/**
* @author Dmitry Shohov
*/
public class GbpUsdEmaIndicator implements IIndicator, IDrawingIndicator {
private IndicatorInfo indicatorInfo;
private InputParameterInfo[] inputParameterInfos;
private OptInputParameterInfo[] optInputParameterInfos;
private OutputParameterInfo[] outputParameterInfos;
private IBar[][] inputs = new IBar[2][];
private double[][] outputs = new double[2][];
private IIndicator normalEMA;
private IIndicator gbpUsdEMA;
private IConsole console;
public void onStart(IIndicatorContext context) {
IIndicatorsProvider provider = context.getIndicatorsProvider();
console = context.getConsole();
normalEMA = provider.getIndicator("EMA");
gbpUsdEMA = provider.getIndicator("EMA");
indicatorInfo = new IndicatorInfo("GBPUSDEMA", "Shows normal EMA and GBPUSDEMA", "My indicators",
true, false, true, 2, 1, 2);
InputParameterInfo gbpUsdInput = new InputParameterInfo("Input data", InputParameterInfo.Type.BAR);
gbpUsdInput.setInstrument(Instrument.GBPUSD);
inputParameterInfos = new InputParameterInfo[] {new InputParameterInfo("Input data", InputParameterInfo.Type.BAR), gbpUsdInput};
optInputParameterInfos = new OptInputParameterInfo[] {new OptInputParameterInfo("Time period", OptInputParameterInfo.Type.OTHER,
new IntegerRangeDescription(20, 2, 100, 1))};
OutputParameterInfo gbpUsdOutput = new OutputParameterInfo("GBPUSD_EMA", OutputParameterInfo.Type.DOUBLE, OutputParameterInfo.DrawingStyle.LINE);
gbpUsdOutput.setDrawnByIndicator(true);
outputParameterInfos = new OutputParameterInfo[] {new OutputParameterInfo("EMA", OutputParameterInfo.Type.DOUBLE, OutputParameterInfo.DrawingStyle.LINE), gbpUsdOutput};
}
public IndicatorResult calculate(int startIndex, int endIndex) {
double[] emaInput = new double[inputs[0].length];
for (int i = 0; i < inputs[0].length; i++) {
IBar bar = inputs[0][i];
emaInput[i] = bar.getClose();
}
normalEMA.setInputParameter(0, emaInput);
normalEMA.setOutputParameter(0, outputs[0]);
IndicatorResult result = normalEMA.calculate(startIndex, endIndex);
emaInput = new double[inputs[1].length];
for (int i = 0; i < inputs[1].length; i++) {
IBar bar = inputs[1][i];
emaInput[i] = bar.getClose();
}
if (emaInput.length - gbpUsdEMA.getLookback() > 0) {
double[] gbpUsdEMAOutput = new double[emaInput.length - gbpUsdEMA.getLookback()];
gbpUsdEMA.setInputParameter(0, emaInput);
gbpUsdEMA.setOutputParameter(0, gbpUsdEMAOutput);
IndicatorResult gbpUsdResult = gbpUsdEMA.calculate(0, emaInput.length - 1);
int j = 0;
for (int i = 0; i < result.getNumberOfElements(); i++) {
IBar bar = inputs[0][i + result.getFirstValueIndex()];
long barTime = bar.getTime();
//looking for the gbpusd candle with the same time
while (j < gbpUsdResult.getFirstValueIndex() + gbpUsdResult.getNumberOfElements() && inputs[1][j].getTime() < barTime) {
j++;
}
if (j >= gbpUsdResult.getFirstValueIndex() + gbpUsdResult.getNumberOfElements() || inputs[1][j].getTime() != barTime || j < gbpUsdResult.getFirstValueIndex()) {
outputs[1][i] = Double.NaN;
} else {
outputs[1][i] = gbpUsdEMAOutput[j - gbpUsdResult.getFirstValueIndex()];
}
}
} else {
for (int i = 0; i < result.getNumberOfElements(); i++) {
outputs[1][i] = Double.NaN;
}
}
return result;
}
public Point drawOutput(Graphics g, int outputIdx, Object valuesArr, Color color, Stroke stroke, IIndicatorDrawingSupport indicatorDrawingSupport, java.util.List<Shape> shapes, Map<Color, java.util.List<Point>> handles) {
IBar[] candles = indicatorDrawingSupport.getCandles();
double[] values = (double[]) valuesArr;
if (candles.length != values.length) {
console.getErr().println(candles.length + " <> " + values.length);
}
double min = Double.MAX_VALUE;
double max = Double.MIN_VALUE;
double gbpMin = Double.MAX_VALUE;
double gbpMax = Double.MIN_VALUE;
for (int i = indicatorDrawingSupport.getIndexOfFirstCandleOnScreen() - 1, j = indicatorDrawingSupport.getIndexOfFirstCandleOnScreen() + indicatorDrawingSupport.getNumberOfCandlesOnScreen() + 1; i < j; i++) {
if (i < 0 || i >= candles.length) {
continue;
}
IBar candle = candles[i];
min = Math.min(min, candle.getLow());
max = Math.max(max, candle.getHigh());
if (!Double.isNaN(values[i])) {
gbpMin = Math.min(gbpMin, values[i]);
gbpMax = Math.max(gbpMax, values[i]);
}
}
GeneralPath path = new GeneralPath();
boolean plottingStarted = false;
float x = 0;
float y = 0;
for (int i = indicatorDrawingSupport.getIndexOfFirstCandleOnScreen() - 1, j = indicatorDrawingSupport.getIndexOfFirstCandleOnScreen() + indicatorDrawingSupport.getNumberOfCandlesOnScreen() + 1; i < j; i++) {
if (i < 0 || i >= candles.length) {
continue;
}
if (Double.isNaN(values[i])) {
continue;
}
double allignedValue = ((values[i] - gbpMin) / (gbpMax - gbpMin)) * (max - min) + min;
x = indicatorDrawingSupport.getMiddleOfCandle(i);
y = indicatorDrawingSupport.getYForValue(allignedValue);
if (plottingStarted) {
path.lineTo(x, y);
} else {
path.moveTo(x, y);
plottingStarted = true;
}
}
g.setColor(color);
((Graphics2D) g).setStroke(stroke);
((Graphics2D) g).draw(path);
return new Point((int) x, (int) y);
}
public IndicatorInfo getIndicatorInfo() {
return indicatorInfo;
}
public InputParameterInfo getInputParameterInfo(int index) {
if (index <= inputParameterInfos.length) {
return inputParameterInfos[index];
}
return null;
}
public int getLookback() {
return Math.max(normalEMA.getLookback(), gbpUsdEMA.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] = (IBar[]) array;
}
public void setOptInputParameter(int index, Object value) {
normalEMA.setOptInputParameter(index, value);
gbpUsdEMA.setOptInputParameter(index, value);
}
public void setOutputParameter(int index, Object array) {
outputs[index] = (double[]) array;
}
}
Quote:
In strategy is there any possibility how to draw into chart lines like indicators?
It's possible to draw POLY_LINE lines, but of course, they won't look so good as indicator lines. Consider please this
https://www.dukascopy.com/swiss/docs/interfaces/IChart.htmHowever, thank you for idea, we will consider it to implement in the JForex