Reputation: 23
I am running a subscription session using BLPAPI and I am able to get real-time data but I want to isolate a particular value from the (extensive) list of fields. Then I would like to put it into a dataframe with "Ticker" and "Field" e.g.
Ticker | Last Price |
---|---|
ESM3 Index | 4138.25 |
import blpapi
session = blpapi.Session()
session.start()
subscriptions = blpapi.SubscriptionList()
subscriptions.add("ESM3 Index", "LAST_PRICE", " ",)
session.subscribe(subscriptions)
while(True):
event = session.nextEvent()
for msg in event:
print(msg)
It results in:
CID: {[ valueType=AUTOGEN classId=0 value=1 ]}
MarketDataEvents = {
MKTDATA_EVENT_TYPE = TRADE
MKTDATA_EVENT_SUBTYPE = NEW
EVT_TRADE_DATE_RT = 2023-04-07
NUM_TRADES_RT = 21535
PER_TRADE_VWAP_VOLUME_RT = 59291.000000
PER_TRADE_VWAP_TURNOVER_RT = 244947593.500000
PER_TRADE_VWAP_REALTIME = 4131.277800
LAST_ALL_SESSIONS = 4138.250000
LAST2_TRADE = 4138.250000
LAST_PRICE = 4138.250000
LAST_PRICE_TDY = 4138.250000
LAST2_DIR = -1
LAST_TICK_DIRECTION_RT = 2
LAST_TRADE = 4138.250000
SIZE_LAST_TRADE = 2
SIZE_LAST_TRADE_TDY = 2
TRADE_SIZE_ALL_SESSIONS_RT = 2
ALL_PRICE_SIZE = 2
ALL_PRICE_COND_CODE = "TSUM"
ALL_PRICE = 4138.250000
VOLUME = 59598
VOLUME_TDY = 59598
REALTIME_VOLUME_5_DAY_INTERVAL =
DELTA_AVAT_1_DAY_INTERVAL =
DELTA_AVAT_5_DAY_INTERVAL =
DELTA_AVAT_10_DAY_INTERVAL =
DELTA_AVAT_20_DAY_INTERVAL =
DELTA_AVAT_30_DAY_INTERVAL =
DELTA_AVAT_100_DAY_INTERVAL =
DELTA_AVAT_180_DAY_INTERVAL =
LAST_PRICE_COND_CODE_RT = "TSUM"
PRICE_CHANGE_1Y_NET_RT = -402.000000
PRICE_CHANGE_1Y_PCT_RT = -8.854100
LAST_CONTINUOUS_TRADE_PRICE_RT = 4138.250000
PRICE_LAST_RT = 4138.250000
LAST_TRADE_PRICE_TODAY_RT = 4138.250000
EVT_TRADE_PRICE_RT = 4138.250000
EVT_TRADE_SIZE_RT = 2
EVT_TRADE_CONDITION_CODE_RT = "TSUM"
I would like to be able to extract a specific ticker e.g. "LAST_PRICE"
I have tried using msg.getElement("LAST_PRICE") but it doesn't like this as it says the sub-element cannot be found.
Upvotes: 1
Views: 1007
Reputation: 305
Expanding on the code similar to nature as @DS_London's but incorporating your need for the data to be in a data frame. Although not the most efficient code as highlighted by my need for this post thought it could nevertheless be valuable and will update at such as time I improve on it.
import blpapi
import pandas as pd
import numpy as np
import os
# initialise bloomberg
host='localhost'
port=8194
session_options = blpapi.SessionOptions()
session_options.setServerHost(host)
session_options.setServerPort(port)
session_options.setSlowConsumerWarningHiWaterMark(0.05)
session_options.setSlowConsumerWarningLoWaterMark(0.02)
session = blpapi.Session(session_options)
if not session.start():
print("Failed to start Bloomberg session.")
session.start()
subscriptions = blpapi.SubscriptionList()
# sample selection of securities and fields
fields = ['BID','ASK','TRADE','LAST_PRICE']
subscriptions.add('VOD LN Equity', fields, "", blpapi.CorrelationId('VOD LN Equity'))
subscriptions.add('AZN LN Equity', fields, "", blpapi.CorrelationId('AZN LN Equity'))
session.subscribe(subscriptions)
ColPosDict = {'BID':0,
'ASK':1,
'TRADE':2,
'LAST_PRICE':3}
RowPosDict = {'VOD LN Equity':0,
'AZN LN Equity':1}
df_AllData = pd.DataFrame(np.nan, index=list(['VOD LN Equity' ,'AZN LN Equity']), columns= fields)
while(True):
event = session.nextEvent()
if event.eventType() == blpapi.Event.SUBSCRIPTION_DATA:
for msg in event:
security = msg.correlationIds()[0].value()
eltMsg = msg.asElement()
for fld in fields:
if eltMsg.hasElement(fld):
df_AllData.iat[RowPosDict[security], ColPosDict[fld]] = eltMsg.getElement(fld).getValueAsFloat()
os.system('cls' if os.name == 'nt' else 'clear')
print(df_AllData)
Example Output:
BID ASK TRADE LAST_PRICE
VOD LN Equity 69.72 69.76 NaN 69.72
AZN LN Equity 11200.00 11204.00 NaN 11200.00
Comment:
In this code, the DataFrame is stored in memory, so other parts of the program can access it without refetching the data. To utilise this, you could create a class that handles:
• Connecting to Bloomberg.
• Subscribing to securities.
• Retrieving data when updates come in.
Using PyQt signals (or other signal-slot mechanisms), you can trigger data retrieval when Bloomberg sends new data, rather than continuously polling. This approach avoids unnecessary data usage, especially for tickers that update infrequently (e.g., once a day).
Subscription data gets added to a “queue” from which you receive the data. Bloomberg sends YOU the data you don’t fetch it in a subscription.
Upvotes: 0
Reputation: 4261
You are not filtering the Events by type. The Bloomberg session will send a number of different types of event.
In the OP's code, the first two events will be SESSION_STATUS(=2) as the Session is opened, then a SERVICE_STATUS(=9) event as the Service is opened. After that, you get a SUBSCRIPTION_STATUS(=3) event. Finally, you start to receive the tick data, with type SUBSCRIPTION_DATA(=8): these are the ones you care about and want to handle.
Even when you get a Market Data Event, they are of different types and sub-types, and each may or may not have the data item you are looking for. eg a BID sub-type probably won't have an ASK field.
Here's a short test app which will allow you to interrogate each tick event, and decide how to handle it:
import blpapi
session = blpapi.Session()
session.start()
subscriptions = blpapi.SubscriptionList()
fields = ['BID','ASK','TRADE','LAST_PRICE','LAST_TRADE','EVT_TRADE_PRICE_RT','EVT_TRADE_SIZE_RT']
subscriptions.add('SFRM3 Index', fields)
session.subscribe(subscriptions)
while(True):
event = session.nextEvent()
print("Event type:",event.eventType())
if event.eventType() == blpapi.Event.SUBSCRIPTION_DATA:
for msg in event:
print(" Message type:",msg.messageType())
eltMsg = msg.asElement();
msgType = eltMsg.getElement('MKTDATA_EVENT_TYPE').getValueAsString();
msgSubType = eltMsg.getElement('MKTDATA_EVENT_SUBTYPE').getValueAsString();
print(" ",msgType,msgSubType)
for fld in fields:
if eltMsg.hasElement(fld):
print(" ",fld,eltMsg.getElement(fld).getValueAsFloat())
else:
for msg in event:
print(" Message type:",msg.messageType())
You may see output something like this:
Event type: 2
Message type: SessionConnectionUp
Event type: 2
Message type: SessionStarted
Event type: 9
Message type: ServiceOpened
Event type: 3
Message type: SubscriptionStarted
Message type: SubscriptionStreamsActivated
Event type: 8
Message type: MarketDataEvents
SUMMARY INITPAINT
BID 95.06
ASK 95.065
Event type: 8
Message type: MarketDataEvents
SUMMARY INITPAINT
BID 95.06
ASK 95.065
LAST_PRICE 95.06
LAST_TRADE 95.06
Event type: 8
Message type: MarketDataEvents
TRADE NEW
EVT_TRADE_PRICE_RT 95.06
EVT_TRADE_SIZE_RT 2.0
Message type: MarketDataEvents
TRADE NEW
EVT_TRADE_PRICE_RT 95.06
EVT_TRADE_SIZE_RT 3.0
Message type: MarketDataEvents
TRADE NEW
EVT_TRADE_PRICE_RT 95.06
EVT_TRADE_SIZE_RT 1.0
Event type: 8
Message type: MarketDataEvents
TRADE NEW
EVT_TRADE_PRICE_RT 95.06
EVT_TRADE_SIZE_RT 2.0
Event type: 8
Message type: MarketDataEvents
QUOTE ASK
ASK 95.065
Event type: 8
Message type: MarketDataEvents
QUOTE ASK
ASK 95.065
An important thing to note is that a single Event may have more than one Message, and some Messages (like INITPAINT) may get repeated.
Upvotes: 1