# 合成数据 (/zh/features/data/synthetic-data)

策略在从未发生过的价格上表现如何？VBT 在 Python 中生成合成价格数据：随机游走、几何布朗运动和完整 OHLC K
线。它们可通过随机种子复现，并以与真实市场数据相同的数据对象返回。在数百条合成路径上运行策略，可以显示其在指定模型下可能产生的结果范围。

```python title="Run one strategy on 500 random price paths"
>>> paths = vbt.GBMData.pull(  # (1)
...     [f"path_{i}" for i in range(500)],
...     start="2020-01-01",
...     end="2024-01-01",
...     timeframe="1d",
...     seed=42,
... )
>>> close = paths.get()
>>> close.shape
(1461, 500)

>>> fast = close.rolling(20).mean()
>>> slow = close.rolling(50).mean()
>>> pf = vbt.PF.from_signals(
...     close,
...     fast.vbt.crossed_above(slow),
...     fast.vbt.crossed_below(slow),
...     fees=0.001,
... )
>>> pf.sharpe_ratio.describe().round(3)
count    500.000
mean      -0.096
std        0.494
min       -1.598
25%       -0.437
50%       -0.129
75%        0.224
max        1.754
Name: sharpe_ratio, dtype: float64
>>> print(round((pf.sharpe_ratio > 0).mean(), 3))
0.406

>>> pf.sharpe_ratio.vbt.histplot(trace_kwargs=dict(nbinsx=40)).show()
```

1.  零漂移、日波动率为 1% 的几何布朗运动，每个标的一条独立路径。模型中没有内置可预测趋势。

均线交叉策略在 500 条合成随机价格路径上的夏普比率直方图. [Figure data (JSON)](/assets/figures/features/data/synthetic-sharpe-distribution.de0439809b7d.json)

即使模型没有内置可预测趋势，均线交叉策略仍在 41% 的路径上取得正夏普比率，最佳路径达到
1.75。这为同一策略在历史数据上的表现提供了比较依据。请观察跨路径的分布，而不要把最佳模拟结果当成通用及格线。

## 合成数据可以测试什么？ \[#what-can-you-test-with-synthetic-data]

希望控制测试条件时，可以使用生成路径：

*   在相同随机种子价格上比较策略修改。
*   在保持策略不变的情况下，尝试平静或更剧烈的市场。
*   在生成的 OHLC K 线上测试止损、限价和信号逻辑。
*   检查出乎意料的强劲结果是否也会出现在随机数据上。

生成数据与下载数据使用相同指标、回测和图表，无需数据提供商账户。历史数据上更广泛的验证，请参阅[稳健性与过拟合](/zh/features/optimization/robustness-and-overfitting/)。

## 生成器 \[#generators]

`vbt.RandomData` 对正态分布收益率进行复利累积，`vbt.GBMData`
模拟几何布朗运动。两者都接受初始值、均值、标准差和随机种子，并可按标的分别设置；也都能在任意索引或时间周期上生成任意数量的标的。使用随机种子后，每次运行都产生相同路径，让合成数据实验与已存数据实验一样可复现。对于随机收益率，`symmetric=True`
对损失进行变换，使相同幅度的一涨一跌在乘法复利上相互抵消，从而去除普通收益率的向下漂移。

您可以用某资产收益率估计生成器参数。`RandomData` 接受样本收益率的均值和标准差。对于 GBM，漂移、波动率和 `dt`
必须与所模拟的时间步长一致。这些描述的是简单模型：波动率恒定，没有聚集、自相关或厚尾。这些生成器检验规则是否在噪声中发现结构，而不是模拟真实市场交易方式。更真实的动态请按下文编写自己的模型。

## 比较市场情景 \[#compare-market-scenarios]

参数可按标的不同，因此每个标的都能代表一种情景。这里两条路径使用相同随机抽样，但波动率设置不同：

```python title="Compare volatility scenarios with the same random draws"
>>> scenarios = vbt.GBMData.pull(
...     ["calm", "volatile"],
...     start="2024-01-01",
...     periods=252,
...     timeframe="1d",
...     mean=0.0,
...     std=vbt.symbol_dict({"calm": 0.005, "volatile": 0.02}),
...     seed=42,
...     split_seed=False,
... )
>>> scenarios.get().shape
(252, 2)

>>> (scenarios.get().pct_change().std() * 100).round(2)
symbol
calm        0.48
volatile    1.94
dtype: float64
```

输出为日收益率的样本标准差，以百分比表示。`split_seed=False` 让不同情景使用相同随机抽样，以单独考察波动率变化。默认情况下，VBT 为每个标的派生独立随机种子，如 500
条路径示例所示。将 `scenarios.get()` 传入策略，即可比较两种设置下的行为。

## 合成 OHLC K 线 \[#synthetic-ohlc-bars]

`vbt.RandomOHLCData` 和 `vbt.GBMOHLCData` 在每根 K 线内部模拟逐笔价格，并聚合为开盘、最高、最低和收盘价，因此也能测试止损、限价和 K
线内部逻辑。模拟逐笔数量由 `n_ticks` 控制，也可逐 K 线变化。下方[合成 OHLC](#synthetic-ohlc)功能介绍展示了生成的蜡烛图。

真实数据也能转换为合成数据。`data.mirror_ohlc()` 反转对数收益率，并围绕镜像路径变换其他 OHLC 价格。在原始数据及其镜像上比较策略，可以探索价格移动反向时策略行为改变多少。

## 自定义生成器 \[#custom-generators]

任意模型都能成为数据类。继承 `vbt.SyntheticData`
并为每个标的返回一个序列，该类便会像其他数据源一样处理标的、随机种子和索引。您还可提供更新方法，从模型先前状态继续运行。这里收益率服从 Student t 分布，产生正态收益率所缺少的厚尾：

```python title="Generate fat-tailed price paths with a custom class"
>>> class StudentTData(vbt.SyntheticData):
...     @classmethod
...     def generate_key(
...         cls, key, index, df=3, scale=0.01, start_value=100.0, seed=None, **kwargs
...     ):
...         if seed is not None:
...             np.random.seed(seed)
...         returns = np.random.standard_t(df, size=len(index)) * scale
...         return pd.Series(start_value * np.cumprod(1 + returns), index=index)

>>> fat = StudentTData.pull(
...     ["A", "B"],
...     start="2024-01-01",
...     end="2025-01-01",
...     timeframe="1d",
...     seed=42,
... )
>>> fat.get().pct_change().kurt().round(2)  # (1)
symbol
A     5.60
B    10.26
dtype: float64
```

1.  超额峰度显著高于零；零是正态分布收益率的超额峰度。

## 合成 OHLC \[#synthetic-ohlc]

新增于 1.2.1

✅ 现在提供生成合成 OHLC 数据的新基础模型，尤其适合检测数据泄漏。

```python title="Generate 3 months of synthetic data using Geometric Brownian Motion"
>>> data = vbt.GBMOHLCData.pull("R", start="2022-01", end="2022-04", seed=42)
>>> data.plot().show()
```

使用几何布朗运动生成的三个月合成 OHLC 数据. [Figure data (JSON)](/assets/figures/features/data/synthetic-ohlc.2cf9918db1d2.json)
