问题描述
解决方案
这是一个基于 一目均衡表 (Ichimoku Cloud) 的交易策略。
策略原理
一目均衡表(Ichimoku Kinko Hyo)是一个综合性的技术分析指标,主要包含以下五个部分:
- 转折线 (Tenkan-sen / Conversion Line): (过去9日最高价 + 过去9日最低价) / 2
- 基准线 (Kijun-sen / Base Line): (过去26日最高价 + 过去26日最低价) / 2
- 先行带 A (Senkou Span A): (转折线 + 基准线) / 2,向未来平移26个周期。
- 先行带 B (Senkou Span B): (过去52日最高价 + 过去52日最低价) / 2,向未来平移26个周期。
- 迟行带 (Chikou Span): 当前收盘价,向过去平移26个周期(本策略主要使用前四者构建云带)。
云带 (Kumo) 由先行带 A 和 先行带 B 组成。
交易逻辑
本策略采用经典的 “云带突破 + TK交叉” 逻辑:
- 买入信号:
- 收盘价 高于 云带(即 Price > Span A 且 Price > Span B),表示趋势向上。
- 转折线 大于 基准线(多头排列)。
- 卖出信号:
- 收盘价 跌破 云带(Price < Span A 或 Price < Span B)。
- 或者 转折线 小于 基准线(空头排列)。
策略代码
# -*- coding: utf-8 -*-
import jqdata
import pandas as pd
import numpy as np
def initialize(context):
"""
初始化函数
"""
# 设定基准:沪深300
set_benchmark('000300.XSHG')
# 开启动态复权模式(真实价格)
set_option('use_real_price', True)
# 过滤掉order系列API产生的比error级别低的log
log.set_level('order', 'error')
# 设定手续费
set_order_cost(OrderCost(close_tax=0.001, open_commission=0.0003, close_commission=0.0003, min_commission=5), type='stock')
# 设定要操作的股票池,这里以 上证50 成分股为例
g.stock_pool = get_index_stocks('000016.XSHG')
# 一目均衡表参数
g.n1 = 9 # 转折线周期
g.n2 = 26 # 基准线周期
g.n3 = 52 # 先行带B周期
g.n_shift = 26 # 平移周期
# 每天开盘时运行
run_daily(market_open, time='09:30')
def get_ichimoku_data(security, n1, n2, n3, n_shift):
"""
计算一目均衡表数据
"""
# 获取足够长的历史数据
# 需要的数据长度 = max(n3, n_shift + n3) + 安全余量
count = n3 + n_shift + 10
h_data = attribute_history(security, count, '1d', ['high', 'low', 'close'])
if len(h_data) < count:
return None
# 1. 计算当前的 转折线 (Tenkan-sen) 和 基准线 (Kijun-sen)
# 用于判断 TK 交叉
high_n1 = h_data['high'][-n1:].max()
low_n1 = h_data['low'][-n1:].min()
tenkan_sen = (high_n1 + low_n1) / 2
high_n2 = h_data['high'][-n2:].max()
low_n2 = h_data['low'][-n2:].min()
kijun_sen = (high_n2 + low_n2) / 2
# 2. 计算当前的 云带 (Kumo)
# 注意:今天的云带是由 26 天前的数据计算出来的
# 所以我们需要切片获取 26 天前的数据窗口
# 数据截止到 n_shift (26) 天前
past_data = h_data.iloc[:-n_shift]
# 基于过去数据计算当时的转折线
p_high_n1 = past_data['high'][-n1:].max()
p_low_n1 = past_data['low'][-n1:].min()
p_tenkan = (p_high_n1 + p_low_n1) / 2
# 基于过去数据计算当时的基准线
p_high_n2 = past_data['high'][-n2:].max()
p_low_n2 = past_data['low'][-n2:].min()
p_kijun = (p_high_n2 + p_low_n2) / 2
# 计算 先行带 A (Senkou Span A) = (过去转折 + 过去基准) / 2
span_a = (p_tenkan + p_kijun) / 2
# 基于过去数据计算 先行带 B (Senkou Span B)
p_high_n3 = past_data['high'][-n3:].max()
p_low_n3 = past_data['low'][-n3:].min()
span_b = (p_high_n3 + p_low_n3) / 2
return {
'tenkan': tenkan_sen,
'kijun': kijun_sen,
'span_a': span_a,
'span_b': span_b,
'close': h_data['close'][-1]
}
def market_open(context):
"""
每日交易逻辑
"""
# 更新股票池(剔除停牌、ST等,这里简单处理直接用指数成分)
# 实际实盘建议增加过滤逻辑
current_date = context.current_dt.date()
# 获取持仓
positions = context.portfolio.positions
# 待买入列表
buy_list = []
# 待卖出列表
sell_list = []
for stock in g.stock_pool:
# 获取一目均衡表数据
ichi = get_ichimoku_data(stock, g.n1, g.n2, g.n3, g.n_shift)
if not ichi:
continue
close = ichi['close']
span_a = ichi['span_a']
span_b = ichi['span_b']
tenkan = ichi['tenkan']
kijun = ichi['kijun']
# 云带顶部和底部
kumo_top = max(span_a, span_b)
kumo_bottom = min(span_a, span_b)
# --- 卖出逻辑 ---
# 如果持有该股票
if stock in positions and positions[stock].closeable_amount > 0:
# 1. 价格跌破云带 (收盘价 < 云带底部)
# 2. 或者 转折线 下穿 基准线 (死叉)
if close < kumo_bottom or tenkan < kijun:
sell_list.append(stock)
# --- 买入逻辑 ---
# 如果没有持仓
elif stock not in positions:
# 1. 价格在云带上方 (收盘价 > 云带顶部)
# 2. 且 转折线 > 基准线 (多头排列)
if close > kumo_top and tenkan > kijun:
buy_list.append(stock)
# 执行卖出
for stock in sell_list:
order_target_value(stock, 0)
log.info("卖出 %s: 跌破云带或TK死叉" % stock)
# 执行买入
# 简单的资金分配:将可用资金平均分配给待买入股票
if len(buy_list) > 0:
cash = context.portfolio.available_cash
# 预留一点资金防止手续费不够
cash_per_stock = cash / len(buy_list) * 0.98
for stock in buy_list:
order_value(stock, cash_per_stock)
log.info("买入 %s: 突破云带且TK金叉" % stock)
代码关键点解析
-
数据获取与平移 (
get_ichimoku_data):- 一目均衡表最难处理的是“时间平移”。
- 先行带 A 和 B 在图表上是画在“未来26天”的。这意味着,今天看到的云带,实际上是利用 26天前 的历史数据计算出来的数值。
- 代码中
past_data = h_data.iloc[:-n_shift]这一行非常关键,它模拟了回溯到26天前,利用当时的数据计算出 Span A 和 Span B,这两个值构成了今天的云带支撑/阻力位。
-
信号判断:
- Kumo Breakout (云带突破):
close > kumo_top。这是最强的趋势信号,表明价格已经突破了历史阻力区。 - TK Cross (转折/基准线交叉):
tenkan > kijun。类似于移动平均线的金叉,用于确认短期动能。
- Kumo Breakout (云带突破):
-
资金管理:
- 示例代码使用了简单的等权分配。如果有多个买入信号,将当前现金平均分配。
常见问题 Q&A
Q: 为什么 Span A 和 Span B 的计算要用过去的数据?
A: 在一目均衡表的定义中,Span A 和 B 是“前移”绘制的。这意味着,对于交易者来说,今天的云带位置是由过去(26天前)的市场状态决定的。在编写代码时,我们需要“回到过去”计算出那个值,然后拿来和“今天”的价格做对比。
Q: 这个策略适合什么频率?
A: 一目均衡表最初是为日线设计的(Daily),在日线级别上效果最稳定。如果用于分钟级别(如60分钟),需要调整参数或注意噪音干扰。
Q: 如何优化这个策略?
A:
- 增加迟行带确认:要求当前价格高于26天前的价格。
- 止损优化:可以使用基准线(Kijun-sen)作为动态止损线,而不是死叉才卖出。
- 股票池筛选:一目均衡表是趋势指标,在震荡市中会频繁止损。建议结合基本面因子或波动率因子,只在趋势明显的标的上运行。