Low-Level Design Document
Modules, Endpoints, Files, Data Structures and Algorithms
ICICI Direct • Interactive Brokers • Revolut
Figure 1. Component relationships referenced by the detailed design.
1. Runtime components and files
| Component / file | Location | Detailed responsibility |
|---|---|---|
| api_server.py | ~/breeze-app | Flask host; Breeze routes; registers Revolut and IBKR blueprints. |
| revolut_processor.py | ~/breeze-app | Reads account/P&L CSVs; reconstructs holdings and summaries. |
| revolut_upload.py | ~/breeze-app | Validates uploads, PIN, limits, backups and atomic snapshot publishing. |
| ibkr_agent_api.py | ~/breeze-app | Refresh job state machine, claim/progress/upload/fail endpoints. |
| ibkr_windows_agent.py | Windows IBKR-Test | Polls Oracle and executes the local exporter. |
| export_ibkr.py | Windows IBKR-Test | Connects to TWS socket and writes ibkr_snapshot.json. |
| refresh_revolut_prices.py | ~/breeze-app | Refreshes mapped Revolut prices and FX; preserves cache. |
| refresh_ibkr_prices.py | ~/breeze-app | Refreshes prices/FX, applies fallback and enriches IBKR snapshot. |
| ibkr_agent_control.js | /var/www/html | Overrides dashboard refresh button and polls job status. |
| revolut_live.js | /var/www/html | Combines Revolut snapshot and cached price JSON client-side. |
| *.html | /var/www/html | Static presentation pages. |
| .env | ~/breeze-app | Private secrets and operational settings. |
2. Flask endpoint specification
| Method / route | Authentication | Request | Response / action |
|---|---|---|---|
| GET /api/health | Site auth | None | Backend health JSON. |
| GET /api/funds, /holdings, /positions | Site auth + Breeze session | Query parameters as applicable | Breeze portfolio JSON. |
| POST /api/update-session | Site auth + admin PIN | session_token, pin | Updates BREEZE_SESSION_TOKEN in .env. |
| POST /api/revolut/upload | Site auth + admin PIN | multipart account_statement, optional pnl_statement, pin | Validated snapshot rebuild and success metadata. |
| GET /api/revolut/status | Site auth | None | Snapshot timestamp and holdings count. |
| POST /api/ibkr-refresh/request | Site auth + admin PIN | JSON pin | Queues a new UUID job unless one is active. |
| GET /api/ibkr-refresh/status | Site auth | None | Current job state. |
| POST /api/ibkr-agent/claim | Agent token | agentName | Atomically claims queued job. |
| POST /api/ibkr-agent/progress | Agent token | jobId, status, message | Updates job state. |
| POST /api/ibkr-agent/upload | Agent token | multipart jobId + snapshot | Validates/backups/publishes JSON. |
| POST /api/ibkr-agent/fail | Agent token | jobId, message | Marks matching job as error. |
3. IBKR refresh state machine
idle → queued → claimed → exporting → uploading → success ↘ error
| State | Entered by | Meaning |
|---|---|---|
| idle | Initial/reset | No current job. |
| queued | Dashboard request | Waiting for an online agent. |
| claimed | Agent | A named agent owns the job. |
| exporting | Agent | export_ibkr.py is calling local TWS. |
| uploading | Agent | Snapshot is being posted to Oracle. |
| success | Server | Validated snapshot published. |
| error | Agent/server | Failure reason retained for display. |
4. Data structures
4.1 IBKR snapshot position
{ account, symbol, secType, currency, exchange, conId, quantity, avgCost, marketPrice, marketValue, unrealizedPnL, realizedPnL, priceSource?, priceRefreshedAt? }
4.2 Revolut holding
{ ticker, quantity, currency, estimatedCostBasis, estimatedAverageCost, lastActivityDate, activity:{buys,sells,dividends,splits}, currentPrice?, marketValue?, unrealizedPnL? }
4.3 External price cache
{ generatedAt, prices:{ SYMBOL:{price,currency,provider,providerSymbol,refreshedAt,...}}, fx:{"USD/GBP":{rate,provider,refreshedAt}}, errors:[], refreshSummary:{} }
5. Revolut processing algorithm
- Validate required account columns.
- Sort transactions by date.
- Maintain FIFO lots per ticker.
- BUY adds quantity and cost; SELL reduces earliest lots proportionally.
- STOCK SPLIT rescales quantities without changing remaining total cost.
- Negative MERGER - STOCK removes quantity; MERGER - CASH is excluded from active holdings.
- Ignore internal Revolut entity migration transfers to avoid double counting.
- Aggregate realised P/L and income from the optional P&L file.
- Write temporary JSON, reload for validation, back up prior snapshot, then publish.
6. Price refresh algorithms
6.1 Revolut
- Load mapping, snapshot and previous cache.
- Use Twelve Data for mapped USD positions and USD/GBP, EUR/GBP.
- Use Alpha Vantage for mapped GBP/EUR listings with GBX divisor where configured.
- Preserve old values for failed requests.
- Publish validated cache; dashboard calculates market value and P/L.
6.2 IBKR
- Load positions and ibkr_symbols.json.
- Use external quote where supported.
- If no external price exists, copy the snapshot marketPrice as an IBKR snapshot fallback.
- Refresh required currency/GBP pairs.
- Calculate marketValue = quantity × price.
- Calculate costBasis = quantity × avgCost.
- Calculate unrealizedPnL = marketValue − costBasis.
- Convert totals to GBP and write externalPricing metadata.
- Back up and rewrite the snapshot so the existing IBKR page consumes the enriched values.
7. Nginx routing
location /api/ { proxy_pass http://127.0.0.1:3000/api/; ... } location ^~ /api/ibkr-agent/ { auth_basic off; proxy_pass http://127.0.0.1:3000/api/ibkr-agent/; ... }
The narrow agent route bypasses website Basic Authentication to permit machine polling, but every Flask agent operation still requires X-IBKR-Agent-Token.
8. Configuration settings
| Setting | Purpose | Exposure |
|---|---|---|
| BREEZE_APP_KEY / SECRET / SESSION_TOKEN | ICICI API authentication | Private .env |
| ADMIN_UPDATE_PIN | State-changing dashboard actions | Private .env; entered interactively |
| IBKR_AGENT_TOKEN | Machine authentication | Private .env + protected Windows config |
| TWELVE_DATA_API_KEY | US/FX/crypto quotes | Private .env |
| ALPHA_VANTAGE_API_KEY | Mapped UK/EU quotes | Private .env |
| Polling and delay values | Pacing and timeout behaviour | Private config/.env |
9. Logging and recovery
- Cron stdout/stderr is redirected to per-job log files.
- PM2 logs capture Flask startup and endpoint errors.
- Snapshot backups are stored under protected app directories.
- Upload archives and backups are outside the public web root.
- Job state is persisted in ibkr_refresh_state.json.
10. Error-handling requirements
| Error | Handling |
|---|---|
| Invalid admin PIN | 403; no state change. |
| Invalid agent token | 403; no claim/upload. |
| Wrong job ID | 409; prevent stale agent from publishing. |
| Invalid CSV/JSON | 400; retain old snapshot. |
| Provider limit/error | Record error and retain cached/fallback value. |
| TWS timeout | Agent marks job error; retain old snapshot. |
| Permission/publish failure | Do not replace working file; fix ownership and retry safely. |
References
- Interactive Brokers API home: https://www.interactivebrokers.com/campus/ibkr-api-page/ibkr-api-home/
- Interactive Brokers TWS API introduction: https://interactivebrokers.github.io/tws-api/introduction.html
- Interactive Brokers TWS API connectivity: https://interactivebrokers.github.io/tws-api/connection.html
- Twelve Data pricing: https://twelvedata.com/pricing
- Alpha Vantage support and limits: https://www.alphavantage.co/support/
- Alpha Vantage API documentation: https://www.alphavantage.co/documentation/
- Ubuntu CronHowto: https://help.ubuntu.com/community/CronHowto