Skip to content

[ANN] Rblpapi: Connecting R to Bloomberg

3 messages · Aaron Goldenberg, Dirk Eddelbuettel, Carlos Ungil

#
This is incredibly helpful! Thank you! Are there plans to include portfolio
calls in future releases? Is this something you would like help
implementing?
#
On 17 August 2015 at 17:49, Aaron Goldenberg wrote:
| This is incredibly helpful! Thank you! Are there plans to include portfolio
| calls in future releases? Is this something you would like help
| implementing?

The documentation at 

   http://www.bloomberglabs.com/api/documentation/

is pretty good about what the API supports.

If there is something you would like to add, you could file an issue ticket
at our Github issue tracker

   https://github.com/Rblp/Rblpapi/issues

to start a discussion.  I don;t think we'll say No to useful additions.

Dirk
#
Hi Aaron,

You might find the files below useful as a starting point if you want to add this functionality (you?ll also have to add beqs and bport to NAMESPACE). This unfinished implementation can retrieve data from Bloomberg, but it still has to be converted properly to R data frames (or whatever structure makes sense depending on the type of response).

Best regards,

Carlos
PortfolioDataResponse = {
    securityData[] = {
        securityData = {
            security = "U1234567-1 Client"
            eidData[] = {
            }
            fieldExceptions[] = {
            }
            sequenceNumber = 0
            fieldData = {
                PORTFOLIO_MEMBERS[] = {
                    PORTFOLIO_MEMBERS = {
                        Security = "..... Equity"
                    }
 ...... ...... ...... ...... ...... ...... ......

Error: Unsupported datatype: BLPAPI_DATATYPE_SEQUENCE.
BeqsResponse = {
    data = {
        fieldDisplayUnits = {
            Ticker = ""
            Short Name = ""
            Market Cap = ""
            GICS Sector = ""
            Cntry = ""
        }
        securityData[] = {
            securityData = {
                security = "AAPL US"
                fieldExceptions[] = {
                }
                fieldData = {
                    Ticker = "AAPL US"
                    Short Name = "APPLE INC"
                    Market Cap = 667446607872.000000
                    GICS Sector = "Information Technology"
                    Cntry = "United States"
                }
            }
 ...... ...... ...... ...... ...... ...... ......

[1] Cntry       GICS Sector Market Cap  Short Name  Ticker     
<0 rows> (or 0-length row.names)


========
R/bport.R
========

bport <- function(portid, fields="MEMBERS", date=NULL, identity=NULL, con=.pkgenv$con) {
    if (!(fields %in% c("MEMBERS","MPOSITION","MWEIGHT","DATA"))) stop("Fields should be one of MEMBERS, MPOSITION, MWEIGHT, DATA.", call.=FALSE)
    bport_Impl(con, portid, paste("PORTFOLIO_",fields,sep=""), date, identity)
}

========
R/beqs.R
========

beqs <- function(name, type="PRIVATE", group=NULL, languageId=NULL, identity=NULL, con=.pkgenv$con) {
    if (!(type %in% c("PRIVATE","GLOBAL"))) stop("Type should be PRIVATE or GLOBAL.", call.=FALSE)
    beqs_Impl(con, name, type, group, languageId, identity)
}

========
src/bport.cpp
========

#include <iostream>
#include <vector>
#include <string>
#include <blpapi_session.h>
#include <blpapi_service.h>
#include <blpapi_request.h>
#include <blpapi_event.h>
#include <blpapi_message.h>
#include <blpapi_element.h>
#include <Rcpp.h>
#include <blpapi_utils.h>

using BloombergLP::blpapi::Session;
using BloombergLP::blpapi::Service;
using BloombergLP::blpapi::Request;
using BloombergLP::blpapi::Event;
using BloombergLP::blpapi::Element;
using BloombergLP::blpapi::Message;
using BloombergLP::blpapi::MessageIterator;

void getPortfolioDataResult(Event& event, LazyFrameT& lazy_frame) {
  Rcpp::List ans;
    MessageIterator msgIter(event);
    if (!msgIter.next()) {
        throw std::logic_error("Not a valid MessageIterator.");
    }
    Message msg = msgIter.message();
    msg.print(Rcpp::Rcerr);
    Element response = msg.asElement();
    if (std::strcmp(response.name().string(),"PortfolioDataResponse")) {
        throw std::logic_error("Not a valid PortfolioDataResponse.");
    }
    Element securityData = response.getElement("securityData");
    for (size_t i = 0; i < securityData.numValues(); ++i) {
        Element this_security = securityData.getValueAsElement(i);
        Element fieldData = this_security.getElement("fieldData");
        for(size_t j = 0; j < fieldData.numElements(); ++j) {
            Element e = fieldData.getElement(j);
            LazyFrameIteratorT iter = assertColumnDefined(lazy_frame,e,securityData.numValues());
            populateDfRow(iter->second,i,e);
        }
    }
}

// Simpler interface with std::vector<std::string> thanks to Rcpp::Attributes
//
// [[Rcpp::export]]
SEXP bport_Impl(SEXP con_, std::vector<std::string> securities, std::vector<std::string> fields, 
              SEXP date_, SEXP identity_) {

    // via Rcpp Attributes we get a try/catch block with error propagation to R "for free"
    Session* session = 
        reinterpret_cast<Session*>(checkExternalPointer(con_, "blpapi::Session*"));

    const std::string rdsrv = "//blp/refdata";
    if (!session->openService(rdsrv.c_str())) {
        Rcpp::stop("Failed to open " + rdsrv);
    }
    
    Service refDataService = session->getService(rdsrv.c_str());
    Request request = refDataService.createRequest("PortfolioDataRequest");
    request.getElement("securities").appendValue(securities[0].c_str());
    request.getElement("fields").appendValue(fields[0].c_str());
    if (date_ != R_NilValue) {
        Element overrides = request.getElement("overrides");
        Element override = overrides.appendElement();
        override.setElement("fieldId","REFERENCE_DATE");
        override.setElement("value", Rcpp::as<std::string>(date_).c_str());
    }
    sendRequestWithIdentity(session, request, identity_);

    LazyFrameT lazy_frame;

    while (true) {
        Event event = session->nextEvent();
        //REprintf("%d\n",event.eventType());
        switch (event.eventType()) {
        case Event::RESPONSE:
        case Event::PARTIAL_RESPONSE:
  	    getPortfolioDataResult(event, lazy_frame);
            break;
        default:
            MessageIterator msgIter(event);
            while (msgIter.next()) {
                Message msg = msgIter.message();
                //FIXME:: capture messages here for debugging
            }
        }
        if (event.eventType() == Event::RESPONSE) { break; }
    }
    return buildDataFrame(lazy_frame, false, false);
}

========
src/beqs.cpp
========

#include <iostream>
#include <vector>
#include <string>
#include <blpapi_session.h>
#include <blpapi_service.h>
#include <blpapi_request.h>
#include <blpapi_event.h>
#include <blpapi_message.h>
#include <blpapi_element.h>
#include <Rcpp.h>
#include <blpapi_utils.h>

using BloombergLP::blpapi::Session;
using BloombergLP::blpapi::Service;
using BloombergLP::blpapi::Request;
using BloombergLP::blpapi::Event;
using BloombergLP::blpapi::Element;
using BloombergLP::blpapi::Message;
using BloombergLP::blpapi::MessageIterator;

void getBeqsResult(Event& event, LazyFrameT& lazy_frame) {
    MessageIterator msgIter(event);
    if (!msgIter.next()) {
        throw std::logic_error("Not a valid MessageIterator.");
    }
    Message msg = msgIter.message();
    msg.print(Rcpp::Rcerr);
    Element response = msg.asElement();
    if (std::strcmp(response.name().string(),"BeqsResponse")) {
        throw std::logic_error("Not a valid BeqsResponse.");
    }
    if (msg.hasElement("responseError")){
      msg.print(Rcpp::Rcerr);
    }
    Element securityData = response.getElement("data").getElement("securityData");
    for (size_t i = 0; i < securityData.numValues(); ++i) {
        Element this_security = securityData.getValueAsElement(i);
        Element fieldData = this_security.getElement("fieldData");
        for(size_t j = 0; j < fieldData.numElements(); ++j) {
            Element e = fieldData.getElement(j);
            LazyFrameIteratorT iter = assertColumnDefined(lazy_frame,e,securityData.numValues());
            populateDfRow(iter->second,i,e);
        }
    }
}

// Simpler interface with std::vector<std::string> thanks to Rcpp::Attributes
//
// [[Rcpp::export]]
SEXP beqs_Impl(SEXP con_, std::string name, std::string type, 
              SEXP group_, SEXP languageId_, SEXP identity_) {

    // via Rcpp Attributes we get a try/catch block with error propagation to R "for free"
    Session* session = 
        reinterpret_cast<Session*>(checkExternalPointer(con_, "blpapi::Session*"));

    const std::string rdsrv = "//blp/refdata";
    if (!session->openService(rdsrv.c_str())) {
        Rcpp::stop("Failed to open " + rdsrv);
    }
    
    Service refDataService = session->getService(rdsrv.c_str());
    Request request = refDataService.createRequest("BeqsRequest");
    request.set ("screenName", name.c_str());
    request.set ("screenType", type.c_str());
    if (group_ != R_NilValue) {
        request.set ("Group", Rcpp::as<std::string>(group_).c_str());
    }
    if (languageId_ != R_NilValue) {
        request.set ("languageId", Rcpp::as<std::string>(languageId_).c_str());
    }
    sendRequestWithIdentity(session, request, identity_);

    LazyFrameT lazy_frame;

    while (true) {
        Event event = session->nextEvent();
        //REprintf("%d\n",event.eventType());
        switch (event.eventType()) {
        case Event::RESPONSE:
        case Event::PARTIAL_RESPONSE:
	    getBeqsResult(event, lazy_frame);
            break;
        default:
            MessageIterator msgIter(event);
            while (msgIter.next()) {
                Message msg = msgIter.message();
                //FIXME:: capture messages here for debugging
            }
        }
        if (event.eventType() == Event::RESPONSE) { break; }
    }
    return buildDataFrame(lazy_frame, false, false);
}