如何在 pandas/每列自定义填充方法中正确重新采样 ohlc 数据

How to resample ohlc data properly in pandas / custom fill method per column

我有缺少时间范围的 OHLC 数据。假设我有以下 pandas 数据帧,由变量 df:

表示
                     Open     High     Low      Close
2019-04-19 00:00:00  0.67068  0.67123  0.67064  0.67123
2019-04-19 00:02:00  0.67062  0.67425  0.67060  0.67223

现在,我对 pandas 数据帧重新采样以填补缺失的空白,我得到以下结果:

df = df.resample('T').ffill()

                     Open     High     Low      Close
2019-04-19 00:00:00  0.67068  0.67123  0.67064  0.67123
2019-04-19 00:01:00  0.67068  0.67123  0.67064  0.67123
2019-04-19 00:02:00  0.67062  0.67425  0.67060  0.67223

从上面我们可以看出,缺失的空隙(00:01:00)是借助ffill()填充的。但是,该行(以 00:01:00 开头的行)中的数据未正确显示,因为开盘价应与前一行(以 00:00:00 开头的行)的收盘价相同。同样,该行(以 00:01:00 开头的行)的收盘价应与下一行(以 00:02:00 开头的行)的开盘价相同。所需的输出应如下所示:

                     Open     High     Low      Close
2019-04-19 00:00:00  0.67068  0.67123  0.67064  0.67123
2019-04-19 00:01:00  0.67123  0.67123  0.67064  0.67062
2019-04-19 00:02:00  0.67062  0.67425  0.67060  0.67223

如何解决 pandas 中的这个问题?

遗憾的是,您不能直接指定每列的填充方法。

解决方法是不在重采样期间填充值,而是在之后填充:

df = df.resample('T').fillna(None)

df['Open'], df['Close'] = (df['Open'].fillna(df['Close'].ffill()),
                           df['Close'].fillna(df['Open'].bfill()))

df = df.ffill()

输出:

                        Open     High      Low    Close
2019-04-19 00:00:00  0.67068  0.67123  0.67064  0.67123
2019-04-19 00:01:00  0.67123  0.67123  0.67064  0.67062
2019-04-19 00:02:00  0.67062  0.67425  0.67060  0.67223

上一个答案(对 OHLC 不正确,但概括起来很有趣)

(df.resample('T')
   .fillna(None)
   .assign(Close=lambda d: d['Close'].bfill())  # bfill for Close
   .ffill()                                     # ffill for others
)

输出:

                        Open     High      Low    Close
2019-04-19 00:00:00  0.67068  0.67123  0.67064  0.67123
2019-04-19 00:01:00  0.67068  0.67123  0.67064  0.67223
2019-04-19 00:02:00  0.67062  0.67425  0.67060  0.67223
交叉填充值:
(df.resample('T')
   .fillna(None)
   .assign(Open=lambda d: d['Open'].fillna(d['Close'].ffill())) # Open = last Close
   .ffill()  # ffill the others
)

输出:

                        Open     High      Low    Close
2019-04-19 00:00:00  0.67068  0.67123  0.67064  0.67123
2019-04-19 00:01:00  0.67123  0.67123  0.67064  0.67123
2019-04-19 00:02:00  0.67062  0.67425  0.67060  0.67223
更多选项

这是另一个示例,我们将对 High 进行插值并将 Low 保留为 NaN:

(df.resample('T')
   .fillna(None)
   .assign(Open=lambda d: d['Open'].ffill(),
           Close=lambda d: d['Close'].bfill(),
           High=lambda d: d['High'].interpolate()
          )
)

输出:

                        Open     High      Low    Close
2019-04-19 00:00:00  0.67068  0.67123  0.67064  0.67123
2019-04-19 00:01:00  0.67068  0.67274      NaN  0.67223
2019-04-19 00:02:00  0.67062  0.67425  0.67060  0.67223

是正确的方向,但是有两个问题:

  1. 如果连续多行缺失值将不起作用,
  2. “高”和“低”的填充在 OHLC 上下文中不合逻辑。

下面是我会做的(重采样后):

  1. Cross-fill 第一个缺失行

    result = df.copy()
    result['open'] = df['open'].fillna(df['close'].ffill(),limit=1)
    result['close'] = df['close'].fillna(df['open'].bfill(),limit=1)
    
  2. 现在,在其余行中传播相等的开盘价和闭盘价:

    result['open'] = result['open'].fillna(result['close'].ffill())
    result['close'] = result['close'].fillna(result['close'].ffill())
    
  3. 最后,逻辑上将高低设置为开盘价和收盘价的最小值和最大值:

    result['high'] = result['high'].fillna(result[['open','close']].max(axis=1))
    result['low'] = result['low'].fillna((result[['open','close']].min(axis=1)))
    

此方法适用于多个连续缺失行的情况,并且还会逻辑处理 'high' 和 'low' 的缺失值。