简体   繁体   中英

Can I apply the XIRR function from tvm library for each row in my table, where the cash flows already on that row?

This is my first question, so I apologize in advance if it's not a perfectly asked question. I already searched all over Stack Overflow (& Google), but was unable to find what I am looking for. Also, I'm new to R and am learning it on my own as I go.

My issues is this: I am trying to compute the internal rate of return for each row in my table using the XIRR function from tvm. I was able to get XIRR to work for a single cash flow stream. Here is an example of what I was able to get to work.

# This is a sample that works
install.packages("tvm")
library(tvm)

x_CF <- c(-7500, 3000, 5000, 1200, 4000)
x_d <- as.Date(c("2016-01-01", "2016-02-01", "2016-04-15", "2016-08-01", "2017-03-26"))
xirr <- xirr(x_CF, x_d)

In my specific scenario, I have a table with the periodic cash flows and dates populated on each row for each ID. The cash flows are in columns cf1, cf2, cf3, cf(n)... and the dates are in columns date1, date2, date3, date(n)... The number of cash flows and dates are currently 14 (n=14), but could be something different (ie 36, 60, etc). This is a code that populates 2 rows from my much larger table.

# This is just 2 rows of my data table where I manually write the values (the real table is much larger and is dynamically created with code)    

sample_data <-
    matrix(
        c(
            "A",
            "2016-01-31", "2016-02-29", "2016-03-31","2016-04-30","2016-05-31",
            1000, 10, 20, -50, -1025,
            "B",
            "2016-01-31", "2016-02-29", "2016-03-31","2016-04-30", "2016-05-31",
            1000, -50, 20, 10, -1025),
        ncol = 11, byrow = TRUE)

colnames(sample_data) <-
    c("SecId",
      "date1", "date2", "date3", "date4", "date5",
      "cf1", "cf2", "cf3", "cf4", "cf5")

sample_data <- tbl_df(sample_data)

sample_data <-
    sample_data %>% mutate_at(vars(starts_with("cf")),
                              funs(as.integer))
sample_data <-
    sample_data %>% mutate_at(vars(starts_with("date")),
                              funs(as.Date))

I would like to use the XIRR function to read cf1:n and date1:n. The result should be another column (XIRR) inserted and the computed values to be A = 0.1412532 and B = 0.1458380.

Is this possible, or should I be looking into some other function? Thanks!

EDIT - Additional details and response to why "peer's" answer didn't work

My actual data has the cash flows and dates in a long table format with over 5.5 million rows. The reason I converted them to the "deprecated" table is because what I'm ultimately trying to do is create a rolling monthly IRR calculation. I figured if I built the Date and Cash flow streams on each line, then I could avoid doing a loop apply XIRR directy to each line. Creating the long table which includes every iteration of ID/Date would not be realistic for this amount of data (I don't think).

With the proposed code, the cash flows and dates are merged for the same ID's, so it doesn't account for rolling periods. I know this wasn't explained in my original question.

In addition, I have periods with missing cash flows which show NA (since they're mutated as.numeric). I need XIRR to handle this by not performing a calculation when there are any NA's. I think this can be handled with is.na = TRUE in the summarise command.

EDIT #2: Found a partial solution

After playing around with this I was able to get the XIRR function to work for the sample data from above. Here is the code that works, but takes a very long time with my actual data.

calc_xirr <- sample_data %>% rowwise() %>%
do(data.frame(., xirr = tryCatch(xirr(unlist(.[7:11]), unlist(.[2:6]),lower=0,upper=1),
                                 error = function(e) {NA}))) %>%
select(SecId, xirr)

I get a warning message "Warning message: In bind_rows_(x, .id) : Unequal factor levels: coercing to character", but the calculation is accurate.

The issue I still have with this is how slow this is for my actual data set. It runs for a very long time (6+ hours), but does produce correct results. Is there any way to rewrite this using parallel processing, or without rowwise, which I'm assuming is a loop operation and is slow.

First of all, tbl_df seems to be deprecated, use as_tibble or as.tibble instead.

I also changed your sample data, since i am getting an error when applying the data from ID "A". I defined the sample data as follows.

sample_data <-
  matrix(
    c(
      "A",
      "2016-01-01",
      "2016-02-01",
      "2016-04-15",
      "2016-08-01",
      "2017-03-26",
      -7500,
      3000,
      5000,
      1200,
      4000,
      "B",
      "2016-01-01",
      "2016-02-01",
      "2016-04-15",
      "2016-08-01",
      "2017-03-26",
      -7500,
      3000,
      5000,
      1200,
      4000
    ),
    ncol = 11,
    byrow = TRUE
  )

colnames(sample_data) <-
  c("ID",
    "date1",
    "date2",
    "date3",
    "date4",
    "date5",
    "cf1",
    "cf2",
    "cf3",
    "cf4",
    "cf5")

I split my code in two parts. The first part is to tidy the data, the second is for creating the desired value.

sample_data <- tbl_df(sample_data)

sample_data <-
  sample_data %>% mutate_at(vars(starts_with("cf")),
                            funs(as.numeric),
                            vars(starts_with("date")),
                            funs(as.Date))
sample_data_dates <-
  sample_data %>% select(starts_with("date"), ID) %>% gather(key, date, -ID) %>% mutate(index = gsub("date", "", key))
sample_data_cashflows <-
  sample_data %>% select(starts_with("cf"), ID) %>% gather(key, cashflow,-ID) %>% mutate(index = gsub("cf", "", key))

sample_data <-
  inner_join(
    sample_data_dates %>% select(-key),
    sample_data_cashflows %>% select(-key),
    by = c("ID", "index")
  ) %>% select(-index)

After this, you have a table with the column names ID, date and cashflow. Then, you can simply calculate the value as a result from the function xirr by the following code:

sample_data %>% group_by(ID) %>% summarise(xirr(cashflow,as.Date(date)))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM