python - 使用平均成本基础法计算成本

标签 python pandas

我有这个 pandas 数据框(我按“代码”升序排序,然后按“日期”和“类型”排序)在“代码”列中显示与股票相关的交易:

            Type Ticker  Qty  Price  Amount  TotalQty
Date                                                 
2020-03-01   Buy    AAA   40    1.0    40.0        40
2020-03-04   Buy    AAA   50    1.5    75.0        90
2020-03-08  Sell    AAA   60    1.2    72.0        30
2020-03-10   Buy    AAA   20    2.0    40.0        50
2020-03-15  Sell    AAA   50    2.0   100.0         0
2020-03-18   Buy    AAA   50    1.5    75.0        50
2020-03-01   Buy    BBB   50    2.0   100.0        50
2020-03-04   Buy    BBB   50    1.5    75.0       100
2020-03-09  Sell    BBB   50    1.0    50.0        50
2020-03-15   Buy    BBB   50    3.0   150.0       100
2020-03-01   Buy    CCC   10    3.0    30.0        10
2020-03-10   Buy    CCC   10    2.0    20.0        20
2020-03-11  Sell    CCC   20    2.2    44.0         0
2020-03-12   Buy    DDD   90    2.0   180.0        90

在“TotalQty”列中,我输入了“Qty”列的累计总和(考虑到“Type”列等于“Sell”时“Qty”的负号)。

现在我想为平均成本基础法计算的平均成本添加另一列。

例如,考虑股票代码“AAA”,在第一次买入后,显然我的平均成本为 1.0。然后在第二次“购买”之后,我的平均成本为 (40.0 + 75.0)/90,即“金额”(40.0 + 75.0) 除以“总数量”(90) 的总和,即 1.278。然后,在第三行,我有 60 只股票的“卖出”,因此“总数量”从 90 变为 30,但平均成本没有改变。最后在第四行,我有一个 20 件的“购买”,可以计算出新的平均成本除以“TotalQty”,即当前“金额”和先前平均成本的总和乘以previous 'TotalQty' 即 (40 + 1.278*30)/50 或 1.567。

期望的输出应该是:

            Type Ticker  Qty  Price  Amount  TotalQty  AverageCost
Date                                                              
2020-03-01   Buy    AAA   40    1.0    40.0        40        1.000
2020-03-04   Buy    AAA   50    1.5    75.0        90        1.278
2020-03-08  Sell    AAA   60    1.2    72.0        30        1.278
2020-03-10   Buy    AAA   20    2.0    40.0        50        1.567
2020-03-15  Sell    AAA   50    2.0   100.0         0        1.567
2020-03-18   Buy    AAA   50    1.5    75.0        50        1.500
2020-03-01   Buy    BBB   50    2.0   100.0        50        2.000
2020-03-04   Buy    BBB   50    1.5    75.0       100        1.750
2020-03-09  Sell    BBB   50    1.0    50.0        50        1.750
2020-03-15   Buy    BBB   50    3.0   150.0       100        2.375
2020-03-01   Buy    CCC   10    3.0    30.0        10        3.000
2020-03-10   Buy    CCC   10    2.0    20.0        20        2.500
2020-03-11  Sell    CCC   20    2.2    44.0         0        2.500
2020-03-12   Buy    DDD   90    2.0   180.0        90        2.000

我试过这段代码

df['AverageCost']=df.apply(lambda x: x.Amount if x.Type=='Buy' else np.NaN,axis=1)
df['AverageCost']=df.groupby('Ticker')['AverageCost'].cumsum().div(df['TotalQty'])
df.fillna(method='ffill',inplace=True)

但这显然给出了错误的结果。我无法使用 df.apply() 获得正确的结果,因为在“卖出”(确实不会改变平均成本)之后,我需要一个新的“买入”访问以前的平均成本来计算新的。

我应该使用 for 循环吗?如何使用?

感谢您的支持!

最佳答案

  1. 您可以过滤Buy 并获得'CumAmountBuy''CumQtyBuy'。然后,您可以将其合并回原始的 dtaframe 和 ffill()。这使我们能够获得不包括 Sell
  2. 行的累积信息
  3. 创建一个系列 s 来计算同一组内 Buy 行的总数,这些行不会直接出现在 sell 之后。我们将有条件地使用它来计算 np.select 条件计算中的一些行。
  4. 但是还有另外两个条件:a. Buy 但确实紧跟在 SellSell 行之后的行。对于 Sell 之后的 Buy 行,您可以使用 `shift()~ 进行您在评论中提到的计算,以完成前一行计算的一部分。
  5. 如果Sell,则返回NaN,但我们使用.ffill() 来填充前几行的值。

df1 = (df.copy()[df['Type'] == 'Buy']
       .assign(CumAmountBuy=df.groupby('Ticker')['Amount'].cumsum())
       .assign(CumQtyBuy=df.groupby('Ticker')['Qty'].cumsum()))
df2 = pd.merge(df,df1,how='left',
                on=['Date','Type', 'Ticker', 'Qty', 'Price', 
                    'Amount', 'TotalQty']).ffill()
s = df2['CumAmountBuy'] / df2['CumQtyBuy']
df2['AverageCost'] = np.select([((df2['Type'] == 'Buy') & (df2['Type'].shift() == 'Sell')),
                         (df2['Type'] == 'Sell')],
                       [((df2['Qty'] * df2['Price'] + df2['TotalQty'].shift() * s.shift()) / df2['TotalQty']),
                        np.nan],
                       s)
df2['AverageCost'] = round(df2['AverageCost'],3).ffill()
df2 = df2.drop(['CumQtyBuy', 'CumAmountBuy'], axis=1)
df2
Out[1]: 
          Date  Type Ticker  Qty  Price  Amount  TotalQty  AverageCost
0   2020-03-01   Buy    AAA   40    1.0    40.0        40        1.000
1   2020-03-04   Buy    AAA   50    1.5    75.0        90        1.278
2   2020-03-08  Sell    AAA   60    1.2    72.0        30        1.278
3   2020-03-10   Buy    AAA   20    2.0    40.0        50        1.567
4   2020-03-15  Sell    AAA   50    2.0   100.0         0        1.567
5   2020-03-18   Buy    AAA   50    1.5    75.0        50        1.500
6   2020-03-01   Buy    BBB   50    2.0   100.0        50        2.000
7   2020-03-04   Buy    BBB   50    1.5    75.0       100        1.750
8   2020-03-09  Sell    BBB   50    1.0    50.0        50        1.750
9   2020-03-15   Buy    BBB   50    3.0   150.0       100        2.375
10  2020-03-01   Buy    CCC   10    3.0    30.0        10        3.000
11  2020-03-10   Buy    CCC   10    2.0    20.0        20        2.500
12  2020-03-11  Sell    CCC   20    2.2    44.0         0        2.500
13  2020-03-12   Buy    DDD   90    2.0   180.0        90        2.000

关于python - 使用平均成本基础法计算成本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64271058/

相关文章:

python - 多处理还是 os.fork、os.exec?

python - 使用另一个列表计算一个列表中元素的出现次数时,有什么更快的方法

python - 从 URL 读取 ZipFile 到 StringIO 并用 panda.read_csv 解析

python - 根据字符串 python pandas 中的逗号数量将列转换为多列

python - ValueError:DataFrame 的真值不明确

python - 将文件加载到 2d numpy 数组中的有效方法

python - 如何使用 scikit-learn 加载之前保存的模型并使用新的训练数据扩展模型

python - 我想在 for 循环中串联运行多个变量,并且我想获取 x 和 y 每次迭代的总和

python - 使用 SQLAlchemy/Pandas to_SQL 填充 SQL 表时检查重复项

python - Python 中的 json_normalize