'R calculate aggregate gains or loss using FIFO method
I have two datasets, one with details on stocks purchased called buy and the other with details on stocks sold called sell
buy = data.frame(TransactionID = c(1:10),
Ticker=c(rep('MSFT',4),rep('AMZN',3),rep('DOCU',3)),
Date=c(rep('01-01-2020',2),rep('01-14-2020',2),rep('01-01-2020',2),rep('01-14-2020',1),'01-01-2020','03-15-2020','04-06-2020'),
Price=c(100,102,102,107,2000,2010,2011,197,182,167),
Quantity=c(10,10,5,5,1,1,2,12,15,15))
sell = data.frame(TransactionID=c(1:7),
Ticker=c('MSFT','MSFT','AMZN','AMZN','DOCU','DOCU','DOCU'),
Date=c('01-07-2020','01-20-2020','01-01-2020','01-30-2020','01-15-2020','04-10-2020','04-20-2020'),
Price=c(97,110,2100,2050,210,205,225),
Quantity=c(7,12,1,3,10,5,3))
The Date is inputted in the format mm-dd-YYYY
My objective is to calculate the aggregate gain/loss on all transactions for the time period included in the data, using the FIFO (First in First Out) method.
I'm trying to do this programmatically using R but have not been successful yet.
Method and desired output
I attempted the calculation manually to demonstrate the FIFO calculation method and the final result that I reached. I have been looking for a way to do this using R, but have not found a successful method yet -
1) 01-07-2020 - Ticker= MSFT - Sold 7 @ $97 - Total = $679
FIFO Cost of 7 @ $100 - Total = $700
Gain/Loss = -$21
2) 01-01-2020 - Ticker=AMZN - Sold 1 @ $2100 - Total = $2100
FIFO Cost of 1 @ $2000 - Total = $2000
Gain/Loss = +$100
3) 01-15-2020 - Ticker=DOCU - Sold 10 @ $210 - Total = $2100
FIFO Cost of 10 @ $197 - Total = $1970
Gain/Loss = +$130
4) 01-20-2020 - Ticker=MSFT - Sold 12 @ $110 - Total = $1320
FIFO Cost of 12 @ $[3x$100 + 9x$102] - Total = $1218
Gain/Loss = +$102
5) 01-30-2020 - Ticker=AMZN - Sold 3 @ $2050 - Total = $6150
FIFO Cost of 3 @ $[1x$2010 + 2x$2011] - Total = $6032
Gain/Loss = +$118
6) 04-10-2020 - Ticker=DOCU - Sold 5 @ $205 - Total = $1025
FIFO Cost of 5 @ $[2x$197 + 3x$182] - Total = $940
Gain/Loss = +$85
7) 04-20-2020 - Ticker=DOCU - Sold 3 @ $225 - Total = $675
FIFO Cost of 3 @ $182 - Total = $546
Gain/Loss = +$129
Output
Total Loss: -$21 , Total Gains: $664
Net gains are $643
Any help on how to reach this answer programmatically would be greatly appreciated.
Solution 1:[1]
A bit messy, but works.
library(dplyr)
# First of all, let's convert date to Date class:
buy$Date <- as.Date(buy$Date, '%m-%d-%Y')
sell$Date <- as.Date(sell$Date, '%m-%d-%Y')
# Empty df that will have results of each transaction:
result <- data.frame()
# For each line in Sell df we are going to run this loop
for (i in 1:nrow(sell)) {
print(sell[i, ])
# Create a temporary table by filtering 'buy' df to the right Ticker and dates before or equal to Sell operation
temp <- buy %>%
filter(Date <= sell$Date[i],
Ticker == sell$Ticker[i])
j = 1
sellQ = sell$Quantity[i]
FIFO = 0
# Running a while loop on temp table, iteratively updating FIFO
while (sellQ > 0) {
if (sellQ <= temp$Quantity[j]) {
temp$Quantity[j] = temp$Quantity[j] - sellQ
FIFO = FIFO + (sellQ * temp$Price[j])
sellQ = 0
} else {
FIFO = FIFO + (temp$Quantity[j] * temp$Price[j])
sellQ = sellQ - temp$Quantity[j]
temp$Quantity[j] = 0
j = j + 1
}
}
SoldTotal <- sell$Price[i] * sell$Quantity[i]
gain_loss <- SoldTotal - FIFO
# Creating output line:
output <- data.frame(round = i,
Ticker = sell$Ticker[i],
FIFO = FIFO,
SoldTotal = SoldTotal,
gain_loss = gain_loss)
# Adding output line to result df:
result <- rbind(result, output)
# Updating buy table
buy <- buy %>%
filter(!TransactionID %in% temp$TransactionID) %>%
bind_rows(temp) %>%
arrange(TransactionID) %>%
filter(Quantity != 0)
print('Completed successfully')
}
Final output:
TotalGain = result %>%
filter(gain_loss > 0) %>%
summarise(totalGain = sum(gain_loss)) %>%
.[[1]]
TotalLoss = result %>%
filter(gain_loss < 0) %>%
summarise(totalGain = sum(gain_loss)) %>%
.[[1]]
NetGains = TotalGain + TotalLoss
print(paste('Total Gain:', TotalGain))
print(paste('Total Loss:', TotalLoss))
print(paste('Net Gains:', NetGains))
print('Details:')
result
Result:
> print(paste('Total Gain:', TotalGain))
[1] "Total Gain: 664"
> print(paste('Total Loss:', TotalLoss))
[1] "Total Loss: -21"
> print(paste('Net Gains:', NetGains))
[1] "Net Gains: 643"
>
> print('Details:')
[1] "Details:"
> result
round FIFO SoldTotal gain_loss
1 1 700 679 -21
2 2 1218 1320 102
3 3 2000 2100 100
4 4 6032 6150 118
5 5 1970 2100 130
6 6 940 1025 85
7 7 546 675 129
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | coip |
