Search code examples
pandasdataframeformulamoving-average

Inverse formula of exponential moving average (ewm) in pandas


I have created this pandas dataframe

import pandas as pd

ds = {'col1' : [1,2,3,4,3,3,2,2,2,4,5,6,7,5,4,3,2,2,4,5,12]}
df = pd.DataFrame(data=ds)

The dataset looks like this:

display(df)

    col1
0     1
1     2
2     3
3     4
4     3
5     3
6     2
7     2
8     2
9     4
10    5
11    6
12    7
13    5
14    4
15    3
16    2
17    2
18    4
19    5
20   12

I now calculate the 3-period Exponential Moving Average as follows:

time_window = 3
df['ema3'] = df['col1'].ewm(com=time_window - 1,
                        min_periods=time_window).mean()

The resulting dataframe looks like this:

    col1    ema3
0   1        NaN
1   2        NaN
2   3   2.263158
3   4   2.984615
4   3   2.990521
5   3   2.993985
6   2   2.642059
7   2   2.419350
8   2   2.275833
9   4   2.860698
10  5   3.582139
11  6   4.394353
12  7   5.267388
13  5   5.177952
14  4   4.784403
15  3   4.188695
16  2   3.458389
17  2   2.971930
18  4   3.314775
19  5   3.876685
20  12  6.585000

Question: what value for col1 would return an EMA of 8.12 at record 21?

    col1    ema3
0   1        NaN
1   2        NaN
2   3   2.263158
3   4   2.984615
4   3   2.990521
5   3   2.993985
6   2   2.642059
7   2   2.419350
8   2   2.275833
9   4   2.860698
10  5   3.582139
11  6   4.394353
12  7   5.267388
13  5   5.177952
14  4   4.784403
15  3   4.188695
16  2   3.458389
17  2   2.971930
18  4   3.314775
19  5   3.876685
20  12  6.585000
21  ??  8.120000

Is there a formula that inverts the ewm and gives a value for col1 such that the EMA at record 21 is 8.12000? I don't want to iterate numerous values. I am asking if anyone knows a formula (that I can code in python) for that.

Thanks!


Solution

  • An exponentially weighted moving average is defined as following:

    EWMA(t) = a * value(t) + (1-a) * EWMA(t-1)
    

    In your case, you want value(t) and you know that EWMA(t) = 8.12 and EWMA(t-1) = 6.585, and a = 1/(1+com). You can thus solve:

    com = time_window - 1
    a = 1/(1+com) # 0.333
    x = (8.12 - (1-a)*6.585) / a
    

    Output: 11.189999999999996

    Verification (not with an exact precision):

         col1      ema3
    0    1.00       NaN
    1    2.00       NaN
    2    3.00  2.263158
    3    4.00  2.984615
    4    3.00  2.990521
    5    3.00  2.993985
    6    2.00  2.642059
    7    2.00  2.419350
    8    2.00  2.275833
    9    4.00  2.860698
    10   5.00  3.582139
    11   6.00  4.394353
    12   7.00  5.267388
    13   5.00  5.177952
    14   4.00  4.784403
    15   3.00  4.188695
    16   2.00  3.458389
    17   2.00  2.971930
    18   4.00  3.314775
    19   5.00  3.876685
    20  12.00  6.585000
    21  11.19  8.120205