Skip to content

Add Alpaca broker support (paper-trading by default)#61

Merged
IamJasonBian merged 1 commit into
mainfrom
IamJasonBian/alpaca-broker-support
May 9, 2026
Merged

Add Alpaca broker support (paper-trading by default)#61
IamJasonBian merged 1 commit into
mainfrom
IamJasonBian/alpaca-broker-support

Conversation

@IamJasonBian

Copy link
Copy Markdown
Owner

Summary

  • Adds utils/alpaca_broker.AlpacaBroker for single-leg equity options orders via Alpaca, so the engine has a second broker path next to Robinhood / IBKR.
  • Defaults to paper trading (https://paper-api.alpaca.markets). The live Alpaca account is intentionally not funded yet, so live trading is gated behind ALPACA_PAPER=false (env) or AlpacaBroker(paper=False) and is not wired into the CLI flag set.
  • Mirrors the banner / dry-run / pre-trade-validation style of the new option methods on SafeCashBot. Single-leg only -- spreads can be added later.

What changed

  • utils/alpaca_broker.py -- AlpacaBroker with get_account, get_option_quote, place_option_buy_limit_order, place_option_sell_limit_order, get_open_option_positions. Builds OPRA symbols (e.g. XLY260918C00120000) so callers don't have to know the OCC encoding. Pre-trade validation: buying-power on buys, position-held on sells.
  • scripts/place_option_order_alpaca.py -- CLI wrapper that mirrors scripts/place_option_order.py. --live means "send to the paper endpoint" (i.e. actually call submit_order). A --real-money flag is left as a TODO until funded.
  • tests/test_alpaca_broker.py -- smoke tests with a mocked TradingClient asserting (a) dry_run=True never calls submit_order and (b) dry_run=False calls it exactly once with the right OPRA symbol, qty, and limit price. Stubs alpaca-py at import time so CI without the dep still collects.
  • requirements.txt -- pins alpaca-py>=0.30.0 (was an opt-in comment before).
  • .env.example -- documents ALPACA_API_KEY_ID / ALPACA_API_SECRET_KEY / ALPACA_PAPER under a new "Alpaca broker" block; legacy ALPACA_API_KEY / ALPACA_SECRET_KEY aliases preserved.

No changes to safe_cash_bot.py, rh_auth.py, or any IBKR code.

Test plan

  • pytest tests/test_alpaca_broker.py -- 4/4 pass locally
  • OPRA encoding verified: XLY 2026-09-18 $120 CALL -> XLY260918C00120000 and SPY 2026-12-19 $432.5 PUT -> SPY261219P00432500
  • Dry-run CLI smoke: python scripts/place_option_order_alpaca.py XLY 2026-09-18 120 call 1 4.50 buy prints the banner and exits without calling submit_order
  • Reviewer: with paper credentials in .env, run python scripts/place_option_order_alpaca.py XLY 2026-09-18 120 call 1 4.50 buy --live to confirm the order lands in the Alpaca paper dashboard
  • Reviewer: confirm safe_cash_bot.py and Robinhood paths are unchanged

Follow-ups (intentionally out of scope)

  • --real-money CLI flag once the live Alpaca account is funded
  • Multi-leg / spread support
  • Wire AlpacaBroker into the higher-level execution engine alongside the RH/IBKR paths

Adds an Alpaca adapter for single-leg equity options orders so the
engine has a second broker path next to Robinhood / IBKR. Defaults to
paper trading (https://paper-api.alpaca.markets) because the Alpaca
account is not yet funded -- live trading is gated behind an explicit
ALPACA_PAPER=false flip and is intentionally NOT wired into the CLI yet.

Surface mirrors the new option methods on SafeCashBot: same banner
format ('='*70 dividers), same dry_run gating, same [OK]/[ERR]/[WARN]
prefixes. Single-leg only -- spreads can be added later.

Changes:
- utils/alpaca_broker.py: AlpacaBroker class with get_account,
  get_option_quote, place_option_buy_limit_order,
  place_option_sell_limit_order, get_open_option_positions. Builds OPRA
  symbols (e.g. XLY260918C00120000) from (symbol, expiration, strike,
  type) so callers don't have to know the OCC encoding. Pre-trade
  validation: buying-power check on buys, position-held check on sells.
- scripts/place_option_order_alpaca.py: CLI wrapper mirroring
  scripts/place_option_order.py. --live means "send to the paper
  endpoint" (i.e. actually call submit_order). A --real-money flag is
  left as a TODO until the live account is funded.
- tests/test_alpaca_broker.py: smoke tests with mocked TradingClient
  asserting (a) dry_run=True never calls submit_order and (b)
  dry_run=False calls submit_order exactly once with the right OPRA
  symbol. Stubs alpaca-py at import time so CI without the dep still
  collects.
- requirements.txt: pin alpaca-py>=0.30.0 (was an opt-in comment).
- .env.example: document ALPACA_API_KEY_ID / ALPACA_API_SECRET_KEY /
  ALPACA_PAPER under a new "Alpaca broker" block; keep the legacy
  ALPACA_API_KEY / ALPACA_SECRET_KEY aliases for older fill-audit code.

Env vars are loaded with python-dotenv to match utils/rh_auth.py:21.
No changes to safe_cash_bot.py or any RH code.
@IamJasonBian IamJasonBian merged commit bafca96 into main May 9, 2026
3 of 6 checks passed
@IamJasonBian IamJasonBian deleted the IamJasonBian/alpaca-broker-support branch May 9, 2026 20:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant