Skip to content

fix: CCXT contract resolution + provider resilience#40

Merged
luokerenx4 merged 34 commits intomasterfrom
dev
Mar 5, 2026
Merged

fix: CCXT contract resolution + provider resilience#40
luokerenx4 merged 34 commits intomasterfrom
dev

Conversation

@luokerenx4
Copy link
Contributor

Summary

  • Sequential loadMarkets with per-type retries — CCXT's fetchMarkets fires 6 concurrent requests via Promise.all; one failure kills the batch. Monkey-patched to load each market type sequentially with independent retries (8 attempts, exponential backoff). Skips option markets by default.
  • Alpaca init retrygetAccount() during init now retries 5 times with exponential backoff instead of failing immediately.
  • Enforce aliceId as required contract identifiergetQuote, getFundingRate, getOrderBook, placeOrder, closePosition now require aliceId instead of bare symbol. Fixes CCXT tools failing when symbol matches multiple markets (e.g. "BTC" → spot + swap). Also adds CCXT unified symbol lookup in contractToCcxt.
  • Split CcxtAccount and AlpacaAccount into smaller modules — Extract types, contract resolution helpers, and PnL computation into separate files for maintainability.

Test plan

  • npx tsc --noEmit — no type errors
  • npx vitest run src/extension/trading/ — 109 tests pass
  • Manual: verify searchContracts("BTC") returns aliceId, then getQuote({ aliceId }) works
  • Manual: verify Bybit loadMarkets succeeds through proxy

🤖 Generated with Claude Code

luokerenx4 and others added 30 commits March 4, 2026 12:15
…anager, TradingGit

Introduces the IBKR-style unified trading architecture (new files only, zero changes to existing code):

- Contract: 1:1 IBKR replica with conId→aliceId ("{provider}-{nativeId}")
- ITradingAccount: unified account interface replacing ICryptoTradingEngine/ISecuritiesTradingEngine
- AccountManager: multi-account registry with cross-account equity aggregation and contract search
- TradingGit: merged Wallet+SecWallet into a single Trading-as-Git implementation (~330 lines vs ~1230 combined)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Unified GuardContext uses Position[] + AccountInfo from the new trading
interfaces. MaxPositionSizeGuard handles both crypto (usd_size/size) and
securities (notional/qty) params. Guard pipeline takes ITradingAccount
instead of engine-specific types.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
… main.ts rewrite

PR4+PR5 combined: replace separate crypto-trading and securities-trading
extensions with the unified IBKR-style account model.

- Add AlpacaAccount and CcxtAccount (direct ITradingAccount implementations)
- Add unified operation-dispatcher (Operation → ITradingAccount bridge)
- Add unified tool factory (createTradingTools) with capability-gated tools
- Add TradingGit adapter (git-style commit/push/log tools)
- Add wallet-state-bridge (ITradingAccount → GitState)
- Add factory.ts (wireAccountTrading + config-to-account helpers)
- Rewrite main.ts to use AccountManager with per-account TradingGit
- Replace EngineContext engine-specific getters with accountManager
- Add unified /api/trading/ web routes, remove old /api/crypto + /api/securities
- Update UI API client with backward-compat wrappers
- Archive old extensions to trading-archived/ (not yet deleted)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add 99 tests across 7 files for unified trading architecture
  (TradingGit, AccountManager, OperationDispatcher, WalletStateBridge,
  Guards, Factory) with shared MockTradingAccount test helper
- Fix CCXT constructor crash: options:undefined overriding internal
  defaults — use conditional spread instead
- Merge Crypto and Securities frontend into unified Trading view:
  sidebar 2 NavGroups → 1, TradingPage absorbs SecuritiesPage,
  PortfolioPage uses dynamic per-account API, remove all legacy
  API wrappers, unify types (AccountInfo/Position/TradingAccount)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace per-account tool registration (which caused ToolCenter overwrites)
with a single set of tools that route dynamically via `source` parameter.
Drop the legacy `sec` prefix from all tool names.

- Query tools (getAccount, getPortfolio, etc.) default to all accounts
- Mutation tools (placeOrder, walletCommit, etc.) require explicit source
- New listAccounts tool for AI to discover available accounts
- Merge git/adapter.ts into adapter.ts (both need source routing)
- Simplify main.ts: one toolCenter.register() call for trading

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…tional

- walletLog/Show/Status/Commit/Push/Sync → tradingLog/Show/Status/Commit/Push/Sync
- tradingCommit/Push/Sync source now optional — omit to operate on all accounts
  (like git push without specifying a remote)
- Clean up remaining "wallet" references in tool descriptions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of routing to first available account, try all accounts and
return quotes from every account that supports the symbol.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Detect empty API keys at construction time and short-circuit auth-required
methods with a clear error instead of making doomed network calls.
Public endpoints (getQuote, getFundingRate, getOrderBook) still work.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move provider-specific tools (getFundingRate, getOrderBook, adjustLeverage)
from adapter.ts into CcxtAccount.createProviderTools(), registered dynamically
when CCXT comes online. Slim AccountCapabilities to just supportedSecTypes +
supportedOrderTypes, removing all boolean flags. Make getMarketClock required
on ITradingAccount (every broker implements it). Operation dispatcher uses
duck-typing for provider-specific actions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
adjustLeverage is not a meaningful standalone operation — leverage is
a margin setting, not a trade. placeOrder already handles leverage at
order time. Remove adjustLeverage tool, instance method, operation
dispatcher case, and leverage field from OrderRequest/Order interfaces.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Extract OrderType (7 types: +trailing_stop, trailing_stop_limit, moc)
  and TimeInForce (6 values: +opg, gtd) as standalone type aliases
- Add IBKR fields to OrderRequest/Order: trailingAmount, trailingPercent,
  goodTillDate, parentId, ocaGroup
- Add modifyOrder to ITradingAccount core interface (IBKR replace semantics)
- Implement modifyOrder in AlpacaAccount (replaceOrder), CcxtAccount (editOrder)
- Add trailing_stop support to AlpacaAccount (trail_price/trail_percent)
- Expand placeOrder/modifyOrder tool schemas in adapter with all new fields
- Add modifyOrder to OperationAction, dispatcher, and TradingGit formatting
- Delete MaxLeverageGuard (dead after adjustLeverage removal)
- Clean up all adjustLeverage references from git types, TradingGit, comments

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ails

Align contract search with IBKR's dual interface pattern:
- searchContracts(pattern) for fuzzy discovery (reqMatchingSymbols)
- getContractDetails(query) for exact specification lookup (reqContractDetails)

Both exposed as AI tools with source filtering for multi-account attribution.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…license to AGPL-3.0

- Delete trading-archived/ (superseded by unified trading/)
- Remove MaxLeverageGuard from barrel export (guard was deleted previously)
- Switch license from MIT to AGPL-3.0-only to prevent closed-source forks

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prevent agent from redundantly calling searchContracts after equitySearch
by clearly distinguishing broker-level contract search from market data
research tools. Add when-to-use / when-not-to-use guidance.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ketSearchForResearch

Single entry point for market data symbol discovery across all asset classes.
Results tagged with assetClass attribution. Equity sub-tool descriptions updated
to reference the new tool name.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ptions

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…e-search

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Includes:
- IBKR-aligned unified trading (multi-account, Contract model, searchContracts/getContractDetails)
- Unified marketSearchForResearch (merged equitySearch + cryptoSearch + currencySearch)
- Relicense MIT → AGPL-3.0-only
- Remove trading-archived/
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Platform defines the compatibility structure (exchange type, market mode,
sandbox) that can be shared by multiple accounts. Config splits into
platforms.json + accounts.json with auto-migration from legacy
crypto.json + securities.json.

- IPlatform interface + CcxtPlatform/AlpacaPlatform implementations
- platform-factory: createPlatformFromConfig, createAccountFromConfig
- loadTradingConfig() with legacy config migration (read-only)
- AccountManager: platformId field on entries and summaries
- main.ts: platform-driven N-account init loop, per-account git state
  paths (data/trading/{accountId}/commit.json) with legacy fallback

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Backend: add /api/trading/config endpoints for platform and account
CRUD with credential masking. Frontend: rewrite TradingPage from
nested cards to compact table + right-sliding panel layout for better
overview and reduced scrolling.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Remove standalone platform management (PlatformsBar, Add Platform,
Platform tab). Platform is now an internal detail auto-created/updated
when saving accounts and cleaned up on account deletion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Creation flow now uses a 3-step wizard dialog (platform type →
connection config → credentials). Editing uses a single-page
centered modal with all sections inline.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- AlpacaAccount: compute realized PnL from FILL activities using FIFO
  lot matching with 60s TTL cache (replaces hardcoded 0)
- AccountManager: use Promise.allSettled in getAggregatedEquity so one
  failing account doesn't take down the entire endpoint
- PortfolioPage: unified layout with hero metrics from /equity endpoint,
  compact account strip, cost-basis column, resilient data fetching

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
CCXT's fetchMarkets uses Promise.all to fire all market-type requests
concurrently (6 for bybit: spot, linear, inverse, option×3). A single
failure kills the entire batch. This is unreliable on unstable networks.

Changes:
- Monkey-patch fetchMarkets to load each type sequentially with
  independent retries (8 attempts, 500ms backoff)
- Skip option markets by default (reduces requests from 6 to 3)
- Failed types are skipped instead of blocking the entire init

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace state-based page switching with react-router-dom Routes
- Sidebar nav items now use Link + useLocation instead of button + onClick
- Each page has its own URL path (/portfolio, /trading, /settings, etc.)
- Browser refresh preserves current page, back/forward navigation works
- Unknown routes redirect to / (Chat)
- Also: throttle getAggregatedEquity warnings to once per 5 min per account

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
luokerenx4 and others added 4 commits March 5, 2026 22:00
Extract from the 761-line monolith:
- ccxt-types.ts: CcxtAccountConfig, CcxtMarket, retry constants
- ccxt-contracts.ts: contract resolution as pure functions
- ccxt-tools.ts: createCcxtProviderTools (was static method)

CcxtAccount.ts shrinks from 761 to 558 lines. All contract helpers
are now standalone functions parameterized by (markets, exchangeName),
making them independently testable.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract types, contract helpers, and PnL computation into separate files
following the same pattern used for CcxtAccount.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
getQuote, getFundingRate, getOrderBook, placeOrder, closePosition now
require aliceId instead of bare symbol. Fixes CCXT tools failing when
symbol matches multiple markets (e.g. BTC → spot + swap).

Also adds CCXT unified symbol lookup in contractToCcxt so
"BTC/USDT:USDT" resolves directly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@luokerenx4 luokerenx4 merged commit 56f653d into master Mar 5, 2026
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