I'd convert this into a tibble and work in the Tidyverse. The easiest way is to take your dataframe and convert it to a tibble like I do below on the mtcars dataset.
library(tidyverse)
library(lubridate)
mtcars <- mtcars %>% tibble()
mtcars %>% head()
In your example, i had to convert it into a tibble since I didn't have the dataframe provided. Depending on your data, I'd say your best bet is to group by isin and then make sure you're in order.
tribble(
~isin, ~Year, ~Month, ~MV, ~P, ~RI, ~VA, ~MNEM,
"BMG0539N1020", 2011, 12, 804.00, 20.10, 92.80, 2888.1, "N:AOD",
"BMG0539N1020", 2012, 12, 1148.00, 28.70, 132.50,13.5, "N:AOD",
"BMG067231032", 2014, 12, 3598.35, 100.91,90.40, 406557.6, "N:AVAN"
) %>%
mutate(across(c(Year, Month), ~as.integer(.))) %>%
# make sure you get end of year data to make these annual returns.
filter(Month == 12) %>%
mutate(report_date = make_date(year = Year, month = Month, day = 1) %>% ceiling_date(unit = 'month'),
year_end = as_date(report_date - 1),
report_year = year(report_date)) %>%
group_by(isin) %>%
arrange(report_date, .by_group = TRUE) %>%
mutate(ret = RI / lag(RI) - 1) %>%
ungroup()