feat: Tradier broker mirror — config-switch redundancy for Alpaca execution
tradier_broker/ mirrors every trading call the live loop makes on AlpacaPaperClient (account, clock, positions, orders, submit incl. bracket->OTOCO, cancel, replace, close) with identical signatures and Alpaca-shaped returns, so trading_execution / exit_manager / flatten / execution / sync run unchanged. Market data always delegates to Alpaca. - BROKER=tradier (+ TRADIER_* env) swaps execution client in run_live_paper; default path untouched - client_order_id -> tag preserves the lost-submit reconcile - TradierApiError subclasses AlpacaApiError so the executor's rejection-vs-transport fork works as-is - sandbox-verified: balances/clock/positions/orders, OTOCO preview (result:true), place -> tag lookup -> cancel round trip - 18 unit tests (translation + client paths); executor integration checked - docs/TRADIER-FALLBACK.md switch runbook Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
48d75816b6
commit
1cefb51c63
8 files changed
+960
-1
No files matched your search
@@ -0,0 +1,53 @@
|
||||
# Tradier broker fallback
|
||||
|
||||
Redundancy path if the Alpaca live account stays blocked. `tradier_broker/`
|
||||
mirrors every trading call the live loop makes on `AlpacaPaperClient` — same
|
||||
method names, signatures, and Alpaca-shaped return dicts — so
|
||||
`trading_execution`, `runtime/exit_manager`, `runtime/flatten`,
|
||||
`alpaca_paper.execution` and `alpaca_paper.sync` run unchanged.
|
||||
|
||||
## Switch (config only)
|
||||
|
||||
```
|
||||
BROKER=tradier
|
||||
TRADIER_ACCESS_TOKEN=... # sandbox or live token
|
||||
TRADIER_ACCOUNT_ID=... # e.g. VA71549758
|
||||
TRADIER_ENV=sandbox # 'live' for real money — explicit opt-in
|
||||
```
|
||||
|
||||
`BROKER` unset/`alpaca` = today's behavior, byte-for-byte. Alpaca keys stay
|
||||
required either way: **market data (bars, screeners, quotes, news) always
|
||||
stays on Alpaca** — the Tradier client only replaces order execution and
|
||||
account/position state, delegating all data calls to the Alpaca client.
|
||||
|
||||
## Verify before trusting
|
||||
|
||||
```
|
||||
python3 -m tradier_broker.smoke # balances/clock/positions/orders
|
||||
python3 -m tradier_broker.smoke --preview AAPL # broker-validates bracket form, never submits
|
||||
python3 -m tradier_broker.smoke --place-cancel AAPL # full submit -> tag lookup -> cancel
|
||||
```
|
||||
|
||||
Smoke refuses order exercises against the live base URL.
|
||||
|
||||
## Mapping notes
|
||||
|
||||
- Alpaca bracket -> Tradier OTOCO (entry + OCO take-profit limit / stop);
|
||||
oto -> OTO; standalone gtc stop sells map directly.
|
||||
- `client_order_id` -> Tradier `tag` (lost-submit reconcile works via tag lookup).
|
||||
- Tradier positions carry no mark; `get_positions` prices them off
|
||||
`/markets/quotes` (sandbox quotes are 15-min delayed — fine for redundancy
|
||||
checks, and live tokens get real-time).
|
||||
- `replace_order` maps to PUT (moves stop/limit without cancelling — OCO stays
|
||||
intact); Tradier cannot change qty on a working order (raises, cancel+resubmit).
|
||||
- `get_orders` is session-scoped at Tradier (today's orders) and status/symbol
|
||||
filters are client-side; the live loop only queries today + held symbols, so
|
||||
behavior matches.
|
||||
|
||||
## Before flipping live money to Tradier
|
||||
|
||||
1. Rotate the sandbox token (it transited chat) and mint a live token.
|
||||
2. Run a full paper week on sandbox with `BROKER=tradier` in the paper stack.
|
||||
3. Re-run the naked-stop drill from docs/LIVE-CUTOVER.md — leg-stripping
|
||||
semantics differ per broker; verify a filled OTOCO's stop leg survives an
|
||||
entry-order cancel attempt.
|
||||
Reference in new issue
Block a user