提示词

1
假设有一个DataFrame,index是日期,有一列数据是股票的收盘价,收盘价中可能包括多种趋势,需要对其进行趋势检测,找出明显的上涨趋势并可视化,请给出示例代码。

答案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import statsmodels.api as sm
from scipy.stats import linregress
from sklearn.preprocessing import MinMaxScaler

plt.style.use('seaborn-v0_8')
#指定字体,防止中文出现乱码,windows系统指定为‘SimHei’
plt.rcParams['font.sans-serif'] = ['SimHei']
#这行代码让中文的负号“-”可以正常显示
plt.rcParams["axes.unicode_minus"]=False

# 1. 创建示例数据(含异常值,替换为你的实际数据)
df = pd.read_excel('../数据/2-1.xlsx')
df = df[['日期', '收盘']]
df.columns = ['date','Close']
df['date'] = pd.to_datetime(df['date'])
df.set_index('date', inplace = True)

# 2. 修正趋势检测函数
def detect_trends(series):
# 方法1:移动平均交叉策略(使用20日均线)
ma20 = series.rolling(20).mean() # 20日移动平均线[1,3](@ref)

# 方法2:线性回归趋势线
X = np.arange(len(series))
slope, intercept, r_value, p_value, std_err = linregress(X, series)

# 方法3:时间序列分解(使用20日周期)
decomposition = sm.tsa.seasonal_decompose(series, period=20) # 20日周期分解[9](@ref)
trend_component = decomposition.trend.dropna()

# 方法4:20日滚动斜率(修复索引错误)
rolling_slopes = []
for i in range(len(series)):
# 取20日窗口
start_idx = max(0, i - 19) # 确保有20个数据点
window = series.iloc[start_idx:i+1]

if len(window) > 1: # 至少有2个点才能计算斜率
x = np.arange(len(window))
slope_value = linregress(x, window.values).slope
rolling_slopes.append(slope_value)
else:
rolling_slopes.append(np.nan) # 不足2个点则填充NaN

return ma20, slope, trend_component, rolling_slopes

# 3. 使用修正后的函数
ma20, overall_slope, trend_comp, rolling_slopes = detect_trends(df['Close'])

# 4. 可视化设计
plt.figure(figsize=(16, 12))
ax1 = plt.subplot(3, 1, 1)

# 原始价格与20日均线
df['Close'].plot(ax=ax1, label='收盘价', alpha=0.6)
ma20.plot(ax=ax1, label='20日均线', color='orange', lw=2)

# 标注价格在均线上方的区域
ax1.fill_between(df.index, df['Close'], ma20,
where=(df['Close'] > ma20),
color='red', alpha=0.3, label='价格高于均线')

# 趋势分解可视化
ax2 = plt.subplot(3, 1, 2, sharex=ax1)
trend_comp.plot(ax=ax2, color='green', label='趋势成分')
ax2.fill_between(trend_comp.index, trend_comp,
where=(trend_comp.pct_change() > 0),
color='red', alpha=0.3, label='上涨区间')

# 20日滚动斜率可视化
ax3 = plt.subplot(3, 1, 3, sharex=ax1)
slope_series = pd.Series(rolling_slopes, index=df.index)
slope_series.plot(ax=ax3, color='blue', label='20日滚动斜率')
ax3.axhline(0, color='black', ls='--')
ax3.fill_between(df.index, rolling_slopes, 0,
where=(np.array(rolling_slopes) > 0),
color='red', alpha=0.3, label='上升趋势')

# 添加趋势强度标记
strong_trend_points = slope_series[slope_series > slope_series.quantile(0.9)]
ax3.scatter(strong_trend_points.index, strong_trend_points.values,
color='darkred', s=50, label='强上升趋势')

# 图表美化
ax1.set_title(f'整体趋势方向:{"上涨" if overall_slope > 0 else "下跌"} (斜率:{overall_slope:.4f})', fontsize=14)
ax1.set_ylabel('价格', fontsize=12)
ax1.legend(loc='upper left')
ax1.grid(alpha=0.3)

ax2.set_title('趋势成分分解 (20日周期)', fontsize=14)
ax2.set_ylabel('趋势值', fontsize=12)
ax2.legend(loc='upper left')
ax2.grid(alpha=0.3)

ax3.set_title('20日滚动斜率分析', fontsize=14)
ax3.set_ylabel('斜率', fontsize=12)
ax3.set_xlabel('日期', fontsize=12)
ax3.legend(loc='upper left')
ax3.grid(alpha=0.3)

plt.tight_layout()
plt.show()

# 5. 输出趋势分析结果
print(f"整体趋势斜率: {overall_slope:.6f} (正值表示上涨趋势)")
print(f"强上升趋势出现次数: {len(strong_trend_points)}次")
print("主要强上升趋势时间段:")
for i in range(0, len(strong_trend_points), 5):
print(f"{strong_trend_points.index[i].strftime('%Y-%m-%d')} - 斜率: {strong_trend_points.iloc[i]:.4f}")

数据导入以及防止画图中文乱码的代码是我加进去的,其余都是ai写的。

图像: