Personal investment portfolio dashboard with AI agent capabilities
Powered by Interactive Brokers data · FastAPI · React · AI Agents
IBKR Dash is a self-hosted investment portfolio dashboard that pulls data from Interactive Brokers via the Flex Web Service, stores it in SQLite, and presents it through a modern web UI. It includes five AI agents powered by any OpenAI-compatible LLM, enhanced with deterministic investment analysis engines for reliable, auditable trade decisions.
Key highlights:
- 📊 Real-time portfolio dashboard — equity curves, position tables, performance calendars
- 🤖 5 AI agents — copilot, daily review, trade decisions, trade reviews, risk assessment
- 🧠 Deterministic analysis engines — technical signals, risk/reward, investment thesis, fundamental change detection
- 🛡️ Risk Gate — post-composer safety layer that blocks unsafe trade actions
- 🔒 HMAC session auth — cookie-based sessions with optional password protection
- 🌐 i18n support — English and Chinese (Simplified)
- 🐳 Docker ready — single
docker compose upto run everything - ⚙️ Admin UI — configure LLM, IBKR, scheduler, email, and auth from the browser
| Feature | Description |
|---|---|
| Dashboard | Portfolio overview with equity curve, asset distribution, P&L calendar |
| Positions | Real-time and historical position data with detail drill-down |
| Trades | Trade history with per-trade P&L and summary statistics |
| Cash Flows | Deposits, withdrawals, transfers with running balance |
| Dividends | Dividend history and summary by symbol |
| Charts | Equity curve, performance calendar, sector distribution |
| Agent | Endpoint | Description |
|---|---|---|
| Account Copilot | POST /api/copilot/chat |
Chat-based portfolio assistant with tool use |
| Daily Position Review | POST /api/daily-position-review/generate |
AI-generated daily portfolio analysis |
| Trade Decision | POST /api/trade-decision/analyze |
Entry/exit/hold analysis with 5 sub-analyses + risk gate |
| Trade Review | POST /api/trade-review/review |
Post-trade evaluation and lessons |
| Risk Assessment | POST /api/risk-assessment/assess |
Portfolio risk analysis and alerts |
These pure-Python engines run without LLM calls, providing reliable and auditable analysis:
| Engine | File | Description |
|---|---|---|
| Technical Signal | technical_signal_engine.py |
MA20/50/200, ATR14, volume ratio, relative strength, support/resistance, trend-break classification |
| Risk/Reward | risk_reward_engine.py |
Upside/downside estimation, R-multiple, action guidance, position sizing |
| Investment Thesis | investment_thesis.py |
Per-symbol playbooks with add/hold/sell rules, trigger evaluation |
| Fundamental Change | fundamental_change_engine.py |
Revenue/margin/cash-flow trend detection, guidance change, thesis-broken check |
| Risk Gate | trade_decision/risk_gate.py |
Post-composer safety: panic detection, trend-break gating, thesis gating, R-multiple gating |
| Feature | Description |
|---|---|
| Settings | Centralized config UI for all services |
| Scheduler | Cron-based IBKR data import with manual trigger |
| Prompt Management | Edit AI agent prompts without code changes |
| LLM Management | Switch providers, test connections |
| Agent Monitoring | View agent traces, runs, and errors |
| SMTP config for daily review delivery |
┌─────────────────────────────────────────────────────────────┐
│ Browser │
│ React 18 + TypeScript + Vite │
│ ECharts · React Router · i18next │
└────────────────────────┬────────────────────────────────────┘
│ /api/* (Nginx proxy)
▼
┌─────────────────────────────────────────────────────────────┐
│ Backend (FastAPI) │
│ uvicorn · Pydantic v2 · httpx · SQLite │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Copilot │ │ Daily │ │ Trade │ │ Risk │ │
│ │ Agent │ │ Review │ │ Decision │ │Assessment│ │
│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Deterministic Engines (no LLM) │ │
│ │ Tech Signals · Risk/Reward · Investment Thesis │ │
│ │ Fundamental Change · Risk Gate │ │
│ └──────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Structured Output Pipeline │ │
│ │ parse → validate → repair → fallback │ │
│ └──────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ ReAct Runtime │ │
│ │ plan → tool_call → observe → answer │ │
│ └──────────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────────┐ │
│ │ Worker Scheduler (background) │ │
│ │ APScheduler · IBKR Flex Web Service │ │
│ │ Fetch → Parse (CSV/XML) → Transform → Write │ │
│ └──────────────────────────────────────────────────┘ │
└────────────────────────┬────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ SQLite (WAL mode) │
│ data/ibkr_dash.db │
└─────────────────────────────────────────────────────────────┘
| Tool | Version | Install |
|---|---|---|
| Python | 3.11+ | python.org |
| Node.js | 18+ | nodejs.org |
| Git | 2.30+ | git-scm.com |
# 1. Clone
git clone https://github.com/xuranus/ibkr-dash.git
cd ibkr-dash
# 2. Backend
cd backend
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --reload --port 8000
# 3. Frontend (new terminal)
cd frontend
npm install && npm run dev
# 4. Worker (new terminal, optional)
cd worker
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txtdocker compose up -d --build
# → http://localhost:8080If port 8080 is in use: FRONTEND_PORT=8081 docker compose up -d.
The Docker setup runs 2 containers: backend (FastAPI + worker scheduler) and frontend (Nginx + React SPA).
All configuration is stored in data/config.json and managed via Admin Settings at http://localhost:5173/admin/settings. No .env files.
Full configuration reference (click to expand)
| Key | Default | Description |
|---|---|---|
ibkr.flex_token |
"" |
Flex Web Service token |
ibkr.flex_query_ids |
"1532356,1532359" |
Comma-separated query IDs |
ibkr.flex_base_url |
https://www.interactivebrokers.com/... |
Flex API URL |
ibkr.flex_poll_interval_seconds |
10 |
Poll interval |
ibkr.flex_max_poll_retries |
60 |
Max retries |
| Key | Default | Description |
|---|---|---|
llm.api_key |
"" |
OpenAI-compatible API key |
llm.base_url |
https://api.openai.com/v1 |
API endpoint |
llm.default_model |
gpt-4o |
Model name |
llm.temperature |
0.1 |
Sampling temperature |
llm.max_tokens |
8192 |
Max response tokens |
| Key | Default | Description |
|---|---|---|
scheduler.enabled |
true |
Enable cron scheduler |
scheduler.hour |
12 |
Hour to run |
scheduler.minute |
30 |
Minute to run |
scheduler.timezone |
Asia/Shanghai |
Timezone |
| Key | Default | Description |
|---|---|---|
auth.username |
admin |
Login username |
auth.password |
"" |
Password (empty = no auth) |
auth.cookie_secure |
false |
Require HTTPS for cookies |
| Key | Default | Description |
|---|---|---|
email.smtp_host |
"" |
SMTP server |
email.smtp_port |
587 |
SMTP port |
email.smtp_username |
"" |
SMTP username |
email.smtp_password |
"" |
SMTP password |
email.from_address |
"" |
Sender address |
email.to_addresses |
[] |
Recipient addresses |
email.enabled |
false |
Enable email |
| Key | Default | Description |
|---|---|---|
advanced.app_env |
"development" |
Environment name |
advanced.debug |
false |
Debug mode |
advanced.sqlite_path |
"data/ibkr_dash.db" |
Database path |
advanced.log_level |
"INFO" |
Logging level |
advanced.cors_origins |
"http://localhost:5173" |
CORS origins |
advanced.data_dir |
"data/flex_exports" |
Flex export dir |
advanced.cache_ttl_seconds |
86400 |
Cache TTL (24h) |
See config.example.json for the full template.
# From a Flex CSV export
cd worker
python -m worker.main import ../data/flex_exports/your_file.csv
# Use sample data
python -m worker.main import worker/fixtures/daily_sample.csv
# Automatic pull (requires Flex token in Admin Settings)
python -m worker.main run-schedulercurl -X POST http://localhost:8000/api/copilot/chat \
-H "Content-Type: application/json" \
-d '{"message": "What is my current portfolio allocation?"}'# Daily position review
curl -X POST http://localhost:8000/api/daily-position-review/generate \
-H "Content-Type: application/json" \
-d '{"account_id": "U1234567"}'
# Trade decision
curl -X POST http://localhost:8000/api/trade-decision/analyze \
-H "Content-Type: application/json" \
-d '{"symbol": "AAPL", "action": "buy"}'
# Risk assessment
curl -X POST http://localhost:8000/api/risk-assessment/assess \
-H "Content-Type: application/json" \
-d '{"account_id": "U1234567"}'All endpoints are prefixed with /api. Full interactive docs at http://localhost:8000/docs.
| Method | Path | Description |
|---|---|---|
GET |
/api/account/overview |
Account overview |
GET |
/api/account/snapshots |
Account snapshots |
GET |
/api/positions |
Position list with pagination |
GET |
/api/positions/{symbol} |
Position detail |
GET |
/api/positions/{symbol}/realtime |
Real-time position data |
GET |
/api/trades |
Trade history |
GET |
/api/trades/summary |
Trade summary stats |
GET |
/api/cash-flows |
Cash flow list |
GET |
/api/cash-flows/summary |
Cash flow summary |
GET |
/api/dividends |
Dividend history |
GET |
/api/dividends/summary |
Dividend summary |
GET |
/api/charts/equity-curve |
Equity curve data |
GET |
/api/charts/performance-calendar |
Daily P&L calendar |
| Method | Path | Description |
|---|---|---|
POST |
/api/copilot/chat |
Chat with copilot |
GET |
/api/copilot/sessions |
List chat sessions |
POST |
/api/daily-position-review/generate |
Generate daily review |
GET |
/api/daily-position-review/latest |
Get latest review |
POST |
/api/trade-decision/analyze |
Analyze trade decision |
POST |
/api/trade-review/review |
Review a trade |
POST |
/api/risk-assessment/assess |
Assess portfolio risk |
GET |
/api/agent-tasks |
List agent tasks |
GET |
/api/agent-tasks/{id} |
Get task detail |
| Method | Path | Description |
|---|---|---|
POST |
/api/auth/login |
Log in |
POST |
/api/auth/logout |
Log out |
GET |
/api/auth/session |
Check session status |
| Method | Path | Description |
|---|---|---|
GET |
/api/admin/settings |
List all settings |
PUT |
/api/admin/settings |
Update settings |
POST |
/api/admin/settings/reset |
Reset to defaults |
GET |
/api/admin/system/status |
System status |
GET |
/api/admin/llm/health |
LLM connection health |
POST |
/api/admin/llm/test |
Test LLM connection |
GET |
/api/admin/ibkr/settings |
IBKR settings |
POST |
/api/admin/scheduler/trigger-import |
Trigger data import |
POST |
/api/admin/scheduler/trigger-ai-report |
Trigger AI report |
GET |
/api/admin/prompts |
List AI prompts |
POST |
/api/admin/prompts |
Create/update prompt |
GET |
/api/admin/agent-monitoring/overview |
Agent monitoring |
ibkr-dash/
├── backend/ # FastAPI server + AI agents
│ ├── app/
│ │ ├── agents/ # AI agent system (5 agents)
│ │ │ ├── account_copilot/
│ │ │ ├── daily_review/
│ │ │ ├── trade_decision/ # Includes risk_gate.py
│ │ │ ├── trade_review/
│ │ │ ├── risk_assessment/
│ │ │ ├── structured_output/
│ │ │ ├── eval_harness.py # Eval case/result dataclasses
│ │ │ ├── eval_judge.py # LLM-as-judge evaluation
│ │ │ └── eval_correctness_rubrics.py
│ │ ├── api/routes/ # 25 route modules
│ │ ├── services/ # Business logic
│ │ │ ├── technical_signal_engine.py
│ │ │ ├── risk_reward_engine.py
│ │ │ ├── investment_thesis.py
│ │ │ ├── fundamental_change_engine.py
│ │ │ ├── email_service.py
│ │ │ └── agent_replay_service.py
│ │ ├── schemas/ # Pydantic models
│ │ └── core/ # Config, DB, auth, cache
│ └── tests/ # 21 test files, 211 tests
├── frontend/ # React + TypeScript
│ ├── src/
│ │ ├── views/ # 19 page components
│ │ ├── components/ # 20 reusable components
│ │ ├── api/ # API clients
│ │ ├── hooks/ # React hooks
│ │ ├── i18n/ # EN + ZH-CN translations
│ │ ├── types/ # TypeScript types
│ │ └── utils/ # Utility functions
│ └── package.json
├── worker/ # Data ETL
│ ├── worker/
│ │ ├── parsers/ # IBKR Flex CSV/XML parsers
│ │ ├── clients/ # DB and API clients
│ │ ├── jobs/ # Scheduled jobs
│ │ └── core/ # Config, logger, scheduler
│ └── tests/ # 5 test files
├── data/ # Runtime data (gitignored)
│ ├── ibkr_dash.db # SQLite database
│ ├── config.json # App configuration
│ └── flex_exports/ # IBKR Flex CSV/XML files
├── docker/ # Dockerfiles + nginx.conf
├── docs/ # Docusaurus documentation
├── scripts/ # Utility scripts
├── config.example.json # Config template
├── docker-compose.yml # Docker orchestration
└── .dockerignore # Build context exclusions
# Backend (211 tests across 21 test files)
cd backend && python -m pytest tests/ -v
# Frontend (10 test files)
cd frontend && npx vitest run
# Worker
cd worker && python -m pytest tests/ -v| Layer | Technology | Purpose |
|---|---|---|
| Backend | FastAPI + Pydantic v2 | REST API with validation |
| Database | SQLite (WAL mode) | Zero-config embedded DB |
| HTTP Client | httpx | LLM API calls |
| Worker | APScheduler | Cron-like job scheduling |
| Frontend | React 18 + TypeScript | UI framework |
| Build Tool | Vite 5 | Dev server + bundler |
| Charts | ECharts 5.5 | Interactive visualizations |
| i18n | react-i18next | EN + ZH-CN |
| Auth | HMAC-SHA256 | Session tokens |
| AI | OpenAI-compatible API | Any LLM provider |
Can I use a non-OpenAI LLM provider?
Yes. Any OpenAI-compatible API works. Set llm.base_url and llm.api_key in Admin Settings. Supported providers include DeepSeek, Xiaomi MiMo, Ollama, LiteLLM, and more.
How do I disable authentication?
Leave auth.password empty in Admin Settings. The dashboard will be accessible without login.
Where is my data stored?
All data is stored locally in data/ibkr_dash.db (SQLite). Configuration is in data/config.json. Neither file is committed to version control.
How do I change the scheduler time?
Go to Admin Settings → Scheduler and update hour, minute, and timezone. Changes take effect immediately — no restart needed.
Can I run this without Docker?
Yes. Follow the Local Development instructions. Each module (backend, frontend, worker) runs independently.
How do I back up my data?
Copy data/ibkr_dash.db and data/config.json. For Docker:
docker compose exec backend cp /app/backend/data/ibkr_dash.db /tmp/backup.db
docker compose cp backend:/tmp/backup.db ./backup.dbFull documentation is available in the docs/ directory (powered by Docusaurus):