Autonomous AI-powered investment intelligence for the Pakistan Stock Exchange
Built for the AISeekho 2026 — Google Antigravity Hackathon · Challenge 1: Autonomous Content-to-Action Agent
PSX Portfolio Agent is a fully autonomous, end-to-end agentic system that scrapes live market data from the Pakistan Stock Exchange, reads financial news from Pakistan's top sources, extracts and cross-validates investment signals, resolves contradictions using weighted arbitration, and produces a fully justified, risk-adjusted portfolio — all in a single API call.
The agent does not rely on static rules. Every portfolio is reasoned from scratch by Gemini, grounded in real-time data scraped minutes before.
┌─────────────────────────────────────────────────────────────────┐
│ React Frontend │
│ Vite · Tailwind CSS · Framer Motion · Axios │
└──────────────────────────┬──────────────────────────────────────┘
│ REST /api/v1
┌──────────────────────────▼──────────────────────────────────────┐
│ FastAPI REST API │
│ /health · /portfolio/run · /market/snapshot · /news │
└──────────────────────────┬──────────────────────────────────────┘
│
ActionChain (5 Steps)
│
┌─────────────────┼──────────────────────┐
▼ ▼ ▼
PSXScraper NewsScraper SignalExtractor
KSE-100 Index Dawn Business + ContradictionDetector
Equities Board ARY Business
(Playwright) Geo Business
│ │ │
└─────────────────┴───────────────────────┘
│
GeminiAgent
(gemini-3-flash-preview)
│
PortfolioBuilder
PKR amounts · Shares
Stop-loss · Sharpe
│
Portfolio (JSON)
| Step | Action | Description |
|---|---|---|
| 1 | Scrape Market Data | Fetches KSE-100 index, all-share prices, and volumes from PSX using Playwright for JS-rendered pages |
| 2 | Scrape News | Concurrently scrapes Dawn Business, ARY Business, and Geo Business; extracts ticker mentions via regex |
| 3 | Extract Signals | Price momentum × volume surge → market signals; keyword sentiment scoring → news signals |
| 4 | Resolve Conflicts | Detects bullish_vs_bearish, source_disagreement, confidence_spread; resolves via weighted arbitration |
| 5 | Construct Portfolio | Gemini reasons over signals + conflicts → structured JSON → typed Portfolio with PKR allocation, share counts, stop-losses, and Sharpe ratio |
- Python 3.12+
- Node.js 18+
- A Google Gemini API key
git clone https://github.com/muhammadwali0/psx-portfolio-agent.git
cd psx-portfolio-agent
python -m venv .venv && source .venv/bin/activate
make install-devcp .env.example .env
# Add your GOOGLE_API_KEY to .env# Backend only
make run
# Backend + Frontend together
make run-all| Service | URL |
|---|---|
| API | http://localhost:8080 |
| Swagger UI | http://localhost:8080/docs |
| Frontend | http://localhost:5173 |
Triggers the full 5-step agent pipeline. Returns 202 Accepted immediately with a run_id for polling.
{
"capital_pkr": 1000000,
"max_positions": 5,
"risk_preference": "medium",
"tickers_filter": []
}Poll for completion. Status transitions: pending → in_progress → completed | failed
Live PSX market snapshot — no pipeline required.
Latest articles from Dawn Business, ARY Business, and Geo Business.
Returns { signals: [...], conflicts: [...] } for a completed run.
| Variable | Required | Default | Description |
|---|---|---|---|
GOOGLE_API_KEY |
✅ | — | Gemini API key |
GEMINI_MODEL |
gemini-3-flash-preview |
Model ID | |
ENVIRONMENT |
development |
development | staging | production |
|
PORT |
8080 |
Server port (Cloud Run injects this) | |
PORTFOLIO_CAPITAL_PKR |
1000000 |
Default capital in PKR | |
PORTFOLIO_MAX_POSITIONS |
5 |
Max stocks in portfolio | |
RISK_FREE_RATE |
0.21 |
SBP policy rate for Sharpe calculation | |
REDIS_URL |
— | Optional Redis for persistent run store |
All tests are fully offline — scrapers and Gemini are mocked. No API key or network required.
make test # Full suite
make test-cov # With HTML coverage report
make test-fast # Stop on first failuretests/
├── test_api.py # FastAPI endpoint integration tests
├── test_chain.py # ActionChain orchestrator tests
├── test_detector.py # ContradictionDetector unit tests
├── test_portfolio_builder.py # PortfolioBuilder unit tests
├── test_psx_scraper.py # PSXScraper HTML parsing tests
└── test_signals.py # SignalExtractor unit tests
make docker-build
make docker-runmake deploygcloud builds submit --config cloudbuild.yaml \
--substitutions _REGION=us-central1,_REPO=psx-agent,_SERVICE=psx-portfolio-agentThe cloudbuild.yaml pipeline builds the Docker image, pushes to Artifact Registry, and deploys to Cloud Run with secrets injected from Secret Manager.
make lint # ruff
make fmt # black + ruff --fix
make typecheck # mypypsx-portfolio-agent/
├── app/
│ ├── agent/gemini_agent.py # Gemini reasoning engine
│ ├── api/routes.py # FastAPI endpoints
│ ├── portfolio/builder.py # Portfolio construction
│ ├── scrapers/
│ │ ├── base.py # Async base with retry
│ │ ├── psx_scraper.py # PSX market data (Playwright)
│ │ └── news_scraper.py # Dawn / ARY / Geo
│ ├── signals/
│ │ ├── extractor.py # Signal generation
│ │ └── detector.py # Contradiction detection
│ ├── chain.py # 5-step orchestrator
│ ├── config.py # Pydantic settings
│ ├── models.py # Domain models
│ └── store.py # Run store (memory / Redis)
├── frontend/ # React + Vite frontend
├── tests/ # Offline test suite
├── Dockerfile
├── cloudbuild.yaml
└── Makefile
MIT — see LICENSE