/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.financial.analytics.ircurve;
import java.io.Serializable;
import org.apache.commons.lang.ObjectUtils;
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.model.irfutureoption.FutureOptionUtils;
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 synthetic futures.
*/
public class SyntheticFutureCurveInstrumentProvider implements CurveInstrumentProvider, Serializable {
/** The ticker scheme */
private static final ExternalScheme SCHEME = ExternalSchemes.OG_SYNTHETIC_TICKER;
/** The month codes */
private static final BiMap<Month, Character> MONTH_CODE;
/** The future prefix */
private final String _futurePrefix;
static {
MONTH_CODE = HashBiMap.create();
MONTH_CODE.put(Month.JANUARY, 'F');
MONTH_CODE.put(Month.FEBRUARY, 'G');
MONTH_CODE.put(Month.MARCH, 'H');
MONTH_CODE.put(Month.APRIL, 'J');
MONTH_CODE.put(Month.MAY, 'K');
MONTH_CODE.put(Month.JUNE, 'M');
MONTH_CODE.put(Month.JULY, 'N');
MONTH_CODE.put(Month.AUGUST, 'Q');
MONTH_CODE.put(Month.SEPTEMBER, 'U');
MONTH_CODE.put(Month.OCTOBER, 'V');
MONTH_CODE.put(Month.NOVEMBER, 'X');
MONTH_CODE.put(Month.DECEMBER, 'Z');
}
/**
* @param futurePrefix The future prefix, not null
*/
public SyntheticFutureCurveInstrumentProvider(final String futurePrefix) {
ArgumentChecker.notNull(futurePrefix, "future prefix");
_futurePrefix = futurePrefix;
}
@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 startTenor, final Tenor futureTenor, final int numFutureFromTenor) {
if (futureTenor.equals(Tenor.THREE_MONTHS)) {
return createQuarterlyIRFutureStrips(curveDate, startTenor, numFutureFromTenor, _futurePrefix);
} else if (futureTenor.equals(Tenor.ONE_MONTH)) {
return createMonthlyIRFutureStrips(curveDate, startTenor, numFutureFromTenor, _futurePrefix);
}
throw new OpenGammaRuntimeException("Can only create ids for quarterly or monthly tenors");
}
/**
* Gets the future prefix.
* @return The future prefix
*/
public String getFuturePrefix() {
return _futurePrefix;
}
@Override
public String getMarketDataField() {
return MarketDataRequirementNames.MARKET_VALUE;
}
@Override
public DataFieldType getDataFieldType() {
return DataFieldType.OUTRIGHT;
}
@Override
public ExternalId getInstrument(final LocalDate curveDate, final Tenor tenor, final int numQuarterlyFuturesFromTenor) {
return createQuarterlyIRFutureStrips(curveDate, tenor, numQuarterlyFuturesFromTenor, _futurePrefix);
}
@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 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");
}
private static ExternalId createQuarterlyIRFutureStrips(final LocalDate curveDate, final Tenor tenor, final int numQuartlyFuturesFromTenor, final String prefix) {
final StringBuilder futureCode = new StringBuilder();
futureCode.append(prefix);
final LocalDate curveFutureStartDate = curveDate.plus(tenor.getPeriod());
final String expiryCode = getQuarterlyExpiryCodeForFutures(numQuartlyFuturesFromTenor, curveFutureStartDate);
futureCode.append(expiryCode);
return ExternalId.of(SCHEME, futureCode.toString());
}
private static ExternalId createMonthlyIRFutureStrips(final LocalDate curveDate, final Tenor tenor, final int numMonthlyFuturesFromTenor, final String prefix) {
final StringBuilder futureCode = new StringBuilder();
futureCode.append(prefix);
final LocalDate curveFutureStartDate = curveDate.plus(tenor.getPeriod());
final String expiryCode = getMonthlyExpiryCodeForFutures(numMonthlyFuturesFromTenor, curveFutureStartDate);
futureCode.append(expiryCode);
return ExternalId.of(SCHEME, futureCode.toString());
}
private static String getQuarterlyExpiryCodeForFutures(final int nthFuture, final LocalDate curveDate) {
final LocalDate expiry = FutureOptionUtils.getApproximateIRFutureQuarterlyExpiry(nthFuture, curveDate);
final StringBuilder result = new StringBuilder(MONTH_CODE.get(expiry.getMonth()).toString());
result.append(expiry.getYear() % 1000);
return result.toString();
}
private static String getMonthlyExpiryCodeForFutures(final int nthFuture, final LocalDate curveDate) {
final LocalDate expiry = FutureOptionUtils.getApproximateIRFutureMonth(nthFuture, curveDate);
final StringBuilder result = new StringBuilder(MONTH_CODE.get(expiry.getMonth()));
result.append(expiry.getYear() % 1000);
return result.toString();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + _futurePrefix.hashCode();
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final SyntheticFutureCurveInstrumentProvider other = (SyntheticFutureCurveInstrumentProvider) obj;
return ObjectUtils.equals(_futurePrefix, other._futurePrefix);
}
}