Как получить результат по группе, когда group_by не применяется. Взвешенные средние для акций - PullRequest
1 голос
/ 11 февраля 2020

Я хочу обновить средневзвешенные цены своих акций, как покупать и продавать их.
Я нашел частичное решение (хотя переполнение стека: Использование таблицы смещения и данных для обновления стоимости инвентаря ), но он не группируется по долям. Мои данные выглядят так:


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

Проблема в том, что я хотел бы перезапустить, когда «Поделиться» изменится с b на x. Как и в случае с функцией group_by.

Я ценю любую помощь.

1 Ответ

1 голос
/ 11 февраля 2020

Вот рекурсивная опция в 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)]

output:

   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
...