Сочетание блеска с тестами Quantstrat - PullRequest
0 голосов
/ 05 ноября 2018

Я пытаюсь создать веб-приложение с намерением использовать quantstrat. Тем не менее, у меня возникли некоторые трудности в интеграции двух. Нет документации по этому вопросу, поэтому сложно найти место для начала. Вот код, который у меня есть сейчас. Буду очень признателен, если вы дадите мне знать, что я делаю неправильно. Спасибо

library(shiny)
library(devtools)
library(quantmod)
library(quantstrat)
library(TTR)
library(png)
library(dplyr)
Sys.setenv(TZ = "UTC")
currency('USD')

ui <- fluidPage(

# Application title
titlePanel("myfirst"),


sidebarLayout(
  sidebarPanel(
    selectInput(
     "stocks", label = "chose stock", choices = 
      c("AAPL", "CAT")
    ),
    dateInput("init_date", "chose init date", 
     value = Sys.Date() -100),
    dateInput("start_date", "chose start date", 
     value = Sys.Date() - 99),
    dateInput("end_date", "chose end date", 
     value = Sys.Date()),
    selectInput("init_equity", "starting 
    equity", choices = c(1000, 50000))
  ),


  mainPanel(
     plotOutput("plot"),
     textOutput("text")
  )
  )

  )

  server <- function(input, output) {
  init_date = reactive({
  input$init_date
   })
  start_date = reactive({
input$start_date
})
end_date = reactive({
input$end_date
 })
 init_equity = reactive({
  input$init_equity
 })

  V = reactive({
  getSymbols(input$stocks, from = start_date(), 
 to = end_date(), index.class = "POSIXct", 
adjust = T)
 })

 observe({
stock(input$stocks, currency = "USD", multiplier 
= 1)
   })

  portfolio.st = account.st = strategy.st = 
 "my.first"

 rm.strat(portfolio.st)
 rm.strat(account.st)

 observe({ 
   initPortf(name = portfolio.st,
        symbols = "V",
        initDate = init_date())
 initAcct(name = account.st,
         portfolios = portfolio.st,
         initDate = init_date(),
         initEq = init_equity())
 initOrders(portfolio = portfolio.st,
           symbols = "V",
           initDate = init_date()
           )
 strategy(strategy.st, store = T)


 })

observe({ add.indicator(strategy = strategy.st,
            name = "SMA",
            arguments = list(x = 
  quote(Cl(mktdata)), 
                             n = 10),
            label = "nFast")

add.indicator(strategy = strategy.st, 
              name = "SMA", 
              arguments = list(x = 
quote(Cl(mktdata)), 
                               n = 30), 
              label = "nSlow")

add.signal(strategy = strategy.st,
           name="sigCrossover",
           arguments = list(columns = c("nFast", "nSlow"),
                            relationship = "gte"),
           label = "long")
add.signal(strategy = strategy.st,
           name="sigCrossover",
           arguments = list(columns = c("nFast", "nSlow"),
                            relationship = "lt"),
           label = "short")
add.rule(strategy = strategy.st,
         name = "ruleSignal",
         arguments = list(sigcol = "long",
                          sigval = TRUE,
                          orderqty = 100,
                          ordertype = "stoplimit",
                          orderside = "long", 
                          threshold = 0.0005,
                          prefer = "High", 
                          TxnFees = -10, 
                          replace = FALSE),
         type = "enter",
         label = "EnterLONG")
add.rule(strategy.st,
         name = "ruleSignal",
         arguments = list(sigcol = "short",
                          sigval = TRUE,
                          orderqty = -100,
                          ordertype = "stoplimit",
                          threshold = -0.005, 
                          orderside = "short", 
                          replace = FALSE, 
                          TxnFees = -10, 
                          prefer = "Low"),
         type = "enter",
         label = "EnterSHORT")
add.rule(strategy.st, 
         name = "ruleSignal", 
         arguments = list(sigcol = "short", 
                          sigval = TRUE, 
                          orderside = "long", 
                          ordertype = "market", 
                          orderqty = "all", 
                          TxnFees = -10, 
                          replace = TRUE), 
         type = "exit", 
         label = "Exit2SHORT")
add.rule(strategy.st, 
         name = "ruleSignal", 
         arguments = list(sigcol = "long", 
                          sigval = TRUE, 
                          orderside = "short", 
                          ordertype = "market", 
                          orderqty = "all", 
                          TxnFees = -10, 
                          replace = TRUE), 
         type = "exit", 
         label = "Exit2LONG")
applyStrategy(strategy.st, portfolios = portfolio.st)
updatePortf(portfolio.st)
updateAcct(account.st)
updateEndEq(account.st)

})

 output$plot = reactive(
  chart.Posn(portfolio.st, Symbol = "V")
  )
 }

 # Run the application 
  shinyApp(ui = ui, server = server)

1 Ответ

0 голосов
/ 20 апреля 2019

Интересная идея. То, что вы пытаетесь сделать, немного сложнее из-за характера того, как рыночные данные по торгуемым инструментам хранятся в локальной среде в переменных, имена которых равны их символам / тикерам.

Кроме того, в вашем блестящем приложении есть некоторые необычные вещи; будьте осторожны при использовании reactive({, isolate({ и других компонентов сервера. Например, когда у вас есть объекты сервера, такие как

start_date = reactive({
input$start_date
})` 

, которые являются избыточными.

Вот пример, который делает то, что вы пытаетесь достичь. Я пытался сохранить имена переменных в соответствии с вашим примером, где это возможно.

Возможно, вы захотите пересмотреть свой рабочий процесс: я думаю, что вы должны запускать большие партии симуляций в quantstrat независимо от блеска, а затем сохранять результаты на диск. Затем загрузите эти результаты с диска при запуске приложения Shiny. Тем не менее, этот пример, мы надеемся, рассмотрит все оставшиеся у вас путаницы.

Кроме того, вы должны быть осторожны с тем, как часто вы запрашиваете данные у Yahoo через getSymbols. Ниже я запрашиваю данные только один раз при первом запуске приложения и сохраняю рыночные данные в символах в среде, называемой rawdata. Затем, если вы снова остановите и перезапустите свое приложение, вы не будете продолжать запрашивать данные в Yahoo (что может привести к ошибкам, когда они регулируют объем загрузки в течение определенного периода времени).


# Could put these in global.R, these global variables are "hard coded"  ----------------
min_date_barrier <- "2012-01-01"
max_date_barrier <- "2019-04-17"
stock_universe <- c("AAPL", "CAT", "BB")

# These variables won't change when the app launches, so hard code them too:

Sys.setenv(TZ = "UTC")
currency('USD')
stock(stock_universe, currency = "USD", multiplier = 1)

portfolio.st <- account.st <- strategy.st <- "my.first"

# In here, store the original market data which contains your full range of possible values for the market data:
# Don't keep requesting data frequently otherwise you won't be able to download the data temporarily.
if (!exists("rawdata")) {
    rawdata <- new.env()
    assign("rawdata", rawdata, envir = .GlobalEnv)

    lapply(stock_universe, function(sym) {
        # if (exists(sym, envir = rawdata)) {
        #     message("Have already downloaded data for ", sym)
        #     return()
        # } else {
            getSymbols(stock_universe,
                       env = rawdata,  # important to specify environment
                       from = min_date_barrier,
                       to = max_date_barrier,
                       adjust = T, auto.assign = TRUE)
        #}
        return()
    })

}

# UI ----------------------------------------------------------------------

ui <- fluidPage(

    # Application title
    titlePanel("myfirst"),


    sidebarLayout(
        sidebarPanel(
            selectInput(
                "stock", label = "Choose stock", choices = stock_universe
            ),

            dateInput("start_date", "Choose start date",
                      value = "2018-02-03"),
            dateInput("end_date", "Choose end date",
                      value = "2019-04-10"),
            selectInput("init_equity", "starting
    equity", choices = c(1000, 50000))
        ),


        mainPanel(
            plotOutput("plot_backtest"),
            verbatimTextOutput("results")
        )
    )

)



# server ------------------------------------------------------------------

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

    # all your reactives don't make sense -- only use the inputs when you need them on the server side


    backtest_setup <- reactive({

        # need these input variables in this reactive to avoid bugs in the app when you change the time range:

        input$start_date
        input$end_date
        rm.strat(portfolio.st, silent = FALSE)
        initPortf(name = portfolio.st,
                  symbols = input$stock,        #------------------------ correct way to apply the "stock" input
                  initDate = "2000-01-01")
        initAcct(name = account.st,
                 portfolios = portfolio.st,
                 initDate = "2000-01-01",
                 initEq = as.numeric(input$init_equity)) # convert equity to numeric from string
        initOrders(portfolio = portfolio.st,
                   symbols = input$stock,  # ----------------------------------
                   initDate = "2000-01-01"
        )
        strategy(strategy.st, store = T)


        add.indicator(strategy = strategy.st,
                      name = "SMA",
                      arguments = list(x =
                                           quote(Cl(mktdata)),
                                       n = 10),
                      label = "nFast")

        add.indicator(strategy = strategy.st,
                      name = "SMA",
                      arguments = list(x =
                                           quote(Cl(mktdata)),
                                       n = 30),
                      label = "nSlow")

        add.signal(strategy = strategy.st,
                   name="sigCrossover",
                   arguments = list(columns = c("nFast", "nSlow"),
                                    relationship = "gte"),
                   label = "long")
        add.signal(strategy = strategy.st,
                   name="sigCrossover",
                   arguments = list(columns = c("nFast", "nSlow"),
                                    relationship = "lt"),
                   label = "short")
        add.rule(strategy = strategy.st,
                 name = "ruleSignal",
                 arguments = list(sigcol = "long",
                                  sigval = TRUE,
                                  orderqty = 100,
                                  ordertype = "stoplimit",
                                  orderside = "long",
                                  threshold = 0.0005,
                                  prefer = "High",
                                  TxnFees = -10,
                                  replace = FALSE),
                 type = "enter",
                 label = "EnterLONG")
        add.rule(strategy.st,
                 name = "ruleSignal",
                 arguments = list(sigcol = "short",
                                  sigval = TRUE,
                                  orderqty = -100,
                                  ordertype = "stoplimit",
                                  threshold = -0.005,
                                  orderside = "short",
                                  replace = FALSE,
                                  TxnFees = -10,
                                  prefer = "Low"),
                 type = "enter",
                 label = "EnterSHORT")
        add.rule(strategy.st,
                 name = "ruleSignal",
                 arguments = list(sigcol = "short",
                                  sigval = TRUE,
                                  orderside = "long",
                                  ordertype = "market",
                                  orderqty = "all",
                                  TxnFees = -10,
                                  replace = TRUE),
                 type = "exit",
                 label = "Exit2SHORT")
        add.rule(strategy.st,
                 name = "ruleSignal",
                 arguments = list(sigcol = "long",
                                  sigval = TRUE,
                                  orderside = "short",
                                  ordertype = "market",
                                  orderqty = "all",
                                  TxnFees = -10,
                                  replace = TRUE),
                 type = "exit",
                 label = "Exit2LONG")

    })

    V <- reactive({

        validate(need(input$start_date >= as.Date(min_date_barrier), "start date cannot be less than hard coded min_date_barrier"))
        validate(need(input$end_date <= as.Date(max_date_barrier), "end date cannot be greater than  hard coded max_date_barrier"))
        validate(need(as.Date(input$start_date) < as.Date(input$end_date), "start date must be less than end date."))
        # assign symbol market data to the global environment for the range of dates you want:
        time_rng <- paste0(input$start_date, "/", input$end_date)
        mdata <- get(input$stock, envir = rawdata)
        mdata <- mdata[time_rng]

        validate(need(NROW(mdata) > 0, "no data available, choose an appropriate time range"))

        mdata
    })

    backtest_results <- reactive({

        backtest_setup()
        mdata <- V()
        assign(input$stock, mdata, envir = .GlobalEnv)
        # not supplying mktdata as a parameter, so look in global environment for objects with the symbol names (which will exist because V assigns to .GlobalEnv):
        applyStrategy(strategy.st, portfolios = portfolio.st)
        # alternatively you could pass in the data directly to apply strategy if you're just using one symbol of data in the applyStrategy call, instead of having applyStrategy directly search in the .GlobalEnv for the symbol name
        #applyStrategy(strategy.st, portfolios = portfolio.st, mktdata = mdata)
        updatePortf(portfolio.st)
        updateAcct(account.st)
        updateEndEq(account.st)

    })

    output$plot_backtest = renderPlot({
        backtest_results()
        chart.Posn(portfolio.st, Symbol = input$stock)
    })

    output$results = renderPrint({
        backtest_setup()
        tmpdata <- V() # need this here so that any changes to the inputs will reprint the trade stats table
        print(tradeStats(portfolio.st))
    })

}

# Run the application
shinyApp(ui = ui, server = server)

Приложение будет выглядеть примерно так:

enter image description here

...