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