/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.bbg.loader; import static com.opengamma.bbg.BloombergConstants.FIELD_AMT_ISSUED; import static com.opengamma.bbg.BloombergConstants.FIELD_ANNOUNCE_DT; import static com.opengamma.bbg.BloombergConstants.FIELD_BASE_CPI; import static com.opengamma.bbg.BloombergConstants.FIELD_BB_COMPOSITE; import static com.opengamma.bbg.BloombergConstants.FIELD_BULLET; import static com.opengamma.bbg.BloombergConstants.FIELD_CALC_TYP_DES; import static com.opengamma.bbg.BloombergConstants.FIELD_CALLABLE; import static com.opengamma.bbg.BloombergConstants.FIELD_CNTRY_ISSUE_ISO; import static com.opengamma.bbg.BloombergConstants.FIELD_CPN; import static com.opengamma.bbg.BloombergConstants.FIELD_CPN_FREQ; import static com.opengamma.bbg.BloombergConstants.FIELD_CPN_TYP; import static com.opengamma.bbg.BloombergConstants.FIELD_CRNCY; import static com.opengamma.bbg.BloombergConstants.FIELD_DAYS_TO_SETTLE; import static com.opengamma.bbg.BloombergConstants.FIELD_DAY_CNT_DES; import static com.opengamma.bbg.BloombergConstants.FIELD_FIRST_CPN_DT; import static com.opengamma.bbg.BloombergConstants.FIELD_FLOATER; import static com.opengamma.bbg.BloombergConstants.FIELD_FLT_BENCH_MULTIPLIER; import static com.opengamma.bbg.BloombergConstants.FIELD_FLT_DAYS_PRIOR; import static com.opengamma.bbg.BloombergConstants.FIELD_FLT_SPREAD; import static com.opengamma.bbg.BloombergConstants.FIELD_GUARANTOR; import static com.opengamma.bbg.BloombergConstants.FIELD_ID_BBG_UNIQUE; import static com.opengamma.bbg.BloombergConstants.FIELD_ID_BB_SEC_NUM_DES; import static com.opengamma.bbg.BloombergConstants.FIELD_ID_CUSIP; import static com.opengamma.bbg.BloombergConstants.FIELD_ID_ISIN; import static com.opengamma.bbg.BloombergConstants.FIELD_ID_SEDOL1; import static com.opengamma.bbg.BloombergConstants.FIELD_INDUSTRY_GROUP; import static com.opengamma.bbg.BloombergConstants.FIELD_INDUSTRY_SECTOR; import static com.opengamma.bbg.BloombergConstants.FIELD_INFLATION_LAG; import static com.opengamma.bbg.BloombergConstants.FIELD_INFLATION_LINKED_INDICATOR; import static com.opengamma.bbg.BloombergConstants.FIELD_INT_ACC_DT; import static com.opengamma.bbg.BloombergConstants.FIELD_ISSUER; import static com.opengamma.bbg.BloombergConstants.FIELD_ISSUE_DT; import static com.opengamma.bbg.BloombergConstants.FIELD_ISSUE_PX; import static com.opengamma.bbg.BloombergConstants.FIELD_IS_PERPETUAL; import static com.opengamma.bbg.BloombergConstants.FIELD_MARKET_SECTOR_DES; import static com.opengamma.bbg.BloombergConstants.FIELD_MATURITY; import static com.opengamma.bbg.BloombergConstants.FIELD_MIN_INCREMENT; import static com.opengamma.bbg.BloombergConstants.FIELD_MIN_PIECE; import static com.opengamma.bbg.BloombergConstants.FIELD_PARSEKYABLE_DES; import static com.opengamma.bbg.BloombergConstants.FIELD_PAR_AMT; import static com.opengamma.bbg.BloombergConstants.FIELD_REDEMP_VAL; import static com.opengamma.bbg.BloombergConstants.FIELD_REFERENCE_INDEX; import static com.opengamma.bbg.BloombergConstants.FIELD_RESET_IDX; import static com.opengamma.bbg.BloombergConstants.FIELD_RTG_FITCH; import static com.opengamma.bbg.BloombergConstants.FIELD_RTG_MOODY; import static com.opengamma.bbg.BloombergConstants.FIELD_RTG_SP; import static com.opengamma.bbg.BloombergConstants.FIELD_SECURITY_DES; import static com.opengamma.bbg.BloombergConstants.FIELD_SECURITY_TYP; import static com.opengamma.bbg.BloombergConstants.FIELD_SETTLE_DT; import static com.opengamma.bbg.BloombergConstants.FIELD_TICKER; import static com.opengamma.bbg.BloombergConstants.FIELD_ZERO_CPN; import static com.opengamma.bbg.BloombergConstants.MARKET_SECTOR_MUNI; import static com.opengamma.bbg.BloombergConstants.FIELD_INTERPOLATION_FOR_COUPON_CALC; import static com.opengamma.bbg.util.BloombergDataUtils.isValidField; import java.util.HashSet; import java.util.Set; import org.fudgemsg.FudgeMsg; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.threeten.bp.LocalDate; import org.threeten.bp.LocalTime; import org.threeten.bp.ZoneId; import org.threeten.bp.ZoneOffset; import org.threeten.bp.ZonedDateTime; import com.google.common.collect.ImmutableSet; import com.opengamma.OpenGammaRuntimeException; import com.opengamma.bbg.referencedata.ReferenceDataProvider; import com.opengamma.bbg.security.BloombergSecurityProvider; import com.opengamma.core.id.ExternalSchemes; import com.opengamma.financial.convention.daycount.DayCount; import com.opengamma.financial.convention.daycount.DayCountFactory; import com.opengamma.financial.convention.frequency.Frequency; import com.opengamma.financial.convention.frequency.SimpleFrequency; import com.opengamma.financial.convention.frequency.SimpleFrequencyFactory; import com.opengamma.financial.convention.yield.YieldConvention; import com.opengamma.financial.convention.yield.YieldConventionFactory; import com.opengamma.financial.security.bond.BondSecurity; import com.opengamma.financial.security.bond.CorporateBondSecurity; import com.opengamma.financial.security.bond.FloatingRateNoteSecurity; import com.opengamma.financial.security.bond.GovernmentBondSecurity; import com.opengamma.financial.security.bond.InflationBondSecurity; import com.opengamma.financial.security.bond.MunicipalBondSecurity; import com.opengamma.id.ExternalId; import com.opengamma.id.ExternalIdBundle; import com.opengamma.master.security.ManageableSecurity; import com.opengamma.util.money.Currency; import com.opengamma.util.time.Expiry; import com.opengamma.util.time.ExpiryAccuracy; /** * Loads the data for a bond from Bloomberg. */ public class BondLoader extends SecurityLoader { /** Logger. */ private static final Logger s_logger = LoggerFactory.getLogger(BondLoader.class); /** * The fields to load from Bloomberg. */ private static final Set<String> BLOOMBERG_BOND_FIELDS = ImmutableSet.of( FIELD_ISSUER, FIELD_INDUSTRY_GROUP, FIELD_INDUSTRY_SECTOR, FIELD_CNTRY_ISSUE_ISO, FIELD_SECURITY_TYP, FIELD_CALC_TYP_DES, FIELD_GUARANTOR, FIELD_CRNCY, FIELD_MATURITY, FIELD_CPN_TYP, FIELD_CPN, FIELD_CPN_FREQ, FIELD_ZERO_CPN, FIELD_DAY_CNT_DES, FIELD_ANNOUNCE_DT, FIELD_INT_ACC_DT, FIELD_SETTLE_DT, FIELD_FIRST_CPN_DT, FIELD_ISSUE_PX, FIELD_AMT_ISSUED, FIELD_MIN_PIECE, FIELD_MIN_INCREMENT, FIELD_PAR_AMT, FIELD_REDEMP_VAL, FIELD_FLOATER, FIELD_INFLATION_LINKED_INDICATOR, FIELD_REFERENCE_INDEX, FIELD_CALLABLE, FIELD_IS_PERPETUAL, FIELD_BULLET, FIELD_BASE_CPI, FIELD_RTG_FITCH, FIELD_RTG_MOODY, FIELD_RTG_SP, FIELD_BB_COMPOSITE, FIELD_ID_BBG_UNIQUE, FIELD_ID_CUSIP, FIELD_ID_ISIN, FIELD_ID_SEDOL1, FIELD_TICKER, FIELD_MARKET_SECTOR_DES, FIELD_SECURITY_DES, FIELD_FLT_DAYS_PRIOR, FIELD_FLT_SPREAD, FIELD_FLT_BENCH_MULTIPLIER, FIELD_ISSUE_DT, FIELD_DAYS_TO_SETTLE, FIELD_RESET_IDX, FIELD_PARSEKYABLE_DES, FIELD_ID_BB_SEC_NUM_DES, FIELD_INFLATION_LAG, FIELD_INTERPOLATION_FOR_COUPON_CALC); /** * The valid Bloomberg security types for Bond */ public static final Set<String> VALID_SECURITY_TYPES = ImmutableSet.of( "Prvt CMO FLT", "EURO MTN", "EURO-ZONE", "CF", "ABS Other", "EURO NON-DOLLAR", "CMBS", "ABS Auto", "PRIV PLACEMENT", "GLOBAL", "EURO-DOLLAR", "YANKEE", "US DOMESTIC", "ABS Card", "Prvt CMO Other", "SN", "Agncy ABS Other", "US GOVERNMENT", "UK GILT STOCK", "CANADIAN", "DOMESTIC", "AUSTRALIAN"); private static final String SOVEREIGN = "Sovereign"; /** * Creates an instance. * @param referenceDataProvider the provider, not null */ public BondLoader(final ReferenceDataProvider referenceDataProvider) { super(s_logger, referenceDataProvider, SecurityType.BOND); } private String validateAndGetStringField(final FudgeMsg fieldData, final String fieldName) { if (!isValidField(fieldData.getString(fieldName))) { s_logger.warn(fieldName + " is null, cannot construct bond security"); throw new OpenGammaRuntimeException(fieldName + " is null, cannot construct bond security"); } return fieldData.getString(fieldName); } private String validateAndGetNullableStringField(final FudgeMsg fieldData, final String fieldName) { if (!isValidField(fieldData.getString(fieldName))) { return null; } return fieldData.getString(fieldName); } private Double validateAndGetDoubleField(final FudgeMsg fieldData, final String fieldName) { if (!isValidField(fieldData.getString(fieldName))) { s_logger.warn(fieldName + " is null, cannot construct bond security"); throw new OpenGammaRuntimeException(fieldName + " is null, cannot construct bond security"); } return fieldData.getDouble(fieldName); } private Double validateAndGetNullableDoubleField(final FudgeMsg fieldData, final String fieldName) { if (!isValidField(fieldData.getString(fieldName))) { return null; } return fieldData.getDouble(fieldName); } private Integer validateAndGetNullableIntegerField(final FudgeMsg fieldData, final String fieldName) { if (!isValidField(fieldData.getString(fieldName))) { return null; } return fieldData.getInt(fieldName); } private ZonedDateTime validateAndGetNullableDateField(final FudgeMsg fieldData, final String fieldName) { if (!isValidField(fieldData.getString(fieldName))) { return null; } // These will need to be sorted out. final LocalTime expiryTime = LocalTime.of(17, 00); final ZoneId zone = ZoneOffset.UTC; final LocalDate localDate = LocalDate.parse(fieldData.getString(fieldName)); return localDate.atTime(expiryTime).atZone(zone); } private Integer validateAndGetIntegerField(final FudgeMsg fieldData, final String fieldName) { if (!isValidField(fieldData.getString(fieldName))) { s_logger.warn(fieldName + " is null, cannot construct bond security"); throw new OpenGammaRuntimeException(fieldName + " is null, cannot construct bond security"); } return fieldData.getInt(fieldName); } //------------------------------------------------------------------------- @Override protected ManageableSecurity createSecurity(final FudgeMsg fieldData) { try { final String issuerName = validateAndGetStringField(fieldData, FIELD_ISSUER); final String issuerType = validateAndGetStringField(fieldData, FIELD_INDUSTRY_GROUP); final String issuerSector = validateAndGetStringField(fieldData, FIELD_INDUSTRY_SECTOR); final String inflationIndicator = validateAndGetNullableStringField(fieldData, FIELD_INFLATION_LINKED_INDICATOR); final String isPerpetualStr = validateAndGetNullableStringField(fieldData, FIELD_IS_PERPETUAL); final boolean isPerpetual = (isPerpetualStr != null && isPerpetualStr.trim().toUpperCase().contains("Y")); final String isBulletStr = validateAndGetNullableStringField(fieldData, FIELD_BULLET); final boolean isBullet = (isBulletStr != null && isBulletStr.trim().toUpperCase().contains("Y")); final String isFloaterStr = validateAndGetNullableStringField(fieldData, FIELD_FLOATER); final boolean isFloater = (isFloaterStr != null && isFloaterStr.trim().toUpperCase().contains("Y")); final String callable = validateAndGetNullableStringField(fieldData, FIELD_CALLABLE); final boolean isCallable = (callable != null && callable.trim().toUpperCase().contains("Y")); final String issuerDomicile = validateAndGetStringField(fieldData, FIELD_CNTRY_ISSUE_ISO); final String market = validateAndGetStringField(fieldData, FIELD_SECURITY_TYP); final String currencyStr = validateAndGetStringField(fieldData, FIELD_CRNCY); final Currency currency = Currency.parse(currencyStr); final String yieldConventionStr = validateAndGetStringField(fieldData, FIELD_CALC_TYP_DES); final YieldConvention yieldConvention = YieldConventionFactory.INSTANCE.getYieldConvention(yieldConventionStr); if (yieldConvention == null) { throw new OpenGammaRuntimeException("Cannot get yield Convention called " + yieldConventionStr); } final String guaranteeType = fieldData.getString(FIELD_GUARANTOR); // bit unsure about this one. String maturityStr = validateAndGetNullableStringField(fieldData, FIELD_MATURITY); if (maturityStr == null && isPerpetual) { maturityStr = "2049-06-29"; // fake date, need to remove. } // These will need to be sorted out. final LocalTime expiryTime = LocalTime.of(17, 00); final ZoneId zone = ZoneOffset.UTC; Expiry maturity = null; try { maturity = new Expiry(LocalDate.parse(maturityStr).atTime(expiryTime).atZone(zone), ExpiryAccuracy.DAY_MONTH_YEAR); } catch (final Exception e) { throw new OpenGammaRuntimeException(maturityStr + " returned from bloomberg not in format yyyy-mm-dd", e); } final String rtgFitch = validateAndGetNullableStringField(fieldData, FIELD_RTG_FITCH); final String rtgMoody = validateAndGetNullableStringField(fieldData, FIELD_RTG_MOODY); final String rtgSp = validateAndGetNullableStringField(fieldData, FIELD_RTG_SP); final String bbComposite = validateAndGetNullableStringField(fieldData, FIELD_BB_COMPOSITE); final String couponType = validateAndGetStringField(fieldData, FIELD_CPN_TYP); final Double couponRate = validateAndGetDoubleField(fieldData, FIELD_CPN); final String zeroCoupon = validateAndGetStringField(fieldData, FIELD_ZERO_CPN); final String cusip = validateAndGetStringField(fieldData, FIELD_ID_CUSIP); Frequency couponFrequency; if ("Y".equals(zeroCoupon)) { couponFrequency = SimpleFrequency.NEVER; } else { final Integer couponFrequencyInt = validateAndGetNullableIntegerField(fieldData, FIELD_CPN_FREQ); couponFrequency = couponFrequencyInt != null ? SimpleFrequencyFactory.INSTANCE.getFrequency(couponFrequencyInt) : SimpleFrequency.NEVER; } String dayCountString = validateAndGetStringField(fieldData, FIELD_DAY_CNT_DES); // REVIEW: jim 27-Jan-2011 -- remove this and fix it properly. boolean isEOM = true; if (dayCountString.endsWith("NON-EOM")) { isEOM = false; } if (dayCountString.equals("ACT/ACT") || dayCountString.equals("ACT/ACT NON-EOM")) { dayCountString = "Actual/Actual ICMA"; } if (dayCountString.equals("BUS DAYS/252")) { dayCountString = "Business/252"; } final ZonedDateTime announcementDate = validateAndGetNullableDateField(fieldData, FIELD_ANNOUNCE_DT); final ZonedDateTime interestAccrualDate = validateAndGetNullableDateField(fieldData, FIELD_INT_ACC_DT); final ZonedDateTime settlementDate = validateAndGetNullableDateField(fieldData, FIELD_SETTLE_DT); final ZonedDateTime firstCouponDate = validateAndGetNullableDateField(fieldData, FIELD_FIRST_CPN_DT); if (currencyStr.equals("GBP")) { if (announcementDate.toLocalDate().isAfter(LocalDate.of(1998, 11, 1)) && dayCountString.equals("ACT/ACT")) { dayCountString = "Actual/Actual ICMA"; } else if (dayCountString.equals("ACT/365")) { dayCountString = "Actual/365"; } } final DayCount dayCount = DayCountFactory.of(dayCountString); final Double issuancePrice = validateAndGetNullableDoubleField(fieldData, FIELD_ISSUE_PX); final Double totalAmountIssued = validateAndGetDoubleField(fieldData, FIELD_AMT_ISSUED); final Double minimumAmount = validateAndGetDoubleField(fieldData, FIELD_MIN_PIECE); final Double minimumIncrement = validateAndGetDoubleField(fieldData, FIELD_MIN_INCREMENT); final Double parAmount = validateAndGetDoubleField(fieldData, FIELD_PAR_AMT); final Double redemptionValue = validateAndGetDoubleField(fieldData, FIELD_REDEMP_VAL); //String bbgUnique = validateAndGetStringField(fieldData, FIELD_ID_BBG_UNIQUE); final String marketSector = validateAndGetStringField(fieldData, FIELD_MARKET_SECTOR_DES); final String des = validateAndGetStringField(fieldData, FIELD_SECURITY_DES); ManageableSecurity bondSecurity; final ExternalId legalEntityId = ExternalId.of(ExternalSchemes.CUSIP_ENTITY_STUB, cusip.substring(0, 6)); if ((inflationIndicator != null) && (inflationIndicator.trim().toUpperCase().startsWith("Y"))) { // six character stub of CUSIP to link to legal entity. final String referenceIndexStr = validateAndGetStringField(fieldData, FIELD_REFERENCE_INDEX); final String baseCPI = validateAndGetStringField(fieldData, FIELD_BASE_CPI); // keep as string because going into attributes final String inflationLag = validateAndGetStringField(fieldData, FIELD_INFLATION_LAG); final String daysToSettle = validateAndGetStringField(fieldData, FIELD_DAYS_TO_SETTLE); final String interpolationMethod = validateAndGetStringField(fieldData, FIELD_INTERPOLATION_FOR_COUPON_CALC); final ExternalId referenceIndex = ExternalId.of(ExternalSchemes.BLOOMBERG_TICKER, referenceIndexStr); bondSecurity = new InflationBondSecurity(issuerName, issuerType, issuerDomicile, market, currency, yieldConvention, maturity, couponType, couponRate, couponFrequency, dayCount, interestAccrualDate, settlementDate, firstCouponDate, issuancePrice, totalAmountIssued, minimumAmount, minimumIncrement, parAmount, redemptionValue); ((BondSecurity) bondSecurity).setAnnouncementDate(announcementDate); ((BondSecurity) bondSecurity).setGuaranteeType(guaranteeType); ((BondSecurity) bondSecurity).addAttribute("BaseCPI", baseCPI); ((BondSecurity) bondSecurity).addAttribute("ReferenceIndexId", referenceIndex.toString()); ((BondSecurity) bondSecurity).addAttribute("InflationLag", inflationLag); ((BondSecurity) bondSecurity).addAttribute("daysToSettle", daysToSettle); ((BondSecurity) bondSecurity).addAttribute("interpolationMethod", interpolationMethod); } else if (isFloater) { // six character stub of CUSIP to link to legal entity. final String benchmarkRateStr = validateAndGetStringField(fieldData, FIELD_RESET_IDX) + " Index"; //TODO safe to assume the suffix? final ExternalId benchmarkRateId = ExternalSchemes.bloombergTickerSecurityId(benchmarkRateStr); final ZonedDateTime issueDate = validateAndGetNullableDateField(fieldData, FIELD_ISSUE_DT); final int daysToSettle = validateAndGetIntegerField(fieldData, FIELD_DAYS_TO_SETTLE); final int resetDays = validateAndGetIntegerField(fieldData, FIELD_FLT_DAYS_PRIOR); final double spread = validateAndGetDoubleField(fieldData, FIELD_FLT_SPREAD); final double leverage = validateAndGetDoubleField(fieldData, FIELD_FLT_BENCH_MULTIPLIER); final String country = validateAndGetStringField(fieldData, FIELD_CNTRY_ISSUE_ISO); final ExternalId regionId = ExternalSchemes.financialRegionId(country); bondSecurity = new FloatingRateNoteSecurity(currency, maturity, issueDate, minimumIncrement, daysToSettle, resetDays, dayCount, regionId, legalEntityId, benchmarkRateId, spread, leverage, couponFrequency); } else if (issuerType.trim().equals(SOVEREIGN)) { bondSecurity = new GovernmentBondSecurity(issuerName, issuerType, issuerDomicile, market, currency, yieldConvention, maturity, couponType, couponRate, couponFrequency, dayCount, interestAccrualDate, settlementDate, firstCouponDate, issuancePrice, totalAmountIssued, minimumAmount, minimumIncrement, parAmount, redemptionValue); ((BondSecurity) bondSecurity).setAnnouncementDate(announcementDate); ((BondSecurity) bondSecurity).setGuaranteeType(guaranteeType); } else if (marketSector.equals(MARKET_SECTOR_MUNI)) { bondSecurity = new MunicipalBondSecurity(issuerName, issuerType, issuerDomicile, market, currency, yieldConvention, maturity, couponType, couponRate, couponFrequency, dayCount, interestAccrualDate, settlementDate, firstCouponDate, issuancePrice, totalAmountIssued, minimumAmount, minimumIncrement, parAmount, redemptionValue); ((BondSecurity) bondSecurity).setAnnouncementDate(announcementDate); ((BondSecurity) bondSecurity).setGuaranteeType(guaranteeType); } else { bondSecurity = new CorporateBondSecurity(issuerName, issuerType, issuerDomicile, market, currency, yieldConvention, maturity, couponType, couponRate, couponFrequency, dayCount, interestAccrualDate, settlementDate, firstCouponDate, issuancePrice, totalAmountIssued, minimumAmount, minimumIncrement, parAmount, redemptionValue); ((BondSecurity) bondSecurity).setAnnouncementDate(announcementDate); ((BondSecurity) bondSecurity).setGuaranteeType(guaranteeType); } bondSecurity.setName(des.trim()); bondSecurity.addAttribute("Bullet", isBullet ? "Y" : "N"); bondSecurity.addAttribute("Callable", isCallable ? "Y" : "N"); bondSecurity.addAttribute("Perpetual", isPerpetual ? "Y" : "N"); bondSecurity.addAttribute("EOM", isEOM ? "Y" : "N"); bondSecurity.addAttribute("LegalEntityId", legalEntityId.toString()); if (rtgFitch != null) { bondSecurity.addAttribute("RatingFitch", rtgFitch); } if (rtgMoody != null) { bondSecurity.addAttribute("RatingMoody", rtgMoody); } if (rtgSp != null) { bondSecurity.addAttribute("RatingSP", rtgSp); } if (issuerSector != null) { bondSecurity.addAttribute("IndustrySector", issuerSector); } if (bbComposite != null) { bondSecurity.addAttribute("RatingComposite", bbComposite); } // set identifiers parseIdentifiers(fieldData, bondSecurity); return bondSecurity; } catch (final OpenGammaRuntimeException ogre) { s_logger.error("Error loading bond {} - {} - FLOATER={}, Fields are {}", new Object[] {fieldData.getValue(FIELD_ID_ISIN), ogre.getMessage(), fieldData.getString(FIELD_FLOATER), null }); //fieldData }); return null; } } /** * Parse the identifiers from the response. Note that we don't populate BLOOMBERG_TICKER because it's always either S or T. * @param fieldData the response, not null * @param security the security to populate, not null */ @Override protected void parseIdentifiers(final FudgeMsg fieldData, final ManageableSecurity security) { final String bbgUnique = fieldData.getString(FIELD_ID_BBG_UNIQUE); final String cusip = fieldData.getString(FIELD_ID_CUSIP); final String isin = fieldData.getString(FIELD_ID_ISIN); final String sedol1 = fieldData.getString(FIELD_ID_SEDOL1); final String ticker = fieldData.getString(FIELD_TICKER); final String coupon = fieldData.getString(FIELD_CPN); final String maturity = fieldData.getString(FIELD_MATURITY); final String marketSector = fieldData.getString(FIELD_MARKET_SECTOR_DES); final String parsekyableDes = fieldData.getString(FIELD_PARSEKYABLE_DES); final String idBbSecNumDes = fieldData.getString(FIELD_ID_BB_SEC_NUM_DES); final Set<ExternalId> identifiers = new HashSet<ExternalId>(); if (isValidField(bbgUnique)) { identifiers.add(ExternalSchemes.bloombergBuidSecurityId(bbgUnique)); security.setUniqueId(BloombergSecurityProvider.createUniqueId(bbgUnique)); } if (isValidField(cusip)) { identifiers.add(ExternalSchemes.cusipSecurityId(cusip)); } if (isValidField(sedol1)) { identifiers.add(ExternalSchemes.sedol1SecurityId(sedol1)); } if (isValidField(isin)) { identifiers.add(ExternalSchemes.isinSecurityId(isin)); } if (isValidField(idBbSecNumDes) && isValidField(marketSector)) { identifiers.add(ExternalSchemes.bloombergTickerSecurityId(idBbSecNumDes.replaceAll("\\s+", " ").concat(" ").concat(marketSector.trim()))); } else if (isValidField(parsekyableDes)) { s_logger.warn("For {} Could not find valid field BB_SEC_NUM_DES and/or MARKET_SECTOR " + "(essentially the Ticker, coupon, maturity + yellow key) so falling back to PARSEKYABLE_DES. " + " This may mean bond future baskets won't link to the underlying correctly as they are in the TCM format.", parsekyableDes); identifiers.add(ExternalSchemes.bloombergTickerSecurityId(parsekyableDes.replaceAll("\\s+", " "))); } if (isValidField(ticker) && isValidField(coupon) && isValidField(maturity) && isValidField(marketSector)) { try { identifiers.add(ExternalSchemes.bloombergTCMSecurityId(ticker, coupon, maturity, marketSector)); } catch (final Exception e) { s_logger.warn("Couldn't add Bloomberg TCM to bond", e); } } security.setExternalIdBundle(ExternalIdBundle.of(identifiers)); } @Override protected Set<String> getBloombergFields() { return BLOOMBERG_BOND_FIELDS; } }