将闪亮与Quantstrat回测结合起来 [英] Combining shiny with Quantstrat backtests

查看:80
本文介绍了将闪亮与Quantstrat回测结合起来的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正试图制作一个使用Quantstrat的Web应用程序.但是,我很难将两者整合在一起.没有关于此的文档,因此很难找到起点.这是我现在拥有的代码.如果您能让我知道我做错了,将不胜感激.谢谢

I am trying to make a web app with the intention of using quantstrat. However I am having a bit of difficulty integrating the two. There is no documentation on this so it's tough to find a place to start. Here is the code I have right now. It would be much appreciated if you could let me know what I am doing wrong. Thank you

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)

推荐答案

有趣的想法.由于所交易产品的市场数据如何存储在本地环境中的变量名称(其名称等于交易品种/股票代码)的性质,您要尝试执行的操作有些挑战.

Interesting idea. What you're trying to do is a little challenging due to the nature of how the market data for the instruments traded is stored in the local environment in variables that have names equal to their symbols/tickers.

此外,您的闪亮应用程序还具有一些奇特的功能;请注意如何使用reactive({isolate({和其他服务器组件.例如,当您拥有

Also, you're some peculiar things with your shiny app; be careful how you use reactive({, isolate({ and other server components. For instance when you have server objects like

start_date = reactive({
input$start_date
})` 

那是多余的.

这里是一个示例,它可以完成您想要达到的目标.我尽力使变量名与您的示例保持一致.

Here is an example that does what you're trying to achieve. I've tried to keep the variable names consistent with your example where possible.

您可能想重新考虑您的工作流程:我认为您应该独立于quantstratquantstrat中运行大量仿真,然后将结果保存到磁盘.然后,在启动Shiny应用程序时从磁盘加载这些结果.尽管如此,该示例还是有望解决您所遇到的任何困惑.

You may want to reconsider your workflow: I think you should run large batches of simulations in quantstrat independently of shiny, then save the results to disk. Then load these results from disk when you launch your Shiny app. Nevertheless this example will hopefully sort out any remaining confusion you have.

此外,您应该注意通过getSymbols向yahoo请求数据的频率.我下面要做的是仅在应用程序首次启动时请求一次数据,并将市场数据存储在名为rawdata的环境中的符号中.然后,如果停止并再次重新启动应用程序,您将不会继续向yahoo请求数据(这可能会在一段时间内限制您可以下载的数量,从而给您带来错误).

Also, you should be careful about how often you request data from yahoo via getSymbols. What I do below is request the data only once when the app is first launched, and store the market data in the symbols in an environment called rawdata. Then if you stop and restart your app again, you won't keep making requests to yahoo for data (which might give you errors when they throttle how much you can download within a period of time).


# 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)

该应用将如下所示:

这篇关于将闪亮与Quantstrat回测结合起来的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆