欢迎加入专注于财经数据与量化投研的【数据科学实战】知识星球!在这里,您将获取持续更新的《财经数据宝典》和《量化投研宝典》,这两部宝典相辅相成,为您在量化投研道路上提供明确指引。 我们提供了精选的国内外量化投研的 180+ 篇高质量文章,并每日更新最新研究成果,涵盖策略开发、因子分析、风险管理等核心领域。 无论您是量化投资新手还是经验丰富的研究者,星球社区都能帮您少走弯路,事半功倍,共同探索数据驱动的投资世界!
引言
在量化交易的世界里,策略的参数选择往往决定了最终的成败。许多交易者习惯凭经验或感觉“手动”调整参数,这不仅效率低下,而且很难找到最优解。
这就好比在大海捞针,你可能永远不知道是否存在更好的参数组合。
今天我们要介绍的案例来自 Brian Hulela,他通过 贝叶斯优化 (Bayesian Optimization) 技术,将一个经典的 Ichimoku Cloud (一目均衡表) 交易策略的四年期回报率,从原本不错的 31.77% 惊人地提升到了 **167.50%**,同时还将最大回撤 (Max Drawdown) 从 -32% 降低到了 -21%。
本文将带你一步步通过 Python 复现这个过程,看看数据科学是如何赋能金融交易的。
什么是 Ichimoku 策略与贝叶斯优化?
在开始代码实战之前,我们先简单理解两个核心概念:
- **Ichimoku Cloud (一目均衡表)**:这是一种多功能的如意指标,用于定义支撑位和阻力位,识别趋势方向,衡量动量并提供交易信号。它主要由 Tenkan (转折线)、Kijun (基准线) 和 Senkou B (先行带 B) 等线条组成。
-
贝叶斯优化:这是一种寻找函数最大值或最小值的策略。与暴力尝试所有可能的参数组合 (网格搜索) 不同,贝叶斯优化会根据之前的测试结果来“智能”地猜测下一组最可能带来更好结果的参数,从而高效地找到最优解。
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'], 1, 0)
# 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(5, 20, name='tenkan_period'),
Integer(20, 50, name='kijun_period'),
Integer(40, 100, 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=(14, 8))
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 交易策略进行贝叶斯优化。
- 告别盲猜:通过算法自动寻找参数,替代了低效的手动尝试。
- 显著提升:在 AAPL 的案例中,回报率从 30% 级跃升至 160% 级,且风险控制更好。
- 方法通用:这套贝叶斯优化的逻辑不仅限于 Ichimoku,你可以将其应用到 MACD,RSI 或任何带有参数的量化策略中。
量化交易的核心在于数据驱动。当你下次构建策略时,不妨试试让算法来帮你做决定。
参考文章
加入专注于财经数据与量化投研的知识星球【数据科学实战】,获取本文完整研究解析、代码实现细节。财经数据与量化投研知识社区
核心权益如下:
- 赠送《财经数据宝典》完整文档,汇集多年财经数据维护经验
- 赠送《量化投研宝典》完整文档,汇集多年量化投研领域经验
- 赠送《PyBroker-入门及实战》视频课程,手把手学习量化策略开发
- 每日分享高质量量化投研文章(已更新 180+篇)、代码和相关资料
星球已有丰富内容积累,包括量化投研论文、财经高频数据、 PyBroker 视频教程、定期直播、数据分享和答疑解难。适合对量化投研和财经数据分析有兴趣的学习者及从业者。欢迎加入我们!