Skip to content

Agent-friendly Schwab CLI tools for portfolio analysis and market insights

License

Notifications You must be signed in to change notification settings

amadad/schwab-cli-tools

Repository files navigation

schwab-cli-tools

Agent-friendly Schwab CLI tools for portfolio analysis, market insights, and trading.

Disclaimer

This project is built on the open-source schwab-py client and is not affiliated with, endorsed by, or supported by Charles Schwab & Co. Use it at your own risk and ensure you comply with Schwab's terms and API policies.

Quick Start

git clone https://github.com/amadad/schwab-cli-tools.git
cd schwab-cli-tools
uv sync
cp .env.example .env
cp config/accounts.template.json config/accounts.json
mkdir -p tokens private

Authentication

uv run schwab-auth               # Portfolio API (opens browser)
uv run schwab-auth --manual      # For headless/remote machines (copy-paste flow)
uv run schwab-market-auth        # Market data API (opens browser)
uv run schwab-market-auth --manual  # For headless/remote machines (copy-paste flow)

thinkorswim Enablement (Required for Trading)

To place orders via the API, each Schwab account must be thinkorswim enabled:

  1. Log into schwab.com
  2. Go to TradeTrading Platforms
  3. Click "Learn how to enable thinkorswim"
  4. Select the accounts you want to enable for API trading
  5. Wait for "Pending Enablement" to complete (may take minutes to hours)
  6. Re-run schwab-auth to refresh your token

Without thinkorswim enablement, orders will be rejected with "No trades are currently allowed". Read-only access (positions, balances, quotes) works without this step.

The --manual flag is for headless servers or SSH sessions where a browser can't open locally. It prints a URL you can open on any device (phone, laptop, etc.), then prompts you to paste the callback URL. Both auth commands support this flag.

Market commands (vix, indices, sectors, market, movers, futures) require the market auth flow. Tokens are stored under ~/.schwab-cli-tools/tokens by default. Refresh tokens expire after 7 days.

CLI Commands

All commands support --json for machine-readable output.

Portfolio Commands

schwab portfolio           # Portfolio summary
schwab p -p                # Portfolio with positions (alias)
schwab positions           # All positions
schwab pos --symbol AAPL   # Filter by symbol (alias)
schwab balance             # Account balances
schwab bal                 # Alias
schwab allocation          # Allocation analysis
schwab alloc               # Alias

Market Commands

schwab vix                 # VIX data and interpretation
schwab indices             # Major indices (S&P, Nasdaq, Dow)
schwab idx                 # Alias
schwab sectors             # Sector performance
schwab sec                 # Alias
schwab market              # Aggregated market signals
schwab mkt                 # Alias
schwab movers              # Top gainers/losers
schwab mov --gainers       # Gainers only
schwab futures             # Pre-market futures (/ES, /NQ)
schwab fut                 # Alias
schwab fundamentals AAPL   # Symbol fundamentals
schwab fund AAPL           # Alias
schwab dividends           # Recent dividends
schwab div --upcoming      # Upcoming ex-dates

Admin Commands

schwab auth                # Check authentication status
schwab doctor              # Run diagnostics
schwab dr                  # Alias
schwab accounts            # List configured accounts

Report Commands

schwab report              # Generate portfolio report
schwab report -o ./out.json
schwab report --no-market  # Skip market data
schwab snapshot            # Complete data snapshot
schwab snap --json         # For automation (alias)

Trade Commands

schwab buy acct_trading AAPL 10 --dry-run   # Preview buy
schwab sell acct_trading AAPL 10 --dry-run  # Preview sell
schwab buy acct_trading AAPL 10 --live      # Execute with --live flag
schwab sell acct_trading AAPL 10 --live     # Execute with --live flag
schwab orders acct_trading                   # Show open orders
schwab ord                                   # Alias

Command Aliases

Full Command Alias
portfolio p
positions pos
balance bal
allocation alloc
indices idx
sectors sec
market mkt
movers mov
futures fut
fundamentals fund
dividends div
doctor dr
snapshot snap
orders ord

Trade Safety

Live trading is DISABLED by default. This is a critical safety feature.

To execute real trades, use one of these methods:

# Method 1: --live flag (per-command, recommended)
schwab sell acct_trading AAPL 10 --live

# Method 2: Environment variable (session-wide)
export SCHWAB_ALLOW_LIVE_TRADES=true
schwab sell acct_trading AAPL 10

Additional safeguards:

  • --dry-run always works (preview mode)
  • Live trades require typing "CONFIRM" (cannot be bypassed)
  • JSON mode cannot execute live trades
  • All trade attempts are logged to ~/.schwab-cli-tools/trade_audit.log

For automation: Use --dry-run only. Never enable live trading in automated environments.

Configuration

Environment Variables

# Default output format (text or json)
export SCHWAB_OUTPUT=json

# Default account alias for buy/sell/orders
export SCHWAB_DEFAULT_ACCOUNT=acct_trading

# Data directory (defaults to ~/.schwab-cli-tools)
export SCHWAB_CLI_DATA_DIR=~/.schwab-cli-tools

# Report directory
export SCHWAB_REPORT_DIR=~/.schwab-cli-tools/reports

# Token paths (override data dir)
export SCHWAB_TOKEN_PATH=~/.schwab-cli-tools/tokens/schwab_token.json
export SCHWAB_MARKET_TOKEN_PATH=~/.schwab-cli-tools/tokens/schwab_market_token.json

# Trade safety (NEVER enable in automation)
export SCHWAB_ALLOW_LIVE_TRADES=true

Account Configuration

Create config/accounts.json from the template:

cp config/accounts.template.json config/accounts.json

See config/CLAUDE.md for the JSON schema and field documentation.

JSON Response Envelope

All --json output follows this schema:

{
  "schema_version": 1,
  "command": "portfolio",
  "timestamp": "2026-01-23T12:00:00",
  "success": true,
  "data": { ... },
  "error": null
}

Errors set success: false and populate error.

Architecture

src/schwab_client/
├── cli/                    # Modular CLI package
│   ├── __init__.py         # Entry point, argparse, routing
│   ├── context.py          # Cached clients, trade logger
│   ├── output.py           # JSON envelope, formatters
│   └── commands/           # Command handlers
│       ├── portfolio.py    # portfolio, positions, balance, allocation
│       ├── market.py       # vix, indices, sectors, movers, etc.
│       ├── trade.py        # buy, sell, orders
│       ├── admin.py        # auth, doctor, accounts
│       └── report.py       # report, snapshot
├── auth.py                 # Portfolio API authentication
├── market_auth.py          # Market API authentication
└── client.py               # SchwabClientWrapper

src/core/                   # Pure business logic
├── portfolio_service.py    # Portfolio aggregation
├── market_service.py       # Market data processing
└── errors.py               # Custom exceptions

config/
├── accounts.schema.json    # JSON schema for accounts
├── accounts.template.json  # Template (tracked)
├── accounts.json           # Your config (gitignored)
└── secure_account_config.py

Development

# Run tests
uv run pytest tests/ -v

# Run with mock clients (no credentials needed)
uv run pytest tests/unit/ -v

# Lint and format
uv run ruff check . --fix
uv run black .

Shell Completion

If argcomplete is installed, enable shell completion:

# Bash
eval "$(register-python-argcomplete schwab)"

# Add to ~/.bashrc for persistence

Security Rules

  1. Never commit .env, config/accounts.json, tokens/, or private/
  2. Never hardcode account numbers or API keys
  3. Refresh tokens expire after 7 days - re-run auth commands
  4. Use schwab doctor to check configuration status
  5. Trade audit logs are written to ~/.schwab-cli-tools/trade_audit.log

Exit Codes

  • 0 - Success
  • 1 - User/configuration error
  • 2 - API/HTTP error

About

Agent-friendly Schwab CLI tools for portfolio analysis and market insights

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •  

Languages