0

我正在尝试创建一个与金融相关的 R Shiny 应用程序。截至目前,我有一个用于创建自定义投资组合的选项卡,这需要我为numericInput原始source_file. 示例source_file如下所示:

日期 沪深500 上海 CSI300 恒指 性病
2016-01-01 +5% -2% +5% +10% +12%
2016-01-08 +3% +13% -8% -3% +10%
2016-01-15 +2% +11% -3% +4% -15%

目前,我必须numericInput为每个变量手动硬编码每个框,如下所示:

tabPanel("Custom Portfolio by Weight",
                           sidebarPanel(
                             tags$h3("Create your own Custom Portfolio by Asset Weight"),
                             tags$h4("Input:"),
                             numericInput(inputId = "custom_csi500", "CSI500 (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_shanghai", "Shanghai Stock Exchange (%)",  min = 0, max = 100),
                             numericInput(inputId = "custom_csi300", "CSI300 (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_hsi", "HSI (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_sti", "STI (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_twse", "TWSE (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_msciw", "MSCI World (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_sp500", "S&P500 (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_n225", "Nikkei 225 (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_lse", "London Stock Exchange (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_asx", "ASX (%)", min = 0, max = 100),

但是,我想创建一些可以扩展到具有我指定的不同数量变量的任何数据帧的东西,而不必手动硬编码它们。我希望任何人都能够帮助我编写一个能够阅读的代码我的数据框中的变量数(日期列除外)并numericInput为每个变量创建那么多框。非常感谢您的帮助!如果需要,我在下面附上了我的 App.R 和 Global.R 以供参考。干杯!

应用程序

# Load packages
library(shiny)
library(shinythemes)
source("./global.R")

# Defining UI
ui <- fluidPage(theme = shinytheme("darkly"),
                navbarPage(
                  "Test App",
                  tabPanel("Custom Portfolio by Weight",
                           sidebarPanel(
                             tags$h3("Create your own Custom Portfolio by Asset Weight"),
                             tags$h4("Input:"),
                             numericInput(inputId = "custom_csi500", "CSI500 (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_shanghai", "Shanghai Stock Exchange (%)",  min = 0, max = 100),
                             numericInput(inputId = "custom_csi300", "CSI300 (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_hsi", "HSI (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_sti", "STI (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_twse", "TWSE (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_msciw", "MSCI World (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_sp500", "S&P500 (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_n225", "Nikkei 225 (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_lse", "London Stock Exchange (%)", min = 0, max = 100),
                             numericInput(inputId = "custom_asx", "ASX (%)", min = 0, max = 100),
                             mainPanel(
                             plotOutput(outputId = "custom_returns"),
                           ), #mainPanel
                ), #tabpanel
                ) #navbarPage
) #fluidPage

server <- function(input, output, session) {

#to output custom_returns for Custom Portfolio by Asset Weight
    output$custom_returns <- renderPlot({
      calculate_portfolio_returns(
        customrange = input$customrange,
        asset_weights = c(input$custom_csi500/100,
          input$custom_shanghai/100,                
          input$custom_csi300/100,
          input$custom_hsi/100,
          input$custom_sti/100,
          input$custom_twse/100,
          input$custom_msciw/100,
          input$custom_sp500/100,
          input$custom_n225/100,
          input$custom_lse/100,
          input$custom_asx/100,
          input$custom_custom/100))
    })
}
  
# Create Shiny Object
  shinyApp(ui = ui, server = server)

全球.R

# Load packages
library(tidyverse)
library(ggcorrplot)
library(zoo)
library(xts)
library(testit)
library(PerformanceAnalytics)

#choose source file to work with
file_name = file.choose()
source_file = read_csv(file_name)
source_file$Date = as.Date(source_file$Date, format = "%Y-%m-%d")

########################
calculate_portfolio_returns = function(customrange, asset_weights)
{
  #filter source file by date range specified
  source_file_filtered <- source_file %>% 
    filter(Date >= customrange[1] & Date <= customrange[2])
  
  source_file_filtered_no_date <- source_file_filtered[,2:length(source_file_filtered)]
  
  #create new column called Cumulative_Returns to convert % daily returns
  Cumulative_Returns <- cumsum(source_file_filtered_no_date)
  
  # Extract necessary parameters
  n_cols = ncol(Cumulative_Returns)
  n_assets = n_cols
  
  #To ensure portfolio is always weighted at 100% at all times
  assert(length(asset_weights) == n_assets)
  assert(abs(sum(asset_weights)-1) <= 0.001)
  
  portfolio_returns = data.matrix(Cumulative_Returns) %*% asset_weights
  portfolio_returns_with_date = cbind(source_file_filtered[,1], portfolio_returns)
  g = ggplot(data = portfolio_returns_with_date, mapping = aes(x=Date, y=portfolio_returns)) +
   geom_line(color="blue") + ggtitle(paste("Custom Portfolio Returns from", customrange[1], "to", customrange[2])) +
   geom_hline(yintercept = 0, linetype = "dashed") + theme(plot.title = element_text(hjust=0.5)) +
    ylab("Portfolio Returns (%)")
  print(g)
}

4

1 回答 1

1

这是一个可能对您有帮助的演示。

您可以将 .csv 文件上传到闪亮的应用程序。它将忽略第一列(或者您可以修改以专门删除日期列)。

数字输入将根据读入的标题列名称动态生成。

该演示有一个calc按钮,它将存储输入数据并进行进一步处理(计算返回)。还添加了一个表格来显示输入的数据。

编辑:如果按下calc按钮后要调用自定义函数 ( calculate_portfolio_returns),则可以在 中添加对该函数的调用eventReactive,因为这取决于输入按钮。要传递来自数字输入的值,您可以将这些值临时存储在 vectorvals中,然后vals作为参数传递给函数(参见下面的修改代码)。在演示中,我调用了一个自定义函数calc_sum,它将在控制台中打印数字输入的总和。最后一点,我return在末尾添加了一个明确的input_vals(),以便vals可以共享以在output$table.

library(shiny)

ui <- fluidPage(
  fileInput(inputId = "upload_file", "", accept = '.csv'),
  uiOutput("num_inputs"),
  actionButton("calc", "Calculate"),
  tableOutput("table")
)

server <- function(input, output, session) {
  
  data <- reactive({
    infile <- input$upload_file
    if (is.null(infile))
      return(NULL)
    read.csv(infile$datapath, header = TRUE, sep = ",")
  })
  
  header_vars <- reactive({
    names(data()[-1])
  })
  
  output$num_inputs <- renderUI({
    vars <- length(header_vars())
    if (vars > 0) {
      div(
        lapply(seq(vars), function(x) {
          numericInput(inputId = paste0("var_", x), label = header_vars()[x], value = 0, min = 0, max = 100)
        })
      )
    }
  })
  
  input_vals <- eventReactive(input$calc, {
    n_vars <- length(header_vars())
    vals <- c()
    if (n_vars > 0) {
      vals <- sapply(seq(n_vars), function(i) {
        input[[paste0("var_", i)]]
      }) 
    }
    calc_sum(vals)
    return(vals)
  })
  
  calc_sum <- function(vals) {
    print(sum(vals))
  }
  
  output$table <- renderTable({
    data.frame(
      vars = header_vars(),
      vals = input_vals()
    )
  })
  
}

shinyApp(ui = ui, server = server)
于 2021-05-12T15:04:05.263 回答