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
@@ -246,6 +246,22 @@ def build_runtime(args: argparse.Namespace) -> dict:
|
||||
has_keys = alpaca_settings.is_configured
|
||||
client = AlpacaPaperClient(alpaca_settings) if has_keys else None
|
||||
|
||||
# Broker failover: BROKER=tradier swaps the EXECUTION client for the
|
||||
# Tradier mirror (same surface/shapes); market data stays on Alpaca via
|
||||
# delegation. Default (unset/alpaca) is untouched.
|
||||
if os.environ.get("BROKER", "alpaca").strip().lower() == "tradier":
|
||||
from tradier_broker.client import TradierClient
|
||||
from tradier_broker.settings import TradierSettings
|
||||
tradier_settings = TradierSettings.from_env()
|
||||
if tradier_settings.is_configured:
|
||||
client = TradierClient(tradier_settings, data_client=client)
|
||||
print(f"[boot] BROKER=tradier: executing via Tradier "
|
||||
f"({'SANDBOX' if tradier_settings.is_sandbox else 'LIVE'}), "
|
||||
f"data via Alpaca", flush=True)
|
||||
else:
|
||||
print("[boot] WARNING: BROKER=tradier but TRADIER_ACCESS_TOKEN/"
|
||||
"TRADIER_ACCOUNT_ID missing — staying on Alpaca", flush=True)
|
||||
|
||||
# Datastore is Postgres (DATABASE_URL); WATCHER_EVENT_DB_PATH is a legacy
|
||||
# fallback the connection layer ignores.
|
||||
event_db = os.environ.get("WATCHER_EVENT_DB_PATH", "momentum")
|
||||
|
||||
Reference in new issue
Block a user