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.

applying an indicator to range bars
 Post subject: applying an indicator to range bars Post rating: 0   Post Posted: Mon 28 Nov, 2011, 22:08 

User rating: 0
Joined: Tue 22 Nov, 2011, 12:47
Posts: 130
Location: United States,
hi,

I'm new to JForex indicators so I have some basic questions before I dive deeper:

Let's say that I've subscribed to a range bars feed.

now - I want to apply an indicator onto that feed.

I examined the example provided here: https://www.dukascopy.com/wiki/index.php?title=Range_Bars_with_indicators

but I do not understand why in this example the indicator is calculated using time based period?? here is the critical code section:

      return (double[]) indicators.calculateIndicator(instrument, period, new OfferSide[] {OfferSide.BID}, name, 
            new AppliedPrice[] {AppliedPrice.CLOSE}, new Object[] {indicatorPeriod}, from, to)[0];


From the documentation of calculateIndicator - the second parameter is the period of the bars. In the example the period is defined like this :

   @Configurable("Period")
   public Period period = Period.ONE_MIN;


So - why one minute bars? these are Range Bars, so why did the example configured the indicator with minute bars?

Also - it is not clear to me why the start time and the end time for the calcualtion are also based on 1 minute bars:

firstCandleTime = history.getBarStart(RangeBarIndicatorsCandles.this.period, prevRangeBar.getTime());
lastCandleTime = history.getBarStart(RangeBarIndicatorsCandles.this.period, Math.min(curTime,prevRangeBar.getEndTime()));


 
 Post subject: Re: applying an indicator to range bars Post rating: 0   Post Posted: Tue 29 Nov, 2011, 08:33 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
cb888trader wrote:
From the documentation of calculateIndicator - the second parameter is the period of the bars. In the example the period is defined like this :
   @Configurable("Period")
   public Period period = Period.ONE_MIN;

Parameter period is chart timeframe, however, indicatorPeriod is an indicator parameter.
Quote:
So - why one minute bars? these are Range Bars, so why did the example configured the indicator with minute bars?
These are one minute candle sticks - strategy works both with Range bars and candle sticks - it assumes candle stick chart and draws itself range bars on top of it as chart objects.
cb888trader wrote:
Also - it is not clear to me why the start time and the end time for the calcualtion are also based on 1 minute bars:

firstCandleTime = history.getBarStart(RangeBarIndicatorsCandles.this.period, prevRangeBar.getTime());
lastCandleTime = history.getBarStart(RangeBarIndicatorsCandles.this.period, Math.min(curTime,prevRangeBar.getEndTime()));
This finds first and last 1 minute candle stick within the range bar which just arrived in range bar feed.


 
 Post subject: Re: applying an indicator to range bars Post rating: 0   Post Posted: Tue 29 Nov, 2011, 09:34 

User rating: 0
Joined: Tue 22 Nov, 2011, 12:47
Posts: 130
Location: United States,
Support,

From your answers I realize that I was misunderstood. Also - it means that the example is very confusing. You are mixing both time and range bars together while there is no simple example of how to apply indicators on range bars.

Let me try again: We are missing details related to applying Indicators on Range Bars - not Time based Candles. I searched long and yielded no example in the WiKi/Forum.

Can you please provide a working example of how to apply indicators on Range Bars Feeds (not via visual charts)?

Your support is greatly appreciated.

cb888trader.


 
 Post subject: Re: applying an indicator to range bars Post rating: 0   Post Posted: Tue 29 Nov, 2011, 13:35 

User rating: 0
Joined: Tue 22 Nov, 2011, 12:47
Posts: 130
Location: United States,
Dear Support,

Sorry to nag. Can you please answer the above? We cannot proceed with the development without this information.

Kindly,
cb888trader.


 
 Post subject: Re: applying an indicator to range bars Post rating: 0   Post Posted: Tue 29 Nov, 2011, 16:37 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
cb888trader wrote:
Sorry to nag. Can you please answer the above?
We reply as soon as available.
cb888trader wrote:
Can you please provide a working example of how to apply indicators on Range Bars Feeds (not via visual charts)?
Consider the following example strategy (see comments in the source code):
package jforex.strategies.rangebars;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.TimeZone;

import com.dukascopy.api.*;
import com.dukascopy.api.IIndicators.MaType;
import com.dukascopy.api.bar.IRangeBar;
import com.dukascopy.api.indicators.IIndicator;

/**
 * The strategy shows how to emulate range bar history.
 * Also it shows how to use range bar close prices with MA indicator.
 *
 */

@RequiresFullAccess
public class RangeBarsHistory implements IStrategy {

   private IConsole console;
   private IHistory history;
   private IIndicators indicators;
   private SimpleDateFormat sdf;

   @Configurable("Instrument")
   public Instrument instrument = Instrument.EURUSD;
   @Configurable("Offer Side")
   public OfferSide offerSide = OfferSide.BID;
   @Configurable("Price range (pips)")
   public int priceRangePips = 2;
   @Configurable("MA TimePeriod")
   public int maTimePeriod = 5;
   @Configurable("MA Shift")
   public int maShift = 3;
   @Configurable("(config) History Chunk Size")
   public Period historyChunkSize = Period.ONE_MIN;

   public static DecimalFormat df = new DecimalFormat("0.00000");
   private PriceRange priceRange;
   
   @Override
   public void onStart(IContext context) throws JFException {

      this.history = context.getHistory();
      this.console = context.getConsole();
      this.indicators = context.getIndicators();
      console.getOut().println("start");
      priceRange = PriceRange.valueOf(priceRangePips);

      sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      sdf.setTimeZone(TimeZone.getTimeZone("GMT"));

      long time = history.getLastTick(instrument).getTime();
      
      //this much price values we will need for indicator calculation;
      int barCount = maShift + maTimePeriod + 1;
      List<IRangeBar> rangeBars = getHistoryRangeBars(barCount, time);
      
      //log historical range bars
      for(IRangeBar rangeBar : rangeBars){
         print(rangeBar);
      }
      
      //get close prices
      double[] closePrices = new double[rangeBars.size()];
      for(int i =0; i< rangeBars.size(); i++){
         closePrices[i] = rangeBars.get(i).getClose();
      }
      
      double ma = getMa(maTimePeriod, maShift,closePrices);
      print("MA value with period " + maTimePeriod+ " and shift " + maShift +": "+ df.format(ma));
      
      context.stop();
   }

   /**
    * Returns historical range bars starting from histEndTime.
    *
    * @param count range bar count
    * @param histEndTime end time of the latest range bar
    * @return
    * @throws JFException
    */
   private List<IRangeBar> getHistoryRangeBars(int count, long histEndTime) throws JFException {

      long chunkInterval = historyChunkSize.getInterval();
      List<IRangeBar> rangeBars = new ArrayList<IRangeBar>();
      MockRangeBar rangeBar = null;
      ITick tick;
      boolean createNew = true;      

      while (rangeBars.size() < count) {
         //read ticks in chunks
         List<ITick> ticks = history.getTicks(instrument, histEndTime - chunkInterval, histEndTime);
         for (int i = ticks.size() - 1; i >= 0; i--) {
            tick = ticks.get(i);
            
            double price = offerSide == OfferSide.BID ? tick.getBid() : tick.getAsk();
            double volume = offerSide == OfferSide.BID ? tick.getBidVolume() : tick.getAskVolume();
            if (createNew) {
               if (rangeBar != null) {
                  rangeBars.add(rangeBar);
               }
               rangeBar = new MockRangeBar(price, volume, tick.getTime());
               createNew = false;
               continue;
            }
            if (Math.abs(rangeBar.open - price) > instrument.getPipValue() * priceRange.getPipCount()) {
               createNew = true;
               continue;
            }
            if (rangeBar.high < price) {
               rangeBar.high = price;
            }
            if (rangeBar.low > price) {
               rangeBar.low = price;
            }
            rangeBar.close = price;
            rangeBar.vol += volume;
            rangeBar.startTime = tick.getTime();
            rangeBar.tickCount++;

            if (rangeBars.size() >= count) {
               break;
            }
         }
         if (rangeBars.size() >= count) {
            break;
         }
         histEndTime -= chunkInterval;
      }

      //reverse such that the latest range bar is the last one
      Collections.reverse(rangeBars);
      return rangeBars;

   }
   
   /**
    * Calculates MA over an array, see more:
    * https://www.dukascopy.com/wiki/index.php?title=Strategy_API:_Indicators#Calculate_indicator_on_array
    *
    * @param timePeriod
    * @param shift
    * @param priceArr
    * @return
    */
   private double getMa(int timePeriod, int shift, double [] priceArr ) {
      IIndicator maIndicator = indicators.getIndicator("MA");
      
      //set optional inputs
      maIndicator.setOptInputParameter(0, 3);
      maIndicator.setOptInputParameter(1, MaType.SMA.ordinal());
      
      //set inputs
      maIndicator.setInputParameter(0, priceArr);
      
      //set outputs
      double [] resultArr = new double [priceArr.length];
      maIndicator.setOutputParameter(0, resultArr);
      
      //calculate
      maIndicator.calculate(0, priceArr.length - 1);
      print("ma result array: " + arrayToString(resultArr));
      
      int index = resultArr.length - shift - 1 - maIndicator.getLookback();
      double result = resultArr[index];
      return result;
   }

   
   private void print(Object o){
      console.getOut().println(o);
   }
   
   public static String arrayToString(double[] arr) {
      String str = "";
      for (int r = 0; r < arr.length; r++) {
         str += "[" + r + "] " + df.format(arr[r]) + "; ";
      }
      return str;
   }

   @Override
   public void onTick(Instrument instrument, ITick tick) throws JFException {}

   @Override
   public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {}

   @Override
   public void onMessage(IMessage message) throws JFException {}

   @Override
   public void onAccount(IAccount account) throws JFException {}

   @Override
   public void onStop() throws JFException {}

   /**
    * Custom implementation of a IRangeBar, which allows us to create range bars ourselves.
    *
    */
   public class MockRangeBar implements IRangeBar {

      public double open;
      public double close;
      public double low;
      public double high;
      public double vol;
      public long startTime;
      public long endTime;
      public int tickCount;

      @SuppressWarnings("serial")
      private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS") {
         {
            setTimeZone(TimeZone.getTimeZone("GMT"));
         }
      };
      private DecimalFormat df = new DecimalFormat("0.00000");

      public MockRangeBar() {

      }

      public MockRangeBar(double price, double volume, long time) {
            open = close = low = high = price;
            vol = volume;
            startTime = time;
            endTime = time;
            tickCount = 1;
      }

      public MockRangeBar(double open, double close, double low, double high, double vol, long startTime, long endTime, int tickCount) {
         this.open = open;
         this.close = close;
         this.low = low;
         this.high = high;
         this.vol = vol;
         this.startTime = startTime;
         this.endTime = endTime;
         this.tickCount = tickCount;
      }

      @Override
      public double getOpen() {
         return open;
      }

      @Override
      public double getClose() {
         return close;
      }

      @Override
      public double getLow() {
         return low;
      }

      @Override
      public double getHigh() {
         return high;
      }

      @Override
      public double getVolume() {
         return vol;
      }

      @Override
      public long getTime() {
         return startTime;
      }

      @Override
      public String toString() {

         StringBuilder str = new StringBuilder();
         str.append("StartTime: ").append(sdf.format(startTime)).append(" EndTime: ").append(sdf.format(endTime)).append(" O: ")
               .append(df.format(open)).append(" C: ").append(df.format(close)).append(" H: ").append(df.format(high)).append(" L: ")
               .append(df.format(low)).append(" V: ").append(df.format(vol)).append(" TickCount: ").append(tickCount);
         return str.toString();
      }

      @Override   
      public long getEndTime() {
         return endTime;
      }

      @Override
      public long getFormedElementsCount() {
         return tickCount;
      }

   }

}

Attachment:
RangeBarsHistory.java [7.72 KiB]
Downloaded 748 times
The example is rather evolved, so keep us posted if you need further assistance on this.


 
 Post subject: Re: applying an indicator to range bars Post rating: 0   Post Posted: Tue 29 Nov, 2011, 16:52 

User rating: 0
Joined: Tue 22 Nov, 2011, 12:47
Posts: 130
Location: United States,
hi Support,

Could I ask you kindly to change the example code to work with live feed and not with historical data? I'm finding it difficult to adjust the example to work with live data.

So - on each new Range Bar I would like to get the most up to date indicator value.

Many Thanks,
cb888trader.


 
 Post subject: Re: applying an indicator to range bars Post rating: 0   Post Posted: Wed 30 Nov, 2011, 09:40 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
We modified the code such that:
1) The latest indicator value gets retrieved.
2) The indicator values get calculated on every new range bar arrival. Additioanlly needed range bars for indicator calculation get formed from tick history.
package jforex.strategies.rangebars;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.TimeZone;

import com.dukascopy.api.*;
import com.dukascopy.api.IIndicators.MaType;
import com.dukascopy.api.bar.IRangeBar;
import com.dukascopy.api.indicators.IIndicator;
import com.dukascopy.api.listener.IRangeBarFeedListener;

/**
 * The strategy shows how to emulate range bar history.
 * Also it shows how to use range bar close prices with MA indicator.
 *
 */

@RequiresFullAccess
public class RangeBarsHistory2 implements IStrategy {

   private IConsole console;
   private IHistory history;
   private IIndicators indicators;
   private SimpleDateFormat sdf;

   @Configurable("Instrument")
   public Instrument instrument = Instrument.EURUSD;
   @Configurable("Offer Side")
   public OfferSide offerSide = OfferSide.BID;
   @Configurable("Price range (pips)")
   public int priceRangePips = 2;
   @Configurable("MA TimePeriod")
   public int maTimePeriod = 5;
   @Configurable("MA Shift")
   public int maShift = 0;
   @Configurable("Log values")
   public boolean logValues = true;
   @Configurable("(config) History Chunk Size")
   public Period historyChunkSize = Period.ONE_MIN;

   public static DecimalFormat df = new DecimalFormat("0.00000");
   private PriceRange priceRange;
   
   @Override
   public void onStart(IContext context) throws JFException {

      this.history = context.getHistory();
      this.console = context.getConsole();
      this.indicators = context.getIndicators();
      log("start");
      priceRange = PriceRange.valueOf(priceRangePips);

      sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
      
      context.subscribeToRangeBarFeed(instrument, offerSide, priceRange,
            new IRangeBarFeedListener() {
               public void onBar(Instrument instrument, OfferSide offerSide, PriceRange priceRange, IRangeBar bar) {
                  log("Received Range Bar: " + instrument + ", "  + offerSide + ", " + priceRange + ", " + bar);
                  
                  //previous range bars start at this range bar start time -1 milli
                  long histRangeBarStartTime = bar.getTime() - 1;
                  
                  //this much history price values we will need for indicator calculation
                  int histBarCount = maShift + maTimePeriod;
                  List<IRangeBar> rangeBars = null;
                  try {
                     rangeBars = getHistoryRangeBars(histBarCount, histRangeBarStartTime);
                  } catch (JFException e) {
                     console.getErr().println(e);
                  }
                  //add last formed range bar
                  rangeBars.add(bar);
                  
                  //log range bars (note that the last one will be the platform range bar with a bit different toString method
                  for(IRangeBar rangeBar : rangeBars){
                     log(rangeBar);
                  }
                  
                  //get close prices
                  double[] closePrices = new double[rangeBars.size()];
                  for(int i =0; i< rangeBars.size(); i++){
                     closePrices[i] = rangeBars.get(i).getClose();
                  }
                  
                  double ma = getMa(maTimePeriod, maShift,closePrices);
                  print("MA value with period " + maTimePeriod+ " and shift " + maShift +": "+ df.format(ma));
                  
               }
            });
      


      
      //context.stop();
   }

   /**
    * Returns historical range bars starting from histEndTime.
    *
    * @param count range bar count
    * @param histEndTime end time of the latest range bar
    * @return
    * @throws JFException
    */
   private List<IRangeBar> getHistoryRangeBars(int count, long histEndTime) throws JFException {

      long chunkInterval = historyChunkSize.getInterval();
      List<IRangeBar> rangeBars = new ArrayList<IRangeBar>();
      MockRangeBar rangeBar = null;
      ITick tick;
      boolean createNew = true;      

      while (rangeBars.size() < count) {
         //read ticks in chunks
         List<ITick> ticks = history.getTicks(instrument, histEndTime - chunkInterval, histEndTime);
         for (int i = ticks.size() - 1; i >= 0; i--) {
            tick = ticks.get(i);
            
            double price = offerSide == OfferSide.BID ? tick.getBid() : tick.getAsk();
            double volume = offerSide == OfferSide.BID ? tick.getBidVolume() : tick.getAskVolume();
            if (createNew) {
               if (rangeBar != null) {
                  rangeBars.add(rangeBar);
               }
               rangeBar = new MockRangeBar(price, volume, tick.getTime());
               createNew = false;
               continue;
            }
            if (Math.abs(rangeBar.open - price) > instrument.getPipValue() * priceRange.getPipCount()) {
               createNew = true;
               continue;
            }
            if (rangeBar.high < price) {
               rangeBar.high = price;
            }
            if (rangeBar.low > price) {
               rangeBar.low = price;
            }
            rangeBar.close = price;
            rangeBar.vol += volume;
            rangeBar.startTime = tick.getTime();
            rangeBar.tickCount++;

            if (rangeBars.size() >= count) {
               break;
            }
         }
         if (rangeBars.size() >= count) {
            break;
         }
         histEndTime -= chunkInterval;
      }

      //reverse such that the latest range bar is the last one
      Collections.reverse(rangeBars);
      return rangeBars;

   }
   
   /**
    * Calculates MA over an array, see more:
    * https://www.dukascopy.com/wiki/index.php?title=Strategy_API:_Indicators#Calculate_indicator_on_array
    *
    * @param timePeriod
    * @param shift
    * @param priceArr
    * @return
    */
   private double getMa(int timePeriod, int shift, double [] priceArr ) {
      IIndicator maIndicator = indicators.getIndicator("MA");
      
      //set optional inputs
      maIndicator.setOptInputParameter(0, 3);
      maIndicator.setOptInputParameter(1, MaType.SMA.ordinal());
      
      //set inputs
      maIndicator.setInputParameter(0, priceArr);
      
      //set outputs
      double [] resultArr = new double [priceArr.length];
      maIndicator.setOutputParameter(0, resultArr);
      
      //calculate
      maIndicator.calculate(0, priceArr.length - 1);
      print("ma result array: " + arrayToString(resultArr));
      
      int index = resultArr.length - shift - 1 - maIndicator.getLookback();
      double result = resultArr[index];
      return result;
   }

   
   private void print(Object o){
      console.getOut().println(o);
   }
   
   private void log(Object o){
      if(logValues){
         print(o);
      }
   }
   
   public static String arrayToString(double[] arr) {
      String str = "";
      for (int r = 0; r < arr.length; r++) {
         str += "[" + r + "] " + df.format(arr[r]) + "; ";
      }
      return str;
   }

   @Override
   public void onTick(Instrument instrument, ITick tick) throws JFException {}

   @Override
   public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {}

   @Override
   public void onMessage(IMessage message) throws JFException {}

   @Override
   public void onAccount(IAccount account) throws JFException {}

   @Override
   public void onStop() throws JFException {}

   /**
    * Custom implementation of a IRangeBar, which allows us to create range bars ourselves.
    *
    */
   public class MockRangeBar implements IRangeBar {

      public double open;
      public double close;
      public double low;
      public double high;
      public double vol;
      public long startTime;
      public long endTime;
      public int tickCount;

      @SuppressWarnings("serial")
      private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS") {
         {
            setTimeZone(TimeZone.getTimeZone("GMT"));
         }
      };
      private DecimalFormat df = new DecimalFormat("0.00000");

      public MockRangeBar() {

      }

      public MockRangeBar(double price, double volume, long time) {
            open = close = low = high = price;
            vol = volume;
            startTime = time;
            endTime = time;
            tickCount = 1;
      }

      public MockRangeBar(double open, double close, double low, double high, double vol, long startTime, long endTime, int tickCount) {
         this.open = open;
         this.close = close;
         this.low = low;
         this.high = high;
         this.vol = vol;
         this.startTime = startTime;
         this.endTime = endTime;
         this.tickCount = tickCount;
      }

      @Override
      public double getOpen() {
         return open;
      }

      @Override
      public double getClose() {
         return close;
      }

      @Override
      public double getLow() {
         return low;
      }

      @Override
      public double getHigh() {
         return high;
      }

      @Override
      public double getVolume() {
         return vol;
      }

      @Override
      public long getTime() {
         return startTime;
      }

      @Override
      public String toString() {

         StringBuilder str = new StringBuilder();
         str.append("StartTime: ").append(sdf.format(startTime)).append(" EndTime: ").append(sdf.format(endTime)).append(" O: ")
               .append(df.format(open)).append(" C: ").append(df.format(close)).append(" H: ").append(df.format(high)).append(" L: ")
               .append(df.format(low)).append(" V: ").append(df.format(vol)).append(" TickCount: ").append(tickCount);
         return str.toString();
      }

      @Override   
      public long getEndTime() {
         return endTime;
      }

      @Override
      public long getFormedElementsCount() {
         return tickCount;
      }

   }

}


Attachments:
RangeBarsHistory2.java [8.53 KiB]
Downloaded 770 times
DISCLAIMER: Dukascopy Bank SA's waiver of responsability - Documents, data or information available on this webpage may be posted by third parties without Dukascopy Bank SA being obliged to make any control on their content. Anyone accessing this webpage and downloading or otherwise making use of any document, data or information found on this webpage shall do it on his/her own risks without any recourse against Dukascopy Bank SA in relation thereto or for any consequences arising to him/her or any third party from the use and/or reliance on any document, data or information found on this webpage.
 
 Post subject: Re: applying an indicator to range bars Post rating: 0   Post Posted: Wed 30 Nov, 2011, 16:20 

User rating: 0
Joined: Tue 22 Nov, 2011, 12:47
Posts: 130
Location: United States,
thanks support this is really helpful.

1. Can you please provide more details on what this line does?

//set optional inputs
      maIndicator.setOptInputParameter(0, 3);


Shouldn't it be:

//set optional inputs
maIndicator.setOptInputParameter(0, maTimePeriod);



2. I changed the code to support live bars and not historical bars:

Cons -
The indicator will not be calculated until there are enough live bars.

Pros-
1. No need to query back and analyze ticks over and over again on each new range bar
2. The results should be more precise since it is not mock range bars but realtime bars

Can you please help me figuring out why the result does not match a visual SMA indicator on my chart? I wanted to compare the numbers so I opened a chart with SMA with the same Time Period. but the numbers are not an exact match. Any clue?


Here is my code -

package jforex;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.TimeZone;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.BlockingQueue;

import com.dukascopy.api.*;
import com.dukascopy.api.IIndicators.MaType;
import com.dukascopy.api.bar.IRangeBar;
import com.dukascopy.api.indicators.IIndicator;
import com.dukascopy.api.listener.IRangeBarFeedListener;

/**
 * The strategy shows how to emulate range bar history.
 * Also it shows how to use range bar close prices with MA indicator.
 *
 */

@RequiresFullAccess
public class RangeBarsHistory3 implements IStrategy {

   private IConsole console;
   private IHistory history;
   private IIndicators indicators;
   private SimpleDateFormat sdf;

   @Configurable("Instrument")
   public Instrument instrument = Instrument.EURUSD;
   @Configurable("Offer Side")
   public OfferSide offerSide = OfferSide.BID;
   @Configurable("Price range (pips)")
   public int priceRangePips = 3;
   @Configurable("MA TimePeriod")
   public int maTimePeriod = 5;
   @Configurable("MA Shift")
   public int maShift = 0;
   @Configurable("Log values")
   public boolean logValues = true;
   @Configurable("(config) History Chunk Size")
   public Period historyChunkSize = Period.ONE_MIN;

   public static DecimalFormat df = new DecimalFormat("0.00000");
   private PriceRange priceRange;
   
   private BlockingQueue<IRangeBar> rangeBars;
   
   @Override
   public void onStart(IContext context) throws JFException {

      this.history = context.getHistory();
      this.console = context.getConsole();
      this.indicators = context.getIndicators();
      
      log("start");
      
      
      priceRange = PriceRange.valueOf(priceRangePips);

      sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
      

      
      rangeBars = new ArrayBlockingQueue<IRangeBar>(maShift + maTimePeriod);
      
      
      context.subscribeToRangeBarFeed(instrument, offerSide, priceRange,
            new IRangeBarFeedListener() {
               public void onBar(Instrument instrument, OfferSide offerSide, PriceRange priceRange, IRangeBar bar) {
                  log("Received Range Bar: " + instrument + ", "  + offerSide + ", " + priceRange + ", " + bar);

                  if(rangeBars.remainingCapacity()==0){
                     //our queue is full
                     //lets take out the oldest range bar
                     print("Our Queue is full, Removing item: " + rangeBars.poll());
                  }
                  
                  
                  //store the new range bar
                  rangeBars.offer(bar);
                  
                  if(rangeBars.remainingCapacity()>0){
                     print("we do not have enough items for calculating indicator values");
                     return;
                  }
            
                  //get close prices
                  double[] closePrices = new double[rangeBars.size()];
                  
                  Iterator<IRangeBar> barsIterator = rangeBars.iterator();
                  int i = 0;
                  while (barsIterator.hasNext()) {
                     closePrices[i] = barsIterator.next().getClose();
                     i++;
                  }
                  
                  double ma = getMa(maTimePeriod, maShift, closePrices);
                  print("MA value with period " + maTimePeriod+ " and shift " + maShift +": "+ df.format(ma));
                  
               }
            });
      
   }
   
   /**
    * Calculates MA over an array, see more:
    * https://www.dukascopy.com/wiki/index.php?title=Strategy_API:_Indicators#Calculate_indicator_on_array
    *
    * @param timePeriod
    * @param shift
    * @param priceArr
    * @return
    */
   private double getMa(int timePeriod, int shift, double [] priceArr ) {
      IIndicator maIndicator = indicators.getIndicator("MA");
      
      double result = 0;
      
      
      //set optional inputs
      maIndicator.setOptInputParameter(0, maTimePeriod);
      maIndicator.setOptInputParameter(1, MaType.SMA.ordinal());
      
      //set inputs
      maIndicator.setInputParameter(0, priceArr);
      
      //set outputs
      double [] resultArr = new double [priceArr.length];
      maIndicator.setOutputParameter(0, resultArr);
      
      //calculate
      maIndicator.calculate(0, priceArr.length - 1);
      print("ma result array: " + arrayToString(resultArr));
      
      int index = resultArr.length - shift - 1 - maIndicator.getLookback();
      print("Retreiving MA from resultArr[" + index + "]");
      result  = resultArr[index];
      
      return result;
   }

   
   private void print(Object o){
      console.getOut().println(o);
   }
   
   private void log(Object o){
      if(logValues){
         print(o);
      }
   }
   
   public static String arrayToString(double[] arr) {
      String str = "";
      for (int r = 0; r < arr.length; r++) {
         str += "[" + r + "] " + df.format(arr[r]) + "; ";
      }
      return str;
   }

   @Override
   public void onTick(Instrument instrument, ITick tick) throws JFException {}

   @Override
   public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {}

   @Override
   public void onMessage(IMessage message) throws JFException {}

   @Override
   public void onAccount(IAccount account) throws JFException {}

   @Override
   public void onStop() throws JFException {}

}
   


Attachment:
RangeBarsHistory3.java [4.88 KiB]
Downloaded 679 times


 
 Post subject: Re: applying an indicator to range bars Post rating: 0   Post Posted: Wed 30 Nov, 2011, 18:02 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
We managed to receive the correct values with your strategy. With the following parameters:
Image
We received the following values:
Image
We also fixed the historical range bar calculation, but still there seem to be discrepancies.


Attachments:
RangeBarsHistory21.java [8.76 KiB]
Downloaded 810 times
DISCLAIMER: Dukascopy Bank SA's waiver of responsability - Documents, data or information available on this webpage may be posted by third parties without Dukascopy Bank SA being obliged to make any control on their content. Anyone accessing this webpage and downloading or otherwise making use of any document, data or information found on this webpage shall do it on his/her own risks without any recourse against Dukascopy Bank SA in relation thereto or for any consequences arising to him/her or any third party from the use and/or reliance on any document, data or information found on this webpage.
 
 Post subject: Re: applying an indicator to range bars Post rating: 0   Post Posted: Wed 30 Nov, 2011, 21:26 

User rating: 0
Joined: Tue 22 Nov, 2011, 12:47
Posts: 130
Location: United States,
Thank you support for the detailed analysis!

Unfortunately when trying to reproduce the same test - I noticed discrepancies. So I'm not sure - maybe you caught a specific incident.

Did you changed anything on my Strategy?

Any way - your results hold true for 1 pip range. But what if you go up: 3pips, 6 pips etc? On my side I noticed that the discrepancy increases.

So any clue on how to align the calculation hand in hand with the visual calculation? (1pip Range Bar is not something I plan to use - I need higher ranges)


 
 Post subject: Re: applying an indicator to range bars Post rating: 0   Post Posted: Thu 01 Dec, 2011, 09:36 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
We checked once again with the same parameters, except price range - which was set to 3 pips. The results still match:
Image
We only changed the strategy default parameters and from
closePrices[i] = barsIterator.next().getClose();
to
IRangeBar rangeBar = barsIterator.next();
log(rangeBar);
closePrices[i] = rangeBar.getClose();
for logging purposes, but that should not cause any difference.
In any case here is the strategy we ran:
Attachment:
RangeBarsHistory3.java [4.96 KiB]
Downloaded 683 times


 
 Post subject: Re: applying an indicator to range bars Post rating: 0   Post Posted: Thu 01 Dec, 2011, 11:03 

User rating: 0
Joined: Tue 22 Nov, 2011, 12:47
Posts: 130
Location: United States,
hi,

I found the bug. In the original example that you posted the following line:

      
//set optional inputs
maIndicator.setOptInputParameter(0, 3);


should be changed to

//set optional inputs
maIndicator.setOptInputParameter(0, maTimePeriod);


I can now confirm that the calculation is exact.

Thanks,
cb888trader.


 
 Post subject: Re: applying an indicator to range bars Post rating: 0   Post Posted: Thu 01 Dec, 2011, 11:47 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
cb888trader wrote:
I found the bug. In the original example that you posted the following line:
//set optional inputs
maIndicator.setOptInputParameter(0, 3);
should be changed to (..)
Yes that was the case, but in your strategy (RangeBarsHistory3.java) that was already fixed, so we didn't point it out.


 
 Post subject: Re: applying an indicator to range bars Post rating: 0   Post Posted: Thu 01 Dec, 2011, 12:25 

User rating: 0
Joined: Tue 22 Nov, 2011, 12:47
Posts: 130
Location: United States,
hi,

In regards to your algo of simulating Range Bars construction -

In the following line you skip the current tick if you find out that the range was broken:

   maxMove = Math.max(Math.max(Math.abs(rangeBar.open - price), Math.abs(rangeBar.high - price)),Math.abs(rangeBar.low - price));
   //last price broke the range - create new range bar with the next tick

   if (maxMove > range) {
      createNew = true;
      continue;
   }


Isn't that a problem? You are skipping the current tick so the next Range Bar is excluding it. Am I missing something?


 
 Post subject: Re: applying an indicator to range bars Post rating: 0   Post Posted: Thu 01 Dec, 2011, 13:33 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
cb888trader wrote:
In the following line you skip the current tick if you find out that the range was broken:
Thank you for pointing that out. That seems to be the cause of the different values, though still about half of the generated range bars differ from the ones of platform. Fixing this would require a bit more extra work.


Attachments:
RangeBarsHistory2Fix.java [8.72 KiB]
Downloaded 665 times
DISCLAIMER: Dukascopy Bank SA's waiver of responsability - Documents, data or information available on this webpage may be posted by third parties without Dukascopy Bank SA being obliged to make any control on their content. Anyone accessing this webpage and downloading or otherwise making use of any document, data or information found on this webpage shall do it on his/her own risks without any recourse against Dukascopy Bank SA in relation thereto or for any consequences arising to him/her or any third party from the use and/or reliance on any document, data or information found on this webpage.
 
 Post subject: Re: applying an indicator to range bars Post rating: 0   Post Posted: Thu 01 Dec, 2011, 13:59 

User rating: 0
Joined: Tue 22 Nov, 2011, 12:47
Posts: 130
Location: United States,
hi,

Great Job support!

Can you please do that extra effort to refine the code in order to match the system's generated Bars?

I think it will serve well the community in general and those who work with Range Bars like I do.

Thanks!!!
cb888tradaer.


 
 Post subject: Re: applying an indicator to range bars Post rating: 0   Post Posted: Fri 02 Dec, 2011, 14:50 

User rating: 0
Joined: Tue 22 Nov, 2011, 12:47
Posts: 130
Location: United States,
Hi support,

I'm trying to use the same example - but with different MA types. I added a configurable parameter in order to test different MA values.

I'm not getting good results - the numbers differ from UI results - actually - the Indicator seems to ignore MA type and uses SMA all the time.

Can you please help figuring out where is the problem?

Here is the code:
package jforex;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.TimeZone;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.BlockingQueue;

import com.dukascopy.api.*;
import com.dukascopy.api.IIndicators.MaType;
import com.dukascopy.api.bar.IRangeBar;
import com.dukascopy.api.indicators.IIndicator;
import com.dukascopy.api.listener.IRangeBarFeedListener;

/**
 * The strategy shows how to emulate range bar history.
 * Also it shows how to use range bar close prices with MA indicator.
 *
 */

@RequiresFullAccess
public class RangeBarsHistory3 implements IStrategy {

   private IConsole console;
   private IHistory history;
   private IIndicators indicators;
   private SimpleDateFormat sdf;

   @Configurable("Instrument")
   public Instrument instrument = Instrument.EURUSD;
   @Configurable("Offer Side")
   public OfferSide offerSide = OfferSide.BID;
   @Configurable("Price range (pips)")
   public int priceRangePips = 2;
   @Configurable("MA Type")
   public MaType maType = MaType.EMA;
   @Configurable("MA TimePeriod")
   public int maTimePeriod = 5;
   @Configurable("MA Shift")
   public int maShift = 0;
   @Configurable("Log values")
   public boolean logValues = true;
   @Configurable("(config) History Chunk Size")
   public Period historyChunkSize = Period.ONE_MIN;

   public static DecimalFormat df = new DecimalFormat("0.00000");
   private PriceRange priceRange;
   
   private BlockingQueue<IRangeBar> rangeBars;
   
   @Override
   public void onStart(IContext context) throws JFException {

      this.history = context.getHistory();
      this.console = context.getConsole();
      this.indicators = context.getIndicators();
      
      log("start");
      
      
      priceRange = PriceRange.valueOf(priceRangePips);

      sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
      

      
      rangeBars = new ArrayBlockingQueue<IRangeBar>(maShift + maTimePeriod);
      
      
      context.subscribeToRangeBarFeed(instrument, offerSide, priceRange,
            new IRangeBarFeedListener() {
               public void onBar(Instrument instrument, OfferSide offerSide, PriceRange priceRange, IRangeBar bar) {
                  log("Received Range Bar: " + instrument + ", "  + offerSide + ", " + priceRange + ", " + bar);

                  if(rangeBars.remainingCapacity()==0){
                     //our queue is full
                     //lets take out the oldest range bar
                     print("Our Queue is full, Removing item: " + rangeBars.poll());
                  }
                  
                  
                  //store the new range bar
                  rangeBars.offer(bar);
                  
                  if(rangeBars.remainingCapacity()>0){
                     print("we do not have enough items for calculating indicator values");
                     return;
                  }
            
                  //get close prices
                  double[] closePrices = new double[rangeBars.size()];
                  
                  Iterator<IRangeBar> barsIterator = rangeBars.iterator();
                  int i = 0;
                  while (barsIterator.hasNext()) {
                     IRangeBar _bar = barsIterator.next();
                     log(_bar);
                     closePrices[i] = _bar.getClose();
                     i++;
                  }
                  
                  double ma = getMa(maTimePeriod, maShift, closePrices);
                  print("MA value with period " + maTimePeriod+ " and shift " + maShift +": "+ df.format(ma));
                  
               }
            });
      
   }
   
   /**
    * Calculates MA over an array, see more:
    * https://www.dukascopy.com/wiki/index.php?title=Strategy_API:_Indicators#Calculate_indicator_on_array
    *
    * @param timePeriod
    * @param shift
    * @param priceArr
    * @return
    */
   private double getMa(int timePeriod, int shift, double [] priceArr ) {
      IIndicator maIndicator = indicators.getIndicator("MA");
      
      double result = 0;
      
      
      //set optional inputs
      maIndicator.setOptInputParameter(0, timePeriod);
      maIndicator.setOptInputParameter(1, maType.ordinal());
      
      //set inputs
      maIndicator.setInputParameter(0, priceArr);
      
      //set outputs
      double [] resultArr = new double [priceArr.length];
      maIndicator.setOutputParameter(0, resultArr);
      
      //calculate
      maIndicator.calculate(0, priceArr.length - 1);
      print("ma result array: " + arrayToString(resultArr));
      print("Moving Indicator Lookback = " + maIndicator.getLookback());
      print("resultArr.length = " + resultArr.length);
      int index = resultArr.length - shift - 1 - maIndicator.getLookback();
      print("Retreiving MA from resultArr[" + index + "]");
      result  = resultArr[index];
      
      return result;
   }

   
   private void print(Object o){
      console.getOut().println(o);
   }
   
   private void log(Object o){
      if(logValues){
         print(o);
      }
   }
   
   public static String arrayToString(double[] arr) {
      String str = "";
      for (int r = 0; r < arr.length; r++) {
         str += "[" + r + "] " + df.format(arr[r]) + "; ";
      }
      return str;
   }

   @Override
   public void onTick(Instrument instrument, ITick tick) throws JFException {}

   @Override
   public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {}

   @Override
   public void onMessage(IMessage message) throws JFException {}

   @Override
   public void onAccount(IAccount account) throws JFException {}

   @Override
   public void onStop() throws JFException {}

}
   


Attachment:
RangeBarsHistory3.java [5.1 KiB]
Downloaded 763 times


 
 Post subject: Re: applying an indicator to range bars Post rating: 0   Post Posted: Mon 05 Dec, 2011, 08:01 

User rating: 0
Joined: Tue 22 Nov, 2011, 12:47
Posts: 130
Location: United States,
hi Support,

I would greatly appreciate it if you can answer the above -

changing the MA Type doesn't seem to affect the array based indicator calculation.

Thanks!
cb888trader.


 
 Post subject: Re: applying an indicator to range bars Post rating: 0   Post Posted: Mon 05 Dec, 2011, 08:55 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
cb888trader wrote:
I would greatly appreciate it if you can answer the above -

changing the MA Type doesn't seem to affect the array based indicator calculation.
We reply as soon as available.
cb888trader wrote:
Can you please help figuring out where is the problem?
EMA needs some extra inputs to catch-up, because of its exponential nature - if you give it just one value then it equals SMA. Therefore for EMA try using the following value amount:
rangeBars = new ArrayBlockingQueue<IRangeBar>(maShift + maTimePeriod + 10);
Hence it is not always the case, that it suffices to pass value array of size shift + lookback. Depending on indicator (in more particular - indicator's IndicatorInfo), more inputs might be necessary, see unstablePeriod parameter description:
https://www.dukascopy.com/wiki/index.php?title=Indicator_API:_IndicatorInfo
You can also retrieve this information from your strategy in the following way:
https://www.dukascopy.com/wiki/index.php?title=Strategy_API:_Indicators#Retrieving_indicator_metadata
For instance, you might check, if the indicator period is unstable and if it is the case then pass more inputs to it.


 
 Post subject: Re: applying an indicator to range bars Post rating: 0   Post Posted: Mon 05 Dec, 2011, 09:48 

User rating: 0
Joined: Tue 22 Nov, 2011, 12:47
Posts: 130
Location: United States,
hi support,

How did you calculate 10? from the documentation - is it the unstablePeriod ? How can I get this value programmatically?

Do you know the extra buffer length that is required for KAMA (Kaufman Adaptive Moving Average)?

thx,
cb888trader.


 

Jump to:  

  © 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