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.

Error handling for IEngine.submitOrder and IOrder.setXXX
 Post subject: Error handling for IEngine.submitOrder and IOrder.setXXX Post rating: 0   New post Posted: Tue 13 Jul, 2010, 05:53 

User rating: 0
Joined: Sun 11 Jul, 2010, 20:12
Posts: 20
In the MT4 world, it is a very good idea to wrap a bunch of error handling functionality (retires, etc) around the OrderSend and OrderModify functions because sometime you send an order and the order server is buys or disconnected or some other strange error can occur. This is why, for example, there are libraries like OrderReliable:
see for example https://www.forexmt4.com/_MT4_Experts/Li ... v1_1_4.mq4

So for JForex, how much error handling do we need? Sure, the simple submitOrder method works fine on a demo account but on a live account do we need to wrap a similar amount of error handling around this to make sure our order goes through? Is there an equivalent set of code anywhere that handles reliable delivery of new orders, changes to orders, etc.?


 
 Post subject: Re: Error handling for IEngine.submitOrder and IOrder.setXXX Post rating: 0   New post Posted: Tue 13 Jul, 2010, 09:28 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
You need to handle order states IOrder.State https://www.dukascopy.com/swiss/docs/api/index.htm
There is special method created to help do this IOrder.waitForUpdate https://www.dukascopy.com/swiss/docs/api/com/dukascopy/api/IOrder.html#waitForUpdate(long,%20java.util.concurrent.TimeUnit) or you can catch those order state messages in the onMessage method.


 
 Post subject: Re: Error handling for IEngine.submitOrder and IOrder.setXXX Post rating: 0   New post Posted: Tue 13 Jul, 2010, 16:30 

User rating: 0
Joined: Sun 11 Jul, 2010, 20:12
Posts: 20
I was hoping that someone had an actual set of code that handled all the error conditions as in the MQL4 OrderReliable library. It looks like I'll have to write my own. :-(

This answer raises several more questions:

When I submit a new order (or modify/close) an existing one, it looks like I must call IOrder.watForUpdate() which blocks until I ether get a timeout I specify or I get an order state change. Since this blocks, should I be calling this in a separate thread?

What happens if I specify a 20 second timeout and it times out? Is it still working on changing the state in the background even though waitForUpdate has now timed out? How will I ever know that the state has indeed changed?

Support: can you please provide a more detailed explanation of what happens here?


 
 Post subject: Re: Error handling for IEngine.submitOrder and IOrder.setXXX Post rating: 0   New post Posted: Tue 13 Jul, 2010, 16:33 

User rating: 0
Joined: Sun 11 Jul, 2010, 20:12
Posts: 20
And is it possible that I call submitOrder and then never hear anything back? How will I know that my attempt to submit an order has succeeded or failed?


 
 Post subject: Re: Error handling for IEngine.submitOrder and IOrder.setXXX Post rating: 0   New post Posted: Tue 13 Jul, 2010, 17:31 

User rating: 0
Joined: Sun 11 Jul, 2010, 20:12
Posts: 20
Sorry for flooding this thread with questions, but here is what I'm looking at. Let's suppose I want to use IEngine.submitOrder to submit a new order. Here's an outline of some possible code:

IOrder order=engine.submitOrder(getLabel(Symbol()), Symbol(), octype, lotsinmillions, price, slippage, sl, tp);
if (order!=null) {
message=order.waitForUpdate(20,TimeUnit.SECONDS); // wait at most 20 seconds
if (message!=null) {
IMessage.Type msgtype=message.getType();
if (msgtype==IMessage.Type.ORDER_SUBMIT_REJECTED) {
// May want to retry order here
} else if (msgtype==IMessage.Type.ORDER_SUBMIT_OK) {
console.getOut().println("submitOrder succeeded");
} else {
// is any other type of message possible here? If so, how do I handle it?
}
} else { // here if message==null which means timeout
// How do I handle a timeout? Is some other server process still trying to submit the order and change order state
// even after waitForUpdate times out? If I get a timeout, how can I retry the order without worrying about
// a duplicate order going through?
// Someone out there must certainly have written code to handle this!
}
} else { // here if submitOrder returns a null order
// what do I do here?
}

The comment above show my questions. In particular, I'm worried about what happens if I submit a new order and never hear back (ie I get a timeout, signaled by null message). If I know that submitting a new order definitely failed for some reason (because message is not null), then I may want to resubmit the order. But for a timeout, I won't know one way or the other, so how can I retry the order without worrying that the first (failed) order will eventually succeed, so that now I have a double order? And If I allow up to say 5 retries, I certainly want to avoid the possibility of my order going through 5 times in a row!

Someone certainly must have written robust order error handling code for JForex before. Doesn't support or anyone else have a more robust set of code that handles all the possibilities here?


 
 Post subject: Re: Error handling for IEngine.submitOrder and IOrder.setXXX Post rating: 0   New post Posted: Thu 15 Jul, 2010, 09:29 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
zortag wrote:
When I submit a new order (or modify/close) an existing one, it looks like I must call IOrder.watForUpdate() which blocks until I ether get a timeout I specify or I get an order state change. Since this blocks, should I be calling this in a separate thread?

All our messages are processed asynchroniously. You send the request, then after some time you will get a status update in onMessage method. We understand that handling asynchronious messages can be hard for someone. For those who wants to make orders processing synchronious, we added waitForUpdate message. It doesn't fully block current thread, you will still receive onMessage and onAccount updates, but you will not receive onTick or onBar events while thread is in this method. You don't need to call this method from the another thread or its synchronous idea will be broken.
zortag wrote:
What happens if I specify a 20 second timeout and it times out? Is it still working on changing the state in the background even though waitForUpdate has now timed out? How will I ever know that the state has indeed changed?

Yes it is still working. If you give up waiting in waitForUpdate, then you will get notification in onMessage anyway. 20 seconds timeout is unlikely though, usually this means some disconnect or error in strategy (you are waiting something that is not going to happen)
zortag wrote:
And is it possible that I call submitOrder and then never hear anything back? How will I know that my attempt to submit an order has succeeded or failed?

Yes if you get disconnect right after call. You will get message in onMessage method with message.getType() == IMessage.Type.CONNECTION_STATUS. After you will connect again, onMessage will be called with changes to the order.
zortag wrote:
Here's an outline of some possible code:

There is only one good reason for timeouts on submits - you got disconnect. You can keep track of disconnects by handling messages with message.getType() == IMessage.Type.CONNECTION_STATUS in onMessage method. If you don't have disconnect and got a timeout, then there is something totally wrong and you can... for example you can send a mail, make some sound and stop your strategy


 
 Post subject: Re: Error handling for IEngine.submitOrder and IOrder.setXXX Post rating: 0   New post Posted: Thu 15 Jul, 2010, 18:46 

User rating: 0
Joined: Sun 11 Jul, 2010, 20:12
Posts: 20
Thank you - this clears up a few issues. I have a couple more questions though:

Support wrote:
Yes if you get disconnect right after call. You will get message in onMessage method with message.getType() == IMessage.Type.CONNECTION_STATUS. After you will connect again, onMessage will be called with changes to the order.


Suppose I use the IOrder.waitForUpdate() method and I get a disconnect. In that case, will waitForUpdate return an IMessage with message.getType() == IMessage.Type.CONNECTION_STATUS? Or does this message only appear in onMessage()? If I use waitForUpdate will I get the same message in onMessage() or will my use of waitForUpdate mean that I never get that same message in onMessage()?


 
 Post subject: Re: Error handling for IEngine.submitOrder and IOrder.setXXX Post rating: 0   New post Posted: Fri 16 Jul, 2010, 15:41 
User avatar

User rating:
Joined: Fri 31 Aug, 2007, 09:17
Posts: 6139
Quote:
Suppose I use the IOrder.waitForUpdate() method and I get a disconnect. In that case, will waitForUpdate return an IMessage with message.getType() == IMessage.Type.CONNECTION_STATUS?
No, it won't.
Quote:
Or does this message only appear in onMessage()?
Yes
Quote:
If I use waitForUpdate will I get the same message in onMessage() or will my use of waitForUpdate mean that I never get that same message in onMessage()?
You will get your message in both places.


 
 Post subject: Re: Error handling for IEngine.submitOrder and IOrder.setXXX Post rating: 0   New post Posted: Fri 16 Jul, 2010, 17:26 

User rating: 0
Joined: Sun 11 Jul, 2010, 20:12
Posts: 20
OK so it appears that when we submit or change an order in JForex through our strategy, either the order submit change succeeds or fails or a timeout occurs. If it succeeds then fine. If it fails or times out, then we cannot resubmit it - or at least resubmitting it would give the same failed result. So "error handling" for orders is really just a matter of getting information back as to whether the order submit/change succeeded or not and we can't do anything if it doesn't succeed.

Using this understanding, here is some code I now use to monitor order. First inside my strategy class I declare some constants:

    public static final int IDXWAITLOOPS=7;
    public static final int ORDER_RESULT_UNKNOWN=0;
    public static final int ORDER_RESULT_OK=1;
    public static final int ORDER_RESULT_FAILED=-1;
    public static final int ORDER_RESULT_FAILED_RETRY=-2;   // never used since we can never retry
    public static final int ORDER_RESULT_FAILED_NULL_ORDER=-3;
    public static final int ORDER_RESULT_FAILED_FULL_TIMEOUT=-4;


Next inside my strategy class I declare a method waitForOrderUpdate():

    int waitForOrderUpdate(IOrder order, boolean neworder, boolean doprint) throws Exception {
        int orderresult=ORDER_RESULT_UNKNOWN;
        long i1=1;
        long i2=1;
        IMessage msg=null;

        if (order==null) return ORDER_RESULT_FAILED_NULL_ORDER;

        OrderSelect(order);   // sets the internal order to order
        String theticket=OrderTicket();
        //console.getOut().println("Inside waitForOrderUpdate, theticket is now "+StrOrNull(theticket));

        for (int idxwait=0;idxwait<IDXWAITLOOPS;i++) {
            //console.getOut().println("INFO: submitOrder idxwait= "+idxwait);

            msg=order.waitForUpdate(i2,TimeUnit.SECONDS);
            if (msg!=null) {
                IMessage.Type msgtype=msg.getType();
                if (neworder) {
                    if (msgtype==IMessage.Type.ORDER_SUBMIT_REJECTED) {
                        // Here we may want to see if it is possible to retry the order,
                        // but for now we just assume we cannot retry the order, just fail and print out that the order was rejected
                        if (true || doprint) {
                            console.getOut().println("WARNING: submitOrder was rejected for order with ID "+theticket);
                            console.getOut().println("       : msg content = "+msg.getContent());
                        }
                        orderresult=ORDER_RESULT_FAILED;
                    } else if (msgtype==IMessage.Type.ORDER_SUBMIT_OK) {
                        if (doprint) {
                            console.getOut().println("submitOrder succeeded for order with ID "+theticket);
                        }
                        orderresult=ORDER_RESULT_OK;
                    } else {
                        if (true || doprint) {
                            console.getOut().println("submitOrder gave some other message for order with ID "+theticket);
                            console.getOut().println("       : msg content = "+msg.getContent());
                        }
                        orderresult=ORDER_RESULT_UNKNOWN;
                    }
                } else {  // modify order
                    if (msgtype==IMessage.Type.ORDER_CHANGED_REJECTED) {
                        // Here we may want to see if it is possible to retry the order change,
                        // but for now we just assume we cannot retry the order change, just fail and print out that the order change was rejected
                        if (true || doprint) {
                            console.getOut().println("WARNING: change order was rejected for order with ID "+theticket);
                            console.getOut().println("       : msg content = "+msg.getContent());
                        }
                        orderresult=ORDER_RESULT_FAILED;
                    } else if (msgtype==IMessage.Type.ORDER_CHANGED_OK) {
                        if (doprint) {
                            console.getOut().println("change order succeeded for order with ID "+theticket);
                        }
                        orderresult=ORDER_RESULT_OK;
                    } else {
                        if (true || doprint) {
                            console.getOut().println("change order gave some other message for order with ID "+theticket);
                            console.getOut().println("       : msg content = "+msg.getContent());
                        }
                        orderresult=ORDER_RESULT_UNKNOWN;
                    }
                }
                //
                // we received our message so break out of the wait loop
                //
                break;
            } else {
                //
                // Here if msg==null which means timeout
                // Use a Fibonacci sequence of wait times: 1 sec, 2 sec 3 sec 5 sec 8 sec 13 sec 21 sec.
                //
                long pi2=i2;
                i2=i2+i1;
                i1=pi2;
            }
        }
        if (msg==null) {  //here if we timeout out on all waits, nothing we can do other than say the order failed
            orderresult=ORDER_RESULT_FAILED_FULL_TIMEOUT;
        }
        return orderresult;
    }


This method is called right after an engine.submitOrder() or after a change order call like IOrder.setStopLossPrice(). It uses a Fibonacci sequence of wait times (1 sec, 2 sec, 3 sec, 5 sec, 8 sec, 13 sec, 21sec) after which it officially times out. If it receives a message like ORDER_SUBMIT_OK or ORDER_SUBMIT_REJECTED any time before then, it breaks out of the wait loop and returns one of the return codes like ORDER_RESULT_OK or ORDER_RESULT_FAILED. The calling code should just test the return code from waitForOrderUpdate if the calling code cares whether the order was rejected or not.

For example to submit a new order:
            IOrder order=engine.submitOrder(getLabel(Symbol()), Symbol(), octype, lotsinmillions, price, slippage, sl, tp);
            if (order!=null) {
                int orderres=waitForOrderUpdate(order, true, printordermsgs);
                // don't do much of anything with orderres now since it never lets us know if we can retry the order
                if (orderres==ORDER_RESULT_OK) {
                    OrderSelect(order);
                    theticket=OrderTicket();
                    if (theticket==null) {
                        console.getOut().println("WARNING: ORDER_RESULT_OK but theticket is NULL!");
                    }
                    return theticket;
                } else {
                    console.getOut().println("WARNING: submitOrder returned "+orderres);
                    return null;
                }
            } else {
                console.getOut().println("WARNING: order is null after submitOrder");
                return null;
            }


or to change the stop loss of an existing order:
                    order.setStopLossPrice(sl);
                    orderres=waitForOrderUpdate(order, false, printordermsgs);
                    if (orderres!=ORDER_RESULT_OK) {
                        console.getOut().println("WARNING: change order Stop Loss returned "+orderres);
                        return false;
                    }


I hope other strategy developers will find this useful. As I said, it doesn't look like you can do anything about a rejected or timed out order anyway, but at least you can log it for informational purposes so you can manually take corrective action.


 

Jump to:  

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