/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.instrument.volatilityswap;
import static org.testng.AssertJUnit.assertEquals;
import static org.testng.AssertJUnit.assertFalse;
import org.testng.annotations.Test;
import org.threeten.bp.ZoneId;
import org.threeten.bp.ZonedDateTime;
import com.opengamma.AnalyticsTestBase;
import com.opengamma.analytics.financial.instrument.cash.CashDefinition;
import com.opengamma.analytics.financial.schedule.NoHolidayCalendar;
import com.opengamma.analytics.financial.volatilityswap.FXVolatilitySwap;
import com.opengamma.financial.convention.calendar.Calendar;
import com.opengamma.financial.convention.calendar.MondayToFridayCalendar;
import com.opengamma.financial.convention.frequency.PeriodFrequency;
import com.opengamma.util.money.Currency;
import com.opengamma.util.test.TestGroup;
/**
* Tests the volatility swap definition object.
*/
@Test(groups = TestGroup.UNIT)
public class FXVolatilitySwapDefinitionTest extends AnalyticsTestBase {
/** The current date */
private static final ZonedDateTime NOW = ZonedDateTime.of(2014, 02, 27, 12, 0, 0, 0, ZoneId.of("UTC"));
/** The settlement date */
private static final ZonedDateTime T_PLUS_2D = NOW.plusDays(2);
/** The maturity date */
private static final ZonedDateTime T_PLUS_5Y = NOW.plusYears(5);
/** The observation frequency */
private static final PeriodFrequency OBSERVATION_FREQUENCY = PeriodFrequency.DAILY;
/** The currency */
private static final Currency CCY = Currency.EUR;
/** The base currency */
private static final Currency BASE = Currency.EUR;
/** The counter currency */
private static final Currency COUNTER = Currency.USD;
/** The calendar */
private static final Calendar WEEKENDS = new MondayToFridayCalendar("WEEKEND");
/** The number of observations per year */
private static final double OBS_PER_YEAR = 250;
/** The volatility strike */
private static final double VOL_STRIKE = 0.25;
/** The volatility notional */
private static final double VOL_NOTIONAL = 1.0E6;
/** A Volatility swap definition */
private static final FXVolatilitySwapDefinition DEFINITION = new FXVolatilitySwapDefinition(CCY, BASE, COUNTER, VOL_STRIKE, VOL_NOTIONAL, T_PLUS_2D, T_PLUS_5Y,
T_PLUS_2D, T_PLUS_5Y, OBSERVATION_FREQUENCY, OBS_PER_YEAR, WEEKENDS);
/**
* @throws Exception If a FX volatility swap definition cannot be created from the inputs
*/
private FXVolatilitySwapDefinitionTest() throws Exception {
super(FXVolatilitySwapDefinition.class,
new Object[] {CCY, BASE, COUNTER, VOL_STRIKE, VOL_NOTIONAL, T_PLUS_2D, T_PLUS_5Y, NOW, T_PLUS_5Y, OBSERVATION_FREQUENCY, OBS_PER_YEAR, WEEKENDS },
new Class[] {Currency.class, Currency.class, Currency.class, double.class, double.class,
ZonedDateTime.class, ZonedDateTime.class, ZonedDateTime.class, ZonedDateTime.class, PeriodFrequency.class, double.class, Calendar.class },
new boolean[] {true, true, true, false, false, true, true, true, true, true, false, true });
}
/**
* Tests the getters.
*/
@Test
public void testGetters() {
assertEquals(OBS_PER_YEAR, DEFINITION.getAnnualizationFactor());
assertEquals(WEEKENDS, DEFINITION.getCalendar());
assertEquals(CCY, DEFINITION.getCurrency());
assertEquals(T_PLUS_5Y, DEFINITION.getObservationEndDate());
assertEquals(1303, DEFINITION.getNumberOfObservationsExpected());
assertEquals(OBSERVATION_FREQUENCY, DEFINITION.getObservationFrequency());
assertEquals(T_PLUS_2D, DEFINITION.getObservationStartDate());
assertEquals(T_PLUS_2D, DEFINITION.getEffectiveDate());
assertEquals(T_PLUS_5Y, DEFINITION.getMaturityDate());
assertEquals(VOL_NOTIONAL, DEFINITION.getVolatilityNotional());
assertEquals(VOL_STRIKE, DEFINITION.getVolatilityStrike());
assertEquals(BASE, DEFINITION.getBaseCurrency());
assertEquals(COUNTER, DEFINITION.getCounterCurrency());
}
/**
* Tests the hashcode and equals methods.
*/
@Test
public void testHashCodeEquals() {
FXVolatilitySwapDefinition other = new FXVolatilitySwapDefinition(CCY, BASE, COUNTER, VOL_STRIKE, VOL_NOTIONAL, T_PLUS_2D, T_PLUS_5Y,
T_PLUS_2D, T_PLUS_5Y, OBSERVATION_FREQUENCY, OBS_PER_YEAR, WEEKENDS);
assertEquals(DEFINITION, DEFINITION);
assertEquals(DEFINITION, other);
assertEquals(DEFINITION.hashCode(), other.hashCode());
assertFalse(DEFINITION.equals(null));
assertFalse(DEFINITION.equals(new CashDefinition(CCY, NOW, T_PLUS_5Y, VOL_NOTIONAL, VOL_STRIKE, 5)));
other = new FXVolatilitySwapDefinition(Currency.USD, BASE, COUNTER, VOL_STRIKE, VOL_NOTIONAL, T_PLUS_2D, T_PLUS_5Y,
T_PLUS_2D, T_PLUS_5Y, OBSERVATION_FREQUENCY, OBS_PER_YEAR, WEEKENDS);
assertFalse(other.equals(DEFINITION));
other = new FXVolatilitySwapDefinition(CCY, BASE, COUNTER, VOL_STRIKE + 0.01, VOL_NOTIONAL, T_PLUS_2D, T_PLUS_5Y,
T_PLUS_2D, T_PLUS_5Y, OBSERVATION_FREQUENCY, OBS_PER_YEAR, WEEKENDS);
assertFalse(other.equals(DEFINITION));
other = new FXVolatilitySwapDefinition(CCY, Currency.AUD, COUNTER, VOL_STRIKE, VOL_NOTIONAL, T_PLUS_2D, T_PLUS_5Y,
T_PLUS_2D, T_PLUS_5Y, OBSERVATION_FREQUENCY, OBS_PER_YEAR, WEEKENDS);
assertFalse(other.equals(DEFINITION));
other = new FXVolatilitySwapDefinition(CCY, BASE, Currency.AUD, VOL_STRIKE, VOL_NOTIONAL, T_PLUS_2D, T_PLUS_5Y,
T_PLUS_2D, T_PLUS_5Y, OBSERVATION_FREQUENCY, OBS_PER_YEAR, WEEKENDS);
assertFalse(other.equals(DEFINITION));
other = new FXVolatilitySwapDefinition(CCY, BASE, COUNTER, VOL_STRIKE, VOL_NOTIONAL * 10, T_PLUS_2D, T_PLUS_5Y,
T_PLUS_2D, T_PLUS_5Y, OBSERVATION_FREQUENCY, OBS_PER_YEAR, WEEKENDS);
assertFalse(other.equals(DEFINITION));
other = new FXVolatilitySwapDefinition(CCY, BASE, COUNTER, VOL_STRIKE, VOL_NOTIONAL, T_PLUS_2D.plusDays(1), T_PLUS_5Y,
T_PLUS_2D, T_PLUS_5Y, OBSERVATION_FREQUENCY, OBS_PER_YEAR, WEEKENDS);
assertFalse(other.equals(DEFINITION));
other = new FXVolatilitySwapDefinition(CCY, BASE, COUNTER, VOL_STRIKE, VOL_NOTIONAL, T_PLUS_2D, T_PLUS_5Y.plusDays(1),
T_PLUS_2D, T_PLUS_5Y, OBSERVATION_FREQUENCY, OBS_PER_YEAR, WEEKENDS);
assertFalse(other.equals(DEFINITION));
other = new FXVolatilitySwapDefinition(CCY, BASE, COUNTER, VOL_STRIKE, VOL_NOTIONAL, T_PLUS_2D, T_PLUS_5Y,
T_PLUS_2D.plusDays(1), T_PLUS_5Y, OBSERVATION_FREQUENCY, OBS_PER_YEAR, WEEKENDS);
assertFalse(other.equals(DEFINITION));
other = new FXVolatilitySwapDefinition(CCY, BASE, COUNTER, VOL_STRIKE, VOL_NOTIONAL, T_PLUS_2D, T_PLUS_5Y,
T_PLUS_2D, T_PLUS_5Y.plusDays(1), OBSERVATION_FREQUENCY, OBS_PER_YEAR, WEEKENDS);
assertFalse(other.equals(DEFINITION));
other = new FXVolatilitySwapDefinition(CCY, BASE, COUNTER, VOL_STRIKE, VOL_NOTIONAL, T_PLUS_2D, T_PLUS_5Y,
T_PLUS_2D, T_PLUS_5Y, OBSERVATION_FREQUENCY, OBS_PER_YEAR + 1, WEEKENDS);
assertFalse(other.equals(DEFINITION));
other = new FXVolatilitySwapDefinition(CCY, BASE, COUNTER, VOL_STRIKE, VOL_NOTIONAL, T_PLUS_2D, T_PLUS_5Y,
T_PLUS_2D, T_PLUS_5Y, OBSERVATION_FREQUENCY, OBS_PER_YEAR, new NoHolidayCalendar());
assertFalse(other.equals(DEFINITION));
}
/**
* Tests creation of a forward-starting volatility swap derivative
*/
@SuppressWarnings("deprecation")
@Test
public void testForwardStarting() {
final FXVolatilitySwap volatilitySwap = DEFINITION.toDerivative(NOW);
assertEquals(OBS_PER_YEAR, volatilitySwap.getAnnualizationFactor());
assertEquals(CCY, volatilitySwap.getCurrency());
assertEquals(5.174603174603175, volatilitySwap.getTimeToObservationEnd(), 1.e-12);
assertEquals(2. / 252, volatilitySwap.getTimeToObservationStart(), 0);
assertEquals(OBSERVATION_FREQUENCY, volatilitySwap.getObservationFrequency());
assertEquals(5.174603174603175, volatilitySwap.getTimeToMaturity(), 1.e-12);
assertEquals(VOL_NOTIONAL, volatilitySwap.getVolatilityNotional(), 1.e-12);
assertEquals(VOL_STRIKE, volatilitySwap.getVolatilityStrike());
assertEquals(volatilitySwap, DEFINITION.toDerivative(NOW));
assertEquals(BASE, volatilitySwap.getBaseCurrency());
assertEquals(COUNTER, volatilitySwap.getCounterCurrency());
}
/**
* Tests creation of a seasoned volatility swap derivative
*/
@SuppressWarnings("deprecation")
@Test
public void testSeasoned() {
final FXVolatilitySwapDefinition definition = new FXVolatilitySwapDefinition(CCY, BASE, COUNTER, VOL_STRIKE, VOL_NOTIONAL, T_PLUS_2D, T_PLUS_5Y,
T_PLUS_2D, T_PLUS_5Y, OBSERVATION_FREQUENCY, OBS_PER_YEAR, new NoHolidayCalendar());
final FXVolatilitySwap volatilitySwap = definition.toDerivative(NOW.plusYears(1));
assertEquals(OBS_PER_YEAR, volatilitySwap.getAnnualizationFactor());
assertEquals(CCY, volatilitySwap.getCurrency());
assertEquals(5.7976190476190474, volatilitySwap.getTimeToObservationEnd(), 1.e-12);
assertEquals(-1.4404761904761905, volatilitySwap.getTimeToObservationStart(), 1.e-12);
assertEquals(OBSERVATION_FREQUENCY, volatilitySwap.getObservationFrequency());
assertEquals(5.7976190476190474, volatilitySwap.getTimeToMaturity(), 1.e-12);
assertEquals(VOL_NOTIONAL, volatilitySwap.getVolatilityNotional());
assertEquals(VOL_STRIKE, volatilitySwap.getVolatilityStrike(), 0);
assertEquals(BASE, volatilitySwap.getBaseCurrency());
assertEquals(COUNTER, volatilitySwap.getCounterCurrency());
}
/**
* Tests expected failure for observation frequencies other than daily
*/
@Test(expectedExceptions = IllegalArgumentException.class)
public void testWeeklyObservations() {
final PeriodFrequency freqWeek = PeriodFrequency.WEEKLY;
new FXVolatilitySwapDefinition(CCY, BASE, COUNTER, VOL_STRIKE, VOL_NOTIONAL, T_PLUS_2D, T_PLUS_5Y, T_PLUS_2D, T_PLUS_5Y, freqWeek, OBS_PER_YEAR, WEEKENDS);
}
/**
* Tests that the base and counter currency are different.
*/
@Test(expectedExceptions = IllegalArgumentException.class)
public void testDifferentFXCurrencies() {
new FXVolatilitySwapDefinition(CCY, BASE, BASE, VOL_STRIKE, VOL_NOTIONAL, T_PLUS_2D, T_PLUS_5Y, T_PLUS_2D, T_PLUS_5Y, OBSERVATION_FREQUENCY, OBS_PER_YEAR, WEEKENDS);
}
}