Dukascopy
 
 
Wiki JStore Search Login

Attention! Read the forum rules carefully before posting a topic.

    Try to find an answer in Wiki before asking a question.
    Submit programming questions in this forum only.
    Off topics are strictly forbidden.

Any topics which do not satisfy these rules will be deleted.

Range bars, and custom indicator
 Post subject: Range bars, and custom indicator Post rating: 0   New post Posted: Wed 13 Jul, 2016, 19:51 
User avatar

User rating: 0
Joined: Sat 02 Mar, 2013, 09:43
Posts: 12
Location: Canada, Vancouver
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 {
    }
}




 
 Post subject: Re: Range bars, and custom indicator Post rating: 0   New post Posted: Mon 25 Jul, 2016, 08:42 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
The exception was thrown because indicator call passed 1 optional input parameter instead of required 2.
Indicator can be calculated for renko bars as follows
        IFeedDescriptor fd = new RenkoFeedDescriptor(Instrument.EURUSD, PriceRange.THREE_PIPS, OfferSide.BID);
        Object[] indicatorResult = indicators.calculateIndicator(fd, new OfferSide[] {OfferSide.BID}, "ATR trail", new  IIndicators.AppliedPrice[] {IIndicators.AppliedPrice.CLOSE}, new Object[] {5, 3.5}, 1);
        console.getOut().println(indicatorResult[0]);


 

Jump to:  

cron
  © 1998-2025 Dukascopy® Bank SA
On-line Currency forex trading with Swiss Forex Broker - ECN Forex Brokerage,
Managed Forex Accounts, introducing forex brokers, Currency Forex Data Feed and News
Currency Forex Trading Platform provided on-line by Dukascopy.com