追加一行后是否可以继续EWM?

问题描述 投票:0回答:1

我有一些量化金融代码,可以对股票价格进行一些分析。

我需要计算的一件事是 EWMA。

在进行研究时(即:历史“批量”世界),我有一长串股票价格列表,我可以使用 pandas

ewm(...).mean()
来计算该价格列表上的 EWMA。

后来,当在生产中使用相同的代码时(即:实时“实时”世界),我想仅计算最新股票价格的 EWMA,而不必重新计算整个历史记录。

以下是我面临的问题的演练:

这是一些模拟股票价格的代码:

import numpy as np
import pandas as pd

def gbm(T, N, mu, sigma, S0):        
    dt = float(T)/N
    t = np.linspace(0, T, N)
    W = np.random.standard_normal(size = N) 
    W = np.cumsum(W)*np.sqrt(dt) 
    X = (mu-0.5*sigma**2)*t + sigma*W 
    S = S0*np.exp(X)
    return S

dates = pd.date_range('2021-01-01', '2022-01-01')
T = (dates.max()-dates.min()).days / 365
N = len(dates)
mu = 0.03
sigma = 0.5
S0 = 100
df = pd.DataFrame(index=index, data={'value': gbm(T, N, mu, sigma, S0)}) 

我可以计算数据的 EWMA,如下所示:

df['ewma'] = df['value'].ewm(halflife=30).mean()
df.plot()

plot

我的数据框的尾部如下所示:

tail

众所周知,EWMA 的计算公式是先前的 EWMA 值衰减

1-α
和当前观测值缩放
α

EMA formula

现在我们假装我们正在制作中,并且我们刚刚收到了一个新价格。我在源数据中添加了一个新的观察结果:

df_new = pd.DataFrame(index=[pd.Timestamp('2022-01-02')], data={'value':105})
df = pd.concat([df, df_new])

我的新数据框的尾部如下所示:

new tail

我现在想计算新值的 EWMA。

显然我可以重新计算整个数据帧上 EWM 的整个历史记录:

df['ewma'] = df['value'].ewm(halflife=30).mean()

但是,经过基准测试后,我们发现这是我们生产流程中的一个主要瓶颈。

我知道我可以通过手动计算我的半衰期中的

α
来手动计算新值的 EWMA,然后使用 EWMA 公式与之前的 EWMA 值:

df = df.tail(2).copy()
halflife = 30
alpha = 1 - np.exp(-np.log(2)/halflife)
df.iloc[-1]['ewma'] = (1-alpha)*df.iloc[-2]['ewma'] + alpha*df.iloc[-1]['value']

然而,这会导致批量历史世界中发生的事情之间出现脱节。

我的研究人员编写了使用 pandas 的 Python 代码

ewm(...).mean
,我想获取该代码并将其生产化,但不必为每次价格更新重新计算 EWMA 的整个历史

我想向研究人员展示一个统一的界面,可以在历史批处理世界和实时世界中工作。

这对于熊猫来说可能吗?

我可以为 pandas 提供一些状态,以便它“从上次停止的地方继续”以获得新值吗?

python pandas dataframe
1个回答
0
投票

我假设您正在使用该行(删除此行):

df = df.tail(2).copy()

设置值。如果我们不使用这一行,则不会设置该值。通过使用这一行,您可以覆盖数据框,它会变成两行长。

我还看到一条警告:

FutureWarning: ChainedAssignmentError: behaviour will change in pandas 3.0!
You are setting values through chained assignment. Currently this works in certain cases, but when using Copy-on-Write (which will become the default behaviour in pandas 3.0) this will never work to update the original DataFrame or Series, because the intermediate object on which we are setting values will behave as a copy.
A typical example is when you are setting values in a column of a DataFrame, like:

df["col"][row_indexer] = value

Use `df.loc[row_indexer, "col"] = values` instead, to perform the assignment in a single step and ensure this keeps updating the original `df`.

不要使用链式索引,它不会在新版本中更新您的数据。

这就是它应该如何工作:

halflife = 30
alpha = 1 - np.exp(-np.log(2)/halflife)
df.loc[df.index[-1], 'ewma'] = (1-alpha)*df.loc[df.index[-2]]['ewma'] + alpha*df.loc[df.index[-1],'value']
© www.soinside.com 2019 - 2024. All rights reserved.