我有这个panda数据帧(我按"Ticker"升序排序,然后按"Date"one_answers"Type"排序(,它表示相对于"Tiger"列中股票的交易:
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
在"总计数量"列中,我输入了"数量"列的累计总和(当"类型"列等于"卖出"时,考虑"数量"的负号(。
现在,我想添加另一列以平均成本为基础的方法计算的平均成本。
例如,考虑到股票代码"AAA",在第一次买入后,我的平均成本显然为1.0。然后在第二次"买入"后,我的平均成本为(40.0+75.0(/90,即"金额"(40.0+7.0(除以"总数量"(90(的累计总和,即1.278。然后,在第三行,我有60只股票的"卖出",所以90只的"总数量"变成了30只,但平均成本没有变化。最后,在第四行,我有一个20件的"购买",新的平均成本可以用当前"金额"和以前平均成本之和除以之前的"总数量"来计算,即(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
,用于计算同一组中不直接位于sell
之后的Buy
行的总数。我们将有条件地使用它来计算np.select
条件计算中的一些行 - 然而,还有另外两个条件:a.是
Buy
但DO直接位于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