Close Orders

One can close orders by using either IOrder.close or IEngine.closeOrders methods:

  • To send a request to close the entire order amount use IOrder.close without parameters:

    engine.getOrder("OrderLabel").close();
  • To send a request to close the position with specified amount (partially close) use IOrder.close with an amount parameter:

    double amount = 0.001;
    engine.getOrder("OrderLabel").close(amount);
  • To send a request to close the position with specified price use IOrder.close with amount, price and slippage parameters:
    double lastBid = history.getLastTick(Instrument.EURUSD).getBid();
    order.close(0.3, lastBid - 100 * Instrument.EURUSD.getPipValue(), 5);
  • To close multiple orders use IOrder.close:
    engine.closeOrders(engine.getOrder("order1"), engine.getOrder("order2"), engine.getOrder("order3"));

It is restricted to send more than one order close request per second for the same order. IOrder.getClosePrice() and IOrder.getCloseTime() indicate the time and price of the last close, meaning that if the order gets closed in multiple iterations (i.e. partial close) then only data about the last close can be retrieved. In general, as before any other order changing actions, it is recommended to check the order state, for instance:

if(order.getState() == IOrder.State.FILLED || order.getState() == IOrder.State.OPENED){
    order.close();
} else {
    console.getOut().println("Unable to close order in state: " + order.getState());
}

Examples

Order close and cancel workflow

Consider a strategy which shows how to close and cancel orders and how to follow the wokflow of order states and messages. It also shows how to close/cancel all active orders.

package jforex.orders;

import com.dukascopy.api.*;
import static com.dukascopy.api.IOrder.State.*;
import com.dukascopy.api.IEngine.OrderCommand;

/**
 * The strategy creates an order and then partially closes it with various methods
 * and afterwards closes it in full.
 * 
 * The strategy also demonstrates how to manage the order state on closing or canceling the order.
 * 
 */
public class CloseOrderVarious implements IStrategy {

    private IConsole console;
    private IEngine engine;
    private IHistory history;
    private Instrument instrument = Instrument.EURUSD;

    @Override
    public void onStart(IContext context) throws JFException {
        console = context.getConsole();
        engine = context.getEngine();
        history = context.getHistory();
        context.setSubscribedInstruments(java.util.Collections.singleton(instrument), true);

        IOrder order = engine.submitOrder("order", instrument, OrderCommand.BUY, 0.01);
        order.waitForUpdate(2000, FILLED);

        if (order.getState() != FILLED) {
            console.getOut().println("Can't close order - order not filled: " + order.getState());
            context.stop();
        }

        // unconditional partial close
        order.close(0.003);
        order.waitForUpdate(2000);

        // conditional partial close by price
        double lastBid = history.getLastTick(instrument).getBid();
        order.close(0.003, lastBid - 100 * instrument.getPipValue());
        order.waitForUpdate(2000);

        // conditional partial close by price and slippage
        order.close(0.003, lastBid - 100 * instrument.getPipValue(), 5);
        order.waitForUpdate(2000);

        // unconditional full order close
        order.close();
        order.waitForUpdate(2000, CLOSED);

        if (order.getState() != CLOSED) {
            console.getErr().println("Can't create next order with the same label - order not closed: " +
                            order.getState());
            context.stop();
        }

        // place conditional order such that the price condition is not instantly met
        double price = history.getLastTick(instrument).getAsk() + 5 * instrument.getPipValue();
        order = engine.submitOrder("order", instrument, OrderCommand.BUYSTOP, 0.01, price);
        order.waitForUpdate(2000, OPENED);

        if (order.getState() != OPENED) {
            console.getErr().println("Can't cancel order - order : " + order.getState());
            context.stop();
        }
        order.close();
        order.waitForUpdate(2000, CANCELED);  

        //create both filled and opened orders
        price = history.getLastTick(instrument).getAsk();        
        for(int i = -5; i< 6; i++){
            String label = String.format("order_%sAsk%s", Math.abs(i),i < 0 ? "below" : "above");
            order = engine.submitOrder(
                            label, instrument, OrderCommand.BUYSTOP, 0.01, price + i*instrument.getPipValue());
            order.waitForUpdate(2000, OPENED, FILLED);
        }

        for(IOrder o: engine.getOrders()){
            console.getNotif().println("active orders: " + engine.getOrders());
             if (o.getState() == OPENED || o.getState() == FILLED) {
                 o.close();
                 o.waitForUpdate(2000, CLOSED, CANCELED);
             }
        }

        context.stop();

    }

    @Override
    public void onMessage(IMessage message) throws JFException {
        IOrder order = message.getOrder();
        if (order == null || message.getType() == IMessage.Type.NOTIFICATION) {
            return;
        }
        console.getOut().println(message);
        if (message.getType() == IMessage.Type.ORDER_CLOSE_OK) {
            console.getInfo().println(order + " " +
                    (order.getState() == CANCELED ? "cancelled" :
                    order.getState() == FILLED ? "partially closed" :
                    "fully closed")); //CLOSED
        }

    }

    @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 onAccount(IAccount account) throws JFException {}

    @Override
    public void onStop() throws JFException {}
}

CloseOrderVarious.java

Partial Close

Consider a strategy on its start opens a market order and in 3 increments partially closes the order until it has been closed completely. Strategy gets stopped once the order has been completely closed.

package jforex.strategies.oneorder;

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

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

/**
 * The strategy on its start opens an order and in 3 increments
 * partially closes the order until it has been closed completely.
 * Strategy gets stopped once the order has been completely closed.
 *
 */
@RequiresFullAccess
public class PartialClose implements IStrategy {

    private IOrder order;
    private IEngine engine;
    private IConsole console;
    private IContext context;

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

    @Override
    public void onStart(IContext context) throws JFException {
        engine = context.getEngine();
        console = context.getConsole();
        this.context = context;

        order = engine.submitOrder("order1", Instrument.EURUSD, OrderCommand.BUY, 1);
    }

    private void print(Object o){
        console.getOut().println(o);
    }

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

    @Override
    public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {
        if(instrument != Instrument.EURUSD || period != Period.TEN_SECS){
            return;
        }        
        if(order.getState() == IOrder.State.FILLED){
            order.close(0.4);
            order.waitForUpdate(2000);
            print(String.format("%s closePrice=%s closeTime=%s state=%s", 
                    order.getLabel(), order.getClosePrice(), sdf.format(order.getCloseTime()), order.getState()));
        }
    }

    @Override
    public void onMessage(IMessage message) throws JFException {
        print(message);
        if(order.getState() == IOrder.State.CLOSED){
            print("Order has been closed completely. Stop the strategy");
            context.stop();
            return;
        }
    }

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

    @Override
    public void onStop() throws JFException {}

}

Partial close by price

The strategy on its start opens an order and twice attempts to partially close the order by a price - one that fails and one that succeeds. Eventually the order gets closed in full without any price condition.

package jforex.orders2;

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

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

/**
 * The strategy on its start opens an order and twice attempts
 * to partially close the order by a price.
 * Eventually the order gets closed in full without a price condition
 *
 */
@RequiresFullAccess
public class PartialCloseByPrice implements IStrategy {

    private IOrder order;
    private IEngine engine;
    private IConsole console;
    private IHistory history;
    private Instrument instrument = Instrument.EURUSD;

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

    public void onStart(IContext context) throws JFException {
        engine = context.getEngine();
        console = context.getConsole();
        history = context.getHistory();
        double lastBid = history.getLastTick(instrument).getBid();

        order = engine.submitOrder("orderPartialClose", instrument, OrderCommand.BUY, 1);
        order.waitForUpdate(2000); //wait for OPENED
        order.waitForUpdate(2000); //wait for FILLED

        //should fail with ORDER_CLOSE_REJECTED, since it is unlikely to have liquidity at such price
        order.close(0.3, lastBid + 100 * instrument.getPipValue(), 5);
        order.waitForUpdate(2000); //wait for order change

        //should succeed with ORDER_CLOSE_OK, since jforex allows positive slippage 
        order.close(0.3, lastBid - 100 * instrument.getPipValue(), 5);
        order.waitForUpdate(2000); //wait for order change

        order.close(); //close in full
        context.stop();//stop the strategy
    }

    private void print(Object o){
        console.getOut().println(o);
    }

    public void onMessage(IMessage message) throws JFException {
        print(message);
            print(String.format("%s closePrice=%.5f, amount=%.3f, requestedAmount=%.3f, closeTime=%s, state=%s", 
                    order.getLabel(), order.getClosePrice(), order.getAmount(), order.getRequestedAmount(), 
                    sdf.format(order.getCloseTime()), order.getState()));

    }

    public void onTick(Instrument instrument, ITick tick) throws JFException {}
    public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {}
    public void onAccount(IAccount account) throws JFException {}
    public void onStop() throws JFException {}

}

PartialCloseByPrice.java

Close by time interval

Consider a strategy which closes an order after designated time after its fill.

@Configurable(value = "Close order after (secs)", description = "Time interval after which the order gets closed.")
public int orderCloseSecs = 10;

@Override
public void onStart(IContext context) throws JFException {
    engine = context.getEngine();
    console = context.getConsole();
    order = engine.submitOrder("order1", Instrument.EURUSD, OrderCommand.BUY, 0.01);
}

@Override
public void onTick(Instrument instrument, ITick tick) throws JFException {
    if(order.getState() == IOrder.State.FILLED 
        && order.getFillTime() + orderCloseSecs * 1000 < tick.getTime()){
            order.close();
    }
}

OrderTimedClose.java

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