Add Indicators on Chart

The IChartPanel.add methods get used to plot an indicator on chart. One can retrieve parameters and appearance information of already plotted indicators by calling the IChartPanel.getIndicatorApperanceInfos method. One can also plot another indicator or chart objects on the same indicator panel.

Use optional parameters

The following methods may be used to add indicators on chart. The latter method lets you specify values for indicator optional parameters.

chart.add(indicators.getIndicator("ZIGZAG"));
chart.add(indicators.getIndicator("ET_Nico"), new Object[]{15});

Specify output style

Use the following code to specify the applied price, drawing style, colors, etc for the indicator you add:

IChart chart = context.getChart(Instrument.EURUSD);
IIndicator indCOG = indicators.getIndicator("COG");
for (int i = 0; i < indCOG.getIndicatorInfo().getNumberOfInputs(); i++) {
  InputParameterInfo inputParameterInfo = indCOG.getInputParameterInfo(i);
  inputParameterInfo.setAppliedPrice(AppliedPrice.LOW);
}                                                   

chart.add(indCOG, new Object[]{5, 6, MaType.SMA.ordinal()}, new Color[]{Color.RED, Color.GREEN},
  new DrawingStyle[]{DrawingStyle.DASHDOT_LINE, DrawingStyle.LINE}, new int[]{1, 2});        

Object array optParams, the second parameter of chart.addIndicator, stands for indicator-specific parameters whose info can be retrieved from indicator metadata.

Use on-chart indicator parameters

As mentioned above, one can retrieve parameters and appearance information of already plotted indicators by calling the IChartPanel.getIndicatorApperanceInfos method. Consider a strategy which calculates indicators with the same parameters as they appear on the last selected chart:

private IIndicators indicators;
private IHistory history;
private IConsole console;
private IChart chart;

private int dataCount = 3;

@Override
public void onStart(IContext context) throws JFException {
    indicators = context.getIndicators();
    history = context.getHistory();
    console = context.getConsole();
    chart = context.getLastActiveChart();
    if (chart == null) {
        console.getErr().println("No chart opened!");
        return;
    }
    IFeedDescriptor feedDescriptor = chart.getFeedDescriptor();
    if(feedDescriptor.getDataType() == DataType.TICKS){
        console.getWarn().println("Tick charts need to get calculate with from-to method");
        return;
    }

    for (IIndicatorAppearanceInfo info : chart.getIndicatorApperanceInfos()) {
        AppliedPrice[] appliedPrices = new AppliedPrice[info.getDrawingStyles().length];
        Arrays.fill(appliedPrices, AppliedPrice.CLOSE);
        OfferSide[] offerSides = new OfferSide[info.getDrawingStyles().length];
        Arrays.fill(offerSides, chart.getSelectedOfferSide());
        IIndicator indicator = indicators.getIndicator(info.getName());
        ITimedData feedData = history.getFeedData(feedDescriptor, 0);
        Object[] result = indicators.calculateIndicator(
                feedDescriptor, offerSides, info.getName(), appliedPrices, info.getOptParams(),
                dataCount, feedData.getTime(), 0);
        for (int i = 0; i < indicator.getIndicatorInfo().getNumberOfOutputs(); i++) {
            OutputParameterInfo.Type outputType = indicator.getOutputParameterInfo(i).getType();
            String resultStr = 
                    outputType == OutputParameterInfo.Type.DOUBLE ? Arrays.toString((double[]) result[i])
                    : outputType == OutputParameterInfo.Type.INT ? Arrays.toString((int[]) result[i])
                    : "object outputs need special processing";
            console.getOut().format(
                "%s %s last %s values: %s", 
                info.getName(), indicator.getOutputParameterInfo(i).getName(), dataCount, resultStr).println();
        }

    }
    context.stop();
}

CalculateIndicatorsFromChart.java

Include in OHLC

Consider a strategy which plots EMA and MACD indicators on chart and adds an OHLC informer with indicator showing option. The strategy also calculates the indicators on every bar, such that one can verify that the values match:

ChartAndStrategy.jpg

The function that adds the indicators and the OHLC informer:

    public void onStart(IContext context) throws JFException {
        this.console = context.getConsole();
        this.indicators = context.getIndicators();

        IChart chart = null;
        for(IChart c : context.getCharts(instrument)){
            if(c.getSelectedOfferSide() == this.side
                    && c.getSelectedPeriod() == this.period
                    && c.getFilter() == this.filter){
                chart = c;
                break;
            }
            if(c.getFilter() != this.filter){
                console.getErr().println(
                    "Filter dismatch! Change in platform settings the filter " +
                            "to the same one that the strategy is using!");
                context.stop();
            }
        }
        if(chart == null){
            chart = context.openChart(new TimePeriodAggregationFeedDescriptor(instrument, period, side, filter));
        }

        chart.add(indicators.getIndicator("EMA"), 
                  new Object[] { emaTimePeriod });
        chart.add(indicators.getIndicator("MACD"), 
                  new Object[] { macdFastPeriod, macdSlowPeriod, macdSignalPeriod });

        IOhlcChartObject ohlc = null;
        for (IChartObject obj : chart.getAll()) {
            if (obj instanceof IOhlcChartObject) {
                ohlc = (IOhlcChartObject) obj;
            }
        }
        if (ohlc == null) {
            ohlc = chart.getChartObjectFactory().createOhlcInformer();
            chart.add(ohlc);
        }
        ohlc.setShowIndicatorInfo(true);

        //calculate on the previous bar over candle interval such that the filters get used
        long time = context.getHistory().getBar(instrument, period, side, 1).getTime();
        double[][] macd = indicators.macd(instrument, period, side, AppliedPrice.CLOSE, 
            macdFastPeriod, macdSlowPeriod, macdSignalPeriod, filter, 1, time, 0);

        double[] ema = indicators.ema(instrument, period, side, AppliedPrice.CLOSE, 
            emaTimePeriod, filter, 1, time, 0);

        console.getOut().format("%s - ema=%s, macd=%s (by candle interval)", 
            DateUtils.format(time), arrayToString(ema), arrayToString(macd)).println();
    }

PlotEmaMacdWithOhlc.java

Also consider a generalized version that works with any feed:

PlotEmaMacdWithOhlcFeed.java

Plot on newly opened chart

Consider creating a wrapper class which describes both the indicator data and the feed it is supposed to be calculated on:

    class IndDataAndFeed{

        private IFeedDescriptor feedDescriptor;
        private String indicatorName;
        private Object[] optionalInputs;
        private int outputIndex;
        private IIndicator indicator;
        private IChart chart;

        public IndDataAndFeed(
                String indicatorName, Object[] optionalInputs, int outputIndex, IFeedDescriptor feedDescriptor) {
            this.feedDescriptor = feedDescriptor;
            this.indicatorName = indicatorName;
            this.optionalInputs = optionalInputs;
            this.outputIndex = outputIndex;
        }

        public void openChartAddIndicator(){
            for(IChart openedChart : context.getCharts(feedDescriptor.getInstrument())){
                IFeedDescriptor chartFeed = openedChart.getFeedDescriptor();
                if(chartFeed.getPeriod() == feedDescriptor.getPeriod() 
                        && chartFeed.getOfferSide() == feedDescriptor.getOfferSide()){
                    chart = openedChart;
                }
            }
            if(chart == null){
                chart = context.openChart(feedDescriptor);
            }
            if(chart.getFeedDescriptor().getFilter() != feedDescriptor.getFilter()){
                console.getErr().println("Chart filter " + chart.getFeedDescriptor().getFilter() + 
                    " does not match indicator feed filter " + feedDescriptor.getFilter() +
                    " please adjust the platform settings");
                context.stop();
            }
            indicator = indicators.getIndicator(indicatorName);

            int outputCount = indicator.getIndicatorInfo().getNumberOfOutputs();
            Color[] colors = new Color[outputCount];
            DrawingStyle[] styles = new DrawingStyle[outputCount];
            int[] widths = new int[outputCount];
            for(int outIdx = 0; outIdx< outputCount; outIdx++){
                OutputParameterInfo outInfo = indicator.getOutputParameterInfo(outIdx);
                if(outInfo == null){
                    console.getErr().println(indicatorName + " "  + outIdx + "is null");
                    continue;
                }
                //make colors darker
                colors[outIdx] = new Color(new Random().nextInt(256 * 256 * 256));
                //make solid-line inputs dashed
                styles[outIdx] = outInfo.getDrawingStyle() == DrawingStyle.LINE ?
                        DrawingStyle.DASH_LINE : 
                        outInfo.getDrawingStyle();
                //thicken the 1-width lines
                widths[outIdx] = 2;
            }

            chart.add(indicator, optionalInputs, colors, styles, widths);

            //show indicator values in ohlc
            IOhlcChartObject ohlc = null;
            for (IChartObject obj : chart.getAll()) {
                if (obj instanceof IOhlcChartObject) {
                    ohlc = (IOhlcChartObject) obj;
                }
            }
            if (ohlc == null) {
                ohlc = chart.getChartObjectFactory().createOhlcInformer();
                chart.add(ohlc);
            }
            ohlc.setShowIndicatorInfo(true);
        }

        public double getCurrentValue() throws JFException{
            Object[] outputs = indicators.calculateIndicator(
                    feedDescriptor, 
                    new OfferSide[] { feedDescriptor.getOfferSide() }, 
                    indicatorName,
                    new AppliedPrice[] { AppliedPrice.CLOSE }, 
                    optionalInputs, 
                    0);
            double value = (Double) outputs[outputIndex];
            return value;
        }

        public void removeFromChart(){
            if(chart != null && indicator != null){
                chart.removeIndicator(indicator);
            }
        }

        @Override 
        public String toString(){
            return String.format("%s %s on %s %s feed",
                indicatorName, 
                Arrays.toString(optionalInputs), 
                feedDescriptor.getOfferSide(),
                feedDescriptor.getPeriod());
        }

    }

Then add a list of indicators which you wish to calculate and plot on respective chart:

    private List<IndDataAndFeed> calculatableIndicators = new ArrayList<>(Arrays.asList(new IndDataAndFeed[]{
            new IndDataAndFeed("MACD", new Object[] {12,26,9}, 0,
                               new TimePeriodAggregationFeedDescriptor(
                                       instrument, Period.FIVE_MINS, OfferSide.BID, Filter.WEEKENDS)),
            new IndDataAndFeed("RSI", new Object[] {50}, 0,
                               new TimePeriodAggregationFeedDescriptor(
                                       instrument, Period.FIVE_MINS, OfferSide.BID, Filter.WEEKENDS)),
            new IndDataAndFeed("RSI", new Object[] {50}, 0,
                               new TimePeriodAggregationFeedDescriptor(
                                       instrument, Period.ONE_HOUR, OfferSide.BID, Filter.WEEKENDS)),
            new IndDataAndFeed("CCI", new Object[] {14}, 0,
                               new TimePeriodAggregationFeedDescriptor(
                                       instrument, Period.FIFTEEN_MINS, OfferSide.BID, Filter.WEEKENDS)),
            new IndDataAndFeed("CCI", new Object[] {14}, 0,
                               new TimePeriodAggregationFeedDescriptor(
                                       instrument, Period.ONE_HOUR, OfferSide.BID, Filter.WEEKENDS))
    }));

And finally make calls from the strategy:

    @Override
    public void onStart(IContext context) throws JFException {

        if(!context.getSubscribedInstruments().contains(instrument)){
            context.setSubscribedInstruments(
                    new HashSet<Instrument>(
                            Arrays.asList(new Instrument [] {instrument})), true);
        }

        this.context = context;
        console = context.getConsole();
        indicators = context.getIndicators();

        for(IndDataAndFeed indDataAndFeed : calculatableIndicators){
            indDataAndFeed.openChartAddIndicator();
        }
    }

    @Override
    public void onTick(Instrument instrument, ITick tick) throws JFException {
        if (instrument != this.instrument) {
            return;
        }
        for (IndDataAndFeed indDataAndFeed : calculatableIndicators) {
            double value = indDataAndFeed.getCurrentValue();
            print("%s current value=%.5f", indDataAndFeed, value);
        }
    }

    @Override
    public void onStop() throws JFException {
        for(IndDataAndFeed indDataAndFeed : calculatableIndicators){
            indDataAndFeed.removeFromChart();
        }
    }

FeedMultiIndOpenChartsOhlc.java

Randomize output style and include in OHLC

Consider modifying the previous example, by modifying the indicator ouput styles and including the indicator values in the OHLC information object:

public void openChartAddIndicator(){
    for(IChart openedChart : context.getCharts(feedDescriptor.getInstrument())){
        IFeedDescriptor chartFeed = openedChart.getFeedDescriptor();
        if(chartFeed.getPeriod() == feedDescriptor.getPeriod() && 
                        chartFeed.getOfferSide() == feedDescriptor.getOfferSide()){
            chart = openedChart;
        }
    }
    if(chart == null){
        chart = context.openChart(feedDescriptor);
    }
    if(chart.getFeedDescriptor().getFilter() != feedDescriptor.getFilter()){
        console.getErr().println(
                "Chart filter " + chart.getFeedDescriptor().getFilter() + 
                                " does not match indicator feed filter " +
                                feedDescriptor.getFilter() + " please adjust the platform settings");
        context.stop();
    }
    indicator = indicators.getIndicator(indicatorName);

    int outputCount = indicator.getIndicatorInfo().getNumberOfOutputs();
    Color[] colors = new Color[outputCount];
    DrawingStyle[] styles = new DrawingStyle[outputCount];
    int[] widths = new int[outputCount];
    for(int outIdx = 0; outIdx< outputCount; outIdx++){
        OutputParameterInfo outInfo = indicator.getOutputParameterInfo(outIdx);
        if(outInfo == null){
            console.getErr().println(indicatorName + " "  + outIdx + "is null");
            continue;
        }
        //make colors darker
        colors[outIdx] = new Color(new Random().nextInt(256 * 256 * 256));
        //make solid-line inputs dashed
        styles[outIdx] = outInfo.getDrawingStyle() == DrawingStyle.LINE ? 
                    DrawingStyle.DASH_LINE : 
                        outInfo.getDrawingStyle();
        //thicken the 1-width lines
        widths[outIdx] = 2;
    }

    chart.add(indicator, optionalInputs, colors, styles, widths);

    //show indicator values in ohlc
    IOhlcChartObject ohlc = null;
    for (IChartObject obj : chart.getAll()) {
        if (obj instanceof IOhlcChartObject) {
            ohlc = (IOhlcChartObject) obj;
        }
    }
    if (ohlc == null) {
        ohlc = chart.getChartObjectFactory().createOhlcInformer();
        chart.add(ohlc);
    }
    ohlc.setShowIndicatorInfo(true);
}

FeedMultiIndOpenChartsOhlc.java

The information on this web site is provided only as general information, which may be incomplete or outdated. Click here for full disclaimer.