Oracle3
Open-source trading engine and MCP server for prediction markets. Fee-aware no-arbitrage trading across related contracts, live on Kalshi, Polymarket and Solana or on paper.
Review UOIG fund holdings, research companies, and test portfolio changes
Translation pending
AI summary · README
FinancePython · CGitHub @andrewhulllLatest connection check failedOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
andrewhulll/UOIG-Portfolio-Manager
Translation pending
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
The UOIG Investment Terminal is the internal portfolio analytics, equity research,
and analyst-workflow application for the University of Oregon Investment Group. It
tracks the Tall Firs and Alumni Fund portfolios, compares each fund with its
policy benchmark, and gives members one place to review holdings, research companies,
test portfolio changes, and communicate weekly coverage updates.Read the full README ↗The UOIG Investment Terminal is the internal portfolio analytics, equity research, and analyst-workflow application for the University of Oregon Investment Group. It tracks the Tall Firs and Alumni Fund portfolios, compares each fund with its policy benchmark, and gives members one place to review holdings, research companies, test portfolio changes, and communicate weekly coverage updates.
The current application is a React/Vite frontend backed by FastAPI, Supabase Postgres, WorkOS authentication, and scheduled GitHub Actions. Production uses Vercel for the frontend and Render for the backend; the same application can also run locally or as a single Docker container.
The terminal is a decision-support and research system. It is not a brokerage, order-management system, or intraday trading feed. Portfolio values use finalized daily closes.
The terminal turns UOIG's holdings, market history, company research, coverage assignments, and team submissions into a shared operating workspace. It serves four primary jobs:
| Area | What it provides |
|---|---|
| Funds dashboard | Combined or per-fund AUM, indexed performance versus benchmarks, alpha, beta, Sharpe ratio, volatility, valuation, yield, top holdings, MTD contributors, and sector mix. |
| Holdings | Searchable and sortable positions with fund, sector, weight, market value, closing price, day/MTD change, cost basis, unrealized gain, valuation, trend, and CSV export. |
| Sectors | UOIG's five coverage groups—TMT, IME, Healthcare, Financial, and Consumer—with portfolio weights, holdings, MTD performance, fund mix, sector benchmark comparisons, and weekly movers. |
| Stock research | Price history, company and position facts, institutional holders, internal thesis, quarterly financials, earnings, current news, analyst research, and curated Kalshi prediction markets. |
| Global equity search | Search by company or ticker and open a research page for an equity even when UOIG does not own it. |
| Market screener | Preset and custom screens across company, trading, valuation, profitability, leverage, liquidity, financial-statement, short-interest, and ESG fields. Results open directly into stock research. |
| Portfolio optimization | Benchmark-relative diagnostics, tracking error, active share, beta, volatility, concentration, security/sector active-risk contribution, interactive what-if weights, and a constrained optimizer with portfolio views. |
| My Coverage | Analyst-specific company cards with price/MTD context, upcoming earnings, and relevant news based on assignments stored in the organization directory. |
| Weekly submissions and Inbox | Analysts flag articles or write summaries, submit a sector digest, and receive acknowledgement notices. Sector leaders review, comment on, and acknowledge routed submissions; admins can review all sectors. |
| Organization administration | Invite-only member directory, profiles, roles, company coverage, and independent sector-leadership assignments. Admins manage invitations and assignments. |
| Claude co-pilot | Context-aware chat about the current fund, holding, or sector, plus an asynchronous managed-agent run that receives the full portfolio snapshot for deeper market analysis. Requires Anthropic configuration. |
| User preferences and routing | Persistent landing page, default fund, default period, profile settings, and deep links for funds, stocks, sectors, optimization, coverage, inbox, and assistant views. |
Current holdings use the nightly database snapshot for prices and closed-company data. Opening a holding therefore does not fan out into live Yahoo Finance requests; only the News tab refreshes on demand.
Off-portfolio equities use shared TTL caches to avoid repeating the same upstream requests for every user.
Optimization outputs are analytical proposals only; they do not place trades or write new holdings to the database.
Drafts are editable until submission. The weekly deadline is Thursday at 5:00 PM
America/Los_Angeles, and earlier weeks remain available read-only. See
SUBMISSIONS.md for the detailed state and permission model.
Sector access comes from an explicit leadership assignment, independent of the member's WorkOS role and personal ticker coverage. Admins can review every sector.
The application intentionally separates portfolio monitoring from exploratory research to limit yfinance traffic and keep production stable on a single Render IP.
nightly-refresh runs at 06:00 UTC and, in order:
The workflow requires the same DATABASE_URL used by the deployed backend. The
fundamentals and snapshot stages are intentionally non-fatal so a Yahoo issue cannot
invalidate a successful price refresh.
keep-alive pings only /api/health every ten
minutes to reduce Render free-tier cold starts. It does not request market data or
affect yfinance usage.
Browser
└─ React + Vite frontend (Vercel)
└─ FastAPI JSON API (Render)
├─ Supabase Postgres
│ holdings, prices, dividends, fundamentals, caches,
│ submissions, inbox messages
├─ WorkOS
│ sessions, invitations, roles, directory metadata
├─ yfinance / Alpha Vantage / Kalshi
│ market data, benchmark constituents, prediction markets
└─ Anthropic
contextual chat and managed market-analysis agent
GitHub Actions
└─ nightly refreshes write directly to the same Supabase database
The Docker image builds the React app and lets FastAPI serve both the SPA and API on
one port. The production split deployment instead serves web/dist from Vercel and
uses VITE_API_BASE to reach Render.
api/ FastAPI routes, auth gate, submissions API, and SPA mount
web/ React/Vite terminal UI
src/ analytics, authentication, ingestion, caching, and database model
scripts/ seed, migrate, reconcile, refresh, fundamentals, and snapshot jobs
tests/ backend unit and integration tests
data/ local SQLite database and generated data (git-ignored)
The application is invite-only. WorkOS supports Google OAuth and email/password, including verification and password reset. Except for health and authentication, every API route requires a valid session.
| Role | Application permissions |
|---|---|
Analyst (member) | Use the terminal, view assigned coverage, draft and submit weekly sector updates, and receive acknowledgement messages. |
| Sector Leader | Use the terminal and review submissions for explicitly assigned lead sectors. |
| Admin | Invite members, change roles, manage company coverage and leadership assignments, and review all sector submissions. |
See AUTH_SETUP.md for WorkOS provisioning and
DEPLOYMENT_PLAN.md for the Vercel/Render/Supabase setup.
For local UI development only, UOIG_AUTH_DISABLED=1 bypasses authentication. Never
set it in production.
DATABASE_URLpython -m pip install -r requirements.txt
python -m uvicorn api.main:app --port 8000
npm --prefix web install
npm --prefix web run dev
Open http://localhost:5173. Vite proxies /api to http://localhost:8000.
npm --prefix web run build
python -m uvicorn api.main:app --port 8000
Open http://localhost:8000.
docker build -t uoig-terminal .
docker run --rm -p 8000:8000 \
-e DATABASE_URL=postgresql://... \
-e WORKOS_API_KEY=... \
-e WORKOS_CLIENT_ID=... \
-e WORKOS_COOKIE_PASSWORD=... \
-e WORKOS_ORG_ID=... \
uoig-terminal
SQLite is the local default at data/portfolio.db. Setting DATABASE_URL—or using
the git-ignored supabase.url.txt fallback—switches the same query layer to Postgres.
Use a Supabase pooler URI in hosted environments.
python -m scripts.seed_db # seed holdings from Portfolio Holdings.xlsx
python -m scripts.migrate_to_postgres # copy the local store to Postgres/Supabase
python -m scripts.refresh # incremental closing prices and dividends
python -m scripts.refresh --full # full price-history backfill
python -m scripts.fundamentals # current-holding fundamentals
python -m scripts.snapshots # current-holding stock-tab snapshots
python -m scripts.reconcile # compare the DB with the source workbook
The current holdings table remains the source of truth for positions. The transaction schema exists for future ledger work, but the terminal does not currently provide trade execution or a complete transaction-derived book.
config.yaml defines funds, benchmarks, sector mappings, risk parameters, market-data
pacing, and the default managed-agent ID.
Important deployed variables:
| Variable | Purpose |
|---|---|
DATABASE_URL | Supabase/Postgres connection shared by Render and GitHub Actions. |
WORKOS_API_KEY, WORKOS_CLIENT_ID, WORKOS_COOKIE_PASSWORD, WORKOS_ORG_ID | Invite-only authentication and organization membership. |
WORKOS_REDIRECT_URI, FRONTEND_URL | OAuth callback and post-login destination. |
CORS_ORIGINS, UOIG_COOKIE_SAMESITE, UOIG_COOKIE_SECURE | Cross-origin session configuration for Vercel → Render. |
ANTHROPIC_API_KEY | Claude chat and managed-agent access. |
ANTHROPIC_AGENT_ID | Optional override for the managed market-analysis agent. |
TYPESAFE_API_KEY | Optional backend-only Jev key for persistent news thesis/company assessments. |
TYPESAFE_MODEL | Optional pinned Jev model override; defaults to jev-1.13.0. Changing it creates new assessments. |
ALPHAVANTAGE_API_KEY | Optional benchmark-constituent refresh used by optimization. |
VITE_API_BASE | Public Render backend URL embedded in the Vercel frontend build. |
Local secret-file fallbacks are supported and git-ignored. Do not commit API keys, database credentials, or WorkOS secrets.
Install the backend requirements and set TYPESAFE_API_KEY on the backend (Render
environment variables in production), then restart it. Never use a VITE_ variable
for this key. Without the key, ordinary news continues to work.
Stock News and My Coverage assess up to the ten newest distinct Yahoo articles. The UI shows whether news supports, detracts from, or is neutral to the recorded thesis, plus estimated business impact and the impact assessment's confidence. Mixed or insufficient evidence is marked Unclear. Without a thesis, direction describes company implications instead. Assessments use Yahoo's title and available summary; headline-only inputs are labeled. Impact describes business significance over twelve months, not a predicted stock-price move. Confidence is model certainty, not investment-return probability; thesis classification confidence is in its tooltip.
Date sorting is the default, with Confidence and Impact alternatives. Missing scores
sort last. Sorting makes no API calls. Pending results refresh through
/api/stock/{ticker}/news-analysis, which reads the saved feed without fetching Yahoo.
The news_analysis table is automatically created in the existing SQLite/Postgres
store. Completed results never expire and survive market-data reseeding; they are
independent of the ten-minute Yahoo feed cache. Assessments are shared across users
and keyed by ticker, article identity/content, thesis points, rubric, and pinned model.
Changed article text or thesis points create new assessments while old ones remain.
Database claims prevent concurrent duplicate calls. Workers are bounded to four,
with a queue cap of forty; failures retry on subsequent requests after five minutes,
up to three attempts per assessment. Abandoned claims recover after ten minutes.
A crash after a remote response but before saving can require a repeated call.
Database or Jev failures leave headlines usable and show assessment unavailable.
Validate with python -m pytest -q, node tests/test_news_sort.mjs, and
npm --prefix web run build. Tests mock Jev and use temporary databases; no live
key or billable call is required.
The frontend consumes the following main route groups:
| Routes | Purpose |
|---|---|
/api/data, /api/series/*, /api/fund-series/*, /api/sector-series/* | Portfolio snapshot and historical analytics. |
/api/search, /api/quote/*, /api/holders/*, /api/stock/* | Owned and off-portfolio equity research. |
/api/screener/* | Screener field catalog and market queries. |
/api/optimize/* | Diagnostics, what-if calculations, and optimizer solves. |
/api/coverage/me | Authenticated analyst coverage dashboard. |
/api/flags/*, /api/submissions/*, /api/inbox/* | Weekly coverage workflow and messaging. |
/api/organization/*, /api/profile | Directory, assignments, roles, and profile management. |
/api/chat, /api/agent/run* | Claude chat and asynchronous managed-agent analysis. |
/api/auth/* | Google OAuth, password authentication, invitations, reset, session, and logout. |
/api/health | Public backend health/configuration check. |
python -m pytest -q
npm --prefix web run build
Tests use temporary databases and mocked external services where applicable; they do not submit real WorkOS messages or execute trades.