Dukascopy
 
 
Wiki JStore Search Login

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

    Submit JForex API bug reports in this forum only.
    Submit Converter issues in Converter Issues.
    Off topics are strictly forbidden.

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

com.dukascopy.api.JFException: Incorrect thread
 Post subject: com.dukascopy.api.JFException: Incorrect thread Post rating: 0   New post Posted: Thu 07 Aug, 2014, 16:52 

User rating: 0
Joined: Sat 28 Jun, 2014, 22:08
Posts: 6
Location: United KingdomUnited Kingdom
one shoot code:

Order CANCELLED: #250956270 ENTRY SELL 1 mil. AUD/JPY @ LIMIT 95.943 IF ASK <= 95.973 EXPIRES after: 01 hour 00 min 07 sec - Position #64329373
Order ACCEPTED: #250956507 ENTRY BUY 1 mil. AUD/JPY @ LIMIT 96.045 IF BID => 96.015 EXPIRES: 2014-07-03 01:00:21 - Position #64329401
Order ACCEPTED: #250956508 STOP LOSS SELL 1 mil. AUD/JPY @ MKT IF BID <= 95.975 - Position #64329401
Order ACCEPTED: #250956509 TAKE PROFIT SELL 1 mil. AUD/JPY @ LIMIT 96.055 IF BID => 96.055 - Position #64329401
Order ACCEPTED: #250956511 ENTRY SELL 1 mil. AUD/JPY @ LIMIT 95.905 IF ASK <= 95.935 EXPIRES: 2014-07-03 01:00:21 - Position #64329403
Order ACCEPTED: #250956512 STOP LOSS BUY 1 mil. AUD/JPY @ MKT IF ASK  => 95.975 - Position #64329403
Order ACCEPTED: #250956513 TAKE PROFIT BUY 1 mil. AUD/JPY @ LIMIT 95.895 IF ASK <= 95.895 - Position #64329403
Order FILLED at 95.912 (#250956511 ENTRY SELL 1 mil. AUD/JPY @ LIMIT 95.905 IF ASK <= 95.935 EXPIRES: 2014-07-03 01:00:21)  - Position #64329403
Cancelling order #250956507 ENTRY BUY 1000000 AUD/JPY @ LIMIT 96.065 IF BID => 96.015 at 2014-07-03 01:00:09.609 GMT by the strategy "TSAuto": from the local computer
com.dukascopy.api.JFException: Incorrect thread
   at com.dukascopy.api.impl.connect.validation.OrderValidator.validateClose(OrderValidator.java:445)
   at com.dukascopy.api.impl.connect.PlatformOrderImpl.close(PlatformOrderImpl.java:316)
   at com.dukascopy.api.impl.connect.PlatformOrderImpl.close(PlatformOrderImpl.java:421)
   at com.dukascopy.api.impl.connect.PlatformOrderImpl.close(PlatformOrderImpl.java:425)
   at com.dukascopy.api.impl.connect.PlatformOrderImpl.close(PlatformOrderImpl.java:429)
   at ffactory.direct3.DeadlineThread.run(DeadlineThread.java:31)
com.dukascopy.api.JFException: Incorrect thread
   at com.dukascopy.api.impl.connect.validation.OrderValidator.validateClose(OrderValidator.java:445)
   at com.dukascopy.api.impl.connect.PlatformOrderImpl.close(PlatformOrderImpl.java:316)
   at com.dukascopy.api.impl.connect.PlatformOrderImpl.close(PlatformOrderImpl.java:421)
   at com.dukascopy.api.impl.connect.PlatformOrderImpl.close(PlatformOrderImpl.java:425)
   at com.dukascopy.api.impl.connect.PlatformOrderImpl.close(PlatformOrderImpl.java:429)
   at ffactory.direct3.DeadlineThread.run(DeadlineThread.java:31)
com.dukascopy.api.JFException: Incorrect thread
   at com.dukascopy.api.impl.connect.validation.OrderValidator.validateClose(OrderValidator.java:445)
   at com.dukascopy.api.impl.connect.PlatformOrderImpl.close(PlatformOrderImpl.java:316)
   at com.dukascopy.api.impl.connect.PlatformOrderImpl.close(PlatformOrderImpl.java:421)
   at com.dukascopy.api.impl.connect.PlatformOrderImpl.close(PlatformOrderImpl.java:425)
   at com.dukascopy.api.impl.connect.PlatformOrderImpl.close(PlatformOrderImpl.java:429)
   at ffactory.direct3.DeadlineThread.run(DeadlineThread.java:31)
com.dukascopy.api.JFException: Incorrect thread
   at com.dukascopy.api.impl.connect.validation.OrderValidator.validateClose(OrderValidator.java:445)
   at com.dukascopy.api.impl.connect.PlatformOrderImpl.close(PlatformOrderImpl.java:316)
   at com.dukascopy.api.impl.connect.PlatformOrderImpl.close(PlatformOrderImpl.java:421)
   at com.dukascopy.api.impl.connect.PlatformOrderImpl.close(PlatformOrderImpl.java:425)
   at com.dukascopy.api.impl.connect.PlatformOrderImpl.close(PlatformOrderImpl.java:429)
   at ffactory.direct3.DeadlineThread.run(DeadlineThread.java:31)
com.dukascopy.api.JFException: Incorrect thread
   at com.dukascopy.api.impl.connect.validation.OrderValidator.validateClose(OrderValidator.java:445)
   at com.dukascopy.api.impl.connect.PlatformOrderImpl.close(PlatformOrderImpl.java:316)
   at com.dukascopy.api.impl.connect.PlatformOrderImpl.close(PlatformOrderImpl.java:421)
   at com.dukascopy.api.impl.connect.PlatformOrderImpl.close(PlatformOrderImpl.java:425)
   at com.dukascopy.api.impl.connect.PlatformOrderImpl.close(PlatformOrderImpl.java:429)
   at ffactory.direct3.DeadlineThread.run(DeadlineThread.java:31)
com.dukascopy.api.JFException: Incorrect thread

....SO ON UNTIL THE LOG FILE GET 2GB.


The business process is simple, when an order get filled the other one (in long or short position respectively) has to be cancel.
Unfortunatly, as you can see from the log, I get this error for every tick I receive, until the log file get 2Gb of size and for same reason the thread stop to iterate and write on the log this message.

Anybody out there has face the same issue?

Thanks,

Mario


 
 Post subject: Re: com.dukascopy.api.JFException: Incorrect thread Post rating: 0   New post Posted: Fri 08 Aug, 2014, 08:16 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
If your strategy works in multiple threads, you have to make sure that all order-changing operations get carried out from the main strategy thread, you can do this by calling IContext.executeTask. See examples:
https://www.dukascopy.com/wiki/#Threading/Examples


 
 Post subject: Re: com.dukascopy.api.JFException: Incorrect thread Post rating: 0   New post Posted: Tue 12 Aug, 2014, 12:37 

User rating: 0
Joined: Sat 28 Jun, 2014, 22:08
Posts: 6
Location: United KingdomUnited Kingdom
Thanks for the support; I tried to use this work around you suggested but nothing is change, I faced the same issue.
I moved the code to exec and close orders into a Runnable object, then passing it at IContext.executeTask method:

private class CloseOrder implements Callable<Object>{
           private IOrder order;
          
           public CloseOrder(IOrder order) {
               this.order = order;
           }
                          
           public Object call() throws Exception {
               order.close();
               return true;
           }
       }


Unfortunately I still get the 2Gb log file filled with the same Exception!


 
 Post subject: Re: com.dukascopy.api.JFException: Incorrect thread Post rating: 0   New post Posted: Wed 13 Aug, 2014, 09:11 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
Could you please provide an example strategy which replicates the case? If there are specific launch conditions please provide them as well.


 
 Post subject: Re: com.dukascopy.api.JFException: Incorrect thread Post rating: 0   New post Posted: Wed 13 Aug, 2014, 10:50 

User rating: 0
Joined: Sat 28 Jun, 2014, 22:08
Posts: 6
Location: United KingdomUnited Kingdom
As you asked, here the code, the submit method is like in pseudocode but the rest of the code is fine:

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.io.FilenameUtils;

import com.dukascopy.api.IAccount;
import com.dukascopy.api.IBar;
import com.dukascopy.api.IConsole;
import com.dukascopy.api.IContext;
import com.dukascopy.api.IDataService;
import com.dukascopy.api.IEngine;
import com.dukascopy.api.IFXSentimentIndex;
import com.dukascopy.api.IHistory;
import com.dukascopy.api.IMessage;
import com.dukascopy.api.IOrder;
import com.dukascopy.api.IStrategy;
import com.dukascopy.api.ITick;
import com.dukascopy.api.Instrument;
import com.dukascopy.api.JFException;
import com.dukascopy.api.Period;
import com.google.gson.Gson;





public class TSAuto implements IStrategy {

   private IEngine engine = null;
   private IConsole console = null;
   private IDataService dataService = null;
   private IHistory history = null;

   public String currency;
   public boolean longpos;
   public AtomicBoolean enter = new AtomicBoolean();
   public Entry entry;
   
   public Entry getEntry() {
      return entry;
   }

   public void setEntry(Entry entry) {
      this.entry = entry;
   }
   
   private IContext context;

   public void onStart(IContext context) throws JFException {
      this.context = context;
      engine = context.getEngine();
      dataService = context.getDataService();
      history = context.getHistory();
      console = context.getConsole();
      console.getOut().println("Started");
      engine.closeOrders(engine.getOrders());
   }
   
   int counter = 0;
   long timeEntered;

   
   @Override
   public void onTick(Instrument instrument, ITick tick) throws JFException {
      
         if (enter.get() && !orderFillOk && currency != null && counter<20 && timeEntered+14*1000<tick.getTime()) {
            
            counter++;
            timeEntered = tick.getTime();
            instrument = Instrument.valueOf(currency);
            tick = history.getLastTick(instrument);   
            
            context.executeTask(new OpenOrder(tick,instrument));
   
            if(counter==19 || orderFillOk) {
               enter.set(false);
               counter = 0;
               orderFillOk = false;
            }
         } else if (enter.get() && currency == null) {
            enter.set(false);
            counter = 0;
            orderFillOk = false;
         } else if(orderFillOk) {
            enter.set(false);
            counter = 0;
            orderFillOk = false;
         }
         
   }

   @Override
   public void onBar(Instrument instrument, Period period, IBar askBar,
         IBar bidBar) throws JFException {
      // TODO Auto-generated method stub

   }

   public HashMap<String, IOrder> createdOrders = new HashMap<String, IOrder>();
   
   boolean orderFillOk = false;
   
   @Override
   public void onMessage(IMessage message) throws JFException {
      try {
         if (message.getType().equals(IMessage.Type.ORDER_FILL_OK)) {      
            IOrder order = message.getOrder();
            if (order.getLabel().contains("DIRECT")) {
               if (order.isLong()) {
                  orderFillOk = true;
                  final IOrder aux =  createdOrders.get("SHORT");
                  if(aux!=null) {
                     context.executeTask(new CloseOrder(aux));
                  }
               } else {
                  orderFillOk = true;
                  final IOrder aux =  createdOrders.get("LONG");
                  if(aux!=null) {
                     context.executeTask(new CloseOrder(aux));
                  }
               }
            }
         }
      } catch(Exception e) {
         e.printStackTrace();
      }
   }

   @Override
   public void onAccount(IAccount account) throws JFException {
      // TODO Auto-generated method stub

   }

   @Override
   public void onStop() throws JFException {
      // TODO Auto-generated method stub

   }

   public String getCurrency() {
      return currency;
   }

   public boolean isLongpos() {
      return longpos;
   }

   public boolean tryEnter() {
      return enter.compareAndSet(false, true);
   }

   public void setCurrency(String currency) {
      this.currency = currency;
   }

   public void setLongpos(boolean longpos) {
      this.longpos = longpos;
   }

   public void setEnter(boolean enter) {
      this.enter.set(enter);
   }
   
   private class OpenOrder implements Callable<Object>{

      ITick tick = null;
      Instrument instrument = null;


        OpenOrder(ITick tick, Instrument instrument) {
            this.tick = tick;
            this.instrument = instrument;
        }
                       
        public Object call() throws Exception {
           long goodTillTime = tick.getTime() + 14 * 1000;

         IOrder longOrder = engine.submitOrder( .. parameters with goodTillTime.. );
         createdOrders.put("LONG", longOrder);
   
         IOrder shortOrder = engine.submitOrder( .. parameters with goodTillTime.. );
         createdOrders.put("SHORT", shortOrder);
           
            return true;
        }
    }
   
   private class CloseOrder implements Callable<Object> {
       private IOrder order;
          
       public CloseOrder(IOrder order) {
           this.order = order;
       }
                          
       public Object call() throws Exception {
           order.close();
           return true;
       }
   }
   
}




 
 Post subject: Re: com.dukascopy.api.JFException: Incorrect thread Post rating: 0   New post Posted: Thu 14 Aug, 2014, 13:19 

User rating: 0
Joined: Sat 28 Jun, 2014, 22:08
Posts: 6
Location: United KingdomUnited Kingdom
Have you been able to reproduce this problem?

Thanks,

Mario


 
 Post subject: Re: com.dukascopy.api.JFException: Incorrect thread Post rating: 0   New post Posted: Thu 14 Aug, 2014, 19:01 
User avatar

User rating: 98
Joined: Mon 23 Jul, 2012, 02:02
Posts: 656
Location: United States, Durham, NC
I do tons of asynchronous operations on Orders, but
NOT directly from the auxiliary threads !
You simply must understand IContext.executeTask(<Callable>)
in great detail, and avoid any "ordinary" asynch thread operations
on critical data structures.

Understanding Threading is critical, and I'm sure you do
understand it. But it's just like doing operations on some
Swing GUI element from an arbitrary thread.

Fortunately the API checks the Thread identity to avoid
data corruption.

Good Luck !
HyperScalper


 
 Post subject: Re: com.dukascopy.api.JFException: Incorrect thread Post rating: 0   New post Posted: Thu 14 Aug, 2014, 19:08 
User avatar

User rating: 98
Joined: Mon 23 Jul, 2012, 02:02
Posts: 656
Location: United States, Durham, NC
First of all, you don't need to use the
IContext.executeTask(<Callable>) from within
the IStrategy.onTick(...) since you are
already on the "order thread".

I'm not saying you don't know what you doing :)
or that it isn't legitimate,
but that looks very "strange" when you see
that in one of the IStrategy callback routines...

If you WAIT for completion of such a call, then
you will just get DEADLOCK.

             
            context.executeTask(new OpenOrder(tick,instrument));
   


You would have to get the Future<T> at the very
least, in order to be able to ensure that the task
executed without error, etc... normally, that is...

I haven't debugged your code, but that would
appear to be something you would not want
to do, as it is likely to be unnecessary at best,
and "deadlock prone" at worst (if you wait for
the result).

HyperScalper


 
 Post subject: Re: com.dukascopy.api.JFException: Incorrect thread Post rating: 0   New post Posted: Sat 16 Aug, 2014, 20:40 

User rating: 0
Joined: Sat 28 Jun, 2014, 22:08
Posts: 6
Location: United KingdomUnited Kingdom
Hi HyperScalper,

thank you for the double answer, unofortunatly I have to say that my application is not so "multithreading" there is just one thread I use to decide to enter, using an AtomicBoolean as flag for enter position, but the rest is just as a normal single-thread application.

I used the executeTask method cause the support had suggest this way, but as I wrote here I get the same exception.
Please have a look on the original solution code:

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicBoolean;

import com.dukascopy.api.IAccount;
import com.dukascopy.api.IBar;
import com.dukascopy.api.IConsole;
import com.dukascopy.api.IContext;
import com.dukascopy.api.IDataService;
import com.dukascopy.api.IEngine;
import com.dukascopy.api.IFXSentimentIndex;
import com.dukascopy.api.IHistory;
import com.dukascopy.api.IMessage;
import com.dukascopy.api.IOrder;
import com.dukascopy.api.IStrategy;
import com.dukascopy.api.ITick;
import com.dukascopy.api.Instrument;
import com.dukascopy.api.JFException;
import com.dukascopy.api.Period;
import com.google.gson.Gson;




public class TSAutoBK implements IStrategy {

   private IEngine engine = null;
   private IConsole console = null;
   private IDataService dataService = null;
   private IHistory history = null;

   public String currency;
   public boolean longpos;
   public AtomicBoolean enter = new AtomicBoolean();
   public Entry entry;
   
   
   public Entry getEntry() {
      return entry;
   }

   public void setEntry(Entry entry) {
      this.entry = entry;
   }

   public void onStart(IContext context) throws JFException {
      engine = context.getEngine();
      dataService = context.getDataService();
      history = context.getHistory();
      console = context.getConsole();
      console.getOut().println("Started");
      engine.closeOrders(engine.getOrders());
   }
   
   int counter = 0;
   long timeEntered;

   
   @Override
   public void onTick(Instrument instrument, ITick tick) throws JFException {
      //currency = "EURUSD";
      if(!forLog) {
         long goodTillTime = tick.getTime() + 14 * 1000;
         if (enter.get() && !orderFillOk && currency != null && counter<20 && timeEntered+14*1000<tick.getTime()) {
            counter++;
            
            IOrder longOrder = engine.submitOrder( ..parameters here with goodTillTime...);
   
            createdOrders.put("LONG", longOrder);
            
            IOrder shortOrder = engine.submitOrder( ..parameters here with goodTillTime...);
   
            createdOrders.put("SHORT", shortOrder);
   
            if(counter==19 || orderFillOk) {
               enter.set(false);
               counter = 0;
               orderFillOk = false;
            }
         } else if (enter.get() && currency == null) {
            enter.set(false);
            counter = 0;
            orderFillOk = false;
         } else if(orderFillOk) {
            enter.set(false);
            counter = 0;
            orderFillOk = false;
         }
      } else {
         //log
         IFXSentimentIndex sent = dataService.getFXSentimentIndex(instrument);
           logJson(instrument,tick,sent);
      }
   }

   @Override
   public void onBar(Instrument instrument, Period period, IBar askBar,
         IBar bidBar) throws JFException {
      // TODO Auto-generated method stub

   }

   public HashMap<String, IOrder> createdOrders = new HashMap<String, IOrder>();
   
   boolean orderFillOk = false;
   
   @Override
   public void onMessage(IMessage message) throws JFException {
      try {
         if(!forLog) {
            if (message.getType().equals(IMessage.Type.ORDER_FILL_OK)) {      
               IOrder order = message.getOrder();
               if (order.getLabel().contains("DIRECT")) {
                  if (order.isLong()) {
                     orderFillOk = true;
                     IOrder aux =  createdOrders.get("SHORT");
                     if(aux!=null)
                        aux.close();
                  } else {
                     orderFillOk = true;
                     IOrder aux =  createdOrders.get("LONG");
                     if(aux!=null)
                        aux.close();
                  }
               }
            }
         }
      } catch(Exception e) {
         e.printStackTrace();
      }
   }

   @Override
   public void onAccount(IAccount account) throws JFException {
      // TODO Auto-generated method stub

   }

   @Override
   public void onStop() throws JFException {
      // TODO Auto-generated method stub

   }

   public String getCurrency() {
      return currency;
   }

   public boolean isLongpos() {
      return longpos;
   }

   public boolean tryEnter() {
      return enter.compareAndSet(false, true);
   }

   public void setCurrency(String currency) {
      this.currency = currency;
   }

   public void setLongpos(boolean longpos) {
      this.longpos = longpos;
   }

   public void setEnter(boolean enter) {
      this.enter.set(enter);
   }
   
}



as you can see, it is quite straightforward! really I cant understand where the problem is....


 
 Post subject: Re: com.dukascopy.api.JFException: Incorrect thread Post rating: 2   New post Posted: Mon 18 Aug, 2014, 19:22 
User avatar

User rating: 98
Joined: Mon 23 Jul, 2012, 02:02
Posts: 656
Location: United States, Durham, NC
Don't place an IOrder return from IEngine.submit
into some collection. You don't need to. Just
use the String order label as a key, and then you
can query it later using IEngine.getOrders()
or getOrder(orderlLabelKey).

When using a double-submit as you are doing,
it may be useful (not required) to use waitForUpdate
which will enable you to check the status of the
submit. Ordinarily that will be delivered asynchronously
but you can wait for the small amount of time it will
take for status update using waitForUpdate.

I'm just writing this off the top of my head, but
you will need to submit a complete piece of code,
with parameters, so that somebody can replicate
your problem.

When you are in an onTick or onBar callback, then
you *are* on the proper thread (serialized) for
performing Order operations. That is correct.
But I can't debug your code :)

Only when you have asynch events which require access
to Order processing, then that is when you *must*
use IContext.executeTask(Callable) to do that;
otherwise you violate Threading requirements.

Most "naive"/"newbie" coders, coding simple things, just use
an onTick or onBar type of callback event to "drive"
their logic forward. That ensures they are automatically
on the Order callback thread, which will not result
in Thread violation exceptions. (Most of them will
not really understand threading, so this is a good
thing.)

Remember that if you are on the executeTask queue
thread, that waiting or blocking in that thread can
cause a Deadlock situation. You can get this same
problem when using the Swing event queue, and
using a blocking call which queues further events
on the same queue, which will never execute,
resulting in a Deadlock condition.

HyperScalper


 
 Post subject: Re: com.dukascopy.api.JFException: Incorrect thread Post rating: 1   New post Posted: Mon 18 Aug, 2014, 19:39 
User avatar

User rating: 98
Joined: Mon 23 Jul, 2012, 02:02
Posts: 656
Location: United States, Durham, NC
Keep in mind also that "driving" your logic
from within onTick can suffer dozens or more
callbacks per second.

This is a common problem where onTick events
trigger too many events, and the logic does
not "pace" things appropriately.

Perhaps better, unless you are trying to do some
HFT scalping is to drive from the onBar event
and filter for 10 seconds, or 30 seconds so that
your logic can check at those intervals how things
are going.

Using onTick is only for the most demanding of
logic, and is likely to cause problems..... unless
you really need onTick ... Performing Order
submissions in onTick needs some sort of
"throttling" logic to be sure it is not "overdriven"
which is not what you intend.

"Why is software so hard?" LOL

HyperScalper


 

Jump to:  

cron
  © 1998-2024 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