RBloomberg

Il semble que le package RBloomberg ne soit plus mis à jour. Je dis bien « il semble » parce qu’à titre personnel, je ne l’ai jamais utilisé.

Pour ceux que ça intéresse, voici mes fonctions : c’est un poil limité (pas de données intraday), on peut coder ça de manière beaucoup plus élégante mais ces petites fonctions offrent l'avantage de leur remarquable robustesse.

# ========================================================================= #
# BLOO.R
# ========================================================================= #

# ------------------------------------------------------------------------- #
# Options & libraries
if(! "RDCOMClient" %in% .packages()) library("RDCOMClient")

# ------------------------------------------------------------------------- #
# Utilities

# Converts R Date objets into COMDate objets.
b.BloombergDate = function(x) {
      res <- as.numeric(as.Date(x)) + 25569
      class(res) <- "COMDate"
      return(res)
}

# Converts COMDate objets into R Date objets.
b.RDate = function(x) {
      res <- as.Date("1899-12-30") + as.numeric(x)
      return(res)
}

# Replaces #N/A by NA.
b.NA = function(x) {
      x[substr(x, 1, 4) == "#N/A"] <- NA
      return(x)
}

# Turns a vector x into a list of vectors of max length n.
b.Frag = function(x, n) {
      nx <- length(x)
      v <- 1 + c(0, n * (1:ceiling(nx/n)))
      res <- lapply(1:(length(v)-1),
            function(i, x, v, nx) { x[v[i]:min(c(v[i+1]-1), nx)] },
            x = x, v = v, nx = nx)
      return(res)
}

# Error manager
is.error = function(x) class(x) == "try-error"

# ------------------------------------------------------------------------- #
# b.History
# Retrieves times series and forces them into a matrix.

# Args:
# tk         a vector of Bloomberg tickers
# fld        1 Bloomberg field, e.g. *LAST_PRICE* or *VOLUME* (etc...)
# start      start date (ISO 8601 format)
# end        end date (ISO 8601 format), defaults to Sys.Date()
# suffix     1 suffix (*Equity*, *Index* etc...)

# Output:
# A matrix with dates as row names and tk (without suffix) as colnames.

b.History = function(tk, fld, start, end = Sys.Date(), suffix = "") {
      if(length(fld) != 1) stop("'fld' must be of length 1")
      
      v <- seq.Date(as.Date(start), as.Date(end), by = 1)
      res <- matrix(NA, length(v), length(tk),, list(as.character(v), tk))
      
      b <- try(
            COMCreate("Bloomberg.Data.1"),
            silent = TRUE)
      
      if(! is.error(b)) {
            
            b[["Timeout"]] <- 12000
            b[["DisplayNonTradingDays"]] <- 64
            b[["NonTradingDayValue"]] <- 256
            b[["Periodicity"]] <- 1
            class(b) <- "COMIDispatch"
            
            d0 <- b.BloombergDate(start)
            d1 <- b.BloombergDate(end)
            
            U <- b.Frag(1:length(tk), 10)
            
            for(i in 1:length(U)) {
                  
                  tki <- paste(tk[U[[i]]], suffix)
                  
                  dta <- try(
                        b$BLPGetHistoricalData(
                              Security = tki,
                              Fields = fld,
                              StartDate = d0,
                              EndDate = d1),
                        silent = TRUE)
                  
                  if(! is.error(dta)) {
                        
                        d <- try(
                              lapply(dta[[1]],
                                    function(x) b.RDate(b.NA(unlist(x)))),
                              silent = TRUE)
                        r <- try(
                              lapply(dta[[2]],
                                    function(x) as.numeric(b.NA(unlist(x)))),
                              silent = TRUE)
                                          
                        if(! is.error(d) & ! is.error(r)) {
                              
                              tmp <- try(
                                    all(d[[1]] == do.call(cbind, d)),
                                    silent = TRUE)
                              chk <- if(! is.error(tmp)) tmp else FALSE
                              
                              if(chk) {
                                    ir <- as.character(d[[1]])
                                    ic <- tk[U[[i]]]
                                    res[ir, ic] <- do.call(cbind, r)
                              } else {
                                    for(j in 1:length(d)) {
                                          ir <- as.character(d[[j]])
                                          ic <- tk[U[[i]]][j]
                                          res[ir, ic] <- r[[j]]
                                    }
                              }
                        }
                  }
            }
      }
            
      rm(b)
      gc(verbose = FALSE)
      
      ix <- ! weekdays(v) %in% weekdays(as.Date("2000-01-01") + 0:1)
      res <- res[ix, ]
      return(res)
}

# ------------------------------------------------------------------------- #
# b.Point
# Retrieves one data for as many tickers you want.

# Args:
# tk         a vector of Bloomberg tickers
# f          1 Bloomberg field, e.g. *NAME* or *ID_ISIN* (etc...)
# string     logical: should output be coerced as string?

# Output:
# A vector of length(tk).

b.Point = function(tk, f, string = TRUE) {
      
      res <- rep(NA, length(tk))
      res <- if(string) as.character(res) else as.numeric(res)
      
      b <- try(
            COMCreate("Bloomberg.Data.1"),
            silent = TRUE)
      
      if(! is.error(b)) {
            
            b[["Timeout"]] <- 12000
            b[["DisplayNonTradingDays"]] <- 64
            b[["NonTradingDayValue"]] <- 256
            b[["Periodicity"]] <- 1
            class(b) <- "COMIDispatch"
            
            U <- b.Frag(1:length(tk), 300)
            
            for(i in 1:length(U)) {
                  
                  tki <- paste(tk[U[[i]]], "Equity")
                  
                  dta <- try(
                        b$BlpSubscribe(tki, f),
                        silent = TRUE)
                  
                  if(! is.error(dta)) {
                        tmp <- b.NA(unlist(dta))
                        if(string) {
                              res[U[[i]]] <- as.character(tmp)
                        } else {
                              res[U[[i]]] <- as.numeric(tmp)
                        }
                  }
            }
      }
      
      rm(b)
      gc(verbose = FALSE)
      
      return(res)
}

# ------------------------------------------------------------------------- #
# b.List
# Equivalent of b.Point but designed to retrieve index members. 

# Args:
# tk         1 Bloomberg tickers
# fld        1 Bloomberg field, defaults to *INDX_MEMBERS*
# suffix     1 suffix, defaults to *Index*

# Output:
# A vector.

b.List = function(tk, f = "INDX_MEMBERS", suffix = "Index") {
      
      res <- NULL
      
      b <- try(COMCreate("Bloomberg.Data.1"), silent = TRUE)
      
      if(! is.error(b)) {
            b[["Timeout"]] <- 12000
            b[["DisplayNonTradingDays"]] <- 64
            b[["NonTradingDayValue"]] <- 256
            b[["Periodicity"]] <- 1
            
            dta <- try(
                  b$BlpSubscribe(
                        Security = paste(tk, suffix),
                        Fields = f),
                  silent = TRUE)
            
            if(! is.error(dta)) {
                  res <- as.character(unlist(dta))
            } 
      }
      
      rm(b)
      gc(verbose = FALSE)
      
      return(res)
}
# -------------------------------- The End -------------------------------- #

Par exemple, pour récupérer la liste des composants du S&P 500 :

tk <- b.List("SPX")

Pour récupérer les noms :

b.Point(tk, "NAME", string = TRUE)

Pour les cours de clôture :

b.History(tk, "LAST_PRICE", from, to, suffix = "Index")

NB : il n'est pas impossible que j'ai laissé trainer quelques fonctions personnelles là-dedans (j'ai failli oublier de vous donner is.error). Vos retours d’expérience sont les bienvenus !

Aucun commentaire:

Enregistrer un commentaire