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.

IIndicator.macd giving different results then JF client
 Post subject: IIndicator.macd giving different results then JF client Post rating: 0   Post Posted: Wed 29 Jun, 2011, 14:16 

User rating: -
Hello,

I'm working on a relatively simple MACD strategy, but I cannot get the IIndicator instance to give me the same numbers as generated in the JForex client. They're always a little off. I do apply the same offerside, period, appliedprice etc. yet I cannot reproduce the results that can be found in the Jforex client. It's definately not a timing issue either, just the numbers being up to about 10% off.

Any help would be greatly appreciated, I really cannot find the cause for this.

Johan


 
 Post subject: Re: IIndicator.macd giving different results then JF client Post rating: 0   Post Posted: Wed 29 Jun, 2011, 14:37 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
There are multiple things and parameters that might cause the results to differ, for example, a common cause is the time zone which should be adjusted to GMT. Could you please provide a source code fragment which brings different results from that of JForex client?


 
 Post subject: Re: IIndicator.macd giving different results then JF client Post rating: 0   Post Posted: Wed 29 Jun, 2011, 15:11 

User rating: -
Wow, thanks for your quick reply. Here a more elaborate outline of the problem.

package singlejartest;

import com.dukascopy.api.*;

public class MACDstrategy implements IStrategy {
    private IEngine engine = null;
    private IIndicators indicators = null;
    private int tagCounter = 0;
    private IConsole console;
    private IHistory history;
   
    double macdResult [];
    double lastmacdResult [];
   
    double stopLoss;
    double takeProfit;
   
    IOrder openOrder;
    ITick lastTick;
   
    private static final int NONE = 0;
    private static final int LONG = 1;
    private static final int SHORT = 2;
   
    int lastOrder = NONE;
   
    public static final String DATE_FORMAT_NOW = "yyyy-MM-dd HH:mm:ss";
   
    //DEBUG
    boolean flipper=false;
    //debug
   
    public void onStart(IContext context) throws JFException {
        engine = context.getEngine();
        history = context.getHistory();
        indicators = context.getIndicators();
        this.console = context.getConsole();
        console.getOut().println("Started");
       
       
    }

    public void onStop() throws JFException {
        for (IOrder order : engine.getOrders()) {
            order.close();
        }
        console.getOut().println("Stopped");
    }

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

    public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) {

       if (period != Period.ONE_MIN) return;
       if (instrument != Instrument.EURJPY) return;
       
          try {
          macdResult = indicators.macd(instrument, Period.ONE_MIN, OfferSide.BID, IIndicators.AppliedPrice.CLOSE, 40, 8, 80, 1 );
      } catch (JFException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }

      try{
            lastTick = history.getLastTick(instrument);
        }
        catch(JFException e) {
            e.printStackTrace(console.getErr());
        }
       
        //DEBUG
        //if (flipper== true) {macdResult [2] = 0.1; flipper= false;} else {macdResult [2] = -0.1; flipper= true;}
        //DEBUG
       
      System.out.println("Current: " + macdResult[2]);
       
      if (lastmacdResult!= null)  {
           System.out.println("Last: " + lastmacdResult[2]);
        }
      System.out.println("----------------");
      
      if (lastmacdResult !=null) {
         if (macdResult[2] >= 0.0000 && lastmacdResult[2]< 0.0000 && lastOrder != LONG) {
            stopLoss = lastTick.getBid() - 0.50;
            takeProfit = lastTick.getBid() + 1.20;
            try {
               if (openOrder != null) {
                  if (openOrder.getState() != IOrder.State.CLOSED) {
                     openOrder.close();
                  }
               }
               openOrder = engine.submitOrder(getLabel(instrument), instrument, IEngine.OrderCommand.BUY, 0.1, 0, 20, stopLoss, takeProfit);
               lastOrder = LONG;
            } catch (JFException e) {
               e.printStackTrace();
            }
         }
         if (macdResult[2] <= 0.0000 && lastmacdResult[2] > 0.0000 && lastOrder != SHORT) {
            stopLoss = lastTick.getBid() + 0.50;
            takeProfit = lastTick.getBid() - 1.20;
            try {
               if (openOrder != null) {
                  if (openOrder.getState() != IOrder.State.CLOSED) {
                     openOrder.close();
                  }
               }
               openOrder = engine.submitOrder(getLabel(instrument), instrument, IEngine.OrderCommand.SELL, 0.1, 0, 20, stopLoss, takeProfit);
               lastOrder = SHORT;
            } catch (JFException e) {
               e.printStackTrace();
            }
         }
      }
      lastmacdResult = macdResult;
   }

    //count open positions
    protected int positionsTotal(Instrument instrument) throws JFException {
        int counter = 0;
        for (IOrder order : engine.getOrders(instrument)) {
            if (order.getState() == IOrder.State.FILLED) {
                counter++;
            }
        }
        return counter;
    }

    protected String getLabel(Instrument instrument) {
        String label = instrument.name();
        label = label.substring(0, 2) + label.substring(3, 5);
        label = label + (tagCounter++);
        label = label.toLowerCase();
        return label;
    }

    public void onMessage(IMessage message) throws JFException {
    }

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


Is my code. it outputs as you can see in the overlay of my screenshot of the jforex client. as you can see. For the 13:55 minute MACD Hist on Jforex shows 0.0570678. My code shows 0.057202909204... for my strategy this is too big a difference. When I backtest this code, the orders are off (both ways, sometimes to early, sometimes too late).

(minute 13:54 was 0.0553319 on the client, and 0.554979... from my code)

The screenshot can be found at: https://www.forexfox.nl/extupl/macdproblem.png

Thanks in advance,

Johan

Both indicators are set to 40,8,80. Close price, bid.


 
 Post subject: Re: IIndicator.macd giving different results then JF client Post rating: 0   Post Posted: Thu 30 Jun, 2011, 12:16 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
Apparently the problem was that the timezone was not set to GMT. We adjusted your strategy to use the GMT, updated the print statements to include the time and added the indicator to the chart from the strategy.
package jforex.bugtests;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.TimeZone;

import com.dukascopy.api.*;

public class MACDstrategy implements IStrategy {
   private IEngine engine = null;
   private IIndicators indicators = null;
   private int tagCounter = 0;
   private IConsole console;
   private IHistory history;
   private IChart chart;

   double macdResult[];
   double lastmacdResult[];

   // macd specific params
   private int fastPeriod = 40;
   private int slowPeriod = 8;
   private int signalPeriod = 80;
   private int shift = 1;

   // strategy specific params
   private Instrument instrument = Instrument.EURJPY;
   private Period period = Period.ONE_MIN;

   double stopLoss;
   double takeProfit;

   IOrder openOrder;
   ITick lastTick;

   private static final int NONE = 0;
   private static final int LONG = 1;
   private static final int SHORT = 2;

   int lastOrder = NONE;

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

   // DEBUG
   boolean flipper = false;

   // debug

   public void onStart(IContext context) throws JFException {
      engine = context.getEngine();
      history = context.getHistory();
      indicators = context.getIndicators();
      this.console = context.getConsole();
      this.chart = context.getChart(instrument);
      console.getOut().println("Started");

      /* uncomment to see the ordering of optional parameters
      IIndicator indicator = indicators.getIndicator("MACD");
      for (int i = 0; i < indicator.getIndicatorInfo().getNumberOfOptionalInputs(); i++){
          console.getOut().println( i + ": name = '"+ indicator.getOptInputParameterInfo(i).getName() + "' type = "+ indicator.getOptInputParameterInfo(i).getType());
      }
      */
      chart.addIndicator(indicators.getIndicator("MACD"), new Object[]{fastPeriod, slowPeriod, signalPeriod});
   }

   public void onStop() throws JFException {
      for (IOrder order : engine.getOrders()) {
         order.close();
      }
      console.getOut().println("Stopped");
   }

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

   }

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

      if (period != this.period || instrument != this.instrument)
         return;

      macdResult = indicators.macd(instrument, period, OfferSide.BID, IIndicators.AppliedPrice.CLOSE, fastPeriod, slowPeriod,
            signalPeriod, shift);

      lastTick = history.getLastTick(instrument);
      
      // DEBUG
      // if (flipper== true) {macdResult [2] = 0.1; flipper= false;} else {macdResult [2] = -0.1; flipper= true;}
      // DEBUG

      print(sdf.format(bidBar.getTime()) + " Current: " + macdResult[2] + " whole array: " + arrayToString(macdResult));

      if (lastmacdResult != null) {
         print(sdf.format(bidBar.getTime()) + " Last: " + lastmacdResult[2]  + " whole array: " + arrayToString(macdResult));
      }
      print("----------------");

      if (lastmacdResult != null) {
         if (macdResult[2] >= 0.0000 && lastmacdResult[2] < 0.0000 && lastOrder != LONG) {
            stopLoss = lastTick.getBid() - 0.50;
            takeProfit = lastTick.getBid() + 1.20;
            if (openOrder != null) {
               if (openOrder.getState() != IOrder.State.CLOSED) {
                  openOrder.close();
               }
            }
            openOrder = engine
                  .submitOrder(getLabel(instrument), instrument, IEngine.OrderCommand.BUY, 0.1, 0, 20, stopLoss, takeProfit);
            lastOrder = LONG;
         }
         if (macdResult[2] <= 0.0000 && lastmacdResult[2] > 0.0000 && lastOrder != SHORT) {
            stopLoss = lastTick.getBid() + 0.50;
            takeProfit = lastTick.getBid() - 1.20;
            if (openOrder != null) {
               if (openOrder.getState() != IOrder.State.CLOSED) {
                  openOrder.close();
               }
            }
            openOrder = engine.submitOrder(getLabel(instrument), instrument, IEngine.OrderCommand.SELL, 0.1, 0, 20, stopLoss,
                  takeProfit);
            lastOrder = SHORT;
         }
      }
      lastmacdResult = macdResult;
   }

   // print both on client and java consoles
   private void print(Object o) {
      console.getOut().println(o);
      System.out.println(o);
   }
   
   public static String arrayToString(double [] arr){
      String str = "";
      for (int r=0; r<arr.length; r++) {
          str += " [" + r + "] " + (new DecimalFormat("0.000000")).format(arr[r]) + ", ";
      }
      return str;
   }

   // count open positions
   protected int positionsTotal(Instrument instrument) throws JFException {
      int counter = 0;
      for (IOrder order : engine.getOrders(instrument)) {
         if (order.getState() == IOrder.State.FILLED) {
            counter++;
         }
      }
      return counter;
   }

   protected String getLabel(Instrument instrument) {
      return (instrument.getPrimaryCurrency().toString() + instrument.getSecondaryCurrency().toString() + (tagCounter++)).toLowerCase();
   }

   public void onMessage(IMessage message) throws JFException {
   }

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


 
 Post subject: Re: IIndicator.macd giving different results then JF client Post rating: 0   Post Posted: Thu 30 Jun, 2011, 12:35 

User rating: -
Wow thanks for the effort. I'm having a little trouble compiling though. It's giving a nullPointerException at line 65.

(java.lang.NullPointerException @ jforex.bugtests.MACDstrategy.onStart(MACDstrategy.java:65)
null: java.lang.NullPointerException
at jforex.bugtests.MACDstrategy.onStart(MACDstrategy.java:65)
at com.dukascopy.api.impl.execution.t.call(Unknown Source)
at com.dukascopy.api.impl.connect.ao.a(Unknown Source)
at com.dukascopy.api.impl.connect.w.call(Unknown Source)
at com.dukascopy.api.impl.connect.w.call(Unknown Source)
at com.dukascopy.api.impl.execution.j.call(Unknown Source)
at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at com.dukascopy.api.impl.execution.f$a.f(Unknown Source)
at com.dukascopy.api.impl.execution.f$a.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
2011-06-30 13:30:07.452 ERROR DCClientImpl$a - Exception thrown while running onStart method: null
java.lang.NullPointerException
at jforex.bugtests.MACDstrategy.onStart(MACDstrategy.java:65)
at com.dukascopy.api.impl.execution.t.call(Unknown Source)
at com.dukascopy.api.impl.connect.ao.a(Unknown Source)
at com.dukascopy.api.impl.connect.w.call(Unknown Source)
at com.dukascopy.api.impl.connect.w.call(Unknown Source)
at com.dukascopy.api.impl.execution.j.call(Unknown Source)
at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source)
at java.util.concurrent.FutureTask.run(Unknown Source)
at com.dukascopy.api.impl.execution.f$a.f(Unknown Source)
at com.dukascopy.api.impl.execution.f$a.run(Unknown Source)
at java.lang.Thread.run(Unknown Source))

So, ALMOST there :-)?

Thanks again,

Johan


 
 Post subject: Re: IIndicator.macd giving different results then JF client Post rating: 0   Post Posted: Thu 30 Jun, 2011, 13:49 

User rating: -
Just found the obvious mistake in that line and testing now.

Thanks again,

J


 
 Post subject: Re: IIndicator.macd giving different results then JF client Post rating: 0   Post Posted: Thu 30 Jun, 2011, 14:22 

User rating: -
Oh no, same nullpointerexception....

J


 
 Post subject: Re: IIndicator.macd giving different results then JF client Post rating: 0   Post Posted: Thu 30 Jun, 2011, 14:43 

User rating: -
Also, wouldn't the wrong timezone result in the number begin out of synch (with a few bars in between, because of time difference)?

J


 
 Post subject: Re: IIndicator.macd giving different results then JF client Post rating: 0   Post Posted: Thu 30 Jun, 2011, 15:56 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
JohanRens wrote:
Also, wouldn't the wrong timezone result in the number begin out of synch (with a few bars in between, because of time difference)?
No JForex always works with GMT, it's Java the one that needs the timezone adjustment.
JohanRens wrote:
Oh no, same nullpointerexception....
Presumably you figured out that EURJPY chart has to be open and EURJPY instrument has to be selected in Historical Tester settings.


 
 Post subject: Re: IIndicator.macd giving different results then JF client Post rating: 0   Post Posted: Mon 04 Jul, 2011, 12:19 

User rating: -
Thanks for your help so far, but it doesn't seem to work (I'm starting the strategy in jforex now, whereas I was programming in eclipse beforehand).

It still is off. The code should produce a long signal if the MACD hist is of another polarity then the last MACD hist. But it doesn't. I still think it's due to the Iindicator giving slightly different results.

Any ideas?

Thanks in advance,

Johan Rensink

Here is another screenshot (from a backtest): https://imageshack.us/photo/my-images/811/macdproblem3.png/


 
 Post subject: Re: IIndicator.macd giving different results then JF client Post rating: 0   Post Posted: Tue 05 Jul, 2011, 08:35 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
JohanRens wrote:
It still is off. The code should produce a long signal if the MACD hist is of another polarity then the last MACD hist. But it doesn't. I still think it's due to the Iindicator giving slightly different results.
You can verify the results by comparing the print statements to the values of the drawn indicator. Moreover, after finalizing historical testing you can add to the chart another instance of MACD indicator and compare its values to the print statements and the values of MACD indicator added from your strategy. We noticed that the period in the chart was 30 mins, did you adjust the period in you strategy accordingly?


 
 Post subject: Re: IIndicator.macd giving different results then JF client Post rating: 0   Post Posted: Wed 06 Jul, 2011, 10:41 

User rating: -
Hi,

Yes I did change it into 30 mins (that was how the strategy was meant originally), but still the results as in my last post. Can you do better over there with that code and make the strategy trade on an MACD cross?? Also, in jforex, where do I find the console/code output? I've been programming in eclipse and the numbers are still off there, but perhaps it's different in the client.

Regards,

Johan


 
 Post subject: Re: IIndicator.macd giving different results then JF client Post rating: 0   Post Posted: Thu 07 Jul, 2011, 08:15 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
JohanRens wrote:
Can you do better over there with that code and make the strategy trade on an MACD cross??
Consider the following strategy (note that the parameters are pulled out as @Configurable):
package jforex.bugtests;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.TimeZone;

import com.dukascopy.api.*;
import com.dukascopy.api.IEngine.OrderCommand;

public class MACDstrategy2 implements IStrategy {
   private IEngine engine = null;
   private IIndicators indicators = null;
   private int tagCounter = 0;
   private IConsole console;
   private IHistory history;
   private IChart chart;

   // macd specific params
   private int fastPeriod = 40;
   private int slowPeriod = 8;
   private int signalPeriod = 80;

   // strategy specific params
   @Configurable("Insturment")
   public Instrument instrument = Instrument.EURJPY;
   @Configurable("Period")
   public Period period = Period.ONE_MIN;
   @Configurable("Stop Loss")
   public double stopLoss = 0.50;
   @Configurable("Take Profit")
   public double takeProfit = 1.20;
   @Configurable("Order amount")
   public double amount = 0.1;

   IOrder openOrder;

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

   public void onStart(IContext context) throws JFException {
      engine = context.getEngine();
      history = context.getHistory();
      indicators = context.getIndicators();
      this.console = context.getConsole();
      this.chart = context.getChart(instrument);
      console.getOut().println("Started");

      chart.addIndicator(indicators.getIndicator("MACD"), new Object[] { fastPeriod, slowPeriod, signalPeriod });
   }

   public void onStop() throws JFException {
      for (IOrder order : engine.getOrders()) {
         order.close();
      }
      console.getOut().println("Stopped");
   }

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

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

      if (period != this.period || instrument != this.instrument)
         return;

      double[] macdResult = indicators.macd(instrument, period, OfferSide.BID, IIndicators.AppliedPrice.CLOSE, fastPeriod, slowPeriod,
            signalPeriod, 1);
      double[] lastMacdResult = indicators.macd(instrument, period, OfferSide.BID, IIndicators.AppliedPrice.CLOSE, fastPeriod,
            slowPeriod, signalPeriod, 2);

      print(sdf.format(bidBar.getTime()) + " Current: " + macdResult[2] + " Last: " + lastMacdResult[2]);

      if (macdResult[2] >= 0 && lastMacdResult[2] < 0 && (openOrder == null || !openOrder.isLong())) {
         openOrder = submitOrder(OrderCommand.BUY);
      } else if (macdResult[2] <= 0 && lastMacdResult[2] > 0 && (openOrder == null || openOrder.isLong())) {
         openOrder = submitOrder(OrderCommand.SELL);
      }
   }

   private IOrder submitOrder(OrderCommand orderCmd) throws JFException {

      //close order and wait max 1 sec for the close to be finalized
      if(openOrder != null && engine.getOrders().contains(openOrder)){
         openOrder.close();
         openOrder.waitForUpdate(1000);
      }
      double stopLossPrice, takeProfitPrice;
      // Calculating stop loss and take profit prices
      if (orderCmd == OrderCommand.BUY) {
         stopLossPrice = history.getLastTick(this.instrument).getBid() - stopLoss;
         takeProfitPrice = history.getLastTick(this.instrument).getBid() + takeProfit;
      } else {
         stopLossPrice = history.getLastTick(this.instrument).getAsk() + stopLoss;
         takeProfitPrice = history.getLastTick(this.instrument).getAsk() - takeProfit;
      }

      // Submitting an order for the specified instrument at the current market price
      return engine.submitOrder(getLabel(instrument), this.instrument, orderCmd, this.amount, 0, 20, stopLossPrice, takeProfitPrice);
   }

   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 + "] " + (new DecimalFormat("0.000000")).format(arr[r]) + ", ";
      }
      return str;
   }

   protected String getLabel(Instrument instrument) {
      return (instrument.getPrimaryCurrency().toString() + instrument.getSecondaryCurrency().toString() + (tagCounter++)).toLowerCase();
   }

   public void onMessage(IMessage message) throws JFException {
   }

   public void onAccount(IAccount account) throws JFException {
   }
}
JohanRens wrote:
Also, in jforex, where do I find the console/code output?
If you are running strategy with live data, the IConsole.getOut().println() will print to the strategy-specific tab, if you are testing historical data you have to check Messages in Historical Tester tab in order to receive the messages. System.out.println() will print to the java console (if you have one turned on). See more about console here:
https://www.dukascopy.com/wiki/index.php?title=IConsole


 
 Post subject: Re: IIndicator.macd giving different results then JF client Post rating: 0   Post Posted: Tue 12 Jul, 2011, 15:11 

User rating: -
Hi,

The numbers are still not the same for longer periods (shorter ones seem to be ok), but also the backtester is giving me some trouble (hanging itself etc.). I'm going to switch to MT4 for this strategy for now.

Thanks for all the help.

Johan


 
 Post subject: Re: IIndicator.macd giving different results then JF client Post rating: 0   Post Posted: Wed 13 Jul, 2011, 14:05 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
If the historical tester hangs, please post the exception you get in java console


 

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