我来为你设计一个综合Python案例,演示三种不同方式实现"变向突破次数对比"(比如在股票、交易数据分析中常见)。

场景:检测价格序列的变向突破次数
假设我们有一个股票价格序列,需要统计不同策略下价格突破前期高/低点的次数对比。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from typing import List, Tuple, Optional
import warnings
warnings.filterwarnings('ignore')
class TrendBreakAnalyzer:
"""
趋势变向突破分析器
对比不同周期/策略下的突破次数
"""
def __init__(self, prices: List[float], dates: Optional[List[str]] = None):
"""
初始化价格数据
:param prices: 价格序列
:param dates: 日期序列(可选)
"""
self.prices = np.array(prices)
self.n = len(prices)
self.dates = dates if dates else [f'T-{self.n-i}' for i in range(self.n)]
# 计算基本统计量
self.high = np.maximum.accumulate(self.prices)
self.low = np.minimum.accumulate(self.prices)
def method1_simple_break(self, lookback: int = 5) -> Tuple[int, int]:
"""
方法1:简单N日突破
统计价格突破前N日高点/低点的次数
"""
up_breaks = 0
down_breaks = 0
for i in range(lookback, self.n):
# 前N日最高价
prev_high = np.max(self.prices[i-lookback:i])
prev_low = np.min(self.prices[i-lookback:i])
# 当前价格突破
if self.prices[i] > prev_high:
up_breaks += 1
elif self.prices[i] < prev_low:
down_breaks += 1
return up_breaks, down_breaks
def method2_donchian_channel(self, period: int = 20) -> Tuple[int, int]:
"""
方法2:唐奇安通道突破
使用上下轨进行突破统计
"""
if period > self.n:
return 0, 0
up_breaks = 0
down_breaks = 0
last_break = None # 记录上次突破方向
for i in range(period, self.n):
channel_high = np.max(self.prices[i-period:i])
channel_low = np.min(self.prices[i-period:i])
# 检测突破
if self.prices[i] > channel_high and last_break != 'up':
up_breaks += 1
last_break = 'up'
elif self.prices[i] < channel_low and last_break != 'down':
down_breaks += 1
last_break = 'down'
return up_breaks, down_breaks
def method3_zigzag_break(self, retrace_threshold: float = 0.05) -> Tuple[int, int]:
"""
方法3:之字形突破
基于价格回撤百分比识别转折点并统计突破
"""
if self.n < 3:
return 0, 0
# 识别转折点
turning_points = []
direction = None # 'up' 或 'down'
for i in range(1, self.n - 1):
# 局部高点
if self.prices[i] > self.prices[i-1] and self.prices[i] > self.prices[i+1]:
turning_points.append((i, 'high', self.prices[i]))
# 局部低点
elif self.prices[i] < self.prices[i-1] and self.prices[i] < self.prices[i+1]:
turning_points.append((i, 'low', self.prices[i]))
# 统计突破次数
up_breaks = 0
down_breaks = 0
last_trend = None
for idx, point_type, price in turning_points:
if point_type == 'high':
if last_trend == 'down' or last_trend is None:
# 检查是否突破前一个高点
if len(turning_points) > 1 and price > turning_points[-2][2]:
up_breaks += 1
last_trend = 'up'
elif point_type == 'low':
if last_trend == 'up' or last_trend is None:
if len(turning_points) > 1 and price < turning_points[-2][2]:
down_breaks += 1
last_trend = 'down'
return up_breaks, down_breaks
def compare_all_methods(self) -> pd.DataFrame:
"""
对比所有方法的突破次数
"""
results = {}
# 不同参数组合
params = {
'简单5日突破': {'method': 'simple', 'lookback': 5},
'简单10日突破': {'method': 'simple', 'lookback': 10},
'唐奇安20日': {'method': 'donchian', 'period': 20},
'唐奇安30日': {'method': 'donchian', 'period': 30},
'之字形5%': {'method': 'zigzag', 'threshold': 0.05},
'之字形10%': {'method': 'zigzag', 'threshold': 0.10}
}
for name, param in params.items():
if param['method'] == 'simple':
up, down = self.method1_simple_break(param['lookback'])
elif param['method'] == 'donchian':
up, down = self.method2_donchian_channel(param['period'])
else:
up, down = self.method3_zigzag_break(param['threshold'])
results[name] = {
'向上突破': up,
'向下突破': down,
'总突破': up + down,
'成功率': f"{up/(up+down)*100:.1f}%" if (up+down) > 0 else 'N/A'
}
df = pd.DataFrame(results).T
df.index.name = '策略'
return df
def visualize_breaks(self, method: str = 'simple', **kwargs):
"""
可视化突破点
"""
fig, axes = plt.subplots(2, 1, figsize=(15, 10))
# 价格和移动平均线
axes[0].plot(self.dates, self.prices, label='价格', color='blue', alpha=0.7)
if self.n > 20:
ma20 = pd.Series(self.prices).rolling(20).mean()
axes[0].plot(self.dates, ma20, label='MA20', color='orange', linestyle='--')
axes[0].set_title('价格走势与突破点')
axes[0].set_ylabel('价格')
axes[0].legend()
axes[0].grid(True, alpha=0.3)
# 标记突破点
break_points = {'up': [], 'down': []}
if method == 'simple':
lookback = kwargs.get('lookback', 5)
for i in range(lookback, self.n):
prev_high = np.max(self.prices[i-lookback:i])
prev_low = np.min(self.prices[i-lookback:i])
if self.prices[i] > prev_high:
break_points['up'].append(i)
axes[0].scatter(i, self.prices[i], color='green', s=100,
marker='^', zorder=5, alpha=0.8)
elif self.prices[i] < prev_low:
break_points['down'].append(i)
axes[0].scatter(i, self.prices[i], color='red', s=100,
marker='v', zorder=5, alpha=0.8)
# 第二个图:突破次数对比
methods_data = self.compare_all_methods()
x = range(len(methods_data))
width = 0.35
bars1 = axes[1].bar([i - width/2 for i in x], methods_data['向上突破'],
width, label='向上突破', color='green', alpha=0.7)
bars2 = axes[1].bar([i + width/2 for i in x], methods_data['向下突破'],
width, label='向下突破', color='red', alpha=0.7)
axes[1].set_xlabel('策略')
axes[1].set_ylabel('突破次数')
axes[1].set_title('各策略突破次数对比')
axes[1].set_xticks(x)
axes[1].set_xticklabels(methods_data.index, rotation=45, ha='right')
axes[1].legend()
axes[1].grid(True, alpha=0.3)
# 在柱状图上添加数值标签
for bar in bars1:
height = bar.get_height()
axes[1].text(bar.get_x() + bar.get_width()/2., height,
f'{int(height)}', ha='center', va='bottom')
for bar in bars2:
height = bar.get_height()
axes[1].text(bar.get_x() + bar.get_width()/2., height,
f'{int(height)}', ha='center', va='bottom')
plt.tight_layout()
plt.show()
# 输出统计结果
print("\n" + "="*60)
print(f"变向突破次数统计对比 (基于{method}方法)")
print("="*60)
print(f"向上突破次数: {len(break_points['up'])}")
print(f"向下突破次数: {len(break_points['down'])}")
print(f"总突破次数: {len(break_points['up']) + len(break_points['down'])}")
print(f"突破频率: {(len(break_points['up']) + len(break_points['down'])) / self.n * 100:.2f}%")
# 示例运行
def generate_sample_data(n_days: int = 200) -> List[float]:
"""
生成模拟价格数据(含趋势和波动)
"""
np.random.seed(42)
# 基础价格
base_price = 100
# 生成趋势
trend = np.cumsum(np.random.randn(n_days) * 0.5)
trend = trend - trend[0] # 从0开始
# 添加季节性
seasonal = 5 * np.sin(np.linspace(0, 4*np.pi, n_days))
# 添加噪声
noise = np.random.randn(n_days) * 2
# 组合
prices = base_price + trend + seasonal + noise
# 确保价格为正
prices = np.maximum(prices, 10)
return prices.tolist()
# 主程序
if __name__ == "__main__":
# 生成模拟数据
prices = generate_sample_data(200)
dates = pd.date_range('2024-01-01', periods=200, freq='D').strftime('%Y-%m-%d').tolist()
# 创建分析器实例
analyzer = TrendBreakAnalyzer(prices, dates)
# 执行所有方法并对比
print("="*60)
print("趋势变向突破分析 - 综合对比")
print("="*60)
# 详细对比
result_df = analyzer.compare_all_methods()
print("\n各策略突破次数对比:")
print(result_df.to_string())
# 可视化
analyzer.visualize_breaks(method='simple', lookback=10)
# 额外分析:寻找最佳参数
print("\n" + "="*60)
print("参数优化分析")
print("="*60)
lookback_range = range(5, 31, 5)
results = []
for lookback in lookback_range:
up, down = analyzer.method1_simple_break(lookback)
total = up + down
results.append({
'周期': lookback,
'向上突破': up,
'向下突破': down,
'总突破': total,
'单日突破频率': f"{total/analyzer.n*100:.2f}%"
})
opt_df = pd.DataFrame(results)
print(opt_df.to_string(index=False))
print("\n分析结论:")
print(f"- 最优参数: 周期{opt_df.loc[opt_df['总突破'].idxmax(), '周期']}日")
print(f"- 最高突破频率: {opt_df['单日突破频率'].max()}")
print(f"- 平均突破次数: {opt_df['总突破'].mean():.1f}")
这个综合案例展示了:
三种不同突破策略
- 简单N日突破:最基础的方法
- 唐奇安通道:防止频繁交易
- 之字形突破:基于转折点识别
核心功能模块
- 数据生成与预处理
- 多种策略实现
- 性能对比分析
- 可视化展示
实际应用价值
- 股票/期货交易策略分析
- 技术指标回测
- 参数优化
运行结果会展示每种策略的突破次数对比、可视化图表以及参数优化建议,帮助你选择最适合当前市场环境的突破策略。