Skip to main content
Version: v4

Design

How it works

  1. SuiviBourse loads your portfolio from either a config.yaml file (manual mode) or from CSV/XLSX transaction files (events mode).
  2. Independent scheduled jobs run in parallel:
    • Scraping — fetches current prices from Yahoo! Finance. There is one self-rescheduling job per held symbol, and each one is market-aware: it polls only while the symbol's market is open and sleeps until the next open otherwise.
    • Ingestion — reloads and re-aggregates your portfolio configuration.
    • Backfill — progressively fills in historical prices, in both directions: backward to your first purchase, and forward to recover a session missed while the app was down (events mode only).
    • Performance — recomputes the per-account and global return series (events mode, opt-in accounts only).
  3. Every data point is written to InfluxDB 3 Core in the portfolio_metrics measurement.
  4. Grafana reads InfluxDB (SQL datasource) to display your portfolio in a ready-made dashboard.
  5. A legacy Prometheus /metrics endpoint is also exposed for backward compatibility with pre-v4 deployments.

Architecture

SuiviBourse (app)
┌────────────────────┬────────────────────┬────────────────────┬────────────────────┐
│ SCRAPING │ INGESTION │ BACKFILL │ PERFORMANCE │
│ (per symbol, │ (every 300s) │ (every 60s) │ (SB_PERF_INTERVAL)│
│ market-aware) │ │ events mode only │ events mode only │
│ • yfinance.Ticker()│ • Load config or │ • Backward: to the │ • Only when data │
│ • marketState → │ event files │ first BUY event │ changed │
│ poll or sleep │ • Validate │ • Forward: recover │ • Recompute XIRR / │
│ • Open: write pt │ • Aggregate │ missed sessions │ TWR / value │
│ • Closed: sleep to │ • Cache (by mtime) │ • 1 chunk / cycle │ • Write account_/ │
│ next open │ • Update shares[] │ • Enrich + write │ portfolio series │
└─────────┬──────────┴─────────┬──────────┴─────────┬──────────┴─────────┬──────────┘
│ │ │ │
└────────────────────┴─────────┬──────────┴────────────────────┘

┌───────────────────┐ ┌──────────────────┐
│ InfluxDB 3 Core │◄──────►│ Grafana │
│ portfolio_metrics │ SQL │ dashboard │
└───────────────────┘ └──────────────────┘

│ (legacy, snapshot only)
┌───────────────────┐
│ Prometheus /metrics│ :8081
└───────────────────┘

Independent schedules

The application runs several scheduled jobs that operate independently. Because they are decoupled, an error in one never blocks the others.

JobCadenceEnv variablePurposeError handling
ScrapingPer symbol, market-awareSB_REGULAR_INTERVALFetch live prices from Yahoo! FinanceSleeps closed markets to next open; backs a dead ticker off exponentially
IngestionEvery 300 sSB_INGESTION_INTERVALReload & re-aggregate the portfolioKeeps the previous valid configuration
BackfillEvery 60 sSB_BACKFILL_INTERVALFill historical price data (events mode)Retries the same chunk on the next cycle
PerformanceEvery SB_PERF_INTERVAL s (gated)SB_PERF_INTERVALRecompute per-account & global returns (events mode, opt-in)Skips the run when nothing changed

Scraping is no longer a single global loop: SuiviBourse schedules one self-rescheduling job per held symbol, and each job re-arms on its own cadence from the symbol's live marketState. An open (REGULAR) market re-polls every SB_REGULAR_INTERVAL; a closed one sleeps until the next open. See market-aware scraping for the full model, the worker-pool dials and the resulting weekend/holiday chart gaps.

Why separate schedules?
  • Isolation — if your event files contain an error, price scraping keeps running with the last valid configuration.
  • Different frequencies — stock prices change only while markets are open, your portfolio rarely changes, and backfill only needs to nibble away at history over time.
  • Efficient caching — ingestion only reprocesses when files actually change (based on their modification time), and the performance job only recomputes when something new has landed.

Storage & visualization

  • InfluxDB 3 Core is the primary datastore. All live and historical points land in a single measurement, portfolio_metrics. See the InfluxDB data model for the full tag/field schema.
  • Grafana connects to InfluxDB through its SQL query mode and ships with a provisioned dashboard in the Docker Compose stack.
  • The legacy Prometheus endpoint (:8081/metrics) still exposes the sb_* gauges for the current snapshot of each share. See Legacy Prometheus endpoint.

Configuration modes

SuiviBourse supports two mutually exclusive configuration modes. See the Configuration section for details.

ModeSourceUse case
Manualconfig.yamlSimple, static portfolio
Eventsevents/*.csv, *.xlsxTransaction history, automatic aggregation, historical backfill