[R-SIG-Finance] [ANN] Rblpapi: Connecting R to Bloomberg

Carlos Ungil carlos.ungil at gmail.com
Tue Aug 18 23:15:26 CEST 2015


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

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

Error: Unsupported datatype: BLPAPI_DATATYPE_SEQUENCE.

> beqs("Insider Buyers","GLOBAL","Popular")
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);
}


> On 17 Aug 2015, at 23:49, Aaron Goldenberg <aaron at quantrisktrading.com> 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?
> 
> 	[[alternative HTML version deleted]]
> 
> _______________________________________________
> R-SIG-Finance at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-sig-finance
> -- Subscriber-posting only. If you want to post, subscribe first.
> -- Also note that this is not the r-help list where general R questions should go.



More information about the R-SIG-Finance mailing list