Search code examples
c++bloomberg

Bloomberg Equity Option Chain through API


I am currently working on a project that should help me create an implied volatility surface for a given stock. For this purpose, I am writing a script that will download all the available options for this specific stock - from what I've gathered, this is possible by sending a request through the Bloomberg API using bulks fields/overrides. Here is my current code:

d_host = "localhost";
d_port = 8194;
SessionOptions sessionOptions;
sessionOptions.setServerHost(d_host.c_str());
sessionOptions.setServerPort(d_port);
Session session(sessionOptions);
Service refDataService = session.getService("//blp/refdata");
Request request = refDataService.createRequest("ReferenceDataRequest");

request.append("securities", "MSFT US EQUITY");
request.append("fields", "CHAIN_TICKERS");

// add overrides
Element overrides = request.getElement("overrides");
Element override1 = overrides.appendElement();
override1.setElement("fieldId", "CHAIN_PUT_CALL_TYPE_OVRD");
override1.setElement("value", "C");

Element override2 = overrides.appendElement();
override2.setElement("fieldId", "CHAIN_POINTS_OVRD");
override2.setElement("value", 100);

Element override3 = overrides.appendElement();
override3.setElement("fieldId", "CHAIN_EXP_DT_OVRD");
override3.setElement("value", "20250203");

std::cout << "Sending Request: " << request << std::endl;
CorrelationId cid(this);
session.sendRequest(request, cid);

(followed by event handling)

Now I have several issues/questions:

  1. The code compiles without problems, but when running it on the Bloomberg terminal,the following error is printed: bloomberg error How would I go about fixing this problem? I assume I made a mistake somewhere in the override fields..

  2. How would I need to adjust my code to download all options available given a specific maturity, i.e. I want to get a list of all the options until today + 15 years.

  3. How would I then download the implied volatility for each option? Would I need to store the tickers in an array and then send a request for the field "IVOL_MID" for each option or is there some kind of way to obtain all the volatilities at once?

Edit: Here is the code of my event handler, since that seems to be the problem.

    session.sendRequest(request, cid);

    while (true)
    {
        Event event = session.nextEvent();
        MessageIterator msgIter(event);
        while (msgIter.next()) {
            Message msg = msgIter.message();
            if (msg.correlationId() == cid) {
                processMessage(msg);
            }
        }
        if (event.eventType() == Event::RESPONSE) {
            break;
        }
    }




 void processMessage(Message &msg)
{
    Element securityDataArray = msg.getElement(SECURITY_DATA);
    int numSecurities = securityDataArray.numValues();
    for (int i = 0; i < numSecurities; ++i) {
        Element securityData = securityDataArray.getValueAsElement(i);
        std::cout << securityData.getElementAsString(SECURITY)
            << std::endl;
        const Element fieldData = securityData.getElement(FIELD_DATA);
        for (size_t j = 0; j < fieldData.numElements(); ++j) {
            Element field = fieldData.getElement(j);
            if (!field.isValid()) {
                std::cout << field.name() << " is NULL." << std::endl;
            }
            else {
                std::cout << field.name() << " = "
                    << field.getValueAsString() << std::endl;
            }
        }

        Element fieldExceptionArray =
            securityData.getElement(FIELD_EXCEPTIONS);
        for (size_t k = 0; k < fieldExceptionArray.numValues(); ++k) {
            Element fieldException =
                fieldExceptionArray.getValueAsElement(k);
            std::cout <<
                fieldException.getElement(ERROR_INFO).getElementAsString(
                "category")
                << ": " << fieldException.getElementAsString(FIELD_ID);
        }
        std::cout << std::endl;
    }

Solution

  • As seen in the other answer, the problem lies in the event handling so I've rewritten that part using some examples from the Bloomberg API emulator.

    session.sendRequest(request, cid);
    bool continueToLoop = true;
    while (continueToLoop)
    {
        Event evt = session.nextEvent();
        switch (evt.eventType())
        {
            case Event::RESPONSE:
                continueToLoop = false; //fall through
            case Event::PARTIAL_RESPONSE:
                ProcessReferenceDataEvent(evt);
            break;
         }
    }
    
    void ProcessReferenceDataEvent(Event evt)
    {
        const string level1 = "";
        const string level2 = "\t";
        const string level3 = "\t\t";
        const string level4 = "\t\t\t";
    
        std::cout << endl << endl;
        std::cout << level1 << "EventType = " << evt.eventType();
    
        MessageIterator iter(evt);
        while (iter.next())
        {
            Message msg = iter.message();
    
            std::cout << endl << endl;
            std::cout << level1 << "correlationID = " << msg.correlationId().asInteger() << endl;
            std::cout << level1 << "messageType = " << msg.messageType().string() << endl;
            std::cout << endl << endl;
            Element SecurityDataArray = msg.getElement(SECURITY_DATA);
            int numSecurities = SecurityDataArray.numValues();
            for (int valueIndex = 0; valueIndex < numSecurities; valueIndex++)
            {
                Element SecurityData = SecurityDataArray.getValueAsElement(valueIndex);
    
                string Security = SecurityData.getElementAsString(SECURITY);
                std::cout << level2 << Security << endl;
    
                bool hasFieldErrors = SecurityData.hasElement("fieldExceptions", true);
                if (hasFieldErrors)
                {
                    Element FieldErrors = SecurityData.getElement(FIELD_EXCEPTIONS);
                    for (size_t errorIndex = 0; errorIndex < FieldErrors.numValues(); errorIndex++)
                    {
                        Element fieldError = FieldErrors.getValueAsElement(errorIndex);
                        string fieldId = fieldError.getElementAsString(FIELD_ID);
    
                        Element errorInfo = fieldError.getElement(ERROR_INFO);
                        string source = errorInfo.getElementAsString("source");
                        int code = errorInfo.getElementAsInt32("code");
                        string category = errorInfo.getElementAsString("category");
                        string strMessage = errorInfo.getElementAsString("message");
                        string subCategory = errorInfo.getElementAsString("subcategory");
    
                        cerr << level3 << "field error:" << endl;
                        cerr << level4 << "fieldId = " << fieldId << endl;
                        cerr << level4 << "source = " << source << endl;
                        cerr << level4 << "code = " << code << endl;
                        cerr << level4 << "category = " << category << endl;
                        cerr << level4 << "errorMessage = " << strMessage << endl;
                        cerr << level4 << "subCategory = " << subCategory << endl;
                    }
                }
    
                bool isSecurityError = SecurityData.hasElement("securityError", true);
                if (isSecurityError)
                {
                    Element secError = SecurityData.getElement("securityError");
                    string source = secError.getElementAsString("source");
                    int code = secError.getElementAsInt32("code");
                    string category = secError.getElementAsString("category");
                    string errorMessage = secError.getElementAsString("message");
                    string subCategory = secError.getElementAsString("subcategory");
    
                    cerr << level3 << "security error:" << endl;
                    cerr << level4 << "source = " << source << endl;
                    cerr << level4 << "code = " << code << endl;
                    cerr << level4 << "category = " << category << endl;
                    cerr << level4 << "errorMessage = " << errorMessage << endl;
                    cerr << level4 << "subCategory = " << subCategory << endl;
                }
                else
                {
                    Element FieldData = SecurityData.getElement(FIELD_DATA);
    
    
                    double pxLast = FieldData.getElementAsFloat64("PX_LAST");
                    double bid = FieldData.getElementAsFloat64("BID");
                    double ask = FieldData.getElementAsFloat64("ASK");
                    string ticker = FieldData.getElementAsString("TICKER");
    
                    std::cout << level3 << "fields: " << endl;
                    std::cout << level4 << "PX_LAST = " << pxLast << endl;
                    std::cout << level4 << "BID = " << bid << endl;
                    std::cout << level4 << "ASK = " << ask << endl;
                    std::cout << level4 << "TICKER = " << ticker << endl;
    
                    bool excludeNullElements = true;
                    if (FieldData.hasElement("CHAIN_TICKERS", excludeNullElements))
                    {
                        Element chainTickers = FieldData.getElement("CHAIN_TICKERS");
                        for (size_t chainTickerValueIndex = 0; chainTickerValueIndex < chainTickers.numValues(); chainTickerValueIndex++)
                        {
                            Element chainTicker = chainTickers.getValueAsElement(chainTickerValueIndex);
                            string strChainTicker = chainTicker.getElementAsString("Ticker");
    
                            std::cout << level4 << "CHAIN_TICKER = " << strChainTicker << endl;
                        }
                    }
                    else
                    {
                        std::cout << level4 << "NO CHAIN_TICKER information" << endl;
                    }
                }
            }
        }
    }
    

    Regarding the second question, the Bloomberg support staff recommended me to just pick an arbitarily high number so that all options would be downloaded, i.e.

    override2.setElement("fieldId", "CHAIN_POINTS_OVRD");
    override2.setElement("value", 50000);
    

    For the third question, it is possible to download the chain tickers for all maturities by setting the "CHAIN_EXP_DT_OVRD" override to 'ALL' (this part is currently untested):

        Element override3 = overrides.appendElement();
        override3.setElement("fieldId", "CHAIN_EXP_DT_OVRD");
        override3.setElement("value", 'ALL');