Python FastAPI Ollama scikit-learn React SQLite Tests Machine Learning License

A self-hosted macroeconomic intelligence platform powered by a local LLM (Ollama). It continuously monitors global macro conditions — regime, liquidity, stress, and inflation cycles — and answers free-text questions about the current economic environment.

Features

  • Regime detection — 6-regime scorecard (z-score based) + unsupervised HMM regime detector
  • Inflation regime — unsupervised HMM on 65 years of FRED inflation data (CPI/PCE/M2/real rate)
  • Recession probability — walk-forward calibrated logistic model (6m and 12m horizons)
  • US Liquidity Index — Fed balance sheet, RRP, TGA, M2
  • Stress monitor — composite 0–100 index (VIX, HY spreads, Fear & Greed, DXY)
  • Correlation analysis — Pearson/Spearman with bootstrap CI, OLS, and regime-conditional breakdowns
  • Ask Macro — autonomous tool-calling agent: routes any macro question to the right data tools
  • Agent traceability — every /ask call persists its full agentic loop trace to SQLite (tools called, arguments, raw results, latency per iteration)
  • Alerts — webhook subscriptions, threshold triggers, scheduler-driven snapshots
  • React dashboard — live gauges, timeline, and conversational interface

Stack

Layer Technology
Backend FastAPI + Uvicorn, Python 3.12
LLM Ollama (local, model configurable)
Data FRED API, yfinance, ECB SDW, BoJ
Database SQLite (aiosqlite) — cache, history, alerts
ML scikit-learn, hmmlearn, statsmodels, numpy
Frontend React 18 + Vite + Tailwind CSS v3 + Recharts
Config pydantic-settings, env prefix MACRO_

Quick start

Prerequisites

Installation

git clone <repo-url>
cd macro-analyst

# Install Python dependencies
pip install -r requirements.txt

# Copy and fill in environment variables
cp .env.example .env
# Edit .env — required: MACRO_FRED_API_KEY and MACRO_OLLAMA_URL

Run

# Backend
uvicorn app.api:app --host 0.0.0.0 --port 8000 --reload

# Frontend (dev)
cd ui && npm install && npm run dev
# → http://localhost:5173

# Or build the frontend for production (served by FastAPI at /ui)
cd ui && npm run build

Docker

docker compose up

Key environment variables

Variable Required Default Description
MACRO_FRED_API_KEY Yes FRED API key (free)
MACRO_OLLAMA_URL Yes http://localhost:11434 Ollama base URL
MACRO_API_KEY No (empty = open) Bearer auth for all endpoints
MACRO_SNAPSHOT_INTERVAL_HOURS No 1 Scheduler snapshot frequency
MACRO_ALERT_WEBHOOK_URL No Webhook URL for alert delivery

See .env.example for the full list.

API endpoints

Method Path Description
GET /health Monitoring endpoint — Ollama, scheduler, DB, ML models
GET /brief Ultra-compact macro brief (no LLM, near-instant)
GET /snapshot Full macro snapshot (regime + liquidity + stress + brief)
GET /macro-context Compact snapshot for peer agent injection (< 500 tokens)
POST /ask Free-text macro question → bullets + conclusion
POST /ask/structured Same as /ask but returns machine-readable MacroAnswer
GET /regime Regime scorecard (6 regimes, z-scores)
GET /liquidity US Liquidity Index
GET /stress Stress monitor 0–100
GET /correlations Asset–driver correlation analysis
GET /indicators Raw indicator values
GET /history Snapshot history
GET /regime/timeline Regime timeline
POST /alerts/subscribe Register a webhook
GET /v1/tools OpenAI-compatible tool catalog
POST /v1/tool_call Invoke a tool by name
GET /ask/traces Agentic loop traces for recent /ask calls
DELETE /cache Flush the SQLite cache

Swagger UI: http://localhost:8000/docs

Full reference: docs/api.md

Example questions & answers

Real traces from the ask_traces table — questions sent to POST /ask, answers generated by the agentic pipeline.


Q: What is the current macro regime and main risks?

The current macro regime is Goldilocks (score 0.526, 33% agreement). Stress is elevated at 71 / 100 (70th percentile over 5 years), driven by a VIX of 25.5 and real rates at +1.25% that are compressing the 2Y/10Y spread to just +0.54 bps.

Key points:

  • Stress is high at 71.0 — at the 70.99th percentile vs. the last 5 years
  • Real rates remain elevated at +1.25%, suppressing duration appetite
  • Risk bias score is 0.452 — mild risk-off tilt within the goldilocks regime

Conclusion: The economy faces a latent regime-shift risk — sticky inflation and high stress could tip the balance despite the current goldilocks classification.

Latency: 29s — 1 agentic iteration


Q: What is the BTC price and current crypto outlook?

BTC is at $69,201 (+4.9% today, +1.56% on the week). The macro backdrop is goldilocks with a bullish crypto bias, but stress at 71 is a headwind worth monitoring.

Key points:

  • BTC 1-day change: +4.9%, 1-week: +1.56%
  • Regime: goldilocks with expanding liquidity and risk-on sentiment
  • Stress at 71 / 100 represents a non-trivial tail risk for risk assets

Conclusion: Bitcoin shows strong bullish momentum within a stable goldilocks regime — but elevated stress warrants position discipline.

Latency: 18s — 1 agentic iteration


Agent traceability

Every call to POST /ask runs an autonomous agentic loop: the LLM selects tools, executes them in parallel, receives their results, and iterates until it can answer. Each run is fully traced and persisted to SQLite.

What is recorded

For each /ask call, one row is written to the ask_traces table with:

Field Description
question The user's question verbatim
latency_s Total wall-clock time for the full pipeline
total_iterations Number of tool-calling rounds
iterations JSON array — one entry per round (see below)
final_response Raw LLM output before parsing

Each iteration entry contains:

  • iteration — round number (1-based)
  • assistant_content — any text the LLM emitted before the tool calls
  • tools — list of {tool, args, result} for every tool called in that round

Inspect traces

# Most recent 20 traces (last 7 days)
curl http://localhost:8000/ask/traces

# Last 5 traces over 30 days
curl "http://localhost:8000/ask/traces?limit=5&days=30"

Example response (one trace):

{
  "id": 42,
  "timestamp": "2026-03-10T14:32:01Z",
  "question": "What is the current macro regime?",
  "latency_s": 28.9,
  "total_iterations": 1,
  "final_response": "{\"direct_answer\": \"Goldilocks...\"}",
  "iterations": [
    {
      "iteration": 1,
      "assistant_content": "",
      "tools": [
        {
          "tool": "get_macro_snapshot",
          "args": {},
          "result": { "regime": "goldilocks", "stress": 71.0, "vix": 25.5 }
        },
        {
          "tool": "detect_regime_hmm",
          "args": {},
          "result": { "current_state": 2, "state_proba": [0.02, 0.11, 0.87] }
        }
      ]
    }
  ]
}

Why this matters

Traceability is fundamental to production AI systems:

  • Auditability — know exactly which data sources the LLM consulted before answering
  • Debugging — if an answer is wrong, inspect whether the right tools were called with the right arguments and whether the results were correct
  • Trust — answers backed by traceable tool calls are verifiable, not hallucinated
  • Iteration — tool selection patterns reveal which questions are answered well and which need better routing rules

ML models

Three production models, all trained offline and served via app/ml/api/:

Model Task Approach History
hmm_regime Unsupervised macro regime GaussianHMM + PCA + BIC selection 1987+
hmm_inflation Unsupervised inflation regime GaussianHMM + PCA + BIC selection 1961+
recession_6m Recession probability at 6 months Walk-forward logistic + Platt 1968+
recession_12m Recession probability at 12 months Walk-forward logistic + Platt 1968+

Training

# Train all models
python scripts/train_models.py

# Train a specific model
python scripts/train_models.py --model hmm
python scripts/train_models.py --model hmm-inflation
python scripts/train_models.py --model recession

# Rebuild FRED/yfinance panels from scratch, then train
python scripts/train_models.py --rebuild-panels

# Dry-run — build panels only, no training
python scripts/train_models.py --dry-run

Artifacts are saved to storage/models/artifacts/ (.joblib) and model cards to storage/models/metadata/ (.json).

Model documentation:

Architecture

macro-analyst/
├── app/
│   ├── agent/          # Snapshot + Ask autonomous pipelines
│   ├── compute/        # Regime, stress, liquidity, correlations
│   ├── ml/             # HMM models, RecessionProbit, features, validation
│   │   ├── api/        # Async inference entry points
│   │   ├── models/     # GaussianHMM, RecessionProbit
│   │   ├── features/   # Feature sets, transforms, spreads
│   │   ├── labels/     # USREC recession labels
│   │   ├── datasets/   # FRED + market panel builders
│   │   ├── backtests/  # Regime return analysis
│   │   ├── validation/ # Walk-forward CV, metrics
│   │   └── registry/   # Model store (joblib) + metadata
│   ├── providers/      # FRED, ECB, BoJ, yfinance
│   ├── llm/            # Ollama client
│   ├── api.py          # FastAPI — all endpoints
│   ├── tools.py        # 14 async data tools
│   ├── tool_spec.py    # OpenAI function-calling catalog
│   ├── config.py       # pydantic-settings
│   ├── cache.py        # SQLite cache
│   ├── history.py      # Snapshot history persistence
│   ├── alerts.py       # Webhook + alert management
│   └── scheduler.py    # APScheduler
├── docs/               # Full documentation
├── scripts/            # Offline training and backfill utilities
├── storage/            # Parquet panels + model artifacts
├── tests/              # pytest test suite (≥80% coverage)
├── ui/                 # React + Vite dashboard
└── docker-compose.yml

Full architecture: docs/architecture.md

Tests

# Install dev dependencies (pytest + pytest-cov + pytest-asyncio)
pip install -r requirements-dev.txt

# Run all tests with coverage report
pytest

# Run a specific test file
pytest tests/test_api_v3.py -v

# Coverage only
pytest --cov=app --cov-report=html

Coverage target: 80% (enforced by pytest.ini).

Two requirements files:

  • requirements.txt — runtime dependencies only (FastAPI, ML libs, etc.). Use this in production and Docker.
  • requirements-dev.txt — includes everything in requirements.txt plus test tooling (pytest, pytest-asyncio, pytest-cov). Use this locally and in CI.

CI/CD

GitHub Actions workflows are defined in .github/workflows/:

Workflow Trigger Jobs
ci.yml Push / PR on master lint (ruff) → tests (pytest ≥80% coverage) → UI build (tsc + vite) → Docker dry-run
release.yml Push of a v*.*.* tag Build UI → build & push Docker image to GitHub Container Registry

To publish a new release:

git tag v1.2.0
git push origin v1.2.0

The image is pushed to ghcr.io/<owner>/macro-analyst with tags 1.2.0, 1.2, and latest.

Tests that require a live Ollama instance (test_tools_full, test_agent_ask, test_snapshot, test_llm_client) are excluded from CI.

Documentation

Document Content
docs/setup.md Installation, configuration, Docker
docs/architecture.md System layers, data flow, design decisions
docs/api.md Full API endpoint reference
docs/ml/hmm_regime.md HMM Regime Detector
docs/ml/hmm_inflation.md HMM Inflation Detector
docs/ml/recession_probit.md Recession Probit Model

License

MIT

Built With

Share this project:

Updates