Abstract
I know Bloomberg has made it's API open to the public. Unfortunately, I use Python and there begins my dilemma. It is not a Bloomberg supported programming language. Speaking of which, after any convesation I have with someone from their Helpdesk, there's nothing much I can do but bang my head on top of my desk.I have written this document to provide ample information on how to interface with Bloomberg using Python. I have endured a great amount of pain in order to make sure that information here will work for all Bloomberg installations.
Bloomberg.Data.1
This is the legacy way of doing things. It DOESN'T work on all Bloomberg installations. But for completeness sake, the code is as simple as:import win32com.client
BLP = win32com.client.Dispatch('Bloomberg.Data.1')
V3 API
comtypes, win32com, and ctypes are 3 python modules that I have experimented with. I will only provide information for comtypes and win32com since my tango with ctypes has gone into an infinite loop. According to Bloomberg, the library for V3 API can be accessed via registered or unregistered mode. The modules below will determine which one you have. I have broken down the modules for easy maintenance.bbg_helper.py
import logger
import win32com.client, win32com.client.gencache
import comtypes.client as COM
import blpapicom2_unregistered as unreg_mode
try:
logger.info('Trying blpapicom2.Session.1 registered mode (comtypes.client)')
session = COM.CreateObject('blpapicom2.Session.1')
logger.info('comtypes.client blpapicom2.Session.1 registered mode is OK')
except Exception as e:
logger.warn('FAILED IN STARTING blpapicom2.Session.1 WITH MESSAGE: %s', str(e))
try:
logger.info('Trying blpapicom.Session registered mode (comtypes.client)')
session = COM.CreateObject('blpapicom.Session')
logger.info('comtypes.client blpapicom.Session registered mode is OK')
except Exception as e:
logger.warn('FAILED IN STARTING blpapicom.Session WITH MESSAGE: %s', str(e))
try:
logger.info('Trying blpapicom2.Session.1 registered mode (win32com.client)')
session = win32com.client.CastTo(win32com.client.gencache.EnsureDispatch('blpapicom2.Session.1'),'ISession')
logger.info(win32com.client blpapicom2.Session.1 registered mode is OK)
except Exception as e:
logger.warn('FAILED IN STARTING blpapicom2.Session.1 WITH MESSAGE: %s', str(e))
try:
logger.info('Trying blpapicom.Session registered mode (win32com.client)')
session = win32com.client.CastTo(win32com.client.gencache.EnsureDispatch('blpapicom.Session'),'ISession')
logger.info('win32com.client blpapicom.Session registered mode is OK')
except Exception as e:
) logger.warn('FAILED IN STARTING blpapicom.Session WITH MESSAGE: %s', str(e))
try:
session = unreg_mode.BlpCoCreateInstance()
except:
pass
blpapicom2_unregistered.py
import sys
import win32com.client
import comtypes.client as COM
import logger
import blpapicom_unregistered as unreg_mode
# config for Windows XP users
API_XP = unreg_mode.API2_XP
# config for Windows 7 users
API_WIN7 = unreg_mode.API2_WIN7
def BlpCoCreateInstance():
'''
Return a Session object
'''
Session = None
Module = None
try:
logger.info('Trying blpapicom2.dll un-registered mode (comtypes.client)')
if sys.getwindowsversion()[0] < 6:
logger.info('Trying for Windows XP config')
Module = COM.GetModule(API_XP)
else:
logger.info('Trying for Windows 7 config')
Module = COM.GetModule(API_WIN7)
if Module is not None:
Session = COM.CreateObject(Module.Session)
logger.info('comtypes.client blpapicom2.dll un-registered mode is OK')
except Exception as e:
logger.warn('FAILED IN STARTING blpapicom2.dll WITH MESSAGE: %s', str(e))
try:
logger.info('Trying blpapicom2.dll un-registered mode (win32com.client)')
Session = win32com.client.CastTo(win32com.client.Dispatch('blpapicom2.Session'),'ISession')
logger.info('win32com.client blpapicom2.dll un-registered mode is OK')
except Exception as e:
logger.warn('FAILED IN STARTING blpapicom2.dll WITH MESSAGE: %s', str(e))
try:
Session = unreg_mode.BlpCoCreateInstance()
except:
pass
return Session
blpapicom_unregistered.py
import sys
import win32com.client
import comtypes.client as COM
import logger
import ctypes_unregistered as unreg_mode
# config for Windows XP users
API2_XP = unreg_mode.API2_XP
API_XP = unreg_mode.API_XP
# config for Windows 7 users
API2_WIN7 = unreg_mode.API2_WIN7
API_WIN7 = unreg_mode.API_WIN7
def BlpCoCreateInstance():
'''
Return a Session object
'''
Session = None
Module = None
try:
logger.info('Trying blpapicom.dll un-registered mode (comtypes.client)')
if sys.getwindowsversion()[0] < 6:
logger.info('Trying for Windows XP config')
Module = COM.GetModule(API_XP)
else:
logger.info('Trying for Windows 7 config')
Module = COM.GetModule(API_WIN7)
if Module is not None:
Session = COM.CreateObject(Module.Session)
logger.info('comtypes.client blpapicom.dll un-registered mode is OK')
except Exception as e:
logger.warn('FAILED IN STARTING blpapicom.dll WITH MESSAGE: %s', str(e))
try:
logger.info('Trying blpapicom.dll un-registered mode (win32com.client)')
Session = win32com.client.CastTo(win32com.client.Dispatch('blpapicom.Session'),'ISession')
logger.info('win32com.client blpapicom.dll un-registered mode is OK')
except Exception as e:
try:
Session = unreg_mode.BlpCoCreateInstance()
except:
pass
return Session
ctypes_unregistered.py
import sys
import ctypes
import logger
OLEAUT32 = ctypes.oledll.oleaut32
OLE32 = ctypes.oledll.ole32
OLE32.CoInitialize(0)
# IIDs
RCLSID = '{9FDBE237-38A5-4d8c-BB9C-2EB55FB1EABE}'
RIID = '{4AC751C2-BB10-4702-BB05-791D93BB461C}'
BYTE = ctypes.c_byte
WORD = ctypes.c_int
DWORD = ctypes.c_long
# config for Windows XP users
ROOT_XP = r'C:\Program Files\BLP\API'
LOADER_XP = ROOT_XP + '\\' + 'bbloaderv3.dll'
API2_XP = ROOT_XP + '\\' + 'blpapicom2.dll'
API_XP = ROOT_XP + '\\' + 'blpapicom.dll'
# config for Windows 7 users
ROOT_WIN7 = r'C:\Program Files (x86)\BLP\API'
LOADER_WIN7 = ROOT_WIN7 + '\\' + 'bbloaderv3.dll'
API2_WIN7 = ROOT_WIN7 + '\\' + 'blpapicom2.dll'
API_WIN7 = ROOT_WIN7 + '\\' + 'blpapicom.dll'
def PrintGUIDValue(guid):
'''
Return GUID _fields_ values
'''
return "Data1: %s; Data2: %s; Data3: %s; Data4: %s" %(str(guid.Data1), str(guid.Data2), str(guid.Data3),"".join(str(guid.Data4)))
class GUID(ctypes.Structure):
_fields_ = [
("Data1", ctypes.c_long),
("Data2", ctypes.c_int),
("Data3", ctypes.c_int),
("Data4", ctypes.c_byte * 8),
]
def __init__(self, name=None):
if name is not None:
self._as_parameter = OLE32.CLSIDFromString(unicode(name), ctypes.byref(self))
def __repr__(self):
s = (ctypes.c_wchar * 39)()
OLE32.StringFromGUID2(ctypes.byref(self), s, 39)
return "guid: %s" % s.value
def __str__(self):
s = (ctypes.c_wchar * 39)()
OLE32.StringFromGUID2(ctypes.byref(self), s, 39)
return s.value
def __cmp__(self, other):
if isinstance(other, GUID):
return not OLE32.IsEqualGUID(ctypes.byref(self), ctypes.byref(other))
return -1
def __nonzero__(self):
result = str(buffer(self)) != "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
return result
def __eq__(self, other, IsEqualGUID=OLE32.IsEqualGUID):
return isinstance(other, GUID) and IsEqualGUID(ctypes.byref(self), ctypes.byref(other))
def PrintGUIDValue(self):
''' Return GUID _fields_ values '''
return PrintGUIDValue(self)
def BlpCoCreateInstance():
'''
Implementation is incomplete. DO NOT USE!
'''
Session = None
bbloaderv3 = None
blpapicom2 = None
if sys.getwindowsversion()[0] < 6:
bbloaderv3 = ctypes.windll.LoadLibrary(LOADER_XP)
blpapicom2 = API_XP
else:
bbloaderv3 = ctypes.windll.LoadLibrary(LOADER_ISPACE)
blpapicom2 = API2_WIN7
rclsidguid = GUID(RCLSID)
riidguid = GUID(RIID)
rclsid = ctypes.byref(rclsidguid)
riid = ctypes.byref(riidguid)
logger.info(repr(rclsidguid) + " := " + rclsidguid.PrintGUIDValue())
logger.info(repr(riidguid) + " := " + riidguid.PrintGUIDValue())
BlpCoCreateInstance = getattr(bbloaderv3, 'BlpCoCreateInstance')
BlpCoCreateInstance.restype = ctypes.c_char_p
bbloaderv3.BlpCoCreateInstance(blpapicom2, rclsid, riid)
return Session
"""
We are trying to mimic how Bloomberg uses the data control in unregistered mode (VBA).
Below is taken from their WAPI documentation Ref# COMv3RegUnreg
' Please note that the full path must be included to the location of the
' bbloaderv3.dll file. If this path is not correct, please, replace it
' with the correct path
Private Declare Function BlpCoCreateIntance Lib "bbloaderv3.dll" _
(ByVal lpszFilePathName As String, ByRef rclsid As GUID, riid As GUID) As Object
Private Declare Function CLSIDFromString Lib "ole32.dll" (pstCLS As Long, _
clsid As GUID) As Long
Private Declare Function GetActiveObject Lib "oleaut32.dll" (lpRclsid As Long, _
pvReserved As Long, lpUnk As Long) As Long
Private Type GUID
Data1 As Long
Data2 As Integer
Data3 As Integer
Data4 (7) As Byte
End Type
Dim rclsid As GUID
Dim riid as GUID
Dim FileName As String
Private WithEvents session As Object
Private Function GuidFromStGuid(ByVal stGuid As String) As GUID
Dim rc As Long
If Left$(stGuid, 7) = "{guid {" Then
If Right$(stGuid, 2) = "}}" Then
stGuid = Mid$(stGuid, 7, 38)
End If
End If
rc = CLSIDFromString(ByVal StrPtr(stGuid), GuidFromStGuid)
End Function
' Instantiate the Bloomberg COM Data Control
Private Sub Class_Initialize()
FileName = "blpapicom2.dll"
Set session = BlpCoCreateInstance(FileName, _
GuidFromStGuid("{guid {9FDBE237-38A5-4d8c-BB9C-2EB55FB1EABE}}"), _
GuidFromStGuid("{guid {4AC751C2-BB10-4702-BB05-791D93BB461C}}"))
session.Start
End Sub
"""
Session
The ultimate goal is to get a Session object. Once that is done, sending request should be a breeze.import datetime
TODAY = datetime.datetime.today()
APIREFDATA_SVC = '//blp/refdata'
RESPONSE = 5
PARTIAL_RESPONSE = 6
def MakeRequest(security, fldList, overrideFields=None, overrideValues=None):
'''
Request test harness
'''
result = []
session.QueueEvents = True
session.Start()
session.OpenService(APIREFDATA_SVC)
service = session.GetService(APIREFDATA_SVC)
req = service.CreateRequest("ReferenceDataRequest")
#not sure if this will work
sec = req.GetElement('securities')
sec.AppendValue(security)
flds = req.GetElement('fields')
for fld in fldList:
flds.AppendValue(fld)
if overrideFields:
overridables = zip(overrideFields, overrideValues)
overrides = req.GetElement("overrides")
for overrideField, overrideValue in overridables:
override = overrides.AppendElment()
override.SetElement('fieldId', overrideField)
override.SetElement('value', overrideValue)
session.SendRequest(req)
while True:
eventObj = session.NextEvent()
if eventObj.EventType == PARTIAL_RESPONSE or eventObj.EventType == RESPONSE:
it = eventObj.CreateMessageIterator()
while it.Next():
msg = it.Message
numSecurities = msg.GetElement("securityData").NumValues
for secIndex in xrange(0, numSecurities):
security = msg.GetElement("securityData").GetValue(secIndex)
fields = security.GetElement("fieldData")
numFields = fields.NumElements
for fldIndex in xrange(0, numFields):
field = fields.GetElement(fldIndex).Value
result.append(field)
if eventObj.EventType == RESPONSE:
break
return result
def MakeHistoricalDataRequest(security, fldList, overrideFields=None, overrideValues=None, dateFrom=None, dateTo=None):
'''
Historical request test harness
'''
result = []
session.QueueEvents = True
session.Start()
session.OpenService(APIREFDATA_SVC)
service = session.GetService(APIREFDATA_SVC)
req = service.CreateRequest("HistoricalDataRequest")
sec = req.GetElement('securities')
sec.AppendValue(security)
flds = req.GetElement('fields')
for fld in fldList:
flds.AppendValue(fld)
if dateFrom:
req.Set('startDate', dateFrom)
else:
req.Set('startDate', TODAY.strftime('%Y%m%d'))
if dateTo:
req.Set('endDate', dateTo)
else:
req.Set('endDate', TODAY.strftime('%Y%m%d'))
req.Set('periodicitySelection', 'DAILY')
if overrideFields:
overridables = zip(overrideFields, overrideValues)
overrides = req.GetElement("overrides")
for overrideField, overrideValue in overridables:
override = overrides.AppendElment()
override.SetElement('fieldId', overrideField)
override.SetElement('value', overrideValue)
session.SendRequest(req)
while True:
eventObj = session.NextEvent()
if eventObj.EventType == PARTIAL_RESPONSE or eventObj.EventType == RESPONSE:
it = eventObj.CreateMessageIterator()
while it.Next():
msg = it.Message
security = msg.GetElement("securityData")
#secVal = security.GetElement("security")
field_exceptions = security.GetElement("fieldExceptions")
# process exceptions
if field_exceptions.NumValues > 0:
element = field_exceptions.GetValuesAsElement(0)
field_id = element.GetElement("fieldId")
error_info = element.GetElement("errorInfo")
error_message = error_info.GetElement("message")
logger.warn('Exception with %s with message: %s' %(field_id, error_message))
# process field data
field_data = security.GetElement("fieldData")
numFields = field_data.NumValues
for fldIndex in xrange(0, numFields):
element = field_data.GetValueAsElement(fldIndex)
# repack everything by date
subResult = []
for field in fldList:
if element.HasElement(field):
subResult.append(element.GetElement(field).Value)
result.append(subResult)
if eventObj.EventType == RESPONSE:
break
return result