D3.js 数据可视化 - 生成交易图表、权益曲线、风险指标可视化
73
66%
Does it follow best practices?
Impact
78%
3.71xAverage score across 3 eval scenarios
Passed
No known issues
Optimize this skill with Tessl
npx tessl skill review --optimize ./.trae/skills/quant-visualization/SKILL.md此技能指导 Claude 使用 D3.js 生成交互式数据可视化,专门用于量化交易场景:权益曲线、交易分布、风险指标、策略对比等。
import * as d3 from "d3";
// 权益曲线 - 显示账户盈亏随时间变化
const drawEquityCurve = (data) => {
const width = 800;
const height = 400;
const margin = { top: 20, right: 30, bottom: 50, left: 60 };
const svg = d3.select("#equity-curve")
.append("svg")
.attr("width", width)
.attr("height", height);
// X轴 - 时间
const x = d3.scaleTime()
.domain(d3.extent(data, d => d.date))
.range([margin.left, width - margin.right]);
// Y轴 - 权益
const y = d3.scaleLinear()
.domain(d3.extent(data, d => d.equity))
.range([height - margin.bottom, margin.top]);
// 添加网格线
svg.append("g")
.attr("class", "grid")
.call(d3.axisLeft(y)
.tickSize(-(width - margin.left - margin.right))
.tickFormat("")
);
// 添加权益曲线
const line = d3.line()
.x(d => x(d.date))
.y(d => y(d.equity))
.curve(d3.curveMonotoneX);
svg.append("path")
.datum(data)
.attr("fill", "none")
.attr("stroke", "#10b981")
.attr("stroke-width", 2)
.attr("d", line);
// 添加最大回撤区域
const drawdownArea = d3.area()
.x(d => x(d.date))
.y0(d => y(d.equity))
.y1(d => y(d.peakEquity));
svg.append("path")
.datum(data)
.attr("fill", "rgba(239, 68, 68, 0.2)")
.attr("d", drawdownArea);
};// 交易 PnL 分布 - 直方图
const drawTradeDistribution = (trades) => {
const svg = d3.select("#trade-dist").append("svg");
// 计算分箱
const histogram = d3.histogram()
.value(d => d.pnl)
.domain([-500, 500])
.thresholds(50);
const bins = histogram(trades.map(d => d.pnl));
// 绘制柱状图
svg.selectAll(".bar")
.data(bins)
.enter()
.append("rect")
.attr("class", "bar")
.attr("x", d => x(d.x0))
.attr("width", d => Math.max(0, x(d.x1) - x(d.x0) - 1))
.attr("y", d => y(d.length))
.attr("height", d => height - margin.bottom - y(d.length))
.attr("fill", d => d.x0 < 0 ? "#ef4444" : "#10b981");
};// 货币对表现热力图
const drawSymbolHeatmap = (data) => {
const colorScale = d3.scaleSequential(d3.interpolateRdYlGn)
.domain([-50, 50]); // PnL % 范围
const cells = svg.selectAll(".cell")
.data(data)
.enter()
.append("g")
.attr("class", "cell");
cells.append("rect")
.attr("x", d => x(d.symbol))
.attr("y", d => y(d.timeframe))
.attr("width", x.bandwidth())
.attr("height", y.bandwidth())
.attr("fill", d => colorScale(d.pnlPct))
.attr("stroke", "#fff")
.attr("stroke-width", 2);
// 添加标签
cells.append("text")
.attr("x", d => x(d.symbol) + x.bandwidth() / 2)
.attr("y", d => y(d.timeframe) + y.bandwidth() / 2)
.attr("text-anchor", "middle")
.attr("dy", ".35em")
.text(d => `${d.pnlPct.toFixed(1)}%`);
};// 策略对比雷达图
const drawStrategyRadar = (strategies) => {
const metrics = ["Win Rate", "Profit Factor", "Sharpe", "Max DD", "Recovery"];
const angleSlice = Math.PI * 2 / metrics.length;
const radarLine = d3.lineRadial()
.angle(d => angleSlice * metrics.indexOf(d.metric))
.radius(d => r(d.value))
.curve(d3.curveLinearClosed);
// 为每个策略绘制雷达线
strategies.forEach((strategy, i) => {
const color = d3.schemeCategory10[i];
svg.append("path")
.datum(strategy.values)
.attr("d", radarLine)
.attr("fill", color)
.attr("fill-opacity", 0.3)
.attr("stroke", color)
.attr("stroke-width", 2);
});
};// 交易时间热力图(周 x 时段)
const drawTimeDistribution = (trades) => {
const days = ["Mon", "Tue", "Wed", "Thu", "Fri"];
const hours = Array.from({ length: 24 }, (_, i) => i);
// 聚合数据
const aggData = cross(days, hours).map(([day, hour]) => {
const dayTrades = trades.filter(t =>
t.day === day && t.hour === hour
);
return {
day, hour,
count: dayTrades.length,
pnl: d3.sum(dayTrades, d => d.pnl)
};
});
// 绘制热力图
const cells = svg.selectAll(".cell")
.data(aggData)
.enter()
.append("rect")
.attr("x", d => x(d.hour))
.attr("y", d => y(d.day))
.attr("width", x.bandwidth())
.attr("height", y.bandwidth())
.attr("fill", d => d.pnl > 0 ? "#10b981" : "#ef4444")
.attr("fill-opacity", d => Math.min(1, Math.abs(d.pnl) / 100));
};生成回测报告仪表板,包含:
1. 权益曲线(带最大回撤标记)
2. 回撤曲线
3. 月度收益柱状图
4. 胜率饼图
5. 盈亏比分布直方图实时交易监控面板:
1. 当前持仓汇总表
2. 风险敞口进度条
3. 未实现盈亏实时更新
4. 货币对表现热力图多策略对比:
1. 权益曲线叠加图
2. 回撤对比图
3. 夏普比率雷达图
4. 月度收益热力图对比风险分析可视化:
1. VaR(风险价值)分布图
2. 期望 shortfall 图
3. 相关性矩阵热力图
4. 波动率时间序列// 量化交易标准配色
const colors = {
profit: "#10b981", // 绿色
loss: "#ef4444", // 红色
neutral: "#6b7280", // 灰色
primary: "#3b82f6", // 蓝色
warning: "#f59e0b", // 橙色
danger: "#dc2626" // 深红
};// 使用 viewBox 实现响应式
svg.attr("viewBox", `0 0 ${width} ${height}`)
.attr("preserveAspectRatio", "xMidYMid meet");// 添加 Tooltip
const tooltip = d3.select("body")
.append("div")
.attr("class", "tooltip")
.style("opacity", 0);
bars.on("mouseover", function(event, d) {
tooltip.transition().duration(200).style("opacity", 1);
tooltip.html(`
<strong>Trade #${d.ticket}</strong><br/>
Symbol: ${d.symbol}<br/>
PnL: $${d.pnl.toFixed(2)}<br/>
Time: ${d.time}
`);
});// 平滑过渡
path.transition()
.duration(1000)
.ease(d3.easeCubicOut)
.attr("d", line);<!DOCTYPE html>
<html>
<head>
<script src="https://d3js.org/d3.v7.min.js"></script>
<style>
.dashboard { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; }
.chart { background: #1e293b; border-radius: 8px; padding: 20px; }
.title { color: #e2e8f0; font-size: 18px; margin-bottom: 10px; }
</style>
</head>
<body>
<div class="dashboard">
<div class="chart">
<div class="title">Equity Curve</div>
<div id="equity-curve"></div>
</div>
<div class="chart">
<div class="title">Trade Distribution</div>
<div id="trade-dist"></div>
</div>
<div class="chart">
<div class="title">Symbol Performance</div>
<div id="symbol-heatmap"></div>
</div>
<div class="chart">
<div class="title">Strategy Comparison</div>
<div id="strategy-radar"></div>
</div>
</div>
</body>
</html>npm install d3@7生成策略回测可视化报告:
1. 权益曲线(显示峰值和回撤)
2. 月度收益柱状图
3. 盈亏分布直方图
4. 连续亏损/盈利序列图
5. 将结果保存为 HTML 文件创建实时交易监控面板:
1. 当前持仓列表(可筛选货币对)
2. 总风险敞口仪表
3. 未实现盈亏实时更新
4. 胜率进度条
5. 响应式设计,适配移动端对比三个策略版本的表现:
1. 权益曲线叠加(不同颜色)
2. 回撤对比图
3. 夏普比率、胜率、盈亏比雷达图
4. 月度收益热力图
5. 生成可交互的 HTML 报告版本历史:
3069d33
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.