Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 28 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,34 +98,60 @@ ibkr connect test --profile gateway-paper

### Account and positions

If a profile is connected to multiple managed accounts, pass `--account` to target a specific account:

```bash
ibkr account summary --profile gateway-paper
ibkr account summary --profile gateway-paper --account U123456789
ibkr positions --profile gateway-paper
ibkr positions --profile gateway-paper --account U123456789
```

### Orders

```bash
ibkr orders open --profile gateway-paper
ibkr orders open --profile gateway-paper --account U123456789
ibkr orders completed --profile gateway-paper
ibkr orders executions --profile gateway-paper
ibkr orders cancel 12345 --profile gateway-paper
ibkr orders modify 12345 --limit 150.50 --profile gateway-paper
ibkr orders cancel 12345 --profile gateway-paper --account U123456789
ibkr orders modify 12345 --limit 150.50 --profile gateway-paper --account U123456789
```

### Trading

Trading commands auto-detect a subset of contract types from `symbol`:

- `AAPL` -> stock
- `SPY260417C00700000` / `SPY260417C700` / `SPY260417C720.5` -> option on `SMART`
- `USDJPY` -> forex on `IDEALPRO`
- `ESZ6` -> future

Option symbols support the no-space OCC format and a simplified strike format:

- `SPY260417C00700000` -> standard OCC strike encoding
- `SPY260417C700` -> strike `700.0`
- `SPY260417C720.5` -> strike `720.5`, equivalent to OCC strike `00720500`

Symbols that do not match an option, forex, or future pattern are treated as stocks.

Preview first:

```bash
ibkr buy AAPL 10 --preview --profile gateway-live
ibkr buy AAPL 10 --preview --profile gateway-live --account U123456789
ibkr sell AAPL 10 --preview --profile gateway-live
ibkr buy SPY260417C00700000 1 --preview --profile gateway-live
ibkr buy "SPY260417C720.5" 1 --preview --profile gateway-live
ibkr buy USDJPY 1000 --preview --profile gateway-live
ibkr buy ESZ6 1 --preview --profile gateway-live
```

Submit only when you explicitly intend to place an order:

```bash
ibkr buy AAPL 10 --submit --profile gateway-live
ibkr buy AAPL 10 --submit --profile gateway-live --account U123456789
ibkr sell AAPL 10 --submit --profile gateway-live
```

Expand Down
30 changes: 23 additions & 7 deletions src/ibkr_cli/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from importlib.metadata import PackageNotFoundError, version
from pathlib import Path
from typing import Dict, List, Optional, Sequence, Tuple
from collections import defaultdict

import typer
from rich.console import Console
Expand Down Expand Up @@ -719,7 +720,16 @@ def account_summary(
return

console.print(render_profile_detail(selected_name, selected_profile, selected_name == config.default_profile))
console.print(render_account_summary_table(payload["rows"], str(payload["selected_account"])))
if payload["selected_account"]:
console.print(render_account_summary_table(payload["rows"], str(payload["selected_account"])))
else:
grouped_rows: Dict[str, List[Dict[str, object]]] = defaultdict(list)
for row in payload["rows"]:
grouped_rows[str(row["account"])].append(row)
for index, account_key in enumerate(sorted(grouped_rows)):
if index:
console.print()
console.print(render_account_summary_table(grouped_rows[account_key], account_key))


@app.command()
Expand Down Expand Up @@ -948,11 +958,14 @@ def execute_trade_command(

@app.command()
def buy(
symbol: str = typer.Argument(..., help="Ticker symbol, for example AAPL."),
symbol: str = typer.Argument(
...,
help="Trading symbol. Examples: AAPL (stock), USDJPY (forex), ESZ6 (future), SPY260417C700 (option).",
),
quantity: float = typer.Argument(..., help="Order quantity."),
profile: Optional[str] = typer.Option(None, "--profile", "-p", help="Profile name to use."),
exchange: str = typer.Option("SMART", "--exchange", help="Exchange to use for contract qualification."),
currency: str = typer.Option("USD", "--currency", help="Currency to use for contract qualification."),
exchange: str = typer.Option("SMART", "--exchange", help="Exchange override for contract qualification."),
currency: str = typer.Option("USD", "--currency", help="Currency override for stock and futures qualification."),
order_type: str = typer.Option("MKT", "--type", help="Order type: MKT, LMT, STP, STP LMT, or TRAIL."),
limit_price: Optional[float] = typer.Option(None, "--limit", help="Limit price (required for LMT / STP LMT)."),
stop_price: Optional[float] = typer.Option(None, "--stop", help="Stop trigger price (required for STP / STP LMT, optional for TRAIL)."),
Expand All @@ -978,11 +991,14 @@ def buy(

@app.command()
def sell(
symbol: str = typer.Argument(..., help="Ticker symbol, for example AAPL."),
symbol: str = typer.Argument(
...,
help="Trading symbol. Examples: AAPL (stock), USDJPY (forex), ESZ6 (future), SPY260417C700 (option).",
),
quantity: float = typer.Argument(..., help="Order quantity."),
profile: Optional[str] = typer.Option(None, "--profile", "-p", help="Profile name to use."),
exchange: str = typer.Option("SMART", "--exchange", help="Exchange to use for contract qualification."),
currency: str = typer.Option("USD", "--currency", help="Currency to use for contract qualification."),
exchange: str = typer.Option("SMART", "--exchange", help="Exchange override for contract qualification."),
currency: str = typer.Option("USD", "--currency", help="Currency override for stock and futures qualification."),
order_type: str = typer.Option("MKT", "--type", help="Order type: MKT, LMT, STP, STP LMT, or TRAIL."),
limit_price: Optional[float] = typer.Option(None, "--limit", help="Limit price (required for LMT / STP LMT)."),
stop_price: Optional[float] = typer.Option(None, "--stop", help="Stop trigger price (required for STP / STP LMT, optional for TRAIL)."),
Expand Down
Loading