long is a macOS-only TWS trading GUI.
Current stack:
- Native
AppKitwindow and controls - Apple
GameController.frameworkfor controller input on macOS - Interactive Brokers TWS / Gateway connectivity
ixwebsocketlocalhost control server- bridge batch sender for
tape-engineover local Unix domain sockets
Important architecture note:
- The app now uses native AppKit views instead of
GLFW + Dear ImGui. - The trading logic, TWS integration, WebSocket handling, and controller handling remain in C++ / ObjC++ code.
Build requirements:
- macOS
- Xcode Command Line Tools
- Protocol Buffers (
protocand headers/libs) when building against the newer IB API
Build:
cmake -S . -B build
cmake --build build -j4Run:
open build/tws_gui.appDirect executable inside the bundle:
./build/tws_gui.app/Contents/MacOS/tws_guiRun the Phase-1 engine daemon:
./build/tape_enginePackage a distributable zip:
cmake --build build --target tws_gui_zipDependency paths:
- ixWebSocket is expected at
./ixwebsocket - nlohmann/json is expected at
./nlohmann_json - The build auto-detects a downloaded IB API under
~/Downloads/twsapi_macunix/...when present
External dependency paths also work. If you keep ixwebsocket and nlohmann_json
outside this workspace, pass them explicitly:
cmake -S . -B build \
-DIXWEBSOCKET_DIR=/absolute/path/to/ixwebsocket \
-DNLOHMANN_JSON_DIR=/absolute/path/to/nlohmann_json
cmake --build build -j4Phase-0 mock bridge validation:
- If no vendored IB API is available, the workspace falls back to the local mock IB API.
- The bridge and recovery semantics are covered by
tws_gui_tests.
cmake -S . -B build-phase0 \
-DCMAKE_BUILD_TYPE=Debug \
-DIXWEBSOCKET_DIR=/absolute/path/to/ixwebsocket \
-DNLOHMANN_JSON_DIR=/absolute/path/to/nlohmann_json
cmake --build build-phase0 --target tws_gui_tests -j4
ctest --test-dir build-phase0 --output-on-failurePhase-1 bridge sender notes:
longnow batches queued bridge records into framed MessagePack batches fortape-engine.- The sender uses the Unix domain socket path from
LONG_TAPE_ENGINE_SOCKETwhen set. - If that env var is unset, the sender defaults to
/tmp/tape-engine.sock. tape_enginewrites per-batch segments and a hash-linkedmanifest.jsonlunderLONG_TAPE_ENGINE_DATA_DIR.- If
LONG_TAPE_ENGINE_DATA_DIRis unset, the daemon defaults to/tmp/tape-engine.
Packaging notes:
- The app is built as a real macOS
.appbundle. - Non-system protobuf/abseil dylibs are embedded into
Contents/Frameworks. - The bundle is ad-hoc signed locally after dependency fixup.
- Notarization is not automated yet.