-
-
Notifications
You must be signed in to change notification settings - Fork 0
CLI
ibctl is the command-line interface to a running TWS Headless engine. It communicates over a Unix socket (/tmp/tws_headless.sock by default).
./ibctl.py [command] [args...] [--socket PATH] [--timeout SECS] [--json]- How do I see what's going on?
- How do I fund a plugin?
- How do I transfer assets between plugins?
- How do I load and start a plugin?
- How do I stop or pause a plugin?
- How do I place a manual trade?
- How do I place a manual trade as a plugin instance?
- How do I send a custom request to a plugin?
- How do I load multiple instances of a plugin?
- How do I reconcile plugin holdings with IB?
- How do I shut down gracefully?
- Full Command Reference
./ibctl.py status
./ibctl.py summary
./ibctl.py summary --json # machine-readable./ibctl.py positions./ibctl.py plugin list./ibctl.py plugin dump momentum_5day
./ibctl.py plugin dump momentum_5day --json./ibctl.py plugin status momentum_5dayFunding a plugin means moving cash (or positions) from the _unassigned pool into the plugin's ledger. No IB orders are placed — this is bookkeeping only.
./ibctl.py transfer list _unassigned./ibctl.py transfer cash _unassigned momentum_5day 25000The engine shows what would change without making any changes.
./ibctl.py transfer cash _unassigned momentum_5day 25000 --confirm# Preview
./ibctl.py transfer position _unassigned momentum_5day SPY 100
# Execute
./ibctl.py transfer position _unassigned momentum_5day SPY 100 --confirmRun two transfers in sequence — one for cash, one for each position.
Transfer in the opposite direction:
./ibctl.py transfer cash momentum_5day _unassigned 25000 --confirmTransfers between any two plugins work the same as transfers to/from _unassigned.
# From plugin A to plugin B
./ibctl.py transfer cash plugin_a plugin_b 5000 --confirm./ibctl.py transfer position plugin_a plugin_b SPY 50 --confirm./ibctl.py transfer list plugin_a- Both plugins must be loaded (not necessarily started)
- The source must have sufficient cash/quantity
- Negative amounts are not allowed — reverse the from/to instead
- No confirmation prompt is shown without
--confirm; always preview first
./ibctl.py plugin load plugins.momentum_5day.pluginThe path is a Python import path relative to the engine's working directory.
Append =slot_name to the path to assign a stable instance key. Each slot
gets independent state, holdings, and a distinct CLI address:
./ibctl.py plugin load plugins.momentum_5day.plugin=spy_momentum
./ibctl.py plugin load plugins.momentum_5day.plugin=qqq_momentum
# Now address each by slot name
./ibctl.py plugin start spy_momentum
./ibctl.py plugin start qqq_momentum
./ibctl.py transfer cash _unassigned spy_momentum 25000 --confirm
./ibctl.py transfer cash _unassigned qqq_momentum 25000 --confirmWithout =slot, the plugin's own name (from super().__init__("name", ...)) is used as the slot.
With an optional descriptor (metadata tag visible in plugin list):
./ibctl.py plugin load plugins.momentum_5day.plugin "SPY momentum strategy"./ibctl.py plugin start momentum_5dayYou can also use the plugin's UUID (shown in plugin list):
./ibctl.py plugin start a3f1c2d4-...plugin load automatically transitions through LOADED; you still need plugin start to move to STARTED. The typical sequence is:
./ibctl.py plugin load plugins.momentum_5day.plugin
./ibctl.py plugin start momentum_5day
./ibctl.py transfer cash _unassigned momentum_5day 25000 --confirm./ibctl.py plugin list
./ibctl.py plugin status momentum_5dayThe plugin saves its state, calculate_signals stops being called, but streams and subscriptions remain active. Resume any time.
./ibctl.py plugin freeze momentum_5day
./ibctl.py plugin resume momentum_5dayThe plugin saves state, unsubscribes from streams and MessageBus, and transitions to STOPPED. Holdings are preserved.
./ibctl.py plugin stop momentum_5dayStops (if running) then removes it from the engine. Holdings remain in SQLite for the next load.
./ibctl.py plugin unload momentum_5dayThe plugin keeps running (receiving data, callbacks fire) but calculate_signals is skipped.
./ibctl.py plugin disable momentum_5day
./ibctl.py plugin enable momentum_5day./ibctl.py pause
./ibctl.py resume./ibctl.py order buy SPY 100
./ibctl.py order sell QQQ 50 --confirm./ibctl.py order buy AAPL 25 limit 175.00 --confirm
./ibctl.py order sell MSFT 30 limit 420.00./ibctl.py order sell SPY 100 stop 445.00 --confirm# stop price, then limit price
./ibctl.py order sell SPY 100 stop-limit 445 443 --confirm./ibctl.py order sell SPY 100 trail 2.50 --confirm./ibctl.py order sell SPY 100 trail 0.5% --confirm./ibctl.py order buy SPY 100 moc --confirm
./ibctl.py order buy SPY 100 moo --confirm./ibctl.py order sell QQQ 50 loc 390.00 --confirm
./ibctl.py order buy QQQ 50 loo 385.00 --confirmAppend --tif to any order type:
./ibctl.py order buy SPY 100 limit 450 --tif gtc --confirm # Good-til-cancelled
./ibctl.py order buy SPY 100 limit 450 --tif ioc # Immediate-or-cancel
./ibctl.py order buy SPY 100 limit 450 --tif fok # Fill-or-killDefault TIF is day.
Use trade instead of order to place a real IB order and book the fill against a specific plugin's holdings, commission tracking, and P&L ledger.
# By plugin name (works when only one instance is loaded)
./ibctl.py trade momentum_5day BUY SPY 50 --confirm
# By slot name (required when multiple instances of the same class are running)
./ibctl.py trade spy_momentum BUY SPY 100 --confirm
./ibctl.py trade qqq_momentum BUY QQQ 75 --confirm
# By UUID (always unambiguous)
./ibctl.py trade a3f1c2d4-17e7-4ee5-ac03-282e0cd05c2b BUY SPY 50 --confirm
# With a reason (logged in execution history)
./ibctl.py trade spy_momentum SELL SPY 50 --reason "stop hit" --confirmThe fill updates that instance's holdings (current_cash, current_positions), commissions are attributed to it, and P&L is reported against it — identical to a signal the plugin generated itself.
Without --confirm, the command is a dry-run preview that shows what would be placed without placing it.
./ibctl.py liquidate SPY --confirm # One symbol
./ibctl.py liquidate --confirm # EverythingPlugins implement handle_request(request_type, payload). You can invoke it from the CLI:
# No payload
./ibctl.py plugin request momentum_5day get_status
# With JSON payload
./ibctl.py plugin request momentum_5day set_period '{"period": 20}'
# Get the response as JSON
./ibctl.py plugin request momentum_5day get_status --jsonThe response always has a "success" key. On success, data is under "data".
Use plugin message to send arbitrary JSON to a plugin without specifying a request type.
Inside the plugin, request_type will be "message":
./ibctl.py plugin message momentum_5day '{"action": "reset", "value": 0.5}'Well-behaved plugins implement cli_help() to document their commands:
./ibctl.py plugin help momentum_5dayUseful for testing calculate_signals without waiting for the next bar:
./ibctl.py plugin trigger momentum_5dayReconciliation compares what each plugin's ledger says it holds against the actual IB account positions.
./ibctl.py reconcile
./ibctl.py reconcile --json # Machine-readable reportThe report shows:
- Positions the plugin claims but IB doesn't have
- Positions IB has that no plugin claims
- Cash discrepancies
Reconciliation is advisory — it reports differences but does not auto-correct them. Use transfers to realign bookkeeping.
./ibctl.py stopThis signals the engine to:
- Stop all plugins (saving state)
- Cancel open IB subscriptions
- Close the IB connection
- Exit
| Flag | Default | Description |
|---|---|---|
--socket PATH |
/tmp/tws_headless.sock |
Unix socket path |
--timeout SECS |
10 | Command timeout |
--json |
off | Force JSON output |
| Command | Description |
|---|---|
status |
Account overview and net liquidation |
positions |
All positions with P&L |
summary |
Plugin-by-plugin breakdown |
help |
List all commands |
| Command | Description |
|---|---|
plugin list |
All loaded plugins, their state, instance ID |
plugin load PATH[=SLOT] [DESC] |
Load plugin; optional =SLOT assigns instance key |
plugin unload NAME|SLOT|ID |
Unload plugin (stops first if needed) |
plugin status NAME|SLOT|ID |
Plugin state, holdings summary |
plugin start NAME|SLOT|ID |
Transition LOADED → STARTED |
plugin stop NAME|SLOT|ID |
Transition STARTED/FROZEN → STOPPED |
plugin freeze NAME|SLOT|ID |
Pause signal generation, keep streams |
plugin resume NAME|SLOT|ID |
Resume from FROZEN |
plugin enable NAME|SLOT|ID |
Re-enable signal generation |
plugin disable NAME|SLOT|ID |
Suppress signals without stopping |
plugin trigger NAME|SLOT|ID |
Run one calculate_signals cycle now |
plugin dump NAME|SLOT|ID |
Positions, open orders, holdings detail |
plugin request NAME TYPE [JSON] |
Send typed request to plugin's handle_request
|
plugin message NAME [JSON] |
Send arbitrary JSON (delivers request_type="message") |
plugin help NAME |
Show plugin CLI help (calls cli_help()) |
NAME is the plugin's class name; SLOT is the instance key assigned at load; ID is the UUID shown in plugin list. All are accepted interchangeably.
| Command | Description |
|---|---|
transfer list PLUGIN |
Show cash and positions available to transfer |
transfer cash FROM TO AMOUNT [--confirm] |
Move cash between plugins |
transfer position FROM TO SYMBOL QTY [--confirm] |
Move position between plugins |
Without --confirm, all transfer commands are dry-run previews.
| Command | Description |
|---|---|
order buy|sell SYMBOL QTY [TYPE] [options] [--confirm] |
Place any order type |
trade NAME|SLOT|ID buy|sell SYMBOL QTY [--confirm] [--reason TEXT] |
Order attributed to a plugin instance; updates its holdings and P&L |
liquidate [SYMBOL] [--confirm] |
Liquidate one or all positions |
Order types:
| Type syntax | IB order type |
|---|---|
| (omitted) | Market (MKT) |
limit PRICE |
Limit (LMT) |
stop PRICE |
Stop (STP) |
stop-limit STOP LIMIT |
Stop-Limit (STP LMT) |
trail AMOUNT |
Trailing Stop — fixed |
trail N% |
Trailing Stop — percentage |
moc |
Market on Close |
loc PRICE |
Limit on Close |
moo |
Market on Open |
loo PRICE |
Limit on Open |
TIF values: day (default) · gtc · ioc · fok
| Command | Description |
|---|---|
pause |
Freeze all plugins |
resume |
Resume all plugins |
reconcile [--json] |
Compare plugin ledgers to IB account |
stop |
Graceful engine shutdown |
TWS Headless
- Startup sequence
- Market data & streams
- Plugin execution
- Holdings & bookkeeping
- Order lifecycle
- State persistence
- See what's going on
- Fund a plugin
- Transfer assets
- Load and start a plugin
- Stop or pause a plugin
- Place a manual trade
- Send a plugin request
- Manage instrument list
- Reconcile holdings
- Move paper → live
- Shut down
- Full command reference
Plugin Manual ← complete reference
- File layout
- Lifecycle methods
- State persistence
- Market data streams
- Trade signals
- Order callbacks
- Holdings management
- MessageBus
- ContractBuilder
- Instrument compliance
- Multiple instances (slots)
- CLI help & messaging
- Threading rules
- Full example