Dealing with bloomberg Blpapi element that returns HasElement() as True but causes not found exception

Viewed 147

I am consuming trade and quote data with BLPAPI in C#. When I process a LAST_TRADE_PRICE_TIME_TODAY_RT like this using //blp/mktdata service and processing the SUBCRIPTION_DATA event fine except for this message element:

{MarketDataEvents = {
    RT_TIME_OF_TRADE = 2022-06-23
    INDICATIVE_NEAR = 
    IMBALANCE_BUY = 
    IMBALANCE_SELL = 
    ORDER_IMB_BUY_VOLUME = 
    ORDER_IMB_SELL_VOLUME = 
    THEO_PRICE = 
    IMBALANCE_INDIC_RT = 
    PREV_CLOSE_VALUE_REALTIME = 11737.5
    TRADING_DT_REALTIME = 2022-06-24
    PREV_TRADING_DT_REALTIME = 2022-06-23
    PX_ASK_LME_OFFICIAL_RT = 
    NUM_TRADES_RT = 0
    PX_OFFICIAL_AUCTION_RT = 
    LAST_UPDATE_BID_RT = 2022-06-23
    LAST_UPDATE_ASK_RT = 2022-06-23
    OFFICIAL_AUCTION_VOLUME_RT = 
    IN_AUCTION_RT = 
    TURNOVER_TODAY_REALTIME = 
    OFFICIAL_OPEN_AUCTION_PRICE_RT = 
    OFFICIAL_OPEN_AUCTION_VOLUME_RT = 
    OFFICIAL_CLOSE_AUCTION_PRICE_RT = 
    OFFICIAL_CLOSE_AUCTION_VOLUME_RT = 
    AUCTION_EXTENSION_RT = 
    BLOCK_TRADE_ACCUM_VOLUME_RT = 
    TOTAL_MSG_SCRAPED_OFFERS_RT = 
    EVENT_TIME = 22:30:00.000
    VOLUME_THEO = 
    OPEN_YLD_TDY_RT = 
    HIGH_YLD_TDY_RT = 
    LOW_YLD_TDY_RT = 
    LAST_YLD_TDY = 
    MID_TDY = 
    SIZE_LAST_TRADE_TDY = 
    RT_PX_CHG_NET_1D = 171.75
    RT_PX_CHG_PCT_1D = 1.485
    OPEN_TDY = 
    ASK_SIZE_TDY = 
    BID_SIZE_TDY = 
    VOLUME_TDY = 
    LAST_PRICE_TDY = 
    BID_TDY = 
    ASK_TDY = 
    HIGH_TDY = 
    LOW_TDY = 
    BID_YLD_TDY = 
    ASK_YLD_TDY = 
    TIME = 2022-06-23
    LAST_UPDATE_ALL_SESSIONS_RT = 
    PX_OPEN_ALL_WITH_SWITCHOVER_RT = 
    BID_ALL_SESSION_TDY_RT = 
    ASK_ALL_SESSION_TDY_RT = 
    CONTINUOUS_TRAD_CLOS_BID_PX_RT = 
    CONTINUOUS_TRAD_CLOS_ASK_PX_RT = 
    POST_CLOSING_AUCTION_BID_PX_RT = 
    POST_CLOSING_AUCTION_ASK_PX_RT = 
    LAST_TRADE_RECEIVED_TIME_RT = 
    PRICE_CHANGE_ON_DAY_RT = 171.75
    PRICE_LAST_ASK_RT = 
    PRICE_LAST_BID_RT = 
    PRICE_HIGH_RT = 
    PRICE_LOW_RT = 
    PRICE_OPEN_RT = 
    LAST_TRADE_PRICE_TODAY_RT = 
    PREVIOUS_TOTAL_VOLUME_RT = 622197
    PREVIOUS_CLOSE_ADJ_BY_GR_DVD_RT = 
    TIME_AUCTION_CALL_CONCLUSION_RT = 
    PER_TRADE_VWAP_REALTIME = 
    PER_TRADE_VWAP_TURNOVER_RT = 
    PER_TRADE_VWAP_VOLUME_RT = 
    OPEN_HIGH_PRICE_REALTIME = 
    OPEN_LOW_PRICE_REALTIME = 
    CLOSE_HIGH_PRICE_REALTIME = 
    CLOSE_LOW_PRICE_REALTIME = 
    EXCHANGE_FOR_PHYSICAL_VOLUME_RT = 
    EXCHANGE_FOR_SWAP_VOLUME_RT = 
    LAST_BID_TIME_TODAY_REALTIME = 
    LAST_ASK_TIME_TODAY_REALTIME = 
    LAST_MID_TIME_TODAY_REALTIME = 
    LAST_PRICE_TIME_TODAY_REALTIME = 
    LAST_TRADE_PRICE_TIME_TODAY_RT = 
    MINIMUM_ORDER_LIMIT_PRICE_RT = 
    MAXIMUM_ORDER_LIMIT_PRICE_RT = 
    MIN_DYNAMIC_TRADING_LIMIT_PX_RT = 
    MAX_DYNAMIC_TRADING_LIMIT_PX_RT = 
    15_SECOND_PRICE_CHANGE_RT = 
    1_MINUTE_PRICE_CHANGE_RT = 
    5_MINUTE_PRICE_CHANGE_RT = 
    15_MINUTE_PRICE_CHANGE_RT = 
    1_HOUR_PRICE_CHANGE_RT = 
    CIRCUIT_BREAKER_TRIG_SIGNAL_RT = 
    LAST_CONTINUOUS_TRADE_PRICE_RT = 
    DYNAMIC_TRADING_LIMITS_REF_PX_RT = 
    LAST_OFF_BOOK_TRADE_PRICE_RT = 
    CB_TRIGGER_SIGNAL_START_TIME_RT = 
    CB_TRIGGER_SIGNAL_END_TIME_RT = 
    EFFECTIVE_DATE_RT = 
    OPEN_TRADE_PRICE_TODAY_RT = 
    HIGH_TRADE_PRICE_TODAY_RT = 
    LOW_TRADE_PRICE_TODAY_RT = 
    EXCHANGE_FOR_RISK_VOLUME_RT = 
    BLOOMBERG_CLOSE_PRICE_TODAY_RT = 
    PRICE_CLOSE_CC_TODAY_RT = 
    SUB_SEC_TM_AUCT_CALL_CNCLSN_RT = 
    THEORETICAL_TIME_TODAY_RT = 
    ON_EXCHANGE_VOLUME_TODAY_RT = 
    ON_BOOK_VOLUME_TODAY_RT = 
    LIT_BOOK_VOLUME_TODAY_RT = 
    CONTINUOUS_VOLUME_TODAY_RT = 
    AUCTION_VOLUME_TODAY_RT = 
    SCHEDULED_AUCT_VOLUME_TODAY_RT = 
    OPENING_AUCTION_VOLUME_RT = 
    CLOSING_AUCTION_VOLUME_RT = 
    INTRADAY_AUCTION_VOLUME_TODAY_RT = 
    UNSCHEDULED_AUCT_VOLUME_TODAY_RT = 
    TRADE_LAST_CLOSE_VOLUME_TODAY_RT = 
    PRE_POST_AUTO_EXECTN_VOL_TDY_RT = 
    DARK_BOOK_VOLUME_TODAY_RT = 
    ON_BK_NEG_BTF_OR_CC_VOL_TDY_RT = 
    ODD_LOT_BOOK_VOLUME_TODAY_RT = 
    OFF_BOOK_VOLUME_TODAY_RT = 
    NEGOTIATED_VOLUME_TODAY_RT = 
    OFF_BK_BLOCK_OR_CC_VOLUME_TDY_RT = 
    OFF_BOOK_ODD_LOT_VOLUME_TODAY_RT = 
    OTC_VOLUME_TODAY_RT = 
    SYSTEMATIC_INTERNAL_VOL_TDY_RT = 
    REPORTED_DARK_VOLUME_TODAY_RT = 
    PERCENT_CHANGE_ON_DAY_TODAY_RT = 
    NET_CHANGE_ON_DAY_TODAY_RT = 
    LAST_TRADE_AM_SESSION_TODAY_RT = 
    OPEN_PRICE_AM_SESSION_TODAY_RT = 
    HIGH_PRICE_AM_SESSION_TODAY_RT = 
    LOW_PRICE_AM_SESSION_TODAY_RT = 
    VOLUME_AM_SESSION_TODAY_RT = 
    LAST_TRADE_PM_SESSION_TODAY_RT = 
    OPEN_PRICE_PM_SESSION_TODAY_RT = 
    HIGH_PRICE_PM_SESSION_TODAY_RT = 
    LOW_PRICE_PM_SESSION_TODAY_RT = 
    VOLUME_PM_SESSION_TODAY_RT = 
    EXCHANGE_VWAP_TODAY_RT = 
    SETTLEMENT_PRESENT_VALUE_RT = 
    MATURITY_CALIBRATION_RATE_RT = 
    MATURITY_CALIBRATION_PV_RT = 
    CONTRIBUTED_RECOVERY_RATE_RT = 
    PAR_SPREAD_BID_RT = 
    PAR_SPREAD_ASK_RT = 
    LIQUIDITY_INDICATOR_RT = 
    PRICE_BID_CLOSE_TODAY_RT = 
    PRICE_ASK_CLOSE_TODAY_RT = 
    OFFICIAL_CLOSE_TODAY_RT = 
    PREVIOUS_BLOOMBERG_CLOSE_PX_RT = 11737.5
    PREVIOUS_LAST_TRADE_PRICE_RT = 11688
    BLOOMBERG_SEND_TIME_RT = 2022-06-23T21:31:23.469+00:00
    10_MINUTE_PRICE_CHANGE_RT = 
    30_MINUTE_PRICE_CHANGE_RT = 
    BLOOMBERG_CLOSE_PX_AM_TODAY_RT = 
    PERIODIC_AUCT_ON_DMD_VOL_TDY_RT = 
    PERIODIC_AUCT_ON_DMD_THEO_PX_RT = 
    CHG_NET_REG_SES_PRV_RG_SES_CL_RT = 
    CHG_PCT_REG_SES_PRV_RG_SES_CL_RT = 
    ACTUAL_TRADED_PRICE_RT = 
    MIN_DYNMC_BID_ORDR_LIMT_PX_RT = 
    MAXMM_DYNMC_BID_ORDR_LIMT_PX_RT = 
    MIN_DYNMC_ASK_ORDR_LIMT_PX_RT = 
    MAXMM_DYNMC_ASK_ORDR_LIMT_PX_RT = 
    MKTDATA_EVENT_TYPE = SUMMARY
    MKTDATA_EVENT_SUBTYPE = NEWDAY
    DELTA_AVAT_30_DAY_INTERVAL = 
    DELTA_AVAT_1_DAY_INTERVAL = 
    DELTA_AVAT_5_DAY_INTERVAL = 
    DELTA_AVAT_10_DAY_INTERVAL = 
    DELTA_AVAT_20_DAY_INTERVAL = 
    DELTA_AVAT_100_DAY_INTERVAL = 
    DELTA_AVAT_180_DAY_INTERVAL = 
    DELTA_ATAT_1_DAY_INTERVAL = 
    DELTA_ATAT_5_DAY_INTERVAL = 
    DELTA_ATAT_10_DAY_INTERVAL = 
    DELTA_ATAT_20_DAY_INTERVAL = 
    DELTA_ATAT_30_DAY_INTERVAL = 
    DELTA_ATAT_100_DAY_INTERVAL = 
    DELTA_ATAT_180_DAY_INTERVAL = 
    REALTIME_15_SEC_PRICE_PCT_CHG = 
    REALTIME_ONE_MIN_PRICE_PCT_CHG = 
    REALTIME_FIVE_MIN_PRICE_PCT_CHG = 
    REALTIME_15_MIN_PRICE_PCT_CHG = 
    REALTIME_ONE_HOUR_PRICE_PCT_CHG = 
    REALTIME_VOLUME_5_DAY_INTERVAL = 
    CURRENT_SESSION_RT = 4
    IMPLIED_BID_PRICE_RT = 
    IMPLIED_ASK_PRICE_RT = 
    IMPLIED_BID_SIZE_RT = 
    IMPLIED_ASK_SIZE_RT = 
    IS_DELAYED_STREAM = false
}
}

I use this to check the datetime and emit a trade event:

                    if (message.HasElement(LAST_TIME))
                    {
                        if (message.GetElementAsDatetime(LAST_TIME).IsValid())
                        {
                            DateTime time = message.GetElementAsDatetime(LAST_TIME).ToSystemDateTime();

                            if (message.HasElement(LAST) && message.HasElement(SIZE))
                            {
                                double last = message.GetElementAsFloat64(LAST);
                                int last_size = message.GetElementAsInt32(SIZE);
                                long volume = message.GetElementAsInt64(VOLUME); ...

I receive:

'Bloomberglp.Blpapi.NotFoundException: LAST_TRADE_PRICE_TIME_TODAY_RT has no value in MarketDataUpdate.'

I have tried converting to string first and checking if empty and checking null. Any ideas would be helpful...

2 Answers

I suspect that

if (message.HasElement(LAST_TIME))

returns true because the field is there (but empty). However when you call:

if (message.GetElementAsDatetime(LAST_TIME).IsValid())

GetElementAsDatetime throws an exception because the value (which is empty) is not a valid datetime.

I think something like this may work:

Element lastTime = message.GetElement(LAST_TIME);
if (lastTime.Datatype() == Schema.Datatype.DATETIME) {
  DateTime dt = lastTime.GetValueAsDatetime();

I don't think checking the DataType is what you want. The DataType is part of the schema. It should always be set even when there is no value. If it seems to be working, it is possibly because the element's data type is not DATETIME. For instance, if it is of type DATE, or TIME, GetAsDateTime would still work, but the DataType will never be DATETIME—meaning the code path will never get hit. What you want to check is if it has a value.

HasElement is saying that the schema contains such an element, but if the schema definition allows for there to be zero values (optional), it might not have a value. GetValueAsDatetime() is really GetValueAsDatetime(0), meaning the 0th value which may not exist. Note the same function can be used for array type items that have more than one value. I think the correct way to check this would be:

Element lastTime = message.GetElement(LAST_TIME);
if (lastTime.NumValues > 0) {
  DateTime dt = lastTime.GetValueAsDatetime();
Related