You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Pandas中识别价格状态(用EMA斜率替代滞后ADX)

基于EMA斜率识别股票价格趋势状态

背景

已有包含26条股票开盘价(Open)、最高价(High)、最低价(Low)、收盘价(Close)的Pandas DataFrame,需新增Regime字段,用1、2、3分别标记非趋势状态、下跌趋势状态、上涨趋势状态。因ADX指标存在滞后性,改用EMA斜率实现更及时的趋势识别。

原始数据与DataFrame构建

代码实现

import pandas as pd
import numpy as np

ds = {
    'Date': ['15/06/2025','16/06/2025','17/06/2025','18/06/2025','19/06/2025','20/06/2025','21/06/2025','22/06/2025','23/06/2025','24/06/2025','25/06/2025','26/06/2025','27/06/2025','28/06/2025','29/06/2025','30/06/2025','01/07/2025','02/07/2025','03/07/2025','04/07/2025','05/07/2025','06/07/2025','07/07/2025','08/07/2025','09/07/2025','10/07/2025'],
    'Open': [310,320,305,312,312,324,315,321,320,300,289,276,274,273,265,249,200,189,175,161,171,179,200,240,285,286],
    'High': [321,321,307,313,320,329,321,321,320,301,289,277,276,274,266,250,201,190,179,170,180,199,239,289,286,300],
    'Low': [310,305,304,311,300,300,310,321,298,289,275,272,274,265,254,200,190,175,160,161,170,175,185,241,284,280],
    'Close': [315,319,306,311,318,321,321,321,299,289,276,273,274,265,250,252,190,175,161,170,180,199,239,288,284,300],
}

df = pd.DataFrame(data=ds)

原始DataFrame输出

print(df)

          Date  Open  High  Low  Close
0   15/06/2025   310   321  310    315
1   16/06/2025   320   321  305    319
2   17/06/2025   305   307  304    306
3   18/06/2025   312   313  311    311
4   19/06/2025   312   320  300    318
5   20/06/2025   324   329  300    321
6   21/06/2025   315   321  310    321
7   22/06/2025   321   321  321    321
8   23/06/2025   320   320  298    299
9   24/06/2025   300   301  289    289
10  25/06/2025   289   289  275    276
11  26/06/2025   276   277  272    273
12  27/06/2025   274   276  274    274
13  28/06/2025   273   274  265    265
14  29/06/2025   265   266  254    250
15  30/06/2025   249   250  200    252
16  01/07/2025   200   201  190    190
17  02/07/2025   189   190  175    175
18  03/07/2025   175   179  160    161
19  04/07/2025   161   170  161    170
20  05/07/2025   171   180  170    180
21  06/07/2025   179   199  175    199
22  07/07/2025   200   239  185    239
23  08/07/2025   240   289  241    288
24  09/07/2025   285   286  284    284
25  10/07/2025   286   300  280    300

实现步骤

1. 标准化日期格式

先将Date列转换为datetime类型,确保时间序列的连续性:

df['Date'] = pd.to_datetime(df['Date'], format='%d/%m/%Y')

2. 计算收盘价的EMA

选择合适的EMA周期(这里用12日作为示例,可根据需求调整),Pandas的ewm方法直接支持EMA计算:

# 计算12日EMA
ema_period = 12
df['EMA'] = df['Close'].ewm(span=ema_period, adjust=False).mean()

3. 计算EMA的斜率

EMA斜率代表EMA的变化速率,提供两种实现方式:

方式一:简单差分法(适合短周期快速计算)

因数据是连续交易日,时间间隔视为1,直接计算EMA的一阶差分:

df['EMA_Slope'] = df['EMA'].diff()

方式二:滚动窗口线性回归(更稳定,适合趋势判断)

用滚动窗口内的线性回归拟合斜率,能过滤短期噪音:

from sklearn.linear_model import LinearRegression

def calculate_slope(series):
    x = np.arange(len(series)).reshape(-1, 1)
    y = series.values.reshape(-1, 1)
    model = LinearRegression().fit(x, y)
    return model.coef_[0][0]

# 用5天滚动窗口计算斜率
window_size = 5
df['EMA_Slope'] = df['EMA'].rolling(window=window_size).apply(calculate_slope)

4. 设定阈值并标记趋势状态

根据斜率的正负和绝对值设定阈值,区分三种状态:

  • 斜率绝对值小于阈值 → 非趋势(标记为1)
  • 斜率为负且绝对值大于阈值 → 下跌趋势(标记为2)
  • 斜率为正且大于阈值 → 上涨趋势(标记为3)
# 设定阈值(可根据数据波动调整,这里用2作为示例)
slope_threshold = 2

df['Regime'] = np.where(
    abs(df['EMA_Slope']) < slope_threshold,
    1,
    np.where(
        df['EMA_Slope'] > slope_threshold,
        3,
        2
    )
)

# 处理滚动窗口产生的NaN值(前window_size-1行无斜率,暂标记为1)
df['Regime'] = df['Regime'].fillna(1).astype(int)

最终结果示例

执行上述代码后,Regime字段已添加到DataFrame中,可通过打印查看核心列:

print(df[['Date', 'Close', 'EMA', 'EMA_Slope', 'Regime']])

关键说明

  • EMA周期和斜率阈值需要根据股票的波动特性调整,建议通过回测优化参数
  • 滚动窗口线性回归的窗口大小也会影响趋势识别的灵敏度,窗口越大越滞后但越稳定
  • 若需要更精准的趋势判断,可结合多个周期EMA的斜率综合分析

内容的提问来源于stack exchange,提问作者Giampaolo Levorato

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 16:59:49