/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.financial.analytics.ircurve;
import org.threeten.bp.LocalDate;
import org.threeten.bp.Month;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.core.id.ExternalSchemes;
import com.opengamma.core.value.MarketDataRequirementNames;
import com.opengamma.financial.analytics.ircurve.strips.DataFieldType;
import com.opengamma.financial.analytics.volatility.surface.BloombergFutureUtils;
import com.opengamma.id.ExternalId;
import com.opengamma.id.ExternalScheme;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.time.Tenor;
/**
* Provides market data ids for quarterly or monthly futures.
*/
public class BloombergFutureCurveInstrumentProvider implements CurveInstrumentProvider {
/** The external scheme for the tickers */
private static final ExternalScheme SCHEME = ExternalSchemes.BLOOMBERG_TICKER;
/** Bloomberg month codes for futures */
private static BiMap<Month, Character> s_monthCode;
/** The future prefix */
private final String _futurePrefix;
/** The market sector postfix */
private final String _marketSector;
/** The market data field */
private final String _dataField;
/** The data field type */
private final DataFieldType _fieldType;
static {
s_monthCode = HashBiMap.create();
s_monthCode.put(Month.JANUARY, 'F');
s_monthCode.put(Month.FEBRUARY, 'G');
s_monthCode.put(Month.MARCH, 'H');
s_monthCode.put(Month.APRIL, 'J');
s_monthCode.put(Month.MAY, 'K');
s_monthCode.put(Month.JUNE, 'M');
s_monthCode.put(Month.JULY, 'N');
s_monthCode.put(Month.AUGUST, 'Q');
s_monthCode.put(Month.SEPTEMBER, 'U');
s_monthCode.put(Month.OCTOBER, 'V');
s_monthCode.put(Month.NOVEMBER, 'X');
s_monthCode.put(Month.DECEMBER, 'Z');
}
/**
* Sets the market data field to {@link MarketDataRequirementNames#MARKET_VALUE}
* @param futurePrefix The future prefix, not null
* @param marketSector The market sector postfix, not null
*/
public BloombergFutureCurveInstrumentProvider(final String futurePrefix, final String marketSector) {
this(futurePrefix, marketSector, MarketDataRequirementNames.MARKET_VALUE, DataFieldType.OUTRIGHT);
}
/**
* @param futurePrefix The future prefix, not null
* @param marketSector The market sector postfix, not null
* @param dataField The market data field, not null
* @param fieldType The data field type, not null
*/
public BloombergFutureCurveInstrumentProvider(final String futurePrefix, final String marketSector,
final String dataField, final DataFieldType fieldType) {
ArgumentChecker.notNull(futurePrefix, "future prefix");
ArgumentChecker.notNull(marketSector, "market sector");
ArgumentChecker.notNull(dataField, "data field");
ArgumentChecker.notNull(fieldType, "field type");
_futurePrefix = futurePrefix;
_marketSector = marketSector;
_dataField = dataField;
_fieldType = fieldType;
}
@Override
public ExternalId getInstrument(final LocalDate curveDate, final Tenor tenor) {
throw new OpenGammaRuntimeException("Only futures supported");
}
@Override
public ExternalId getInstrument(final LocalDate curveDate, final Tenor tenor, final int periodsPerYear, final boolean isPeriodicZeroDeposit) {
throw new OpenGammaRuntimeException("Only futures supported");
}
@Override
public ExternalId getInstrument(final LocalDate curveDate, final Tenor tenor, final int numQuarterlyFuturesFromTenor) {
return createQuarterlyIRFutureStrips(curveDate, tenor, numQuarterlyFuturesFromTenor, _futurePrefix, " " + _marketSector);
}
@Override
public ExternalId getInstrument(final LocalDate curveDate, final Tenor startTenor, final Tenor futureTenor, final int numFuturesFromTenor) {
//TODO there must be a more elegant way to do this
if (futureTenor.equals(Tenor.THREE_MONTHS)) {
return createQuarterlyIRFutureStrips(curveDate, startTenor, numFuturesFromTenor, _futurePrefix, " " + _marketSector);
} else if (futureTenor.equals(Tenor.ONE_MONTH)) {
return createMonthlyIRFutureStrips(curveDate, startTenor, numFuturesFromTenor, _futurePrefix, " " + _marketSector);
}
throw new OpenGammaRuntimeException("Can only create ids for quarterly or monthly tenors");
}
@Override
public ExternalId getInstrument(final LocalDate curveDate, final Tenor tenor, final Tenor payTenor, final Tenor receiveTenor, final IndexType payIndexType,
final IndexType receiveIndexType) {
throw new OpenGammaRuntimeException("Only futures supported");
}
@Override
public ExternalId getInstrument(final LocalDate curveDate, final Tenor tenor, final Tenor resetTenor, final IndexType indexType) {
throw new OpenGammaRuntimeException("Only futures supported");
}
@Override
public ExternalId getInstrument(final LocalDate curveDate, final Tenor startTenor, final int startIMMPeriods, final int endIMMPeriods) {
throw new UnsupportedOperationException("Only futures supported");
}
@Override
public String getMarketDataField() {
return _dataField;
}
@Override
public DataFieldType getDataFieldType() {
return _fieldType;
}
private ExternalId createQuarterlyIRFutureStrips(final LocalDate curveDate, final Tenor tenor, final int numQuartlyFuturesFromTenor, final String prefix, final String postfix) {
final StringBuilder futureCode = new StringBuilder();
futureCode.append(prefix);
final LocalDate curveFutureStartDate = curveDate.plus(tenor.getPeriod());
final String expiryCode = BloombergFutureUtils.getQuarterlyExpiryCodeForFutures(prefix, numQuartlyFuturesFromTenor, curveFutureStartDate);
futureCode.append(expiryCode);
futureCode.append(postfix);
return ExternalId.of(SCHEME, futureCode.toString());
}
private ExternalId createMonthlyIRFutureStrips(final LocalDate curveDate, final Tenor tenor, final int numMonthlyFuturesFromTenor, final String prefix, final String postfix) {
final StringBuilder futureCode = new StringBuilder();
futureCode.append(prefix);
final LocalDate curveFutureStartDate = curveDate.plus(tenor.getPeriod());
final String expiryCode = BloombergFutureUtils.getMonthlyExpiryCodeForFutures(prefix, numMonthlyFuturesFromTenor, curveFutureStartDate);
futureCode.append(expiryCode);
futureCode.append(postfix);
return ExternalId.of(SCHEME, futureCode.toString());
}
/**
* Gets the future prefix.
* @return The future prefix
*/
public String getFuturePrefix() {
return _futurePrefix;
}
/**
* Gets the market sector postfix.
* @return The market sector postfix
*/
public String getMarketSector() {
return _marketSector;
}
@Override
public boolean equals(final Object o) {
if (o == null) {
return false;
}
if (!(o instanceof BloombergFutureCurveInstrumentProvider)) {
return false;
}
final BloombergFutureCurveInstrumentProvider other = (BloombergFutureCurveInstrumentProvider) o;
return getFuturePrefix().equals(other.getFuturePrefix()) &&
getMarketSector().equals(other.getMarketSector()) &&
getMarketDataField().equals(other.getMarketDataField()) &&
getDataFieldType() == other.getDataFieldType();
}
@Override
public int hashCode() {
return getFuturePrefix().hashCode() ^ getMarketSector().hashCode() ^ getMarketDataField().hashCode()
^ getDataFieldType().hashCode() * (2 ^ 16);
}
}