Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bdh request does not return data frame because of a single bad date in Bloomberg data #282

Open
philaris opened this issue Dec 7, 2018 · 0 comments

Comments

@philaris
Copy link

philaris commented Dec 7, 2018

Hi all, and thank you for this nice API.

There is an issue with the following historical request for ticker 'RBS LN Equity' and field LATEST_ANNOUNCEMENT_DATE:

Rblpapi::blpConnect()
result <- Rblpapi::bdh(
  securities = c('RBS LN Equity'),
  fields = c('LATEST_ANNOUNCEMENT_DT'),
  start.date = as.Date('2003-12-01'),
  end.date = as.Date('2018-11-30'),
  options = NULL,
  overrides = c('FUND_PER' = 'Q'),
  verbose = TRUE
)

I get the following error:

Day of month value is out of range 1..31
<boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::gregorian::bad_day_of_month> > in bdh_Impl(con, securities, fields, start.date, end.date, options, overrides, verbose, identity, int.as.double): Day of month value is out of range 1..31>

Data in the LATEST_ANNOUNCEMENT_DT field is received as a real number, where for example 2018-10-26 is represented by the real number 20181026.000000.

The reason for the error is the following entry in the data from Bloomberg as seen from the verbose output of the above request:

fieldData = {
  date = 2015-12-31
  LATEST_ANNOUNCEMENT_DT = 0.000000
}

All other entries for LATEST_ANNOUNCEMENT_DT in the timeseries are fine (stored as real number values), e.g.:

fieldData = {
  date = 2018-09-30
  LATEST_ANNOUNCEMENT_DT = 20181026.000000
}

I traced the exception through HistoricalDataResponseToDF in src/bdh.cpp:

            populateDfRow(res[colindex], i, e, rtypes[colindex]);

and then populateDfRow in src/blpapi_utils.cpp:

  case RblpapiT::Date:
    // handle the case of BBG passing down dates as double in YYYYMMDD format
    REAL(ans)[row_index] = e.datatype()==BLPAPI_DATATYPE_FLOAT32 || e.datatype()==BLPAPI_DATATYPE_FLOAT64 ?
      bbgDateToRDate(e.getValueAsFloat64()) :
      bbgDateToRDate(e.getValueAsDatetime());
    break;

and bbgDateToRDate in src/blpapi_utils.cpp:

const int bbgDateToRDate(const Datetime& bbg_date) {
  if(bbg_date.hasParts(DatetimeParts::TIME)) {
    throw std::logic_error("Attempt to convert a Datetime with time parts set to an R Date.");
  }
  const boost::gregorian::date r_epoch(1970,1,1);
  boost::gregorian::date bbg_boost_date(bbg_date.year(),bbg_date.month(),bbg_date.day());
  boost::gregorian::date_period dp(r_epoch,bbg_boost_date);
  return static_cast<int>(dp.length().days());
}

const int bbgDateToRDate(const double yyyymmdd_date) {
  if(yyyymmdd_date < 0) {
    throw std::logic_error("Attempt to convert a negative double value to an R Date.");
  }
  if(trunc(yyyymmdd_date)!=yyyymmdd_date) {
    throw std::logic_error("Attempt to convert a double value with time parts set to an R Date.");
  }

  const boost::gregorian::date r_epoch(1970,1,1);
  const int year = static_cast<int>(yyyymmdd_date/1.0e4);
  const int month = static_cast<int>(yyyymmdd_date/1.0e2) % 100;
  const int day = static_cast<int>(yyyymmdd_date) % 100;
  boost::gregorian::date bbg_boost_date(year,month,day);
  boost::gregorian::date_period dp(r_epoch,bbg_boost_date);
  return static_cast<int>(dp.length().days());
}

The exception is thrown in the constructor call for variable bbg_boost_date in the above code. With a single problematic value as above, the Rblpapi::bdh call returns no R data frame. My question is whether this behavior is too strict.

I am wondering if a better behavior would be to ignore the exceptions that are propagated through populateDfRow and have an NA value in the resulting R data frame.

A simple (but drastic) solution that implements this last behavior and does not change the existing code too much could be to create a version of populateDfRow (e.g., called populateDfRowNoExcept) that catches all exceptions and use that in HistoricalDataResponseToDF of src/bdh.cpp.

What do you think?

Best regards,
Panagiotis CHEILARIS

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant