spec
spec

Reputation: 1

Creating variable based on reactive one in shiny

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.

Upvotes: 0

Views: 354

Answers (1)

jpdugo17
jpdugo17

Reputation: 7116

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.

Upvotes: 1

Related Questions