# 交互式图表 (/zh/features/analytics/interactive-charts)

如何看清策略实际做了什么？VBT 在 Python 中将回测、价格、指标、信号和参数结果绘制为交互式 Plotly 图表：放大查看单笔交易，悬停读取准确数值，并将任意图表组合在一张图中。

```python title="Plot a backtest with orders, trade P&L, a custom RSI panel, and drawdowns"
>>> data = vbt.YFData.pull("BTC-USD", start="2023-01-01", end="2024-01-01")
>>> rsi = data.run("rsi", window=14).rsi
>>> pf = vbt.PF.from_signals(data, rsi.vbt.crossed_below(30), rsi.vbt.crossed_above(70))

>>> def plot_rsi(pf, rsi, add_trace_kwargs=None, fig=None):  # (1)
...     rsi.rename("RSI").vbt.plot(add_trace_kwargs=add_trace_kwargs, fig=fig)

>>> pf.plot(
...     subplots=[
...         "orders",
...         "trade_pnl",
...         ("rsi", dict(title="RSI", plot_func=plot_rsi, rsi=rsi)),
...         "drawdowns",
...     ],
...     settings=dict(bm_returns=False),
... ).show()
```

1.  自定义面板是一个函数，向传入的子图中绘图。

2023 年比特币 RSI 策略图，包含买卖订单、交易盈亏、RSI 指标和回撤. [Figure data (JSON)](/assets/figures/features/analytics/interactive-charts-portfolio.82d6e04cdee9.json)

## 投资组合与交易图表 \[#portfolio-and-trade-charts]

`pf.plot()` 根据具名子图绘制仪表盘。内置子图包括
`orders`、`trades`、`trade_pnl`、`trade_signals`、`cumulative_returns`、`drawdowns`、`underwater`、`gross_exposure`、`allocations`、`cash`、`assets`
和 `value`，每个都可通过 `subplot_settings` 配置。每个子图也有独立方法，例如
`pf.plot_cumulative_returns()`、`pf.plot_underwater()`，以及展示多资产权重随时间变化的 `pf.plot_allocations()`。

记录也能自行绘图：`pf.trades.plot()` 显示每笔交易从入场到退出的过程及其利润，`pf.drawdowns.plot(top_n=5)`
则突出显示最大回撤。对于收益，一行代码就能绘制月收益日历热图：`pf.returns_acc.resample("M").ts_heatmap()`。

## 价格、指标和信号图表 \[#price-indicator-and-signal-charts]

数据对象可绘制带成交量的蜡烛图或 OHLC 图。通过传入 `fig`，可将指标和信号添加到同一张图中：

```python title="Overlay moving averages and crossover signals on candlesticks"
>>> sub = data.loc["2023-04-01":"2023-08-31"]
>>> fast = sub.close.rolling(10).mean()
>>> slow = sub.close.rolling(30).mean()
>>> entries = fast.vbt.crossed_above(slow)
>>> exits = fast.vbt.crossed_below(slow)

>>> fig = sub.plot(plot_volume=False)
>>> fast.rename("SMA 10").vbt.plot(fig=fig)
>>> slow.rename("SMA 30").vbt.plot(fig=fig)
>>> entries.vbt.signals.plot_as_entries(fast, fig=fig)  # (1)
>>> exits.vbt.signals.plot_as_exits(fast, fig=fig)
>>> fig.show()
```

1.  在快速均线上为每次入场绘制标记。

2023 年 4 至 8 月比特币蜡烛图，包含 10 天和 30 天均线，以及交叉入场和退出标记. [Figure data (JSON)](/assets/figures/features/analytics/interactive-charts-candlestick.5b9b028ce41e.json)

使用 VBT 构建的指标具有默认设置合理的 `plot` 方法，TA-Lib 指标则根据输出类型绘图，例如折线图或直方图。

## 热图及其他通用图表 \[#heatmaps-and-other-generic-plots]

任意 Series 或 DataFrame 都能通过访问器获得绘图方法：折线、散点、柱状、直方、箱线、热图和三维体积图。三个参数组成的参数网格可以转换为热图，并用滑块控制第三个参数：

```python title="Explore three RSI strategy parameters with a heatmap and a slider"
>>> btc = vbt.YFData.pull("BTC-USD", start="2020-01-01", end="2025-01-01")
>>> rsi = btc.run("rsi", window=14).rsi

>>> @vbt.parameterized(merge_func="concat")  # (1)
... def sharpe(lower, upper, sl_stop):
...     pf = vbt.PF.from_signals(
...         btc,
...         rsi.vbt.crossed_below(lower),
...         rsi.vbt.crossed_above(upper),
...         sl_stop=sl_stop,
...     )
...     return pf.sharpe_ratio

>>> sharpes = sharpe(
...     vbt.Param([20, 25, 30, 35, 40]),
...     vbt.Param([60, 65, 70, 75, 80]),
...     vbt.Param([0.05, 0.1, 0.2]),
... )
>>> sharpes.vbt.heatmap(x_level="lower", y_level="upper", slider_level="sl_stop").show()
```

1.  对每种参数组合运行函数，并拼接 75 个结果。

RSI 入场和退出阈值的夏普比率热图，使用滑块控制止损水平. [Figure data (JSON)](/assets/figures/features/analytics/interactive-charts-heatmap-slider.53955f7134c5.json)

如果 Plotly Express 中有您需要的图表，可从访问器调用，例如
`df.vbt.px.parallel_coordinates()`。交叉验证切分也有自己的图表，展示每次切分的训练和测试区间。

## 自定义 \[#customization]

每种绘图方法都接受用于轨迹的 `trace_kwargs`、用于将轨迹放入子图的
`add_trace_kwargs`，以及图形布局关键词。例如，`slow.vbt.plot(trace_kwargs=dict(line=dict(color="orange", dash="dash")), fig=fig)`
绘制一条橙色虚线。`vbt.make_subplots` 创建多面板图形；由于结果是标准 Plotly 图形，之后仍可使用 Plotly 的全部功能。

主题和默认设置位于 `vbt.settings.plotting`，例如使用 `vbt.settings.set_theme("dark")`
创建深色图表。对于夜间或周末休市的市场，`fig.auto_rangebreaks(freq="1D")` 会为缺失时间添加 Plotly 范围断点，让蜡烛相邻排列，而非留出空隙。

## 随新数据更新的图表 \[#charts-that-update-with-new-data]

您可以在保留布局和样式的同时，更新现有 Plotly 轨迹中的数据。将更新连接到 `DataUpdater`，即可在新 K 线到来时刷新蜡烛图，或在 notebook
小部件中更新价格和指标曲线。这适合持续观察序列最新部分，无需每次创建新图。

[数据流水线](/zh/features/data/financial-data-pipelines/)介绍定时数据更新，[实时模拟](/zh/features/backtesting/live-simulation/)介绍如何在新
K 线上继续运行投资组合。还可使用 `imageio` 将连续图表图像保存为 GIF 帧，回放图表的变化过程。

## 大数据与输出 \[#large-data-and-output]

跨越数年的分钟图包含数百万个数据点，浏览器绘制较慢。安装 `plotly-resampler` 后，设置
`vbt.settings.plotting["use_resampler"] = True`，图表将加载降采样视图，并随缩放逐步细化。也可以先选择较短区间再绘图，或先对投资组合重采样：`pf.resample("1D")`
返回总收益相同的日频投资组合，其图表每天绘制一个点。

## 分享交互式图表与导出图像 \[#share-interactive-charts-and-export-images]

使用 `fig.show()` 在 notebook 和浏览器中交互显示图形，使用 `fig.show_png()` 或 `fig.show_svg()` 显示静态图像，并通过
`fig.write_image()` 或 `fig.write_html()` 保存文件。静态图像由 Plotly 的 `kaleido`
包渲染，因此请先安装；如果导出卡住，请更新它。渲染器既可为单张图设置，也可全局设置。

HTML 导出保留缩放、悬停标签和图例控制，让其他人无需安装 Python 或 VBT，也能在浏览器中探索结果。默认情况下，Plotly 会将图表数据及其 JavaScript
库包含在文件中。如何保存图形或将多张图组合在一个页面，请参阅
[Plotly HTML 导出指南](https://plotly.com/python/interactive-html-export/)。报告或演示需要固定图像时，请使用 PNG 或 SVG。
