Building the IBKR C++ API Client Library
Recently, I wanted to use the C++ API client library that Interactive Brokers provides and experiment with some algorithmitic trading and monitoring of my positions. I had hoped there would be some precompiled binaries already for MacOS & Linux/aarch64; however, I did not have luck finding any. That is not a problem since Interactive Brokers provides the source to the client libraries under a license that allows for non-commercial use. The source can be downloaded here after agreeing to the license.
I downloaded the Latest
release of the library for Mac/Unix, which at the time of this writing is version API 10.34
. Once downloaded, I extracted the .zip file:
~/Downloads $ unzip -d twsapi_macunix.1034.02 twsapi_macunix.1034.02.zip
The build documentation for Mac/Unix is available here. The documentation is mostly focused on the building the Python library and the C++ library build documentation is lacking. The API’s Decimal
implementation also has an odd dependency on the Intel Decimal Library, which was concerning since I wanted to build this for MacOS on Apple Silicon and Linux/aarch64. I assumed the Intel library is Intel-specific, but much to my pleasant surprise it is not.
After downloading the Intel Decimal Floating-Point Math Library from: https://www.intel.com/content/www/us/en/developer/articles/tool/intel-decimal-floating-point-math-library.html, I extracted that tarball:
Building the Intel Decimal Floating-Point Math Library
~/Downloads $ tar xvzf IntelRDFPMathLib20U2.tar.gz
Interactive Brokers provides steps to build the library contained in IBJts/source/cppclient/Intel_lib_build.txt
, which I followed with some necessary modifications below:
IntelRDFPMathLib20U2/LIBRARY modify "makefile":
a)
Line 370:
change
BID_LIB = $(LIB_DIR)/libbid.$A
to
BID_LIB = $(LIB_DIR)/libbid.dylib # or .so when building on Linux
b)
Line 377:
change
$(AR_CMD) $(AR_OUT)$@ $^
to
gcc -o $@ $^ -shared
c)
Line 112:
change
_CFLAGS_OPT :=
to
_CFLAGS_OPT := -fPIC -Wno-implicit-function-declaration # added to avoid issues with newer versions of clang and gcc (>=14), which now treat implicit function declarations as an error
If building on Linux/aarch64, the following error will be encountered about an unknown architecture:
[dlewis@defiant LIBRARY]$ make
makefile.iml_head:356: *** Unknown host architecture aarch64. Stop.
This can be easily fixed by making some small changes to the makefile.iml_head
file around line 347:
# add aarch64 with EFI2 specified for both ARCH_LIST and ARCH_TYPE
ARCH_ALIAS := x86 ia64 EM64T x86_64 i686 amd64 Intel64 sun4u aarch64
ARCH_LIST := IA32 IA64 EFI2 EFI2 IA32 EFI2 EFI2 EFI2 EFI2
ARCH_TYPE := IA32 IA64 EFI2 EFI2 IA32 EFI2 EFI2 EFI2 EFI2
ARCH_TYPES := IA32 IA64 EFI2
Now, the Intel Decimal Library can be built without issues on MacOS or Linux/aarch64:
~/Downloads/IntelRDFPMathLib20U2/LIBRARY $ make CC=gcc CALL_BY_REF=0 GLOBAL_RND=0 GLOBAL_FLAGS=0 UNCHANGED_BINARY_FLAGS=0
Once the build finishes, there will be a .dylib/.so:
~/Downloads/IntelRDFPMathLib20U2/LIBRARY $ ls -l libbid.dylib
-rwxr-xr-x 1 dlewis staff 5019408 Feb 11 14:39 libbid.dylib
~/Downloads/IntelRDFPMathLib20U2/LIBRARY $ file libbid.dylib
libbid.dylib: Mach-O 64-bit dynamically linked shared library arm64
Building the IBKR C++ API Client Library
Back to building the IBKR C++ API client library. The libbid.dylib/.so needs to be copied to IBJts/source/cppclient/client/lib
:
~/Downloads/twsapi_macunix.1034.02/IBJts/source/cppclient/client $ mkdir lib
~/Downloads/twsapi_macunix.1034.02/IBJts/source/cppclient/client $ cp ~/Downloads/IntelRDFPMathLib20U2/LIBRARY/libbid.dylib lib/
~/Downloads/twsapi_macunix.1034.02/IBJts/source/cppclient/client $ ls -l lib/libbid.dylib
-rwxr-xr-x 1 dlewis staff 5019408 Feb 11 14:44 lib/libbid.dylib
I had many issues building with CMake in IBJts/source/cppclient/client
, and the sources include a generic makefile
, which seemed much easier to modify, so I went that route instead. Here’s my slightly modified makefile
:
CXX=g++
CXXFLAGS=-pthread -Wall -Wno-switch -Wno-unused-function -std=c++11 -shared -fPIC
ROOT_DIR=.
BASE_SRC_DIR=${ROOT_DIR}
INCLUDES=-I${ROOT_DIR}
LIB_DIR=lib
LIB_NAME=bid
TARGET=libTwsSocketClient.dylib # or .so if building on Linux
$(TARGET):
$(CXX) $(CXXFLAGS) $(INCLUDES) $(BASE_SRC_DIR)/*.cpp -L$(LIB_DIR) -l$(LIB_NAME) -o$(TARGET)
clean:
rm -f $(TARGET) *.o
Once that is modified, make
can simply be run without issue:
~/Downloads/twsapi_macunix.1034.02/IBJts/source/cppclient/client $ make
g++ -pthread -Wall -Wno-switch -Wno-unused-function -std=c++11 -shared -fPIC -I. ./*.cpp -Llib -lbid -olibTwsSocketClient.dylib
In preparation for building the sample client IBKR provides, I copied libTwsSocketClient.dylib
to lib
, where previously libbid.dylib
was copied to:
~/Downloads/twsapi_macunix.1034.02/IBJts/source/cppclient/client $ cp libTwsSocketClient.dylib lib/
~/Downloads/twsapi_macunix.1034.02/IBJts/source/cppclient/client $ ls -l lib/
total 12200
-rwxr-xr-x 1 dlewis staff 1221496 Feb 11 14:57 libTwsSocketClient.dylib
-rwxr-xr-x 1 dlewis staff 5019408 Feb 11 14:44 libbid.dylib
Building the C++ Sample Application
Now, the client can be built in IBJts/samples/Cpp/TestCppClient
. First, some similar makefile
modifications need to be made, and again I avoided using CMake because of problems encountered with the build process. It can be made to work, but it is much simpler to just use the provided makefile
. Here is my diff of the makefile after modifications:
~/Downloads/twsapi_macunix.1034.02/IBJts/samples/Cpp/TestCppClient $ diff -u makefile makefile.orig
--- makefile 2025-02-11 15:03:37
+++ makefile.orig 2025-02-11 15:02:31
@@ -4,10 +4,10 @@
BASE_SRC_DIR=${ROOT_DIR}/client
INCLUDES=-I${BASE_SRC_DIR} -I${ROOT_DIR}
SOURCE_DIR=${BASE_SRC_DIR}
-SOURCE_LIB=TwsSocketClient
+SOURCE_LIB=libTwsSocketClient.so
LIB_DIR=$(SOURCE_DIR)/lib
LIB_NAME_A=libbid.a
-LIB_NAME=bid
+LIB_NAME_SO=libbid.so
TARGET=TestCppClient
$(TARGET)Static:
@@ -17,7 +17,7 @@
$(CXX) $(CXXFLAGS) $(INCLUDES) $(BASE_SRC_DIR)/*.cpp ./*.cpp -L$(LIB_DIR) -l:$(LIB_NAME_SO) -o$(TARGET)
$(TARGET)Dynamic:
- $(CXX) $(CXXFLAGS) $(INCLUDES) ./*.cpp -L$(LIB_DIR) -l$(LIB_NAME) -L$(SOURCE_DIR) -l$(SOURCE_LIB) -o$(TARGET)Dynamic
+ $(CXX) $(CXXFLAGS) $(INCLUDES) ./*.cpp -L$(LIB_DIR) -l:$(LIB_NAME_SO) -L$(SOURCE_DIR) -l:$(SOURCE_LIB) -o$(TARGET)Dynamic
run$(TARGET)Static:
./$(TARGET)Static
The makefile
can be easily modified or used to generate static application binaries, but in this case I opted for dynamic linking. If you go the statically linked route, then you can also easily make the necessary modifications to the C++ API library makefile
in
Finally, we can build and run the TestCppClientDynamic
:
~/Downloads/twsapi_macunix.1034.02/IBJts/samples/Cpp/TestCppClient $ make TestCppClientDynamic
g++ -pthread -Wall -Wno-switch -Wpedantic -Wno-unused-function -std=c++11 -I../../../source/cppclient/client -I../../../source/cppclient ./*.cpp -L../../../source/cppclient/client/lib -lbid -L../../../source/cppclient/client -lTwsSocketClient -oTestCppClientDynamic
~/Downloads/twsapi_macunix.1034.02/IBJts/samples/Cpp/TestCppClient $ DYLD_LIBRARY_PATH=../../../source/cppclient/client/lib ./TestCppClientDynamic
Start of C++ Socket Client Test 0
Attempt 1 of 50
Connecting to 127.0.0.1:7496 clientId:0
Error. Id: -1, Time: Tue Feb 11 15:08:17 2025, Code: 502, Msg: Couldn't connect to TWS. Confirm that "Enable ActiveX and Socket Clients" is enabled and connection port is the same as "Socket Port" on the TWS "Edit->Global Configuration...->API->Settings" menu. Live Trading ports: TWS: 7496; IB Gateway: 4001. Simulated Trading ports for new installations of version 954.1 or newer: TWS: 7497; IB Gateway: 4002
Cannot connect to 127.0.0.1:7496 clientId:0
Sleeping 10 seconds before next attempt
Success! Hopefully, this will be helpful to someone looking to build the IBKR C++ API library on MacOS or Linux/aarch64.