Joseph Balnt
Joseph Balnt

Reputation: 140

How can I detect when an order fills using the Interactive Brokers Java API?

Problem

The IBKR TWS (Trader Workstation) is a tool for managing stock orders in the stock market, by Interactive Brokers. They provide an API to automate orders, like placing orders, cancelling orders, and more.

I'm creating a program to handle executed orders in my Trader Workstation using the Interactive Brokers Java API.

I'm having trouble detecting when an order fills.

The documentation describes that the execDetails callback (which is an EWrapper method, see code below) is invoked when an order is filled, but I tried using that and the execDetails callback was never invoked (I tested this by logging the reqid int in that callback, and I never got any log).

I have also researched about the completedOrder callback, which I'm not sure if that's the callback that will be invoked when an order is filled, because I tested both callbacks with a simple log, and nothing was outputting in the console.

I don't understand the reqExecutions function and whether I need that. I have already read the documentation on this callback, and I don't understand what I'm doing wrong. I want to know I how can detect when an order fills, or executes in the TWS using their API.


Code

Here is my current code:

import com.ib.client.*;

import java.util.*;

public class Main implements EWrapper {
    private static EClientSocket clientSocket;
    private static EJavaSignal readerSignal;

    public static void main(String[] args) throws InterruptedException, IOException {
        readerSignal = new EJavaSignal();
        clientSocket = new EClientSocket(this, readerSignal);
        clientSocket.eConnect("127.0.0.1", 7497, 0);
    }
    
    clientSocket.placeOrder(orderidE, contractFill("CUSIP", "USD", tickSymbol, "STK", "SMART"), orderFill(lmtPriceDouble, actionString, "LMT", "GTC", orderQuantity, account,  0));
    //Order executes successfully after sometime
    public static Order orderFill(double lmtPrice, String action, String orderType, String tif, int totalQuantity, String account, int clientId){
        Order order = new Order();
        order.m_lmtPrice = lmtPrice;
        order.m_action = action;
        order.m_orderType = orderType;
        order.m_tif = tif;
        order.m_totalQuantity = totalQuantity;
        order.m_account = account;
        order.m_clientId = clientId;
        return order;
    }
    public static Contract contractFill(String secIdType, String currency, String symbol, String secType, String exchange){
        Contract contract = new Contract();
        contract.m_secIdType = secIdType;
        contract.m_currency = currency;
        contract.m_symbol = symbol;
        contract.m_secType = secType;
        contract.m_exchange = exchange;
        return contract;
    }
    /*Implemented EWrapper methods
    ...
    */
    @Override
    public void execDetails(int reqId, Contract contract, Execution execution) {
        System.out.println(execution + " " + contract + " " + reqId);
    }

    @Override
    public void execDetailsEnd(int reqId) {
        System.out.println(reqId);
    }
    /*Implemented EWrapper methods
    ...
    */
    @Override
    public void completedOrder(Contract contract, Order order, OrderState orderState) {
        System.out.println(contract);
        System.out.println(order);
        System.out.println(orderState);
    }
    @Override
    public void completedOrdersEnd() {
        System.out.println("cOE");
    }/*Implemented rest of EWrapper methods
    ...
    */
}

I am placing the orders by hand while this code is running, and the order fills fairly quickly (while the code is running), so the code should detect it, but (my problem -->)none of the callbacks are being invoked. What am I supposed to be doing to detect order executions? (Note: I'm placing the orders by hand and by code in the TWS as of now).

Upvotes: 4

Views: 2297

Answers (1)

brian
brian

Reputation: 10989

Here is code that works, I tested with api 9.81.

Note that if you're using clientID 0 then you should also get callbacks from trades place in TWS. I've never tried, but the docs are clear.

import com.ib.client.*;
import java.io.IOException;

import java.util.*;

public class MainIB implements EWrapper {
    private EClientSocket clientSocket;
    private EJavaSignal readerSignal;
    
    public static void main(String[] args) throws IOException {
        new MainIB().connect();
        System.in.read();//press enter to exit
        System.exit(0);
    }
    
    private void connect() {
        readerSignal = new EJavaSignal();
        clientSocket = new EClientSocket(this, readerSignal);
        clientSocket.eConnect("127.0.0.1", 7497, 0);
        //Create a reader to consume messages from the TWS. The EReader will consume the incoming messages and put them in a queue
        EReader reader = new EReader(clientSocket, readerSignal);
        reader.start();
        //Once the messages are in the queue, an additional thread can be created to fetch them
        Thread processer = new Thread(() -> {
            while ( clientSocket.isConnected() ) { 
                readerSignal.waitForSignal();
                try {
                    reader.processMsgs();
                } catch (IOException ex) {}
            }
        });
        processer.setDaemon(true);
        processer.start();
    }
    
    public Order orderFill(double lmtPrice, String action, String orderType, String tif, int totalQuantity, String account, int clientId){
        Order order = new Order();
        order.lmtPrice(lmtPrice);
        order.action(action);
        order.orderType(orderType);
        order.tif(tif);
        order.totalQuantity(totalQuantity);
        //order.account(account);
        //order.clientId(clientId);
        return order;
    }
    public Contract contractFill(String secIdType, String currency, String symbol, String secType, String exchange){
        Contract contract = new Contract();
        //contract.secIdType(secIdType);
        contract.currency(currency);
        contract.symbol(symbol);
        contract.secType(secType);
        contract.exchange(exchange);
        return contract;
    }

    @Override
    public void error(int id, int errorCode, String errorMsg) {
        System.out.println(errorCode + " " + errorMsg);
    }

    @Override
    public void nextValidId(int i) {
        int orderidE = i;
        clientSocket.placeOrder(orderidE++, contractFill("", "CAD", "USD", "CASH", "IDEALPRO"), 
                                          orderFill(0, "SELL", "MKT", "GTC", 100000, "",  0));
    }

    @Override
    public void orderStatus(int i, String status, double d, double d1, double d2, int i1, int i2, double d3, int i3, String string1, double d4) {
        System.out.println("status " + status);
    }

    @Override
    public void execDetails(int reqId, Contract contract, Execution execution) {
        System.out.println(execution + " " + contract + " " + reqId);
    }
    
    /*Implemented rest of EWrapper methods
    ...
    */
}

Here is bit of my api.Day.0.log file

t:ms <-> msg#                        #  desc  
9:064 -> 15-1-DU123456-              15 my account #
9:065 -> 9-1-2-                      9 next valid id
9:065 -> 4-2--1-2104-Market da       4 errors(or info) 
9:065 -> 4-2--1-2104-Market da
9:072 <- 3-45-2-0-USD-CASH--0.       <- 3 means an order I sent   
9:671 -> 5-34-2-15016062-USD-C       5 order status
9:722 -> 11--1-2-15016062-USD-       11 exec 
9:724 -> 5-34-2-15016062-USD-C       more status
9:727 -> 5-34-2-15016062-USD-C
9:728 -> 59-1-0000e215.60b94f1       59 commission report

Upvotes: 3

Related Questions