R/portfolio.R

#' @name portfolio
#' @aliases portfolio
#' @docType class
#' @title Portfolio Object Manager
#' @description {
#' Manage your portfolio never be so easy. This object will save all your portfolio and help you manage them all at once.
#' You can do backtesting by combining this object with powerful tools such as TTR package to generate a technical analysis.
#' }
#' @author Suberlin Sinaga @2021
#' @importFrom dplyr rename
#' @return Object of type \code{\link{portfolio}}
portfolio <- R6Class(
  "portfolio",
  private = list(init = NULL),
  public = list(
    #' @description Add portfolio that you have into the object. Each portfolio will be stored using prefix \code{portfolio.}
    #' @aliases add_portfolio
    #' @param data: The portfolio that you add
    #' @param symbol: The name of the portfolio you were added
    #' @return Object of type \code{\link{portfolio}}
    add_portfolio = function(data, symbol = deparse(substitute(data))){
      if (!all(c("o", "l", "h", "c", "t", "v") %in% names(data))){
        stop("Please provide tolhcv data!!")
      }
      private[[paste0("portfolio.", symbol)]] = data %>%
        rename(time = t,
               open = o,
               close = c,
               high = h,
               low = l,
               volume = v)
    },
    #' @description Add colum to your portfolio data. In some cases, you have your own custom column. In that case, you can add some by using this method.
    #' @aliases add_col
    #' @param x: vector for the data
    #' @param symbol: {The name of the portfolio you want to add to. Please be aware, if you set this leave as NULL, it may not work as expected. It is
    #' because it will add the column to all portfolio that may have different dimension.}
    #' @return Object of type \code{\link{portfolio}}
    add_col = function(x, colname, symbols = NULL) {
      if (missing(symbols)) {
        names = grep("portfolio.", names(private), value = TRUE)
      } else {
        if (length(symbols) == 1) {
          names = grep(paste0("portfolio.", symbols), names(private), value = TRUE)
        } else {
          names = c()
          for (symbol in symbols) {
            name = grep(paste0("portfolio.", symbol), names(private), value = TRUE)
            names = c(names, name)
          }
        }
      }
      for (name in names) {
        private[[name]][[colname]] = x
      }
      invisible(self)
    },
    #' @description {Instead of adding a column, you might
    #' want to add an indicator to your portfolio. Using this method you can directly calculate the indicator and add the data to your portfolio.}
    #' @aliases add_indicator
    #' @param .fun: the function to calculate the desired indicator
    #' @param colnames: The name of the column to store the new indikator. If left blank, it will take the name of the function.
    #' @param to_vector: To indicate you want to drop the dataframe using \code{drop = TRUE} argument.
    #' @param ...: This ellipsis used to store the arguments needed by the function. Refers to each function to use it.
    #' @return Object of type \code{\link{portfolio}}
    add_indicator = function(.fun, colnames, indicator_name = deparse(substitute(.fun)), to_vector = FALSE, ...) {
      if (class(.fun) != "function") stop("Please privide a function")
      names = grep("portfolio.", names(private), value = TRUE)
      if (length(names) == 0) stop("You hadn't registered any symbol and the data. Please register it first.")
      for (name in names) {
        if (to_vector) {
          private[[name]][[indicator_name]] = .fun(private[[name]][, colnames, drop = TRUE], ...)
        } else {
          private[[name]][[indicator_name]] = .fun(private[[name]][, colnames], ...)
        }
      }
      invisible(self)
    },
    #' @description {In trading data, the famous indicators are EMA, SMA or so on that in fact need to lag data. The backwards is that it leaves so many NAs.
    #' Call this method to clean the messy.}
    #' @aliases remove_na
    #' @return Object of type \code{\link{portfolio}}
    remove_na = function() {
      names = grep("portfolio.", names(private), value = TRUE)
      if (length(names) == 0) stop("You hadn't registered any symbol and the data. Please register it first.")
      for (name in names) {
        private[[name]] = private[[name]][complete.cases(private[[name]]),]
      }
      invisible(self)
    }
  ),
  lock_objects = FALSE
)
blakcjack/ims documentation built on Dec. 19, 2021, 9:52 a.m.