691175002 / BLPInterface

Python Bloomberg API and Pandas Wrapper
49 stars 28 forks source link

How Use BDP/referenceRequest with Override #3

Open fcarpentey75012 opened 4 years ago

fcarpentey75012 commented 4 years ago

Hello,

Thanks you for you code, but i would like to use referenceRequest with Override, i try many solution but i don't find the solution. Do you have idea for to resolve the problem ?

Thanks you for your time !

691175002 commented 4 years ago

Here is a more complete version of the code, it might work in its entirety but you could also pull the improvements you need.

# -*- coding: utf-8 -*-
""" A wrapper for the Bloomberg API.

Designed to roughly emulate the Excel API.

All requests return well-formed Series or DataFrames where appropriate and can
handle any number of securities and fields within a single request.

Excel BDH: historicalRequest()
Excel BDP: referenceRequest()
Excel BDS: bulkRequest()

Note: Securities may be fetched by ticker, bbgid or cusip using the following
      formats: "BMO CN Equity", "BBG0000000000", or "/cusip/000000000"

Created July 2015 

@author: ryan
"""
import socket
import itertools
from datetime import datetime, date, time

import pandas as pd
import numpy as np
from pandas import Series
from pandas import DataFrame

# Default Connections
BLP_HOST   = 'localhost'
BLP_PORT   = 8194
PROXY_HOST = ''
PROXY_PORT = 5001

class RequestError(Exception):
    """A RequestError is raised when there is a problem with a Bloomberg API response."""
    def __init__(self, description, value=None):
        self.value = value
        self.description = description

    def __str__(self):
        if self.value is not None:
            return self.description + '\n' + self.value
        return self.description

def _uwrap(s):
    """Helper function to convert a string or list into a list of unique entries."""
    s = [s] if isinstance(s, str) else s
    return list(set(s))

def _convertDate(d):
    """Helper function to convert dates and datetimes into blpapi strings."""
    if isinstance(d, np.datetime64):
        d = pd.Timestamp(d)
    elif isinstance(d, pd.Period):
        d = d.to_timestamp(freq='D')

    if isinstance(d, date):
        if isinstance(d, datetime) and (d.time() != time(0)):
            return d.strftime('%Y-%m-%dT%H:%M:%S')
        else:
            return d.strftime('%Y%m%d')
    return d

# Attempt to import the Bloomberg API.  Technically this is a bad idea as it
# can mask unrelated ImportErrors but whatever.
try:
    # noinspection PyUnresolvedReferences
    import blpapi

    # The Bloomberg API was successfully imported - Create the normal
    # BLPInterface class.

    DEFAULT_HOST = BLP_HOST
    DEFAULT_PORT = BLP_PORT

    class BLPInterface:
        """ A wrapper for the Bloomberg API that returns DataFrames.  This class
            manages a //BLP/refdata service and therefore does not handle event
            subscriptions.

            All calls are blocking and responses are parsed and returned as 
            DataFrames where appropriate. 

            A RequestError is raised when an invalid security is queried.  Invalid
            fields will fail silently and may result in an empty DataFrame.
        """
        # noinspection PyShadowingBuiltins
        def __init__(self, host=BLP_HOST, port=BLP_PORT, open=True):
            self.active = False
            self.host = host
            self.port = port
            self.session = None
            self.refDataService = None
            if open:
                self.open()

        def open(self):
            if not self.active:
                sessionOptions = blpapi.SessionOptions()
                sessionOptions.setServerHost(self.host)
                sessionOptions.setServerPort(self.port)
                sessionOptions.setAutoRestartOnDisconnection(True)

                self.session = blpapi.Session(sessionOptions)
                if (not self.session.start()) or (not self.session.openService("//blp/refdata")):
                    raise RequestError('Failed to start session')

                self.refDataService = self.session.getService('//BLP/refdata')
                self.active = True

        def close(self):
            if self.active:
                self.session.stop()
                self.active = False

        def historicalRequest(self, securities, fields, startDate, endDate='', overrides=None, **kwargs):
            """ Equivalent to the Excel BDH Function.

                If securities are provided as a list, the returned DataFrame will
                have a MultiIndex.

                StartDate and endDate should be a datetime.date or YYYYMMDD string.
                Datetimes or Timestamps with a non-zero time component will not be
                recognized correctly by the Bloomberg API.

                Useful kwargs are periodicitySelection, adjustmentNormal,
                adjustmentAbnormal, adjustmentSplit, and currency.
            """
            defaults = {'startDate'               : startDate.replace('-', '') if isinstance(startDate, str) else startDate,
                        'endDate'                 : endDate.replace('-', '') if isinstance(endDate, str) else endDate,
                        'periodicityAdjustment'   : 'CALENDAR',
                        'periodicitySelection'    : 'DAILY',
                        'nonTradingDayFillOption' : 'NON_TRADING_WEEKDAYS',
                        'adjustmentNormal'        : False,
                        'adjustmentAbnormal'      : False,
                        'adjustmentSplit'         : True,
                        'adjustmentFollowDPDF'    : False}
            defaults.update(kwargs)
            usecurities = _uwrap(securities)
            ufields = _uwrap(fields)
            response = self.sendRequest('HistoricalData', usecurities, ufields, overrides, defaults)

            data = []
            keys = []

            for msg in response:
                securityData = msg.getElement('securityData')
                fieldData = securityData.getElement('fieldData')
                fieldDataList = [fieldData.getValueAsElement(i) for i in range(fieldData.numValues())]

                df = DataFrame(columns=ufields)

                for fld in fieldDataList:
                    for v in [fld.getElement(i) for i in range(fld.numElements())
                              if fld.getElement(i).name() != 'date']:
                        df.ix[fld.getElementAsDatetime('date'), str(v.name())] = v.getValue()

                df.index = pd.to_datetime(df.index)
                df.replace('#N/A History', np.nan, inplace=True)

                keys.append(securityData.getElementAsString('security'))
                data.append(df)

            if len(data) == 0:
                return DataFrame()
            else:
                data = pd.concat(data, keys=keys, axis=1, names=['Security', 'Field']).sort_index()
                data.index.name = 'Date'

            if isinstance(securities, str) and isinstance(fields, str):
                data = data.iloc[:,0]
                data.name = fields
            elif isinstance(securities, str):
                data.columns = data.columns.droplevel('Security')
                data = data[fields]
            elif isinstance(fields, str):
                data.columns = data.columns.droplevel('Field')
                data = data[securities]
            else:
                data = data[list(itertools.product(securities, fields))]
            return data

        def referenceRequest(self, securities, fields, overrides=None, **kwargs):
            """ Equivalent to the Excel BDP Function.

                If either securities or fields are provided as lists, a DataFrame
                will be returned.
            """
            usecurities = _uwrap(securities)
            ufields = _uwrap(fields)
            response = self.sendRequest('ReferenceData', usecurities, ufields, overrides, kwargs)
            data = DataFrame(index=usecurities, columns=ufields)

            for msg in response:
                securityData = msg.getElement('securityData')
                securityDataList = [securityData.getValueAsElement(i) for i in range(securityData.numValues())]

                for sec in securityDataList:
                    fieldData = sec.getElement('fieldData')
                    fieldDataList = [fieldData.getElement(i) for i in range(fieldData.numElements())]

                    for fld in fieldDataList:
                        data.ix[sec.getElementAsString('security'), str(fld.name())] = fld.getValue()

            if data.empty:
                return DataFrame()
            else:
                data.index.name = 'Security'
                data.columns.name = 'Field'

            if isinstance(securities, str) and isinstance(fields, str):
                data = data.iloc[0, 0]
            elif isinstance(securities, str):
                data = data.iloc[0, :][fields]
            elif isinstance(fields, str):
                data = data.iloc[:, 0][securities]
            else:
                data = data.loc[securities, fields]
            return data

        def bulkRequest(self, securities, fields, overrides=None, **kwargs):
            """ Equivalent to the Excel BDS Function.

                If securities are provided as a list, the returned DataFrame will
                have a MultiIndex.

                You may also pass a list of fields to a bulkRequest.  An appropriate
                MultiIndex will be generated, however such a DataFrame is unlikely
                to be useful unless the bulk data fields contain overlapping columns.
            """
            response = self.sendRequest('ReferenceData', securities, fields, overrides, kwargs)

            data = []
            keys = []

            for msg in response:
                securityData = msg.getElement('securityData')
                securityDataList = [securityData.getValueAsElement(i) for i in range(securityData.numValues())]

                for sec in securityDataList:
                    fieldData = sec.getElement('fieldData')
                    fieldDataList = [fieldData.getElement(i) for i in range(fieldData.numElements())]

                    fldData = []
                    fldKeys = []

                    for fld in fieldDataList:
                        df = DataFrame()
                        for v in [fld.getValueAsElement(i) for i in range(fld.numValues())]:
                            s = Series()
                            for d in [v.getElement(i) for i in range(v.numElements())]:
                                try:
                                    s[str(d.name())] = d.getValue()
                                except:
                                    # There is seriously no end to the shit getValue() can raise.
                                    pass
                            # Bloomberg returns this magic number instead of NaN for certain bulk fields.
                            df = df.append(s.where(s != -2.4245362661989844e-14, np.nan), ignore_index=True)

                        try: 
                            df = df.set_index(df.columns[0])
                            if not df.empty:
                                fldKeys.append(str(fld.name()))
                                fldData.append(df)
                        except IndexError:
                            pass

                    if fldData:
                        keys.append(sec.getElementAsString('security'))
                        data.append(pd.concat(fldData, keys=fldKeys, names=['Field']))

            if data:
                data = pd.concat(data, keys=keys, names=['Security'])
                data.columns.name = 'Element'
            else:
                return DataFrame()

            if isinstance(securities, str) and isinstance(fields, str):
                data = data.reset_index(['Security', 'Field'], drop=True)
            elif isinstance(securities, str):
                data = data.reset_index('Security', drop=True)
            elif isinstance(fields, str):
                data = data.reset_index('Field', drop=True)
            return data

        def portfolioDataRequest(self, securities, fields, overrides=None, **kwargs):
            response = self.sendRequest('PortfolioData', securities, fields, overrides, kwargs)
            # TODO: Read exactly like bulkrequest
            return response

        def intradayBarRequest(self, security, startDate, endDate, **kwargs):
            """ Performs an IntradayBarRequest.

                IntradayBarRequests can only include a single security and will
                return a predefined set of fields.  The granularity of this
                request can be set via the interval parameter in minutes.

                To receive data, startDate and endDate must include a UTC time.
            """
            defaults = {'startDateTime'           : startDate,
                        'endDateTime'             : endDate,
                        'eventType'               : 'TRADE',
                        'interval'                : 5,
                        'adjustmentNormal'        : False,
                        'adjustmentAbnormal'      : False,
                        'adjustmentSplit'         : True,
                        'adjustmentFollowDPDF'    : False}
            defaults.update(kwargs)

            response = self.sendRequest('IntradayBar', security, [], None, defaults)

            data = DataFrame()
            for msg in response:
                tickData = msg.getElement('barData').getElement('barTickData')
                tickDataList = [tickData.getValueAsElement(i) for i in range(tickData.numValues())]

                for tick in tickDataList:
                    dt = tick.getElementAsDatetime('time').replace(tzinfo=None)
                    for v in [tick.getElement(i) for i in range(1, tick.numElements())]:
                        # Get every value as a string and cast to the apropriate type later
                        # This is pretty dirty but network latency dominates the runtime of this function
                        data.ix[dt, str(v.name())] = v.getValueAsString()

            data.index.name = 'Date'
            return data.apply(pd.to_numeric, errors='coerce').sort_index()

        def intradayTickRequest(self, security, startDate, endDate, **kwargs):
            """ Performs an IntradayTickRequest.

                IntradayTickRequests can only include a single security and will
                return a predefined set of fields.

                To receive data, startDate and endDate must include a UTC time.
            """
            defaults = {'startDateTime'           : startDate,
                        'endDateTime'             : endDate,
                        'eventTypes'              : ['TRADE']}
            defaults.update(kwargs)

            response = self.sendRequest('IntradayTick', security, [], None, defaults)

            data = DataFrame()
            for msg in response:
                tickData = msg.getElement('tickData').getElement('tickData')
                tickDataList = [tickData.getValueAsElement(i) for i in range(tickData.numValues())]

                for tick in tickDataList:
                    dt = tick.getElementAsDatetime('time').replace(tzinfo=None)
                    for v in [tick.getElement(i) for i in range(1, tick.numElements())]:
                        data.ix[dt, str(v.name())] = v.getValueAsString()

            data.index.name = 'Date'
            return data.apply(pd.to_numeric, errors='coerce').sort_index()

        def sendRequest(self, requestType, securities, fields, overrides, elements):
            """ Prepares and sends a request then blocks until it can return 
                the complete response.

                Depending on the complexity of your request, incomplete and/or
                unrelated messages may be returned as part of the response.
            """
            request = self.refDataService.createRequest(requestType + 'Request')

            if isinstance(securities, str):
                securities = [securities]
            if isinstance(fields, str):
                fields = [fields]

            for s in securities:
                try:
                    request.getElement("securities").appendValue(s)
                except:
                    request.set('security', s)

            for f in fields:
                request.getElement("fields").appendValue(f)

            for k, v in elements.items():
                if isinstance(v, list):
                    for i in v:
                        request.getElement(k).appendValue(_convertDate(i))
                else:
                    request.set(k, _convertDate(v))

            if overrides is not None:
                for k, v in overrides.items():
                    ovr = request.getElement('overrides').appendElement()
                    ovr.setElement("fieldId", str(k))
                    ovr.setElement('value', str(_convertDate(v)))

            self.session.sendRequest(request)

            response = []
            while True:
                event = self.session.nextEvent(100)
                for msg in event:
                    if msg.hasElement('responseError'):
                        raise RequestError('Response Error', str(msg.getElement('responseError')))
                    if msg.hasElement('securityData'):
                        if msg.getElement('securityData').hasElement('fieldExceptions') and\
                                (msg.getElement('securityData').getElement('fieldExceptions').numValues() > 0):
                            raise RequestError('Field Error', str(msg.getElement('securityData').getElement('fieldExceptions')))
                        if msg.getElement('securityData').hasElement('securityError'):
                            raise RequestError('Security Error', str(msg.getElement('securityData').getElement('securityError')))

                    if msg.messageType() == requestType + 'Response':
                        response.append(msg)

                if event.eventType() == blpapi.Event.RESPONSE:
                    break

            return response

        def __enter__(self):
            self.open()
            return self

        # noinspection PyUnusedLocal
        def __exit__(self, exc_type, exc_val, exc_tb):
            self.close()

        def __del__(self):
            self.close()

except ImportError:
    # The Bloomberg API was not found - Implement a Proxy BLPInterface
    # instead.
    from rqm.source import net

    DEFAULT_HOST = PROXY_HOST
    DEFAULT_PORT = PROXY_PORT

    class BLPInterface:
        """ A wrapper for the Bloomberg API that returns DataFrames.  This is
            the Proxy version of the BLPInterface and was created as the 
            current environment does not have Bloomberg access.

            All requests will be forwarded to (host, port).  Run BLPServer.py
            on a computer to fulfil requests.

            All calls are blocking and responses are parsed and returned as 
            DataFrames where appropriate.
        """
        # noinspection PyShadowingBuiltins
        def __init__(self, host=PROXY_HOST, port=PROXY_PORT, open=True):
            self.active = False
            self.host = host
            self.port = port
            self.socket = None
            if open:
                self.open()

        def open(self):
            if not self.active:
                self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                self.socket.settimeout(60)
                self.socket.connect((self.host, self.port))
                self.active = True

        def historicalRequest(self, securities, fields, startDate, endDate='', overrides=None, **kwargs):
            kwargs['securities'] = securities
            kwargs['fields']     = fields
            kwargs['startDate']  = startDate
            kwargs['endDate']    = endDate
            kwargs['overrides']  = overrides
            return self.sendRequest('historicalRequest', kwargs)

        def referenceRequest(self, securities, fields, overrides=None, **kwargs):
            kwargs['securities'] = securities
            kwargs['fields']     = fields
            kwargs['overrides']  = overrides
            return self.sendRequest('referenceRequest', kwargs)

        def bulkRequest(self, securities, fields, overrides=None, **kwargs):
            kwargs['securities'] = securities
            kwargs['fields']     = fields
            kwargs['overrides']  = overrides
            return self.sendRequest('bulkRequest', kwargs)

        def intradayBarRequest(self, security, startDate, endDate, **kwargs):
            kwargs['security']   = security
            kwargs['startDate']  = startDate
            kwargs['endDate']    = endDate
            return self.sendRequest('intradayBarRequest', kwargs)

        def intradayTickRequest(self, security, startDate, endDate, **kwargs):
            kwargs['security']   = security
            kwargs['startDate']  = startDate
            kwargs['endDate']    = endDate
            return self.sendRequest('intradayTickRequest', kwargs)

        # noinspection PyTypeChecker
        def sendRequest(self, requestType, arguments):
            net.sendObject(self.socket, [requestType, arguments])
            return net.receiveObject(self.socket)

        def close(self):
            if self.active:
                self.socket.close()
                self.active = False

        def __enter__(self):
            self.open()
            return self

        # noinspection PyUnusedLocal
        def __exit__(self, exc_type, exc_val, exc_tb):
            self.close()

        def __del__(self):
            self.close()

def main():
    """ Basic usage examples.

        Note that if any tickers have changed since these examples were written
        a RequestError will be raised.
    """
    try:
        blp = BLPInterface()

        # ==============================
        # = HistoricalRequest Examples =
        # ==============================
        # Requesting a single security and field returns a simple Series.
        print(blp.historicalRequest('BMO CN Equity', 'PX_LAST', '20141231', '20150131'))

        # Requesting multiple fields returns a DataFrame.  Dates may also be passed as a datetime.
        print(blp.historicalRequest('BNS CN Equity', ['PX_LAST', 'PX_VOLUME'],
                                    datetime(2014, 12, 31), datetime(2015, 1, 31)))

        # Requesting multiple securities and fields returns a DataFrame with a MultiIndex.
        print(blp.historicalRequest(['CM CN Equity', 'NA CN Equity'], ['PX_LAST', 'PX_VOLUME'],
                                    '20141231', '20150131'))

        # You may force the returned data to be of a specific format by passing arguments as lists.
        print(blp.historicalRequest(['NA CN Equity'], ['PX_LAST'], '20141231', '20150131'))

        # Keyword arguments are added to the request, allowing you to perform advanced queries.
        print(blp.historicalRequest('TD CN Equity', 'PCT_CHG_INSIDER_HOLDINGS', '20141231', '20150131',
                                    periodicitySelection='WEEKLY'))

        blp.close()

        # The BLPInterface Class can also be used as a ContextManager.
        with BLPInterface() as blp:
            # =============================
            # = ReferenceRequest Examples =
            # =============================
            # Requesting a single security/field will return the single value, not a DataFrame.
            print(blp.referenceRequest('BBD/B CN Equity', 'GICS_SECTOR'))

            # Requesting multiple securities or fields will return a Series or DataFrame.
            print(blp.referenceRequest(['CNR CN Equity', 'CP CN Equity'], ['SECURITY_NAME_REALTIME', 'LAST_PRICE']))

            # You may force any request to return a DataFrame by passing the arguments as lists.
            print(blp.referenceRequest(['MDA CN Equity'], ['NAME_RT']))

            # Passing overrides in a dictionary is also supported
            print(blp.referenceRequest('TCK/B CN Equity', 'BICS_REVENUE_%_LEVEL_ASSIGNED',
                                       overrides={'EQY_FUNDS_SEGMENT_NUMBER':1}))

            print(blp.referenceRequest(['IBM US Equity', 'MSFT US Equity'], ['PX_LAST', 'DS002', 'EQY_WEIGHTED_AVG_PX'],
                                       overrides={'VWAP_START_TIME' : '9:30',
                                                  'VWAP_END_TIME'   : '11:30'}))
            # ========================
            # = BulkRequest Examples =
            # ========================
            # Requesting a single security and field will return a DataFrame.
            print(blp.bulkRequest('CIG CN Equity', 'EQY_DVD_ADJUST_FACT'))

            # You may request multiple securities and/or fields to receive a MultiIndex
            # print (blp.bulkRequest(['CP CN Equity','CNR CN Equity'],'PG_REVENUE'))
            # print (blp.bulkRequest('CIG CN Equity',['EQY_DVD_ADJUST_FACT','DVD_HIST_ALL']))

            # ========================
            # = Tick Examples ========
            # ========================
            # Tick requests can only contain a single security.
            print(blp.intradayBarRequest('BMO CN Equity','2015-08-21T6:00:00','2015-08-21T16:00:00'))
            print(blp.intradayTickRequest('ZCL CN Equity','2015-08-21T6:00:00','2015-08-21T16:00:00'))

    except RequestError:
        raise

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

BIG thanks !! The code work very well, we blocked on Override. Thanks you !

fcarpentey75012 commented 4 years ago

Hello, i have a new problem with API. I would this sendresquest : print(blp.referenceRequest(['C13 FP Equity'], ['INTERVAL_PERCENT_CHANGE','INTERVAL_PERCENT_CHANGE'],overrides={'CALC_INTERVAL':'1Y','CALC_INTERVAL':'5Y'})). But Bloomberg API send me back same value. It's possible to send same Field and same Overrides but with different value ? Thks you for your time !

fcarpentey75012 commented 4 years ago

Field INTERVAL_PERCENT_CHANGE INTERVAL_PERCENT_CHANGE Security
C13 FP Equity 0.077103 0.077103

691175002 commented 4 years ago

As far as I am aware you will need to submit two requests to do what you want. An override applies to the entire request.

blp.referenceRequest(['C13 FP Equity'], ['INTERVAL_PERCENT_CHANGE'],overrides={'CALC_INTERVAL':'1Y'})
blp.referenceRequest(['C13 FP Equity'], ['INTERVAL_PERCENT_CHANGE'],overrides={'CALC_INTERVAL':'5Y'})

Depending on how many intervals you need it might make more sense to do a history request and calculate the trailing periods in Pandas.

fcarpentey75012 commented 4 years ago

Thnks you for your response, i try this :

`def created_dictionnary(liste_overrides,liste_values): dictionnary_parameter={} if len(name_list) != liste_overrides: dictionnary_parameter={} for key,value in zip(liste_overrides,liste_values): if key not in dictionnary_parameter: dictionnary_parameter[key]=[value] else: dictionnary_parameter[key].append(value) return dictionnary_parameter

blp = BLPInterface() with BLPInterface() as blp:

list_one = ['CALC_INTERVAL', 'CALC_INTERVAL', 'CALC_INTERVAL', 'RISK_MEASURES_TIME_FRAME', 'RISK_MEASURES_TIME_FRAME']
list_two = ['1Y','3Y', '5Y', '4.0', '5.0']
my_list = []
name_list = list(dict.fromkeys(list_one))
if len(name_list) != list_one:
    dictionnary_overrides_values = created_dictionnary(list_one,list_two)
    for x in dictionnary_overrides_values:
        list_values = dictionnary_overrides_values.get(x)
        for i in list_values:
            ss = []
            ss.append(x)

            cc = []
            cc.append(i)

            dictionnary_parametre = dict(zip(ss, cc))
            df = blp.referenceRequest(['C13 FP Equity'], ['INTERVAL_PERCENT_CHANGE','MAXIMUM_DRAWDOWN_PCT'],overrides=dictionnary_parametre)

            # name_list.append(df['INTERVAL_PERCENT_CHANGE'].tolist())
            # print(name_list)

blp.close()
# `

But it's not very optimal, but i was think to modify your code for to take list in send and not dictionnary. I try this :

`class RequestError(Exception): """A RequestError is raised when there is a problem with a Bloomberg API response.""" def init (self, value, description): self.value = value self.description = description

def __str__ (self):
    return self.description + '\n\n' + str(self.value)

class BLPInterface: """ A wrapper for the Bloomberg API that returns DataFrames. This class manages a //BLP/refdata service and therefore does not handle event subscriptions.

    All calls are blocking and responses are parsed and returned as 
    DataFrames where appropriate. 

    A RequestError is raised when an invalid security is queried.  Invalid
    fields will fail silently and may result in an empty DataFrame.
""" 
def __init__ (self, host='localhost', port=8194, open=True):
    self.active = False
    self.host = host
    self.port = port
    if open:
        self.open()

def open (self):
    if not self.active:
        sessionOptions = blpapi.SessionOptions()
        sessionOptions.setServerHost(self.host)
        sessionOptions.setServerPort(self.port)
        self.session = blpapi.Session(sessionOptions)
        self.session.start()
        self.session.openService('//BLP/refdata')
        self.refDataService = self.session.getService('//BLP/refdata')
        self.active = True

def close (self):
    if self.active:
        self.session.stop()
        self.active = False

def historicalRequest (self, securities, fields, startDate, endDate, **kwargs):
    """ Equivalent to the Excel BDH Function.

        If securities are provided as a list, the returned DataFrame will
        have a MultiIndex.
    """
    defaults = {'startDate'       : startDate,
        'endDate'                 : endDate,
        'periodicityAdjustment'   : 'ACTUAL',
        'periodicitySelection'    : 'DAILY',
        'nonTradingDayFillOption' : 'ACTIVE_DAYS_ONLY',
        'adjustmentNormal'        : False,
        'adjustmentAbnormal'      : False,
        'adjustmentSplit'         : True,
        'adjustmentFollowDPDF'    : False}   
    defaults.update(kwargs)

    response = self.sendRequest('HistoricalData', securities, fields, defaults)

    data = []
    keys = []

    for msg in response:
        securityData = msg.getElement('securityData')
        fieldData = securityData.getElement('fieldData')
        fieldDataList = [fieldData.getValueAsElement(i) for i in range(fieldData.numValues())]

        df = DataFrame()

        for fld in fieldDataList:
            for v in [fld.getElement(i) for i in range(fld.numElements()) if fld.getElement(i).name() != 'date']:
                df.ix[fld.getElementAsDatetime('date'), str(v.name())] = v.getValue()

        df.index = pd.to_datetime(df.index)
        df.replace('#N/A History', np.nan, inplace=True)

        keys.append(securityData.getElementAsString('security'))
        data.append(df)

    if len(data) == 0:
        return DataFrame()
    if type(securities) == str:
        data = pd.concat(data, axis=1)
        data.columns.name = 'Field'
    else:
        data = pd.concat(data, keys=keys, axis=1, names=['Security','Field'])

    data.index.name = 'Date'
    return data

def referenceRequest (self, securities, fields, **kwargs):
    """ Equivalent to the Excel BDP Function.

        If either securities or fields are provided as lists, a DataFrame
        will be returned.
    """
    response = self.sendRequest('ReferenceData', securities, fields, kwargs)

    data = DataFrame()

    for msg in response:
        securityData = msg.getElement('securityData')
        securityDataList = [securityData.getValueAsElement(i) for i in range(securityData.numValues())]
        for sec in securityDataList:
            fieldData = sec.getElement('fieldData')
            fieldDataList = [fieldData.getElement(i) for i in range(fieldData.numElements())]

            for fld in fieldDataList:
                data.ix[sec.getElementAsString('security'), str(fld.name())] = fld.getValue()

    if data.empty:
        return data
    else: 
        data.index.name = 'Security'
        data.columns.name = 'Field'
        return data.iloc[0,0] if ((type(securities) == str) and (type(fields) == str)) else data

def referenceRequest_override (self, securities, fields, overridesfieldsId, overridesfieldsVal, **kwargs):
    """ Equivalent to the Excel BDP Function.

        If either securities or fields are provided as lists, a DataFrame
        will be returned.

    """
    response = self.sendRequest('ReferenceData', securities, fields, overridesfieldsId, overridesfieldsVal,  kwargs)

    data = DataFrame()

    for msg in response:
        securityData = msg.getElement('securityData')
        securityDataList = [securityData.getValueAsElement(i) for i in range(securityData.numValues())]

        for sec in securityDataList:
            fieldData = sec.getElement('fieldData')
            fieldDataList = [fieldData.getElement(i) for i in range(fieldData.numElements())]

            for fld in fieldDataList:
                data.ix[sec.getElementAsString('security'), str(fld.name())] = fld.getValue()

    if data.empty:
        return data
    else: 
        data.index.name = 'Security'
        data.columns.name = 'Field'
        return data.iloc[0,0] if ((type(securities) == str) and (type(fields) == str)) else data

def bulkRequest (self, securities, fields, **kwargs):
    """ Equivalent to the Excel BDS Function.

        If securities are provided as a list, the returned DataFrame will
        have a MultiIndex.

        You may pass a list of fields to a bulkRequest.  An appropriate
        Index will be generated, however such a DataFrame is unlikely to
        be useful unless the bulk data fields contain overlapping columns.
    """
    response = self.sendRequest('ReferenceData', securities, fields, kwargs)

    data = []
    keys = []

    for msg in response:
        securityData = msg.getElement('securityData')
        securityDataList = [securityData.getValueAsElement(i) for i in range(securityData.numValues())]

        for sec in securityDataList:
            fieldData = sec.getElement('fieldData')
            fieldDataList = [fieldData.getElement(i) for i in range(fieldData.numElements())]

            df = DataFrame()

            for fld in fieldDataList:
                for v in [fld.getValueAsElement(i) for i in range(fld.numValues())]:
                    s = Series()
                    for d in [v.getElement(i) for i in range(v.numElements())]:
                        s[str(d.name())] = d.getValue()
                    df = df.append(s, ignore_index=True)

            if not df.empty:
                keys.append(sec.getElementAsString('security'))
                data.append(df.set_index(df.columns[0]))

    if len(data) == 0:
        return DataFrame()
    if type(securities) == str:
        data = pd.concat(data, axis=1)
        data.columns.name = 'Field'
    else:
        data = pd.concat(data, keys=keys, axis=0, names=['Security',data[0].index.name])

    return data

def sendRequest (self, requestType, securities, fields, overridesfieldsId, overridesfieldsVal, elements):
    """ Prepares and sends a request then blocks until it can return 
        the complete response.

        Depending on the complexity of your request, incomplete and/or
        unrelated messages may be returned as part of the response.
    """
    request = self.refDataService.createRequest(requestType + 'Request')

    if type(securities) == str:
        securities = [securities]
    if type(fields) == str:
        fields = [fields]
    if type(overridesfieldsId) == str:
        overridesfieldsId = [overridesfieldsId]
    if type(overridesfieldsVal) == str:
        overridesfieldsVal = [overridesfieldsVal]

    ovr = request.getElement("overrides").appendElement()

    for s in securities:
        request.getElement("securities").appendValue(s)
    for f in fields:
        request.getElement("fields").appendValue(f)
    for oi in overridesfieldsId:
        ovr.setElement("fieldId",str(oi))
    for ov in overridesfieldsVal:
        ovr.setElement("value",ov)
    for k, v in elements.items():
        if type(v) == datetime:
            v = v.strftime('%Y%m%d')
        request.set(k, v)
        print(overridesfieldsId)
    self.session.sendRequest(request)

    response = []
    while True:
        event = self.session.nextEvent(100)
        for msg in event:
            if msg.hasElement('responseError'):
                raise RequestError(msg.getElement('responseError'), 'Response Error')
            if msg.hasElement('securityData'):
                if msg.getElement('securityData').hasElement('fieldExceptions') and (msg.getElement('securityData').getElement('fieldExceptions').numValues() > 0):
                    raise RequestError(msg.getElement('securityData').getElement('fieldExceptions'), 'Field Error')
                if msg.getElement('securityData').hasElement('securityError'):
                    raise RequestError(msg.getElement('securityData').getElement('securityError'), 'Security Error')

            if msg.messageType() == requestType + 'Response':
                response.append(msg)

        if event.eventType() == blpapi.Event.RESPONSE:
            break

    return response

def __enter__ (self):
    self.open()
    return self

def __exit__ (self, exc_type, exc_val, exc_tb):
    self.close()

def __del__ (self):
    self.close()

def main(): """ Basic usage examples.

    Note that if any tickers have changed since these examples were written
    a RequestError will be raised.
"""
try:
    blp = BLPInterface()

    # ==============================
    # = HistoricalRequest Examples =
    #===============================
    # Requesting a single security and field returns a simple DataFrame.
    # print (blp.historicalRequest('BMO CN Equity', 'PX_LAST', '20141231', '20150131'))

    # Requesting multiple fields returns a DataFrame with multiple columns.  Dates may also be passed as a datetime.
    # print (blp.historicalRequest('BNS CN Equity', ['PX_LAST', 'PX_VOLUME'], datetime(2014, 12, 31), datetime(2015, 1, 31)))

    # Requesting multiple securities returns a DataFrame with a MultiIndex.
    df = blp.referenceRequest_override(['C13 FP Equity'], ['MAXIMUM_DRAWDOWN_PCT','INTERVAL_PERCENT_CHANGE'],['RISK_MEASURES_TIME_FRAME','CALC_INTERVAL'],['4','2'])
    print(df)

    #df = blp.historicalRequest(['CM CN Equity'], ['PX_LAST'], '20141231', '20150131')
    #print(df)

    #df=df.iloc[:, df.columns.get_level_values(0)=='CM CN Equity']
    # aa = df.iloc[:, df.columns.get_level_values(1)=='PX_LAST']
    # print(aa.pct_change())

    # You may force any DataFrame to include a MultiIndex by passing the arguments as lists.
    # print (blp.historicalRequest(['NA CN Equity'], ['PX_LAST'], '20141231', '20150131'))
    # 
    # # Keyword arguments are added to the request, allowing you to perform advanced queries.
    # print (blp.historicalRequest('TD CN Equity', 'PCT_CHG_INSIDER_HOLDINGS', '20141231', '20150131', periodicitySelection='WEEKLY'))

    blp.close()

    # The BLPInterface Class can also be used as a ContextManager.
    # with BLPInterface() as blp:
    #     =============================
    #     = ReferenceRequest Examples =
    #     =============================
    #     Requesting a single security/field will return the single value, not a DataFrame.
    #     # print (blp.referenceRequest('BBD/B CN Equity', 'GICS_SECTOR'))
    #     
    #     # Requesting multiple securities or fields will return a DataFrame.
    #     print (blp.referenceRequest(['CNR CN Equity', 'CP CN Equity'], ['SECURITY_NAME_REALTIME', 'LAST_PRICE']))
    #     
    #     # You may force any request to return a DataFrame by passing the arguments as lists.
        # print (blp.referenceRequest(['MDA CN Equity'], ['NAME_RT']))
    #     
    #     # ========================
    #     # = BulkRequest Examples =
    #     # ========================
    #     # Requesting a single security and field will return a DataFrame.
    #     print (blp.bulkRequest('CIG CN Equity','EQY_DVD_ADJUST_FACT'))
    #     
    #     You may request multiple securities and/or fields.
    #     This feature is generally not useful as the resulting DataFrame is ugly.
    #     print (blp.bulkRequest(['CP CN Equity','CNR CN Equity'],'PG_REVENUE'))
    #     print (blp.bulkRequest('CIG CN Equity',['EQY_DVD_ADJUST_FACT','DVD_HIST_ALL']))

except RequestError as e:
    print (e.value)
    raise

if name == "main": try: main() except KeyboardInterrupt: print ("Ctrl+C pressed. Stopping...")`

But, my problem is that i can't send multi overrides, do you have idea for to adjust your code and my code ?

Thanks you for your time and your help !

fcarpentey75012 commented 4 years ago

I modified the SendResquest **

691175002 commented 4 years ago

You cannot sent multi-overrides because Bloomberg does not accept multi-overrides. Even if you append multiple copies of the same fieldId to the overrides element Bloomberg will just ignore all but the last one.

https://data.bloomberglp.com/labs/sites/2/2014/07/blpapi-developers-guide-2.54.pdf

fcarpentey75012 commented 4 years ago

Hi,

I find this solution to have request with Overrides. But, i would like put the hour in my request BDH Because i want the OPEN price between hours for example 20200219 at 11:00:00 It's possible ?

Thanks you !

` import socket import itertools from datetime import datetime, date, time from collections import Counter import pandas as pd import numpy as np from pandas import Series from pandas import DataFrame

Default Connections

BLP_HOST = 'localhost' BLP_PORT = 8194 PROXY_HOST = '' PROXY_PORT = 5001

class RequestError(Exception): """A RequestError is raised when there is a problem with a Bloomberg API response.""" def init(self, description, value=None): self.value = value self.description = description

def __str__(self):
    if self.value is not None:
        return self.description + '\n' + self.value
    return self.description

def _uwrap(s): """Helper function to convert a string or list into a list of unique entries.""" s = [s] if isinstance(s, str) else s return list(set(s))

def _convertDate(d): """Helper function to convert dates and datetimes into blpapi strings.""" if isinstance(d, np.datetime64): d = pd.Timestamp(d) elif isinstance(d, pd.Period): d = d.to_timestamp(freq='D')

if isinstance(d, date):
    if isinstance(d, datetime) and (d.time() != time(0)):
        return d.strftime('%Y-%m-%dT%H:%M:%S')
    else:
        return d.strftime('%Y%m%d')
return d

Attempt to import the Bloomberg API. Technically this is a bad idea as it

can mask unrelated ImportErrors but whatever.

try:

noinspection PyUnresolvedReferences

import blpapi

# The Bloomberg API was successfully imported - Create the normal
# BLPInterface class.

DEFAULT_HOST = BLP_HOST
DEFAULT_PORT = BLP_PORT

class BLPInterface:
    """ A wrapper for the Bloomberg API that returns DataFrames.  This class
        manages a //BLP/refdata service and therefore does not handle event
        subscriptions.

        All calls are blocking and responses are parsed and returned as
        DataFrames where appropriate.

        A RequestError is raised when an invalid security is queried.  Invalid
        fields will fail silently and may result in an empty DataFrame.
    """
    # noinspection PyShadowingBuiltins
    def __init__(self, host=BLP_HOST, port=BLP_PORT, open=True):
        self.active = False
        self.host = host
        self.port = port
        self.session = None
        self.refDataService = None
        if open:
            self.open()

    def open(self):
        if not self.active:
            sessionOptions = blpapi.SessionOptions()
            sessionOptions.setServerHost(self.host)
            sessionOptions.setServerPort(self.port)
            sessionOptions.setAutoRestartOnDisconnection(True)

            self.session = blpapi.Session(sessionOptions)
            if (not self.session.start()) or (not self.session.openService("//blp/refdata")):
                raise RequestError('Failed to start session')

            self.refDataService = self.session.getService('//BLP/refdata')
            self.active = True

    def close(self):
        if self.active:
            self.session.stop()
            self.active = False

    def historicalRequest(self, securities, fields, startDate, endDate='', overrides=None, **kwargs):
        """ Equivalent to the Excel BDH Function.

            If securities are provided as a list, the returned DataFrame will
            have a MultiIndex.

            StartDate and endDate should be a datetime.date or YYYYMMDD string.
            Datetimes or Timestamps with a non-zero time component will not be
            recognized correctly by the Bloomberg API.

            Useful kwargs are periodicitySelection, adjustmentNormal,
            adjustmentAbnormal, adjustmentSplit, and currency.
        """
        defaults = {'startDate'               : startDate.replace('-', '') if isinstance(startDate, str) else startDate,
                    'endDate'                 : endDate.replace('-', '') if isinstance(endDate, str) else endDate,
                    'periodicityAdjustment'   : 'CALENDAR',
                    'periodicitySelection'    : 'DAILY',
                    'nonTradingDayFillOption' : 'NON_TRADING_WEEKDAYS',
                    'adjustmentNormal'        : False,
                    'adjustmentAbnormal'      : False,
                    'adjustmentSplit'         : True,
                    'adjustmentFollowDPDF'    : False}
        defaults.update(kwargs)
        usecurities = _uwrap(securities)
        ufields = _uwrap(fields)
        response = self.sendRequest('HistoricalData', usecurities, ufields, overrides, defaults)

        data = []
        keys = []

        for msg in response:
            securityData = msg.getElement('securityData')
            fieldData = securityData.getElement('fieldData')
            fieldDataList = [fieldData.getValueAsElement(i) for i in range(fieldData.numValues())]

            df = DataFrame(columns=ufields)

            for fld in fieldDataList:
                for v in [fld.getElement(i) for i in range(fld.numElements())
                          if fld.getElement(i).name() != 'date']:
                    df.ix[fld.getElementAsDatetime('date'), str(v.name())] = v.getValue()

            df.index = pd.to_datetime(df.index)
            df.replace('#N/A History', np.nan, inplace=True)

            keys.append(securityData.getElementAsString('security'))
            data.append(df)

        if len(data) == 0:
            return DataFrame()
        else:
            data = pd.concat(data, keys=keys, axis=1, names=['Security', 'Field']).sort_index()
            data.index.name = 'Date'

        if isinstance(securities, str) and isinstance(fields, str):
            data = data.iloc[:,0]
            data.name = fields
        elif isinstance(securities, str):
            data.columns = data.columns.droplevel('Security')
            data = data[fields]
        elif isinstance(fields, str):
            data.columns = data.columns.droplevel('Field')
            data = data[securities]
        else:
            data = data[list(itertools.product(securities, fields))]
        return data

    def referenceRequest(self, securities, fields, overrides=None, **kwargs):
        """ Equivalent to the Excel BDP Function.

            If either securities or fields are provided as lists, a DataFrame
            will be returned.
        """
        usecurities = _uwrap(securities)
        ufields = _uwrap(fields)
        response = self.sendRequest('ReferenceData', usecurities, ufields, overrides, kwargs)
        data = DataFrame(index=usecurities, columns=ufields)

        for msg in response:
            securityData = msg.getElement('securityData')
            securityDataList = [securityData.getValueAsElement(i) for i in range(securityData.numValues())]

            for sec in securityDataList:
                fieldData = sec.getElement('fieldData')
                fieldDataList = [fieldData.getElement(i) for i in range(fieldData.numElements())]

                for fld in fieldDataList:
                    data.ix[sec.getElementAsString('security'), str(fld.name())] = fld.getValue()

        if data.empty:
            return DataFrame()
        else:
            data.index.name = 'Security'
            data.columns.name = 'Field'

        if isinstance(securities, str) and isinstance(fields, str):
            data = data.iloc[0, 0]
        elif isinstance(securities, str):
            data = data.iloc[0, :][fields]
        elif isinstance(fields, str):
            data = data.iloc[:, 0][securities]
        else:
            data = data.loc[securities, fields]
        return data

    def bulkRequest(self, securities, fields, overrides=None, **kwargs):
        """ Equivalent to the Excel BDS Function.

            If securities are provided as a list, the returned DataFrame will
            have a MultiIndex.

            You may also pass a list of fields to a bulkRequest.  An appropriate
            MultiIndex will be generated, however such a DataFrame is unlikely
            to be useful unless the bulk data fields contain overlapping columns.
        """
        response = self.sendRequest('ReferenceData', securities, fields, overrides, kwargs)

        data = []
        keys = []

        for msg in response:
            securityData = msg.getElement('securityData')
            securityDataList = [securityData.getValueAsElement(i) for i in range(securityData.numValues())]

            for sec in securityDataList:
                fieldData = sec.getElement('fieldData')
                fieldDataList = [fieldData.getElement(i) for i in range(fieldData.numElements())]

                fldData = []
                fldKeys = []

                for fld in fieldDataList:
                    df = DataFrame()
                    for v in [fld.getValueAsElement(i) for i in range(fld.numValues())]:
                        s = Series()
                        for d in [v.getElement(i) for i in range(v.numElements())]:
                            try:
                                s[str(d.name())] = d.getValue()
                            except:
                                # There is seriously no end to the shit getValue() can raise.
                                pass
                        # Bloomberg returns this magic number instead of NaN for certain bulk fields.
                        df = df.append(s.where(s != -2.4245362661989844e-14, np.nan), ignore_index=True)

                    try:
                        df = df.set_index(df.columns[0])
                        if not df.empty:
                            fldKeys.append(str(fld.name()))
                            fldData.append(df)
                    except IndexError:
                        pass

                if fldData:
                    keys.append(sec.getElementAsString('security'))
                    data.append(pd.concat(fldData, keys=fldKeys, names=['Field']))

        if data:
            data = pd.concat(data, keys=keys, names=['Security'])
            data.columns.name = 'Element'
        else:
            return DataFrame()

        if isinstance(securities, str) and isinstance(fields, str):
            data = data.reset_index(['Security', 'Field'], drop=True)
        elif isinstance(securities, str):
            data = data.reset_index('Security', drop=True)
        elif isinstance(fields, str):
            data = data.reset_index('Field', drop=True)
        return data

    def portfolioDataRequest(self, securities, fields, overrides=None, **kwargs):
        response = self.sendRequest('PortfolioData', securities, fields, overrides, kwargs)
        # TODO: Read exactly like bulkrequest
        return response

    def intradayBarRequest(self, security, startDate, endDate, **kwargs):
        """ Performs an IntradayBarRequest.

            IntradayBarRequests can only include a single security and will
            return a predefined set of fields.  The granularity of this
            request can be set via the interval parameter in minutes.

            To receive data, startDate and endDate must include a UTC time.
        """
        defaults = {'startDateTime'           : startDate,
                    'endDateTime'             : endDate,
                    'eventType'               : 'TRADE',
                    'interval'                : 5,
                    'adjustmentNormal'        : False,
                    'adjustmentAbnormal'      : False,
                    'adjustmentSplit'         : True,
                    'adjustmentFollowDPDF'    : False}
        defaults.update(kwargs)

        response = self.sendRequest('IntradayBar', security, [], None, defaults)

        data = DataFrame()
        for msg in response:
            tickData = msg.getElement('barData').getElement('barTickData')
            tickDataList = [tickData.getValueAsElement(i) for i in range(tickData.numValues())]

            for tick in tickDataList:
                dt = tick.getElementAsDatetime('time').replace(tzinfo=None)
                for v in [tick.getElement(i) for i in range(1, tick.numElements())]:
                    # Get every value as a string and cast to the apropriate type later
                    # This is pretty dirty but network latency dominates the runtime of this function
                    data.ix[dt, str(v.name())] = v.getValueAsString()

        data.index.name = 'Date'
        return data.apply(pd.to_numeric, errors='coerce').sort_index()

    def intradayTickRequest(self, security, startDate, endDate, **kwargs):
        """ Performs an IntradayTickRequest.

            IntradayTickRequests can only include a single security and will
            return a predefined set of fields.

            To receive data, startDate and endDate must include a UTC time.
        """
        defaults = {'startDateTime'           : startDate,
                    'endDateTime'             : endDate,
                    'eventTypes'              : ['TRADE']}
        defaults.update(kwargs)

        response = self.sendRequest('IntradayTick', security, [], None, defaults)

        data = DataFrame()
        for msg in response:
            tickData = msg.getElement('tickData').getElement('tickData')
            tickDataList = [tickData.getValueAsElement(i) for i in range(tickData.numValues())]

            for tick in tickDataList:
                dt = tick.getElementAsDatetime('time').replace(tzinfo=None)
                for v in [tick.getElement(i) for i in range(1, tick.numElements())]:
                    data.ix[dt, str(v.name())] = v.getValueAsString()

        data.index.name = 'Date'
        return data.apply(pd.to_numeric, errors='coerce').sort_index()

    def sendRequest(self, requestType, securities, fields, overrides, elements):
        """ Prepares and sends a request then blocks until it can return
            the complete response.

            Depending on the complexity of your request, incomplete and/or
            unrelated messages may be returned as part of the response.
        """
        request = self.refDataService.createRequest(requestType + 'Request')

        if isinstance(securities, str):
            securities = [securities]
        if isinstance(fields, str):
            fields = [fields]

        for s in securities:
            try:
                request.getElement("securities").appendValue(s)
            except:
                request.set('security', s)

        for f in fields:
            request.getElement("fields").appendValue(f)

        for k, v in elements.items():
            if isinstance(v, list):
                for i in v:
                    request.getElement(k).appendValue(_convertDate(i))
            else:
                request.set(k, _convertDate(v))

        if overrides is not None:
            for k, v in overrides.items():
                ovr = request.getElement('overrides').appendElement()
                ovr.setElement("fieldId", str(k))
                ovr.setElement('value', str(_convertDate(v)))

        self.session.sendRequest(request)

        response = []
        while True:
            event = self.session.nextEvent(100)
            for msg in event:
                if msg.hasElement('responseError'):
                    raise RequestError('Response Error', str(msg.getElement('responseError')))
                if msg.hasElement('securityData'):
                    if msg.getElement('securityData').hasElement('fieldExceptions') and\
                            (msg.getElement('securityData').getElement('fieldExceptions').numValues() > 0):
                        raise RequestError('Field Error', str(msg.getElement('securityData').getElement('fieldExceptions')))
                    if msg.getElement('securityData').hasElement('securityError'):
                        raise RequestError('Security Error', str(msg.getElement('securityData').getElement('securityError')))

                if msg.messageType() == requestType + 'Response':
                    response.append(msg)

            if event.eventType() == blpapi.Event.RESPONSE:
                break

        return response

    def __enter__(self):
        self.open()
        return self

    # noinspection PyUnusedLocal
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()

    def __del__(self):
        self.close()

except ImportError:

The Bloomberg API was not found - Implement a Proxy BLPInterface

# instead.
from rqm.source import net

DEFAULT_HOST = PROXY_HOST
DEFAULT_PORT = PROXY_PORT

class BLPInterface:
    """ A wrapper for the Bloomberg API that returns DataFrames.  This is
        the Proxy version of the BLPInterface and was created as the
        current environment does not have Bloomberg access.

        All requests will be forwarded to (host, port).  Run BLPServer.py
        on a computer to fulfil requests.

        All calls are blocking and responses are parsed and returned as
        DataFrames where appropriate.
    """
    # noinspection PyShadowingBuiltins
    def __init__(self, host=PROXY_HOST, port=PROXY_PORT, open=True):
        self.active = False
        self.host = host
        self.port = port
        self.socket = None
        if open:
            self.open()

    def open(self):
        if not self.active:
            self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.socket.settimeout(60)
            self.socket.connect((self.host, self.port))
            self.active = True

    def historicalRequest(self, securities, fields, startDate, endDate='', overrides=None, **kwargs):
        kwargs['securities'] = securities
        kwargs['fields']     = fields
        kwargs['startDate']  = startDate
        kwargs['endDate']    = endDate
        kwargs['overrides']  = overrides
        return self.sendRequest('historicalRequest', kwargs)

    def referenceRequest(self, securities, fields, overrides=None, **kwargs):
        kwargs['securities'] = securities
        kwargs['fields']     = fields
        kwargs['overrides']  = overrides
        return self.sendRequest('referenceRequest', kwargs)

    def bulkRequest(self, securities, fields, overrides=None, **kwargs):
        kwargs['securities'] = securities
        kwargs['fields']     = fields
        kwargs['overrides']  = overrides
        return self.sendRequest('bulkRequest', kwargs)

    def intradayBarRequest(self, security, startDate, endDate, **kwargs):
        kwargs['security']   = security
        kwargs['startDate']  = startDate
        kwargs['endDate']    = endDate
        return self.sendRequest('intradayBarRequest', kwargs)

    def intradayTickRequest(self, security, startDate, endDate, **kwargs):
        kwargs['security']   = security
        kwargs['startDate']  = startDate
        kwargs['endDate']    = endDate
        return self.sendRequest('intradayTickRequest', kwargs)

    # noinspection PyTypeChecker
    def sendRequest(self, requestType, arguments):
        net.sendObject(self.socket, [requestType, arguments])
        return net.receiveObject(self.socket)

    def close(self):
        if self.active:
            self.socket.close()
            self.active = False

    def __enter__(self):
        self.open()
        return self

    # noinspection PyUnusedLocal
    def __exit__(self, exc_type, exc_val, exc_tb):
        self.close()

    def __del__(self):
        self.close()

def bdp(securities, fields): blp = BLPInterface() if type(fields) is dict: return overrides(securities, fields) else: return blp.referenceRequest(securities,fields)

def overrides(liste_tickers,dict_bloom):

Tableau en attente

df = []
# Incrementation des tableau en attente
c = 0
# Fields
fields_bm = dict_bloom['field']
# Fields sans overrides
fields_overrides = dict_bloom['field_overrides']
#Doublon total
doublon_total= []
for i in fields_overrides.keys():
    pending = [k for k,v in Counter(fields_overrides[i][0]).items() if v>1]
    if pending != []:
        doublon_total.append(pending)

# On définis si c'est un appel avec ou sans overrides
if len(fields_overrides.keys()) !=0:
    # --------On divise en deux le dictionnaire pour extraite les fields et les fields avec override-------------------------------
    # Liste des fields avec overrides
    list_fields_overrides = [i for i in fields_overrides.keys()]

    # Liste des fields qui n'ont pas d'overrides
    Liste_fields_whitoutoverrides= [i for i in fields_bm if i not in list_fields_overrides]

    # Keys des dictionnaire
    for i in fields_overrides.keys():
        list_doublon = [k for k,v in Counter(fields_overrides[i][0]).items() if v>1]
        # Doublons
        if len(list_doublon) >= 1:
            # On définis les éléments en double
            overrides_duplicate = [doublon_in_list for doublon_in_list in list_doublon]
            # Liste
            List = []
            Liste_value_whitoutoverrides = []
            Liste_overrides_whitoutoverrides = []
            Liste_fields_whitoverrides = []

            # Liste des overrides
            List = fields_overrides[i][0]

            #Localise les doublons pour appeler leurs valeurs
            idx = [i for i, val in enumerate(List) if val in overrides_duplicate]

            # Liste Overrides
            Liste_overrides_whitoutoverrides = List
            Liste_overrides_whitoutoverrides = [v for i,v in enumerate(Liste_overrides_whitoutoverrides) if i not in idx]
            # Liste Value
            Liste_value_whitoutoverrides = fields_overrides[i][1]
            Liste_value_whitoutoverrides = [v for i,v in enumerate(Liste_value_whitoutoverrides) if i not in idx]

            # Appel Bloom
            for x in idx:
                Liste_overrides_whitoutoverrides.append(fields_overrides[i][0][x])
                Liste_value_whitoutoverrides.append(fields_overrides[i][1][x])

                if i in list_fields_overrides:
                    Liste_fields_whitoverrides.append(i)

                # Appel Blom
                fields = Liste_fields_whitoverrides

                overrides = {Liste_overrides_whitoutoverrides[i]: Liste_value_whitoutoverrides[i] for i in range(len(Liste_overrides_whitoutoverrides))}

                # df[c] = blp.referenceRequest(liste_tickers, fields,overrides=overrides)
                df.append(c)
                df[c] = blp.referenceRequest(liste_tickers, fields,overrides=overrides)
                if c == 0:
                    df_bloom =  df[c]
                    name = str(i) + str(fields_overrides[i][1][x])
                    df_bloom = df_bloom.rename(columns={i: name})
                else:
                    df_bloom = pd.concat([df_bloom, df[c]], axis=1, sort=False)
                    name = str(i) + str(fields_overrides[i][1][x])
                    df_bloom = df_bloom.rename(columns={i: name})

                df_bloom = df_bloom.T.drop_duplicates().T
                c = c + 1
                # Nettoyage des list
                Liste_overrides_whitoutoverrides.remove(fields_overrides[i][0][x])
                Liste_value_whitoutoverrides.remove(fields_overrides[i][1][x])
                Liste_fields_whitoverrides = []
                one_duplicate = 3
        #Si aucun overrides en double, on fait un seul appel
        elif len(list_doublon) >= 0:
            fields = [i] + Liste_fields_whitoutoverrides
            ovrd = fields_overrides[i][0]
            val = fields_overrides[i][1]
            overrides = dict(zip(ovrd, val))

            if doublon_total == []:
                fields = dict_bloom['field']
                df_bloom =  blp.referenceRequest(liste_tickers, fields,overrides=overrides)
                one_duplicate = 4
            else:
                call =  blp.referenceRequest(liste_tickers, fields,overrides=overrides)
                try:
                    df_bloom_whitout_overrides = pd.concat([df_bloom, call], axis=1, sort=False)
                    one_duplicate = 2
                except:
                    df_bloom_whitout_overrides = call
                    print('ij')
                    one_duplicate = 1

if one_duplicate == 1:
    df_bloom = pd.concat([df_bloom, df_bloom_whitout_overrides], axis=1, sort=False)
    df_bloom = df_bloom.T.drop_duplicates().T
elif one_duplicate == 2:
    df_bloom = pd.concat([df_bloom, df_bloom_whitout_overrides], axis=1, sort=False)
    df_bloom = df_bloom.T.drop_duplicates().T
elif one_duplicate == 3:
    df_bloom_whitout_overrides =  blp.referenceRequest(liste_tickers, Liste_fields_whitoutoverrides)
    df_bloom = pd.concat([df_bloom, df_bloom_whitout_overrides], axis=1, sort=False)
    df_bloom = df_bloom.T.drop_duplicates().T
elif one_duplicate == 4:
    df_bloom = df_bloom

return df_bloom

a = {'field': ['NAME', 'INDUSTRY_SUBGROUP','INTERVAL_PERCENT_CHANGE', 'INTERVAL_STD_DEV'], 'field_overrides': { 'INTERVAL_STD_DEV': [['CALC_INTERVAL'], ['1Y']],'INTERVAL_PERCENT_CHANGE': [['CALC_INTERVAL'], ['1Y']]}}

blp = BLPInterface()

a = {'field': ['INTERVAL_START_VALUE'], 'field_overrides': { 'INTERVAL_START_VALUE': [['END_DATE_OVERRIDE','START_DATE_OVERRIDE'], ['20200210','20190210']]}} print(bdp(['ESH0 Index'],a))

blp.close()

`