Skip to content

10.2 生成式AI

概念详解

生成式AI(Generative AI)在量化金融中正在打开全新的可能性。与传统的判别式模型(如预测收益率方向)不同,生成模型学习数据的底层分布,能够生成与真实数据统计特征相似的新样本。这一能力在量化金融中有着多种重要应用。

生成式AI在量化金融中的主要应用方向:

1. 合成数据生成(Synthetic Data Generation) 金融数据的历史样本量通常不足以训练复杂的深度学习模型(尤其是对于低频策略,独立样本数可能只有几百个)。生成模型可以通过学习真实数据的分布来生成无限的"伪样本",用于:

  • 增强训练数据:扩充有限的训练集,缓解过拟合
  • 压力测试:生成极端市场场景的样本,评估策略的尾部风险
  • 隐私保护:生成去标识化的合成数据集,在不暴露真实客户数据的前提下进行模型开发

2. 市场情景生成(Scenario Generation) 生成模型可以学习市场在不同Regime下的联合分布,生成各种可能的未来路径(而非单一的点预测),用于:

  • 风险管理的蒙特卡洛模拟
  • 投资组合压力测试
  • 期权定价的改进

3. 异常检测(Anomaly Detection) 通过训练生成模型学习"正常"市场行为的分布,当新的数据落在低概率区域时,将其标记为异常。这在检测市场操纵、闪崩预警等场景中有应用。

4. 大语言模型(LLM)辅助量化

  • 自动化研报分析:解析分析师报告、电话会议记录中的关键信息
  • 因子挖掘:通过自然语言指令自动生成和测试候选因子
  • 代码生成:辅助编写和调试量化策略代码
  • 知识提取:从学术论文中提取可测试的量化策略

核心生成模型类型:

  • GAN(生成对抗网络):通过生成器与判别器的博弈学习数据分布,擅长生成逼真的金融时间序列
  • VAE(变分自动编码器):学习数据的概率潜在表示,可用于生成和异常检测
  • Diffusion Models:通过逐步去噪生成数据,在图像生成领域取得突破后,正在被应用到时间序列生成中
  • GPT/LLM:基于Transformer的生成式语言模型,在文本分析和代码生成中有广泛应用
名词解释:GAN

生成对抗网络,通过生成器与判别器的博弈来学习真实数据的分布,可生成逼真的金融时间序列用于数据增强。

名词解释:扩散模型(Diffusion Models)

一类生成模型,通过逐步向数据添加噪声(前向过程)然后学习反向去噪(逆向过程)来生成新样本。在金融时间序列生成中展现出优于GAN的稳定性和多样性。

名词解释:变分自动编码器(VAE)

一种将输入编码为概率分布(而非确定性的点)的自动编码器,可以生成具有连续性和多样性的新样本。

数学原理

GAN的博弈框架

GAN由两个神经网络组成:生成器 G 和判别器 D。两者进行极小极大博弈:

$$\min_G \max_D \; \mathbb{E}_{x\sim p_{data}}[\log D(x)] + \mathbb{E}_{z\sim p_z}[\log(1 - D(G(z)))]$$
  • 生成器 G(z) 将随机噪声 z 映射为"假"数据
  • 判别器 D(x) 判断输入 x 是真实数据(输出接近1)还是生成数据(输出接近0)
  • G 希望最大化 D(G(z))(让判别器犯错),D 希望正确区辨真假

VAE的ELBO目标

VAE通过最大化证据下界(ELBO)来学习:

$$\mathcal{L}_{ELBO} = \mathbb{E}_{q_\phi(z|x)}[\log p_\theta(x|z)] - D_{KL}(q_\phi(z|x) \| p(z))$$

第一项是重建误差(生成的样本应尽可能像原始输入),第二项是KL散度(后验分布应尽可能接近先验)。

扩散模型的前向与反向过程

前向过程(加噪):

$$q(x_t|x_{t-1}) = \mathcal{N}(x_t; \sqrt{1-\beta_t}x_{t-1}, \beta_t I)$$

反向过程(去噪):

$$p_\theta(x_{t-1}|x_t) = \mathcal{N}(x_{t-1}; \mu_\theta(x_t, t), \Sigma_\theta(x_t, t))$$

训练目标是预测每一步添加的噪声:

$$\mathcal{L} = \mathbb{E}_{t, x_0, \epsilon}\left[\|\epsilon - \epsilon_\theta(x_t, t)\|^2\right]$$

Python实战

📌 案例1:GAN结构示意

PYTHON3 行 · 89 B
📄此处有展示代码3 行 · 89 B展开 ▼
python
generator = build_generator()
discriminator = build_discriminator()
# 对抗训练循环
点击展开可浏览运行结果
📘 本段为公式演示片段(伪代码占位符,无完整上下文)

📌 案例2:金融时间序列GAN(TimeGAN概念实现)

PYTHON130 行 · 5.0 KB
📄此处有展示代码130 行 · 5.0 KB展开 ▼
python
import numpy as np
import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset

class FinancialGAN:
    """
    简化版金融时间序列GAN
    
    生成器: 从噪声生成收益率序列
    判别器: 区辩真实 vs 生成的收益率序列
    """
    
    def __init__(self, seq_length=60, feature_dim=5, latent_dim=32):
        self.seq_length = seq_length
        self.feature_dim = feature_dim
        self.latent_dim = latent_dim
        
        # 生成器
        self.generator = nn.Sequential(
            nn.Linear(latent_dim, 128),
            nn.LeakyReLU(0.2),
            nn.Linear(128, 256),
            nn.LeakyReLU(0.2),
            nn.Linear(256, seq_length * feature_dim),
            nn.Tanh()  # 输出范围 [-1, 1]
        )
        
        # 判别器
        self.discriminator = nn.Sequential(
            nn.Linear(seq_length * feature_dim, 256),
            nn.LeakyReLU(0.2),
            nn.Dropout(0.3),
            nn.Linear(256, 128),
            nn.LeakyReLU(0.2),
            nn.Dropout(0.3),
            nn.Linear(128, 1),
            nn.Sigmoid()
        )
        
        self.g_optimizer = optim.Adam(self.generator.parameters(), lr=0.0002, betas=(0.5, 0.999))
        self.d_optimizer = optim.Adam(self.discriminator.parameters(), lr=0.0002, betas=(0.5, 0.999))
        self.criterion = nn.BCELoss()
    
    def train(self, real_data, n_epochs=100, batch_size=32):
        """训练GAN"""
        real_data = torch.FloatTensor(real_data)
        dataset = TensorDataset(real_data)
        dataloader = DataLoader(dataset, batch_size=batch_size, shuffle=True)
        
        for epoch in range(n_epochs):
            for batch_idx, (real_batch,) in enumerate(dataloader):
                batch_size_actual = real_batch.size(0)
                
                # 真实标签为1,虚假标签为0
                real_labels = torch.ones(batch_size_actual, 1)
                fake_labels = torch.zeros(batch_size_actual, 1)
                
                # === 训练判别器 ===
                self.d_optimizer.zero_grad()
                
                # 真实数据损失
                real_output = self.discriminator(real_batch.view(batch_size_actual, -1))
                d_real_loss = self.criterion(real_output, real_labels)
                
                # 虚假数据损失
                noise = torch.randn(batch_size_actual, self.latent_dim)
                fake_data = self.generator(noise)
                fake_output = self.discriminator(fake_data.detach().view(batch_size_actual, -1))
                d_fake_loss = self.criterion(fake_output, fake_labels)
                
                d_loss = d_real_loss + d_fake_loss
                d_loss.backward()
                self.d_optimizer.step()
                
                # === 训练生成器 ===
                self.g_optimizer.zero_grad()
                
                noise = torch.randn(batch_size_actual, self.latent_dim)
                fake_data = self.generator(noise)
                fake_output = self.discriminator(fake_data.view(batch_size_actual, -1))
                g_loss = self.criterion(fake_output, real_labels)  # 生成器希望被判定为真
                
                g_loss.backward()
                self.g_optimizer.step()
            
            if epoch % 20 == 0:
                print(f"Epoch {epoch}: D_loss={d_loss.item():.4f}, G_loss={g_loss.item():.4f}")
    
    def generate(self, n_samples):
        """生成合成金融时间序列"""
        self.generator.eval()
        with torch.no_grad():
            noise = torch.randn(n_samples, self.latent_dim)
            synthetic = self.generator(noise)
            synthetic = synthetic.view(n_samples, self.seq_length, self.feature_dim)
            return synthetic.numpy()

# ===== 示例:使用GAN生成合成收益率数据 =====
np.random.seed(42)
n_sequences = 500
seq_len = 60
n_features = 5

# 生成真实数据(模拟多资产收益率)
real_returns = np.random.randn(n_sequences, seq_len, n_features) * 0.01
# 加入一些真实数据的统计特征:波动率聚类
for i in range(n_sequences):
    regime = np.random.choice([0.5, 1.0, 2.0], p=[0.2, 0.6, 0.2])
    real_returns[i] *= regime

# 训练GAN(概念演示)
print("金融时间序列GAN演示:")
print(f"  真实数据形状: {real_returns.shape}")
print(f"  生成器将在 {seq_len * n_features} 维空间中学习\n")

gan = FinancialGAN(seq_length=seq_len, feature_dim=n_features, latent_dim=32)

# gan.train(real_returns, n_epochs=200)  # 实际训练时取消注释
# synthetic_data = gan.generate(100)
# 
# # 验证生成数据的统计特征
# print("生成数据的统计验证:")
# print(f"  真实数据均值: {real_returns.mean():.6f}")
# print(f"  合成数据均值: {synthetic_data.mean():.6f}")
# print(f"  真实数据标准差: {real_returns.std():.6f}")
# print(f"  合成数据标准差: {synthetic_data.std():.6f}")

print("GAN模型结构已创建,取消注释以运行训练")
点击展开可浏览运行结果
金融时间序列GAN演示:
  真实数据形状: (500, 60, 5)
  生成器将在 300 维空间中学习

📌 案例3:LLM辅助因子挖掘

PYTHON43 行 · 1.7 KB
📄此处有展示代码43 行 · 1.7 KB展开 ▼
python
def llm_factor_generation_example():
    """
    使用LLM自动生成候选因子代码
    
    实际应用中,可以通过API调用GPT-4/Claude等LLM,
    根据自然语言描述生成因子计算代码
    """
    
    prompt_template = """
    请根据以下因子描述,生成Python代码来计算这个量化因子:
    
    因子名称: {factor_name}
    因子描述: {description}
    数据变量: df (pandas DataFrame, columns包括: open, high, low, close, volume)
    
    要求:
    1. 返回一个pandas Series作为因子值
    2. 处理缺失值和异常值
    3. 在代码注释中说明计算逻辑
    """
    
    examples = [
        {
            'factor_name': 'Amihud非流动性',
            'description': '衡量股票的流动性不足程度,定义为日收益率的绝对值除以日成交金额的平均值。非流动性越高,交易成本越大。',
        },
        {
            'factor_name': '价格延迟因子',
            'description': '衡量价格对市场信息反应的延迟程度。将股票日收益率对同期和滞后N期的市场收益率做回归,计算滞后项回归系数之和占总回归系数的比例。',
        },
        {
            'factor_name': '日内动量',
            'description': '用开盘后第一个小时的收益率(开盘价到10:30的价格变化)预测最后一个小时的收益率(14:00到收盘的价格变化)。使用过去M天的数据进行统计。',
        }
    ]
    
    print("LLM辅助因子挖掘示例:")
    for ex in examples:
        print(f"\n  因子: {ex['factor_name']}")
        print(f"  描述: {ex['description']}")
        print(f"  [提示词已生成,调用LLM API即可获得因子代码]")

llm_factor_generation_example()
点击展开可浏览运行结果
LLM辅助因子挖掘示例:

  因子: Amihud非流动性
  描述: 衡量股票的流动性不足程度,定义为日收益率的绝对值除以日成交金额的平均值。非流动性越高,交易成本越大。
  [提示词已生成,调用LLM API即可获得因子代码]

  因子: 价格延迟因子
  描述: 衡量价格对市场信息反应的延迟程度。将股票日收益率对同期和滞后N期的市场收益率做回归,计算滞后项回归系数之和占总回归系数的比例。
  [提示词已生成,调用LLM API即可获得因子代码]

  因子: 日内动量
  描述: 用开盘后第一个小时的收益率(开盘价到10:30的价格变化)预测最后一个小时的收益率(14:00到收盘的价格变化)。使用过去M天的数据进行统计。
  [提示词已生成,调用LLM API即可获得因子代码]

📌 案例4:使用生成模型进行压力测试

PYTHON51 行 · 1.7 KB
📄此处有展示代码51 行 · 1.7 KB展开 ▼
python
def generate_extreme_scenarios(n_scenarios=1000, base_mu=0.0005, base_sigma=0.01):
    """
    使用参数化方法生成极端市场场景用于压力测试
    
    该方法利用Copula + 尾部依赖来生成多资产极端共跌场景
    """
    from scipy.stats import norm, t as t_dist
    
    results = []
    
    for i in range(n_scenarios):
        # 生成相关性矩阵(随机但保持正定性)
        n_assets = 5
        random_corr = np.random.uniform(0.3, 0.8, size=(n_assets, n_assets))
        random_corr = (random_corr + random_corr.T) / 2
        np.fill_diagonal(random_corr, 1.0)
        
        try:
            L = np.linalg.cholesky(random_corr)
        except np.linalg.LinAlgError:
            continue
        
        # 使用t-Copula(胖尾)生成联合场景
        df = 3  # 自由度=3,尾部很厚
        z = np.random.randn(n_assets)
        u = L @ z
        
        # t分布缩放(引入共线性极端事件)
        chi = np.random.chisquare(df) / df
        scenarios = u / np.sqrt(chi) * base_sigma * 3  # 3倍波动
        
        results.append({
            'scenario_id': i,
            'returns': scenarios,
            'max_loss': scenarios.min(),
            'correlation': random_corr[0, 1],
            'total_shock': np.abs(scenarios).sum()
        })
    
    # 找出Top 10最极端的场景
    results.sort(key=lambda x: x['total_shock'], reverse=True)
    
    print("极端场景压力测试:")
    print("-" * 50)
    for i, r in enumerate(results[:5]):
        print(f"场景 {r['scenario_id']}: 最大跌幅={r['max_loss']:.2%}, "
              f"总冲击={r['total_shock']:.2%}")
    
    return results

extreme_scenarios = generate_extreme_scenarios(500)
点击展开可浏览运行结果
极端场景压力测试:
--------------------------------------------------
场景 202: 最大跌幅=-32.87%, 总冲击=113.86%
场景 92: 最大跌幅=18.29%, 总冲击=112.30%
场景 297: 最大跌幅=-22.80%, 总冲击=78.66%
场景 112: 最大跌幅=-22.19%, 总冲击=71.06%
场景 486: 最大跌幅=-19.22%, 总冲击=69.61%

常见误区

误区1:GAN生成的金融数据可以替代真实数据。 GAN生成的数据可以复现真实数据的统计特征(均值、方差、自相关等),但不能创造真实数据中没有的信息。使用GAN数据进行回测可能严重低估真实风险。

误区2:LLM可以直接用来选股。 LLM虽然在文本理解方面表现出色,但它们不是为数值预测设计的。LLM更适合作为量化工作流中的"辅助工具"(代码生成、文本分析、因子描述),而非"决策引擎"。

误区3:生成的合成数据越多越好。 数据增强有边际递减效应。1000个真实样本+9000个合成样本的训练效果,通常不如1000个真实样本+合适的正则化。合成数据主要用于极端场景的覆盖,而非简单堆量。

误区4:生成模型的评估容易。 判断生成数据"好不好"是困难的。视觉检查、分布匹配度量(MMD)、自相关函数比较等都不完美。金融时间序列的细微结构(如波动率聚类的精确模式)很容易被度量的平均行为掩盖。

误区5:LLM生成的策略代码可以直接实盘使用。 LLM生成的代码可能包含逻辑错误、前视偏差、或使用了已过时的API。所有LLM生成的代码都需要经过严格的代码审查、回测验证和模拟交易测试。

实战练习

练习1: 实现一个简化版的TimeGAN(时间序列GAN)来生成股票收益率序列:

  • 使用LSTM作为生成器和判别器的核心
  • 在训练中同时优化监督损失(前后时刻的一致性)和对抗损失
  • 生成的序列与真实序列比较:均值、标准差、偏度、峰度、自相关函数、波动率聚类
  • 分析:生成数据在哪一维度上最难"骗过"判别器?

练习2: 使用LLM API(如OpenAI GPT-4或Anthropic Claude)实现以下自动化流水线:

  • Step 1:给定一篇学术论文标题,自动生成该论文提出的因子计算代码
  • Step 2:自动生成该因子的回测代码
  • Step 3:分析回测结果并生成评估报告
  • 评估:LLM生成的代码质量如何?需要进行多少人工修正?

练习3: 训练一个VAE模型用于市场异常检测:

  • 使用真实交易日数据训练VAE
  • 计算每个交易日的重建误差(reconstruction error)
  • 设定阈值,标记重建误差异常高的交易日
  • 检查这些异常交易日是否对应已知的市场事件(闪崩、政策冲击)

延伸阅读

  1. Goodfellow, I., et al. (2014). Generative Adversarial Nets. NeurIPS. — GAN的原始论文。
  2. Yoon, J., et al. (2019). Time-series Generative Adversarial Networks. NeurIPS. — TimeGAN的原始论文,专门用于时间序列生成。
  3. Wiese, M., et al. (2020). Quant GANs: Deep Generation of Financial Time Series. Quantitative Finance, 20(9), 1419-1440. — GAN在金融时间序列生成中的应用。
  4. Assefa, S. A., et al. (2020). Generating Synthetic Data in Finance: Opportunities, Challenges and Pitfalls. SSRN. — 合成数据在金融中的机遇与陷阱。
  5. Lopez-Lira, A., & Tang, Y. (2023). Can ChatGPT Forecast Stock Price Movements? Return Predictability and Large Language Models. SSRN. — LLM预测股票收益的最新研究。

本章要点

  • GANVAE是金融合成数据生成的主要工具,可用于数据增强和压力测试
  • 生成模型的输出不能替代真实数据——合成数据只能复现统计特征,不能创造真实Alpha
  • 大语言模型(LLM)在量化工作流中非常有价值,但最适合作为辅助工具而非决策引擎
  • 扩散模型(Diffusion Models)在时间序列生成中展现出优于GAN的潜力
  • 生成数据的质量评估比生成本身更困难——细微的结构差异可能在回测中被放大
  • 所有AI生成的代码或信号都需要严格的验证流程才能进入实盘