Skip to main content
Glama

📈 Trading CLI

Local, multi-account paper-trading engine for humans and AI agents. Live terminal dashboard, Alpaca-style orders, REST + MCP server. SQLite state, Yahoo Finance market data. Simulation only — never places live brokerage orders. 🚫💸

🧺 Assets

🛠️ Engine

Stocks / ETFs / crypto (BTC-USD) / FX (EURUSD=X) / futures (ES=F) / equity options (OCC AAPL260116C00250000)

market / limit / stop / stop_limit / trailing_stop + bracket / OCO / OTO / mleg with take_profit / stop_loss, notional sizing, client order IDs, TIF (gtc / day / ioc / fok / opg / cls), extended-hours limit orders

⚙️ Setup

Requires Python 3.10+ and Bun >=1.4.1 (the tradingcli-tui dashboard runs on Bun + OpenTUI).

# from source
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt          # or: pip install -e .
(cd tui && bun install)                  # TUI deps (Bun + OpenTUI)

# isolated tool install (uv)
uv tool install .

🗄️ Database defaults to ~/.papertrade.db; override with PAPERTRADE_DB=/tmp/test.db or PAPERTRADE_DB=:memory: for isolated in-memory tests.

Related MCP server: tastytrade-mcp

🚀 Run

# first-run wizard + live TUI dashboard 🖥️ (Bun + OpenTUI)
python3 papertrade.py            # or: tradingcli
# explicit dash
python3 papertrade.py dash       # or: tradingcli dash (or: tradingcli-tui)
# legacy Rich dashboard
python3 papertrade.py dash --rich
# headless snapshot for agents / scripting 🤖 (single JSON envelope, no TTY)
tradingcli-tui --headless --json snapshot
tradingcli-tui --headless --json snapshot -a mybook
tradingcli-tui --headless --json backtest -a mybook --lookback-days 1825

👛 Accounts

python3 papertrade.py new mybook --cash 50000
python3 papertrade.py accounts --json
python3 papertrade.py use mybook

💹 Trade → inspect

python3 papertrade.py buy AAPL 5 -a mybook
python3 papertrade.py positions -a mybook --json
python3 papertrade.py market --json

🔄 Alpaca-style order lifecycle

python3 papertrade.py order submit AAPL --side buy --qty 10 --type limit --limit-price 185 -a mybook
python3 papertrade.py order submit AAPL --side sell --qty 10 --type trailing-stop --trail-percent 3 -a mybook
python3 papertrade.py order get --order-id 2 --json   # pending limit from above
python3 papertrade.py order replace 2 --limit-price 184
python3 papertrade.py order cancel-all -a mybook
python3 papertrade.py order submit AAPL --side buy --qty 10 --type limit --limit-price 180 --dry-run --json
python3 papertrade.py position close AAPL --percent 50 -a mybook
python3 papertrade.py position close-all -a mybook

🧷 Brackets, options, watchlists, research

# bracket / OCO / OTO — use --take-profit / --stop-loss / --stop-loss-limit
# options / chain / watchlists / research
python3 papertrade.py option get AAPL270115C00100000 --json
python3 papertrade.py option exercise AAPL270115C00100000 -a mybook
python3 papertrade.py chain AAPL 2027-01-15
python3 papertrade.py watchlist create Tech --symbols AAPL,MSFT,NVDA -a mybook
python3 papertrade.py watchlist quotes Tech -a mybook --json
python3 papertrade.py data bars AAPL --timeframe 1Day --limit 30 --json
python3 papertrade.py data snapshot AAPL --json
python3 papertrade.py data movers --json
python3 papertrade.py calendar --start 2026-07-01 --end 2026-07-31 --json

# backtest current holdings as a retrospective (see notes below)
python3 papertrade.py backtest -a mybook --lookback-days 1825 --commission-bps 10 --json

🤖 Every command accepts one automation flag: --json / --csv / --quiet. --schema prints the command tree without touching market data; doctor checks DB integrity.

Press g in the TUI to open 📊 Backtesting & Graphs — live equity curve beside a backtesting.py current-holdings backtest (return, CAGR, vol, Sharpe, Sortino, costs, maxDD). Universe is the selected account's open positions; 6m / 1y / 2y / 5y / 10y / max presets or exact days. CAGR uses real calendar elapsed time; options appear as skipped (no point-in-time chain history); futures use continuous series without roll costs. Curves are time-weighted, so deposits/withdrawals don't masquerade as alpha. The result has intentional look-ahead/survivorship bias — it's a "what if we held today's book" retrospective, not an OOS strategy test. Yahoo adjusted closes are used; crypto top-of-book is indicative.

🕸️ Web UI (unsupported)

static/ excluded from the wheel; web_ui.py retained but unsupported — use the TUI, CLI --json, or MCP server instead.

🔌 MCP server (for Claude Code / Cursor / Hermes)

Preferred surface for AI agents — typed, idempotent, single DB contract.

python3 mcp_server.py                              # core — 60 tools (default, safe)
PAPERTRADE_MCP_PROFILE=advanced python3 mcp_server.py  # 72 tools — adds destructive/specialist ops
PAPERTRADE_MCP_PROFILE=full python3 mcp_server.py      # 79 tools — adds legacy aliases (buy/sell/quote/…)
PAPERTRADE_MCP_RESPONSE_FORMAT=json python3 mcp_server.py  # force JSON contract
# or via entry point after pip install -e .
tradingcli-mcp

core responses use {"ok": true, "data": …} / {"ok": false, "error": {"code": "…", "message": "…"}}. mcp_catalog reports the active profile + tool list. Mutating tools take idempotency_key + agent for safe retries.

Client config 🔧 — copy .mcp.json to your client's MCP config and fix the path:

{
  "mcpServers": {
    "papertrade": {
      "command": "python3",
      "args": ["/absolute/path/to/Trading-CLI/mcp_server.py"],
      "env": { "PAPERTRADE_MCP_PROFILE": "core" }
    }
  }
}

For agents importing as a library instead of MCP, see docs/agent-guide.md.

✅ Verify

Tests are standalone scripts (no pytest needed):

python3 test_papertrade.py
python3 test_backtesting.py
python3 test_performance.py
python3 test_concurrency.py
python3 test_mcp_server.py
python3 test_mcp_profiles.py
python3 test_dashboard.py
python3 test_alpaca_parity.py
python3 test_cli.py
python3 test_edge_cases.py
python3 test_market_data.py
python3 test_mcp_features.py
python3 test_invariants.py
python3 test_tui_parity.py
python3 test_quote_cache.py
bun test ./tui/tests/
tradingcli config list
tradingcli config set myapp.threshold 42
tradingcli events --since-id 0 --limit 20 --json
tradingcli export -a mybook --format parquet --output mybook.parquet
tradingcli perf -a mybook --benchmark SPY --json

Yahoo Finance supplies market data. Historical quote/trade series and crypto top-of-book are explicitly marked aggregated/indicative — not exchange tick tapes or full depth.

Available Tools

60 tools
account_activityC

Unified account fills, orders, transfers, dividends, splits, and option events.

Inputs: account (required), end, limit, start, +1 more. Returns: result

account_createC

Create an account. Reuse idempotency_key safely when retrying the same mutation.

Inputs: name (required), cash, agent, idempotency_key. Returns: result

account_detailsC

Account balances, configured risk limits, and open-position count.

Inputs: account (required). Returns: result

account_listA

List all paper accounts and their cash balances.

Inputs: no named parameters. Returns: result

audit_logA

Paginated mutation audit trail with agent and idempotency attribution.

Inputs: limit, offset, account. Returns: result

bulk_quotesA

Fetch up to 50 comma-separated live symbols concurrently.

Inputs: symbols (required). Returns: result

buy_optionA

Buy an option. expiry is YYYY-MM-DD, kind is 'C' or 'P', contracts x100 shares. Market order unless limit (premium) is given. Use option_chain to find valid expiries/strikes.

Inputs: kind (required), expiry (required), strike (required), account (required), +5 more. Returns: result

config_deleteC

Delete a config key.

Inputs: key (required), agent, idempotency_key. Returns: result

config_getC

Get a config value.

Inputs: key (required). Returns: result

config_listA

List all config keys.

Inputs: no named parameters. Returns: result

config_setC

Set a config value.

Inputs: key (required), value (required), agent, idempotency_key. Returns: result

database_backupA

Create a consistent online backup under ~/.papertrade_backups.

Inputs: no named parameters. Returns: result

depositB

Add cash to a paper account.

Inputs: amount (required), account (required), agent, idempotency_key. Returns: result

eventsA

Poll unified audit/order events since an id. For agents to replace polling with incremental sync.

Inputs: limit, account, since_id. Returns: result

futures_symbolsA

List supported futures symbols with their contract multiplier and initial margin.

Inputs: no named parameters. Returns: result

get_default_accountA

Return the account used when CLI/TUI calls omit an explicit account.

Inputs: no named parameters. Returns: result

healthcheckA

Check SQLite integrity, WAL mode, schema version, and core record counts.

Inputs: no named parameters. Returns: result

market_barsC

Historical OHLCV bars from Yahoo Finance.

Inputs: symbol (required), end, limit, start, +1 more. Returns: result

market_latest_quoteC

Latest bid, ask, and last indication.

Inputs: symbol (required). Returns: result

market_most_activesD

Current most-active equity screener.

Inputs: limit. Returns: result

market_moversC

Current day gainers and losers.

Inputs: limit. Returns: result

market_newsC

Recent symbol news headlines and links.

Inputs: symbol (required), limit. Returns: result

market_snapshotC

Combined latest quote, daily bar, previous close, and change.

Inputs: symbol (required). Returns: result

market_statusA

Holiday/early-close-aware NYSE status and next open/close time.

Inputs: no named parameters. Returns: result

mcp_catalogA

Describe the active catalog, response contract, profiles, and legacy aliases.

Inputs: no named parameters. Returns: result

option_chainA

List option expiries for an underlying, or near-the-money strikes for one expiry (YYYY-MM-DD).

Inputs: underlying (required), expiry. Returns: result

option_contractA

Parse and quote one OCC option contract.

Inputs: symbol (required). Returns: result

order_cancelB

Cancel one pending order by id; canonical counterpart to order_cancel_all.

Inputs: order_id (required), agent, idempotency_key. Returns: result

order_cancel_allA

Cancel every pending/held order, optionally restricted to one account.

Inputs: agent, account, idempotency_key. Returns: result

order_getA

Get one order by numeric id or by account plus client order id.

Inputs: account, order_id, client_order_id. Returns: result

order_replaceA

Replace selected fields on a pending order and return the new order id.

Inputs: order_id (required), qty, agent, trail, +5 more. Returns: result

ordersB

List paginated order history, including source agent and idempotency key.

Inputs: account (required), limit, offset. Returns: result

order_submitC

Submit market, limit, stop, stop-limit, trailing, bracket, OCO, or OTO orders.

Inputs: side (required), symbol (required), account (required), qty, +16 more. Returns: result

performanceB

Portfolio performance since inception: return, CAGR, Sharpe, Sortino, volatility, max drawdown. Reconstructs a daily equity curve from the trade/cashflow ledger and real historical prices.

Inputs: account (required). Returns: result

pnlA

Mark-to-market P&L report for an account: positions, unrealized P&L, cash, total equity.

Inputs: account (required). Returns: result

portfolio_backtestA

Backtest the account's current open positions and cash with backtesting.py.

The universe is read from this account's SQLite positions, options without reliable continuous history are reported as skipped, and results include the equity curve, return, CAGR, volatility, Sharpe, Sortino, and drawdown. The default window is five years; request up to 36500 calendar days. This is a current-holdings retrospective, not an out-of-sample strategy test.

Inputs: account (required), end, start, lookback_days, +1 more. Returns: result

position_closeB

Close all or part of one position by quantity or percentage.

Inputs: symbol (required), account (required), qty, agent, +2 more. Returns: result

position_close_allB

Liquidate every open position in an account at current market prices.

Inputs: account (required), agent, idempotency_key. Returns: result

position_getA

Get one live-marked position with market value and unrealized P&L.

Inputs: symbol (required), account (required). Returns: result

positionsA

List open positions (symbol, side, qty, avg cost, asset class) for an account.

Inputs: account (required). Returns: result

preview_orderA

Dry-run an order against cash, margin, short, naked-option, and leverage limits.

Inputs: qty (required), side (required), symbol (required), account (required), +1 more. Returns: result

quotes_streamA

Poll live quotes N times at an interval; returns list of snapshots for a simple stream without WebSocket.

Inputs: symbols (required), snapshots, interval_sec. Returns: result

rename_accountA

Rename a paper portfolio. Updates positions, orders, history, and the default pointer.

Inputs: new (required), old (required), agent, idempotency_key. Returns: result

risk_getA

Show the account's shorting, naked-option, leverage, and order-size limits.

Inputs: account (required). Returns: result

risk_setB

Change selected account risk limits; omitted fields retain their current values.

Inputs: account (required), agent, allow_short, clear_max_order, +4 more. Returns: result

sell_optionB

Sell/write an option (opens a short if not covering). Same params as buy_option.

Inputs: kind (required), expiry (required), strike (required), account (required), +5 more. Returns: result

set_default_accountA

Set the default portfolio used by the CLI and dashboard when no account is specified.

Inputs: name (required), agent, idempotency_key. Returns: result

summaryA

One-line-per-portfolio snapshot for all accounts: cash, equity, unrealized P&L, position count. Fast overview for deciding which account to act on.

Inputs: no named parameters. Returns: result

tickA

Check all pending limit orders against current prices and fill any that crossed.

Inputs: no named parameters. Returns: result

trading_calendarB

List NYSE sessions, including holidays and early closes.

Inputs: end, start. Returns: result

validate_symbolC

Validate a symbol and return its live price, class, multiplier, and margin.

Inputs: symbol (required). Returns: result

watchlist_addB

Add a symbol to a persistent watchlist.

Inputs: symbol (required), account (required), watchlist (required), agent, +1 more. Returns: result

watchlist_createB

Create a persistent named watchlist with comma-separated symbols.

Inputs: name (required), account (required), agent, symbols, +1 more. Returns: result

watchlist_deleteC

Delete a persistent watchlist.

Inputs: account (required), watchlist (required), agent, idempotency_key. Returns: result

watchlist_getC

Get one named watchlist or numeric watchlist id.

Inputs: account (required), watchlist (required). Returns: result

watchlist_listB

List an account's persistent watchlists.

Inputs: account (required). Returns: result

watchlist_quotesA

Return live quotes for every symbol saved in a watchlist.

Inputs: account (required), watchlist (required). Returns: result

watchlist_removeB

Remove a symbol from a persistent watchlist.

Inputs: symbol (required), account (required), watchlist (required), agent, +1 more. Returns: result

withdrawB

Remove cash from a paper account (fails if it would go negative).

Inputs: amount (required), account (required), agent, idempotency_key. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    C2.8/5.0

    Scored across 60 tools

    Disambiguation3/5

    Most tools are grouped by resource with specific descriptions, but there is overlap between order_submit and buy_option/sell_option for option trades, and events/audit_log/account_activity all present similar history/log data. Helpful descriptions mitigate the ambiguity, but selection is not always obvious.

    Naming Consistency3/5

    Naming is readable due to consistent resource prefixes like order_, watchlist_, market_, and config_, but the convention is mixed: order_submit is object_verb, validate_symbol is verb_object, and summary/positions/pnl/healthcheck are noun-only. The lack of a uniform pattern prevents a higher score.

    Tool Count1/5

    At 60 tools, this server far exceeds the 3-15 well-scoped range and crosses the 50+ extreme mismatch threshold. Even for a trading CLI, the tool surface is overwhelming; it should be consolidated or split into focused sub-servers to keep agent selection tractable.

    Completeness5/5

    The tool surface covers account management, order lifecycle, positions, watchlists, market data, options and futures, risk management, performance/backtest, audit/events, config, and backup/admin. Common trading workflows have no obvious dead ends, making this a very complete server for its domain.

    Maintenance

    ActivityNo data
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      Not graded
      quality
      B
      maintenance
      Full-lifecycle algorithmic trading MCP server. AI strategy generation from plain English, backtesting, live bot deployment to 10+ brokers, portfolio monitoring, and prediction markets. Stocks, options, crypto, futures. 32 tools. Free tier.
      -
    • A
      license
      A
      quality
      D
      maintenance
      MCP server for the tastytrade brokerage API, providing tools for account management, market data, and order execution.
      18
      MIT
    • F
      license
      B
      quality
      D
      maintenance
      MCP server for Interactive Brokers via IB Gateway, enabling read access to account data and trading capabilities for paper accounts.
      11
      -
    • A
      license
      B
      quality
      D
      maintenance
      A read-only-by-default MCP server for Interactive Brokers that exposes account, positions, PnL, market data, and trade history from a local TWS/IB Gateway session, with optional trading capabilities.
      15
      MIT