001 package org.findata.blpwrapper;
002
003 import com.bloomberglp.blpapi.*;
004
005 import java.util.Arrays;
006 import java.util.ArrayList;
007 import java.util.HashSet;
008 import java.util.regex.Pattern;
009
010 import java.util.logging.Level;
011 import java.util.logging.Logger;
012 import java.util.logging.FileHandler;
013 import java.util.logging.SimpleFormatter;
014
015 public class Connection {
016 private SessionOptions session_options;
017 private Session session;
018
019 private Logger logger;
020
021 public ArrayList response_cache;
022
023 // Session options defaults.
024 private String server_host = "localhost";
025 private int server_port = 8194;
026
027 private String refdata_service_name = "//blp/refdata";
028 private boolean refdata_service_open = false;
029 private String refdata_request_name = "ReferenceDataRequest";
030 private String histdata_request_name = "HistoricalDataRequest";
031 private String intraday_tick_request_name = "IntradayTickRequest";
032 private String intraday_bar_request_name = "IntradayBarRequest";
033
034 private String apifields_service_name = "//blp/apiflds";
035 private boolean apifields_service_open = false;
036
037 private boolean throw_invalid_ticker_error = true;
038
039 public static final int REFERENCE_DATA_RESULT = 1;
040 public static final int BULK_DATA_RESULT = 2;
041 public static final int HISTORICAL_DATA_RESULT = 3;
042 public static final int FIELD_INFO_RESULT = 4;
043 public static final int INTRADAY_TICK_RESULT = 5;
044 public static final int INTRADAY_BAR_RESULT = 6;
045
046 public static final int MB = 1048576;
047
048 public static final String DATETIME_OPTION_NAMES[] = {
049 "startDateTime",
050 "endDateTime"
051 };
052
053 public static final String BOOLEAN_OPTION_NAMES[] = {
054 "useUTCTime",
055 "returnRelativeDate",
056 "adjustmentNormal",
057 "adjustmentAbnormal",
058 "adjustmentSplit",
059 "adjustmentFollowDPDF",
060 "returnEids",
061 "includeConditionCodes",
062 "includeNonPlottableEvents",
063 "includeExchangeCodes"
064 };
065
066 public Connection() throws java.io.IOException, java.lang.InterruptedException, WrapperException {
067 this(Level.FINEST);
068 }
069
070 public Connection(Level logLevel) throws java.io.IOException, java.lang.InterruptedException, WrapperException {
071 response_cache = new ArrayList();
072 setupLogger(logLevel);
073 connect();
074 }
075
076 public Connection(Level logLevel, String serverHost, int serverPort) throws java.io.IOException, java.lang.InterruptedException, WrapperException {
077 server_host = serverHost;
078 server_port = serverPort;
079 response_cache = new ArrayList();
080 setupLogger(logLevel);
081 connect();
082 }
083
084 private void setupLogger(Level log_level) throws java.io.IOException {
085 logger = Logger.getLogger("org.findata.blpwrapper");
086 logger.setUseParentHandlers(false);
087 logger.setLevel(log_level);
088
089 if (logger.getHandlers().length == 0) {
090 FileHandler handler = new FileHandler("%h/org.findata.blpwrapper.%g.log", 100*MB, 100, true);
091 handler.setFormatter(new SimpleFormatter());
092 logger.addHandler(handler);
093 }
094 }
095
096 private void connect() throws java.io.IOException, java.lang.InterruptedException, WrapperException {
097 setupSessionOptions();
098 setupSession();
099 processEventLoop();
100 }
101
102 public void close() throws java.io.IOException, java.lang.InterruptedException {
103 session.stop();
104 }
105
106 private void setupSessionOptions() {
107 session_options = new SessionOptions();
108 session_options.setServerHost(server_host);
109 session_options.setServerPort(server_port);
110 }
111
112 private void setupSession() throws java.io.IOException, java.lang.InterruptedException {
113 session = new Session(session_options);
114 session.start();
115 }
116
117 public void setThrowInvalidTickerError(boolean arg) {
118 throw_invalid_ticker_error = arg;
119 }
120
121 public CorrelationID nextCorrelationID(int result_type, String[] securities, String[] fields) throws Exception {
122 DataResult result;
123 switch(result_type) {
124 case REFERENCE_DATA_RESULT: result = new ReferenceDataResult(securities, fields); break;
125 case BULK_DATA_RESULT: result = new BulkDataResult(securities, fields); break;
126 case HISTORICAL_DATA_RESULT: result = new HistoricalDataResult(securities, fields); break;
127 case FIELD_INFO_RESULT: result = new FieldInfoResult(securities); break;
128 case INTRADAY_TICK_RESULT: result = new IntradayTickDataResult(securities, fields); break;
129 case INTRADAY_BAR_RESULT: result = new IntradayBarDataResult(securities, fields); break;
130 default: throw new WrapperException("unknown result_type " + result_type);
131 }
132 if (response_cache.add(result)) {
133 return(new CorrelationID(response_cache.size()-1));
134 } else {
135 throw new Exception("unable to add to response_cache");
136 }
137 }
138
139 private Service getRefDataService() throws java.io.IOException, java.lang.InterruptedException {
140 if (!refdata_service_open) {
141 refdata_service_open = session.openService(refdata_service_name);
142 }
143 return(session.getService(refdata_service_name));
144 }
145
146 private Service getApiDataService() throws java.io.IOException, java.lang.InterruptedException {
147 if (!apifields_service_open) {
148 apifields_service_open = session.openService(apifields_service_name);
149 }
150 return(session.getService(apifields_service_name));
151 }
152
153 private CorrelationID sendApiDataRequest(int result_type, String[] field_identifiers) throws Exception {
154 Service service = getApiDataService();
155 Request request = service.createRequest("FieldInfoRequest");
156
157 for (int i = 0; i < field_identifiers.length; i++) {
158 request.append("id", field_identifiers[i]);
159 }
160
161 String[] mock_fields = {""};
162 CorrelationID correlation_id = nextCorrelationID(result_type, field_identifiers, mock_fields);
163 session.sendRequest(request, correlation_id);
164 return(correlation_id);
165 }
166
167 private CorrelationID sendRefDataRequest(int result_type, String request_name, String[] securities, String[] fields, String[] override_fields, String[] override_values, String[] option_names, String[] option_values) throws Exception {
168 String[] event_types = new String[0];
169 return(sendRefDataRequest(result_type, request_name, securities, fields, override_fields, override_values, option_names, option_values, event_types));
170 }
171
172 private CorrelationID sendRefDataRequest(int result_type, String request_name, String[] securities, String[] fields, String[] override_fields, String[] override_values, String[] option_names, String[] option_values, String[] event_types) throws Exception {
173 Service service = getRefDataService();
174 Request request = service.createRequest(request_name);
175
176 if (request.hasElement("securities")) {
177 Element securities_element = request.getElement("securities");
178 for (int i = 0; i < securities.length; i++) {
179 securities_element.appendValue(securities[i]);
180 }
181 }
182
183 if (request.hasElement("fields")) {
184 Element fields_element = request.getElement("fields");
185 for (int i = 0; i < fields.length; i++) {
186 fields_element.appendValue(fields[i]);
187 }
188 }
189
190 if (override_fields.length > 0) {
191 Element override_values_element = request.getElement("overrides");
192 for (int i = 0; i < override_fields.length; i++) {
193 if (!override_fields[i].equals("IGNORE")) {
194 Element override = override_values_element.appendElement();
195 override.setElement("fieldId", override_fields[i]);
196 override.setElement("value", override_values[i]);
197 logger.fine("override " + override_fields[i] + " set to " + override_values[i]);
198 }
199 }
200 }
201
202 if (event_types.length > 0) {
203 for (int i = 0; i < event_types.length; i++) {
204 request.append("eventTypes", event_types[i]);
205 }
206 }
207
208 for (int i = 0; i < option_names.length; i++) {
209 String n = option_names[i];
210
211 HashSet datetime_option_names = new HashSet(Arrays.asList(DATETIME_OPTION_NAMES));
212 HashSet boolean_option_names = new HashSet(Arrays.asList(BOOLEAN_OPTION_NAMES));
213
214 if (datetime_option_names.contains(n)) {
215 Pattern p = Pattern.compile(":|-|\\.|\\s"); // Expecting e.g. 2010-01-01 09:00:00.000
216 String[] time_parts = p.split(option_values[i]);
217
218 int year = new Integer(time_parts[0]).intValue();
219 int month = new Integer(time_parts[1]).intValue();
220 int day_of_month = new Integer(time_parts[2]).intValue();
221 int hour = new Integer(time_parts[3]).intValue();
222 int minute = new Integer(time_parts[4]).intValue();
223 int second = new Integer(time_parts[5]).intValue();
224 int millisecond = new Integer(time_parts[6]).intValue();
225
226 Datetime d = new Datetime(year, month, day_of_month, hour, minute, second, millisecond);
227 logger.fine("option " + n + " set to Datetime value " + d + ".");
228 request.set(n, d);
229 } else if (boolean_option_names.contains(n)) {
230 boolean option_value;
231
232 String true_value_elements[] = {"true", "TRUE", "True", "t", "T"};
233 HashSet true_values = new HashSet(Arrays.asList(true_value_elements));
234
235 String false_value_elements[] = {"false", "FALSE", "False", "f", "F"};
236 HashSet false_values = new HashSet(Arrays.asList(false_value_elements));
237
238 if (true_values.contains(option_values[i])) {
239 option_value = true;
240 } else if (false_values.contains(option_values[i])) {
241 option_value = false;
242 } else {
243 throw new WrapperException("Unable to convert this string '" + option_values[i] + "' to a boolean.");
244 }
245
246 logger.fine("option " + n + " set to boolean value " + option_value + " original string '" + option_values[i] + "'.");
247 request.set(n, option_value);
248 } else {
249 logger.fine("option " + n + " set to string value '" + option_values[i] + "'.");
250 request.set(n, option_values[i]);
251 }
252 }
253
254 CorrelationID correlation_id = nextCorrelationID(result_type, securities, fields);
255 session.sendRequest(request, correlation_id);
256 return(correlation_id);
257 }
258
259 private void processEventLoop() throws java.lang.InterruptedException, WrapperException {
260 processEventLoop(0);
261 }
262
263 private void processEventLoop(int result_type) throws java.lang.InterruptedException, WrapperException {
264 boolean await_response = (result_type > 0);
265 boolean cont = true;
266 while (cont) {
267 Event event = session.nextEvent();
268
269 switch (event.eventType().intValue()) {
270 case Event.EventType.Constants.SESSION_STATUS: processSessionStatusEvent(event); cont=await_response; break;
271 case Event.EventType.Constants.SERVICE_STATUS: processServiceStatusEvent(event); cont=await_response; break;
272 case Event.EventType.Constants.RESPONSE: processResponseEvent(result_type, event); cont=false; break;
273 case Event.EventType.Constants.PARTIAL_RESPONSE: processResponseEvent(result_type, event); break;
274 default: throw new WrapperException(event.eventType());
275 }
276 }
277 }
278
279 private void processSessionStatusEvent(Event event) throws WrapperException {
280 MessageIterator msgIter = event.messageIterator();
281
282 while(msgIter.hasNext()) {
283 Message message = msgIter.next();
284 Element response = message.asElement();
285
286 if (response.name().equals("SessionStarted")) {
287 logger.info("Session Started");
288 } else if (response.name().equals("SessionStartupFailure")) {
289 logger.warning("" + response);
290 Element reason = response.getElement(0);
291 throw new WrapperException("Session not started because: " + reason.getElementAsString("description"));
292 } else {
293 logger.warning("" + response);
294 throw new WrapperException("Session not started. See logs. Please report this to blpwrapper maintainer.");
295 }
296 }
297 }
298
299 private void processServiceStatusEvent(Event event) throws WrapperException {
300 MessageIterator msgIter = event.messageIterator();
301
302 while(msgIter.hasNext()) {
303 Message message = msgIter.next();
304 Element response = message.asElement();
305
306 if (response.name().equals("ServiceOpened")) {
307 logger.info("Service Started");
308 } else {
309 logger.warning("" + response);
310 throw new WrapperException("Service not started. See logs. Please report this to blpwrapper maintainer.");
311 }
312 }
313 }
314
315 private void processResponseEvent(int result_type, Event event) throws WrapperException {
316 MessageIterator msgIter = event.messageIterator();
317
318 while (msgIter.hasNext()) {
319 Message message = msgIter.next();
320 int response_id = (int)message.correlationID().value();
321 logger.fine("Response id " + response_id);
322 DataResult result;
323
324 switch(result_type) {
325 case REFERENCE_DATA_RESULT: result = (ReferenceDataResult)response_cache.get(response_id); break;
326 case BULK_DATA_RESULT: result = (BulkDataResult)response_cache.get(response_id); break;
327 case HISTORICAL_DATA_RESULT: result = (HistoricalDataResult)response_cache.get(response_id); break;
328 case FIELD_INFO_RESULT: result = (FieldInfoResult)response_cache.get(response_id); break;
329 case INTRADAY_TICK_RESULT: result = (IntradayTickDataResult)response_cache.get(response_id); break;
330 case INTRADAY_BAR_RESULT: result = (IntradayBarDataResult)response_cache.get(response_id); break;
331 default: throw new WrapperException("unknown result_type " + result_type);
332 }
333
334 Element response = message.asElement();
335
336 if (response.hasElement("responseError")) {
337 Element response_error = response.getElement("responseError");
338 logger.warning(response_error.toString());
339 throw new WrapperException("response error: " + response_error.getElementAsString("message"));
340 }
341 logger.fine("Processing response:\n" + response);
342 result.processResponse(response, logger, throw_invalid_ticker_error);
343 }
344 }
345
346 public DataResult fieldInfo(String[] fields) throws Exception {
347 int response_id = (int)sendApiDataRequest(FIELD_INFO_RESULT, fields).value();
348 processEventLoop(FIELD_INFO_RESULT);
349 return((DataResult)response_cache.get(response_id));
350 }
351
352 public DataResult blp(String[] securities, String[] fields) throws Exception {
353 String[] override_fields = new String[0];
354 String[] override_values = new String[0];
355 String[] option_names = new String[0];
356 String[] option_values = new String[0];
357 return(blp(securities, fields, override_fields, override_values, option_names, option_values));
358 }
359
360 public DataResult blp(String[] securities, String[] fields, String[] override_fields, String[] override_values) throws Exception {
361 String[] option_names = new String[0];
362 String[] option_values = new String[0];
363 return(blp(securities, fields, override_fields, override_values, option_names, option_values));
364 }
365
366 public DataResult blp(String[] securities, String[] fields, String[] override_fields, String[] override_values, String[] option_names, String[] option_values) throws Exception {
367 int response_id = (int)sendRefDataRequest(REFERENCE_DATA_RESULT, refdata_request_name, securities, fields, override_fields, override_values, option_names, option_values).value();
368 processEventLoop(REFERENCE_DATA_RESULT);
369 return((DataResult)response_cache.get(response_id));
370 }
371
372 public DataResult blh(String security, String[] fields, String start_date, String end_date) throws Exception {
373 String[] override_fields = new String[0];
374 String[] override_values = new String[0];
375
376 String[] option_names = {"startDate", "endDate"};
377 String[] option_values = new String[2];
378 option_values[0] = start_date;
379 option_values[1] = end_date;
380
381 return(blh(security, fields, override_fields, override_values, option_names, option_values));
382 }
383
384 public DataResult blh(String security, String[] fields, String start_date) throws Exception {
385 String[] override_fields = new String[0];
386 String[] override_values = new String[0];
387
388 String[] option_names = {"startDate"};
389 String[] option_values = new String[1];
390 option_values[0] = start_date;
391
392 return(blh(security, fields, override_fields, override_values, option_names, option_values));
393 }
394
395 public DataResult blh(String security, String[] fields, String start_date, String end_date, String[] override_fields, String[] override_values) throws Exception {
396 String[] option_names = {"startDate", "endDate"};
397 String[] option_values = new String[2];
398 option_values[0] = start_date;
399 option_values[1] = end_date;
400
401 return(blh(security, fields, override_fields, override_values, option_names, option_values));
402 }
403
404 public DataResult blh(String security, String[] fields, String start_date, String[] override_fields, String[] override_values) throws Exception {
405 String[] option_names = {"startDate"};
406 String[] option_values = new String[1];
407 option_values[0] = start_date;
408
409 return(blh(security, fields, override_fields, override_values, option_names, option_values));
410 }
411
412 public DataResult blh(String security, String[] fields, String start_date, String[] override_fields, String[] override_values, String[] option_names, String[] option_values) throws Exception {
413
414 int len = option_names.length;
415 String[] option_names_with_start = new String[len + 1];
416 String[] option_values_with_start = new String[len + 1];
417
418 for (int i = 0; i < len; i++) {
419 option_names_with_start[i] = option_names[i];
420 option_values_with_start[i] = option_values[i];
421 }
422
423 option_names_with_start[len] = "startDate";
424 option_values_with_start[len] = start_date;
425
426 return(blh(security, fields, override_fields, override_values, option_names_with_start, option_values_with_start));
427 }
428
429 public DataResult blh(String security, String[] fields, String start_date, String end_date, String[] override_fields, String[] override_values, String[] option_names, String[] option_values) throws Exception {
430
431 int len = option_names.length;
432 String[] option_names_with_start = new String[len + 2];
433 String[] option_values_with_start = new String[len + 2];
434
435 for (int i = 0; i < len; i++) {
436 option_names_with_start[i] = option_names[i];
437 option_values_with_start[i] = option_values[i];
438 }
439
440 option_names_with_start[len] = "startDate";
441 option_values_with_start[len] = start_date;
442
443 option_names_with_start[len+1] = "endDate";
444 option_values_with_start[len+1] = end_date;
445
446 return(blh(security, fields, override_fields, override_values, option_names_with_start, option_values_with_start));
447 }
448
449 public DataResult blh(String security, String[] fields, String[] override_fields, String[] override_values, String[] option_names, String[] option_values) throws Exception {
450 String[] securities = new String[1];
451 securities[0] = security;
452
453 int response_id = (int)sendRefDataRequest(HISTORICAL_DATA_RESULT, histdata_request_name, securities, fields, override_fields, override_values, option_names, option_values).value();
454 processEventLoop(HISTORICAL_DATA_RESULT);
455 return((DataResult)response_cache.get(response_id));
456 }
457
458 /**
459 * Request bulk data from [name redacted]. Shortcut method which allows you to call bls simply by passing a security and field.
460 * @param security A string containing security ticker.
461 * @param field A string containing field mnemonic.
462 */
463 public DataResult bls(String security, String field) throws Exception {
464 String[] override_fields = new String[0];
465 String[] override_values = new String[0];
466 String[] option_names = new String[0];
467 String[] option_values = new String[0];
468 return(bls(security, field, override_fields, override_values, option_names, option_values));
469 }
470
471 /**
472 * Request bulk data from [name redacted]. Bulk data may return several different fields for a single requested field.
473 * @param security A string containing security ticker.
474 * @param field A string containing field mnemonic.
475 * @param override_fields Array of strings with field mnemonics for override fields.
476 * @param override_values Array of strings with override values, must be in same order as override_fields.
477 */
478 public DataResult bls(String security, String field, String[] override_fields, String[] override_values) throws Exception {
479 String[] option_names = new String[0];
480 String[] option_values = new String[0];
481 return(bls(security, field, override_fields, override_values, option_names, option_values));
482 }
483
484 /**
485 * Request bulk data from [name redacted]. Bulk data may return several different fields for a single requested field.
486 * @param security A string containing security ticker.
487 * @param field A string containing field mnemonic.
488 * @param override_fields Array of strings with field mnemonics for override fields.
489 * @param override_values Array of strings with override values, must be in same order as override_fields.
490 * @param option_names Array of strings with option names.
491 * @param option_values Array of strings with option values, must be in same order as option_names.
492 */
493 public DataResult bls(String security, String field, String[] override_fields, String[] override_values, String[] option_names, String[] option_values) throws Exception {
494 String[] securities = new String[1];
495 securities[0] = security;
496
497 String[] fields = new String[1];
498 fields[0] = field;
499
500 int response_id = (int)sendRefDataRequest(BULK_DATA_RESULT, refdata_request_name, securities, fields, override_fields, override_values, option_names, option_values).value();
501 processEventLoop(BULK_DATA_RESULT);
502 return((DataResult)response_cache.get(response_id));
503 }
504
505 public DataResult tick(String security, String[] event_types, String start_date_time, String end_date_time) throws Exception {
506 String[] option_names = new String[0];
507 String[] option_values = new String[0];
508
509 return(tick(security, event_types, start_date_time, end_date_time, option_names, option_values));
510 }
511
512 public DataResult tick(String security, String[] event_types, String start_date_time, String end_date_time, String[] option_names, String[] option_values) throws Exception {
513 String[] securities = new String[0];
514 String[] fields = new String[0];
515
516 int len = option_names.length;
517 String[] option_names_with_start = new String[len + 3];
518 String[] option_values_with_start = new String[len + 3];
519
520 for (int i = 0; i < option_names.length; i++) {
521 option_names_with_start[i] = option_names[i];
522 option_values_with_start[i] = option_values[i];
523 }
524
525 option_names_with_start[len] = "security";
526 option_values_with_start[len] = security;
527 option_names_with_start[len+1] = "startDateTime";
528 option_values_with_start[len+1] = start_date_time;
529 option_names_with_start[len+2] = "endDateTime";
530 option_values_with_start[len+2] = end_date_time;
531
532 String[] override_fields = new String[0];
533 String[] override_values = new String[0];
534
535 int response_id = (int)sendRefDataRequest(INTRADAY_TICK_RESULT, intraday_tick_request_name, securities, fields, override_fields, override_values, option_names_with_start, option_values_with_start, event_types).value();
536 processEventLoop(INTRADAY_TICK_RESULT);
537 return((DataResult)response_cache.get(response_id));
538 }
539
540 public DataResult bar(String security, String event_type, String start_date_time, String end_date_time, String interval) throws Exception {
541 String[] securities = new String[0];
542 String[] fields = new String[0];
543
544 String[] option_names = new String[0];
545 String[] option_values = new String[0];
546 String[] override_fields = new String[0];
547 String[] override_values = new String[0];
548
549 int len = option_names.length;
550 String[] option_names_with_start = new String[len + 5];
551 String[] option_values_with_start = new String[len + 5];
552
553 for (int i = 0; i < option_names.length; i++) {
554 option_names_with_start[i] = option_names[i];
555 option_values_with_start[i] = option_values[i];
556 }
557
558 option_names_with_start[len] = "security";
559 option_values_with_start[len] = security;
560 option_names_with_start[len+1] = "startDateTime";
561 option_values_with_start[len+1] = start_date_time;
562 option_names_with_start[len+2] = "endDateTime";
563 option_values_with_start[len+2] = end_date_time;
564 option_names_with_start[len+3] = "eventType";
565 option_values_with_start[len+3] = event_type;
566 option_names_with_start[len+4] = "interval";
567 option_values_with_start[len+4] = interval;
568
569 int response_id = (int)sendRefDataRequest(INTRADAY_BAR_RESULT, intraday_bar_request_name, securities, fields, override_fields, override_values, option_names_with_start, option_values_with_start).value();
570 processEventLoop(INTRADAY_BAR_RESULT);
571 return((DataResult)response_cache.get(response_id));
572 }
573 }
574