From f442f59d6e390291a8f2961bb984112f57adf0ca Mon Sep 17 00:00:00 2001 From: Ame Date: Wed, 25 Mar 2026 02:50:34 +0800 Subject: [PATCH 1/4] fix: service tests write snapshots to tmpdir instead of data/trading/ createSnapshotService now accepts optional baseDir parameter. Service tests pass tmpdir and clean up in afterEach, preventing acc1/acc2 residue in the project's data directory. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/domain/trading/snapshot/service.ts | 6 ++++-- src/domain/trading/snapshot/snapshot.spec.ts | 5 ++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/domain/trading/snapshot/service.ts b/src/domain/trading/snapshot/service.ts index 236a7f76..0510ecbf 100644 --- a/src/domain/trading/snapshot/service.ts +++ b/src/domain/trading/snapshot/service.ts @@ -26,14 +26,16 @@ export interface SnapshotService { export function createSnapshotService(deps: { accountManager: AccountManager eventLog?: EventLog + /** Override storage base directory (tests use tmpdir). */ + baseDir?: string }): SnapshotService { - const { accountManager, eventLog } = deps + const { accountManager, eventLog, baseDir } = deps const stores = new Map() function getStore(accountId: string): SnapshotStore { let s = stores.get(accountId) if (!s) { - s = createSnapshotStore(accountId) + s = createSnapshotStore(accountId, baseDir ? { baseDir } : undefined) stores.set(accountId, s) } return s diff --git a/src/domain/trading/snapshot/snapshot.spec.ts b/src/domain/trading/snapshot/snapshot.spec.ts index 909cfb59..2f9b9e50 100644 --- a/src/domain/trading/snapshot/snapshot.spec.ts +++ b/src/domain/trading/snapshot/snapshot.spec.ts @@ -341,21 +341,24 @@ describe('Snapshot Service', () => { let manager: AccountManager let eventLog: EventLog let service: SnapshotService + let serviceDir: string beforeEach(async () => { manager = new AccountManager() const logPath = tempPath('jsonl') eventLog = await createEventLog({ logPath }) + serviceDir = tempDir() const broker = new MockBroker({ id: 'acc1', label: 'Test' }) const uta = new UnifiedTradingAccount(broker) manager.add(uta) - service = createSnapshotService({ accountManager: manager, eventLog }) + service = createSnapshotService({ accountManager: manager, eventLog, baseDir: serviceDir }) }) afterEach(async () => { await eventLog._resetForTest() + await rm(serviceDir, { recursive: true, force: true }) }) // #20 From e5bf9a9c1f68e3cbc3bcbf38205a5ec8077dda54 Mon Sep 17 00:00:00 2001 From: Ame Date: Wed, 25 Mar 2026 11:06:04 +0800 Subject: [PATCH 2/4] docs: add IBKR broker README and annotate data source limitations New README covers TWS market data channels (updatePortfolio vs reqMktData vs streaming), US equity trading sessions including overnight (Blue Ocean ATS), socket error handling design, and known limitations around price staleness after 20:00 ET. IbkrBroker methods (getAccount, getPositions, getQuote) annotated with data source, refresh behavior, and overnight coverage gaps. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/domain/trading/brokers/ibkr/IbkrBroker.ts | 54 ++++++++--- src/domain/trading/brokers/ibkr/README.md | 94 +++++++++++++++++++ 2 files changed, 134 insertions(+), 14 deletions(-) create mode 100644 src/domain/trading/brokers/ibkr/README.md diff --git a/src/domain/trading/brokers/ibkr/IbkrBroker.ts b/src/domain/trading/brokers/ibkr/IbkrBroker.ts index d0c364eb..ed37f74f 100644 --- a/src/domain/trading/brokers/ibkr/IbkrBroker.ts +++ b/src/domain/trading/brokers/ibkr/IbkrBroker.ts @@ -244,24 +244,24 @@ export class IbkrBroker implements IBroker { // ==================== Queries ==================== + /** + * Get account summary. + * + * Data source: reqAccountUpdates → accountDownloadEnd callback. + * + * netLiquidation is reconstructed from cash + Σ(position.marketValue) + * because TWS's account-level NetLiquidation tag is cached server-side + * and refreshes less frequently than position-level data. + * + * Note: position marketPrice comes from updatePortfolio() callbacks, + * which TWS stops pushing after ~20:00 ET (see README.md "TWS Market + * Data Channels"). During overnight hours, the reconstructed netLiq + * will be stale even though Blue Ocean ATS prices may be moving. + */ async getAccount(): Promise { const download = await this.downloadAccount() - // TotalCashValue is stable (cash doesn't change with market moves). const totalCashValue = parseFloat(download.values.get('TotalCashValue') ?? '0') - - // Reconstruct netLiquidation and unrealizedPnL from position-level data. - // - // TWS's account-level tags (NetLiquidation, UnrealizedPnL) are cached - // server-side and may not refresh between market sessions. However, the - // updatePortfolio() callbacks that populate download.positions carry - // per-position marketPrice, marketValue, and unrealizedPnL that are - // more current. - // - // Formula: netLiq = cash + Σ(position.marketValue) - // - // When there are no positions, fall back to the TWS-reported value - // since cash-only accounts have accurate NetLiquidation. let totalMarketValue = 0 let positionUnrealizedPnL = 0 for (const pos of download.positions) { @@ -289,6 +289,21 @@ export class IbkrBroker implements IBroker { } } + /** + * Get current positions with market prices. + * + * Data source: reqAccountUpdates → updatePortfolio() callbacks. + * Each position's marketPrice/marketValue comes from TWS's internal + * portfolio valuation, NOT from a real-time market data subscription. + * + * TWS controls the push frequency. During regular hours (09:30-16:00 ET) + * updates come every few seconds. After ~20:00 ET, updatePortfolio() + * stops pushing entirely — prices freeze even though overnight trading + * (Blue Ocean ATS) may be active. See README.md for details. + * + * To get fresher prices, use getQuote() which calls reqMktData in + * snapshot mode and can see overnight session data. + */ async getPositions(): Promise { const download = await this.downloadAccount() return download.positions @@ -323,6 +338,17 @@ export class IbkrBroker implements IBroker { } } + /** + * Get a one-time market data snapshot for a contract. + * + * Data source: reqMktData with snapshot=true → tickPrice/tickSize/ + * tickSnapshotEnd callbacks. Unlike updatePortfolio(), this channel + * CAN return overnight session prices (Blue Ocean ATS) and is not + * limited to positions in the account. + * + * Each call briefly occupies one TWS market data line (limit ~100), + * auto-released after tickSnapshotEnd. + */ async getQuote(contract: Contract): Promise { if (!contract.exchange) contract.exchange = 'SMART' if (!contract.currency) contract.currency = 'USD' diff --git a/src/domain/trading/brokers/ibkr/README.md b/src/domain/trading/brokers/ibkr/README.md new file mode 100644 index 00000000..74c8b859 --- /dev/null +++ b/src/domain/trading/brokers/ibkr/README.md @@ -0,0 +1,94 @@ +# IbkrBroker — Interactive Brokers TWS/Gateway Adapter + +IBroker implementation for Interactive Brokers via `@traderalice/ibkr` (Node port of the official Python TWS API). + +## Architecture + +``` +IbkrBroker → EClient (TCP) → TWS/Gateway → IBKR Servers + ↑ +RequestBridge (callback → Promise adapter) +``` + +- **EClient**: TCP socket to TWS, multiplexes requests via numeric `reqId` +- **RequestBridge**: EWrapper implementation that converts callbacks into Promises +- **No API keys**: Authentication is handled by TWS/Gateway GUI login + +## TWS Market Data Channels + +TWS has multiple independent data channels with different characteristics. +Understanding which channel we use (and don't use) is critical for debugging price issues. + +### `reqAccountUpdates` → `updatePortfolio()` (what we use) + +- **Subscribe**: `reqAccountUpdates(true, accountId)` — one-time subscription +- **Callback**: `updatePortfolio(contract, position, marketPrice, marketValue, avgCost, unrealizedPnL, realizedPnL, accountName)` +- **Behavior**: TWS internally decides when to push updates. During regular trading hours, updates come every few seconds. During after-hours and overnight, updates slow down or stop entirely. +- **Coverage**: Only positions in the account. No quote data for contracts you don't hold. +- **Current usage**: `getPositions()` and `getAccount()` both rely on this channel via `downloadAccount()`. + +### `reqMktData` — snapshot mode (what `getQuote()` uses) + +- **Call**: `reqMktData(reqId, contract, '', true, false, [])` — `snapshot=true` +- **Callbacks**: `tickPrice()`, `tickSize()`, `tickString()`, then `tickSnapshotEnd()` +- **Behavior**: One-time batch of current market data. Auto-cancels after `tickSnapshotEnd`. +- **Coverage**: Any contract, including ones you don't hold. Includes overnight session data from Blue Ocean ATS. +- **Limitation**: Counts against TWS market data line limit (~100 concurrent). Snapshot mode is short-lived so typically not a problem. + +### `reqMktData` — streaming mode (not currently used) + +- **Call**: `reqMktData(reqId, contract, '', false, false, [])` — `snapshot=false` +- **Callbacks**: Continuous `tickPrice()`, `tickSize()` updates +- **Behavior**: Real-time tick-level updates. This is what TWS front-end uses for its price display. +- **Coverage**: Same as snapshot mode, but continuous. Includes overnight session data. +- **Limitation**: Each active subscription counts against the 100-line limit until explicitly cancelled via `cancelMktData()`. + +### `reqTickByTickData` (not currently used) + +- **Behavior**: Granular tick-by-tick data (Last, BidAsk, AllLast) +- **Use case**: Algo trading, tape reading +- **Not needed** for portfolio snapshots + +## US Equity Trading Sessions + +All times in US/Eastern (ET): + +| Session | Hours (ET) | Hours (UTC+8) | Venue | +|---------|-----------|---------------|-------| +| Pre-market | 04:00 - 09:30 | 16:00 - 21:30 | ECN (ARCA, BATS) | +| Regular | 09:30 - 16:00 | 21:30 - 04:00+1 | NYSE, NASDAQ | +| After-hours | 16:00 - 20:00 | 04:00 - 08:00 | ECN | +| Overnight | 20:00 - 04:00+1 | 08:00 - 16:00 | Blue Ocean ATS (dark pool) | + +**Key insight**: "Total Available Hours" shown in TWS (04:00 - 20:00 ET) does NOT include overnight trading. Overnight trading is a separate session via Blue Ocean ATS, available for select contracts (flagged as "Overnight Trading is available" in TWS). + +### Impact on data channels + +- **`updatePortfolio()`**: Stops refreshing around 20:00 ET. Does NOT push overnight session prices. This is why snapshot equity curves flatten after UTC+8 08:00. +- **`reqMktData` (snapshot/streaming)**: CAN return overnight session prices if the contract supports overnight trading. This is why TWS front-end still shows last price changes after 20:00 ET. +- **Conclusion**: If we need accurate overnight prices for snapshots, we must use `reqMktData` instead of relying on `updatePortfolio()` cached prices. + +## Socket Error Handling + +The `@traderalice/ibkr` Connection class is a Node port of Python's `Connection`. + +**Python behavior**: `recvMsg()` catches `socket.error` inline → calls `self.disconnect()` → reader thread exits naturally. No error propagation. + +**Our adaptation** (`packages/ibkr/src/connection.ts`): Socket `error` events call `this.disconnect()` directly (matching Python). The `disconnect()` method: +1. Sets `this.socket = null` first (prevents double cleanup) +2. Calls `socket.destroy()` +3. Calls `wrapper.connectionClosed()` + +The `close` event handler checks `if (this.socket === null) return` to avoid double-calling `connectionClosed()` when `disconnect()` already handled cleanup. + +Upper layers (UTA health system) detect the disconnect via `connectionClosed()` → health degrades → auto-recovery attempts reconnection. + +## Known Limitations + +1. **`getPositions()` price staleness**: Prices come from `updatePortfolio()` which TWS controls. During overnight hours, prices freeze even though the market has activity on Blue Ocean ATS. Future improvement: call `getQuote()` per position to refresh prices. + +2. **`getAccount()` netLiq reconstruction**: TWS's account-level `NetLiquidation` tag is cached server-side. We reconstruct it from `cash + Σ(position.marketValue)` for accuracy. But since position prices can be stale (see #1), the reconstructed netLiq inherits that staleness. + +3. **Single account**: Current implementation assumes one account per TWS connection. Multi-account setups (Financial Advisor accounts) would need `reqAccountUpdatesMulti` instead. + +4. **Market clock**: Hardcoded to NYSE regular hours (9:30-16:00 ET, Mon-Fri). Does not account for holidays, half-days, or per-contract trading schedules. Should use `ContractDetails.tradingHours` in the future. From ad8f603be11281e152cc9c72b4c1eb191e5e8a60 Mon Sep 17 00:00:00 2001 From: Ame Date: Wed, 25 Mar 2026 13:01:48 +0800 Subject: [PATCH 3/4] =?UTF-8?q?docs:=20update=20README=20for=20pre-v1=20?= =?UTF-8?q?=E2=80=94=20align=20structure,=20mark=20roadmap=20complete?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Project Structure: rewrite to match domain/ + tool/ refactor (remove stale extension/ and openbb/ paths) - Features: add account snapshots, dynamic broker config UI, account enable/disable - Architecture: rename Extensions → Domain, add Snapshots node - Key Concepts: Extension → Domain + Tool layering - Configuration: add snapshot.json - Roadmap: mark all four v1 milestones complete Co-Authored-By: Claude Opus 4.6 (1M context) --- README.md | 121 +++++++++++++++++++++++++++++------------------------- 1 file changed, 64 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index 48541a63..3f93fb8a 100644 --- a/README.md +++ b/README.md @@ -34,16 +34,17 @@ Your one-person Wall Street. Alice is an AI trading agent that gives you your ow - **Event log** — persistent append-only JSONL event log with real-time subscriptions and crash recovery - **Cron scheduling** — event-driven cron system with AI-powered job execution and automatic delivery to the last-interacted channel - **Evolution mode** — two-tier permission system. Normal mode sandboxes the AI to `data/brain/`; evolution mode gives full project access including Bash, enabling the agent to modify its own source code -- **Hot-reload** — enable/disable connectors (Telegram, MCP Ask) and reconnect trading engines at runtime without restart -- **Web UI** — local chat interface with real-time SSE streaming, sub-channels with per-channel AI config, portfolio dashboard, and full config management (trading, data sources, connectors, AI provider, heartbeat, tools) +- **Account snapshots** — periodic and event-driven account state capture with equity curve visualization. Configurable snapshot intervals and carry-forward for gaps +- **Hot-reload** — enable/disable trading accounts and connectors (Telegram, MCP Ask) at runtime without restart +- **Web UI** — local chat interface with real-time SSE streaming, sub-channels with per-channel AI config, portfolio dashboard with equity curve, and full config management. Dynamic broker config forms rendered from broker-declared schemas ## Key Concepts **Provider** — The AI backend that powers Alice. Claude (via `@anthropic-ai/claude-agent-sdk`, supports OAuth login or API key) or Vercel AI SDK (direct API calls to Anthropic, OpenAI, Google). Switchable at runtime via `ai-provider.json`. -**Extension** — A self-contained tool package registered in ToolCenter. Each extension owns its tools, state, and persistence. Examples: trading, brain, analysis-kit. +**Domain** — Business logic layer (`src/domain/`). Each domain module (trading, market-data, analysis, news, brain, thinking) owns its state and persistence. **Tool** (`src/tool/`) is a thin bridge layer that registers domain capabilities as AI tools in ToolCenter. -**UTA (Unified Trading Account)** — The core business entity for trading. Each UTA owns a broker connection (`IBroker`), a git-like operation history (`TradingGit`), and a guard pipeline. Think of it as a git repository for trades — multiple UTAs are like a monorepo with independent histories. AI and the frontend interact with UTAs exclusively; brokers are internal implementation details. All types (Contract, Order, Execution, OrderState) come from IBKR's type system via `@traderalice/ibkr`. `AccountManager` owns the full UTA lifecycle (create, reconnect, enable/disable, remove). +**UTA (Unified Trading Account)** — The core business entity for trading. Each UTA owns a broker connection (`IBroker`), a git-like operation history (`TradingGit`), a guard pipeline, and a snapshot scheduler. Think of it as a git repository for trades — multiple UTAs are like a monorepo with independent histories. AI and the frontend interact with UTAs exclusively; brokers are internal implementation details. All types (Contract, Order, Execution, OrderState) come from IBKR's type system via `@traderalice/ibkr`. `AccountManager` owns the full UTA lifecycle (create, reconnect, enable/disable, remove). **Trading-as-Git** — The workflow inside each UTA. Stage operations (`stagePlaceOrder`, `stageClosePosition`, etc.), commit with a message, then push to execute. Push runs guards, dispatches to the broker, snapshots account state, and records a commit with an 8-char hash. Full history is reviewable via `tradingLog` / `tradingShow`. @@ -77,13 +78,14 @@ graph LR CCR[ConnectorCenter] end - subgraph Extensions - OBB[OpenBB Data] - AK[Analysis Kit] + subgraph Domain + MD[Market Data] + AN[Analysis] subgraph UTA[Unified Trading Account] TR[Trading Git] GD[Guards] BK[Brokers] + SN[Snapshots] end NC[News Collector] BR[Brain] @@ -108,9 +110,9 @@ graph LR TC -->|Vercel tools| VS TC -->|in-process MCP| AS TC -->|MCP tools| MCP - OBB --> AK - OBB --> NC - AK --> TC + MD --> AN + MD --> NC + AN --> TC GD --> TR TR --> BK UTA --> TC @@ -129,9 +131,9 @@ graph LR **Providers** — interchangeable AI backends. Claude (Agent SDK) uses `@anthropic-ai/claude-agent-sdk` with tools delivered via in-process MCP — supports Claude Pro/Max OAuth login or API key. Vercel AI SDK runs a `ToolLoopAgent` in-process with direct API calls. `ProviderRouter` reads `ai-provider.json` on each call to select the active backend at runtime. -**Core** — `AgentCenter` is the top-level orchestration center that routes all calls (both stateless and session-aware) through `ProviderRouter`. `ToolCenter` is a centralized tool registry — extensions register tools there, and it exports them in Vercel AI SDK and MCP formats. `EventLog` provides persistent append-only event storage (JSONL) with real-time subscriptions and crash recovery. `ConnectorCenter` tracks which channel the user last spoke through. +**Core** — `AgentCenter` is the top-level orchestration center that routes all calls (both stateless and session-aware) through `ProviderRouter`. `ToolCenter` is a centralized tool registry — `tool/` files register domain capabilities there, and it exports them in Vercel AI SDK and MCP formats. `EventLog` provides persistent append-only event storage (JSONL) with real-time subscriptions and crash recovery. `ConnectorCenter` tracks which channel the user last spoke through. -**Extensions** — domain-specific tool sets registered in `ToolCenter`. Each extension owns its tools, state, and persistence. The trading extension centers on `UnifiedTradingAccount` (UTA) — each UTA bundles a broker connection, git-like operation history, and guard pipeline into a single entity. Guards enforce pre-execution safety checks (position size limits, trade cooldowns, symbol whitelist) inside each UTA before orders reach the broker. `NewsCollector` runs background RSS fetches into a persistent archive searchable by the agent. +**Domain** — business logic modules registered as AI tools via the `tool/` bridge layer. The trading domain centers on `UnifiedTradingAccount` (UTA) — each UTA bundles a broker connection, git-like operation history, guard pipeline, and snapshot scheduler into a single entity. Guards enforce pre-execution safety checks (position size limits, trade cooldowns, symbol whitelist) inside each UTA before orders reach the broker. Snapshots capture periodic account state for equity curve tracking. `NewsCollector` runs background RSS fetches into a persistent archive searchable by the agent. **Tasks** — scheduled background work. `CronEngine` manages jobs and fires `cron.fire` events into the EventLog on schedule; a listener picks them up, runs them through `AgentCenter`, and delivers replies via `ConnectorCenter`. `Heartbeat` is a periodic health-check that uses a structured response protocol (HEARTBEAT_OK / CHAT_NO / CHAT_YES). @@ -179,6 +181,7 @@ All config lives in `data/config/` as JSON files with Zod validation. Missing fi | `tools.json` | Tool enable/disable configuration | | `market-data.json` | Data backend (`typebb-sdk` / `openbb-api`), per-asset-class providers, provider API keys, embedded HTTP server config | | `news.json` | RSS feeds, fetch interval, retention period | +| `snapshot.json` | Account snapshot interval and retention | | `compaction.json` | Context window limits, auto-compaction thresholds | | `heartbeat.json` | Heartbeat enable/disable, interval, active hours | @@ -197,55 +200,60 @@ On first run, defaults are auto-copied to the user override path. Edit the user src/ main.ts # Composition root — wires everything together core/ - agent-center.ts # Top-level AI orchestration center, owns ProviderRouter - ai-provider.ts # AIProvider interface + ProviderRouter (runtime switching) + agent-center.ts # Top-level AI orchestration, owns ProviderRouter + ai-provider-manager.ts # GenerateRouter + StreamableResult + AskOptions tool-center.ts # Centralized tool registry (Vercel + MCP export) - ai-config.ts # Runtime provider config read/write - model-factory.ts # Model instance factory for Vercel AI SDK session.ts # JSONL session store + format converters compaction.ts # Auto-summarize long context windows - config.ts # Zod-validated config loader - event-log.ts # Persistent append-only event log (JSONL) + config.ts # Zod-validated config loader (generic account schema with brokerConfig) + ai-config.ts # Runtime AI provider selection + event-log.ts # Append-only JSONL event log connector-center.ts # ConnectorCenter — push delivery + last-interacted tracking async-channel.ts # AsyncChannel for streaming provider events to SSE - provider-utils.ts # Shared provider utilities (session conversion, tool bridging) - media.ts # MediaAttachment extraction from tool outputs + model-factory.ts # Model instance factory for Vercel AI SDK + media.ts # MediaAttachment extraction media-store.ts # Media file persistence types.ts # Plugin, EngineContext interfaces ai-providers/ vercel-ai-sdk/ # Vercel AI SDK ToolLoopAgent wrapper agent-sdk/ # Claude backend (@anthropic-ai/claude-agent-sdk, OAuth + API key) - extension/ - analysis-kit/ # Indicator calculator and market data tools - equity/ # Equity fundamentals and data adapter - market/ # Unified symbol search across equity, crypto, currency - news/ # RSS collector, archive search tools - trading/ # Unified Trading Account (UTA): brokers, git-like commits, guards, AI tool adapter - UnifiedTradingAccount.ts # UTA class — owns broker + git + guards - account-manager.ts # UTA lifecycle management (init, reconnect, enable/disable, remove) + registry - git-persistence.ts # Git state load/save (commit history to disk) - brokers/ # IBroker interface + implementations - registry.ts # Broker type registry (self-registration with config schema + UI fields) - factory.ts # AccountConfig → IBroker (delegates to registry) - alpaca/ # Alpaca broker (US equities) - ccxt/ # CCXT broker (100+ crypto exchanges) - ibkr/ # Interactive Brokers (TWS/Gateway, callback→Promise bridge) + domain/ + trading/ # Unified multi-account trading, guard pipeline, git-like commits + UnifiedTradingAccount.ts # UTA class — owns broker + git + guards + snapshots + account-manager.ts # UTA lifecycle (init, reconnect, enable/disable) + registry + git-persistence.ts # Git state load/save + brokers/ + registry.ts # Broker self-registration (configSchema + configFields + fromConfig) + alpaca/ # Alpaca (US equities) + ccxt/ # CCXT (100+ crypto exchanges) + ibkr/ # Interactive Brokers (TWS/Gateway) mock/ # In-memory test broker git/ # Trading-as-Git engine (stage → commit → push) guards/ # Pre-execution safety checks (position size, cooldown, whitelist) - thinking-kit/ # Reasoning and calculation tools + snapshot/ # Periodic + event-driven account state capture, equity curve + market-data/ # Structured data layer (typebb in-process + OpenBB API remote) + equity/ # Equity data + SymbolIndex (SEC/TMX local cache) + crypto/ # Crypto data layer + currency/ # Currency/forex data layer + commodity/ # Commodity data layer (EIA, spot prices) + economy/ # Macro economy data layer + client/ # Data backend clients (typebb SDK, openbb-api) + analysis/ # Indicators, technical analysis + news/ # RSS collector + archive search brain/ # Cognitive state (memory, emotion) - browser/ # Browser automation bridge (via OpenClaw) - openbb/ - sdk/ # In-process opentypebb SDK clients (equity, crypto, currency, news, economy, commodity) - api-server.ts # Embedded OpenBB-compatible HTTP server (optional, port 6901) - equity/ # Equity data layer + SymbolIndex (SEC/TMX local cache) - crypto/ # Crypto data layer - currency/ # Currency/forex data layer - commodity/ # Commodity data layer (EIA, spot prices) - economy/ # Macro economy data layer - news/ # News data layer - credential-map.ts # Maps config key names to OpenBB credential field names + thinking/ # Safe expression evaluator + tool/ # AI tool definitions — thin bridge from domain to ToolCenter + trading.ts # Trading tools (delegates to domain/trading) + equity.ts # Equity fundamental tools (uses domain/market-data) + market.ts # Symbol search tools (uses domain/market-data) + analysis.ts # Indicator calculation tools (uses domain/analysis) + news.ts # News archive tools (uses domain/news) + brain.ts # Cognition tools (uses domain/brain) + thinking.ts # Reasoning tools (uses domain/thinking) + browser.ts # Browser automation tools (wraps openclaw) + server/ + mcp.ts # MCP protocol server + opentypebb.ts # Embedded OpenBB-compatible HTTP API (optional) connectors/ web/ # Web UI chat (Hono, SSE streaming, sub-channels) telegram/ # Telegram bot (grammY, polling, commands) @@ -253,31 +261,30 @@ src/ task/ cron/ # Cron scheduling (engine, listener, AI tools) heartbeat/ # Periodic heartbeat with structured response protocol - plugins/ - mcp.ts # MCP server for tool exposure - skills/ # Agent skill definitions - openclaw/ # Browser automation subsystem (frozen) + openclaw/ # ⚠️ Frozen — DO NOT MODIFY data/ config/ # JSON configuration files - default/ # Factory defaults (persona, heartbeat prompts) sessions/ # JSONL conversation histories brain/ # Agent memory and emotion logs cache/ # API response caches - trading/ # Trading commit history (per-account) + trading/ # Trading commit history + snapshots (per-account) news-collector/ # Persistent news archive (JSONL) cron/ # Cron job definitions (jobs.json) event-log/ # Persistent event log (events.jsonl) + tool-calls/ # Tool invocation logs + media/ # Uploaded attachments +default/ # Factory defaults (persona, heartbeat prompts) docs/ # Architecture documentation ``` ## Roadmap to v1 -Open Alice is in pre-release. The following items must land before the first stable version: +Open Alice is in pre-release. All planned v1 milestones are now complete — remaining work is testing and stabilization. -- [ ] **Tool confirmation** — sensitive tools (order placement, cancellation, position close) require explicit user confirmation before execution, with a per-tool bypass mechanism for trusted workflows -- [ ] **Trading-as-Git stable interface** — the UTA class and git workflow are functional; remaining work is serialization format (FIX-like tag-value encoding for Operation persistence) and the `tradingSync` polling loop +- [x] **Tool confirmation** — achieved through Trading-as-Git's push approval mechanism. Order execution requires explicit user approval at the push step, similar to merging a PR +- [x] **Trading-as-Git stable interface** — the core workflow (stage → commit → push → approval) is stable and running in production - [x] **IBKR broker** — Interactive Brokers integration via TWS/Gateway. `IbkrBroker` bridges the callback-based `@traderalice/ibkr` SDK to the Promise-based `IBroker` interface via `RequestBridge`. Supports all IBroker methods including conId-based contract resolution -- [ ] **Account snapshot & analytics** — unified trading account snapshots with P&L breakdown, exposure analysis, and historical performance tracking +- [x] **Account snapshot & analytics** — periodic and event-driven snapshots with equity curve visualization, configurable intervals, and carry-forward for data gaps ## Star History From 1572df59ce99cf180feb09d75f8e826d7e7c7f16 Mon Sep 17 00:00:00 2001 From: Ame Date: Wed, 25 Mar 2026 13:02:53 +0800 Subject: [PATCH 4/4] chore: bump version to 0.9.0-beta.8 Co-Authored-By: Claude Opus 4.6 (1M context) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4eff78bf..20973548 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "open-alice", - "version": "0.9.0-beta.7", + "version": "0.9.0-beta.8", "description": "File-based trading agent engine", "type": "module", "scripts": {