view schwab_trader/README.md @ 244:b8aa08503378

[tools] Add sandboxed online LaTeX editor Co-authored-by: Copilot <[email protected]>
author MrJuneJune <me@mrjunejune.com>
date Mon, 03 Aug 2026 16:56:25 -0700
parents eb8b4230fdb9
children
line wrap: on
line source

# Schwab Trader

Small Bazel-built helper for the Schwab Trader API. This project is only plumbing: it helps authenticate, inspect accounts, build explicit user-specified stock orders, and submit them only when a live-trade confirmation flag is present.

It does not recommend trades, choose symbols, allocate portfolio risk, or automate a strategy.

## Can Schwab accounts be traded by API?

Yes. Schwab provides the Trader API through the Schwab Developer Portal. The flow is OAuth 2.0:

1. Create an app in the Schwab Developer Portal.
2. Get an app key and app secret.
3. Register a redirect URI.
4. Open the OAuth authorization URL and log in through Schwab.
5. Exchange the returned `code` for an access token and refresh token.
6. Use the access token against `https://api.schwabapi.com/trader/v1`.

Do not use username/password scraping or browser automation. The supported path is OAuth tokens.

Useful endpoints this project targets:

- `GET https://api.schwabapi.com/trader/v1/accounts/accountNumbers`
- `GET https://api.schwabapi.com/trader/v1/accounts`
- `GET https://api.schwabapi.com/trader/v1/accounts/{accountHash}`
- `POST https://api.schwabapi.com/trader/v1/accounts/{accountHash}/orders`

Schwab uses account hashes for trading API calls. Fetch them with `account-numbers` before placing any order.

## Build and test

From the repo root:

```bash
bazel build //schwab_trader:schwab_cli
bazel test //schwab_trader:schwab_client_test
bazel build //schwab_trader:schwab_dashboard
bazel test //schwab_trader:dashboard_test
```

## Configuration

Set these environment variables:

```bash
export SCHWAB_APP_KEY="your-schwab-app-key"
export SCHWAB_APP_SECRET="your-schwab-app-secret"
export SCHWAB_REDIRECT_URI="https://127.0.0.1"
export SCHWAB_TOKEN_FILE="$HOME/.config/zenbu/schwab_tokens.json"
```

`SCHWAB_TOKEN_FILE` is optional and defaults to `~/.config/zenbu/schwab_tokens.json`. Token files are written with `0600` permissions.

## OAuth bootstrap

Print the Schwab login URL:

```bash
bazel run //schwab_trader:schwab_cli -- auth-url
```

Open it, log in through Schwab, authorize the app, then copy the full callback URL or just its `code` parameter:

```bash
bazel run //schwab_trader:schwab_cli -- token --code 'https://127.0.0.1/?code=...'
```

Refresh later:

```bash
bazel run //schwab_trader:schwab_cli -- refresh
```

## Account discovery

```bash
bazel run //schwab_trader:schwab_cli -- account-numbers
bazel run //schwab_trader:schwab_cli -- accounts --positions
```

## Order dry run

Build a stock order payload without sending it:

```bash
bazel run //schwab_trader:schwab_cli -- build-equity-order \
  --action BUY \
  --symbol AAPL \
  --quantity 1 \
  --order-type MARKET
```

`place-equity-order` is also dry-run by default:

```bash
bazel run //schwab_trader:schwab_cli -- place-equity-order \
  --account-hash "$SCHWAB_ACCOUNT_HASH" \
  --action SELL \
  --symbol AAPL \
  --quantity 1 \
  --order-type LIMIT \
  --price 250.00
```

To actually submit an order, both safety flags are required:

```bash
bazel run //schwab_trader:schwab_cli -- place-equity-order \
  --account-hash "$SCHWAB_ACCOUNT_HASH" \
  --action BUY \
  --symbol AAPL \
  --quantity 1 \
  --order-type MARKET \
  --live \
  --confirm-live-trade
```

Use live trading only after checking the generated JSON, account hash, symbol, quantity, order type, and Schwab API permissions.

## Local sentiment dashboard

Run the local dashboard:

```bash
bazel run //schwab_trader:schwab_dashboard
```

Then open:

```text
http://127.0.0.1:8765
```

The dashboard is intentionally local-first and read/paper-trade oriented. It has no live-trade endpoint. It shows:

- Schwab environment/token status without exposing token values
- risk settings such as profit target, stop loss, confidence threshold, and max paper-trade dollars
- manually added social evidence from Reddit/X/news/etc.
- deterministic sentiment signals and confidence
- paper trades with simple risk rejection
- audit events

The dashboard stores state in:

```text
~/.local/share/zenbu/schwab_trader/dashboard.db
```

Override it when testing:

```bash
bazel run //schwab_trader:schwab_dashboard -- --db /tmp/schwab_dashboard.db
```

Social evidence can be added through the page or API:

```bash
curl -X POST http://127.0.0.1:8765/api/evidence \
  -H 'Content-Type: application/json' \
  -d '{"source":"reddit","symbol":"AAPL","text":"$AAPL bullish strong growth","engagement":42}'
```