Py学习  »  Python

收益率从 32% 飙升至 168%!用 Python 贝叶斯优化打造超级交易策略

数据科学实战 • 9 月前 • 582 次点击  

欢迎加入专注于财经数据与量化投研的【数据科学实战】知识星球!在这里,您将获取持续更新的《财经数据宝典》和《量化投研宝典》,这两部宝典相辅相成,为您在量化投研道路上提供明确指引。 我们提供了精选的国内外量化投研的 180+ 篇高质量文章,并每日更新最新研究成果,涵盖策略开发、因子分析、风险管理等核心领域。 无论您是量化投资新手还是经验丰富的研究者,星球社区都能帮您少走弯路,事半功倍,共同探索数据驱动的投资世界!

引言

在量化交易的世界里,策略的参数选择往往决定了最终的成败。许多交易者习惯凭经验或感觉“手动”调整参数,这不仅效率低下,而且很难找到最优解。

这就好比在大海捞针,你可能永远不知道是否存在更好的参数组合。

今天我们要介绍的案例来自 Brian Hulela,他通过 贝叶斯优化 (Bayesian Optimization) 技术,将一个经典的 Ichimoku Cloud (一目均衡表) 交易策略的四年期回报率,从原本不错的 31.77% 惊人地提升到了 **167.50%**,同时还将最大回撤 (Max Drawdown) 从 -32% 降低到了 -21%。

本文将带你一步步通过 Python 复现这个过程,看看数据科学是如何赋能金融交易的。

什么是 Ichimoku 策略与贝叶斯优化?

在开始代码实战之前,我们先简单理解两个核心概念:

  1. **Ichimoku Cloud (一目均衡表)**:这是一种多功能的如意指标,用于定义支撑位和阻力位,识别趋势方向,衡量动量并提供交易信号。它主要由 Tenkan (转折线)、Kijun (基准线) 和 Senkou B (先行带 B) 等线条组成。
  2. 贝叶斯优化:这是一种寻找函数最大值或最小值的策略。与暴力尝试所有可能的参数组合 (网格搜索) 不同,贝叶斯优化会根据之前的测试结果来“智能”地猜测下一组最可能带来更好结果的参数,从而高效地找到最优解。

Python 实战案例

接下来,我们将使用 yfinance 获取数据,并利用 scikit-optimize 库进行参数优化。

1. 环境准备

首先,我们需要安装必要的 Python 库。

# 安装必要的软件包
# yfinance: 下载历史股价数据
# matplotlib: 绘图可视化
# tabulate: 格式化表格输出
# scikit-optimize: 执行贝叶斯优化
%pip install yfinance matplotlib tabulate scikit-optimize -q

导入所需的库:

import yfinance as yf
import pandas as pd
import matplotlib.pyplot as plt
from tabulate import tabulate
from skopt import gp_minimize
from skopt.space import Integer
import numpy as np

# 设置绘图风格 (可选)
plt.style.use('seaborn-v0_8')

2. 获取历史数据

在这个案例中,我们以  AAPL (苹果公司) 从 2020 年到 2024 年的股票数据为例。

# 下载历史股票数据
symbol = "AAPL"
data = yf.download(symbol, start="2020-01-01", end="2024-12-31")

# 扁平化多层列索引 (处理 yfinance 新版格式)
if isinstance(data.columns, pd.MultiIndex):
    data.columns = data.columns.get_level_values(0)

# 查看前几行数据
print(data.head())

3. 定义 Ichimoku 策略逻辑

这是核心部分。我们需要编写一个函数,根据输入的参数 (Tenkan,Kijun,Senkou B 的周期) 计算指标,生成买卖信号,并计算回测的收益率。

策略逻辑如下:

  • 买入信号:收盘价高于云带 (Senkou A 和 B 的最大值),且 Tenkan 线金叉 Kijun 线。
  • 卖出信号:收盘价跌破云带。
def ichimoku_signals(data, tenkan_period, kijun_period, senkou_b_period):
    """
    计算 Ichimoku 指标并进行简单的回测
    """

    df = data.copy()
    high = df['High']
    low = df['Low']
    
    # 1. 计算 Ichimoku 线条
    # Tenkan-sen (转折线): (过去 N 期的最高价 + 最低价) / 2
    df['tenkan'] = (high.rolling(tenkan_period).max() + low.rolling(tenkan_period).min()) / 2
    
    # Kijun-sen (基准线): (过去 M 期的最高价 + 最低价) / 2
    df['kijun'] = (high.rolling(kijun_period).max() + low.rolling(kijun_period).min()) / 2
    
    # Senkou Span A (先行带 A): (Tenkan + Kijun) / 2,向未来平移 Kijun 周期
    df['senkou_a'] = ((df['tenkan'] + df['kijun']) / 2).shift(kijun_period)
    
    # Senkou Span B (先行带 B): (过去 P 期的最高价 + 最低价) / 2,向未来平移 Kijun 周期
    df['senkou_b'] = ((high.rolling(senkou_b_period).max() + low.rolling(senkou_b_period).min()) / 2).shift(kijun_period)
    
     # 2. 生成信号
    # 价格在云带之上
    df['above_cloud'] = df['Close'] > df[['senkou_a''senkou_b']].max(axis=1)
    
    # Tenkan 上穿 Kijun (金叉)
    # 当前 Tenkan > Kijun 且 上一期 Tenkan <= 上一期 Kijun
    df['tenkan_cross'] = (df['tenkan'] > df['kijun']) & (df['tenkan'].shift(1) <= df['kijun'].shift(1))
    
    # 综合买入信号
    df['signal'] = np.where(df['above_cloud'] & df['tenkan_cross'], 10)
    
    # 3. 回测逻辑
    balance = 10000  # 初始资金 10000 美元
    position = 0     # 持仓状态
    equity_curve = []
    
    for i in range(len(df)):
        current_close = df['Close'].iloc[i]
        
        # 买入逻辑
        if df['signal'].iloc[i] == 1 and position == 0:
            position = balance / current_close
            balance = 0
        
        # 卖出/止损逻辑: 价格跌破云带
        elif position > 0 and current_close < df[['senkou_a''senkou_b']].min(axis=1).iloc[i]:
            balance = position * current_close
            position = 0
            
        # 记录每日权益
        current_equity = balance + position * current_close
        equity_curve.append(current_equity)
        
    df['equity'] = equity_curve
    
    # 计算总回报率
    total_return = (df['equity'].iloc[-1] - 10000) / 10000 * 100
    
    return df, total_return

4. 使用贝叶斯优化寻找最佳参数

我们定义一个目标函数。因为优化器通常是寻找“最小值”,而我们想要“最大化”收益,所以我们返回收益率的负数。

# 定义目标函数
def objective(params):
    tenkan, kijun, senkou_b = params
    # 运行策略并获取回报率
    _, total_return = ichimoku_signals(data, tenkan, kijun, senkou_b)
    # 返回负值,因为 gp_minimize 是求最小值的
    return -total_return

# 定义参数的搜索空间
# Tenkan 周期范围: 5 到 20
# Kijun 周期范围: 20 到 50
# Senkou B 周期范围: 40 到 100
search_space = [
    Integer(520, name='tenkan_period'),
    Integer(2050, name='kijun_period'),
    Integer(40100, name='senkou_b_period')
]

# 运行贝叶斯优化
print("开始优化参数,请稍候...")
result = gp_minimize(
    objective, 
    search_space, 
    n_calls=25,       # 尝试 25 次组合
    random_state=42   # 保证结果可复现
)

print("优化完成!")

5. 结果分析与可视化

优化完成后,我们提取最佳参数,并再次运行策略以查看详细表现。

best_tenkan, best_kijun, best_senkou_b = result.x
best_return = -result.fun

# 使用优化后的参数运行策略
data_optimized, final_return = ichimoku_signals(data.copy(), best_tenkan, best_kijun, best_senkou_b)

# 计算最大回撤 (Max Drawdown)
max_equity = data_optimized['equity'].cummax()
drawdown = (data_optimized['equity'] - max_equity) / max_equity
max_drawdown = drawdown.min() * 100

# 打印结果表格
stats = [
    ["优化后的 Tenkan 周期", best_tenkan],
    ["优化后的 Kijun 周期", best_kijun],
    ["优化后的 Senkou B 周期", best_senkou_b],
    ["预期总回报率"f"{best_return:.0f}%"],
    ["最大回撤"f"{max_drawdown:.0f}%"]
]

print(tabulate(stats, headers=["指标""数值"], tablefmt="rounded_outline"))

输出结果示例:

╭──────────────────────┬───────╮
│ 指标                 │ 数值  │
├──────────────────────┼───────┤
│ 优化后的 Tenkan 周期  │ 19    │
│ 优化后的 Kijun 周期   │ 20    │
│ 优化后的 Senkou B 周期│ 98    │
│ 预期总回报率          │ 168%  │
│ 最大回撤             │ -21%  │
╰──────────────────────┴───────╯

通过对比,我们发现:

  • 手动参数:回报率约 31.77%,最大回撤 -32%。
  • 优化参数:回报率飙升至 168%,最大回撤缩小至 -21%。

这说明优化后的策略不仅更赚钱,而且风险更低 (回撤更小)。

最后,我们可以绘制出优化后的交易信号图:

# 提取买卖点用于绘图
buy_signals = data_optimized[(data_optimized['signal'] == 1) & (data_optimized['signal'].shift(1) == 0)]
# 注意:这里为了简化绘图,只标记开仓点,实际平仓逻辑在回测循环中

plt.figure(figsize=(148))
plt.plot(data_optimized.index, data_optimized['Close'], label="收盘价", color='black', alpha=0.6)

# 绘制云带
plt.fill_between(
    data_optimized.index, 
    data_optimized['senkou_a'], 
    data_optimized['senkou_b'],
    where=data_optimized['senkou_a'] >= data_optimized['senkou_b'],
    color='lightgreen', alpha=0.3, label='看涨云带'
)
plt.fill_between(
    data_optimized.index, 
    data_optimized['senkou_a'], 
    data_optimized['senkou_b'],
    where=data_optimized['senkou_a'] < data_optimized['senkou_b'],
    color='lightcoral', alpha=0.3, label='看跌云带'
)

plt.title(f"{symbol} Ichimoku 策略 (优化后参数) 交易信号")
plt.xlabel("日期")
plt.ylabel("价格 ($)")
plt.legend()
plt.show()

总结

本文展示了如何利用 Python 的  scikit-optimize 库对经典的 Ichimoku 交易策略进行贝叶斯优化。

  1. 告别盲猜:通过算法自动寻找参数,替代了低效的手动尝试。
  2. 显著提升:在 AAPL 的案例中,回报率从 30% 级跃升至 160% 级,且风险控制更好。
  3. 方法通用:这套贝叶斯优化的逻辑不仅限于 Ichimoku,你可以将其应用到 MACD,RSI 或任何带有参数的量化策略中。

量化交易的核心在于数据驱动。当你下次构建策略时,不妨试试让算法来帮你做决定。

参考文章

加入专注于财经数据与量化投研的知识星球【数据科学实战】,获取本文完整研究解析、代码实现细节。

财经数据与量化投研知识社区

核心权益如下:

  1. 赠送《财经数据宝典》完整文档,汇集多年财经数据维护经验
  2. 赠送《量化投研宝典》完整文档,汇集多年量化投研领域经验
  3. 赠送《PyBroker-入门及实战》视频课程,手把手学习量化策略开发
  4. 每日分享高质量量化投研文章(已更新 180+篇)、代码和相关资料
  5. 定期更新高频财经数据
  6. 参与年度不少于 10 次专属直播与录播课程
  7. 与核心开发者直接交流,解决实际问题
  8. 获取专业微信群交流机会和课程折扣

星球已有丰富内容积累,包括量化投研论文、财经高频数据、 PyBroker 视频教程、定期直播、数据分享和答疑解难。适合对量化投研和财经数据分析有兴趣的学习者及从业者。欢迎加入我们!

好文推荐

1. 用 Python 打造股票预测系统:Transformer 模型教程(一)

2. 用 Python 打造股票预测系统:Transformer 模型教程(二)

3. 用 Python 打造股票预测系统:Transformer 模型教程(三)

4. 用 Python 打造股票预测系统:Transformer 模型教程(完结)

5. 揭秘隐马尔可夫模型:因子投资的制胜武器

6. YOLO 也能预测股市涨跌?计算机视觉在股票市场预测中的应用

7. 金融 AI 助手:FinGPT 让你轻松掌握市场分析

8. 量化交易秘籍:为什么专业交易员都在用对数收益率?

9. Python 量化投资利器:Ridge、Lasso 和 Elastic Net 回归详解

10. 掌握金融波动率模型:完整 Python 实现指南

好书推荐



Python社区是高质量的Python/Django开发社区
本文地址:http://www.python88.com/topic/189555