Manage Order State

For full workflow of messages on order value or state change please refer to the Order state article. In this article we focus on providing examples on how one can handle order change events. There are two main ways one can go about monitoring order change:

  • In onMessage callback method.
  • By using the IOrder.waitForUpdate method (please do pay attention to method documentation in javadocs).

Essentially, both approaches provide similar functionality, but:

  • For imminent operations (e.g., set stop loss, close order) IOrder.waitForUpdate has the advantage of keeping all the logic in the same place.
  • For non-imminent operations (e.g., order close on stop loss, conditional order fill) one should not use IOrder.waitForUpdate since:
    • mostly it is non-deterministic when the operation will take place and
    • the execution of the method holds up the execution of the rest of the strategy logic
  • onMessage has the advantage of receiving messages about all order changes of the particular account, whilst IOrder.waitForUpdate only works with a single order.

The following subsections provide examples on how to work with both onMessage and IOrder.waitForUpdate.

Use OnMessage

The onMessage method receives all order change messages (on order state or value change), this callback method is also the place where one can apply some strategy logic on certain order changes.

Follow market order fill

Consider submitting market order and log messages as soon as he changes at server side:

public void onStart(IContext context) throws JFException {
    this.engine = context.getEngine();
    this.console = context.getConsole();
    context.setSubscribedInstruments(java.util.Collections.singleton(Instrument.EURUSD), true);
    engine.submitOrder("orderValid", Instrument.EURUSD, OrderCommand.BUY, 0.001);
}

public void onMessage(IMessage message) throws JFException {

    switch(message.getType()){
        case ORDER_SUBMIT_OK : 
            print("Order opened: " + message.getOrder());
            break;
        case ORDER_SUBMIT_REJECTED : 
            print("Order open failed: " + message.getOrder());
            break;
        case ORDER_FILL_OK : 
            print("Order filled: " + message.getOrder());
            break;
        case ORDER_FILL_REJECTED : 
            print("Order cancelled: " + message.getOrder());
            break;
    }
}

TestOnMessage

Stop loss update on fill

Consider submitting a market order with a stop loss price 5 pips below market price and, as soon as it gets filled, adjusting the stop loss price to be precisely 5 pips below the order open price:

public void onStart(IContext context) throws JFException {
    this.engine = context.getEngine();
    this.console = context.getConsole();
    context.setSubscribedInstruments(java.util.Collections.singleton(Instrument.EURUSD), true);

    double price = context.getHistory().getLastTick(Instrument.EURUSD).getBid();

    //submit order with SL and TP at 5 pip distance and slippage 20
    order = engine.submitOrder("orderValid", Instrument.EURUSD, OrderCommand.BUY, 0.001, 0, 20, 
        price - 0.0005, price + 0.0005);
}

public void onMessage(IMessage message) throws JFException {
    //update SL to be at 5 pips from open price
    if(message.getOrder() == order && message.getType() == IMessage.Type.ORDER_FILL_OK){
        order.setStopLossPrice(order.getOpenPrice() - 0.0005);  
    }
}

TestOnMessageSL.java

Stop loss update on fill with queue

Consider changing the previous example, such that the order updates take place in the onTick method instead of in onMessage. Apart from being a workaround for the previous example for earlier JForex-API versions, this approach also might come in handy if the user wants to do all of his order processing in one place (e.g. the onTick method).

private Queue<IOrder> justFilledOrders = new ConcurrentLinkedQueue<IOrder>();

//onStart the same as previous example - we skip it here

public void onMessage(IMessage message) throws JFException {
    if(message.getOrder() == order && message.getType() == IMessage.Type.ORDER_FILL_OK){
        justFilledOrders.add(message.getOrder());
    }
}

public void onTick(Instrument instrument, ITick tick) throws JFException {                              
    //process just filled orders
    while(!justFilledOrders.isEmpty()){
        IOrder filledOrder = justFilledOrders.poll();
        if(filledOrder == order){
            //update SL to be at 5 pips from open price
            order.setStopLossPrice(order.getOpenPrice() - 0.0005);  
        }
    }
}

TestOnMessageSLQueue.java

Resubmit Order

Consider a strategy which on its start submits a market order with an invalid amount such that the order gets rejected. In such case the order gets resubmitted with an increased amount until either the order gets successfully submitted or the maxOrderResubmitCount gets exceeded.

@Configurable("")
public int maxOrderResubmitCount = 5;

private Map<IOrder,Integer> resubmitAttempts = new HashMap<IOrder,Integer>();

public void onStart(IContext context) throws JFException {
    this.engine = context.getEngine();
    this.console = context.getConsole();
    context.setSubscribedInstruments(java.util.Collections.singleton(Instrument.EURUSD), true);

    IOrder order = engine.submitOrder("order", Instrument.EURUSD, OrderCommand.BUY, - 0.002);
    resubmitAttempts.put(order, 0);
}

public void onMessage(IMessage message) throws JFException {

    IOrder order = message.getOrder();

    if(message.getType() == IMessage.Type.ORDER_SUBMIT_REJECTED){
        console.getOut().println(message);
        Integer attempts = resubmitAttempts.get(order);
        if(attempts == null){
            console.getWarn().println("Rejected order was not created by this strategy.");
        } else if (attempts > maxOrderResubmitCount){
            console.getWarn().println("Rejected order has exceeeded resubmit attempt count.");
        } else {
            resubmitAttempts.remove(order);
            IOrder newOrder = engine.submitOrder(order.getLabel(), order.getInstrument(), order.getOrderCommand(), order.getAmount() + 0.001);
            resubmitAttempts.put(newOrder, ++attempts);
            console.getOut().println("Resubmitted order: " + newOrder + " attempts left: " +(maxOrderResubmitCount - attempts + 1));
        }
    }
}     

TestOnMessageResubmit.java

Use IOrder.waitForUpdate

IOrder.waitForUpdate is useful for operations when order change is imminent, like stop loss price update or order close. It is not advised to set the wait time more than a few seconds, since during prolonged IOrder.waitForUpdate execution ticks (LINK) get skipped and bars queue up.

Follow market order fill

Consider following marker order updates after its submission up till IOrder.State.FILLED by using the IOrder.waitForUpdate method.

public void onStart(IContext context) throws JFException {
   this.engine = context.getEngine();
   this.console = context.getConsole();
   context.setSubscribedInstruments(java.util.Collections.singleton(Instrument.EURUSD), true);

        IOrder order = engine.submitOrder("orderValid", Instrument.EURUSD, OrderCommand.BUY, 0.001);
        print(String.format("After submit: state=%s, open price=%.5f, creation time=%s",
                order.getState(), order.getOpenPrice(), DateUtils.format(order.getCreationTime())));

        order.waitForUpdate(2000, IOrder.State.OPENED); //wait max 2 sec for OPENED
        print(String.format("After update: state=%s, open price=%.5f, creation time=%s",
                order.getState(), order.getOpenPrice(), DateUtils.format(order.getCreationTime())));

        order.waitForUpdate(2000, IOrder.State.FILLED); //wait max 2 sec for FILLED
        print(String.format("After update: state=%s, open price=%.5f, fill time=%s",
                order.getState(),order.getOpenPrice(), DateUtils.format(order.getFillTime())));
}

TestWaitForUpdate.java

One can also wait for a certain state, for instance, wait till an order gets filled:

order.waitForUpdate(2000, IOrder.State.FILLED); //wait max 2 sec for FILLED

Stop loss update on fill

Consider awaiting the market order to get filled and then updating its stop loss depending on the actual open price.

public void onStart(IContext context) throws JFException {
    this.engine = context.getEngine();
    this.console = context.getConsole();
    context.setSubscribedInstruments(java.util.Collections.singleton(Instrument.EURUSD), true);

    double price = context.getHistory().getLastTick(Instrument.EURUSD).getBid();

    //submit order with SL and TP at 5 pip distance and slippage 20
    IOrder order = engine.submitOrder("orderValid", Instrument.EURUSD, OrderCommand.BUY, 0.001, 0, 20, 
        price - 0.0005, price + 0.0005);
        order.waitForUpdate(2000, IOrder.State.OPENED); //wait max 2 sec for OPENED
        order.waitForUpdate(2000, IOrder.State.FILLED); //wait max 2 sec for FILLED
    print(String.format("After fill: state=%s, open price=%.5f, fill time=%s, stop loss=%.5f",
    order.getState(),order.getOpenPrice(), sdf.format(order.getFillTime()), order.getStopLossPrice()));

    //adjust stop loss to be in 5 pip distance from open price
    order.setStopLossPrice(order.getOpenPrice() - 0.0005);
    order.waitForUpdate(2000); //wait max 2 sec for SL price to get updated
    print(String.format("After SL update: state=%s, open price=%.5f, fill time=%s, stop loss=%.5f",
        order.getState(),order.getOpenPrice(), sdf.format(order.getFillTime()), order.getStopLossPrice()));
}

TestWaitForUpdateSL.java

Resubmit order

The following example shows how to deal with cases when an order for some reason gets rejected - for simplicity it just submits an order with an invalid amount and on rejection resubmits the order:

public void onStart(IContext context) throws JFException {
    this.engine = context.getEngine();
    this.console = context.getConsole();
    context.setSubscribedInstruments(java.util.Collections.singleton(Instrument.EURUSD), true);

    IOrder order = engine.submitOrder("order", Instrument.EURUSD, OrderCommand.BUY, -0.001);

    IMessage message = order.waitForUpdate(2, TimeUnit.SECONDS);//wait max 2 sec for OPENED
    //resubmit order on rejection
    if(message.getType() == IMessage.Type.ORDER_SUBMIT_REJECTED){
        order = engine.submitOrder("order", Instrument.EURUSD, OrderCommand.BUY, 0.001);
        message = order.waitForUpdate(2, TimeUnit.SECONDS);//wait max 2 sec for OPENED
    }

    print(String.format("After update: state=%s, message=%s", order.getState(), message));              
}

Note that instead of checking the IMessage.Type one can also check the IOrder.State after the execution of IOrder.waitForUpdate.

TestWaitForUpdateResubmit.java

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