Dashboard Pnl Visualization

by smith6jt-cop

skill

Trading dashboard P&L visualization with profit tracker integration, win-rate overlays, R-multiples, and configurable settings

Skill Details

Repository Files

1 file in this skill directory


name: dashboard-pnl-visualization description: "Trading dashboard P&L visualization with profit tracker integration, win-rate overlays, R-multiples, and configurable settings" author: Claude Code date: 2025-12-13

dashboard-pnl-visualization - Research Notes

Experiment Overview

Item Details
Date 2025-12-13
Goal Enhance trading dashboard with comprehensive P&L tracking, win-rate overlays from profit tracker, and R-multiple position visualization
Environment Python 3.10, matplotlib, alpaca-py, Alpaca Trading API
Status Success

Context

Trading dashboards often show only gross P&L without breaking down realized vs unrealized, cost coverage, or win-rate context. This skill documents patterns for integrating profit tracker data into dashboard visualizations.

Verified Workflow

1. DashboardConfig Dataclass

Create a configurable runtime settings system:

from dataclasses import dataclass, field
from typing import List
import json
from pathlib import Path

@dataclass
class DashboardConfig:
    """Runtime configuration for the monitoring dashboard."""
    symbols: List[str] = field(default_factory=lambda: ["SPY", "QQQ", "AAPL"])
    lookback_days: int = 30
    interval_seconds: int = 60
    output_dir: str = "dashboards"
    cost_data: float = 3.33        # Daily data cost
    cost_software: float = 6.67    # Daily software cost
    risk_limit_pct: float = 10.0   # Portfolio risk limit
    profit_log_dir: str = "logs/live"
    save_latest: bool = True

    @classmethod
    def from_json(cls, path: str) -> "DashboardConfig":
        if not path or not Path(path).exists():
            return cls()
        return cls(**json.loads(Path(path).read_text()))

2. Broker Equity History Integration

Fetch real portfolio equity data from Alpaca:

def get_equity_history(
    self,
    period: str = "1M",    # '1D', '1W', '1M', '3M', '1A'
    timeframe: str = "1D", # '1Min', '5Min', '15Min', '1H', '1D'
) -> List[Dict[str, Any]]:
    """Return historical equity curve from the broker."""
    from alpaca.trading.requests import GetPortfolioHistoryRequest

    request = GetPortfolioHistoryRequest(period=period, timeframe=timeframe)
    history = self._client.get_portfolio_history(request)

    if hasattr(history, "equity") and hasattr(history, "timestamp"):
        return [
            {"timestamp": ts, "value": eq}
            for ts, eq in zip(history.timestamp, history.equity)
        ]
    return []

3. Win-Rate Overlay from Profit Tracker

Load profit summary for live metrics overlay:

def load_profit_summary(log_dir: str) -> Dict:
    """Load profit tracker summary for win-rate overlays."""
    path = Path(log_dir)
    summary_files = sorted(path.glob("*/profit_summary.json"))
    if not summary_files:
        return {}

    with summary_files[-1].open() as f:
        summary = json.load(f)

    trades = summary.get("trades", [])
    pnls = [t.get("pnl", 0.0) for t in trades]
    wins = [p for p in pnls if p > 0]

    # Calculate loss streak
    loss_streak = 0
    for pnl in reversed(pnls):
        if pnl <= 0:
            loss_streak += 1
        else:
            break

    return {
        "win_rate": len(wins) / len(pnls) if pnls else 0.0,
        "loss_streak": loss_streak,
        "trade_count": len(pnls),
    }

4. Realized vs Unrealized P&L Split

def get_pnl_breakdown(broker, cfg, profit_overlay, open_pnl=0.0) -> dict:
    """Get P&L breakdown with realized/unrealized split."""
    account = broker.get_account()
    equity = float(account['equity'])
    last_equity = float(account.get('last_equity', equity))

    daily_pnl = equity - last_equity
    unrealized_pnl = float(open_pnl)
    realized_pnl = daily_pnl - unrealized_pnl

    breakdown = {
        'gross_pnl': daily_pnl,
        'unrealized_pnl': unrealized_pnl,
        'realized_pnl': realized_pnl,
        'data_cost': cfg.cost_data,
        'software_cost': cfg.cost_software,
    }
    breakdown['net_pnl'] = breakdown['gross_pnl'] - cfg.cost_data - cfg.cost_software

    # Add win-rate overlay
    if profit_overlay:
        breakdown['win_rate'] = profit_overlay.get('win_rate')
        breakdown['loss_streak'] = profit_overlay.get('loss_streak')

    return breakdown

5. R-Multiple Display for Positions

def calculate_r_multiple(entry_price, current_price, stop_price, side):
    """Calculate R-multiple for position risk-reward."""
    if not stop_price:
        return None

    if side != 'short':
        risk_per_share = entry_price - stop_price
        profit_per_share = current_price - entry_price
    else:
        risk_per_share = stop_price - entry_price
        profit_per_share = entry_price - current_price

    if risk_per_share <= 0:
        return None

    return profit_per_share / risk_per_share

# Color coding for R-multiples
def get_r_color(r_multiple):
    if r_multiple is None:
        return 'gray'
    elif r_multiple >= 2:
        return 'darkgreen'  # Excellent
    elif r_multiple >= 1:
        return 'green'      # Good
    else:
        return 'orange'     # Below target

Failed Attempts (Critical)

Attempt Why it Failed Lesson Learned
Using account.equity - account.last_equity directly Doesn't separate realized from unrealized Pass open_pnl from position calculations
Hardcoding cost values Different users have different infrastructure costs Use DashboardConfig dataclass
Reading profit_summary from fixed path Path varies by session date Use glob to find most recent summary
Displaying R-multiple without stop price Division by zero / meaningless value Return None and show "--" in display

Final Parameters

# CLI arguments for dashboard
parser.add_argument('--config', type=str, help='JSON config path')
parser.add_argument('--symbols', type=str, help='Comma-separated symbols')
parser.add_argument('--lookback-days', type=int, default=30)
parser.add_argument('--data-cost', type=float, default=3.33)
parser.add_argument('--software-cost', type=float, default=6.67)
parser.add_argument('--risk-limit', type=float, default=10.0)
parser.add_argument('--profit-log-dir', type=str, default='logs/live')

Key Insights

  • Realized/unrealized split requires tracking open position P&L separately
  • Win-rate overlays provide crucial context for daily P&L interpretation
  • R-multiples only meaningful when stop prices are set
  • Cost coverage percentage helps evaluate if trading covers infrastructure costs
  • JSON config files allow per-environment customization without code changes
  • Profit tracker summaries should be written with timestamp directories for history

References

  • alpaca_trading/broker.py - get_equity_history() method
  • alpaca_trading/visualization/dashboard.py - R-multiple rendering
  • scripts/monitor_dashboard.py - Full implementation
  • docs/dashboard_improvements.md - Feature documentation

Related Skills

Attack Tree Construction

Build comprehensive attack trees to visualize threat paths. Use when mapping attack scenarios, identifying defense gaps, or communicating security risks to stakeholders.

skill

Grafana Dashboards

Create and manage production Grafana dashboards for real-time visualization of system and application metrics. Use when building monitoring dashboards, visualizing metrics, or creating operational observability interfaces.

skill

Matplotlib

Foundational plotting library. Create line plots, scatter, bar, histograms, heatmaps, 3D, subplots, export PNG/PDF/SVG, for scientific visualization and publication figures.

skill

Scientific Visualization

Create publication figures with matplotlib/seaborn/plotly. Multi-panel layouts, error bars, significance markers, colorblind-safe, export PDF/EPS/TIFF, for journal-ready scientific plots.

skill

Seaborn

Statistical visualization. Scatter, box, violin, heatmaps, pair plots, regression, correlation matrices, KDE, faceted plots, for exploratory analysis and publication figures.

skill

Shap

Model interpretability and explainability using SHAP (SHapley Additive exPlanations). Use this skill when explaining machine learning model predictions, computing feature importance, generating SHAP plots (waterfall, beeswarm, bar, scatter, force, heatmap), debugging models, analyzing model bias or fairness, comparing models, or implementing explainable AI. Works with tree-based models (XGBoost, LightGBM, Random Forest), deep learning (TensorFlow, PyTorch), linear models, and any black-box model

skill

Pydeseq2

Differential gene expression analysis (Python DESeq2). Identify DE genes from bulk RNA-seq counts, Wald tests, FDR correction, volcano/MA plots, for RNA-seq analysis.

skill

Query Writing

For writing and executing SQL queries - from simple single-table queries to complex multi-table JOINs and aggregations

skill

Pydeseq2

Differential gene expression analysis (Python DESeq2). Identify DE genes from bulk RNA-seq counts, Wald tests, FDR correction, volcano/MA plots, for RNA-seq analysis.

skill

Scientific Visualization

Meta-skill for publication-ready figures. Use when creating journal submission figures requiring multi-panel layouts, significance annotations, error bars, colorblind-safe palettes, and specific journal formatting (Nature, Science, Cell). Orchestrates matplotlib/seaborn/plotly with publication styles. For quick exploration use seaborn or plotly directly.

skill

Skill Information

Category:Skill
Last Updated:12/13/2025