Claude Code Plugins

Community-maintained marketplace

Feedback

dashboard-pnl-visualization

@smith6jt-cop/Skills_Registry
0
0

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

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

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 Sat Dec 13 2025 00:00:00 GMT+0000 (Coordinated Universal Time)

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