/** Tests for interest rate future options analytics functions using the black calculator. */ @Test(groups = TestGroup.UNIT) public class IRFutureOptionFnTest { private static final ZonedDateTime VALUATION_TIME = DateUtils.getUTCDate(2014, 1, 22); public static final LocalDate TRADE_DATE = LocalDate.of(2000, 1, 1); public static final OffsetTime TRADE_TIME = OffsetTime.of(LocalTime.of(0, 0), ZoneOffset.UTC); private static final LocalDate MARKET_DATA_DATE = LocalDate.of(2014, 2, 18); private static final double STD_TOLERANCE_PV = 1.0E-3; private IRFutureOptionFn _blackIRFutureOptionFn; private IRFutureOptionFn _normalIRFutureOptionFn; private InterestRateFutureSecurity _irFuture = createIRFuture(); private IRFutureOptionTrade _irFutureOptionTrade = createIRFutureOptionTrade(); private FunctionRunner _functionRunner; private static final CalculationArguments ARGS = CalculationArguments.builder() .valuationTime(VALUATION_TIME) .marketDataSpecification(LiveMarketDataSpecification.LIVE_SPEC) .build(); private static final Interpolator1D LINEAR_FLAT = CombinedInterpolatorExtrapolatorFactory.getInterpolator( Interpolator1DFactory.LINEAR, Interpolator1DFactory.FLAT_EXTRAPOLATOR, Interpolator1DFactory.FLAT_EXTRAPOLATOR); private static final GridInterpolator2D INTERPOLATOR_2D = new GridInterpolator2D(LINEAR_FLAT, LINEAR_FLAT); private static final InterpolatedDoublesSurface TEST_SURFACE = InterpolatedDoublesSurface.from( new double[] {.1, .2, .3}, new double[] {.1, .2, .3}, new double[] {.1, .2, .3}, INTERPOLATOR_2D); private static MarketDataEnvironment createSuppliedData() { LocalDateDoubleTimeSeries optionPrice = ImmutableLocalDateDoubleTimeSeries.of(VALUATION_TIME.toLocalDate(), 0.975); RawId<Double> optionRawId = RawId.of(ExternalSchemes.syntheticSecurityId("Test future option").toBundle()); MarketDataEnvironmentBuilder builder = new MarketDataEnvironmentBuilder(); builder.add(optionRawId, optionPrice); builder.add(VolatilitySurfaceId.of("TestExchange"), new VolatilitySurface(TEST_SURFACE)); builder.valuationTime(VALUATION_TIME); return builder.build(); } @BeforeClass public void setUpClass() { ImmutableMap<Class<?>, Object> components = generateComponents(); VersionCorrectionProvider vcProvider = new FixedInstantVersionCorrectionProvider(Instant.now()); ServiceContext serviceContext = ServiceContext.of(components).with(VersionCorrectionProvider.class, vcProvider); ThreadLocalServiceContext.init(serviceContext); ComponentMap componentMap = ComponentMap.of(components); MarketDataSource marketDataSource = InterestRateMockSources.createMarketDataSource(MARKET_DATA_DATE, true); TestMarketDataFactory marketDataFactory = new TestMarketDataFactory(marketDataSource); ConfigLink<CurrencyMatrix> currencyMatrixLink = ConfigLink.resolved(componentMap.getComponent(CurrencyMatrix.class)); List<MarketDataBuilder> builders = MarketDataBuilders.standard(componentMap, "dataSource", currencyMatrixLink); MarketDataEnvironmentFactory environmentFactory = new MarketDataEnvironmentFactory(marketDataFactory, builders); _functionRunner = new FunctionRunner(environmentFactory); _normalIRFutureOptionFn = FunctionModel.build(IRFutureOptionFn.class, normalConfig(), componentMap); _blackIRFutureOptionFn = FunctionModel.build(IRFutureOptionFn.class, blackConfig(), componentMap); } private FunctionModelConfig blackConfig() { FunctionModelConfig config = config( arguments( function( MarketExposureSelector.class, argument( "exposureFunctions", ConfigLink.resolved(InterestRateMockSources.mockExposureFunctions()))), function( RootFinderConfiguration.class, argument("rootFinderAbsoluteTolerance", 1e-9), argument("rootFinderRelativeTolerance", 1e-9), argument("rootFinderMaxIterations", 1000)), function( DefaultCurveNodeConverterFn.class, argument("timeSeriesDuration", RetrievalPeriod.of(Period.ofYears(1))))), implementations( IRFutureOptionFn.class, DefaultIRFutureOptionFn.class, IRFutureOptionCalculatorFactory.class, IRFutureOptionBlackCalculatorFactory.class, CurveSpecificationMarketDataFn.class, DefaultCurveSpecificationMarketDataFn.class, FXMatrixFn.class, DefaultFXMatrixFn.class, BlackSTIRFuturesProviderFn.class, TestBlackSTIRFuturesProviderFn.class, DiscountingMulticurveCombinerFn.class, ExposureFunctionsDiscountingMulticurveCombinerFn.class, CurveDefinitionFn.class, DefaultCurveDefinitionFn.class, CurveLabellingFn.class, CurveDefinitionCurveLabellingFn.class, CurveSpecificationFn.class, DefaultCurveSpecificationFn.class, CurveConstructionConfigurationSource.class, ConfigDBCurveConstructionConfigurationSource.class, CurveNodeConverterFn.class, DefaultCurveNodeConverterFn.class, HistoricalMarketDataFn.class, DefaultHistoricalMarketDataFn.class, FixingsFn.class, DefaultFixingsFn.class, MarketDataFn.class, DefaultMarketDataFn.class, CurveSelector.class, MarketExposureSelector.class, DiscountingMulticurveCombinerFn.class, CurveSelectorMulticurveBundleFn.class)); return config; } private FunctionModelConfig normalConfig() { FunctionModelConfig config = config( arguments( function( MarketExposureSelector.class, argument( "exposureFunctions", ConfigLink.resolved(InterestRateMockSources.mockExposureFunctions()))), function( RootFinderConfiguration.class, argument("rootFinderAbsoluteTolerance", 1e-9), argument("rootFinderRelativeTolerance", 1e-9), argument("rootFinderMaxIterations", 1000)), function( TestIRFutureOptionNormalSurfaceProviderFn.class, argument("moneynessOnPrice", false)), function( DefaultCurveNodeConverterFn.class, argument("timeSeriesDuration", RetrievalPeriod.of(Period.ofYears(1))))), implementations( IRFutureOptionFn.class, DefaultIRFutureOptionFn.class, IRFutureOptionCalculatorFactory.class, IRFutureOptionNormalCalculatorFactory.class, CurveSpecificationMarketDataFn.class, DefaultCurveSpecificationMarketDataFn.class, FXMatrixFn.class, DefaultFXMatrixFn.class, CurveDefinitionFn.class, DefaultCurveDefinitionFn.class, CurveLabellingFn.class, CurveDefinitionCurveLabellingFn.class, CurveSpecificationFn.class, DefaultCurveSpecificationFn.class, CurveConstructionConfigurationSource.class, ConfigDBCurveConstructionConfigurationSource.class, CurveNodeConverterFn.class, DefaultCurveNodeConverterFn.class, HistoricalMarketDataFn.class, DefaultHistoricalMarketDataFn.class, FixingsFn.class, DefaultFixingsFn.class, MarketDataFn.class, DefaultMarketDataFn.class, CurveSelector.class, MarketExposureSelector.class, IRFutureOptionNormalSurfaceProviderFn.class, TestIRFutureOptionNormalSurfaceProviderFn.class, DiscountingMulticurveCombinerFn.class, CurveSelectorMulticurveBundleFn.class)); return config; } private ImmutableMap<Class<?>, Object> generateComponents() { ImmutableMap.Builder<Class<?>, Object> builder = ImmutableMap.builder(); for (Map.Entry<Class<?>, Object> entry : InterestRateMockSources.generateBaseComponents().entrySet()) { Class<?> key = entry.getKey(); if (key.equals(SecuritySource.class)) { appendSecuritySource((SecuritySource) entry.getValue()); } builder.put(key, entry.getValue()); } return builder.build(); } // TODO - this assumes knowledge of the underlying source, should find a better way to do this private void appendSecuritySource(SecuritySource source) { SecurityMaster master = ((MasterSecuritySource) source).getMaster(); master.add(new SecurityDocument(_irFuture)); } private InterestRateFutureSecurity createIRFuture() { Expiry expiry = new Expiry(ZonedDateTime.of(LocalDate.of(2014, 6, 18), LocalTime.of(0, 0), ZoneOffset.UTC)); String tradingExchange = ""; String settlementExchange = ""; Currency currency = Currency.USD; double unitAmount = 1000; ExternalId underlyingId = InterestRateMockSources.getLiborIndexId(); String category = ""; InterestRateFutureSecurity irFuture = new InterestRateFutureSecurity( expiry, tradingExchange, settlementExchange, currency, unitAmount, underlyingId, category); // Need this for time series lookup ExternalId irFutureId = ExternalSchemes.syntheticSecurityId("Test future"); irFuture.setExternalIdBundle(irFutureId.toBundle()); return irFuture; } private IRFutureOptionTrade createIRFutureOptionTrade() { String exchange = "TestExchange"; ExerciseType exerciseType = new EuropeanExerciseType(); double pointValue = Double.NaN; boolean margined = true; double strike = 0.99; OptionType optionType = OptionType.PUT; ExternalId irFutureId = Iterables.getOnlyElement(_irFuture.getExternalIdBundle()); IRFutureOptionSecurity irFutureOption = new IRFutureOptionSecurity( exchange, _irFuture.getExpiry(), exerciseType, irFutureId, pointValue, margined, _irFuture.getCurrency(), strike, optionType); // Need this for time series lookup irFutureOption.setExternalIdBundle( ExternalSchemes.syntheticSecurityId("Test future option").toBundle()); Counterparty counterparty = new SimpleCounterparty(ExternalId.of(Counterparty.DEFAULT_SCHEME, "COUNTERPARTY")); BigDecimal tradeQuantity = BigDecimal.valueOf(1); SimpleTrade trade = new SimpleTrade(irFutureOption, tradeQuantity, counterparty, TRADE_DATE, TRADE_TIME); trade.setPremium(10.0); trade.setPremiumCurrency(Currency.USD); return new IRFutureOptionTrade(trade); } @Test public void testBlackPresentValue() { Result<MultipleCurrencyAmount> result = _functionRunner.runFunction( ARGS, createSuppliedData(), new Function<Environment, Result<MultipleCurrencyAmount>>() { @Override public Result<MultipleCurrencyAmount> apply(Environment env) { return _blackIRFutureOptionFn.calculatePV(env, _irFutureOptionTrade); } }); assertSuccess(result); MultipleCurrencyAmount mca = result.getValue(); assertThat( mca.getCurrencyAmount(Currency.USD).getAmount(), is(closeTo(-972.460677, STD_TOLERANCE_PV))); } @Test public void testBlackBucketedZeroDelta() { Result<BucketedCurveSensitivities> result = _functionRunner.runFunction( ARGS, createSuppliedData(), new Function<Environment, Result<BucketedCurveSensitivities>>() { @Override public Result<BucketedCurveSensitivities> apply(Environment env) { return _blackIRFutureOptionFn.calculateBucketedZeroIRDelta( env, _irFutureOptionTrade); } }); assertSuccess(result); } @Test public void testNormalPresentValue() { Result<MultipleCurrencyAmount> result = _functionRunner.runFunction( ARGS, createSuppliedData(), new Function<Environment, Result<MultipleCurrencyAmount>>() { @Override public Result<MultipleCurrencyAmount> apply(Environment env) { return _normalIRFutureOptionFn.calculatePV(env, _irFutureOptionTrade); } }); assertSuccess(result); MultipleCurrencyAmount mca = result.getValue(); assertThat( mca.getCurrencyAmount(Currency.USD).getAmount(), is(closeTo(-902.7156551, STD_TOLERANCE_PV))); } @Test public void testNormalPrice() { Result<Double> result = _functionRunner.runFunction( ARGS, createSuppliedData(), new Function<Environment, Result<Double>>() { @Override public Result<Double> apply(Environment env) { return _normalIRFutureOptionFn.calculateModelPrice(env, _irFutureOptionTrade); } }); assertSuccess(result); Double price = result.getValue(); assertThat(price, is(closeTo(0.072284344, STD_TOLERANCE_PV))); } @Test public void testNormalBucketedZeroDelta() { Result<BucketedCurveSensitivities> result = _functionRunner.runFunction( ARGS, createSuppliedData(), new Function<Environment, Result<BucketedCurveSensitivities>>() { @Override public Result<BucketedCurveSensitivities> apply(Environment env) { return _normalIRFutureOptionFn.calculateBucketedZeroIRDelta( env, _irFutureOptionTrade); } }); assertSuccess(result); } }
@Override public OffsetTime deserialize(JsonParser parser, DeserializationContext context) throws IOException { if (parser.hasToken(JsonToken.VALUE_STRING)) { String string = parser.getText().trim(); if (string.length() == 0) { return null; } try { return OffsetTime.parse(string, _formatter); } catch (DateTimeException e) { _rethrowDateTimeException(parser, context, e, string); } } if (!parser.isExpectedStartArrayToken()) { if (parser.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) { return (OffsetTime) parser.getEmbeddedObject(); } throw context.wrongTokenException(parser, JsonToken.START_ARRAY, "Expected array or string."); } int hour = parser.nextIntValue(-1); if (hour == -1) { JsonToken t = parser.getCurrentToken(); if (t == JsonToken.END_ARRAY) { return null; } if (t != JsonToken.VALUE_NUMBER_INT) { _reportWrongToken(parser, context, JsonToken.VALUE_NUMBER_INT, "hours"); } hour = parser.getIntValue(); } int minute = parser.nextIntValue(-1); if (minute == -1) { JsonToken t = parser.getCurrentToken(); if (t == JsonToken.END_ARRAY) { return null; } if (t != JsonToken.VALUE_NUMBER_INT) { _reportWrongToken(parser, context, JsonToken.VALUE_NUMBER_INT, "minutes"); } minute = parser.getIntValue(); } int partialSecond = 0; int second = 0; if (parser.nextToken() == JsonToken.VALUE_NUMBER_INT) { second = parser.getIntValue(); if (parser.nextToken() == JsonToken.VALUE_NUMBER_INT) { partialSecond = parser.getIntValue(); if (partialSecond < 1_000 && !context.isEnabled(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS)) { partialSecond *= 1_000_000; // value is milliseconds, convert it to nanoseconds } parser.nextToken(); } } if (parser.getCurrentToken() == JsonToken.VALUE_STRING) { OffsetTime t = OffsetTime.of(hour, minute, second, partialSecond, ZoneOffset.of(parser.getText())); if (parser.nextToken() != JsonToken.END_ARRAY) { _reportWrongToken(parser, context, JsonToken.END_ARRAY, "timezone"); } return t; } throw context.wrongTokenException( parser, JsonToken.VALUE_STRING, "Expected string for TimeZone after numeric values"); }
public class TestPersistentOffsetTimeAsLongAndStringOffset extends DatabaseCapable { private static final OffsetTime[] offsetTimes = new OffsetTime[] { OffsetTime.of(LocalTime.of(12, 10, 31), ZoneOffset.UTC), OffsetTime.of(LocalTime.of(23, 7, 43, 120), ZoneOffset.ofHours(2)) }; private static EntityManagerFactory factory; @BeforeClass public static void setup() { factory = Persistence.createEntityManagerFactory("test1"); } @AfterClass public static void tearDown() { factory.close(); } @Test public void testPersist() { EntityManager manager = factory.createEntityManager(); manager.getTransaction().begin(); for (int i = 0; i < offsetTimes.length; i++) { OffsetTimeAsLongAndStringOffsetHolder item = new OffsetTimeAsLongAndStringOffsetHolder(); item.setId(i); item.setName("test_" + i); item.setOffsetTime(offsetTimes[i]); manager.persist(item); } manager.flush(); manager.getTransaction().commit(); manager.close(); manager = factory.createEntityManager(); for (int i = 0; i < offsetTimes.length; i++) { OffsetTimeAsLongAndStringOffsetHolder item = manager.find(OffsetTimeAsLongAndStringOffsetHolder.class, Long.valueOf(i)); assertNotNull(item); assertEquals(i, item.getId()); assertEquals("test_" + i, item.getName()); assertEquals(offsetTimes[i], item.getOffsetTime()); } verifyDatabaseTable( manager, OffsetTimeAsLongAndStringOffsetHolder.class.getAnnotation(Table.class).name()); manager.close(); } }