group_by 不适用时如何按组获得结果。股票的加权平均数
How to have a result by group when group_by doesn't apply. Weighted averages for stocks
我想在买入和卖出时更新我的股票价格的加权平均值。
我找到了一个部分解决方案(尽管堆栈溢出:Using shift and data table to update the value of an inventory),但它没有按份额分组。
我的数据如下所示:
library(data.table)
ledger <-data.table(
Share = c(rep("b",3), rep("x",2)),
Prc = c(10,20,15, 35,40),
Qty= c(300,-50,100, 50,-10),
Op =c("Purchase", "Sale", "Purchase", "Purchase", "Sale")
)
到目前为止我想到了什么:
ledger<-ledger %>%group_by(Share)%>%
mutate(Stock = cumsum(Qty))%>%
group_by(Share)%>%
mutate(id =row_number())%>%
mutate(AvgPrice =ifelse( id ==1, Prc, NA_real_))
ledger<-as.data.table(ledger)
ledger[, Stock := cumsum(Qty)] # compute Stock value
ledger[, `:=` ( id = .I, AvgPrice = NA_real_ ) ] # add id and AvgPrice columns
ledger[ 1, AvgPrice := Prc] # compute AvgPrice for first row
# work with remaining rows and find the AvgPrice
ledger[ ledger[, .I[-1]], AvgPrice := {
if( Op == "Sale" ){
ledger[ .I-1, AvgPrice ]
} else {
round( ( ( Qty * Prc ) + ledger[ .I-1, AvgPrice * Stock ] ) /
( Qty + ledger[ .I-1, Stock]) ,
digits = 2 )
}
}, by = id ]
ledger[, id := NULL ] # remove id column
问题是我希望它在 "Share" 从 b 变为 x 时重新启动。就像使用 group_by 函数一样。
感谢任何帮助。
这是data.table
中的一个递归选项:
ledger[, AvgPrice := {
latestInventory <- 0L
lastAvgPrice <- 0L
.SD[, {
Inventory <- cumsum(c(latestInventory, Qty))
QtyBought <- cummax(Inventory)
ValueBought <- cumsum(c(latestInventory * lastAvgPrice,
replace(Qty, Op=="Sale", 0) * Prc))
AvgCostPrice <- ValueBought / QtyBought
latestInventory <- Inventory[.N+1L]
lastAvgPrice <- AvgCostPrice[.N+1L]
.(AvgCostPrice[-1L])
}, .(g=cumsum(shift(Op , fill="Sale")=="Sale" & Op=="Purchase"))]$V1
}, .(Share)]
输出:
Share Prc Qty Op AvgPrice
1: b 10 300 Purchase 10.00000
2: b 20 -50 Sale 10.00000
3: b 15 100 Purchase 11.42857
4: x 35 50 Purchase 35.00000
5: x 40 -10 Sale 35.00000
我想在买入和卖出时更新我的股票价格的加权平均值。
我找到了一个部分解决方案(尽管堆栈溢出:Using shift and data table to update the value of an inventory),但它没有按份额分组。
我的数据如下所示:
library(data.table)
ledger <-data.table(
Share = c(rep("b",3), rep("x",2)),
Prc = c(10,20,15, 35,40),
Qty= c(300,-50,100, 50,-10),
Op =c("Purchase", "Sale", "Purchase", "Purchase", "Sale")
)
到目前为止我想到了什么:
ledger<-ledger %>%group_by(Share)%>%
mutate(Stock = cumsum(Qty))%>%
group_by(Share)%>%
mutate(id =row_number())%>%
mutate(AvgPrice =ifelse( id ==1, Prc, NA_real_))
ledger<-as.data.table(ledger)
ledger[, Stock := cumsum(Qty)] # compute Stock value
ledger[, `:=` ( id = .I, AvgPrice = NA_real_ ) ] # add id and AvgPrice columns
ledger[ 1, AvgPrice := Prc] # compute AvgPrice for first row
# work with remaining rows and find the AvgPrice
ledger[ ledger[, .I[-1]], AvgPrice := {
if( Op == "Sale" ){
ledger[ .I-1, AvgPrice ]
} else {
round( ( ( Qty * Prc ) + ledger[ .I-1, AvgPrice * Stock ] ) /
( Qty + ledger[ .I-1, Stock]) ,
digits = 2 )
}
}, by = id ]
ledger[, id := NULL ] # remove id column
问题是我希望它在 "Share" 从 b 变为 x 时重新启动。就像使用 group_by 函数一样。
感谢任何帮助。
这是data.table
中的一个递归选项:
ledger[, AvgPrice := {
latestInventory <- 0L
lastAvgPrice <- 0L
.SD[, {
Inventory <- cumsum(c(latestInventory, Qty))
QtyBought <- cummax(Inventory)
ValueBought <- cumsum(c(latestInventory * lastAvgPrice,
replace(Qty, Op=="Sale", 0) * Prc))
AvgCostPrice <- ValueBought / QtyBought
latestInventory <- Inventory[.N+1L]
lastAvgPrice <- AvgCostPrice[.N+1L]
.(AvgCostPrice[-1L])
}, .(g=cumsum(shift(Op , fill="Sale")=="Sale" & Op=="Purchase"))]$V1
}, .(Share)]
输出:
Share Prc Qty Op AvgPrice
1: b 10 300 Purchase 10.00000
2: b 20 -50 Sale 10.00000
3: b 15 100 Purchase 11.42857
4: x 35 50 Purchase 35.00000
5: x 40 -10 Sale 35.00000