matthewgilbert / pdblp

pandas wrapper for Bloomberg Open API
MIT License
241 stars 68 forks source link

Another BDH Override Returning Error #29

Closed nellyt00 closed 6 years ago

nellyt00 commented 6 years ago

Hi Matthew,

First of all, thank you for developing this package - I find it very useful. I am trying to override the standard bdh formula to return all working days (or all calendar days) by using the fields from the Bloomberg Open API - Core Developer Guide on page 93:

df = con.bdh("IBM US Equity", "PX_LAST", "20150101", "20150630", ovrds=[("nonTradingDayFillOption", "ALL_CALENDAR_DAYS"), ("nonTradingDayFillMethod", "NIL_VALUE")])

Unfortunately this override is returning an error message:

DEBUG:root:Sending Request:
 HistoricalDataRequest = {
    securities[] = {
        "IBM US Equity"
    }
    fields[] = {
        "PX_LAST"
    }
    startDate = "20150101"
    endDate = "20150630"
    overrides[] = {
        overrides = {
            fieldId = "nonTradingDayFillOption"
            value = "ALL_CALENDAR_DAYS"
        }
        overrides = {
            fieldId = "nonTradingDayFillMethod"
            value = "NIL_VALUE"
        }
    }
}
DEBUG:root:Message Received:
 HistoricalDataResponse = {
    responseError = {
        source = "bbdbh7"
        code = 27
        category = "BAD_ARGS"
        message = "Invalid override field id specified [nid:3626] "
        subcategory = "INVALID_OVERRIDE_FIELD"
    }
}
Traceback (most recent call last):
  File "<input>", line 2, in <module>
  File "C:\Users\nelly\Anaconda3\Lib\site-packages\pdblp\pdblp.py", line 165, in bdh
    elms, ovrds)
  File "C:\Users\nelly\Anaconda3\Lib\site-packages\pdblp\pdblp.py", line 202, in _bdh_list
    if msg.getElement('securityData').hasElement('securityError') or (msg.getElement('securityData').getElement("fieldExceptions").numValues() > 0):  # NOQA
  File "C:\Users\nelly\Anaconda3\Lib\site-packages\blpapi\message.py", line 135, in getElement
    return self.asElement().getElement(name)
  File "C:\Users\nelly\Anaconda3\Lib\site-packages\blpapi\element.py", line 347, in getElement
    _ExceptionUtil.raiseOnError(res[0])
  File "C:\Users\nelly\Anaconda3\Lib\site-packages\blpapi\exception.py", line 145, in raiseOnError
    _ExceptionUtil.raiseException(errorCode, description)
  File "C:\Users\nelly\Anaconda3\Lib\site-packages\blpapi\exception.py", line 137, in raiseException
    raise errorClass(description, errorCode)
blpapi.exception.InvalidArgumentException: Choice sub-element not found for name 'securityData'. (0x00020002)

Any idea how to make it work?

matthewgilbert commented 6 years ago

The error message

 HistoricalDataResponse = {
    responseError = {
        source = "bbdbh7"
        code = 27
        category = "BAD_ARGS"
        message = "Invalid override field id specified [nid:3626] "
        subcategory = "INVALID_OVERRIDE_FIELD"
    }
}

would suggest that either nonTradingDayFillOption or nonTradingDayFillMethod is invalid. This is an error generated upstream by the blpapi library. I am not familiar with these overrides, I would check with Bloomberg Help or double check that these fields are in fact valid by looking in the terminal.

matthewgilbert commented 6 years ago

These are not overrides, they are elements associated with the query to set. Something like this seems to work

df = con.bdh("IBM US Equity", "PX_LAST", "20150101", "20150630",
             elms=[("nonTradingDayFillOption", "ALL_CALENDAR_DAYS"),
                   ("nonTradingDayFillMethod", "NIL_VALUE")])

You can see a description of these in the users guide in a terminal by using WAPI -> API Developer's Guide -> Reference Guide: Services and Schemas

A less up to date version of the User's Guide which also has schemas is available on the internet here, refer to page 166.

nellyt00 commented 6 years ago

Hi Matthew, Thanks a lot for your prompt reply! The blpapi equivalent works for me:

# SimpleHistoryExample.py

import blpapi
from optparse import OptionParser

def parseCmdLine():
    parser = OptionParser(description="Retrieve reference data.")
    parser.add_option("-a",
                      "--ip",
                      dest="host",
                      help="server name or IP (default: %default)",
                      metavar="ipAddress",
                      default="localhost")
    parser.add_option("-p",
                      dest="port",
                      type="int",
                      help="server port (default: %default)",
                      metavar="tcpPort",
                      default=8194)

    (options, args) = parser.parse_args()

    return options

def main():
    options = parseCmdLine()

    # Fill SessionOptions
    sessionOptions = blpapi.SessionOptions()
    sessionOptions.setServerHost(options.host)
    sessionOptions.setServerPort(options.port)

    print("Connecting to %s:%s" % (options.host, options.port))
    # Create a Session
    session = blpapi.Session(sessionOptions)

    # Start a Session
    if not session.start():
        print("Failed to start session.")
        return

    try:
        # Open service to get historical data from
        if not session.openService("//blp/refdata"):
            print("Failed to open //blp/refdata")
            return

        # Obtain previously opened service
        refDataService = session.getService("//blp/refdata")

        # Create and fill the request for the historical data
        request = refDataService.createRequest("HistoricalDataRequest")
        request.getElement("securities").appendValue("IBM US Equity")
        request.getElement("fields").appendValue("PX_LAST")
        request.set("startDate", "20060701")
        request.set("endDate", "20060710")
        request.set("nonTradingDayFillMethod", "NIL_VALUE")
        request.set("nonTradingDayFillOption", "ALL_CALENDAR_DAYS")

        print("Sending Request:", request)
        # Send the request
        session.sendRequest(request)

        # Process received events
        while(True):
            # We provide timeout to give the chance for Ctrl+C handling:
            ev = session.nextEvent(500)
            for msg in ev:
                print(msg)

            if ev.eventType() == blpapi.Event.RESPONSE:
                # Response completly received, so we could exit
                break
    finally:
        # Stop the session
        session.stop()

if __name__ == "__main__":
    print("SimpleHistoryExample")
    try:
        main()
    except KeyboardInterrupt:
        print("Ctrl+C pressed. Stopping...")
matthewgilbert commented 6 years ago

Did you take a look at the second response I posted? This was working for me so give it a try.

With regards to my previous response, the rational for why using ovrds does not work is because this amounts to the following in the code in pdblp

overrides = request.getElement("overrides")
for ovrd_fld, ovrd_val in ovrds:
       ovrd = overrides.appendElement()
       ovrd.setElement("fieldId", ovrd_fld)
       ovrd.setElement("value", ovrd_val)

whereas, as you show above, you want to set an element such as

request.set("nonTradingDayFillMethod", "NIL_VALUE")

which in pdblp is done using the elms keyword in bdh().

nellyt00 commented 6 years ago

Hi Matthew, I've tested your solution on my side and it works fine. Thanks a lot for your kind help and prompt replies!