在熊猫中更改多头/空头头寸的更有效方法

有没有比我在下面提出的更有效的方法来改变熊猫的多头/空头头寸?

逻辑要点:

  • 头寸np.nan一直持续到有买入 (+1) 或卖出 (-1) 信号。
  • 第一次出现买入/卖出 (+/-1) 信号时,将头寸设置为该数字。
  • 设置第一个位置后,将其向前推进。仅在相同符号的情况下添加到位置。否则,更改符号并设置符号乘以 1(即,如果当前头寸为 3,然后您收到卖出 (-1) 信号,则头寸从 3 变为 -1。反之亦然,如果头寸为 -3 且有买入信号,仓位从 -3 变为 1)。

我的代码

import numpy as np
import pandas as pd

df = pd.DataFrame({
    'buy_sell': [np.nan, 1, np.nan, 1, np.nan, np.nan, 1, -1, np.nan, -1, np.nan, 1, np.nan, -1],
    'position': np.nan
})

for i, r, in df.iterrows():
    buy_sell = r['buy_sell']

    # Check if first index
    if i != 0:
        last_position = df.loc[i-1, 'position']

        if np.isnan(buy_sell):
            df.loc[i, 'position'] = last_position
        else:
            if np.isnan(last_position) or last_position * buy_sell <= 0:
                df.loc[i, 'position'] = buy_sell
            else:
                df.loc[i, 'position'] = last_position + buy_sell
    else:
        df.loc[i, 'position'] = buy_sell

预期解决方案

df_expected = pd.DataFrame({
    'buy_sell': [np.nan, 1, np.nan, 1, np.nan, np.nan, 1, -1, np.nan, -1, np.nan, 1, np.nan, -1],
    'position': [np.nan, 1, 1, 2, 2, 2, 3, -1, -1, -2, -2, 1, 1, -1],
})
    buy_sell  position
0        NaN       NaN
1        1.0       1.0
2        NaN       1.0
3        1.0       2.0
4        NaN       2.0
5        NaN       2.0
6        1.0       3.0
7       -1.0      -1.0
8        NaN      -1.0
9       -1.0      -2.0
10       NaN      -2.0
11       1.0       1.0
12       NaN       1.0
13      -1.0      -1.0

注意:我上面的代码生成了预期的数据框。我在问是否有更有效/更好的方式来做我上面所做的事情。

回答

你可以这样做:

df["position"] = df.buy_sell.groupby(
                      df.buy_sell.bfill()
                      .diff()
                      .abs()
                      .cumsum()
                 ).cumsum().ffill()
                 

输出

df
     buy_sell   position
0         NaN        NaN
1      1.0000     1.0000
2         NaN     1.0000
3      1.0000     2.0000
4         NaN     2.0000
5         NaN     2.0000
6      1.0000     3.0000
7     -1.0000    -1.0000
8         NaN    -1.0000
9     -1.0000    -2.0000
10        NaN    -2.0000
11     1.0000     1.0000
12        NaN     1.0000
13    -1.0000    -1.0000

解释

基本上,您希望cumsum通过列中的符号更改创建某种按组,然后,首先我们需要找到这些更改:

>>> df.buy_sell.bfill().diff().abs()
0           NaN
1        0.0000
2        0.0000
3        0.0000
4        0.0000
5        0.0000
6        0.0000
7        2.0000
8        0.0000
9        0.0000
10       2.0000
11       0.0000
12       2.0000
13       0.0000

正如你所看到的,每一个2都是一个符号变化。现在,pandas.Series.cumsum我们可以为每一行分配一个组

>>> df.buy_sell.bfill().diff().abs().cumsum()
0           NaN
1        0.0000
2        0.0000
3        0.0000
4        0.0000
5        0.0000
6        0.0000
7        2.0000
8        2.0000
9        2.0000
10       4.0000
11       4.0000
12       6.0000
13       6.0000

因此,每行 0 是一个组,每行 2 是一个组,依此类推。有了这个,我们可以直接使用pandas.Series.groupbywith pandas.core.groupby.GroupBy.cumsum

>>> df.buy_sell.groupby(df.buy_sell.bfill().diff().abs().cumsum()).cumsum()
0           NaN
1        1.0000
2           NaN
3        2.0000
4           NaN
5           NaN
6        3.0000
7       -1.0000
8           NaN
9       -2.0000
10          NaN
11       1.0000
12          NaN
13      -1.0000

我们现在需要的是将最后一个有效的观察传播到下一个有效的观察pandas.Series.ffill

>>> df.buy_sell.groupby(df.buy_sell.bfill().diff().abs().cumsum()).cumsum().ffill()
0           NaN
1        1.0000
2        1.0000
3        2.0000
4        2.0000
5        2.0000
6        3.0000
7       -1.0000
8       -1.0000
9       -2.0000
10      -2.0000
11       1.0000
12       1.0000
13      -1.0000


以上是在熊猫中更改多头/空头头寸的更有效方法的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>