Quantcast
Channel: Path
Viewing all articles
Browse latest Browse all 83

Bloomberg API Wrapper for C#

$
0
0
As a starter for the year 2015, I wanted to share the current version of my C# wrapper, which can be used to execute reference and historical data requests for Bloomberg BBCOMM server.

In the past, I have been posting all updates for corresponding VBA wrapper in separate blog posts and I think some people have been finding this procedure to be at least inconvinient. To be better prepared for those program modifications and bug fixes which will be found out in the future, I will sanctify this one blog post for all postings concerning Bloomberg API Wrapper class.

Release date : 21-Mar-2015

Client program can use this wrapper to execute reference and historical data requests for BBCOMM server. Design of the wrapper class is simple. We have abstract base class BBCOMMDataRequest, which is holding all the required constants, enumerators, BBCOMM objects and data structures. Base class is implementing most of the required functionality, such as
  • Creating and starting BBCOMM session
  • Construction of Request object
  • Sending Request object to BBCOMM server
  • Closing BBCOMM session
For all of the functionalities described above, one can easily find well-written documentations to work with from Bloomberg. However, one of the values what I am trying to add with this wrapper is the one, which is always missing in these otherwise great documentations: how to pack all requested data into data structures to be easily used by the client?

After a few design iterations and brainstorming moments, I concluded that the program is actually the same for both reference and historical data requests for the most parts. Only relevant difference is algorithm implementation for iterating BBCOMM response and packing values into result data structure. After some further woodshedding, I finally decided to create the design, in which the base class is handling all the common functionalities and derived classes (ReferenceDataRequest, HistoricalDataRequest) are handling the specific algorithm implementation for iterating and packing. Client will have an access to constructors of derived classes, in which securities, fields, overrides, dates and all the other optional parameters are given in for wrapper.

Client will create dynamically-typed 3-dimensional array, into which the resulting data will be assigned by ProcessData method of wrapper. More specifically, for

  • Reference data request : result[1, 0, 1] = 2nd security, 2nd field
  • Historical data request : result[3, 1, 2] = 4th security, 2nd observation date, 3rd field. For the third dimension of the array, index value zero will always store the observation date

All relevant examples can be found in tester program presented below along with the wrapper. To be able to run tester program, one has to create a new console project and copyPaste the program given below. Moreover, project must have reference to Bloomberglp.Blpapi.dll file. For further development and testing purposes, you can use the actual Bloomberg terminal or check out Bloomberg API Emulator.

That's all for now. Thanks for reading my blog. Mike.



Wrapper : 21-Mar-2015

using System;
using System.Collections.Generic;
using System.Linq;
using BBCOMM = Bloomberglp.Blpapi;
using BloombergAPI;
//
// CLIENT PROGRAM
namespace TesterProgram
{
classProgram
{
// data structures
static List<string> bloombergSecurityNames;
static List<string> bloombergFieldNames;
static List<string> bloombergOverrideFields;
static List<string> bloombergOverrideValues;
staticdynamic[, ,] result;
//
staticint Main()
{
try
{
Console.WriteLine("CASE 1 : create reference data request without overrides >");
Console.WriteLine();
//
// create securities
bloombergSecurityNames = new List<string>();
bloombergSecurityNames.Add("GOOG US Equity");
bloombergSecurityNames.Add("CSCO US Equity");
bloombergSecurityNames.Add("CCE US Equity");
//
// create fields
bloombergFieldNames = new List<string>();
bloombergFieldNames.Add("PX_LAST");
bloombergFieldNames.Add("BEST_EPS");
bloombergFieldNames.Add("GICS_SUB_INDUSTRY_NAME");
bloombergFieldNames.Add("EQY_OPT_AVAIL");
bloombergFieldNames.Add("LATEST_ANN_DT_ANNUAL");
bloombergFieldNames.Add("PX_ROUND_LOT_SIZE");
bloombergFieldNames.Add("MIKE_JUNIPERHILL_SHOE_SIZE");
//
// create wrapper object, retrieve and print data
BBCOMMDataRequest wrapper = new ReferenceDataRequest(bloombergSecurityNames, bloombergFieldNames);
result = wrapper.ProcessData();
Print(bloombergSecurityNames, result);
//
Console.WriteLine("CASE 2 : create reference data request with override >");
Console.WriteLine();
//
// re-create fields
bloombergFieldNames = new List<string>();
bloombergFieldNames.Add("PX_LAST");
bloombergFieldNames.Add("BEST_EPS");
//
// create override for best fiscal period
bloombergOverrideFields = new List<string>();
bloombergOverrideFields.Add("BEST_FPERIOD_OVERRIDE");
bloombergOverrideValues = new List<string>();
bloombergOverrideValues.Add("2FY");
//
// retrieve and print data
wrapper = new ReferenceDataRequest(bloombergSecurityNames, bloombergFieldNames, bloombergOverrideFields, bloombergOverrideValues);
result = wrapper.ProcessData();
Print(bloombergSecurityNames, result);
//
Console.WriteLine("CASE 3 : create historical data request for one security >");
Console.WriteLine();
//
bloombergSecurityNames = new List<string>();
bloombergSecurityNames.Add("GOOG US Equity");
//
// re-create field
bloombergFieldNames = new List<string>();
bloombergFieldNames.Add("PX_LAST");
//
// create dates
DateTime startDate = DateTime.Today.AddDays((double)-21);
DateTime endDate = DateTime.Today.AddDays((double)-1);
//
// retrieve and print data
// request time-series for Google : actual daily frequency, but only for weekdays and converted to Thai baht
wrapper = new HistoricalDataRequest(bloombergSecurityNames, bloombergFieldNames, startDate, endDate,
bloombergNonTradingDayFillOption: E_NON_TRADING_DAY_FILL_OPTION.NON_TRADING_WEEKDAYS,
bloombergOverrideCurrency: "THB");
//
result = wrapper.ProcessData();
Print(bloombergSecurityNames, result);
//
Console.WriteLine("CASE 4 : create historical data request for three securities >");
Console.WriteLine();
//
// re-create securities
bloombergSecurityNames = new List<string>();
bloombergSecurityNames.Add("GOOG US Equity");
bloombergSecurityNames.Add("CSCO US Equity");
bloombergSecurityNames.Add("CCE US Equity");
//
// re-create field
bloombergFieldNames = new List<string>();
bloombergFieldNames.Add("PX_LAST");
//
// retrieve and print data
// request three time-series : use default settings to retrieve date-consistent result data
wrapper = new HistoricalDataRequest(bloombergSecurityNames, bloombergFieldNames, startDate, endDate);
result = wrapper.ProcessData();
Print(bloombergSecurityNames, result);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
//
Console.ReadLine();
return 0;
}
// result printer
publicstaticvoid Print(List<string> securities, dynamic[, ,] data)
{
for (int i = 0; i < data.GetLength(0); i++)
{
Console.WriteLine(securities[i]);
for (int j = 0; j < data.GetLength(1); j++)
{
for (int k = 0; k < data.GetLength(2); k++)
{
Console.WriteLine(data[i, j, k]);
}
}
Console.WriteLine();
}
}
}
}
//
// WRAPPER
namespace BloombergAPI
{
// enumerators for historical data request settings
publicenum E_PRICING_OPTION { PRICING_OPTION_PRICE, PRICING_OPTION_YIELD };
publicenum E_PERIODICITY_ADJUSTMENT { ACTUAL, CALENDAR, FISCAL };
publicenum E_PERIODICITY_SELECTION { DAILY, WEEKLY, MONTHLY, QUARTERLY, SEMI_ANNUALLY, YEARLY };
publicenum E_NON_TRADING_DAY_FILL_OPTION { NON_TRADING_WEEKDAYS, ALL_CALENDAR_DAYS, ACTIVE_DAYS_ONLY };
publicenum E_NON_TRADING_DAY_FILL_METHOD { PREVIOUS_VALUE, NIL_VALUE };
//
// abstract base class for data request
publicabstractclassBBCOMMDataRequest
{
// BBCOMM names
protectedreadonly BBCOMM.Name SECURITY_DATA = new BBCOMM.Name("securityData");
protectedreadonly BBCOMM.Name FIELD_DATA = new BBCOMM.Name("fieldData");
protectedreadonly BBCOMM.Name FIELD_ID = new BBCOMM.Name("fieldId");
protectedreadonly BBCOMM.Name VALUE = new BBCOMM.Name("value");
protectedreadonly BBCOMM.Name OVERRIDES = new BBCOMM.Name("overrides");
protectedreadonly BBCOMM.Name SECURITIES = new BBCOMM.Name("securities");
protectedreadonly BBCOMM.Name FIELDS = new BBCOMM.Name("fields");
protectedreadonly BBCOMM.Name SEQUENCE_NUMBER = new BBCOMM.Name("sequenceNumber");
protectedreadonly BBCOMM.Name START_DATE = new BBCOMM.Name("startDate");
protectedreadonly BBCOMM.Name END_DATE = new BBCOMM.Name("endDate");
protectedreadonly BBCOMM.Name DATE = new BBCOMM.Name("date");
protectedreadonly BBCOMM.Name PRICING_OPTION = new BBCOMM.Name("pricingOption");
protectedreadonly BBCOMM.Name PERIODICITY_ADJUSTMENT = new BBCOMM.Name("periodicityAdjustment");
protectedreadonly BBCOMM.Name PERIODICITY_SELECTION = new BBCOMM.Name("periodicitySelection");
protectedreadonly BBCOMM.Name NON_TRADING_DAY_FILL_OPTION = new BBCOMM.Name("nonTradingDayFillOption");
protectedreadonly BBCOMM.Name NON_TRADING_DAY_FILL_METHOD = new BBCOMM.Name("nonTradingDayFillMethod");
protectedreadonly BBCOMM.Name OVERRIDE_CURRENCY = new BBCOMM.Name("currency");
//
// const strings, enumerators, etc.
protectedreadonlystring NOT_AVAILABLE = "#N/A";
protectedreadonlystring SESSION_EXCEPTION = "Session not started";
protectedreadonlystring SERVICE_EXCEPTION = "Service not opened";
protectedreadonlystring REQUEST_TYPE_REFERENCE = "ReferenceDataRequest";
protectedreadonlystring REQUEST_TYPE_HISTORICAL = "HistoricalDataRequest";
protectedreadonlystring REFERENCE_DATA_SERVICE = "//blp/refdata";
protectedreadonlystring BLOOMBERG_DATE_FORMAT = "yyyyMMdd";
protected E_PRICING_OPTION pricingOption;
protected E_PERIODICITY_ADJUSTMENT periodicityAdjustment;
protected E_PERIODICITY_SELECTION periodicitySelection;
protected E_NON_TRADING_DAY_FILL_OPTION nonTradingDayFillOption;
protected E_NON_TRADING_DAY_FILL_METHOD nonTradingDayFillMethod;
protectedstring requestType;
protectedstring startDate;
protectedstring endDate;
protectedstring overrideCurrency;
//
// wrapped BBCOMM objects
protected BBCOMM.Session session;
protected BBCOMM.Service service;
protected BBCOMM.Request request;
//
// input data structures
protected List<string> securityNames = new List<string>();
protected List<string> fieldNames = new List<string>();
protected List<string> overrideFields = new List<string>();
protected List<string> overrideValues = new List<string>();
//
// output result data structure
protecteddynamic[, ,] result;
//
publicdynamic[, ,] ProcessData()
{
Open();
CreateRequest();
SendRequest();
Close();
return result;
}
privatevoid Open()
{
// create and start bloomberg BBCOMM session
BBCOMM.SessionOptions sessionOptions = new BBCOMM.SessionOptions();
session = new BBCOMM.Session(sessionOptions);
if (!session.Start()) thrownew Exception(SESSION_EXCEPTION);
//
// get service from session object and create request by service object
if (!session.OpenService(REFERENCE_DATA_SERVICE)) thrownew Exception(SERVICE_EXCEPTION);
service = session.GetService(REFERENCE_DATA_SERVICE);
request = service.CreateRequest(requestType);
}
privatevoid CreateRequest()
{
// append securities, fields
foreach (string securityName in securityNames) request.Append(SECURITIES, securityName);
foreach (string fieldName in fieldNames) request.Append(FIELDS, fieldName);
//
// conditionally, append overrides into request object
if (overrideFields.Count > 0)
{
BBCOMM.Element requestOverrides = request.GetElement(OVERRIDES);
for (int i = 0; i < overrideFields.Count; i++)
{
BBCOMM.Element requestOverride = requestOverrides.AppendElement();
requestOverride.SetElement(FIELD_ID, overrideFields[i]);
requestOverride.SetElement(VALUE, overrideValues[i]);
}
}
// set optional parameters for historical data request
if (requestType == REQUEST_TYPE_HISTORICAL)
{
request.Set(START_DATE, startDate);
request.Set(END_DATE, endDate);
request.Set(PRICING_OPTION, pricingOption.ToString());
request.Set(PERIODICITY_ADJUSTMENT, periodicityAdjustment.ToString());
request.Set(PERIODICITY_SELECTION, periodicitySelection.ToString());
request.Set(NON_TRADING_DAY_FILL_OPTION, nonTradingDayFillOption.ToString());
request.Set(NON_TRADING_DAY_FILL_METHOD, nonTradingDayFillMethod.ToString());
if (overrideCurrency != String.Empty) request.Set(OVERRIDE_CURRENCY, overrideCurrency);
}
}
privatevoid SendRequest()
{
// send constructed request to BBCOMM server
long ID = Guid.NewGuid().GetHashCode();
session.SendRequest(request, new BBCOMM.CorrelationID(ID));
bool isProcessing = true;
//
while (isProcessing)
{
// receive data response from BBCOMM server, send
// response to be processed by sub-classed algorithm
BBCOMM.Event response = session.NextEvent();
switch (response.Type)
{
case BBCOMM.Event.EventType.PARTIAL_RESPONSE:
ProcessDataResponse(ref response);
break;
case BBCOMM.Event.EventType.RESPONSE:
ProcessDataResponse(ref response);
isProcessing = false;
break;
default:
break;
}
}
}
privatevoid Close()
{
// close BBCOMM session
if (session != null) session.Stop();
}
//
// sub-classes are providing specific algorithm implementations for
// processing and packing BBCOMM server response data into resulting data structure
protectedabstractvoid ProcessDataResponse(ref BBCOMM.Event response);
}
//
// concrete class implementation for processing reference data request
publicclassReferenceDataRequest : BBCOMMDataRequest
{
public ReferenceDataRequest(List<string> bloombergSecurityNames,
List<string> bloombergFieldNames)
{
// ctor : create reference data request without field overrides
requestType = REQUEST_TYPE_REFERENCE;
securityNames = bloombergSecurityNames;
fieldNames = bloombergFieldNames;
//
// define result data structure dimensions for reference data request
result = newdynamic[securityNames.Count, 1, fieldNames.Count];
}
public ReferenceDataRequest(List<string> bloombergSecurityNames,
List<string> bloombergFieldNames, List<string> bloombergOverrideFields,
List<string> bloombergOverrideValues)
{
// ctor : create reference data request with field overrides
requestType = REQUEST_TYPE_REFERENCE;
securityNames = bloombergSecurityNames;
fieldNames = bloombergFieldNames;
overrideFields = bloombergOverrideFields;
overrideValues = bloombergOverrideValues;
//
// define result data structure dimensions for reference data request
result = newdynamic[securityNames.Count, 1, fieldNames.Count];
}
protectedoverridevoid ProcessDataResponse(ref BBCOMM.Event response)
{
// receive response, which contains N securities and M fields
// event queue can send multiple responses for large requests
foreach (BBCOMM.Message message in response.GetMessages())
{
// extract N securities
BBCOMM.Element securities = message.GetElement(SECURITY_DATA);
int nSecurities = securities.NumValues;
//
// loop through all securities
for (int i = 0; i < nSecurities; i++)
{
// extract one security and fields for this security
BBCOMM.Element security = securities.GetValueAsElement(i);
BBCOMM.Element fields = security.GetElement(FIELD_DATA);
int sequenceNumber = security.GetElementAsInt32(SEQUENCE_NUMBER);
int nFieldNames = fieldNames.Count;
//
// loop through all M fields for this security
for (int j = 0; j < nFieldNames; j++)
{
// if the requested field has been found, pack value into result data structure
if (fields.HasElement(fieldNames[j]))
{
result[sequenceNumber, 0, j] = fields.GetElement(fieldNames[j]).GetValue();
}
// otherwise, pack NOT_AVAILABLE string into data structure
else
{
result[sequenceNumber, 0, j] = NOT_AVAILABLE;
}
}
}
}
}
}
//
// concrete class implementation for processing historical data request
publicclassHistoricalDataRequest : BBCOMMDataRequest
{
privatebool hasDimensions = false;
//
// optional parameters are configured to retrieve time-series having actual daily observations, including all weekdays,
// in the case of non-trading days the previous date value will be used.
public HistoricalDataRequest(List<string> bloombergSecurityNames, List<string> bloombergFieldNames,
DateTime bloombergStartDate, DateTime BloombergEndDate,
E_PRICING_OPTION bloombergPricingOption = E_PRICING_OPTION.PRICING_OPTION_PRICE,
E_PERIODICITY_SELECTION bloombergPeriodicitySelection = E_PERIODICITY_SELECTION.DAILY,
E_PERIODICITY_ADJUSTMENT bloombergPeriodicityAdjustment = E_PERIODICITY_ADJUSTMENT.ACTUAL,
E_NON_TRADING_DAY_FILL_OPTION bloombergNonTradingDayFillOption = E_NON_TRADING_DAY_FILL_OPTION.ALL_CALENDAR_DAYS,
E_NON_TRADING_DAY_FILL_METHOD bloombergNonTradingDayFillMethod = E_NON_TRADING_DAY_FILL_METHOD.PREVIOUS_VALUE,
string bloombergOverrideCurrency = "")
{
// ctor : create historical data request without field overrides
requestType = REQUEST_TYPE_HISTORICAL;
securityNames = bloombergSecurityNames;
fieldNames = bloombergFieldNames;
startDate = bloombergStartDate.ToString(BLOOMBERG_DATE_FORMAT);
endDate = BloombergEndDate.ToString(BLOOMBERG_DATE_FORMAT);
//
pricingOption = bloombergPricingOption;
periodicitySelection = bloombergPeriodicitySelection;
periodicityAdjustment = bloombergPeriodicityAdjustment;
nonTradingDayFillOption = bloombergNonTradingDayFillOption;
nonTradingDayFillMethod = bloombergNonTradingDayFillMethod;
overrideCurrency = bloombergOverrideCurrency;
}
public HistoricalDataRequest(List<string> bloombergSecurityNames, List<string> bloombergFieldNames,
DateTime bloombergStartDate, DateTime BloombergEndDate, List<string> bloombergOverrideFields,
List<string> bloombergOverrideValues,
E_PRICING_OPTION bloombergPricingOption = E_PRICING_OPTION.PRICING_OPTION_PRICE,
E_PERIODICITY_SELECTION bloombergPeriodicitySelection = E_PERIODICITY_SELECTION.DAILY,
E_PERIODICITY_ADJUSTMENT bloombergPeriodicityAdjustment = E_PERIODICITY_ADJUSTMENT.ACTUAL,
E_NON_TRADING_DAY_FILL_OPTION bloombergNonTradingDayFillOption = E_NON_TRADING_DAY_FILL_OPTION.ALL_CALENDAR_DAYS,
E_NON_TRADING_DAY_FILL_METHOD bloombergNonTradingDayFillMethod = E_NON_TRADING_DAY_FILL_METHOD.PREVIOUS_VALUE,
string bloombergOverrideCurrency = "")
{
// ctor : create historical data request with field overrides
requestType = REQUEST_TYPE_HISTORICAL;
securityNames = bloombergSecurityNames;
fieldNames = bloombergFieldNames;
overrideFields = bloombergOverrideFields;
overrideValues = bloombergOverrideValues;
startDate = bloombergStartDate.ToString(BLOOMBERG_DATE_FORMAT);
endDate = BloombergEndDate.ToString(BLOOMBERG_DATE_FORMAT);
//
pricingOption = bloombergPricingOption;
periodicitySelection = bloombergPeriodicitySelection;
periodicityAdjustment = bloombergPeriodicityAdjustment;
nonTradingDayFillOption = bloombergNonTradingDayFillOption;
nonTradingDayFillMethod = bloombergNonTradingDayFillMethod;
overrideCurrency = bloombergOverrideCurrency;
}
protectedoverridevoid ProcessDataResponse(ref BBCOMM.Event response)
{
// unzip and pack messages received from BBCOMM server
// receive one security per message and multiple messages per event
foreach (BBCOMM.Message message in response.GetMessages())
{
// extract security and fields
BBCOMM.Element security = message.GetElement(SECURITY_DATA);
BBCOMM.Element fields = security.GetElement(FIELD_DATA);
//
int sequenceNumber = security.GetElementAsInt32(SEQUENCE_NUMBER);
int nFieldNames = fieldNames.Count;
int nObservationDates = fields.NumValues;
//
// the exact dimension will be known only, when the response has been received from BBCOMM server
if (!hasDimensions)
{
// define result data structure dimensions for historical data request
// observation date will be stored into first field for each observation date
result = newdynamic[securityNames.Count, nObservationDates, fieldNames.Count + 1];
hasDimensions = true;
}
//
// loop through all observation dates
for (int i = 0; i < nObservationDates; i++)
{
// extract all field data for a single observation date
BBCOMM.Element observationDateFields = fields.GetValueAsElement(i);
//
// pack observation date into data structure
result[sequenceNumber, i, 0] = observationDateFields.GetElementAsDatetime(DATE);
//
// then, loop through all 'user-requested' fields for a given observation date
// and pack results data into data structure
for (int j = 0; j < nFieldNames; j++)
{
// pack field value into data structure if such value has been found
if (observationDateFields.HasElement(fieldNames[j]))
{
result[sequenceNumber, i, j + 1] = observationDateFields.GetElement(fieldNames[j]).GetValue();
}
// otherwise, pack NOT_AVAILABLE string into data structure
else
{
result[sequenceNumber, i, j + 1] = NOT_AVAILABLE;
}
}
}
}
}
}
}

Viewing all articles
Browse latest Browse all 83

Trending Articles