我有这个 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 循环吗?如何使用?
感谢您的支持!
最佳答案
- 您可以过滤
Buy
并获得'CumAmountBuy'
和'CumQtyBuy'
。然后,您可以将其合并回原始的 dtaframe 和ffill()
。这使我们能够获得不包括Sell
行的累积信息
- 创建一个系列
s
来计算同一组内Buy
行的总数,这些行不会直接出现在sell
之后。我们将有条件地使用它来计算np.select
条件计算中的一些行。 - 但是还有另外两个条件:a.
Buy
但确实紧跟在Sell
和Sell
行之后的行。对于Sell
之后的Buy
行,您可以使用 `shift()~ 进行您在评论中提到的计算,以完成前一行计算的一部分。 - 如果
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/