I have used random forest in R to get probabilities for stocks being in a certain class. With those probabilities i would like to construct portfolios containing the 5 stocks with the highest probabilities on the first date of the dataset, and then rebalance this every 10 days with the stocks with the highest ranking at that time. The portfolio should be equal weighted.

Here is some example data that i think is representable of my data.

Date <- rep(seq(as.Date("2009/01/01"), by = "day", length.out = 100), 10)
Name <- c(rep("Stock A", 100), rep("Stock B",100), rep("Stock C", 100), rep("Stock D", 100), rep("Stock E",100), rep("Stock F",100), rep("Stock G",100), rep("Stock H",100), rep("Stock I", 100), rep("Stock J", 100))
Return <- rnorm(1000)
Prob <- runif(1000)           

DF <- data.frame(Date, Name, Return, Prob)
DF <- DF %>% arrange(Date, desc(Prob))
> head(DF)
        Date    Name      Return      Prob
1 2009-01-01 Stock F  0.52259644 0.8084277
2 2009-01-01 Stock A  0.57720376 0.7617348
3 2009-01-01 Stock B -0.09864981 0.7256358
4 2009-01-01 Stock E -1.26136381 0.6200346
5 2009-01-01 Stock G -1.37360527 0.5680765
6 2009-01-01 Stock D -0.04794049 0.4793370

So the portfolio would contain stock F, A, B, E, and G for the first 10 days, and then rebalance it with the stocks of the highest percentage.

I am not very good at coding and R, and have tried looking at options as to how i can do this with PortfolioAnalytics, PerformanceAnalytics and tidyquant, but am not able to find a solution where i understand how to do this, as i am not interested in using any form of optimizing. I need a simple portfolio determined by my calculated percentages, with rebalancing.

If anyone has any suggestions as to how i can do this, i would highly appreciate it. And if this is the wrong forum for posting this question, i am sorry and will post it elsewhere.


Using dplyr::group_by and dplyr::top_n to get the highest probabilities by date. Then expand to get a weight vector. See my comments in the code.


weights <- DF %>% 
  # filter the dates you want to rebalance on
  filter(Date %in% seq(min(Date), max(Date), by = "10 days")) %>% 
  # group by Date and get the top 5 by Prob
  group_by(Date) %>% 
  top_n(5, Prob) %>% 
  # ungroup removes the grouping again
  ungroup() %>%
  # select Date and Name and add the weight
  select(Date, Name) %>% 
  mutate(weight = 1/5) %>%
  # last step is to complete the weights over all dates
  # (I transform it to wide format first, and locf "last observation carried forward" the NAs,
  #  there might be a more elegant way for this, I'm not sure)
  pivot_wider(names_from = "Name", values_from = "weight", values_fill = list(weight = 0)) %>% 
  complete(Date = seq(as.Date("2009/01/01"), by = "day", length.out = 100)) %>% 
  mutate_at(vars(starts_with("Stock")), na.locf) %>% 
  pivot_longer(names_to = "Name", values_to = "weight", -"Date")

DF %>% 
  # join the weights to the original returns
  left_join(weights, by = c("Date", "Name")) %>% 
  # calculate PF Returns
  group_by(Date) %>% 
  summarise(Return = sum(Return*weight))
  • $\begingroup$ Thank you so much for this! It looks to be what i needed, i will try it tomorrow. $\endgroup$ – signe Apr 16 '20 at 20:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.