/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.bbg.loader;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import org.fudgemsg.FudgeMsg;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.BiMap;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.opengamma.bbg.BloombergConstants;
import com.opengamma.bbg.referencedata.ReferenceDataProvider;
import com.opengamma.bbg.util.BloombergDataUtils;
import com.opengamma.bbg.util.ReferenceDataProviderUtils;
import com.opengamma.id.ExternalIdBundle;
import com.opengamma.master.security.ManageableSecurity;
import com.opengamma.util.ArgumentChecker;
/**
* Maps Bloomberg security type and futures category to subclasses of {@link ManageableSecurity}
*/
public class BloombergSecurityTypeResolver implements SecurityTypeResolver {
/** Logger. */
private static final Logger s_logger = LoggerFactory.getLogger(BloombergSecurityTypeResolver.class);
private static final Map<String, SecurityType> s_futureTypes = Maps.newConcurrentMap();
static {
addValidTypes(s_futureTypes, AgricultureFutureLoader.VALID_FUTURE_CATEGORIES, SecurityType.AGRICULTURE_FUTURE);
addValidTypes(s_futureTypes, BondFutureLoader.VALID_FUTURE_CATEGORIES, SecurityType.BOND_FUTURE);
addValidTypes(s_futureTypes, EnergyFutureLoader.VALID_FUTURE_CATEGORIES, SecurityType.ENERGY_FUTURE);
addValidTypes(s_futureTypes, EquityDividendFutureLoader.VALID_FUTURE_CATEGORIES, SecurityType.EQUITY_DIVIDEND_FUTURE);
addValidTypes(s_futureTypes, FXFutureLoader.VALID_FUTURE_CATEGORIES, SecurityType.FX_FUTURE);
addValidTypes(s_futureTypes, IndexFutureLoader.VALID_FUTURE_CATEGORIES, SecurityType.INDEX_FUTURE);
addValidTypes(s_futureTypes, InterestRateFutureLoader.VALID_FUTURE_CATEGORIES, SecurityType.INTEREST_RATE_FUTURE);
addValidTypes(s_futureTypes, MetalFutureLoader.VALID_FUTURE_CATEGORIES, SecurityType.METAL_FUTURE);
//types for EquityFutureSecurity
addValidTypes(s_futureTypes, EquityFutureLoader.VALID_SECURITY_TYPES, SecurityType.EQUITY_FUTURE);
}
private static final Map<String, SecurityType> s_optionTypes = Maps.newConcurrentMap();
static {
addValidTypes(s_optionTypes, EquityOptionLoader.VALID_SECURITY_TYPES, SecurityType.EQUITY_OPTION);
addValidTypes(s_optionTypes, EquityIndexOptionLoader.VALID_SECURITY_TYPES, SecurityType.EQUITY_INDEX_OPTION);
addValidTypes(s_optionTypes, EquityIndexFutureOptionLoader.VALID_SECURITY_TYPES, SecurityType.EQUITY_INDEX_FUTURE_OPTION);
addValidTypes(s_optionTypes, IRFutureOptionLoader.VALID_SECURITY_TYPES, SecurityType.IR_FUTURE_OPTION);
addValidTypes(s_optionTypes, BondFutureOptionLoader.VALID_SECURITY_TYPES, SecurityType.BOND_FUTURE_OPTION);
addValidTypes(s_optionTypes, CommodityFutureOptionLoader.VALID_SECURITY_TYPES, SecurityType.COMMODITY_FUTURE_OPTION);
addValidTypes(s_optionTypes, FxFutureOptionLoader.VALID_SECURITY_TYPES, SecurityType.FX_FUTURE_OPTION);
}
private static final Map<String, SecurityType> s_swapTypes = Maps.newConcurrentMap();
static {
addValidTypes(s_swapTypes, NonLoadedSecurityTypes.VALID_SWAP_SECURITY_TYPES, SecurityType.SWAP);
addValidTypes(s_swapTypes, NonLoadedSecurityTypes.VALID_BASIS_SWAP_SECURITY_TYPES, SecurityType.BASIS_SWAP);
addValidTypes(s_swapTypes, NonLoadedSecurityTypes.VALID_INFLATION_SWAP_TYPES, SecurityType.INFLATION_SWAP);
}
private static final Map<String, SecurityType> s_miscTypes = Maps.newConcurrentMap();
static {
addValidTypes(s_miscTypes, EquityLoader.VALID_SECURITY_TYPES, SecurityType.EQUITY);
addValidTypes(s_miscTypes, BondLoader.VALID_SECURITY_TYPES, SecurityType.BOND);
addValidTypes(s_miscTypes, NonLoadedSecurityTypes.VALID_EQUITY_INDEX_SECURITY_TYPES, SecurityType.EQUITY_INDEX);
addValidTypes(s_miscTypes, NonLoadedSecurityTypes.VALID_FORWARD_CROSS_SECURITY_TYPES, SecurityType.FORWARD_CROSS);
addValidTypes(s_miscTypes, NonLoadedSecurityTypes.VALID_FRA_SECURITY_TYPES, SecurityType.FRA);
addValidTypes(s_miscTypes, IndexLoader.VALID_SECURITY_TYPES, SecurityType.INDEX);
addValidTypes(s_miscTypes, NonLoadedSecurityTypes.VALID_RATE_TYPES, SecurityType.RATE);
addValidTypes(s_miscTypes, NonLoadedSecurityTypes.VALID_SPOT_RATE_TYPES, SecurityType.SPOT_RATE);
addValidTypes(s_miscTypes, NonLoadedSecurityTypes.VALID_VOLATILITY_QUOTE_TYPES, SecurityType.VOLATILITY_QUOTE);
addValidTypes(s_miscTypes, NonLoadedSecurityTypes.VALID_FX_FORWARD_TYPES, SecurityType.FX_FORWARD);
}
private static final Map<String, SecurityType> s_type2Types = Maps.newConcurrentMap();
static {
addValidTypes(s_type2Types, BillLoader.VALID_SECURITY_TYPES2, SecurityType.BILL);
}
//private static final Map<String, SecurityType> s_cdsTypes = Maps.newConcurrentMap();
static {
addValidTypes(s_swapTypes, NonLoadedSecurityTypes.VALID_CDS_TYPES, SecurityType.CREDIT_DEFAULT_SWAP);
}
private static final Set<String> BBG_FIELDS = Sets.newHashSet(BloombergConstants.FIELD_SECURITY_TYPE, BloombergConstants.FIELD_FUTURES_CATEGORY, BloombergConstants.FIELD_NAME,
BloombergConstants.FIELD_SECURITY_TYPE2);
private final ReferenceDataProvider _referenceDataProvider;
/**
* Creates a BloombergSecurityTypeResolver
*
* @param referenceDataProvider the reference data provider, not null
*/
public BloombergSecurityTypeResolver(final ReferenceDataProvider referenceDataProvider) {
ArgumentChecker.notNull(referenceDataProvider, "referenceDataProvider");
_referenceDataProvider = referenceDataProvider;
}
@Override
public Map<ExternalIdBundle, SecurityType> getSecurityType(final Collection<ExternalIdBundle> identifiers) {
ArgumentChecker.notNull(identifiers, "identifiers");
final Map<ExternalIdBundle, SecurityType> result = Maps.newHashMap();
final BiMap<String, ExternalIdBundle> bundle2Bbgkey = BloombergDataUtils.convertToBloombergBuidKeys(identifiers, _referenceDataProvider);
final Map<String, FudgeMsg> securityTypeResult = ReferenceDataProviderUtils.getFields(bundle2Bbgkey.keySet(), BBG_FIELDS, _referenceDataProvider);
for (final ExternalIdBundle identifierBundle : identifiers) {
final String bbgKey = bundle2Bbgkey.inverse().get(identifierBundle);
if (bbgKey != null) {
final FudgeMsg fudgeMsg = securityTypeResult.get(bbgKey);
if (fudgeMsg != null) {
final String bbgSecurityType = fudgeMsg.getString(BloombergConstants.FIELD_SECURITY_TYPE);
final String bbgSecurityType2 = fudgeMsg.getString(BloombergConstants.FIELD_SECURITY_TYPE2);
final String futureCategory = fudgeMsg.getString(BloombergConstants.FIELD_FUTURES_CATEGORY);
SecurityType securityType = null;
if (bbgSecurityType != null) {
if (bbgSecurityType.toUpperCase().contains(" FUTURE")) {
s_logger.debug("s_futureTypes {}", s_futureTypes);
securityType = s_futureTypes.get(futureCategory);
} else if (bbgSecurityType.toUpperCase().contains(" OPTION")) {
// Special case handling for EQUITY_INDEX_DIVIDEND_FUTURE_OPTION which we
// are otherwise unable to distinguish from EQUITY_INDEX_FUTURE_OPTION
final String name = fudgeMsg.getString(BloombergConstants.FIELD_NAME);
securityType = isEquityIndexFutureDividendOption(futureCategory, name) ?
SecurityType.EQUITY_INDEX_DIVIDEND_FUTURE_OPTION :
s_optionTypes.get(futureCategory);
} else if (bbgSecurityType.toUpperCase().endsWith("SWAP")) {
securityType = s_swapTypes.get(bbgSecurityType);
} else if (bbgSecurityType2 != null && bbgSecurityType2.toUpperCase().contains("BILL")) {
securityType = s_type2Types.get(bbgSecurityType2);
} else {
securityType = s_miscTypes.get(bbgSecurityType);
}
}
if (securityType != null) {
result.put(identifierBundle, securityType);
} else {
s_logger.warn("Unknown security type of {} for {}", bbgSecurityType, identifierBundle);
}
}
}
}
return result;
}
private boolean isEquityIndexFutureDividendOption(final String futureCategory, final String name) {
return name != null && "Equity Index".equals(futureCategory) && name.toUpperCase().contains("DIVIDEND");
}
private static void addValidTypes(final Map<String, SecurityType> sFuturetypes, final Set<String> validSecurityTypes, final SecurityType securityType) {
for (final String bbgSecType : validSecurityTypes) {
sFuturetypes.put(bbgSecType, securityType);
}
}
public ReferenceDataProvider getReferenceDataProvider() {
return _referenceDataProvider;
}
}