Search code examples
rshinygolembizdays

How do I globally load Rmetric Financial calendars into `golem` at the startup?


Question:

What are the best practices to go about setting a "global" financial calendar using load_rmetrics_calenders(), ie a singular run of a function in golem?

Background:

This question is asked prior to finding a possible solution. I am using a function that I made which uses the {bizdays} package to determine certain financial dates. I need to use the function load_rmetrics_calenders() to initiate/set the calenders for a subsequent call in bizdayz::adjust.previous(..., cal = "Rmetrics/NYSE). I understand I could also use a globl setting to set the calneder but that has given me issues in the past.

I would like the to run load_rmetrics_calenders() once at the beginning of a golem instance -- rather than having to call the function directly in the function, which slows it down a fair bit.

Reprex:

my_function<- function(stock = NULL, from = NULL, to = NULL, ...){
    # Set Biz Calender 
 
    # bizdays::load_rmetrics_calendars(year = c(1950:2030), financial = TRUE)

    # DEFENSIVES ---------------------------------------------------------------------------------------------------
    # Assign `to` --> yesterdays close, will reset when close data comes in, 12am
    to <- bizdays::adjust.previous(Sys.Date() - 1, cal = "Rmetrics/NYSE")

I would like to omit setting the calendar every time I call this function, or its called in the golemApp instance while running online.

Possible answers:

  • Execute load_rmetrics_calenders() within golem::runApp() --> once when launched
  • Execute load_rmetrics_calenders() within the server of a golem module that acts as a homepage for the website/app
  • Embed the calendar into settings? --> not aware of a working solution

#1: Current implementation

# Just running the function within the `runApp()`

run_app <- function(
  onStart = NULL,
  options = list(),
  enableBookmarking = NULL,
  ...
) {

  #Configure financial calender
  golem::cat_dev("Loading NYSE calender from Quantlib \n")
  bizdays::load_quantlib_calendars(ql_calendars = "UnitedStates/NYSE", from = "1950-01-01", to = "2030-01-01")
  golem::cat_dev("Done loading calender. \n")

  # Configure global polished settings
  polished_config()

  reactlog::reactlog_enable()

  with_golem_options(
    app = brochureApp(
      # Putting the resources here
      golem_add_external_resources(),
      # Add pages
      welcomePage(),
      # login(),
      dashboard(),
      # logout(),
      terms(),
      onStart = onStart,
      options = options,
      enableBookmarking = enableBookmarking,
      wrapped = shiny::tagList
    ),
    golem_opts = list(...)
  )
}

#2: Writing it in a script to run instead of calling runApp() ie from Docker

# .R file to be called instead of running run_app() explicitly 

  #Configure financial calender
  golem::cat_dev("Loading NYSE calender from Quantlib \n")
  bizdays::load_quantlib_calendars(ql_calendars = "UnitedStates/NYSE", from = "1950-01-01", to = "2030-01-01")
  golem::cat_dev("Done loading calender. \n")

  # Configure global polished settings
  polished_config(...)

  reactlog::reactlog_enable()

# Run app with the calendar loaded
run_app()


Solution

  • You can run the function before the run_app() function is launched and pass the result as an argument to the run_app() fun.

    For example: https://github.com/inrae/diades.atlas/blob/main/app.R#L30, here, I build a series of elements and they are passed to run_app(), so it's run less often (here, every time a new app is launched in RStudio Connect).

    You can also set at the top of your server if you want the function to be launched at every shiny session (but I suppose this is not exactly what you want).

    So, it depends of your deployment logic:

    • If you're deploying a container, you can use (pseudo code here) : CMD R -e "myapp::run_app(data = mypak:build_stuff())". Note that it will depend on the container management service you are using. For example Shiny Proxy will run one container by user, so build_stuff() will be called every time a new user comes.

    • If you're on RStudio Product, you can use the run_app() method from the linked GitHub code.

    If you need to explore the behavior of {golem} apps and when things are run, I've got a toy example here https://github.com/ColinFay/golemexamples/tree/master/golemloadorder that will let you know when things are run/loaded.

    Cheers, Colin