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

不使用pandas ewm函数计算MACD及解决KeyError:'close'问题

手动计算MACD触发KeyError:'close'的问题解决

我尝试手动计算交易领域的技术指标MACD(Moving Average Convergence Divergence),不使用pandas的ewm函数。按照EMA(指数移动平均线)和MACD的计算步骤编写了代码,但运行时持续出现KeyError:'close'错误,尤其在计算Signal Line传入df['macd']时触发。

计算逻辑

EMA计算步骤

  1. 计算简单移动平均线(SMA):(周期内数值之和 / 周期数)
  2. 计算乘数:2 / (周期数 + 1)(例如周期为5时,乘数为2/(5+1)≈33.33%)
  3. 计算EMA:
    • 第一个EMA值使用前一日的SMA代替前一日EMA
    • 后续EMA公式:EMA = (当日收盘价 - 前一日EMA) × 乘数 + 前一日EMA

MACD计算步骤

  1. 计算短期EMA:通常为12期EMA
  2. 计算长期EMA:通常为26期EMA
  3. 计算MACD线:短期EMA减去长期EMA
  4. 计算信号线:对MACD线计算9期EMA

出错代码

import numpy as np
import pandas as pd

# EMA计算逻辑注释
# 1. 计算SMA:(周期内数值之和 / 周期数)
# 2. 计算乘数:2 / (周期数 + 1),比如周期5时乘数≈33.33%
# 3. 计算EMA:第一个EMA用前一日SMA,后续用公式:EMA=(收盘价-前一日EMA)*乘数+前一日EMA

# MACD计算逻辑注释
# 1. 计算12期短期EMA
# 2. 计算26期长期EMA
# 3. MACD线=短期EMA-长期EMA
# 4. 信号线=MACD线的9期EMA

def compute_ema(df,n):
    df['sma'] = df['close'].rolling(n).mean()
    multiplier = 2/(n + 1)
    df.dropna(inplace=True)
    df['ema'] = np.nan
    for i in range(len(df)):
        if i == 1:
            df.loc[df.index[i], 'ema'] =  (df.loc[df.index[i],'close'] - df.loc[df.index[i - 1],'sma']) * multiplier + df.loc[df.index[i - 1], 'sma']
        else:
            df.loc[df.index[i], 'ema'] =  (df.loc[df.index[i],'close'] - df.loc[df.index[i - 1],'ema']) * multiplier + df.loc[df.index[i - 1], 'ema']
    return df

df['fast'] = compute_ema(df, n=12)
df['slow'] = compute_ema(df, n=26)
df['macd'] = df['fast'] - df['slow']
df['signal'] = compute_ema(df['macd'],n)

报错信息

KeyError: 'close'

The above exception was the direct cause of the following exception:

KeyError                                  Traceback (most recent call last)
Cell In[41], line 1
----> 1 df['signal'] = compute_ema(df['macd'],n)

Cell In[21], line 24
     23 def compute_ema(df,n):
...
   3815     #  InvalidIndexError. Otherwise we fall through and re-raise
   3816     #  the TypeError.
   3817     self._check_indexing_error(key)

问题原因

  1. 函数参数不兼容:compute_ema函数默认接收完整DataFrame并依赖df['close']列,但计算信号线时传入的是df['macd'](一个Series),此时访问df['close']必然触发KeyError。
  2. 数据修改逻辑错误:函数内使用df.dropna(inplace=True)直接修改原DataFrame,且返回整个DataFrame,导致df['fast']和df['slow']被赋值为完整DataFrame,后续计算MACD时会出现数据结构不匹配的问题。
  3. EMA起始计算错误:代码中i == 1的判断逻辑错误,第一个EMA值应该对应第一个有效的SMA位置,而非索引为1的位置。

修复后的代码

import numpy as np
import pandas as pd

def compute_ema(series, n):
    # 计算周期SMA作为EMA初始值
    sma = series.rolling(n).mean()
    multiplier = 2 / (n + 1)
    # 初始化EMA数组,保留原索引
    ema = np.full_like(series, np.nan)
    first_valid_idx = sma.first_valid_index()
    
    if not first_valid_idx:
        return pd.Series(ema, index=series.index)
    
    # 第一个EMA值等于对应位置的SMA
    ema[series.index.get_loc(first_valid_idx)] = sma[first_valid_idx]
    
    # 从第一个有效SMA的下一个位置开始迭代计算
    for idx in series.index[series.index.get_loc(first_valid_idx)+1:]:
        prev_idx = series.index[series.index.get_loc(idx)-1]
        ema[series.index.get_loc(idx)] = (series[idx] - ema[series.index.get_loc(prev_idx)]) * multiplier + ema[series.index.get_loc(prev_idx)]
    
    return pd.Series(ema, index=series.index)

# 假设df包含'close'列,示例计算
df['fast'] = compute_ema(df['close'], n=12)
df['slow'] = compute_ema(df['close'], n=26)
df['macd'] = df['fast'] - df['slow']
# 计算信号线时传入macd序列,函数可正确处理
df['signal'] = compute_ema(df['macd'], n=9)

修复说明

  • 函数改为接收Series作为输入,不再依赖特定列名,可灵活计算任意序列的EMA(包括MACD线)
  • 避免修改原数据,返回独立的EMA结果Series,保证原数据完整性
  • 修正EMA起始值的计算逻辑,从第一个有效的SMA位置开始逐步计算后续EMA值

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 19:57:07