Skip to content

NeelakandanNC/Zera

Repository files navigation

ZeraPortfolio Advisor

Post-market geopolitical + fundamental intelligence for your Zerodha portfolio.

ZeraPortfolio is an AI-powered portfolio analysis system that runs after Indian market close (3:30 PM IST) every trading day. It fetches your live Zerodha holdings, scrapes fundamentals from Screener.in, pulls geopolitical signals from World Monitor, and runs a swarm of Google Gemini-powered AI agents to produce a comprehensive daily portfolio report — delivered to your dashboard and WhatsApp.


Table of Contents


Features

  • Live Portfolio Sync — Fetches holdings from Zerodha Kite Connect with 1-hour cache
  • Fundamental Analysis — Scrapes P/E, ROE, ROCE, debt ratios, quarterly profits from Screener.in
  • Geopolitical Intelligence — Maps your portfolio sectors to global geopolitical signals
  • AI Agent Swarm — 4 specialist Gemini agents analyze your portfolio in parallel
  • Daily Reports — Auto-generated at market close with executive summary, per-stock briefings, and actionable recommendations
  • Bloomberg-style Dashboard — Dark terminal aesthetic with risk badges, heatmaps, and sparklines
  • PDF Reports — Server-side HTML-to-PDF generation via WeasyPrint
  • WhatsApp Delivery — PDF sent to your phone via Twilio after each report

Architecture

┌──────────────┐     ┌──────────────┐     ┌──────────────────┐
│   Zerodha    │     │ Screener.in  │     │  World Monitor   │
│  Kite API    │     │  (Scraper)   │     │   (Sidecar)      │
└──────┬───────┘     └──────┬───────┘     └────────┬─────────┘
       │                    │                      │
       └────────────────────┼──────────────────────┘
                            │
                   ┌────────▼────────┐
                   │   FastAPI       │
                   │   Backend       │
                   │   (Port 8000)   │
                   └────────┬────────┘
                            │
              ┌─────────────┼─────────────┐
              ▼             ▼             ▼
     ┌──────────────┐ ┌──────────┐ ┌───────────┐
     │   Gemini     │ │ Neon.db  │ │  Twilio   │
     │  AI Agents   │ │ Postgres │ │  WhatsApp │
     └──────────────┘ └──────────┘ └───────────┘
                            │
                   ┌────────▼────────┐
                   │  React Frontend │
                   │   (Port 5173)   │
                   └─────────────────┘

Agent Workflow

ZeraPortfolio uses a parallel fan-out + sequential synthesis pattern powered by Google ADK and Gemini:

                        ┌─────────────────────┐
                        │    Orchestrator      │
                        │  (asyncio.TaskGroup) │
                        └──────────┬──────────┘
                                   │
                    ┌──────────────┼──────────────┐
                    ▼              ▼              ▼
          ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
          │  Geopolitical│ │ Fundamental  │ │    Risk      │
          │    Agent     │ │    Agent     │ │    Agent     │
          │ (per stock)  │ │ (per stock)  │ │ (portfolio)  │
          │ gemini-flash │ │ gemini-flash │ │ gemini-flash │
          └──────┬───────┘ └──────┬───────┘ └──────┬───────┘
                 │                │                 │
                 └────────────────┼─────────────────┘
                                  │
                        ┌─────────▼──────────┐
                        │  Synthesis Agent   │
                        │   gemini-2.5-pro   │
                        └────────────────────┘
                                  │
                                  ▼
                          Final Report JSON

How it works step by step:

  1. Trigger — At 3:30 PM IST (or via manual POST /api/reports/trigger), the scheduler kicks off a report.

  2. Data Collection

    • Portfolio Agent fetches live holdings from Zerodha Kite Connect API
    • Screener Scraper fetches fundamentals (P/E, ROE, ROCE, debt, quarterly profits) for each stock with polite 2–5s delays
    • World Monitor Client fetches geopolitical signals, mapping each stock's NSE sector to global risk categories
  3. Parallel Analysis (all run concurrently via asyncio.TaskGroup)

    • Geopolitical Agent (1 per stock) — Assesses how current geopolitical events affect each holding. Uses gemini-2.0-flash for speed. Outputs risk level (HIGH/MEDIUM/LOW), time horizon, key regions, and recommended action.
    • Fundamental Agent (1 per stock) — Analyzes financial ratios and quarterly trends. Uses gemini-2.0-flash. Outputs fundamental strength, key risks/positives, valuation assessment, and analyst note.
    • Risk Agent (1 per portfolio) — Evaluates portfolio-level risks: sector concentration, single-stock overweight (>20%), correlation clusters, missing diversification. Outputs a risk score (1–10).
  4. Synthesis — The Synthesis Agent receives all outputs and produces a unified report using gemini-2.5-pro (deeper reasoning). It generates:

    • Executive Summary (3–5 sentences)
    • Portfolio Health Score (1–10)
    • Per-Holding Briefings with combined geo + fundamental view
    • Portfolio-Level Risk Assessment
    • Actionable Recommendations (max 5, prioritized)
    • Market Context paragraph
  5. Delivery

    • Report JSON stored in Neon.db
    • HTML rendered via Jinja2 (Bloomberg Terminal aesthetic)
    • PDF generated via WeasyPrint
    • PDF sent to WhatsApp via Twilio
    • Dashboard auto-refreshes to show the new report

Agent Error Handling

Each agent is wrapped in try/except. If one stock's analysis fails, the others continue. The synthesis agent handles missing inputs gracefully. One bad stock never crashes the whole pipeline.


Tech Stack

Layer Technology
LLM Google Gemini (gemini-2.0-flash for speed, gemini-2.5-pro for synthesis) via Google AI Studio
Agent Framework Google ADK (google-adk)
Backend FastAPI + Uvicorn
Database Neon.db (PostgreSQL via asyncpg + sqlalchemy[asyncio])
Frontend React 18 + Vite + TailwindCSS + Recharts
PDF WeasyPrint (HTML → PDF)
Messaging Twilio WhatsApp API
Scheduling APScheduler (cron-style)
Broker Zerodha Kite Connect API
Scraping httpx + BeautifulSoup4

Project Structure

portfolio_advisor/
├── README.md
├── CLAUDE.md                          # AI assistant instructions
├── LICENSE
├── docker-compose.yml
├── gstack.yaml
├── .gitignore
│
├── backend/
│   ├── .env.example                   # Environment variables template
│   ├── Dockerfile
│   ├── requirements.txt
│   ├── main.py                        # FastAPI app entry + lifespan
│   ├── config.py                      # Pydantic settings
│   ├── scheduler.py                   # APScheduler cron job
│   │
│   ├── db/
│   │   ├── base.py                    # SQLAlchemy async engine
│   │   ├── models.py                  # ORM models (reports, portfolio_cache, zerodha_tokens)
│   │   └── migrations/               # Alembic migrations
│   │
│   ├── integrations/
│   │   ├── zerodha_mcp.py            # Zerodha Kite Connect client
│   │   ├── screener.py               # Screener.in scraper
│   │   └── world_monitor.py          # World Monitor sidecar client
│   │
│   ├── agents/
│   │   ├── schemas.py                # All Pydantic output schemas
│   │   ├── gemini_client.py          # Shared Gemini structured output
│   │   ├── orchestrator.py           # Swarm orchestrator (fan-out + synthesis)
│   │   ├── portfolio_agent.py        # Portfolio data fetcher
│   │   ├── geopolitical_agent.py     # Geo risk analyst (per stock)
│   │   ├── fundamental_agent.py      # Fundamental analyst (per stock)
│   │   ├── risk_agent.py             # Portfolio risk manager
│   │   └── synthesis_agent.py        # Report assembler (gemini-2.5-pro)
│   │
│   ├── report/
│   │   ├── generator.py              # HTML → PDF via WeasyPrint
│   │   └── templates/
│   │       └── report.html           # Bloomberg-style Jinja2 template
│   │
│   ├── delivery/
│   │   └── twilio_sender.py          # WhatsApp PDF sender
│   │
│   └── api/
│       ├── auth.py                    # Zerodha OAuth flow (automated token)
│       ├── health.py                  # GET /health
│       ├── portfolio.py               # GET /api/portfolio/live
│       └── reports.py                 # All /api/reports/* endpoints
│
├── world_monitor_sidecar/
│   ├── Dockerfile
│   └── server.py                      # FastAPI wrapper for worldmonitor
│
└── frontend/
    ├── Dockerfile
    ├── nginx.conf
    ├── package.json
    ├── tsconfig.json
    ├── vite.config.ts
    ├── tailwind.config.ts
    ├── index.html
    └── src/
        ├── main.tsx
        ├── App.tsx
        ├── index.css
        ├── store.ts                   # Zustand global state
        ├── api/
        │   └── client.ts             # Typed API client
        ├── pages/
        │   ├── Dashboard.tsx          # Main dashboard
        │   └── ReportDetail.tsx       # Full report view
        └── components/
            ├── PortfolioTable.tsx      # Holdings table with badges
            ├── ReportCard.tsx          # Latest report summary card
            ├── GeopoliticalHeatmap.tsx # World map risk visualization
            └── RiskGauge.tsx           # Health score gauge

Getting Started

Prerequisites

  • Python 3.12+
  • Node.js 18+
  • Homebrew (macOS) — for WeasyPrint system dependencies
  • PostgreSQL (or a Neon.db account for serverless Postgres)
  • Google AI Studio API key — free at aistudio.google.com
  • Zerodha Kite Connect API key and secret — from kite.trade
    • Set the redirect URL to http://127.0.0.1:8000/api/auth/zerodha/callback in your Kite Connect app
  • Twilio account (optional, for WhatsApp delivery) — from twilio.com

Installation

# Clone the repository
git clone https://github.com/yourusername/zeraportfolio-advisor.git
cd zeraportfolio-advisor

# System dependencies (macOS — required for PDF generation)
brew install pango

# Backend setup
python3 -m venv .venv
source .venv/bin/activate
pip install -r backend/requirements.txt

# Frontend setup
cd frontend
npm install
cd ..

Configuration

# Copy the example env file
cp backend/.env.example backend/.env

Edit backend/.env and fill in your credentials:

# Required
GOOGLE_API_KEY=your-google-ai-studio-key
DATABASE_URL=postgresql+asyncpg://user:pass@host/dbname
ZERODHA_API_KEY=your-kite-api-key
ZERODHA_API_SECRET=your-kite-secret
APP_SECRET_KEY=any-random-secret-string

# Optional (for WhatsApp delivery)
TWILIO_ACCOUNT_SID=your-twilio-sid
TWILIO_AUTH_TOKEN=your-twilio-token
TWILIO_WHATSAPP_FROM=whatsapp:+14155238886
TWILIO_WHATSAPP_TO=whatsapp:+91XXXXXXXXXX

Note: You do NOT need to set ZERODHA_ACCESS_TOKEN manually. The app has a built-in OAuth flow that handles token generation and storage automatically.

Running Locally

You need 3 terminal tabs:

Tab 1 — World Monitor Sidecar:

cd ~/path/to/portfolio_advisor
source .venv/bin/activate
cd world_monitor_sidecar
uvicorn server:app --port 8001

Tab 2 — Backend (FastAPI):

cd ~/path/to/portfolio_advisor
source .venv/bin/activate
cd backend
uvicorn main:app --reload --port 8000

Tab 3 — Frontend (Vite):

cd ~/path/to/portfolio_advisor/frontend
npm run dev

Step 4 — Connect Zerodha (once per day):

Open http://localhost:8000/api/auth/zerodha/login in your browser. Log in with your Zerodha credentials. The app automatically exchanges the request token for an access token and saves it to the database. You'll see a green "Zerodha Connected!" confirmation page.

The Zerodha token expires daily at ~6 AM IST. Visit the login link again each morning to re-authenticate.

Step 5 — Open Dashboard & Run Analysis:

Go to http://localhost:5173. Click the "Run Analysis" button in the top-right corner to generate your first report on demand. It will ask for your APP_SECRET_KEY (from .env) once and remember it. Reports also auto-generate daily at 3:30 PM IST via the scheduler.

The Vite dev server proxies all /api/* and /health requests to the backend at port 8000.

Running with Docker

# Make sure backend/.env is configured
docker compose up --build

This starts all 3 services:

  • Backend on port 8000
  • Frontend on port 5173
  • World Monitor sidecar on port 8001

API Reference

Method Endpoint Description
GET /health System health check (DB, Zerodha, World Monitor)
GET /api/auth/zerodha/login Redirects to Zerodha login (OAuth flow)
GET /api/auth/zerodha/callback OAuth callback — auto-exchanges token and saves to DB
GET /api/auth/zerodha/status Check if a valid Zerodha token exists
GET /api/portfolio/live Current holdings from Zerodha (1-hour cache)
GET /api/reports List reports (last 30 days)
GET /api/reports/latest Most recent completed report
GET /api/reports/{id} Full report by ID
GET /api/reports/{id}/pdf Download report PDF
POST /api/reports/trigger Manually trigger report generation (requires X-API-Key header)

Manual Trigger (CLI)

curl -X POST http://localhost:8000/api/reports/trigger \
  -H "X-API-Key: your-app-secret-key"

Or use the "Run Analysis" button on the dashboard — it does the same thing with a visual progress indicator.


WhatsApp Setup (Twilio)

  1. Go to Twilio Console → Messaging → Try it out → Send a WhatsApp message
  2. Join the sandbox by sending join <sandbox-word> to +1 415 523 8886 on WhatsApp
  3. Set TWILIO_WHATSAPP_TO in your .env to your WhatsApp number with country code (e.g., whatsapp:+919876543210)

The system will send the daily PDF report to your WhatsApp after each successful generation.


Troubleshooting

WeasyPrint / PDF generation fails

WeasyPrint requires system libraries (pango, glib, gobject). On macOS:

brew install pango

The dashboard and reports work without it — only PDF download will be unavailable until pango is installed.

Zerodha token expired

Visit http://localhost:8000/api/auth/zerodha/login to re-authenticate. Tokens expire daily at ~6 AM IST.

Neon.db connection error

Make sure your DATABASE_URL uses postgresql+asyncpg:// (not postgresql://) and ?ssl=require (not ?sslmode=require&channel_binding=require).


License

This project is licensed under the MIT License — see the LICENSE file for details.


Built by Neelakandan — post-market intelligence, every trading day.

About

ZeraPortfolio is a agent that run analysis of your zerodha portfolio at the end of the day and send the report to your whatsapp

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors