skills/trading-visualization/SKILL.md
Professional trading charts including candlesticks, equity curves, drawdowns, correlation heatmaps, and return distributions
npx skillsauth add agiprolabs/claude-trading-skills trading-visualizationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Visualization is the primary interface between a trader and their data. Charts reveal patterns that tables and numbers cannot: breakdowns in strategy, regime transitions, clustering of losses, and the shape of risk. A well-designed chart communicates more in a glance than a page of statistics.
Three uses of trading charts:
| Chart Type | Purpose | Library | |------------|---------|---------| | Candlestick | OHLCV price action with overlays | mplfinance | | Equity curve | Portfolio value over time | matplotlib | | Drawdown | Underwater equity plot | matplotlib | | Return distribution | Histogram + normal fit | matplotlib | | Correlation heatmap | Cross-asset correlation matrix | matplotlib / seaborn | | Trade markers | Entry/exit points on price chart | mplfinance / matplotlib | | Indicator panels | RSI, MACD below price chart | mplfinance | | Position timeline | When positions were held | matplotlib |
Best for candlestick charts. Built on matplotlib with finance-specific defaults.
uv pip install mplfinance
import mplfinance as mpf
# Basic candlestick from a DataFrame with DatetimeIndex
# Columns: Open, High, Low, Close, Volume
mpf.plot(df, type="candle", volume=True, style="charles")
Key features:
addplot for overlays (moving averages, Bollinger Bands)mpf.make_mpf_style()General purpose, most flexible. Use when you need full control over layout.
uv pip install matplotlib
import matplotlib.pyplot as plt
fig, axes = plt.subplots(2, 1, figsize=(14, 8), height_ratios=[3, 1],
sharex=True)
axes[0].plot(dates, equity, color="#00ff88")
axes[1].fill_between(dates, drawdown, 0, color="#ff4444", alpha=0.5)
Interactive charts rendered as HTML. Best for exploration and dashboards.
uv pip install plotly
import plotly.graph_objects as go
fig = go.Figure(data=[go.Candlestick(
x=df.index, open=df["Open"], high=df["High"],
low=df["Low"], close=df["Close"]
)])
fig.update_layout(template="plotly_dark")
fig.write_html("chart.html")
Trading terminals use dark backgrounds by default. All charts in this skill follow that convention.
import matplotlib.pyplot as plt
plt.style.use("dark_background")
plt.rcParams.update({
"figure.facecolor": "#1a1a2e",
"axes.facecolor": "#1a1a2e",
"axes.edgecolor": "#333333",
"grid.color": "#333333",
"grid.alpha": 0.4,
"text.color": "#e0e0e0",
"xtick.color": "#aaaaaa",
"ytick.color": "#aaaaaa",
})
| Element | Color | Hex |
|---------|-------|-----|
| Bullish / profit | Green | #00ff88 |
| Bearish / loss | Red | #ff4444 |
| Neutral / info | Blue | #4488ff |
| Warning | Amber | #ffaa00 |
| MA short | Orange | #ff6600 |
| MA long | Blue | #3399ff |
| MA signal | Yellow | #ffcc00 |
See references/styling_guide.md for complete typography, layout ratios, and export settings.
Most trading charts need multiple synchronized panels — price on top, volume in the middle, indicators at the bottom.
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
fig = plt.figure(figsize=(14, 10))
gs = gridspec.GridSpec(3, 1, height_ratios=[3, 1, 1], hspace=0.05)
ax_price = fig.add_subplot(gs[0])
ax_volume = fig.add_subplot(gs[1], sharex=ax_price)
ax_rsi = fig.add_subplot(gs[2], sharex=ax_price)
# Hide x-tick labels on upper panels
ax_price.tick_params(labelbottom=False)
ax_volume.tick_params(labelbottom=False)
| Layout | Ratios | Use Case |
|--------|--------|----------|
| Price + Volume | [3, 1] | Simple OHLCV chart |
| Price + Volume + Indicator | [3, 1, 1] | Standard analysis view |
| Equity + Drawdown | [2, 1] | Performance review |
| Price + RSI + MACD | [3, 1, 1] | Full indicator stack |
import mplfinance as mpf
import pandas as pd
# df: DataFrame with DatetimeIndex, columns Open/High/Low/Close/Volume
ema20 = df["Close"].ewm(span=20).mean()
ema50 = df["Close"].ewm(span=50).mean()
ap = [
mpf.make_addplot(ema20, color="#ff6600", width=1.2),
mpf.make_addplot(ema50, color="#3399ff", width=1.2),
]
style = mpf.make_mpf_style(
base_mpf_style="nightclouds",
marketcolors=mpf.make_marketcolors(
up="#00ff88", down="#ff4444",
wick={"up": "#00ff88", "down": "#ff4444"},
edge={"up": "#00ff88", "down": "#ff4444"},
volume={"up": "#00ff88", "down": "#ff4444"},
),
facecolor="#1a1a2e", figcolor="#1a1a2e",
gridcolor="#333333", gridstyle="--",
)
mpf.plot(df, type="candle", style=style, addplot=ap,
volume=True, figsize=(14, 8),
title="Token / SOL — 15m", savefig="candles.png")
import numpy as np
import matplotlib.pyplot as plt
def plot_equity_drawdown(equity: pd.Series, title: str = "Portfolio") -> plt.Figure:
"""Plot equity curve with drawdown panel below."""
peak = equity.cummax()
drawdown = (equity - peak) / peak
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(14, 8),
height_ratios=[2, 1], sharex=True)
ax1.plot(equity.index, equity, color="#00ff88", linewidth=1.5)
ax1.plot(equity.index, peak, color="#555555", linewidth=0.8,
linestyle="--", label="Peak")
ax1.set_title(title, fontsize=14, fontweight="bold", color="white")
ax1.set_ylabel("Portfolio Value", fontsize=11)
ax1.legend(loc="upper left")
ax1.grid(True, alpha=0.3)
ax2.fill_between(equity.index, drawdown, 0, color="#ff4444", alpha=0.5)
ax2.set_ylabel("Drawdown", fontsize=11)
ax2.set_xlabel("Date", fontsize=11)
ax2.grid(True, alpha=0.3)
fig.tight_layout()
return fig
from scipy import stats
def plot_return_distribution(returns: pd.Series) -> plt.Figure:
"""Histogram of returns with normal fit and risk metrics."""
fig, ax = plt.subplots(figsize=(10, 6))
ax.hist(returns, bins=50, density=True, alpha=0.7,
color="#4488ff", edgecolor="#333333")
# Normal fit overlay
mu, sigma = returns.mean(), returns.std()
x = np.linspace(returns.min(), returns.max(), 200)
ax.plot(x, stats.norm.pdf(x, mu, sigma), color="#ffaa00",
linewidth=2, label=f"Normal(μ={mu:.4f}, σ={sigma:.4f})")
# VaR line
var_95 = returns.quantile(0.05)
ax.axvline(var_95, color="#ff4444", linestyle="--",
label=f"VaR 95%: {var_95:.4f}")
ax.set_title("Return Distribution", fontsize=14, fontweight="bold")
ax.set_xlabel("Return", fontsize=11)
ax.legend()
ax.grid(True, alpha=0.3)
fig.tight_layout()
return fig
def plot_correlation_heatmap(returns_df: pd.DataFrame) -> plt.Figure:
"""Correlation matrix heatmap with annotations."""
corr = returns_df.corr()
fig, ax = plt.subplots(figsize=(10, 8))
im = ax.imshow(corr, cmap="RdYlGn", vmin=-1, vmax=1, aspect="auto")
ax.set_xticks(range(len(corr.columns)))
ax.set_yticks(range(len(corr.columns)))
ax.set_xticklabels(corr.columns, rotation=45, ha="right")
ax.set_yticklabels(corr.columns)
for i in range(len(corr)):
for j in range(len(corr)):
ax.text(j, i, f"{corr.iloc[i, j]:.2f}",
ha="center", va="center", fontsize=9,
color="black" if abs(corr.iloc[i, j]) < 0.5 else "white")
fig.colorbar(im, ax=ax, shrink=0.8)
ax.set_title("Correlation Matrix", fontsize=14, fontweight="bold")
fig.tight_layout()
return fig
def plot_trades_on_price(
price: pd.Series,
entries: pd.DataFrame, # columns: date, price, side
exits: pd.DataFrame, # columns: date, price, pnl
) -> plt.Figure:
"""Price chart with entry/exit markers."""
fig, ax = plt.subplots(figsize=(14, 7))
ax.plot(price.index, price, color="#aaaaaa", linewidth=1)
# Entry markers
buy_mask = entries["side"] == "long"
ax.scatter(entries.loc[buy_mask, "date"], entries.loc[buy_mask, "price"],
marker="^", color="#00ff88", s=100, zorder=5, label="Buy")
ax.scatter(entries.loc[~buy_mask, "date"], entries.loc[~buy_mask, "price"],
marker="v", color="#ff4444", s=100, zorder=5, label="Short")
# Exit markers
win_mask = exits["pnl"] > 0
ax.scatter(exits.loc[win_mask, "date"], exits.loc[win_mask, "price"],
marker="x", color="#00ff88", s=80, zorder=5)
ax.scatter(exits.loc[~win_mask, "date"], exits.loc[~win_mask, "price"],
marker="x", color="#ff4444", s=80, zorder=5)
ax.set_title("Trades on Price", fontsize=14, fontweight="bold")
ax.legend()
ax.grid(True, alpha=0.3)
fig.tight_layout()
return fig
| Format | Method | Use Case |
|--------|--------|----------|
| PNG | fig.savefig("chart.png", dpi=150) | Sharing, embedding |
| SVG | fig.savefig("chart.svg") | Editing, scaling |
| HTML | fig.write_html("chart.html") (plotly) | Interactive exploration |
| Inline | plt.show() | Jupyter notebooks |
fig.savefig("chart.png", dpi=150, facecolor=fig.get_facecolor(),
edgecolor="none", bbox_inches="tight")
| Skill | Integration |
|-------|-------------|
| pandas-ta | Compute indicators, pass to addplot overlays |
| vectorbt | Extract equity curve and trade list for visualization |
| portfolio-analytics | Plot Sharpe, drawdown, and return metrics |
| risk-management | Visualize position limits and exposure over time |
| position-sizing | Chart position size vs account equity over time |
| regime-detection | Color background by detected market regime |
| correlation-analysis | Generate correlation heatmaps from return data |
references/chart_recipes.md — Complete code recipes for six common chart typesreferences/styling_guide.md — Dark theme setup, colors, typography, layout, and export settingsscripts/chart_generator.py — Generate four chart types from synthetic data (candlestick, equity, returns, trades)scripts/performance_report.py — Multi-chart performance report with summary statisticsdata-ai
DeFi yield evaluation including fee APR, real vs nominal yield, net APY after costs, and yield sustainability analysis
tools
Real-time Solana transaction and account streaming via Yellowstone gRPC (Geyser plugin)
tools
Large wallet monitoring, accumulation and distribution detection, and smart money signal generation for Solana tokens
tools
Wash sale detection under 2025 US crypto rules with 61-day window monitoring, disallowed loss tracking, and safe re-entry countdown