生生不息

生生不息

AI在时间序列中的趋势检测

2025-06-23
AI在时间序列中的趋势检测

提示词

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

答案

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写的。

图像: