Dashboard Pnl Visualization
by smith6jt-cop
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()methodalpaca_trading/visualization/dashboard.py- R-multiple renderingscripts/monitor_dashboard.py- Full implementationdocs/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.
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.
Matplotlib
Foundational plotting library. Create line plots, scatter, bar, histograms, heatmaps, 3D, subplots, export PNG/PDF/SVG, for scientific visualization and publication figures.
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.
Seaborn
Statistical visualization. Scatter, box, violin, heatmaps, pair plots, regression, correlation matrices, KDE, faceted plots, for exploratory analysis and publication figures.
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
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.
Query Writing
For writing and executing SQL queries - from simple single-table queries to complex multi-table JOINs and aggregations
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.
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.
