py-ib-controller 0.1.4__tar.gz → 0.1.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/.github/workflows/ci.yml +4 -1
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/Makefile +15 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/PKG-INFO +99 -22
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/README.md +98 -21
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/agent/src/main/java/ibcontroller/agent/AgentMain.java +67 -70
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/agent/src/main/java/ibcontroller/agent/ComponentLookup.java +37 -83
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/agent/src/main/java/ibcontroller/agent/EventBridge.java +74 -41
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/agent/src/main/java/ibcontroller/agent/Protocol.java +25 -12
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/agent/src/main/java/ibcontroller/agent/Security.java +3 -4
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/agent/src/main/java/ibcontroller/agent/WriteOps.java +51 -99
- py_ib_controller-0.1.5/agent/src/test/java/ibcontroller/agent/AgentTests.java +243 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/docs/Configuration.md +62 -6
- py_ib_controller-0.1.5/docs/development.md +469 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/ibcontroller/actions.py +97 -81
- py_ib_controller-0.1.5/ibcontroller/agent_client.py +605 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/ibcontroller/cli.py +19 -55
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/ibcontroller/config.py +52 -34
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/ibcontroller/control_loop.py +247 -227
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/ibcontroller/data/builtin_settings.toml +1 -1
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/ibcontroller/data/ibcontroller.toml.example +43 -13
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/ibcontroller/data/ibkr_settings.toml.example +30 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/ibcontroller/data/labels.json +51 -3
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/ibcontroller/data/labels.json.example +10 -11
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/ibcontroller/diagnostics.py +53 -18
- py_ib_controller-0.1.5/ibcontroller/dispatch.py +391 -0
- py_ib_controller-0.1.5/ibcontroller/errors.py +33 -0
- py_ib_controller-0.1.5/ibcontroller/ibcontroller-agent.jar +0 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/ibcontroller/labels.py +183 -32
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/ibcontroller/launcher.py +283 -215
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/ibcontroller/logging_setup.py +10 -13
- py_ib_controller-0.1.5/ibcontroller/login.py +660 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/ibcontroller/main.py +22 -13
- py_ib_controller-0.1.5/ibcontroller/management.py +124 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/ibcontroller/recognisers.py +313 -111
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/ibcontroller/schedule.py +2 -1
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/ibcontroller/settings.py +158 -95
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/ibcontroller.env +19 -7
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/py_ib_controller.egg-info/PKG-INFO +99 -22
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/py_ib_controller.egg-info/SOURCES.txt +7 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/py_ib_controller.egg-info/scm_file_list.json +7 -0
- py_ib_controller-0.1.5/py_ib_controller.egg-info/scm_version.json +8 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/pyproject.toml +1 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/tests/conftest.py +12 -4
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/tests/fakes.py +42 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/tests/test_actions.py +214 -196
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/tests/test_agent_client.py +456 -33
- py_ib_controller-0.1.5/tests/test_agent_jar.py +136 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/tests/test_cli.py +74 -10
- py_ib_controller-0.1.5/tests/test_command_wire.py +162 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/tests/test_config.py +34 -21
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/tests/test_control_loop.py +507 -295
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/tests/test_diagnostics.py +101 -4
- py_ib_controller-0.1.5/tests/test_dispatch.py +710 -0
- py_ib_controller-0.1.5/tests/test_errors.py +73 -0
- py_ib_controller-0.1.5/tests/test_labels.py +240 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/tests/test_launcher.py +545 -350
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/tests/test_logging_setup.py +4 -4
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/tests/test_login.py +855 -323
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/tests/test_main.py +7 -8
- py_ib_controller-0.1.5/tests/test_management.py +306 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/tests/test_recognisers.py +571 -35
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/tests/test_schedule.py +5 -3
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/tests/test_settings.py +505 -60
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/tests/test_trace_integration.py +12 -11
- py_ib_controller-0.1.4/docs/development.md +0 -252
- py_ib_controller-0.1.4/ibcontroller/agent_client.py +0 -466
- py_ib_controller-0.1.4/ibcontroller/dispatch.py +0 -288
- py_ib_controller-0.1.4/ibcontroller/ibcontroller-agent.jar +0 -0
- py_ib_controller-0.1.4/ibcontroller/login.py +0 -602
- py_ib_controller-0.1.4/py_ib_controller.egg-info/scm_version.json +0 -8
- py_ib_controller-0.1.4/tests/test_dispatch.py +0 -360
- py_ib_controller-0.1.4/tests/test_labels.py +0 -94
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/.github/ISSUE_TEMPLATE.md +0 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/.github/dependabot.yml +0 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/.github/workflows/publish.yml +0 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/.gitignore +0 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/.pre-commit-config.yaml +0 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/.sdkmanrc +0 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/CONTRIBUTING.md +0 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/LICENSE.txt +0 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/docs/Architecture.svg +0 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/ibcontroller/__init__.py +0 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/ibcontroller/app_dirs.py +0 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/ibcontroller/py.typed +0 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/py_ib_controller.egg-info/dependency_links.txt +0 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/py_ib_controller.egg-info/entry_points.txt +0 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/py_ib_controller.egg-info/requires.txt +0 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/py_ib_controller.egg-info/top_level.txt +0 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/setup.cfg +0 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/tests/__init__.py +0 -0
- {py_ib_controller-0.1.4 → py_ib_controller-0.1.5}/tests/test_app_dirs.py +0 -0
|
@@ -19,6 +19,21 @@ build/ibcontroller-agent.jar: $(SRC)
|
|
|
19
19
|
.PHONY: build
|
|
20
20
|
build: build/ibcontroller-agent.jar
|
|
21
21
|
|
|
22
|
+
# Dependency-free Java unit tests (plain javac + java, same toolchain as the jar).
|
|
23
|
+
TEST_SRC := $(wildcard agent/src/test/java/ibcontroller/agent/*.java)
|
|
24
|
+
|
|
25
|
+
.PHONY: test-java
|
|
26
|
+
test-java: $(SRC) $(TEST_SRC)
|
|
27
|
+
mkdir -p build/test-classes
|
|
28
|
+
$(JAVAC) -d build/test-classes $(SRC) $(TEST_SRC)
|
|
29
|
+
$(JDK)/bin/java -Djava.awt.headless=true -cp build/test-classes ibcontroller.agent.AgentTests
|
|
30
|
+
|
|
31
|
+
# Everything: build the jar, run the Java unit tests, then the Python suite (which
|
|
32
|
+
# includes the tests that drive the built jar).
|
|
33
|
+
.PHONY: test
|
|
34
|
+
test: build test-java
|
|
35
|
+
uv run pytest -n auto
|
|
36
|
+
|
|
22
37
|
# The Python package can't be built standalone -- `ibcontroller/ibcontroller-agent.jar`
|
|
23
38
|
# must exist before `uv build` runs, since it's shipped via [tool.setuptools.package-data]
|
|
24
39
|
# the same way ibcontroller/data/*.json is (see pyproject.toml). This target makes that
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: py-ib-controller
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.5
|
|
4
4
|
Summary: Login/launch controller for TWS and IBKR Gateway, via an in-process Java agent
|
|
5
5
|
Author-email: gnzsnz <8376642+gnzsnz@users.noreply.github.com>
|
|
6
6
|
License-Expression: Apache-2.0
|
|
@@ -125,7 +125,7 @@ And the `ibcontroller run` parameters:
|
|
|
125
125
|
│ --trading-mode <live|paper> Override Config.trading_mode ('live'/'paper') for this invocation. │
|
|
126
126
|
│ --tws-path <path> Override Config.tws_path (the TWS/Gateway install-path inference) for this invocation. │
|
|
127
127
|
│ --tws-channel <str> Override Config.tws_channel ('stable'/'latest', filters install auto-detection) for this invocation. │
|
|
128
|
-
│ --program <
|
|
128
|
+
│ --program <gateway|tws> Override Config.program ('gateway'/'tws') for this invocation. │
|
|
129
129
|
│ --tws-settings-path <path> Override Config.tws_settings_path (where TWS/Gateway stores its own settings) for this invocation. │
|
|
130
130
|
│ --instance <str> Override Config.instance (per-instance log/trace/socket names) for this invocation. Defaults to '{program}-{trading_mode}', so │
|
|
131
131
|
│ --trading-mode alone is usually enough to keep paper/live instances apart. │
|
|
@@ -197,7 +197,7 @@ When environment variable `IBC_APP_DIR` is not set, then
|
|
|
197
197
|
| --- | --- | --- |
|
|
198
198
|
| `config_dir` | `~/.config/ibcontroller` | Linux |
|
|
199
199
|
| `config_dir` | `~/Library/Application Support/ibcontroller` | macOS |
|
|
200
|
-
| `log_dir` | `~/.local/
|
|
200
|
+
| `log_dir` | `~/.local/state/ibcontroller/log` | Linux |
|
|
201
201
|
| `log_dir` | `~/Library/Logs/ibcontroller` | macOS |
|
|
202
202
|
| `socket_dir` | `/run/user/<uid>/ibcontroller` | Linux |
|
|
203
203
|
| `socket_dir` | `~/Library/Caches/TemporaryItems/ibcontroller` | macOS |
|
|
@@ -208,6 +208,13 @@ When `IBC_APP_DIR` is set then:
|
|
|
208
208
|
- `log_dir`-> `IBC_APP_DIR/log`
|
|
209
209
|
- `socket_dir` -> `IBC_APP_DIR/run`
|
|
210
210
|
|
|
211
|
+
Socket paths (`socket_dir/ibcontroller-agent-<instance>-events.sock`) must fit
|
|
212
|
+
the Unix socket limit: 102 bytes on macOS, 106 on Linux. On macOS the default
|
|
213
|
+
`socket_dir` leaves room for an instance name of about 15 characters with a
|
|
214
|
+
5-letter user name (each extra user-name character costs one). Over the limit,
|
|
215
|
+
`ibcontroller run` stops with an error naming the path; use a shorter instance
|
|
216
|
+
name or set `IBC_APP_DIR` to a shorter directory.
|
|
217
|
+
|
|
211
218
|
### Settings
|
|
212
219
|
|
|
213
220
|
`ibcontroller`ships with sensible defaults. **Only the two credential env vars below are actually mandatory**
|
|
@@ -223,7 +230,7 @@ allowing `None`. `Config`'s schema is closed — an unknown key in
|
|
|
223
230
|
| TOML key | Env var or CLI flag | Description | Default |
|
|
224
231
|
| --- | --- | --- | --- |
|
|
225
232
|
| `instance` | `IBC_INSTANCE`, `--instance` | Instance name; separate log/trace files per instance | `"{program}-{trading_mode}"` (e.g. `"gateway-paper"`) |
|
|
226
|
-
| `program` | `IBC_PROGRAM`, `--program` | `"gateway"` or `"tws"` | `"gateway"` |
|
|
233
|
+
| `program` | `IBC_PROGRAM`, `--program` | `"gateway"` or `"tws"` (any letter case); anything else is a config error | `"gateway"` |
|
|
227
234
|
| `tws_version` | `IBC_TWS_VERSION` | Installed TWS/Gateway version, e.g. `"10.50"` | `None` — auto-detected (see below) |
|
|
228
235
|
| `tws_channel` | `IBC_TWS_CHANNEL`, `--tws-channel` | `"stable"`/`"latest"`; narrows auto-detection to one update channel | `"stable"` |
|
|
229
236
|
| `tws_path` | `IBC_TWS_PATH`, `--tws-path` | Override TWS/gateway install-path inference | `None` |
|
|
@@ -237,6 +244,7 @@ allowing `None`. `Config`'s schema is closed — an unknown key in
|
|
|
237
244
|
| `log_backup_count` | `IBC_LOG_BACKUP_COUNT` | Number of rotated backups to keep. Only respected when `log_sink="file"` | `5` |
|
|
238
245
|
| `diagnostic_scope` | `IBC_DIAGNOSTIC_SCOPE` | `"known"`/`"unknown"`/`"all"` — which windows get a structure dump logged (see `docs/Configuration.md`'s "Diagnostics") | `"known"` |
|
|
239
246
|
| `diagnostic_when` | `IBC_DIAGNOSTIC_WHEN` | `"open"`/`"openclose"`/`"never"` — when to log a structure dump | `"never"` |
|
|
247
|
+
| `diagnostic_settings_sweep` | `IBC_DIAGNOSTIC_SETTINGS_SWEEP` | Log a dump of each Global Configuration tree node in `labels.settings.sweep_paths` (see `docs/Configuration.md`'s "Diagnostics") | `false` |
|
|
240
248
|
| (env only) | `IBC_APP_DIR`, `--app-dir` | Override file locations (config/log/run) for container mode; `--app-dir`/`init`/`run` set the env var for the invocation, same effect |
|
|
241
249
|
|
|
242
250
|
TWS/ibgateway settings
|
|
@@ -244,15 +252,16 @@ TWS/ibgateway settings
|
|
|
244
252
|
| TOML key | Env var or CLI flag | Description | Default |
|
|
245
253
|
| --- | --- | --- | --- |
|
|
246
254
|
| `trading_mode` | `IBC_TRADING_MODE`, `--trading-mode` | `"live"` or `"paper"`; which account to authenticate as | `"paper"` |
|
|
247
|
-
| `read_only_login` | `IBC_READ_ONLY_LOGIN` | TWS-only;
|
|
255
|
+
| `read_only_login` | `IBC_READ_ONLY_LOGIN` | TWS-only (Gateway warns and logs in normally); clicks "Enter Read Only" on the 2FA frame instead of waiting for the push, no effect without 2FA (paper) | `false` |
|
|
248
256
|
| `read_only_api` | `IBC_READ_ONLY_API` | `true`/`false` sets it; omit to leave unchanged. Applied to Gateway/TWS automatically -- see "Declarative configuration" below | `None` |
|
|
249
257
|
| `accept_incoming_connections` | `IBC_ACCEPT_INCOMING_CONNECTIONS` | `manual`/`accept`/`reject` | `"manual"` |
|
|
250
258
|
| `existing_session_action` | `IBC_EXISTING_SESSION_ACTION` | `manual`/`primary`/`primaryoverride`/`secondary` | `"manual"` |
|
|
251
259
|
| `login_dialog_display_timeout` | `IBC_LOGIN_DIALOG_DISPLAY_TIMEOUT` | Seconds to wait for the login dialog | `60.0` |
|
|
252
|
-
| `mfa_timeout` | `IBC_MFA_TIMEOUT` | IB's 2FA
|
|
253
|
-
| `relogin_after_mfa_timeout` | `IBC_RELOGIN_AFTER_MFA_TIMEOUT` |
|
|
254
|
-
| `mfa_exit_interval` | `IBC_MFA_EXIT_INTERVAL` |
|
|
255
|
-
| `mfa_timeout_action` | `IBC_MFA_TIMEOUT_ACTION` | `exit` (exit 75, see "Exit codes" above) or `restart` (relaunch with a fresh login) when
|
|
260
|
+
| `mfa_timeout` | `IBC_MFA_TIMEOUT` | IB's 2FA limit in seconds; a dialog closing at or after it counts as timed out | `180.0` |
|
|
261
|
+
| `relogin_after_mfa_timeout` | `IBC_RELOGIN_AFTER_MFA_TIMEOUT` | Log in again after a timed-out push, and enforce `mfa_exit_interval` after an approved one | `false` |
|
|
262
|
+
| `mfa_exit_interval` | `IBC_MFA_EXIT_INTERVAL` | Post-approval wait for login to complete when relogin is on | `60.0` |
|
|
263
|
+
| `mfa_timeout_action` | `IBC_MFA_TIMEOUT_ACTION` | `exit` (exit 75, see "Exit codes" above) or `restart` (relaunch with a fresh login) when `mfa_exit_interval` expires after an approved push | `"exit"` |
|
|
264
|
+
| `restart_cap` | `IBC_RESTART_CAP` | Max consecutive relaunches that never reach READY (login frame timeout, transient login failure, logout, crash during login); then exit 70 | `3` |
|
|
256
265
|
| `auto_restart_time` | `IBC_AUTO_RESTART_TIME` | `"hh:mm AM/PM"` daily auto-restart time. Applied to Gateway/TWS automatically -- see "Declarative configuration" below | `None` |
|
|
257
266
|
| `auto_logoff_time` | `IBC_AUTO_LOGOFF_TIME` | `"hh:mm AM/PM"` daily auto-logoff time; same "Lock and Exit" radio-button pair as `auto_restart_time` -- if both are set, `auto_restart_time` wins | `None` |
|
|
258
267
|
| `time_zone` | `IBC_TIME_ZONE` | IANA zone name, e.g. `"Europe/Zurich"`, written to `jts.ini`'s `TimeZone`. Auto-detected from `TZ`, then `/etc/localtime` -- no setup needed in the common case; never overwrites an existing `TimeZone` line | auto-detected |
|
|
@@ -313,10 +322,19 @@ more fields of the bundled default, field by field — you only need to include
|
|
|
313
322
|
you're changing, not the whole file. Use it when a TWS/Gateway release renames a button
|
|
314
323
|
or dialog title ibcontroller matches against.
|
|
315
324
|
|
|
325
|
+
A malformed file is rejected at startup (exit code 78) with a message naming the file and
|
|
326
|
+
the field: a string where a list is expected, an empty list of titles or buttons, invalid
|
|
327
|
+
JSON, or a `dismiss_rules` entry without `match_title`/`match_text`. A misspelled key is
|
|
328
|
+
logged as a warning and ignored, so check the log if an override seems to have no effect.
|
|
329
|
+
|
|
330
|
+
`generic.dismiss_buttons` lists the buttons tried, in order, to close a pop-up no specific
|
|
331
|
+
handler recognises (default `OK`, `Close`, `Dismiss`).
|
|
332
|
+
|
|
316
333
|
The one part of `labels.json` that isn't just text is `dismiss_rules` — a list of
|
|
317
334
|
"if a window matches, click this button" entries, checked on every window that opens.
|
|
318
335
|
Each entry needs at least one of `match_title`/`match_text` (both, if given, must
|
|
319
|
-
match); `click` is the button's label.
|
|
336
|
+
match); `click` is the button's label. `match_text` also matches message text with HTML
|
|
337
|
+
tags removed and entities decoded, so copy the phrase as it shows on screen.
|
|
320
338
|
|
|
321
339
|
```json
|
|
322
340
|
{
|
|
@@ -330,13 +348,18 @@ match); `click` is the button's label.
|
|
|
330
348
|
}
|
|
331
349
|
```
|
|
332
350
|
|
|
333
|
-
`dismiss_rules`
|
|
334
|
-
|
|
335
|
-
confirmation notice)
|
|
336
|
-
|
|
351
|
+
`dismiss_rules` entries are merged by `name`: an entry with a bundled rule's name replaces
|
|
352
|
+
that rule, an entry with a new name is added, and bundled rules (the non-brokerage-account
|
|
353
|
+
warning, the auto-restart confirmation notice) you don't name are kept. Removing a bundled
|
|
354
|
+
rule is not supported. Good for any pop-up that's always handled the same
|
|
337
355
|
simple way; a dialog needing real logic (parsing a value out of its text, retrying,
|
|
338
356
|
raising an error) isn't expressible this way and needs actual code.
|
|
339
357
|
|
|
358
|
+
Login-outcome dialogs ("Login failed", "Unrecognized Username or Password", the connection
|
|
359
|
+
and too-many-attempts warnings) and the "Shutdown progress" / "Restart in progress" windows
|
|
360
|
+
are always handled first. A `dismiss_rules` entry that matches one of them never runs, so a
|
|
361
|
+
credential rejection still exits with code 77 and a restart is still recognised as one.
|
|
362
|
+
|
|
340
363
|
### `ibkr_settings.toml` — Global Configuration settings
|
|
341
364
|
|
|
342
365
|
Global Configuration settings (the "Configure" / "Settings" dialog inside Gateway/TWS)
|
|
@@ -351,7 +374,13 @@ are applied once, right after login, from two layers combined into one list:
|
|
|
351
374
|
- **Your own `ibkr_settings.toml`** — anything else: any other Global Configuration
|
|
352
375
|
checkbox or text field, activated by pointing `[settings] file = "..."` (or
|
|
353
376
|
`IBC_SETTINGS_FILE`) at a real file (rename `ibkr_settings.toml.example` to
|
|
354
|
-
start from the bundled worked examples
|
|
377
|
+
start from the bundled worked examples: the `api_precautions_*` toggles, plus commented
|
|
378
|
+
entries for the API socket port, the master API client ID and "Send market data in lots
|
|
379
|
+
for US stocks" under `API/Settings`).
|
|
380
|
+
|
|
381
|
+
When no entry resolves to a value (the default), the dialog is not opened. Only the TWS Mosaic
|
|
382
|
+
layout is supported: on TWS Classic no setting is applied and the attempt waits for
|
|
383
|
+
`mfa_timeout` (default 180s) before failing. Gateway is not affected.
|
|
355
384
|
|
|
356
385
|
An entry looks like this:
|
|
357
386
|
|
|
@@ -504,6 +533,42 @@ or both.
|
|
|
504
533
|
instances (e.g. `paper` and `live`) can run in parallel and each tail its own files
|
|
505
534
|
without interleaving, even if copied or globbed out of their directory.
|
|
506
535
|
|
|
536
|
+
## Finding the TWS / Gateway installation
|
|
537
|
+
|
|
538
|
+
ibcontroller does not install anything: it launches the TWS or Gateway you already
|
|
539
|
+
installed with IBKR's own installer, using that install's jars and bundled JRE. It
|
|
540
|
+
resolves the installation in three steps.
|
|
541
|
+
|
|
542
|
+
1. **Install root** (`tws_path`). Unless set, it defaults to:
|
|
543
|
+
|
|
544
|
+
| OS | Default root |
|
|
545
|
+
| --- | --- |
|
|
546
|
+
| macOS | `~/Applications` |
|
|
547
|
+
| Linux | `~/Jts` |
|
|
548
|
+
|
|
549
|
+
2. **Version** (`tws_version`). A pinned `tws_version` is used as-is. Otherwise
|
|
550
|
+
ibcontroller scans the root, picks the greatest installed version and logs the
|
|
551
|
+
choice; `tws_channel` narrows the scan first. See "`tws_version` auto-detection"
|
|
552
|
+
above.
|
|
553
|
+
|
|
554
|
+
3. **Install directory.** Version and `program` select the directory below the root:
|
|
555
|
+
|
|
556
|
+
| OS | Gateway | TWS |
|
|
557
|
+
| --- | --- | --- |
|
|
558
|
+
| macOS | `IB Gateway <version>/` | `Trader Workstation <version>/` |
|
|
559
|
+
| Linux | `ibgateway/<version>/` | `<version>/` |
|
|
560
|
+
|
|
561
|
+
A directory counts as an installation only if it has a `jars/` subfolder. The
|
|
562
|
+
classpath is built from those jars plus the install's `.install4j/i4jruntime.jar`,
|
|
563
|
+
and the JVM options come from its `ibgateway.vmoptions` / `tws.vmoptions`.
|
|
564
|
+
|
|
565
|
+
If nothing matches, ibcontroller exits with an error naming `tws_path` and
|
|
566
|
+
`tws_channel`. A `program = "tws"` request with no TWS install falls back to a
|
|
567
|
+
Gateway install; the reverse does not (details above).
|
|
568
|
+
|
|
569
|
+
Settings (`tws_settings_path`) are separate from the install root: each instance
|
|
570
|
+
defaults to its own `~/Jts/<instance>`, so `paper` and `live` do not share state.
|
|
571
|
+
|
|
507
572
|
## Exit codes
|
|
508
573
|
|
|
509
574
|
`ibcontroller run` exits with a [BSD sysexits](https://man.freebsd.org/cgi/man.cgi?query=sysexits)
|
|
@@ -513,22 +578,34 @@ code, grouped by what a supervisor (a container's `restart:` policy, systemd's
|
|
|
513
578
|
|
|
514
579
|
| Code | Meaning | Supervisor action |
|
|
515
580
|
| --- | --- | --- |
|
|
516
|
-
| `0` | Intentional stop (Ctrl-C, `closedown_at`, Gateway/TWS closed normally, e.g. File>Close) | Do not restart |
|
|
581
|
+
| `0` | Intentional stop (Ctrl-C, `closedown_at`, Gateway/TWS closed normally, e.g. File>Close, or this session yielded to another via `existing_session_action`: `stopped: SESSION_CEDED`) | Do not restart |
|
|
517
582
|
| `1` | Unhandled exception (a bug) | Restart, report |
|
|
518
583
|
| `2` | CLI usage error | Fix the command |
|
|
519
584
|
| `78` (`EX_CONFIG`) | Deployment error (bad config, install not found) | Do not retry |
|
|
520
585
|
| `77` (`EX_NOPERM`) | Credentials rejected | Do not retry (lockout risk) |
|
|
521
|
-
| `
|
|
522
|
-
| `
|
|
586
|
+
| `76` (`EX_PROTOCOL`) | A dialog `existing_session_action` rules out (Trading Login Handoff with `secondary`/`primaryoverride`) | Do not retry |
|
|
587
|
+
| `75` (`EX_TEMPFAIL`) | Login did not complete after 2FA, `mfa_timeout_action=exit` | Retry per policy |
|
|
588
|
+
| `70` (`EX_SOFTWARE`) | `restart_cap` consecutive relaunches never reached READY | Do not retry |
|
|
589
|
+
| `69` (`EX_UNAVAILABLE`) | Transient runtime failure (process crashed or killed, connection lost, JVM exited before becoming ready) | Retry |
|
|
523
590
|
|
|
524
|
-
`77`/`78` work with systemd's `RestartPreventExitStatus=`.
|
|
591
|
+
`70`/`76`/`77`/`78` work with systemd's `RestartPreventExitStatus=`.
|
|
525
592
|
|
|
526
593
|
Some login-blocking dialogs IB reports as a server-side condition -- not a credential
|
|
527
|
-
rejection -- never reach this table at all: a "Login failed"/"Login Error" dialog, or a
|
|
594
|
+
rejection -- never reach this table at all: a "Login failed"/"Login Error"/"not currently available" dialog, or a
|
|
528
595
|
Gateway "Connection to server failed" reason other than a known credential/account one
|
|
529
596
|
(e.g. a stale restart token), make ibcontroller relaunch in-process with a full fresh
|
|
530
|
-
login,
|
|
531
|
-
itself
|
|
597
|
+
login, the same way a scheduled `cold_restart_time` does -- the container
|
|
598
|
+
itself does not exit for these, until `restart_cap` consecutive relaunches never reach READY
|
|
599
|
+
(exit 70).
|
|
600
|
+
|
|
601
|
+
## Stopping under Docker
|
|
602
|
+
|
|
603
|
+
On SIGTERM (`docker stop`, Ctrl-C) a logged-in instance closes through File > Exit/Close so
|
|
604
|
+
TWS/Gateway can save its session and upload settings. Measured over 88 shutdowns: mean 1.3 s,
|
|
605
|
+
p99 4.3 s, max 4.9 s. A slow path (a dialog open, a stuck menu) can take longer: the menu retry
|
|
606
|
+
waits up to 5 s, the exit up to 8 s, then SIGTERM gets 5 s. Docker sends SIGKILL after 10 s by
|
|
607
|
+
default, which loses the graceful close. Set `stop_grace_period: 30s` (Compose) or
|
|
608
|
+
`docker stop -t 30` to keep it.
|
|
532
609
|
|
|
533
610
|
## License
|
|
534
611
|
|
|
@@ -103,7 +103,7 @@ And the `ibcontroller run` parameters:
|
|
|
103
103
|
│ --trading-mode <live|paper> Override Config.trading_mode ('live'/'paper') for this invocation. │
|
|
104
104
|
│ --tws-path <path> Override Config.tws_path (the TWS/Gateway install-path inference) for this invocation. │
|
|
105
105
|
│ --tws-channel <str> Override Config.tws_channel ('stable'/'latest', filters install auto-detection) for this invocation. │
|
|
106
|
-
│ --program <
|
|
106
|
+
│ --program <gateway|tws> Override Config.program ('gateway'/'tws') for this invocation. │
|
|
107
107
|
│ --tws-settings-path <path> Override Config.tws_settings_path (where TWS/Gateway stores its own settings) for this invocation. │
|
|
108
108
|
│ --instance <str> Override Config.instance (per-instance log/trace/socket names) for this invocation. Defaults to '{program}-{trading_mode}', so │
|
|
109
109
|
│ --trading-mode alone is usually enough to keep paper/live instances apart. │
|
|
@@ -175,7 +175,7 @@ When environment variable `IBC_APP_DIR` is not set, then
|
|
|
175
175
|
| --- | --- | --- |
|
|
176
176
|
| `config_dir` | `~/.config/ibcontroller` | Linux |
|
|
177
177
|
| `config_dir` | `~/Library/Application Support/ibcontroller` | macOS |
|
|
178
|
-
| `log_dir` | `~/.local/
|
|
178
|
+
| `log_dir` | `~/.local/state/ibcontroller/log` | Linux |
|
|
179
179
|
| `log_dir` | `~/Library/Logs/ibcontroller` | macOS |
|
|
180
180
|
| `socket_dir` | `/run/user/<uid>/ibcontroller` | Linux |
|
|
181
181
|
| `socket_dir` | `~/Library/Caches/TemporaryItems/ibcontroller` | macOS |
|
|
@@ -186,6 +186,13 @@ When `IBC_APP_DIR` is set then:
|
|
|
186
186
|
- `log_dir`-> `IBC_APP_DIR/log`
|
|
187
187
|
- `socket_dir` -> `IBC_APP_DIR/run`
|
|
188
188
|
|
|
189
|
+
Socket paths (`socket_dir/ibcontroller-agent-<instance>-events.sock`) must fit
|
|
190
|
+
the Unix socket limit: 102 bytes on macOS, 106 on Linux. On macOS the default
|
|
191
|
+
`socket_dir` leaves room for an instance name of about 15 characters with a
|
|
192
|
+
5-letter user name (each extra user-name character costs one). Over the limit,
|
|
193
|
+
`ibcontroller run` stops with an error naming the path; use a shorter instance
|
|
194
|
+
name or set `IBC_APP_DIR` to a shorter directory.
|
|
195
|
+
|
|
189
196
|
### Settings
|
|
190
197
|
|
|
191
198
|
`ibcontroller`ships with sensible defaults. **Only the two credential env vars below are actually mandatory**
|
|
@@ -201,7 +208,7 @@ allowing `None`. `Config`'s schema is closed — an unknown key in
|
|
|
201
208
|
| TOML key | Env var or CLI flag | Description | Default |
|
|
202
209
|
| --- | --- | --- | --- |
|
|
203
210
|
| `instance` | `IBC_INSTANCE`, `--instance` | Instance name; separate log/trace files per instance | `"{program}-{trading_mode}"` (e.g. `"gateway-paper"`) |
|
|
204
|
-
| `program` | `IBC_PROGRAM`, `--program` | `"gateway"` or `"tws"` | `"gateway"` |
|
|
211
|
+
| `program` | `IBC_PROGRAM`, `--program` | `"gateway"` or `"tws"` (any letter case); anything else is a config error | `"gateway"` |
|
|
205
212
|
| `tws_version` | `IBC_TWS_VERSION` | Installed TWS/Gateway version, e.g. `"10.50"` | `None` — auto-detected (see below) |
|
|
206
213
|
| `tws_channel` | `IBC_TWS_CHANNEL`, `--tws-channel` | `"stable"`/`"latest"`; narrows auto-detection to one update channel | `"stable"` |
|
|
207
214
|
| `tws_path` | `IBC_TWS_PATH`, `--tws-path` | Override TWS/gateway install-path inference | `None` |
|
|
@@ -215,6 +222,7 @@ allowing `None`. `Config`'s schema is closed — an unknown key in
|
|
|
215
222
|
| `log_backup_count` | `IBC_LOG_BACKUP_COUNT` | Number of rotated backups to keep. Only respected when `log_sink="file"` | `5` |
|
|
216
223
|
| `diagnostic_scope` | `IBC_DIAGNOSTIC_SCOPE` | `"known"`/`"unknown"`/`"all"` — which windows get a structure dump logged (see `docs/Configuration.md`'s "Diagnostics") | `"known"` |
|
|
217
224
|
| `diagnostic_when` | `IBC_DIAGNOSTIC_WHEN` | `"open"`/`"openclose"`/`"never"` — when to log a structure dump | `"never"` |
|
|
225
|
+
| `diagnostic_settings_sweep` | `IBC_DIAGNOSTIC_SETTINGS_SWEEP` | Log a dump of each Global Configuration tree node in `labels.settings.sweep_paths` (see `docs/Configuration.md`'s "Diagnostics") | `false` |
|
|
218
226
|
| (env only) | `IBC_APP_DIR`, `--app-dir` | Override file locations (config/log/run) for container mode; `--app-dir`/`init`/`run` set the env var for the invocation, same effect |
|
|
219
227
|
|
|
220
228
|
TWS/ibgateway settings
|
|
@@ -222,15 +230,16 @@ TWS/ibgateway settings
|
|
|
222
230
|
| TOML key | Env var or CLI flag | Description | Default |
|
|
223
231
|
| --- | --- | --- | --- |
|
|
224
232
|
| `trading_mode` | `IBC_TRADING_MODE`, `--trading-mode` | `"live"` or `"paper"`; which account to authenticate as | `"paper"` |
|
|
225
|
-
| `read_only_login` | `IBC_READ_ONLY_LOGIN` | TWS-only;
|
|
233
|
+
| `read_only_login` | `IBC_READ_ONLY_LOGIN` | TWS-only (Gateway warns and logs in normally); clicks "Enter Read Only" on the 2FA frame instead of waiting for the push, no effect without 2FA (paper) | `false` |
|
|
226
234
|
| `read_only_api` | `IBC_READ_ONLY_API` | `true`/`false` sets it; omit to leave unchanged. Applied to Gateway/TWS automatically -- see "Declarative configuration" below | `None` |
|
|
227
235
|
| `accept_incoming_connections` | `IBC_ACCEPT_INCOMING_CONNECTIONS` | `manual`/`accept`/`reject` | `"manual"` |
|
|
228
236
|
| `existing_session_action` | `IBC_EXISTING_SESSION_ACTION` | `manual`/`primary`/`primaryoverride`/`secondary` | `"manual"` |
|
|
229
237
|
| `login_dialog_display_timeout` | `IBC_LOGIN_DIALOG_DISPLAY_TIMEOUT` | Seconds to wait for the login dialog | `60.0` |
|
|
230
|
-
| `mfa_timeout` | `IBC_MFA_TIMEOUT` | IB's 2FA
|
|
231
|
-
| `relogin_after_mfa_timeout` | `IBC_RELOGIN_AFTER_MFA_TIMEOUT` |
|
|
232
|
-
| `mfa_exit_interval` | `IBC_MFA_EXIT_INTERVAL` |
|
|
233
|
-
| `mfa_timeout_action` | `IBC_MFA_TIMEOUT_ACTION` | `exit` (exit 75, see "Exit codes" above) or `restart` (relaunch with a fresh login) when
|
|
238
|
+
| `mfa_timeout` | `IBC_MFA_TIMEOUT` | IB's 2FA limit in seconds; a dialog closing at or after it counts as timed out | `180.0` |
|
|
239
|
+
| `relogin_after_mfa_timeout` | `IBC_RELOGIN_AFTER_MFA_TIMEOUT` | Log in again after a timed-out push, and enforce `mfa_exit_interval` after an approved one | `false` |
|
|
240
|
+
| `mfa_exit_interval` | `IBC_MFA_EXIT_INTERVAL` | Post-approval wait for login to complete when relogin is on | `60.0` |
|
|
241
|
+
| `mfa_timeout_action` | `IBC_MFA_TIMEOUT_ACTION` | `exit` (exit 75, see "Exit codes" above) or `restart` (relaunch with a fresh login) when `mfa_exit_interval` expires after an approved push | `"exit"` |
|
|
242
|
+
| `restart_cap` | `IBC_RESTART_CAP` | Max consecutive relaunches that never reach READY (login frame timeout, transient login failure, logout, crash during login); then exit 70 | `3` |
|
|
234
243
|
| `auto_restart_time` | `IBC_AUTO_RESTART_TIME` | `"hh:mm AM/PM"` daily auto-restart time. Applied to Gateway/TWS automatically -- see "Declarative configuration" below | `None` |
|
|
235
244
|
| `auto_logoff_time` | `IBC_AUTO_LOGOFF_TIME` | `"hh:mm AM/PM"` daily auto-logoff time; same "Lock and Exit" radio-button pair as `auto_restart_time` -- if both are set, `auto_restart_time` wins | `None` |
|
|
236
245
|
| `time_zone` | `IBC_TIME_ZONE` | IANA zone name, e.g. `"Europe/Zurich"`, written to `jts.ini`'s `TimeZone`. Auto-detected from `TZ`, then `/etc/localtime` -- no setup needed in the common case; never overwrites an existing `TimeZone` line | auto-detected |
|
|
@@ -291,10 +300,19 @@ more fields of the bundled default, field by field — you only need to include
|
|
|
291
300
|
you're changing, not the whole file. Use it when a TWS/Gateway release renames a button
|
|
292
301
|
or dialog title ibcontroller matches against.
|
|
293
302
|
|
|
303
|
+
A malformed file is rejected at startup (exit code 78) with a message naming the file and
|
|
304
|
+
the field: a string where a list is expected, an empty list of titles or buttons, invalid
|
|
305
|
+
JSON, or a `dismiss_rules` entry without `match_title`/`match_text`. A misspelled key is
|
|
306
|
+
logged as a warning and ignored, so check the log if an override seems to have no effect.
|
|
307
|
+
|
|
308
|
+
`generic.dismiss_buttons` lists the buttons tried, in order, to close a pop-up no specific
|
|
309
|
+
handler recognises (default `OK`, `Close`, `Dismiss`).
|
|
310
|
+
|
|
294
311
|
The one part of `labels.json` that isn't just text is `dismiss_rules` — a list of
|
|
295
312
|
"if a window matches, click this button" entries, checked on every window that opens.
|
|
296
313
|
Each entry needs at least one of `match_title`/`match_text` (both, if given, must
|
|
297
|
-
match); `click` is the button's label.
|
|
314
|
+
match); `click` is the button's label. `match_text` also matches message text with HTML
|
|
315
|
+
tags removed and entities decoded, so copy the phrase as it shows on screen.
|
|
298
316
|
|
|
299
317
|
```json
|
|
300
318
|
{
|
|
@@ -308,13 +326,18 @@ match); `click` is the button's label.
|
|
|
308
326
|
}
|
|
309
327
|
```
|
|
310
328
|
|
|
311
|
-
`dismiss_rules`
|
|
312
|
-
|
|
313
|
-
confirmation notice)
|
|
314
|
-
|
|
329
|
+
`dismiss_rules` entries are merged by `name`: an entry with a bundled rule's name replaces
|
|
330
|
+
that rule, an entry with a new name is added, and bundled rules (the non-brokerage-account
|
|
331
|
+
warning, the auto-restart confirmation notice) you don't name are kept. Removing a bundled
|
|
332
|
+
rule is not supported. Good for any pop-up that's always handled the same
|
|
315
333
|
simple way; a dialog needing real logic (parsing a value out of its text, retrying,
|
|
316
334
|
raising an error) isn't expressible this way and needs actual code.
|
|
317
335
|
|
|
336
|
+
Login-outcome dialogs ("Login failed", "Unrecognized Username or Password", the connection
|
|
337
|
+
and too-many-attempts warnings) and the "Shutdown progress" / "Restart in progress" windows
|
|
338
|
+
are always handled first. A `dismiss_rules` entry that matches one of them never runs, so a
|
|
339
|
+
credential rejection still exits with code 77 and a restart is still recognised as one.
|
|
340
|
+
|
|
318
341
|
### `ibkr_settings.toml` — Global Configuration settings
|
|
319
342
|
|
|
320
343
|
Global Configuration settings (the "Configure" / "Settings" dialog inside Gateway/TWS)
|
|
@@ -329,7 +352,13 @@ are applied once, right after login, from two layers combined into one list:
|
|
|
329
352
|
- **Your own `ibkr_settings.toml`** — anything else: any other Global Configuration
|
|
330
353
|
checkbox or text field, activated by pointing `[settings] file = "..."` (or
|
|
331
354
|
`IBC_SETTINGS_FILE`) at a real file (rename `ibkr_settings.toml.example` to
|
|
332
|
-
start from the bundled worked examples
|
|
355
|
+
start from the bundled worked examples: the `api_precautions_*` toggles, plus commented
|
|
356
|
+
entries for the API socket port, the master API client ID and "Send market data in lots
|
|
357
|
+
for US stocks" under `API/Settings`).
|
|
358
|
+
|
|
359
|
+
When no entry resolves to a value (the default), the dialog is not opened. Only the TWS Mosaic
|
|
360
|
+
layout is supported: on TWS Classic no setting is applied and the attempt waits for
|
|
361
|
+
`mfa_timeout` (default 180s) before failing. Gateway is not affected.
|
|
333
362
|
|
|
334
363
|
An entry looks like this:
|
|
335
364
|
|
|
@@ -482,6 +511,42 @@ or both.
|
|
|
482
511
|
instances (e.g. `paper` and `live`) can run in parallel and each tail its own files
|
|
483
512
|
without interleaving, even if copied or globbed out of their directory.
|
|
484
513
|
|
|
514
|
+
## Finding the TWS / Gateway installation
|
|
515
|
+
|
|
516
|
+
ibcontroller does not install anything: it launches the TWS or Gateway you already
|
|
517
|
+
installed with IBKR's own installer, using that install's jars and bundled JRE. It
|
|
518
|
+
resolves the installation in three steps.
|
|
519
|
+
|
|
520
|
+
1. **Install root** (`tws_path`). Unless set, it defaults to:
|
|
521
|
+
|
|
522
|
+
| OS | Default root |
|
|
523
|
+
| --- | --- |
|
|
524
|
+
| macOS | `~/Applications` |
|
|
525
|
+
| Linux | `~/Jts` |
|
|
526
|
+
|
|
527
|
+
2. **Version** (`tws_version`). A pinned `tws_version` is used as-is. Otherwise
|
|
528
|
+
ibcontroller scans the root, picks the greatest installed version and logs the
|
|
529
|
+
choice; `tws_channel` narrows the scan first. See "`tws_version` auto-detection"
|
|
530
|
+
above.
|
|
531
|
+
|
|
532
|
+
3. **Install directory.** Version and `program` select the directory below the root:
|
|
533
|
+
|
|
534
|
+
| OS | Gateway | TWS |
|
|
535
|
+
| --- | --- | --- |
|
|
536
|
+
| macOS | `IB Gateway <version>/` | `Trader Workstation <version>/` |
|
|
537
|
+
| Linux | `ibgateway/<version>/` | `<version>/` |
|
|
538
|
+
|
|
539
|
+
A directory counts as an installation only if it has a `jars/` subfolder. The
|
|
540
|
+
classpath is built from those jars plus the install's `.install4j/i4jruntime.jar`,
|
|
541
|
+
and the JVM options come from its `ibgateway.vmoptions` / `tws.vmoptions`.
|
|
542
|
+
|
|
543
|
+
If nothing matches, ibcontroller exits with an error naming `tws_path` and
|
|
544
|
+
`tws_channel`. A `program = "tws"` request with no TWS install falls back to a
|
|
545
|
+
Gateway install; the reverse does not (details above).
|
|
546
|
+
|
|
547
|
+
Settings (`tws_settings_path`) are separate from the install root: each instance
|
|
548
|
+
defaults to its own `~/Jts/<instance>`, so `paper` and `live` do not share state.
|
|
549
|
+
|
|
485
550
|
## Exit codes
|
|
486
551
|
|
|
487
552
|
`ibcontroller run` exits with a [BSD sysexits](https://man.freebsd.org/cgi/man.cgi?query=sysexits)
|
|
@@ -491,22 +556,34 @@ code, grouped by what a supervisor (a container's `restart:` policy, systemd's
|
|
|
491
556
|
|
|
492
557
|
| Code | Meaning | Supervisor action |
|
|
493
558
|
| --- | --- | --- |
|
|
494
|
-
| `0` | Intentional stop (Ctrl-C, `closedown_at`, Gateway/TWS closed normally, e.g. File>Close) | Do not restart |
|
|
559
|
+
| `0` | Intentional stop (Ctrl-C, `closedown_at`, Gateway/TWS closed normally, e.g. File>Close, or this session yielded to another via `existing_session_action`: `stopped: SESSION_CEDED`) | Do not restart |
|
|
495
560
|
| `1` | Unhandled exception (a bug) | Restart, report |
|
|
496
561
|
| `2` | CLI usage error | Fix the command |
|
|
497
562
|
| `78` (`EX_CONFIG`) | Deployment error (bad config, install not found) | Do not retry |
|
|
498
563
|
| `77` (`EX_NOPERM`) | Credentials rejected | Do not retry (lockout risk) |
|
|
499
|
-
| `
|
|
500
|
-
| `
|
|
564
|
+
| `76` (`EX_PROTOCOL`) | A dialog `existing_session_action` rules out (Trading Login Handoff with `secondary`/`primaryoverride`) | Do not retry |
|
|
565
|
+
| `75` (`EX_TEMPFAIL`) | Login did not complete after 2FA, `mfa_timeout_action=exit` | Retry per policy |
|
|
566
|
+
| `70` (`EX_SOFTWARE`) | `restart_cap` consecutive relaunches never reached READY | Do not retry |
|
|
567
|
+
| `69` (`EX_UNAVAILABLE`) | Transient runtime failure (process crashed or killed, connection lost, JVM exited before becoming ready) | Retry |
|
|
501
568
|
|
|
502
|
-
`77`/`78` work with systemd's `RestartPreventExitStatus=`.
|
|
569
|
+
`70`/`76`/`77`/`78` work with systemd's `RestartPreventExitStatus=`.
|
|
503
570
|
|
|
504
571
|
Some login-blocking dialogs IB reports as a server-side condition -- not a credential
|
|
505
|
-
rejection -- never reach this table at all: a "Login failed"/"Login Error" dialog, or a
|
|
572
|
+
rejection -- never reach this table at all: a "Login failed"/"Login Error"/"not currently available" dialog, or a
|
|
506
573
|
Gateway "Connection to server failed" reason other than a known credential/account one
|
|
507
574
|
(e.g. a stale restart token), make ibcontroller relaunch in-process with a full fresh
|
|
508
|
-
login,
|
|
509
|
-
itself
|
|
575
|
+
login, the same way a scheduled `cold_restart_time` does -- the container
|
|
576
|
+
itself does not exit for these, until `restart_cap` consecutive relaunches never reach READY
|
|
577
|
+
(exit 70).
|
|
578
|
+
|
|
579
|
+
## Stopping under Docker
|
|
580
|
+
|
|
581
|
+
On SIGTERM (`docker stop`, Ctrl-C) a logged-in instance closes through File > Exit/Close so
|
|
582
|
+
TWS/Gateway can save its session and upload settings. Measured over 88 shutdowns: mean 1.3 s,
|
|
583
|
+
p99 4.3 s, max 4.9 s. A slow path (a dialog open, a stuck menu) can take longer: the menu retry
|
|
584
|
+
waits up to 5 s, the exit up to 8 s, then SIGTERM gets 5 s. Docker sends SIGKILL after 10 s by
|
|
585
|
+
default, which loses the graceful close. Set `stop_grace_period: 30s` (Compose) or
|
|
586
|
+
`docker stop -t 30` to keep it.
|
|
510
587
|
|
|
511
588
|
## License
|
|
512
589
|
|