Skip to content

lxorb/idearum

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

82 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

idearum

A portfolio research and hypothesis-testing platform. Built in 24 h for the Colosseum Idearum hackathon.

What it does

  • Portfolio monitor — live prices, P/L, earnings, key stats. Yahoo-backed, with a Gemini-scored news feed for every position.
  • Profile interview — short scenario-based quiz that derives three personality scores (volatility tolerance, uncertainty comfort, trajectory taste) and turns them into constraint axes for the agent.
  • News pipeline — background worker polls Yahoo, scores articles per ticker through Gemini (sentiment + materiality + impact), persists to SQLite.
  • Hypothesis Lab — Math mode — free-text strategy ("Buy AAPL when PE < 27, sell at PE > 30") → Gemini parser → vectorised backtest with S&P 500 benchmark, indicators, fundamentals.
  • Hypothesis Lab — Complex mode — qualitative research ("Should I buy BYD?") via an evidence-graph fan-out: parses the prompt, runs 4 branches in parallel (current news, historical analogues + per-event backtests, technical signals, peer comparison), and synthesises a verdict + certainty + actionable recommendation. Optionally "watched" for daily re-evaluation as fresh news arrives.
  • AI portfolio scoring — Python FastAPI service that uses AWS Bedrock (Claude Sonnet 4.6) to interpret user constraints, derive scoring axes ("spider web"), and grade your portfolio against them with a recommendations + risk report.

Architecture

┌──────────────────────┐      ┌──────────────────────────────────────────┐
│ React 19 + Vite SPA  │──/api/*──►   Express (TypeScript)               │
│  - Recharts          │      │      - news poller + Gemini scorer        │
│  - Framer Motion     │      │      - backtest engine + price cache     │
│  - Tailwind v4       │      │      - complex hypothesis orchestrator    │
└─────────┬────────────┘      │      - watch worker (daily re-eval)      │
          │                   │      - better-sqlite3 (WAL)              │
          │                   └──────────────────────────────────────────┘
          │
          └──/analyze/*──►    Python FastAPI / uvicorn
                              - Bedrock (Claude Sonnet 4.6)
                              - yfinance + pandas

Two LLMs intentionally: Gemini 2.5 Flash via Vertex AI for the high-throughput news/backtest/complex stack (cheap, fast), Claude Sonnet 4.6 via AWS Bedrock for the qualitative portfolio scoring + recommendation flow.

Repository layout

backend/                  Express + TypeScript API + workers
  src/news/               Yahoo poller, Gemini scorer, SQLite
  src/backtest/           strategy parser + simulator + indicators
  src/complex/            evidence-graph hypothesis engine + watch worker
  src/portofolioAnalysis/ Python FastAPI service (Bedrock)
frontend/                 React 19 + Vite + Tailwind v4
deploy/                   EC2 bootstrap + systemd units + Caddy + push.sh

Run locally

Prerequisites

  • Node 20+
  • Python 3.11+
  • gcloud CLI signed in (gcloud auth application-default login) for Vertex AI access
  • AWS credentials with Bedrock model access to us.anthropic.claude-sonnet-4-6 (for the Python service)

1. Backend (Express + workers)

cd backend
npm install
cp deploy/.env.example .env      # or create one manually:
#   GEMINI_PROJECT=<your-gcp-project>
#   GEMINI_LOCATION=global
#   POLL_INTERVAL_MS=300000
npm run dev                       # http://localhost:3001

2. Frontend (Vite dev server)

cd frontend
npm install
npm run dev                       # http://localhost:5173

Vite's dev proxy forwards /api/* to :3001 and /analyze/* to :8000.

3. Python analysis service (optional, but needed for portfolio scoring)

cd backend/portofolioAnalysis
python3 -m venv .venv
.venv/bin/pip install -r requirements.txt
.venv/bin/python -m uvicorn api:app --host 127.0.0.1 --port 8000

AWS credentials come from your environment (AWS_PROFILE, ~/.aws/credentials, or env vars). Region must be us-west-2.

Deploy to AWS EC2

For a public demo URL backed by a single EC2 instance. End-to-end takes ~10 min.

1. Launch the box

AWS Console → EC2 → Launch instances:

  • AMI: Ubuntu Server 22.04 LTS (64-bit x86)
  • Instance type: t3.small (or t3.medium for headroom)
  • Storage: 20 GiB gp3
  • Key pair: pick or create one — save the .pem, chmod 400 it
  • Security group inbound:
    • 22 SSH from My IP
    • 80 HTTP from Anywhere-IPv4
    • 443 HTTPS from Anywhere-IPv4

Once running, note the Public IPv4 DNS (e.g. ec2-x-x-x-x.us-west-2.compute.amazonaws.com).

2. Bootstrap the instance

From your laptop:

scp -i ~/your-key.pem deploy/bootstrap.sh ubuntu@<host>:/tmp/
ssh -i ~/your-key.pem ubuntu@<host> "sudo bash /tmp/bootstrap.sh"

Installs Node 20, build tools (for the better-sqlite3 native compile), Caddy, and creates the idearum system user.

3. Push code

rsync -avz --exclude node_modules --exclude .git --exclude '*.db' --exclude '*.db-*' \
  -e "ssh -i ~/your-key.pem" \
  ./ ubuntu@<host>:/tmp/idearum/

ssh -i ~/your-key.pem ubuntu@<host> \
  "sudo mv /tmp/idearum /opt/idearum/app && sudo chown -R idearum:idearum /opt/idearum/app"

4. Credentials on the box

On the EC2 box, create the two .env files:

/opt/idearum/app/backend/.env (Node service):

GEMINI_PROJECT=<your-gcp-project>
GEMINI_LOCATION=global
GOOGLE_APPLICATION_CREDENTIALS=/opt/idearum/app/backend/adc.json
PORT=3001

Copy your local ADC file up:

scp -i ~/your-key.pem ~/.config/gcloud/application_default_credentials.json \
  ubuntu@<host>:/tmp/adc.json
ssh -i ~/your-key.pem ubuntu@<host> \
  "sudo mv /tmp/adc.json /opt/idearum/app/backend/adc.json && \
   sudo chown idearum:idearum /opt/idearum/app/backend/adc.json && \
   sudo chmod 600 /opt/idearum/app/backend/adc.json"

/opt/idearum/app/backend/portofolioAnalysis/.env (Python service):

AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...
AWS_SESSION_TOKEN=...
AWS_DEFAULT_REGION=us-west-2

(In a Workshop Studio setup, click "Get AWS CLI credentials" in the sidebar and paste those values — without the export prefix.)

5. Build + start

On the EC2 box:

# Backend (TS → dist + native better-sqlite3 build, ~2 min)
sudo -u idearum bash -c 'cd /opt/idearum/app/backend && npm ci && npm run build'

# Frontend (bake the /api base into the bundle)
sudo -u idearum bash -c 'cd /opt/idearum/app/frontend && npm ci && VITE_API_BASE=/api npm run build'

# Python venv + deps
sudo apt-get install -y python3 python3-venv python3-pip
sudo -u idearum python3 -m venv /opt/idearum/app/backend/portofolioAnalysis/.venv
sudo -u idearum /opt/idearum/app/backend/portofolioAnalysis/.venv/bin/pip install \
  -r /opt/idearum/app/backend/portofolioAnalysis/requirements.txt

# systemd units (one for Node, one for Python uvicorn)
sudo install -m 644 /opt/idearum/app/deploy/idearum.service     /etc/systemd/system/idearum.service
sudo install -m 644 /opt/idearum/app/deploy/idearum-py.service  /etc/systemd/system/idearum-py.service

# Caddy reverse-proxy (HTTP-only on :80; for auto-TLS pass a real domain)
sudo bash -c 'sed "s|{{DOMAIN}}|:80|g" /opt/idearum/app/deploy/Caddyfile > /etc/caddy/Caddyfile'

sudo systemctl daemon-reload
sudo systemctl enable --now idearum idearum-py
sudo systemctl restart caddy

6. Verify

curl http://localhost:3001/health           # Node API
curl http://localhost:8000/health           # Python API
curl http://localhost/api/health            # through Caddy
sudo journalctl -u idearum -u idearum-py -n 30 --no-pager

Open http://<public-DNS>/ in your browser.

7. Iterating

After bootstrap, push changes from your laptop with one command:

HOST=<public-DNS> KEY=~/your-key.pem bash deploy/push.sh           # all
HOST=<public-DNS> KEY=~/your-key.pem bash deploy/push.sh backend   # node only
HOST=<public-DNS> KEY=~/your-key.pem bash deploy/push.sh frontend  # SPA only
HOST=<public-DNS> KEY=~/your-key.pem bash deploy/push.sh python    # FastAPI only

The script rsyncs the relevant tree, runs npm ci / pip install only when lockfiles change, rebuilds, and restarts the right services. Typical round-trip 15–30 s.

Notes & gotchas

  • Yahoo Finance from cloud IPs: foreign-exchange tickers (*.SW, *.DE, *.CO, *.AS) are sometimes refused from US-region EC2 IPs. US tickers work fine. Mitigation: stop/start the instance for a fresh IP, or demo with US tickers.
  • Workshop AWS credentials expire (typically a few hours). Re-pull from the workshop sidebar and rewrite portofolioAnalysis/.env, then sudo systemctl restart idearum-py.
  • Bedrock model access for Claude Sonnet 4.6 may need a one-time use-case form submission in the Bedrock console (model catalog page).
  • SQLite lives at /opt/idearum/app/backend/news.db on the box. It persists across deploys; news, articles, hypothesis_runs, analysis_cache, portfolio_positions tables are auto-created via CREATE TABLE IF NOT EXISTS.

License

Hackathon project — no license, all rights reserved (for now).

About

24h hackathon project for colosseum idearum

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages