Reputation: 1
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
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