TVTommaso
← Back to projects15 Jul 2024Next.js · TypeScript · FastAPI +2
Project

PAC Investment Analysis Webapp

Interactive simulator for periodic investing (PAC/DCA) with inflation, contributions, and index selection, powered by a FastAPI backend and Yahoo Finance data.

Project Overview

This project is a web application that demonstrates the long-term impact of investing via a PAC (Capital Accumulation Plan / dollar-cost averaging). Users can set investment parameters, run historical simulations, and visualize outcomes across rolling periods using real market data.

The frontend is built with Next.js and Velite, delivering a responsive UI where users configure:

  • Market index (ticker)
  • Initial capital
  • Monthly contribution (min/max range)
  • Investment duration (years)
  • Inflation (annual %)

Once parameters are set, the frontend calls a FastAPI backend that runs the core simulation. The engine uses monthly returns derived from Adjusted Close prices to simulate PAC behavior with inflation, and returns:

  • Series of period outcomes (invested vs. non-invested final values)
  • Probability of negative periods
  • Average capital gain (%) across all rolling windows
  • A PNG chart of the invested vs. non-invested trajectories

Historical data is sourced from Yahoo Finance (see “Data Pipeline”) to ensure realistic, reproducible simulations.


Architecture at a Glance

  • Frontend: Next.js + Velite

    • Collects inputs via controlled forms with client-side validation.
    • Calls the backend via typed fetch helpers.
    • Renders numerical metrics and dynamic charts.
  • Backend: FastAPI (single-file service)

    • Versioned API: /api/v1
    • Endpoints:
      • GET /api/v1/health
      • GET /api/v1/tickers
      • GET /api/v1/pac/simulate
      • GET /api/v1/pac/summary
      • GET /api/v1/pac/image (PNG chart)
    • CORS configured for the frontend origin(s).
    • Pure ASGI app served behind WSGI (PythonAnywhere) using a thin ASGI→WSGI adapter.
  • Data Pipeline (Yahoo Finance)

    • Offline ingestion from Yahoo Finance (e.g., via yfinance or direct CSV) to a normalized JSON snapshot (all_yahoo_data.json).
    • The API reads from the snapshot at runtime (no third-party calls in the hot path).
    • Columns are normalized to select a robust price series (prefers Adjusted Close) and compute monthly returns.

This split is deliberate: ingest and normalize once; serve many. It removes runtime dependency on external rate limits, improves latency, and makes results reproducible.


Technical Details

Simulation Model

  • Price series: prefers Adjusted Close; falls back to Close if needed.
  • Monthly returns: computed from the selected price series.
  • PAC schedule: monthly contribution linearly ramps from pacStart to pacStop across years.
  • Inflation: applied as a monthly debit to both the invested and non-invested baselines.
  • Rolling windows: evaluates all valid start months for the chosen horizon; reports distributional outcomes.

REST API Design

  • Versioning: /api/v1/... to enable non-breaking iteration.
  • Contract: Pydantic models for request/response; OpenAPI generated by FastAPI.
  • Validation: strict query constraints (ge, le) for numeric inputs; ticker whitelist from the datastore.
  • Idempotent GETs: simulations are read-only and cacheable by parameters.
  • CORS: explicit allow-list of frontend origins; credentials disabled unless strictly needed.
  • Errors: semantic HTTP codes (400 for invalid tickers/params); structured JSON problem details.
  • Performance:
    • Lazy, cached load of the snapshot file.
    • Prefer pagination for large series (future enhancement on /simulate).
    • Pre-aggregate summaries where feasible.
  • Observability:
    • Add structured logging (request id, params, latency).
    • Health/readiness checks (/health) for deployment automation.
  • Security:
    • Input normalization and strict types; reject unknown params.
    • Limit response size for very large payloads (server-side caps).
    • Rate-limit public endpoints if exposed on the open internet.

Frontend Engineering

  • Typed API client: generate TypeScript types from the OpenAPI schema to keep frontend and backend in lockstep.
  • Input hygiene: debounced inputs, sane defaults, and client-side bounds mirroring server constraints.
  • Caching: cache /tickers and deterministic simulations (query-keyed) to avoid redundant calls.
  • Charts: pre-format series on the client; keep the PNG endpoint as a fallback (server-side render) for easy export.

Data & Yahoo Finance Integration

  • Ingestion job (separate from the web app):
    • Fetch tickers and historical OHLCV via Yahoo Finance.
    • Normalize schema; prefer Adjusted Close; record the source timestamp.
    • Write an immutable, versioned snapshot (e.g., all_yahoo_data-YYYYMMDD.json) and symlink all_yahoo_data.json → latest.
  • Quality gates:
    • Validate date monotonicity; drop non-trading days with no prices.
    • Detect and log missing data; exclude tickers without a usable price column.
  • Reproducibility:
    • Pin data vintages for experiments.
    • Consider columnar formats (Parquet) for faster cold starts on larger datasets.

Why This Design

  • Stability under load: no live third-party calls in request path; deterministic CPU-bound simulation.
  • Reproducible research: data snapshots make results auditable.
  • Evolution-friendly: API versioning, typed contracts, and a clear ingest/serve boundary let you iterate without breaking consumers.