3

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).

Joseph Balnt
  • 130
  • 9
  • Your description of what exactly you do not understand on those links is kinda vague. As it is now, it is not really clear what exactly to explain to you. – Zabuzard May 28 '21 at 18:30
  • On that note, you said that the documentation describes that the callback is invoked when the event happens. However, you just said _it does not work_, what does that mean? Does it not compile? Does it, but just not call the callback? Never? Did you put a print in the callback, never invoked? Can you please elaborate and also show the code versions of your tries? – Zabuzard May 28 '21 at 18:33
  • @Zabuzard I have edited my question, does it make more sense? – Joseph Balnt May 28 '21 at 19:58
  • It would help if you could share the code with your tries and elaborate in more detail whats going on, as explained. – Zabuzard May 28 '21 at 21:07
  • @Zabuzard Thank you for your help so far. I have revised my problem and code, does this make more sense to answer my question? – Joseph Balnt May 30 '21 at 00:07
  • Don't rely on your own logs, turn on api logging. Execs are 11 so look for something like time -> ????11 – brian May 30 '21 at 00:41
  • @brian I tried that, but I don't see how that's helping me. – Joseph Balnt May 30 '21 at 19:00
  • If you're not getting execs in the api log then you're not getting them at all. Maybe your order is the problem. Note that if you use TWS then you will see the api activity in TWS. – brian May 30 '21 at 19:55
  • @brian Where can I find the API activity in TWS? And how can I use that do detect when an order fills in my code? – Joseph Balnt May 31 '21 at 23:03
  • [api log](https://guides.interactivebrokers.com/tws/twsguide.htm#usersguidebook/configuretws/apisettings.htm) , don't include mkt data. In TWS there should be an API tab after you place an order. – brian Jun 01 '21 at 00:50
  • @brian I'm not getting an API tab after I place an order – Joseph Balnt Jun 01 '21 at 02:00
  • How do you know you're placing an order? Are there any errors, are you checking the log? It will be in a jts sub-dir. – brian Jun 01 '21 at 13:03
  • @brian When I place an order it comes in the Orders tab of the Activity section. I don't have a jts folder, I only have a tws folder. – Joseph Balnt Jun 01 '21 at 21:21
  • Ok, I just saw you are placing orders in TWS, not the api. It's more complicated like that. – brian Jun 02 '21 at 00:39
  • @brian I am now using my code to place the orders (I edited the code in the question), and I am getting that API window after they are placed. However, when the orders are filled, neither execDetails nor completedOrder is invoked, which is my problem. – Joseph Balnt Jun 02 '21 at 13:48
  • I'm not sure what completedOrder is for. You will get orderStatus for every status change and ExecDetails on fill. Make sure it's MKT if you want to see a quick fill. Look for the api.0.log file. – brian Jun 02 '21 at 14:51
  • @brian I am placing the order through my code, and when it executes (while the code is running), the execDetails callback is not working, even though I have implemented the EWrapper interface. What am I doing wrong? – Joseph Balnt Jun 03 '21 at 13:41
  • The part of your code with execDetails is ok. I don't even see how the rest of your code can run there are so many errors. That's why I keep suggesting to read the log files. – brian Jun 03 '21 at 15:57
  • @brian Where is the api.0.log file / other log files located? Also, what errors are you talking about (you can assume the variables are already defined)? – Joseph Balnt Jun 03 '21 at 20:33
  • My log files are in jts/??rand?hash??/api.0.Day.log , yours may be in a tws subdir. Just the errors I see are `this` in a static method, and the call to placeOrder outside of a method. Also I think in the newer api versions all the `m_` fields are private. – brian Jun 03 '21 at 22:52

1 Answers1

2

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
brian
  • 10,619
  • 4
  • 21
  • 79
  • It looks as though I didn't have an eReader to fetch the order messages, which is probably why the callback weren't invoked. It works now, thanks! – Joseph Balnt Jun 05 '21 at 14:10
  • That's why you should make your sample code as complete and runnable as possible. I understand leaving out all the interface impl. but it looked like you just copied pieces of code to the question since it was un-runnable. Plus, however you got the private m_ fields to work, there was an earlier api version with public fields and no readerSignal so it looked like code from 2 incompatible versions. – brian Jun 05 '21 at 21:14