Full-stack AI research tool for the AI Module of the 2026 UBS Finance Challenge.
Pair Trade
- LONG Siemens Energy (
ENR.DE) — focus on the Grid Technologies segment - SHORT Sieyuan Electric (
002028.SZ) — Chinese private-sector grid equipment maker
The tool runs a 5-step research pipeline (Tavily search → Anthropic Claude analysis) and produces a structured, exportable research brief that can be embedded directly into the mandatory AI Module slide section.
| Layer | Choice | Why |
|---|---|---|
| Search / news | Tavily | 1000 free searches/month, structured results with URL + timestamp |
| LLM | Anthropic Claude (default claude-sonnet-4-6) |
Reliable in EEA/Germany; provider is auto-detected from available API keys; swappable to OpenAI / Gemini via LLM_PROVIDER env var |
| Backend | Python serverless on Vercel | One function (/api/run), 60s max duration |
| Frontend | Single self-contained index.html |
No build step, no React |
| Hosting | Vercel Hobby Free Tier | $0 |
Total realistic cost for the entire competition: ~$5–10 (Anthropic API calls; ~$0.20–0.30 per pipeline run with Sonnet, $0.05 with Haiku). Tavily and Vercel are free.
Note on LLM provider: This project initially defaulted to Google Gemini Flash, but Gemini's free tier is not available in EEA / Germany without billing. The current default is Anthropic Claude, which works everywhere and is more reliable for the structured-JSON output the pipeline depends on.
git clone <your-repo-url>
cd ubs-ai-module
python3 -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env
# Edit .env and paste your TAVILY_API_KEY and ANTHROPIC_API_KEYGet the keys:
- Tavily (free, 1000 searches/month): https://tavily.com → Settings → API Keys
- Anthropic Claude (free $5 trial credits, ~$0.20–0.30 per run with Sonnet): https://console.anthropic.com/settings/keys
Before the live demo, run the pipeline once locally to produce data/last_snapshot.json. The deployed dashboard uses this as a fallback if the live API call fails (slow venue Wi-Fi, rate limit, etc.).
python fetch_locally.pyThis writes data/last_snapshot.json. Commit it; Vercel will serve it as a static fallback.
Quickest way to preview index.html locally is just to open it in a browser. The live /api/run won't work locally without a Vercel-style runner, but the snapshot fallback does.
For full local backend testing, use Vercel CLI:
npm i -g vercel
vercel dev- Push this repo to GitHub (see below).
- Go to https://vercel.com → "Add New" → "Project" → import your GitHub repo.
- Set environment variables in the Vercel project settings:
TAVILY_API_KEYGEMINI_API_KEY- (optional)
LLM_PROVIDER,LLM_MODELto override defaults.
- Deploy. Vercel auto-detects:
api/run.py→ serverless function at/api/runindex.htmlat root → served at/data/last_snapshot.json→ served at/data/last_snapshot.json
That's it. Your dashboard will be live at https://<project>.vercel.app.
ubs-ai-module/
├── api/
│ ├── run.py # Vercel serverless function: POST /api/run
│ └── _lib/
│ ├── data_sources.py # Tavily adapter
│ ├── llm_client.py # Provider-agnostic LLM (Anthropic default; auto-detect)
│ ├── prompts.py # All system prompts + Tavily query catalogue
│ └── research_engine.py # Pipeline orchestrator
├── data/
│ └── last_snapshot.json # Cached fallback (committed)
├── index.html # Single-file dashboard
├── fetch_locally.py # Local snapshot generator
├── vercel.json # Python runtime config (60s timeout)
├── requirements.txt
├── .env.example
├── .gitignore
└── README.md
1. Research Harvest Tavily search × 17 queries (8 per company + 1 comparison)
2. Sentiment Score Claude → structured JSON per company
3. Keyword Cluster Claude → keyword cloud + topic clusters + divergence
4. Thesis Synthesis Claude → one-line thesis + long/short paragraphs +
key differentiators + why-now + bear cases
5. Compile ResearchReport with all outputs + sources
Typical pipeline duration: 30–60 seconds end-to-end with Sonnet, 15–25 seconds with Haiku.
| Env var | Purpose | Default |
|---|---|---|
TAVILY_API_KEY |
Tavily search API (required) | — |
ANTHROPIC_API_KEY |
Anthropic Claude API (required unless overriding LLM_PROVIDER) |
— |
LLM_PROVIDER |
anthropic | openai | gemini |
auto-detected from available API keys (Anthropic preferred) |
LLM_MODEL |
Model alias for the chosen provider | claude-sonnet-4-6 |
OPENAI_API_KEY |
Only if LLM_PROVIDER=openai |
— |
GEMINI_API_KEY |
Only if LLM_PROVIDER=gemini (NOTE: not free in EEA / Germany) |
— |
In your Vercel project settings → Environment Variables, add:
| Name | Value |
|---|---|
TAVILY_API_KEY |
your Tavily key |
ANTHROPIC_API_KEY |
your Anthropic key |
LLM_MODEL (recommended) |
claude-haiku-4-5 — keeps the pipeline under the 60s function timeout |
LLM_PROVIDER is not required — auto-detected from the keys above.
| Method | Path | Purpose |
|---|---|---|
| GET | / |
Dashboard (index.html) |
| POST | /api/run |
Run the pipeline; returns full ResearchReport JSON |
| GET | /data/last_snapshot.json |
Static cached fallback |
The dashboard always tries POST /api/run first; on failure it falls back to the snapshot and shows a banner.
The competition's AI Module section requires teams to use AI to process information beyond manual research capacity, document methodology, and disclose limitations. This tool produces all three:
- Beyond manual capacity — 17 parallel Tavily queries plus four Gemini analyses across both companies in under 60 seconds.
- Methodology disclosure — every step is logged in the dashboard stepper and described in the Markdown export. Source URLs and timestamps are preserved per item.
- Limitation disclosure — the AI Module Slide Notes button copies the exact slide-ready paragraph: what the AI did, what it did not do, where its outputs are weakest.
The AI module orchestrates a Tavily search-API harvest (~17 queries spanning earnings, segment data, geography, AI/data-center demand, valuation, and policy exposure) and then uses Google Gemini for structured sentiment, keyword clustering, and pair-trade thesis synthesis. It does not access Bloomberg, FactSet, paid terminals, or confidential company information, and does not generate price targets or position-sizing. Sentiment reflects narrative tone in public sources, not market-implied positioning. The AI's role is to compress and structure public research; final pair-trade conviction rests on the team's own fundamental and valuation work.
-
python fetch_locally.py— generate freshdata/last_snapshot.json. - Commit and push.
- Vercel auto-deploys; visit your URL and click Run Analysis to confirm live mode works.
- Open the production URL in advance from the venue Wi-Fi (or use a phone hotspot as backup).
- If the venue Wi-Fi is bad, the snapshot fallback kicks in automatically — no panic.