Im using an ATR based StopLoss indicator
The code is here
package jforex.indicators;
import java.awt.Color;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
import com.dukascopy.api.IConsole;
import com.dukascopy.api.IIndicators.AppliedPrice;
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.IntegerRangeDescription;
import com.dukascopy.api.indicators.OptInputParameterInfo;
import com.dukascopy.api.indicators.OutputParameterInfo;
public class ATRTrail implements IIndicator {
public static final int OPEN = 0;
public static final int CLOSE = 1;
public static final int MIN = 2;
public static final int MAX = 3;
public static final int AVE = 4;
private IndicatorInfo indicatorInfo;
// INPUTS
private InputParameterInfo[] inputParameterInfos;
private double[][] inPrice;
// OPT INPUTS
private OptInputParameterInfo[] optInputParameterInfos;
private int period = 5;
private double mult = 3.5;
// OUTPUTS
private OutputParameterInfo[] outputParameterInfos;
private double[][] output;
private int ATR = 0;
// CONTEXT
private IConsole console;
private IIndicator atr;
public int getLookback() {
atr.setOptInputParameter(0, period);
return atr.getLookback();
}
public int getLookforward() {
return 0;
}
/*************
* CALCULATE *
*************/
public IndicatorResult calculate(int startIndex, int endIndex) {
if (startIndex - getLookback() < 0) {
startIndex -= startIndex - getLookback();
}
if (startIndex > endIndex) {
return new IndicatorResult(0, 0);
}
int len = endIndex - startIndex + 1;
// atr
atr.setInputParameter(0, inPrice);
atr.setOutputParameter(0, output[ATR]);
atr.calculate(startIndex, endIndex);
int atrLB = atr.getLookback();
double prev;
if(inPrice[CLOSE][atrLB - 1] > inPrice[CLOSE][atr.getLookback()]) {
prev = inPrice[CLOSE][atr.getLookback()] + mult * output[ATR][0];
} else {
prev = inPrice[CLOSE][atr.getLookback()] - mult * output[ATR][0];
}
for (int i = 0; i < output[ATR].length; i++) {
int inIdx = i + atr.getLookback();
double stoploss = mult * output[ATR][i];
if(inPrice[CLOSE][inIdx] > prev && inPrice[CLOSE][inIdx - 1] > prev) {
output[ATR][i] = Math.max(prev, inPrice[CLOSE][inIdx] - stoploss);
} else if(inPrice[CLOSE][inIdx] < prev && inPrice[CLOSE][inIdx - 1] < prev) {
output[ATR][i] = Math.min(prev, inPrice[CLOSE][inIdx] + stoploss);
} else if(inPrice[CLOSE][inIdx] > prev) {
output[ATR][i] = inPrice[CLOSE][inIdx] - stoploss;
} else {
output[ATR][i] = inPrice[CLOSE][inIdx] + stoploss;
}
prev = output[ATR][i];
}
return new IndicatorResult(startIndex, len);
}
/***********
* START *
***********/
public void onStart(IIndicatorContext context) {
this.console = context.getConsole();
int[] priceValues = new int[AppliedPrice.values().length];
String[] priceNames = new String[AppliedPrice.values().length];
for (int i = 0; i < priceValues.length; i++) {
priceValues[i] = i;
priceNames[i] = AppliedPrice.values()[i].name();
}
inputParameterInfos = new InputParameterInfo[]{
new InputParameterInfo("price", InputParameterInfo.Type.PRICE)
};
optInputParameterInfos = new OptInputParameterInfo[]{
new OptInputParameterInfo("ATR period",
OptInputParameterInfo.Type.OTHER,
new IntegerRangeDescription(period, 2, 1000, 1)),
new OptInputParameterInfo("ATR multiplication", OptInputParameterInfo.Type.OTHER,
new DoubleRangeDescription(mult, -100.0, 100.0, 0.1, 10)),};
outputParameterInfos = new OutputParameterInfo[]{
new OutputParameterInfo("ATR",
OutputParameterInfo.Type.DOUBLE,
OutputParameterInfo.DrawingStyle.LINE) {
{
this.setColor(Color.BLUE);
}
},};
output = new double[outputParameterInfos.length][];
atr = context.getIndicatorsProvider().getIndicator("ATR");
indicatorInfo = new IndicatorInfo("ATR trail", "ATR trail", "My indicators", true, false, false, inputParameterInfos.length, optInputParameterInfos.length, outputParameterInfos.length);
indicatorInfo.setRecalculateAll(true);
}
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) {
// print(index + ". input: " + arrayToString((double[]) array));
if (array instanceof double[][]) {
inPrice = (double[][]) array;
}
}
public void setOptInputParameter(int index, Object value) {
switch (index) {
case 0:
period = (Integer) value;
break;
case 1:
mult = (Double) value;
break;
}
}
public void setOutputParameter(int index, Object array) {
output[index] = (double[]) array;
}
// ________________________________
// Support: Some helper methods for printing
private void print(Object... o) {
for (Object ob : o) {
//console.getOut().print(ob + " ");
if (ob instanceof double[]) {
print2((double[]) ob);
} else if (ob instanceof double[][]) {
print2((double[][]) ob);
} else if (ob instanceof Long) {
print2(dateToStr((Long) ob));
} else {
print2(ob);
}
print2(" ");
}
console.getOut().println();
}
private void print(Object o) {
console.getOut().println(o);
}
private void print2(Object o) {
console.getOut().print(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);
}
// ________________________________
}
Indicator works fine, and plots as expected.
But, when I then try to create a strategy that references this indicator inside of it.
The strategy just stops/crashes with the message.
18:40:02 java.lang.ArrayIndexOutOfBoundsException: 1 @ com.dukascopy.api.impl.dp.b(L:4979)
18:40:02 Error in indicator: java.lang.ArrayIndexOutOfBoundsException: 1 @ com.dukascopy.api.impl.dp.b(L:4979)
Apparently its this line thats doing it.
Object[] resultByShift = indicators.calculateIndicator(
feedDescriptor, new OfferSide[] {OfferSide.BID}, indName, new AppliedPrice[]{AppliedPrice.CLOSE}, new Object[]{timePeriod}, 1);
Heres the code for the strategy implementing the indicator.
Any ideas??
Also on a side note....I eventually want to use Range Bars, with this indicator in my strategy.
Will this be easy/possible??? Or can I only use time based bars? Like what do I put as the feed descriptor??
package jforex.lib;
import java.util.Arrays;
import com.dukascopy.api.*;
import static com.dukascopy.api.IIndicators.AppliedPrice.*;
import com.dukascopy.api.IIndicators.AppliedPrice;
import com.dukascopy.api.feed.IFeedDescriptor;
import com.dukascopy.api.feed.util.TimePeriodAggregationFeedDescriptor;
import com.dukascopy.api.indicators.IIndicator;
//pass file name if the indicator is located in context.getFilesDir, otherwise - full file path
@CustomIndicators("C:/Users/KK/AppData/local/JForex/Indicators/ATRTrail.jfx")
public class Quadtec implements IStrategy {
private IEngine engine;
private IConsole console;
private IHistory history;
private IContext context;
private IIndicators indicators;
private IUserInterface userInterface;
@Override
public void onStart(IContext context) throws JFException {
this.engine = context.getEngine();
this.console = context.getConsole();
this.history = context.getHistory();
this.context = context;
this.indicators = context.getIndicators();
this.userInterface = context.getUserInterface();
String indPath = getClass().getAnnotation(CustomIndicators.class).value();
//for multiple indicators split the path with File.pathSeparator
IIndicator indicator = indicators.getIndicatorByPath(indPath);
if(indicator == null){
context.stop();
}
String indName = indicator.getIndicatorInfo().getName();
//add indicator to the last active chart if there is one
IChart chart = context.getLastActiveChart();
if(chart != null){
chart.add(indicator);
}
IFeedDescriptor feedDescriptor = chart!= null
? chart.getFeedDescriptor()
: new TimePeriodAggregationFeedDescriptor(Instrument.EURUSD, Period.TEN_SECS, OfferSide.BID, Filter.NO_FILTER);
int timePeriod = (Integer) indicator.getOptInputParameterInfo(0).getDescription().getOptInputDefaultValue();
Object[] resultByShift = indicators.calculateIndicator(
feedDescriptor, new OfferSide[] {OfferSide.BID}, indName, new AppliedPrice[]{AppliedPrice.CLOSE}, new Object[]{timePeriod}, 1);
double prevValue = (Double) resultByShift[0];
long lastTime = history.getFeedData(feedDescriptor, 0).getTime();
Object[] resultByCandleInterval = indicators.calculateIndicator(
feedDescriptor, new OfferSide[] {OfferSide.BID}, indName, new AppliedPrice[]{CLOSE}, new Object[]{timePeriod}, 5, lastTime, 0);
double[] values = (double[]) resultByCandleInterval[0];
}
public void onTick(Instrument instrument, ITick tick) throws JFException {
}
public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {
}
public void onAccount(IAccount account) throws JFException {
}
public void onMessage(IMessage message) throws JFException {
}
public void onStop() throws JFException {
}
}