/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.financial.analytics.volatility.surface;
import org.threeten.bp.LocalDate;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.core.id.ExternalSchemes;
import com.opengamma.financial.analytics.volatility.surface.BloombergFXOptionVolatilitySurfaceInstrumentProvider.FXVolQuoteType;
import com.opengamma.id.ExternalId;
import com.opengamma.id.ExternalScheme;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.time.Tenor;
import com.opengamma.util.tuple.Pair;
/**
* Autogenerates Tullett-Prebon FX option volatility surface codes given a tenor, quote type (ATM, butterfly, risk reversal) and distance from
* ATM.
*/
public class TullettPrebonFXOptionVolatilitySurfaceInstrumentProvider implements SurfaceInstrumentProvider<Tenor, Pair<Number, FXVolQuoteType>> {
/** The Tullett-Prebon scheme */
private static final ExternalScheme SCHEME = ExternalSchemes.SURF;
/** The prefix */
private final String _fxPrefix; //expecting something like FV
/** The currency pair */
private final String _ccyPair; // expecting something like USDJPY
/** The data field name */
private final String _dataFieldName;
/**
* @param fxPrefix The code prefix, not null
* @param ccyPair The currency pair, not null
* @param dataFieldName The data field name, not null
*/
public TullettPrebonFXOptionVolatilitySurfaceInstrumentProvider(final String fxPrefix, final String ccyPair, final String dataFieldName) {
ArgumentChecker.notNull(fxPrefix, "fx prefix");
ArgumentChecker.notNull(ccyPair, "currency pair");
ArgumentChecker.notNull(dataFieldName, "data field name");
_fxPrefix = fxPrefix;
_ccyPair = ccyPair;
_dataFieldName = dataFieldName;
}
/**
* Gets the code prefix.
* @return The code prefix
*/
public String getFXPrefix() {
return _fxPrefix;
}
/**
* Gets the currency pair.
* @return The currency pair
*/
public String getCurrencyPair() {
return _ccyPair;
}
@Override
public String getDataFieldName() {
return _dataFieldName;
}
@Override
public ExternalId getInstrument(final Tenor tenor, final Pair<Number, FXVolQuoteType> volDeltaQuoteType) {
return createFXVolatilityCode(tenor, volDeltaQuoteType);
}
@Override
public ExternalId getInstrument(final Tenor tenor, final Pair<Number, FXVolQuoteType> volDeltaQuoteType, final LocalDate surfaceDate) {
return createFXVolatilityCode(tenor, volDeltaQuoteType);
}
private ExternalId createFXVolatilityCode(final Tenor tenor, final Pair<Number, FXVolQuoteType> volDeltaQuoteType) {
final StringBuffer surf = new StringBuffer();
surf.append(getFXPrefix());
final int delta = volDeltaQuoteType.getFirst().intValue();
final FXVolQuoteType quoteType = volDeltaQuoteType.getSecond();
if (delta == 0) {
if (quoteType == FXVolQuoteType.ATM) {
surf.append("AFV");
} else {
throw new OpenGammaRuntimeException("Asked for an ATM code with non-zero delta");
}
} else {
switch (quoteType) {
case ATM:
throw new OpenGammaRuntimeException("Asked for an ATM code with non-zero delta");
case RISK_REVERSAL:
surf.append(delta / 10); // 10 = 1, 25 = 2
surf.append("DR");
break;
case BUTTERFLY:
surf.append(delta / 10); // 10 = 1, 25 = 2;
surf.append("DB");
break;
default:
throw new OpenGammaRuntimeException("Should never happen - have all quote types in enum");
}
}
surf.append(getCurrencyPair());
//TODO I'm sure this isn't the best way to do this
if (tenor.getPeriod().getYears() != 0) {
if (tenor.getPeriod().getYears() < 3) {
surf.append(String.format("%02d", tenor.getPeriod().getYears() * 12));
surf.append("M");
} else {
surf.append(String.format("%02d", tenor.getPeriod().getYears()));
surf.append("Y");
}
} else if (tenor.getPeriod().getMonths() != 0) {
surf.append(String.format("%02d", tenor.getPeriod().getMonths()));
surf.append("M");
} else if (tenor.getPeriod().getDays() != 0 && tenor.getPeriod().getDays() % 7 == 0) {
surf.append(String.format("%02d", tenor.getPeriod().getDays() / 7));
surf.append("W");
} else {
throw new OpenGammaRuntimeException("Can only handle periods of year, month and week");
}
return ExternalId.of(SCHEME, surf.toString());
}
@Override
public int hashCode() {
return getFXPrefix().hashCode() + getCurrencyPair().hashCode() + getDataFieldName().hashCode();
}
@Override
public boolean equals(final Object obj) {
if (obj == null) {
return false;
}
if (!(obj instanceof TullettPrebonFXOptionVolatilitySurfaceInstrumentProvider)) {
return false;
}
final TullettPrebonFXOptionVolatilitySurfaceInstrumentProvider other = (TullettPrebonFXOptionVolatilitySurfaceInstrumentProvider) obj;
return getFXPrefix().equals(other.getFXPrefix()) &&
getCurrencyPair().equals(other.getCurrencyPair()) &&
getDataFieldName().equals(other.getDataFieldName());
}
}