Wilmott Forums - Python Bloomberg FTW

来源:百度文库 编辑:神马文学网 时间:2024/04/24 22:10:11


Forum Navigation: Select WHO'S ON: 01:22 AM General Forum Technical Forum Economics Forum Numerical Methods Forum Trading Forum The Quantitative Finance FAQs Proje... Student Forum Book And Research Paper Forum Software Forum Careers Forum Jobs Board Events Board Brainteaser Forum Off Topic Forum and Website Bugs and Suggesti...

new topic
search
bookshop
news
help
file share
audio visual
articles
blogs
wiki
forums
home
login

FORUMS >Software Forum
Topic Title: Python + Bloomberg FTW
Created On Tue Nov 29, 05 08:34 AM Topic View: Branch View Threaded (All Messages) Threaded (Single Messages) Linear

Pages: [12>>Next ]


afoster
Senior Member

Posts: 292
Joined: Jul 2002
Tue Nov 29, 05 08:34 AM

Just a little thread for any python n00bs out there to show you how easy it is to use the Bloomberg COM API.....
Python, have that warm fuzzy VB feeling every day.....but with added uberness!
import win32com.client
# Get Dispatch interface from blpdatax.dll
w = win32com.client.Dispatch('Bloomberg.Data.1')
# Use BlpSubscribe method to request price
px_last =  w.BLPSubscribe('AAL LN Equity','PX_LAST')
print px_last
-------------------------
There are No Stupid Questions. But there a LOT of Inquisitive Idiots
 Reply    Quote    Top    Bottom
Tue Nov 29, 05 12:02 PM

Nice !
Do you have any other examples you can share ?
 Reply    Quote    Top    Bottom

afoster
Senior Member

Posts: 292
Joined: Jul 2002
Tue Nov 29, 05 03:01 PM

Sure....the other everyday task most of us have to deal with is connecting to databases.
Once again, python makes this very simple - even more so then ADO imho.
This example connects/queries apostgres database, using theeGenix mx.ODBC library.
# import eGenix mx.ODBC library. Example also works with the pyPgSQL library
import mx.ODBC
import mx.ODBC.Windows
# connect to the postgres database and get a cursor object
db = mx.ODBC.Windows.Connect('maya_ds',user='panda',password='panda' )
c = db.cursor()
# execute a simple select query and print the recordset (of tuples)
c.execute('SELECT * FROM testtypes')
rs = c.fetchall()
for r in rs:
print r
# clean up
c.close()
db.close()
-------------------------
There are No Stupid Questions. But there a LOT of Inquisitive Idiots
Edited: Tue Nov 29, 05 at 03:12 PM by afoster
 Reply    Quote    Top    Bottom
Sat Dec 31, 05 12:03 PM

I was trying to figure out how to have python work with callbacks. From looking at various VBA examples I get as far as the code below but this doesn't work asynchronously (the bid/ask is printed out at the subscribe, not in the EventHandler).
Could someone with a little more experience help me get the Asynchronous subscriptions working ?
import win32com.client
import pythoncom
from win32com.client import constants as const
class EventHandler:
def Data(self, security, cookie, fields, data, status):
print "%s (%d): %s" % ( security, cookie, fields )
blp = win32com.client.DispatchWithEvents("Bloomberg.Data.1", EventHandler)
blp.AutoRelease = False
blp.SubscriptionMode = const.BySecurity
cookie = 1
for security in ['USDJPY Curncy', 'USDGBP Curncy', 'USDEUR Curncy']:
print blp.Subscribe(security, cookie, ['BID', 'ASK'])
cookie = cookie + 1
blp.Flush()
print pythoncom.PumpMessages()
Edited: Mon Feb 20, 06 at 11:53 AM by jfl
 Reply    Quote    Top    Bottom

afoster
Senior Member

Posts: 292
Joined: Jul 2002
Wed Mar 15, 06 12:37 PM

After much delving I have finally figured out how to get Asynchronous Data out of Bloomberg with python (2.4).
NB: You need to run makepy and create the python interface file for Bloomberg Data Type Library.
from win32com.client import DispatchWithEvents
from pythoncom import PumpWaitingMessages, Empty, Missing
from time import time
class BBCommEvent:
def OnData(self, Security, cookie, Fields, Data, Status):
print 'OnData: ' + `Data`
def OnStatus(self, Status, SubStatus, StatusDescription):
print 'OnStatus'
class TestAsync:
def __init__(self):
clsid = '{F2303261-4969-11D1-B305-00805F815CBF}'
progid = 'Bloomberg.Data.1'
print 'connecting to BBComm'
blp = DispatchWithEvents(clsid, BBCommEvent)
blp.AutoRelease = False
blp.Subscribe('EUR Curncy', 1, 'LAST_PRICE', Results = Empty)
blp.Flush()
end_time = time() + 5
while 1:
PumpWaitingMessages()
if end_time < time():
print 'timed out'
break
if __name__ == "__main__":
ta = TestAsync()
-------------------------
There are No Stupid Questions. But there a LOT of Inquisitive Idiots
 Reply    Quote    Top    Bottom

afoster
Senior Member

Posts: 292
Joined: Jul 2002
Wed Mar 15, 06 01:14 PM

Also note, that GetHistoricalData can be called asynchronously like this:
blp.GetHistoricalData('EUR Curncy', 1, 'PX_LAST', datetime(2006, 1, 1), datetime(2006, 3, 1), Results = Empty)
-------------------------
There are No Stupid Questions. But there a LOT of Inquisitive Idiots
 Reply    Quote    Top    Bottom

rogermc
Member

Posts: 26
Joined: Jul 2002
Fri Mar 24, 06 11:09 AM

These are great examples .. we've been using the asynchronous event handlers through VBA to double check fills from brokers, but this implementation is so much cleaner. Two things I'd like to ask:
1. After calling the Flush event is it possible to capture the output (eg your second example using GetHistoricalData returns a list of lists) .. I played around with the class wrapper to have the OnData method return rather than print the data, but no luck
2. How do you pass dates to methods that requires a date as a paramenter? We use a rather flash object oriented database which stores timeseries data and has a COM interface. Your code was able to expose the relevant objects to Python, but I had problems trying to call methods on instances of objects that requires a date. (kept return a message saying requires integer).
Does bloomberg put a wrapper around the datetime object when passing a date into the GetHistoricalData method? I tried passing a datetime instance as the date argument but this wouldn't work. Is there something similar to MATLAB, which has a rather beaut 'get' function which also must have a wrapper of some sort as I could get the method on an instance of the object to return the correct result in that environment
many thanks for any assistance
 Reply    Quote    Top    Bottom

afoster
Senior Member

Posts: 292
Joined: Jul 2002
Fri Mar 24, 06 01:30 PM

Quote
1. After calling the Flush event is it possible to capture the output (eg your second example using GetHistoricalData returns a list of lists) .. I played around with the class wrapper to have the OnData method return rather than print the data, but no luck
If I interpret this question correctly, you wish to use an asynchronous call, but correlate the function return using the cookie.
What you need to understand here is how DispatchWithEvents works:
blp = DispatchWithEvents(clsid, BBCommEvent)
On each OnData call, the Bloomberg blp object creates a new instance of the class BBCommEvent, it then binds the function (in this case OnData) to itself. The implication is that any attributes that you bind to the blp object are now accessable in the OnData function, as attributes of self
For example if in the TestAsync.__init__ you make the following assignment; self.blp.CookieToTickerMap[cookie] = Ticker, then when the OnData event fires, you can now do ticker = self.CookieToTickerMap[cookie]
I have some nice code demonstrating this if you like.
Quote
2. How do you pass dates to methods that requires a date as a paramenter? We use a rather flash object oriented database which stores timeseries data and has a COM interface. Your code was able to expose the relevant objects to Python, but I had problems trying to call methods on instances of objects that requires a date. (kept return a message saying requires integer).
The win32com module converts seemlessly between COM Date type and the python built-in datetime. If you are calling a COM object function that requires a date, you simply construct a datetime instance and pass that, and if the COM object returns a COM Date type, it will be returned as a python built-in datetime object instance.
-------------------------
There are No Stupid Questions. But there a LOT of Inquisitive Idiots
Edited: Fri Mar 24, 06 at 01:32 PM by afoster
 Reply    Quote    Top    Bottom
Sat Mar 25, 06 03:54 AM

I have this without the makepy and the explicit classid; also with a more generic wrapper for the callbacks. I made assumptions about the fields being returned in the same order they were requested. Is there a good api method to translate field numbers to field names - I wrote code to find BBFIELDS.TBL in the registry and then parse it - but this more ugly than I think it should be. This code async-subscribes to a set of securities and return when they have all beenreturned or when something times out. This is quite easy to adapt to a real-time subscrption (ActivateRealtime).
Now, how about COM in Ruby ...
import win32api
import pythoncom
import win32com.client
from win32com.client import constants as const
import time
class EventHandler:
def OnData(self, security, cookie, fields, data, status):
self.mytickcount[cookie] = self.mytickcount[cookie] + 1
processor = self.mymapper[cookie]
# Assume that the order the fields are returned is the order in which we
# asked for them. Can we assume this ?
dict = {}
for i in range(len(self.myfieldnames)):
dict[self.myfieldnames[i]] = data[i]
processor.OnData(security, dict)
def OnStatus(self, status, substatus, description):
processor = self.mymapper[cookie]
processor.OnStatus(status, description)
class AsyncBloomberg:
def __init__(self, securities, fieldnames, processor):
self.blp = win32com.client.DispatchWithEvents("Bloomberg.Data.1", EventHandler)
self.blp.SubscriptionMode = const.BySecurity
self.blp.AutoRelease = False
self.blp.ActivateRealtime = False
self.blp.mymapper = {}
self.blp.mytickcount = {}
self.blp.myfieldnames = fieldnames
cookie = 1
for s in securities:
self.blp.Subscribe(s, cookie, fieldnames, Results = pythoncom.Empty)
self.blp.mymapper[cookie] = processor
self.blp.mytickcount[cookie] = 0
cookie = cookie + 1
self.blp.Flush()
# overhead + time for each security ...
eot = 5 + len(securities) + time.time()
done = False
while not done:
pythoncom.PumpWaitingMessages()
if eot < time.time():
done = True
else:
done = True
for i in self.blp.mytickcount.keys():
if self.blp.mytickcount[i] == 0:
done = False
class MyProcessor:
def __init__(self):
print "%s" % self.__class__.__name__
def OnData(self, ticker, fields):
print ticker, fields
def OnStatus(self, status, description):
print status
if __name__ == "__main__":
sec_names = ['USDJPY Curncy', 'USDGBP Curncy', 'USDEUR Curncy']
sec_fields = ['BID', 'ASK']
processor = MyProcessor()
bb = AsyncBloomberg(sec_names, sec_fields, processor)
Edited: Sat Mar 25, 06 at 07:07 AM by jfl
 Reply    Quote    Top    Bottom
Thu Mar 08, 07 11:38 PM

You don't have to use win32com. You can use the ctypes module (it's a builtin as of Python 2.5) to communicate directly with Bloomberg's DLL. This means you don't need to run makepy on the Bloomberg data service. It might be faster, and it might serve as a guide to using the API from Linux (I haven't tested either proposition).
On the downside, it is more complex than using the COM server. But a lightweight query is not too bad:
# Use ctypes to fetch data using Bloomberg's C API
import ctypes
import time
bloomberg=ctypes.windll.bbapi
connection = bloomberg.bb_connect( 8194 )
lastPriceFieldNumber = 0x0001
typeIsTicker = 730
bbId = bloomberg.bb_getdatax(connection, 1,
ctypes.pointer(ctypes.c_int(typeIsTicker)),
ctypes.c_char_p('IBM US Equity'), 1,
ctypes.pointer(ctypes.c_int(lastPriceFieldNumber)),
0, None, None)
bbSvcCode = 0
bufferLength = 1000  # Really ought to use bb_sizeof_nextmsg()
bbBuffer=ctypes.create_string_buffer('\000'*bufferLength )
while bbSvcCode==0 or bbSvcCode==9:
bbSvcCode = bloomberg.bb_rcvdata(connection, bbBuffer, bufferLength)
time.sleep(0.5)
if bbSvcCode==37:
textLoc = ctypes.addressof(bbBuffer) + 5*4 # based on bb_msg_fieldsx_t, offset five 4-byte ints
text = ctypes.cast(textLoc, ctypes.POINTER(ctypes.c_char_p))
print text.contents.value
 Reply    Quote    Top    Bottom
Thu Mar 08, 07 11:49 PM

For what it's worth, having tried various means of connecting Python to PostgreSQL databases (ODBC, PyPgSQL, PyGreSQL), I ultimately settled on psycopg2. It's been very fast and stable. Caveat: you have to google for the pre-built Windows binaries if you don't want to build them yourself.
 Reply    Quote    Top    Bottom
Tue Dec 04, 07 09:06 AM

Hi afoster,
thanks for your reply on my other thread.
As mentioned in the other thread I am new to using python with bloomberg so I try to get ian insight by recreating the examples mentioned on that topic.
Most of the example work just fine, however, I cannot get the GetHistoricalData to work. I get an error massage that the module is not callable . Could you help me out?
Thank you very much
 Reply    Quote    Top    Bottom
Tue Dec 04, 07 10:28 AM

GetHistoricalData is a bloomberg api call.
Do you have the:
blp = win32com.client.Dispatch('Bloomberg.Data.1')
or
blp = win32com.client.DispatchWithEvents("Bloomberg.Data.1", EventHandler)
(with a defined EventHandler)
before the
blp. GetHistoricalData(...) call ?
it might be easier if you post that section of code which initialized the blp com object and then calls GetHistoricalData(...)
 Reply    Quote    Top    Bottom
Tue Dec 04, 07 03:58 PM

Hi jfl
thanks for your reply.
I wanted to use the same win32.com.client.Dispatch('Bloomberg.Data.1')
but i do not mind using the otherone. I have not quite figured out where the difference lies....
it looks something like this at the moment...
import win32com.client
import datetime
blp = win32com.client.Dispatch('Bloomberg.Data.1')
blp.GetHistoricalData('EUR Curncy', 1, 'LAST_PRICE', datetime(2006, 1, 1), datetime(2006, 3, 1), Results = Empty)
But i still get the error message:
module object is not callable
 Reply    Quote    Top    Bottom

afoster
Senior Member

Posts: 292
Joined: Jul 2002
Tue Dec 04, 07 04:19 PM

Bacause you are using the component in asynchronous mode, but you haven't supplied a callback handler for the COM component.
blp = win32com.client.DispatchWithEvents("Bloomberg.Data.1", EventHandler)
-------------------------
There are No Stupid Questions. But there a LOT of Inquisitive Idiots
Edited: Tue Dec 04, 07 at 04:20 PM by afoster
 Reply    Quote    Top    Bottom
Tue Dec 04, 07 04:28 PM

Edited: Tue Dec 04, 07 at 04:29 PM by papperlapub
 Reply    Quote    Top    Bottom
Tue Dec 04, 07 04:28 PM

I am sorry if I am persistent, but I have also tried the code with
blp = win32com.client.DispatchWithEvents("Bloomberg.Data.1", EventHandler)
and then I get an error message
NameError: name 'EventHandler' is not defined
I looked at all the examples and I just cannot figure out what is wrong.
srry
 Reply    Quote    Top    Bottom

afoster
Senior Member

Posts: 292
Joined: Jul 2002
Tue Dec 04, 07 04:33 PM

Ok here is my one
BLP_CLSID = '{F2303261-4969-11D1-B305-00805F815CBF}'
BLP_PROGID = 'Bloomberg.Data.1'
class BlpEvent:
"""
BlpEvent is a callback function used by the COM events (message dispatch) mechanism
"""
def OnData(self, Security, cookie, Fields, Data, Status):
# pop handler from self.pending and call with data
#expiry_timestamp, handler = self.pending.pop(cookie)
try:
expiry_timestamp, handler = self.pending.pop(cookie)
handler(cookie, Data)
except:
import sys
log.error('unhandled exception: ' % (sys.exc_type, sys.exc_value))
class Broker:
"""
Blp data request broker. Tracks and controls the number of requests sent
to the Blp servers. Controls individual request lifecylce (timeouts) as
well as timeouts for the entire request queue.
"""
def __init__(self):
self.pending_limit  = 20        # max tickets that can be concurently serviced
self.batch_timeout  = 10800     # batch processing timeout
self.ticket_timeout = 300        # ticket timeout (secs)
self.ticket_uid     = 0
self.queued     = {}            # tickets waiting to be serviced
self.pending    = {}            # tickets currently being serviced
# construct Blp ActiveX Control and set property defaults
self.blp = DispatchWithEvents(BLP_CLSID, BlpEvent)
self.blp.Periodicity            = constants.bbDaily
self.blp.DisplayNonTradingDays  = constants.BloombergHandles
self.blp.NonTradingDayValue     = constants.Omit
self.blp.SubscriptionMode       = constants.ByRequest
self.blp.DataOnlyInEvent        = False
self.blp.AutoRelease            = False
# add pending referenceto blp instance object
# used to dispatch BlpEvents to Blp Handler instance objects (derived from BlpBaseHandler
self.blp.pending = self.pending
def SetBlpProperty(self, attr, value):
setattr(self.blp, attr, getattr(constants, value))
def request(self, method, kwargs, handler):
"""
The Bloomberg ActiveX Control supports several asynchonous methods. The most useful
are outlined below;
1. blp.GetHistoricalData(Security=[''], Fields=[''], FromDate=from_dt,
ToDate=to_dt, Result=[])
2. blp.Subscribe(Security=[''], Fields=[''], Result=[])
request arguements:
method: string identifier for the Blp method.
kwargs: keyword arguements for method object
handler: callback function of type func(arg1), to receive data back from BlpEvent.OnData method call
These are used to create an anonymous function (lambda) which is dispatched by
calling _dispatch_requests.
eg. func = lambda instance: getattr(instance, method)(**kwargs)    # create anonymous function
func(self.blp)                                                 # dispatch to blp
"""
self.ticket_uid += 1
kwargs.update({'cookie': self.ticket_uid, 'Results':Empty})
self.queued[self.ticket_uid] = (lambda instance: getattr(instance, method)( **kwargs), handler)
return self.ticket_uid
def flush(self):
start_time = time()
end_time   = start_time + self.batch_timeout   # timeout after 1h (default)
log.info('requesting %i item(s)' % self.size())
while self.size() > 0:
PumpWaitingMessages()       # get Blp events waiting
try:
self._expire_timed_out()
self._dispatch_requests()
except com_error, value:
log.error('COM Error ' % (com_error, value))  # some COM weirdness
pass
if time() > end_time:
print 'timed out'
log.warning('process timed out after %.2f seconds' % (end_time - start_time))
log.info('there are %i item(s) not processed' % size())
break
log.info('process completed in %.2f seconds' % (time() - start_time))
def size(self): return len(self.pending) + len(self.queued)
def _pending_full(self): return not (len(self.pending) < self.pending_limit and len(self.queued) > 0)
def _dispatch_requests(self):
while not self._pending_full():
# pop ticket from self.queued and append to self.pending with expiry timestamp
ticket_uid, (method, handler) = self.queued.popitem()
expiry_timestamp = time() + self.ticket_timeout
self.pending[ticket_uid] = (expiry_timestamp, handler)
method(self.blp)    # make Blp data request
if self._pending_full():    # was not full before, and is now.
self.blp.Flush()        # release requests queued by the Blp ActiveX Control
break
def _expire_timed_out(self):
# remove all expired tickets from self.pending
for ticket_uid in self.pending.keys():
if time() > self.pending[ticket_uid][0]: del self.pending[ticket_uid]
-------------------------
There are No Stupid Questions. But there a LOT of Inquisitive Idiots
 Reply    Quote    Top    Bottom
Tue Dec 04, 07 04:46 PM

Thank you very much
this helped a lot
Best Regards
 Reply    Quote    Top    Bottom
Tue Feb 26, 08 08:46 AM

about module non callable: it is about datetime.
you should either import by:
from datetime import datetime
OR you do:
import datetime
#but then you use it so:
datetime.datetime(2006, 01, 01)
 Reply    Quote    Top    Bottom
Pages: [12>>Next ]

FORUMS >Software Forum
Forum Navigation: Select WHO'S ON: 01:22 AM General Forum Technical Forum Economics Forum Numerical Methods Forum Trading Forum The Quantitative Finance FAQs Proje... Student Forum Book And Research Paper Forum Software Forum Careers Forum Jobs Board Events Board Brainteaser Forum Off Topic Forum and Website Bugs and Suggesti...
 
FuseTalk 4.01 © 1999-2010FuseTalk Inc.