icli
is a command line interface for live trading (or sandbox/paper trading) using IBKR accounts.
The intended use case is for scalping or swing trading, so we prioritize easy of understanding your positions and active orders while removing unnecessary steps when placing orders.
Watch the console replay demo below to see a paper trading account where we add some live quotes for stocks and options, remove quotes, place orders to buy and sell, check execution details to view aggregate commission charges, check outstanding order details, and add some live futures quotes too.
Note: the capture preview is a couple years old at this point and we should make a new one. The interface has improved since then, so try it out from a recent clone and join us here in the future.
Welcome to icli
! You can use icli
to manage manual and automated trading using your IBKR account for stocks, futures, currencies, and options.
You can enable audio announcements of trade events if you also run awwdio and provide your awwdio
address as an environment variable like ICLI_AWWDIO_URL=http://127.0.0.1:8000 poetry run icli
(macOS only currently and you need to manually install the system speech voice packs in system settings).
There's always a hundred more features we could add, but focus goes mainly towards usability and efficient order entry currently. There's an unreleased in-progress algo trading agent plugin to automatically buy and sell stocks, futures, and/or options based on external signals too. Cleaning those up for public release isn't a priority at the moment unless sponsors would like to step up and motivate us for a wider code release to combine all the feautres into a finished product we can publish.
You can run multiple clients in different terminal windows using unique client ids for each session like ICLI_CLIENT_ID=4 poetry run icli
. Note: IBKR restricts orders per-client-id, so for example if you place an order under client id 4, the order will not show up under other clients.
Some helpful advanced commands only available in icli
:
add SPY240412{P,C}005{1,2,3}0000
will add live quotes for each of: SPY240412C00510000
, SPY240412C00520000
, SPY240412C00530000
, SPY240412P00510000
, SPY240412P00520000
, SPY240412P00530000
.
rm SPY240412{P,C}005{1,2,3}0000
too. The syntax also supports range population like add SPXW24041{5..7}{P05135,C05150}000
. Each quote also has a row id, and you can remove quotes by row id individually or using replacement syntax: rm :31
, rm :{31..37}
, rm :{25,27,29}
etc.expand
wrapper like: expand buy {META,MSFT,NVDA,AMD,AAPL} $15_000 MID
— that command will buy approximately $15,000 worth of each symbol using current midpoint quote prices.evict * -1 0 MID
or immediately sell symbols with current market price caps using evict MSFT -1 0 AF
etc as well.
expand?
and evict?
and buy?
for more details of how it all works.buy AAPL 100 MID
to buy then buy AAPL -100 MID
to sell. You can buy and sell by any combination of price and quantity: buy MSFT $10_000 AF
, buy MSFT -10 MKT
etc.$
, so buy AAPL 100 AF
will buy 100 shares of AAPL at the current market price using IBKR's Adaptive Fast order algo type. Price or Quantity values can be positive or negative: buy AAPL 100 AF
, buy AAPL $10_000 AF
, buy AAPL -20 AF
, buy AAPL -$40_000 AF
. You can append preview
to buy
orders to get an estimate of margin impact and other account-based order details too.buy AAPL 100 AF @ 233.33
— submit buy order for 100 shares but with user-specified limit price of $233.33buy AAPL 100 AF @ 233.33 preview
— preview the margin impact and cost estimation without executing an orderbuy AAPL 100 AF @ 233.33 + 10
— same buy order as above, but automatically attach a "take profit" order $10 higherbuy AAPL 100 AF @ 233.33 - 10
— same buy order as above, but automatically attach a "stop loss" order $10 lowerbuy AAPL 100 AF @ 233.33 ± 10
— same buy order as above, but automatically attach a "take profit" $10 high and a "stop loss" $10 lower simultaenously (when one executes, the other is automatically cancelled by the IBKR system)buy
commands concurrently then show your portfolio holdings after they complete:
buy AAPL 100 AF preview&; buy MSFT 100 AF preview&; ls
.&
to your commands to run them concurrently then split commands with ;
, and you can also run any commands sequentially with just ;
as well like: ls; ord; bal SMA
expand
version is easier if your purchase quantity/amount and algo are the same: buy AAPL 100 AF preview&; buy MSFT 100 AF preview&
versus expand buy {MSFT,AAPL} 100 AF prevew
(/ :BP3 AAPL)
shows how many shares you can buy of AAPL (on 33% margin).(grow :AF 300)
calculates your AvailableFunds growing by 300%.(grow (* AAPL (/ :BP3 AAPL)) 7)
(/ AAPL TSLA)
(/ AAPL :18)
.See below for further account setup and environment variable conditions under the Download section.
For tracking feature updates, check the full commit history and you can always run ?
for listing commands and getting help when running commands. The README is slightly undermaintained and some features are lacking complete documentation outside of the runtime itself, so feel free to suggest updates where useful.
position
command can be entered as just p
because it doesn't conflict with any other commandqquote
and quote
commands, so those must be clarified by using qq
or qu
at a minimumhelpers.py:contractForName()
)
/ES
, /MES
, /NQ
, /MNQ
, etcAAPL210716C00155000
/ES210716C05000000
"bto 1 AAPL210716C00155000 sto 2 AAPL210716C00160000 bto 1 AAPL210716C00165000"
add "bto ... sto ..."
) and for requesting spread trades using the spread
command
EVICT [symbol] [quantity]
command to immediately yeet an entire equity position into a MidPrice order with no extra steps
-1
as the quantity to use full quantity helddepth
command)cancel
command with no arguments will bring up a menu for you to select one or more live orders to immediately cancel.cancel *
removes all orders for the current clientcancel AAPL2*
removes all orders for AAPL contracts, etccancel order1 order2 ... orderN
command with arguments will also cancel each requested order id immediately.
orders
command output tableoadd
: add all order symbols to quote view)add [symbols...]
: add symbols to quote view, quoted symbols can be spreads like add AAPL QQQ "buy 1 AAPL210716C00160000 sell 1 AAPL210716C00155000"
to quote a credit spread and two equity symbols)qquote [symbols...]
executions
command)
ES : 4,360.25 ( 1.55% 67.00) ( 1.09% 47.25) 4,362.00 4,293.25 4,360.00 x 158 4,360.25 x 112 4,310.25 4,313.00
Live stock / etf / etn / futures / etc quotes show:
ES
)4,360.25
)( 1.55% 67.00)
)
( 1.09% 47.25)
)
4,362.00
)4,293.25
)4,360.00 x 158
)4,360.25 x 112
)4,310.25
)4,313.00
)For more detailed level 2 quotes, we'd recommend WeBull's TotalView integration because they have a special deal with NASDAQ to allow TotalView for $1.99/month instead of paying IBKR hundreds in fees per month to get limited depth views.
TSLA 210716C00700000: [u 653.98 ( -7.04%)] [iv 0.47] 3.37 ( -32.57% -1.65 5.00) ( 14.29% 0.40 2.95) ( -24.24% -1.10 4.45) 3.35 x 4 3.40 x 3
Live option quotes display more details because prices move faster:
TSLA 210716C00700000
)653.98
)-7.04%
)
653.98
and strike at $700.00
, the stock is currently 7.04% under ATM for the strike:
653.98 * 1.0704 = 700.020192
[iv 0.47]
)3.37
)( -32.57% -1.65 5.00)
)
3.37
is -32.57%
(-1.65
points down) from high of day, which was 5.00
( 14.29% 0.40 2.95)
)
( -24.24% -1.10 4.45)
)3.35 x 4
)3.40 x 3
)For more detailed option level 2 quotes, we'd recommend futu/moomoo in-app real time OPRA Level 2 quotes for $3.99/month. They also have a built-in unusual options volume scanner, and they now have a trading and quote API, but API quotes are billed differently than in-app quotes and the API docs are poorly translated into english, so ymmv.
futu/moomoo also lets you buy equity depth for ARCA/OpenBook/CBOE/BZX/NASDAQ exchanges, but they charge regular market prices for each of those, so you'd be paying over $100/month for full depth coverage (and their TotalView alone is $25.99/month while WeBull offers it for $1.99/month).
The quote view uses this order for showing quotes based on security type:
Futures are sorted first by our specific futures order defined by the FUT_ORD
dict in cli.py
then by name if there isn't a specific sort order requested (because we want /ES
/NQ
/YM
first in the futures list and not /GBP
/BTC
etc).
Stocks/etfs sort in REVERSE alphabetical order because it's easier to see the entry point of the stocks view at the lowest point rather than visually tracking the break where futures and stocks meet.
Single option quotes are displayed in alphabetical order.
Finally, option spreads show last because they are multi-line displays showing each symbol leg per spread.
The overall sort is controlled via cli.py:sortQuotes()
IBKR only exposes their trade API via a gateway application (Gateway or TWS) which proxies requests between your API consumer applications and the IBKR upstream API itself.
First download the IBKR Gateway, login to the gateway (which will manage the connection attempts to IBKR trade and data services), then have your CLI connect to the gateway.
icli
Download icli
as a new repo:
git clone https://github.com/mattsta/icli
Create your local environment:
poetry install
Even though you are logged in to the gateway, the IBKR API still requires your account ID for some actions (because IBKR allows multiple account management, so even if you are logged in as you, it needs to know which account you really want to modify).
Configure your IBKR account id as environment variable or in .env.icli
as:
ICLI_IBKR_ACCOUNT_ID="U..."
You can also configure the gateway host and port to connect to using:
ICLI_IBKR_HOST="127.0.0.1"
ICLI_IBKR_PORT=4001
You can also configure the idle refresh time for toolbar quotes (in seconds):
ICLI_REFRESH=3.3
Configure environment settings as above, confirm the IBKR Gateway is started (and confirm whether you want read-only mode or full mode in addition to noting which port the gateway is opening for local connections), login to the IBKR Gateway (requires 2fa to the IBKR app on your phone), then run:
ICLI_IBKR_PORT=[gateway localhost port] poetry run icli
You should see your account details showing in the large bottom toolbar along with a default set of quotes (assuming you have all the streaming market data permissions required).
View all commands by just hitting enter on a blank line.
View all commands by category by entering ?
.
View per-command documentation by entering a command name followed by a question: limit?
or lim?
or exec?
or pos?
or cancel?
etc.
If you have any doubt about how a command may change your account, check the source for the command in lang.py
yourself just to confirm the data workflow.
icli
uses USD and SMART exchange transactions for all orders (except for futures which use the correct futures exchange per future symbol).You should also be comfortable diving into the code if anything looks wonky to you.
icli
is still limited by all regular IBKR policies including, but not limited to:
executions
command (each row means +20 order credits for the day)/MES
100 times a night on your $4k account (though, watch out for the $0.52 commission per trade).Entry point for the CLI is __main__.py
which handles the event loop setup, environment variable reading, and app launching.
The easiest way to launch the cli is via poetry in the repository directory: poetry run icli
cli commands are processed in a prompt-toolkit loop managed by the somewhat too long dorepl()
method of class IBKRCmdlineApp
in cli.py
.
cli commands are implemented in lang.py
with each command being a class with custom argument definitions as organized by the mutil/dispatch.py
system. Check out the OP_MAP
variable for how command names are mapped to categories and implementation classes.
Your CLI session history is persisted in ~/.tplatcli_ibkr_history.{live,sandbox}
so you have search and up/down recall across sessions.
All actions taken by the underlying IBKR API wrapper are logged in a file named icli-{timestamp}.log
so you can always review every action the API received (which will also be the log where you can view any series of order updates/modifications/cancels since IBKR removes all intermediate order states of orders after an order is complete).
All times in the interface are normalized to display in US Eastern Time where pre-market hours are 0400-0928, market hours are 0930-1600, and after hours is 1600-2000 (with options trading 0930-1600, with certain etf and index options trading until 1615 every day). Futures operate under their own weird futures hours schedule, so enjoy trading your Wheat Options and Mini-sized Wheat Futures between 1900-0745 and 0830-1345.
futsexchanges.py
contains a mostly auto-generated mapping of future symbols to their matching exchanges and full text descriptions. The mapping can be updated by extracting updated versions of the table of IBKR futures using generateFuturesMapping()
. The reason for this mapping is when entering a futures trade order, IBKR requires the exchange name where the futures symbol lives (i.e. there's no SMART futures router and futures only trade on their owning exchange), so we had to create a full lookup table on our own.
Also note: some of the future symbol descriptions are manually modified after the automatic mapping download. Read end of the file for notes about which symbols need additional metadata or symbol changes due to conflicting names or multiplier inconsistencies (example: BRR
bitcoin contract is one symbol, but microbitcoin is 0.1 multiplier, while standard is 5 multiplier, and for some reason IBKR didn't implement the micro as the standard MBT
symbol, so you have to use it as BRR
with explicit multiple).
orders.py
is a central location for defining IBKR order types and extracting order objects from specified order types using all 20+ poorly documented, conflicting, and multi-purpose optional metadata fields an order may need.
icli
is still a work in progress and future features may include:
This is the second trade CLI I've written (the first being a tradier api cli which isn't public yet) because I wanted faster access to scalping options during high volatility times where seconds matter for good trade executions, but navigating apps or web page entry flows wasn't being the most efficient way to place orders.
Writing an IBKR seemed a good way to create a rapid order entry system also capable of using the only public simple fee broker which offers complex exchange-side and simulated order types via API like primary peg (relative orders), mini-algos like adaptive limit/market orders, peg to midpoint, snap to market/primary/midpoint, market with protection, etc.
so here we are.
Feel free to open issues to suggest changes or submit your own PR changes or refactor any existing confusing flows into less coupled components.
Immediate next-step areas of interest are:
OTOCO::BUY_100_TSLA210716C00700000_3.33:SELL_ALL_4.44:STOP_ALL_2.99
which would convert the line into a 3-leg bracket order then execute it all it one step.icli
API to bridge the actual IBKR API