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.