alpaca-trader-rs
An Alpaca Markets trading toolkit for Rust — ships as both an integratable library and a standalone TUI trading app.
- Library (
alpaca_trader_rscrate): typed async REST client, shared domain types, and WebSocket streaming primitives — embed it in your own Rust application. - App (
alpaca-traderbinary): a full interactive terminal dashboard built on the library, with live account data, positions, orders, watchlist management, and order entry.
Installing the App
From crates.io (recommended)
This compiles and installs the alpaca-trader binary to ~/.cargo/bin/. Requires Rust 1.88+.
Pre-compiled binaries
Download the latest binary for your platform from the Releases page.
From source
# binary at: target/release/alpaca-trader
Credential Setup
The app resolves credentials in priority order (highest wins):
| Priority | Method | When to use |
|---|---|---|
| 1 | ALPACA_API_KEY + ALPACA_API_SECRET env vars |
CI, Docker, systemd — single pair for both environments |
| 2 | LIVE_ALPACA_KEY/SECRET or PAPER_ALPACA_KEY/SECRET env vars |
Per-environment .env file on developer machines |
| 3 | OS-native keychain | Desktop users — keys are saved once and reused |
| 4 | Interactive TTY prompt (first run) | No credentials configured yet — app prompts and offers to save to keychain |
Option A — First run (interactive, recommended for desktop):
Just run the app. If no credentials are found, it prompts for your API key and secret, then offers to save them to the OS keychain (macOS Keychain, Windows Credential Store, or Linux keyutils).
Option B — .env file (recommended for development):
# Edit .env and fill in your API keys — see docs/credentials-setup.md
Option C — Environment variables (CI / containers):
See docs/credentials-setup.md for obtaining keys from the Alpaca dashboard.
Running
The header badge shows [PAPER] in cyan or [LIVE] in red at all times.
If you installed from source, use
./run.sh --paper/./run.shinstead ofalpaca-trader.
Managing Stored Credentials
Key Bindings
| Key | Action |
|---|---|
1 / 2 / 3 |
Switch panel (Account / Watchlist / Positions) — or switch Orders sub-tab when on Orders panel |
4 |
Switch to Orders panel |
Tab / Shift-Tab |
Cycle panels forward / backward |
j / k or ↑ / ↓ |
Navigate rows |
g / G |
Jump to first / last row |
Enter |
Open symbol detail |
o |
New order (pre-fills selected symbol) |
s |
SELL SHORT order (Positions panel) |
c |
Cancel selected order |
a |
Add symbol to watchlist |
d |
Remove symbol from watchlist |
/ |
Search / filter watchlist |
r |
Force refresh |
? |
Help overlay |
A |
About overlay |
Esc |
Close modal |
T |
Toggle colour theme |
q / Ctrl-C |
Quit |
Full interaction spec (including mouse): docs/ui-mockups.md
Library Usage
Add to your Cargo.toml:
[]
= "0.5"
= { = "1", = ["full"] }
Fetch account info
use AlpacaClient;
use AlpacaConfig;
async
Place an order
use ;
let order = client.submit_order.await?;
println!;
Manage watchlists
let summaries = client.list_watchlists.await?;
let wl = client.get_watchlist.await?;
for asset in &wl.assets
client.add_to_watchlist.await?;
client.remove_from_watchlist.await?;
Public Library API
| Module | Exposed items |
|---|---|
config |
AlpacaConfig, AlpacaEnv |
client |
AlpacaClient — get_account(), get_positions(), get_orders(), submit_order(), cancel_order(), get_clock(), list_watchlists(), get_watchlist(), add_to_watchlist(), remove_from_watchlist() |
types |
AccountInfo, Position, Order, OrderRequest, OrderSide, OrderType, TimeInForce, Quote, MarketClock, Watchlist, WatchlistSummary, Asset |
events |
Event — unified event enum consumed by the TUI app |
stream |
MarketStream, AccountStream — WebSocket live data |
Crate Structure
alpaca-trader-rs/
├── src/
│ ├── lib.rs # Library root — public API
│ ├── main.rs # Binary entry point — TUI app
│ ├── credentials.rs # Credential resolution: env vars → keychain → TTY prompt
│ ├── config.rs # AlpacaConfig: env resolution, paper/live selection
│ ├── client.rs # AlpacaClient: all REST methods
│ ├── types.rs # Shared domain types (serde-deserializable)
│ ├── events.rs # Event enum
│ ├── app.rs # App state — TEA Model
│ ├── update.rs # update(state, event) + key routing
│ ├── input/ # Per-panel keyboard input handlers
│ │ ├── mod.rs
│ │ ├── watchlist.rs
│ │ ├── positions.rs
│ │ ├── orders.rs
│ │ ├── modal.rs
│ │ └── search.rs
│ ├── handlers/
│ │ ├── input.rs # crossterm EventStream → Event
│ │ └── rest.rs # Periodic REST polling task
│ └── ui/
│ ├── mod.rs # render(frame, app) + popup_area()
│ ├── dashboard.rs # Header, tab bar, status bar
│ ├── account.rs # Account panel + sparkline
│ ├── watchlist.rs # Watchlist table + search
│ ├── positions.rs # Positions table + totals
│ ├── orders.rs # Orders table + sub-tabs
│ ├── modals.rs # Order entry, detail, help, about, confirm modals
│ └── theme.rs # Colours and styles
├── tests/
│ └── client_tests.rs # AlpacaClient integration tests (wiremock)
├── docs/ # Full documentation
├── .env.example # Credential template
├── run.sh # Run script (--paper / --live)
├── Cargo.toml
├── LICENSE-MIT
├── LICENSE-APACHE
└── README.md
Environment Variables
Credentials are loaded from the environment (or a .env file via dotenvy). Only the
variables for the active environment are used — the opposing set is ignored.
Unified pair (highest priority)
| Variable | Description |
|---|---|
ALPACA_API_KEY |
API key ID — used for whichever environment (--paper or live) is active |
ALPACA_API_SECRET |
API secret key — paired with ALPACA_API_KEY |
Per-environment variables
| Variable | Description |
|---|---|
PAPER_ALPACA_ENDPOINT |
https://paper-api.alpaca.markets/v2 — optional override |
PAPER_ALPACA_KEY |
Paper API key ID |
PAPER_ALPACA_SECRET |
Paper API secret key |
LIVE_ALPACA_ENDPOINT |
https://api.alpaca.markets — optional override |
LIVE_ALPACA_KEY |
Live API key ID |
LIVE_ALPACA_SECRET |
Live API secret key |
Features
| Feature | Status |
|---|---|
Typed async REST client (AlpacaClient) |
✅ |
| TUI — header, tabs, status bar, braille line charts | ✅ |
| Account panel with Day P&L, Open P&L, Account # | ✅ |
| Watchlist panel — Volume, Change%, live search | ✅ |
| Positions panel with totals footer | ✅ |
| Orders panel — Open / Filled / Cancelled sub-tabs | ✅ |
| Order Entry modal with Side, Type, TIF dropdowns (↑/↓) | ✅ |
| Symbol Detail modal — OHLCV, intraday chart, watchlist toggle | ✅ |
| Help and About overlays | ✅ |
Paper / Live switching (--paper / --live) |
✅ |
--dry-run mode — simulate orders without sending to Alpaca |
✅ |
| Persistent user preferences (TOML config file) | ✅ |
Runtime colour theme switching (T key) |
✅ |
SELL SHORT from Positions panel (s key) |
✅ |
| Header market-session state (PRE-MARKET / OPEN / AFTER-HOURS / CLOSED) | ✅ |
| Instant UI redraw on terminal resize | ✅ |
| WebSocket market data + account/trade streaming | ✅ |
| Live order submission and cancellation | ✅ |
| Watchlist add / remove (wired to REST) | ✅ |
| OS-native keychain credential storage | ✅ |
| Interactive first-run credential prompt | ✅ |
| Windows, macOS, and Linux support | ✅ |
| GitHub Actions CI, security audit, Codecov (Linux + Windows), release builds | ✅ |
| 449 tests (unit + integration) | ✅ |
Documentation
| Document | Description |
|---|---|
| docs/architecture.md | System design, library/app boundary, data flow, crate choices |
| docs/credentials-setup.md | Obtaining and configuring Alpaca API keys |
| docs/ui-mockups.md | ASCII mockups and full keyboard/mouse interaction spec |
| docs/api-research.md | REST endpoint shapes and live test results |
| docs/testing.md | Testing strategy: mock patterns, crate rationale, full test case inventory |
| docs/licensing.md | License overview and contribution terms |
Contributing
Contributions are welcome! Please see CONTRIBUTING.md for development guidelines and our CODE_OF_CONDUCT.md for community standards.
Licensing
Licensed under either of
- Apache License, Version 2.0 or http://www.apache.org/licenses/LICENSE-2.0
- MIT license or http://opensource.org/licenses/MIT
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.