Market data terminal for the Ghana Stock Exchange — end-of-day prices, charts and technical indicators, watchlists with alerting, portfolio backtesting, and multi-provider LLM commentary. A single Go binary with an embedded UI, backed by QuestDB, Postgres and Redis.
# GSE Terminal
A market data terminal for the **Ghana Stock Exchange**: end-of-day prices
for every listed counter, charts and technical indicators, watchlists with
alerting, and LLM-backed market commentary — served from a single Go binary
with an embedded UI.
## What it does
- **Daily ingest.** Pulls the exchange's own "Daily Shares & ETFs" table
from gse.com.gh at 15:30 UTC and writes it to QuestDB. The same CSV
format can be uploaded by hand from the admin panel; both paths share one
parser, so a backfill and a scheduled run behave identically.
- **Market data.** OHLC history, symbol comparison, sector rotation, top
movers, bid/offer spreads, and a CSV export — 61 `/v1/*` endpoints.
- **Watchlists and alerts.** Per-user rules evaluated after every ingest,
delivered in-app, by email, and by Web Push.
- **AI oracle.** Per-symbol commentary and a daily market briefing, plus a
natural-language query endpoint that generates QuestDB SQL, validates it
as read-only, and retries once using the database's own error when a
statement is rejected.
- **Portfolio.** Holdings, reconstructed value history, and backtesting.
## Architecture
| Piece | Role |
|---|---|
| Go 1.25 (`cmd/server`) | HTTP API, WebSocket hub, scheduler, embedded UI |
| QuestDB | Price time series (`equities`, one row per symbol per session) |
| Postgres | Users, watchlists, alert rules, briefings, audit log |
| Redis | Derived-data cache, sessions, rate-limit and digest state |
| Caddy | TLS termination in production |
`internal/` is organised by domain — `collector` (scraping), `ingestor`
(CSV parsing), `analysis` (indicators, LLM clients, NL→SQL), `alerts`,
`auth`, `push`, `repository` (all three datastores), `server` (handlers).
Two frontends live in the repo: `ui/` is the shipped terminal (vanilla JS +
htmx + Tailwind, compiled by Vite and embedded into the binary via
`go:embed`), and `web/` is a React/Radix rewrite in progress.
The LLM layer takes any provider: Gemini, Anthropic, OpenAI, or * …