This tutorial will show you how to do some basic things with the Interactive Brokers API using Java, the code for everything in this tutorial can be found here.
First download and install Trader Workstation from the interactive brokers site – here.
Then grab the API from here. You are just looking for the TwsApi.jar from that package, so you can add it to your project.
You’ll also want to start TWS, go into configurations -> API -> Settings and check Enable Active X and Socket client
. Take note of the socket port as well, you will need it later.
Broker
We’ll start by adding a broker class to wrap all the Interactive Brokers API code, this is how our application will call IB. Let’s start by adding a connect() and disconnect() function, so your class should start like this:
(IBBroker.java)
import com.ib.client.EClientSocket;
public class IBBroker {
private EClientSocket __clientSocket;
public IBBroker(EClientSocket clientSocket, IBDatastore ibDatastore) {
__clientSocket = clientSocket;
__ibDatastore = ibDatastore;
}
public void connect() {
// ip_address, port, and client ID. Client ID is used to identify the app that connects to TWS, you can
// have multiple apps connect to one TWS instance
__clientSocket.eConnect("127.0.0.1",7497, 1);
}
public void disconnect() {
__clientSocket.eDisconnect();
}
}
Getting Messages from Interactive Brokers
To get messages/data from Interactive Brokers we have to implement their EWrapper interface.
(IBReceiver.java)
import com.ib.client.*;
import java.util.Set;
public class IBReceiver implements EWrapper {
@Override
public void tickPrice(int i, int i1, double v, int i2) {
}
.......
}
There are going to be lots of methods that we have to override, but technically we don’t have to fill out any of them, since they are all void
. We definitely want to implement the error() functions, since we want to know when something goes wrong. Other than that, we will just implement functions as we need them.
Datastore
We also want to add a data store class that will hold all the data that comes back or we set for IB. That way IBBroker and IBReceiver will be able to use the same data, plus you can pass this data store to any other class and they don’t have to know about IBBroker or IBReceiver.
(IBDatastore.java)
import java.util.HashMap;
public class IBDatastore {
public Integer nextValidId = null;
private HashMap<Integer, Tick> __ticks = new HashMap<Integer, Tick>();
public Tick getLatestTick(int symbolId) {
return __ticks.get(symbolId);
}
}
Wiring it up
And finally we tie everything together so that everything is connected:
(Main.java)
package com.queworx;
import com.ib.client.EClientSocket;
import com.ib.client.EJavaSignal;
import com.ib.client.EReaderSignal;
public class Main {
public static void main(String[] args) {
// Signal processing with TWS, we will not be using it
EReaderSignal readerSignal = new EJavaSignal();
IBDatastore ibDatastore = new IBDatastore();
IBReceiver ibReceiver = new IBReceiver(ibDatastore);
EClientSocket clientSocket = new EClientSocket(ibReceiver, readerSignal);
IBBroker ibBroker = new IBBroker(clientSocket, ibDatastore);
try
{
ibBroker.connect();
// Wait for nextValidId
for (int i=0; i<10; i++) {
if (ibDatastore.nextValidId != null)
break;
Thread.sleep(1000);
}
if (ibDatastore.nextValidId == null)
throw new Exception("Didn't get a valid id from IB");
// From here you can add the logic of your application
}
catch(Exception ex)
{
System.err.println(ex);
}
finally
{
ibBroker.disconnect();
System.exit(0);
}
}
}
Notice, that before we issue any requests to IB we wait for nextValidId
to be set. We use that Id when creating an order, but in general it indicates that the connection has been established and TWS is ready to receive requests.
Receiving Quotes
We will be using our broker to request quote information. We have to create a Contract and pass it to reqMktData. We also need to give unique int Ids to our instruments, IB will be giving those Ids back to us in the callback.
(IBBroker.java)
...
public void subscribeQuoteData(int tickerId, String symbol, String exchange) {
// full doc here - https://interactivebrokers.github.io/tws-api/classIBApi_1_1Contract.html
Contract contract = new Contract(0, symbol, "STK", null, 0.0d, null,
null, exchange, "USD", null, null, null,
"SMART", false, null, null);
// We are asking for additional shortable (236) and fundamental ratio (258) information.
// The false says that we don't want a snapshot, we want a streaming feed of data.
// https://interactivebrokers.github.io/tws-api/classIBApi_1_1EClient.html#a7a19258a3a2087c07c1c57b93f659b63
__clientSocket.reqMktData(tickerId, contract, "236,258", false, null);
}
...
For receiving information we will need to fill out tickPrice(), tickSize(), and tickGeneric() in IBReceiver to get the extra info we requested. For example, to modify tickPrice():
(IBReceiver.java)
...
@Override
public void tickPrice(int tickerId, int field, double price, int canAutoExecute) {
if (field != 1 && field != 2 && field != 4)
return;
Tick tick = __ibDatastore.getLatestTick(tickerId);
if (field == 1)
tick.bid = price;
else if (field == 2)
tick.ask = price;
else if (field == 4)
tick.last = price;
tick.modified_at = System.currentTimeMillis();
}
...
The full list of field types are here: https://interactivebrokers.github.io/tws-api/tick_types.html
Placing Orders
Let’s modify our IBBroker to be able to place orders.
(IBBroker.java)
...
private void createOrder(String symbol, String exchange, int quantity, double price, boolean buy)
{
// moved this out into it's own method
Contract contract = __createContract(symbol, exchange);
int orderId = __ibDatastore.nextValidId;
// https://interactivebrokers.github.io/tws-api/classIBApi_1_1Order.html
Order order = new Order();
order.clientId(__clientId);
order.transmit(true);
order.orderType("LMT");
order.orderId(orderId);
order.action(buy ? "BUY" : "SELL");
order.totalQuantity(quantity);
order.lmtPrice(price);
order.account(__ibAccount);
order.hidden(false);
order.minQty(100);
__clientSocket.placeOrder(orderId, contract, order);
// We can either request the next valid orderId or just increment it
__ibDatastore.nextValidId++;
}
...
Then on the receiver side we are going to be looking at the order status. The order status will be called when you submit the order and then any time anything changes. You might receive multiple messages for the same thing.
(IBReceiver.java)
...
@Override
public void orderStatus(int orderId, String status, double filled, double remaining, double avgFillPrice, int permId, int parentId, double lastFillPrice, int clientId, String whyHeld) {
/**
* Here we can check on how our order did. If it partially filled, we might want to resubmit at a different price.
* We might want to update our budget, so that we don't trade any more positions. Etc. All of this is a bit
* beyond the scope of this tutorial.
*/
}
...
Conclusion
The API itself is incredibly complicated, just as the TWS app itself is. You can trade various instruments – stocks, bonds, options, futures, etc. And there are all sorts of orders with all sorts of options. But this tutorial will hopefully get you started so that you can at least get something basic going and then add complexity to it as needed.
This tutorial’s code is on Github. If you need something more advanced, check out the full IB trader that I wrote a long time ago using the Groovy language.
Written by Eddie Svirsky