0

I'm working on shiny app, which calculates basic portfolio statistics. Alongside with stocks, user can define weights which one wants to assign to particular stocks - so the vector with weights should have length equal to the choices vector, and sum up to 1.

I've written this part of code in a server function as I want it to appear after clicking download button:

ui:
 uiOutput("weights")

server:
output$weights <- renderUI({
   textInput('weights', 'Enter a vector of weights (comma delimited - sum must be equal to 1)', 
   value=paste(rep(round(1/length(input$choices),digits=2), times=length(input$choices)), 
   collapse=", "))})

weights <- reactive(
           as.numeric(unlist(strsplit(input$weights, ","))))

Above part work - I've made some test outputs in ui function, so I can see if everything is fine. It also transforms character vector inputted by user in specific way (comma delimited) into numeric one (I couldn't think of other way to do that). However I need to let the app fix the weights vector if user provides wrong one (for example when the sum is not equal 1 or when the length is incorrect). And it would be perfect if that was reactive, so the further calculations would perform automatically. However when I try to create variable containing the if statement that fixes mistakes:

weights1 <- reactive({
                (if(length(weights)==length(names) & sum(weights)==1) weights else
                if(length(weights)==length(names) & sum(weights)!=1) c(weights/sum(weights)) else
                  c(rep(1/length(names),length(names))))})

I get an error:

Warning: Error in sum: invalid 'type' (closure) of argument

Is there any way around it?

After trying solution proposed by @stefan, I have another issue, now I am getting message:

Warning: Error in strsplit: non-character argument

When I try to perform calculations using weights1() vector.

 PortfolioReturn <- function(names, stocks, weights) 
            {
              # portfolio = close_price*weight
              portfolio <- as.data.frame(mapply('*', stocks[,-1], weights))
              #row.names(portfolio) <- stocks$Date
              # daily return = (P(t) - P(t-1)) / P(t-1)
              # it is the percentage price difference
              returns <- as.data.frame(apply(portfolio, 2, diff.xts, lag = 1)/apply(portfolio, 2, DataCombine::shift, shiftBy = -1, reminder = FALSE))
              returns
              # cumulate daily returns
              returns$cum_returns <- as.vector(apply(returns, 1, sum))
              return(returns)
            }
            
            
            ((((
            
            weightsx <- rep(round(1/length(input$choices),digits=2), times=length(input$choices))
            
            returns <- PortfolioReturn(input$choices, stocks, weights1())
            output$returns <- renderTable(tail(returns))

Code works when using weightsx vector, that is giving an equal weight to every stock in chosen portfolio. I'm guessing it is the issue with vector transformation from character to numeric one, but I have no clue how to solve this problem.

2
  • 1
    Only a guess: As weights is a reactive you have to call it like a function, i.e. try with weights() in weights1 <- reactive(... instead of just weights. Commented Jun 4, 2021 at 19:33
  • 1
    It helped, thank you very much! However I'm getting another error: Error in strsplit: non-character argument; I'll edit original post. Commented Jun 4, 2021 at 19:48

1 Answer 1

1

As pointed out by @stefan, reactive values can be accessed adding () at the end (like calling a function).

weights1 <- reactive({
    (if(length(weights())==length(names) & sum(weights())==1) weights() else
        if(length(weights())==length(names) & sum(weights())!=1) c(weights()/sum(weights())) else
            c(rep(1/length(names),length(names))))})

Same if names variable is reactive, which is not specified in the code.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.