feat: wire TUI dashboard panels to live data (closes #134)#152
Merged
Conversation
Make the Textual dashboard functional by wiring its panels to the live data layer instead of showing only static config snapshots. - OverviewPanel: fetches live prices for portfolio holdings and the watchlist via DataRegistry.async_get_with_fallback; P&L computed per holding when prices are available. - PortfolioPanel: uses RiskCalculator.build_snapshot to render market values, weights, and unrealized P&L once all holdings have prices, with a cost-basis fallback for partial data. - WatchlistPanel: fetches live prices for each ticker on refresh. - AlertsPanel: reads active alerts from AlertStore with hot-reload via mtime checks (replacing the static placeholder). - TasksPanel (new): displays scheduled tasks from TaskStore with human-readable next run times (in 5m / in 2h / due). - QracerDashboard accepts optional data_registry, alert_store, and task_store kwargs and injects them into panels during construction and sidebar navigation. - `qracer dashboard` CLI builds the registries via _build_registries() and wires the default ~/.qracer/ stores into the app. Panels keep their existing behaviour when no registry is provided so unit tests (and users without live data) see a "—" placeholder view.
Formatting-only changes to satisfy the code-quality CI step (ruff format --check), no behavioural changes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #134. Makes the Textual TUI dashboard functional by wiring panels to the live data layer instead of showing only static config snapshots.
DataRegistry.async_get_with_fallback(PriceProvider, "get_price", …); per-holding P&L computed when prices are available. Replaces the static "S&P 500 / NASDAQ / VIX" placeholder with a live Watchlist mini-table.RiskCalculator.build_snapshot()to render market values, weights, and unrealized P&L once all holdings have prices; falls back to a cost-basis view for partial data. A total-value label shows either live portfolio value or cost basis.DataTablebacked byAlertStore, with hot-reload via mtime checks (picks up alerts created byqracer replwithout restarting the dashboard).TaskStore.get_active()and renders schedule + human-readable next run time (in 5m/in 2h/due). Added to the DASH sidebar group with hotkey5.QracerDashboardaccepts optionaldata_registry,alert_store,task_storekwargs and injects them into panels both on compose and on sidebar navigation.qracer dashboardCLI now calls_build_registries()and passes~/.qracer/alerts.json+~/.qracer/tasks.jsonstores to the app.Panels keep their placeholder behaviour when no registry/store is provided (useful for tests and users without live data) — every cell that depends on live data falls back to
—.Test plan
uv run pytest tests/dashboard/→ 49 passed (14 new tests: refresh_data behaviour for Overview/Portfolio/Watchlist with a_FakeRegistry, partial-price fallback, AlertsPanel hot-reload, TasksPanel empty/populated/hot-reload,_format_next_runedge cases)uv run pytest tests/cli/ tests/test_cli.py tests/test_alerts.py tests/test_tasks.py tests/test_watchlist.py tests/storage/ tests/risk/→ 238 passed totaluv run ruff check qracer/dashboard/ qracer/cli.py tests/dashboard/→ cleanuv run pyright qracer/dashboard/ qracer/cli.py→ 0 errorsqracer dashboardwith a populated portfolio and watchlist — verify prices appear within one refresh interval and switching panels keeps live data.Notes
REFRESH_INTERVAL_SECONDS = 5.0).DataRegistry.async_get_with_fallback, matching the pattern used byAlertMonitor, so provider priority and fallback are consistent across the app.DEBUGlevel and skipped rather than blanking the whole table.