From ac1892d865a4d4e0ab193cbeda462b22aad7b687 Mon Sep 17 00:00:00 2001 From: Stephen Colebourne Date: Thu, 20 Apr 2023 13:56:25 +0100 Subject: [PATCH 001/116] Fix Maven on CircleCI --- .circleci/config.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f6cc4dcecd..832e0b5740 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -45,9 +45,13 @@ commands: - run: name: Initializing Maven command: | + mvn --version mkdir -p ./.mvn - echo "-e -B -DtrimStackTrace=false --settings $( pwd )/.circleci/maven-settings.xml" > ./.mvn/maven.config - cat ./.mvn/maven.config + echo "-e" >> ./.mvn/maven.config + echo "-B" >> ./.mvn/maven.config + echo "-DtrimStackTrace=false" >> ./.mvn/maven.config + echo "--settings" >> ./.mvn/maven.config + echo "$( pwd )/.circleci/maven-settings.xml" >> ./.mvn/maven.config mvn --version #---------------------------------------------------------------------------- From ccada5ee85d215fbaab3c35eef06a2291007023d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 May 2023 11:38:43 +0100 Subject: [PATCH 002/116] Bump junit-bom from 5.9.2 to 5.9.3 (#2566) Bumps [junit-bom](https://github.com/junit-team/junit5) from 5.9.2 to 5.9.3. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.9.2...r5.9.3) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pom.xml b/modules/pom.xml index 7414a0c418..9b05e8cc72 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -771,7 +771,7 @@ 2.2.3 2.8.3 ${joda-beans.version} - 5.9.2 + 5.9.3 4.9.0 1.7.36 From 55b46cbeaff2939163e004c37de98e74c2f9a86b Mon Sep 17 00:00:00 2001 From: Yuki Iwashita Date: Tue, 2 May 2023 16:16:04 +0100 Subject: [PATCH 003/116] modifier in inflation bond pricers (#2567) --- ...untingCapitalIndexedBondProductPricer.java | 46 ++++++++++++++++--- ...countingCapitalIndexedBondTradePricer.java | 24 +++++++++- ...tingCapitalIndexedBondTradePricerTest.java | 3 +- 3 files changed, 63 insertions(+), 10 deletions(-) diff --git a/modules/pricer/src/main/java/com/opengamma/strata/pricer/bond/DiscountingCapitalIndexedBondProductPricer.java b/modules/pricer/src/main/java/com/opengamma/strata/pricer/bond/DiscountingCapitalIndexedBondProductPricer.java index 15fb10bcd0..b0ba43b1d4 100644 --- a/modules/pricer/src/main/java/com/opengamma/strata/pricer/bond/DiscountingCapitalIndexedBondProductPricer.java +++ b/modules/pricer/src/main/java/com/opengamma/strata/pricer/bond/DiscountingCapitalIndexedBondProductPricer.java @@ -202,8 +202,19 @@ public PointSensitivityBuilder presentValueSensitivity( bond, ratesProvider, discountingProvider, ratesProvider.getValuationDate()); } - // calculate the present value sensitivity - PointSensitivityBuilder presentValueSensitivity( + /** + * Calculates the present value sensitivity of the bond product for the specified reference date. + *

+ * The present value sensitivity of the product is the sensitivity of the present value to + * the underlying curves. + * + * @param bond the product + * @param ratesProvider the rates provider, used to determine price index values + * @param discountingProvider the discount factors provider + * @param referenceDate the reference date + * @return the present value curve sensitivity of the product + */ + public PointSensitivityBuilder presentValueSensitivity( ResolvedCapitalIndexedBond bond, RatesProvider ratesProvider, LegalEntityDiscountingProvider discountingProvider, @@ -392,8 +403,20 @@ public double dirtyNominalPriceFromCurves( return dirtyNominalPriceFromCurves(bond, ratesProvider, discountingProvider, settlementDate); } - // calculate the dirty price - double dirtyNominalPriceFromCurves( + /** + * Calculates the dirty price of the bond security for the specified settlement date. + *

+ * The bond is represented as {@link Security} where standard ID of the bond is stored. + *

+ * Strata uses decimal prices for bonds. For example, a price of 99.32% is represented in Strata by 0.9932. + * + * @param bond the product + * @param ratesProvider the rates provider, used to determine price index values + * @param discountingProvider the discount factors provider + * @param settlementDate the settlement date + * @return the dirty price of the bond security + */ + public double dirtyNominalPriceFromCurves( ResolvedCapitalIndexedBond bond, RatesProvider ratesProvider, LegalEntityDiscountingProvider discountingProvider, @@ -480,8 +503,19 @@ public PointSensitivityBuilder dirtyNominalPriceSensitivity( return dirtyNominalPriceSensitivity(bond, ratesProvider, discountingProvider, settlementDate); } - // calculate the dirty price sensitivity - PointSensitivityBuilder dirtyNominalPriceSensitivity( + /** + * Calculates the dirty price sensitivity of the bond security for the specified settlement date. + *

+ * The dirty price sensitivity of the security is the sensitivity of the dirty price value to + * the underlying curves. + * + * @param bond the product + * @param ratesProvider the rates provider, used to determine price index values + * @param discountingProvider the discount factors provider + * @param settlementDate the settlement date + * @return the dirty price curve sensitivity of the security + */ + public PointSensitivityBuilder dirtyNominalPriceSensitivity( ResolvedCapitalIndexedBond bond, RatesProvider ratesProvider, LegalEntityDiscountingProvider discountingProvider, diff --git a/modules/pricer/src/main/java/com/opengamma/strata/pricer/bond/DiscountingCapitalIndexedBondTradePricer.java b/modules/pricer/src/main/java/com/opengamma/strata/pricer/bond/DiscountingCapitalIndexedBondTradePricer.java index 9264ec900b..04d4073f32 100644 --- a/modules/pricer/src/main/java/com/opengamma/strata/pricer/bond/DiscountingCapitalIndexedBondTradePricer.java +++ b/modules/pricer/src/main/java/com/opengamma/strata/pricer/bond/DiscountingCapitalIndexedBondTradePricer.java @@ -56,6 +56,16 @@ public DiscountingCapitalIndexedBondTradePricer(DiscountingCapitalIndexedBondPro this.productPricer = ArgChecker.notNull(productPricer, "productPricer"); } + //------------------------------------------------------------------------- + /** + * Gets the capital indexed bond product pricer. + * + * @return the product pricer + */ + public DiscountingCapitalIndexedBondProductPricer getProductPricer() { + return productPricer; + } + //------------------------------------------------------------------------- /** * Calculates the present value of the bond trade. @@ -683,13 +693,23 @@ PointSensitivityBuilder forecastValueSensitivityStandardFromCleanPrice( } //------------------------------------------------------------------------- - // calculate the settlement date - private LocalDate settlementDate(ResolvedCapitalIndexedBondTrade trade, LocalDate valuationDate) { + + /** + * Calculates the settlement date. + *

+ * The valuation date is returned if the settlement details are not stored. + * + * @param trade the trade + * @param valuationDate the valuation date + * @return the settlement date + */ + public LocalDate settlementDate(ResolvedCapitalIndexedBondTrade trade, LocalDate valuationDate) { return trade.getSettlement() .map(settle -> settle.getSettlementDate()) .orElse(valuationDate); } + //------------------------------------------------------------------------- private void validate(RatesProvider ratesProvider, LegalEntityDiscountingProvider discountingProvider) { ArgChecker.isTrue(ratesProvider.getValuationDate().isEqual(discountingProvider.getValuationDate()), "the rates providers should be for the same date"); diff --git a/modules/pricer/src/test/java/com/opengamma/strata/pricer/bond/DiscountingCapitalIndexedBondTradePricerTest.java b/modules/pricer/src/test/java/com/opengamma/strata/pricer/bond/DiscountingCapitalIndexedBondTradePricerTest.java index f4e00ba2a7..5946618570 100644 --- a/modules/pricer/src/test/java/com/opengamma/strata/pricer/bond/DiscountingCapitalIndexedBondTradePricerTest.java +++ b/modules/pricer/src/test/java/com/opengamma/strata/pricer/bond/DiscountingCapitalIndexedBondTradePricerTest.java @@ -208,8 +208,7 @@ public class DiscountingCapitalIndexedBondTradePricerTest { private static final double TOL = 1.0e-12; private static final double EPS = 1.0e-6; private static final DiscountingCapitalIndexedBondTradePricer PRICER = DiscountingCapitalIndexedBondTradePricer.DEFAULT; - private static final DiscountingCapitalIndexedBondProductPricer PRODUCT_PRICER = - DiscountingCapitalIndexedBondProductPricer.DEFAULT; + private static final DiscountingCapitalIndexedBondProductPricer PRODUCT_PRICER = PRICER.getProductPricer(); private static final DiscountingCapitalIndexedBondPaymentPeriodPricer PERIOD_PRICER = DiscountingCapitalIndexedBondPaymentPeriodPricer.DEFAULT; private static final DiscountingPaymentPricer PAYMENT_PRICER = DiscountingPaymentPricer.DEFAULT; From f44d43be5226d9f415cd9cc082b9178e16b5d022 Mon Sep 17 00:00:00 2001 From: Anand <49917470+anand-uk@users.noreply.github.com> Date: Fri, 5 May 2023 16:00:51 +0100 Subject: [PATCH 004/116] Expand ArgChecker to validate non-positive args (#2568) --- .../opengamma/strata/collect/ArgChecker.java | 112 ++++++++++++++++++ .../strata/collect/ArgCheckerTest.java | 68 +++++++++++ 2 files changed, 180 insertions(+) diff --git a/modules/collect/src/main/java/com/opengamma/strata/collect/ArgChecker.java b/modules/collect/src/main/java/com/opengamma/strata/collect/ArgChecker.java index 350e3b7626..35afca14f9 100644 --- a/modules/collect/src/main/java/com/opengamma/strata/collect/ArgChecker.java +++ b/modules/collect/src/main/java/com/opengamma/strata/collect/ArgChecker.java @@ -752,6 +752,118 @@ private static String noDuplicatesSortedArrayMsg(String name) { return "Argument array '" + name + "' must be sorted and not contain duplicates"; } + //------------------------------------------------------------------------- + + /** + * Checks that the argument is not positive. + *

+ * Given the input argument, this returns only if it is less than or equal to zero. + * For example, in a constructor: + *

+   *  this.amount = ArgChecker.notPositive(amount, "amount");
+   * 
+ * + * @param argument the argument to check + * @param name the name of the argument to use in the error message, not null + * @return the input {@code argument} + * @throws IllegalArgumentException if the input is positive + */ + public static int notPositive(int argument, String name) { + if (argument > 0) { + throw new IllegalArgumentException(notPositiveMsg(name, argument)); + } + return argument; + } + + private static String notPositiveMsg(String name, Object argument) { + return "Argument '" + name + "' must not be positive but has value " + argument; + } + + /** + * Checks that the argument is not positive. + *

+ * Given the input argument, this returns only if it is less than or equal to zero. + * For example, in a constructor: + *

+   *  this.amount = ArgChecker.notPositive(amount, "amount");
+   * 
+ * + * @param argument the argument to check + * @param name the name of the argument to use in the error message, not null + * @return the input {@code argument} + * @throws IllegalArgumentException if the input is positive + */ + public static long notPositive(long argument, String name) { + if (argument > 0) { + throw new IllegalArgumentException(notPositiveMsg(name, argument)); + } + return argument; + } + + /** + * Checks that the argument is not positive. + *

+ * Given the input argument, this returns only if it is less than or equal to zero. + * For example, in a constructor: + *

+   *  this.amount = ArgChecker.notPositive(amount, "amount");
+   * 
+ * + * @param argument the argument to check + * @param name the name of the argument to use in the error message, not null + * @return the input {@code argument} + * @throws IllegalArgumentException if the input is positive + */ + public static double notPositive(double argument, String name) { + if (argument > 0) { + throw new IllegalArgumentException(notPositiveMsg(name, argument)); + } + return argument; + } + + /** + * Checks that the argument is not positive. + *

+ * Given the input argument, this returns only if it is not null and is less than or equal to zero. + * For example, in a constructor: + *

+   *  this.amount = ArgChecker.notPositive(amount, "amount");
+   * 
+ * + * @param argument the argument to check + * @param name the name of the argument to use in the error message, not null + * @return the input {@code argument} + * @throws IllegalArgumentException if the input is null or positive + */ + public static Decimal notPositive(Decimal argument, String name) { + notNull(argument, name); + if (argument.unscaledValue() > 0) { + throw new IllegalArgumentException(notPositiveMsg(name, argument)); + } + return argument; + } + + /** + * Checks that the argument is not positive if the arguement is not null. + *

+ * Given the input argument, this returns only if it is null or if it is less than or equal to zero. + * For example, in a constructor: + *

+   *  this.amount = ArgChecker.notPositiveIfPresent(amount, "amount");
+   * 
+ * + * @param argument the argument to check + * @param name the name of the argument to use in the error message, not null + * @return the input {@code argument} + * @throws IllegalArgumentException if the input is not null and is positive + */ + public static Decimal notPositiveIfPresent(Decimal argument, String name) { + if (argument != null && argument.unscaledValue() > 0) { + throw new IllegalArgumentException(notPositiveMsg(name, argument)); + } + return argument; + } + //------------------------------------------------------------------------- /** * Checks that the argument is not negative. diff --git a/modules/collect/src/test/java/com/opengamma/strata/collect/ArgCheckerTest.java b/modules/collect/src/test/java/com/opengamma/strata/collect/ArgCheckerTest.java index 5acd240624..29e1fa58aa 100644 --- a/modules/collect/src/test/java/com/opengamma/strata/collect/ArgCheckerTest.java +++ b/modules/collect/src/test/java/com/opengamma/strata/collect/ArgCheckerTest.java @@ -536,6 +536,74 @@ public void test_noNulls_Map_nullValue() { .withMessageMatching(".*map.*'name'.*null.*"); } + //------------------------------------------------------------------------- + @Test + public void test_notPositive_int_ok() { + assertThat(ArgChecker.notPositive(0, "name")).isEqualTo(0); + assertThat(ArgChecker.notPositive(-1, "name")).isEqualTo(-1); + } + + @Test + public void test_notPositve_int_positive() { + assertThatIllegalArgumentException() + .isThrownBy(() -> ArgChecker.notPositive(1, "name")) + .withMessageMatching(".*'name'.*positive.*"); + + } + + @Test + public void test_notPositive_long_ok() { + assertThat(ArgChecker.notPositive(0L, "name")).isEqualTo(0L); + assertThat(ArgChecker.notPositive(-1L, "name")).isEqualTo(-1L); + } + + @Test + public void test_notPositive_long_positive() { + assertThatIllegalArgumentException() + .isThrownBy(() -> ArgChecker.notPositive(1L, "name")) + .withMessageMatching(".*'name'.*positive.*"); + } + + @Test + public void test_notPositive_double_ok() { + assertThat(ArgChecker.notPositive(0d, "name")).isEqualTo(0d); + assertThat(ArgChecker.notPositive(-1d, "name")).isEqualTo(-1d); + } + + @Test + public void test_notPositive_double_positive() { + assertThatIllegalArgumentException() + .isThrownBy(() -> ArgChecker.notPositive(1d, "name")) + .withMessageMatching(".*'name'.*positive.*"); + } + + @Test + public void test_notPositive_Decimal_ok() { + assertThat(ArgChecker.notPositive(Decimal.of(0), "name")).isEqualTo(Decimal.of(0)); + assertThat(ArgChecker.notPositive(Decimal.of(-1), "name")).isEqualTo(Decimal.of(-1)); + } + + @Test + public void test_notPositive_Decimal_positive() { + assertThatIllegalArgumentException() + .isThrownBy(() -> ArgChecker.notPositive(Decimal.of(1), "name")) + .withMessageMatching(".*'name'.*positive.*"); + } + + @Test + public void test_notPositiveIfPresent_Decimal_ok() { + assertThat(ArgChecker.notPositiveIfPresent(null, "name")).isNull(); + assertThat(ArgChecker.notPositiveIfPresent(Decimal.of(0), "name")).isEqualTo(Decimal.of(0)); + assertThat(ArgChecker.notPositiveIfPresent(Decimal.of(-1), "name")).isEqualTo(Decimal.of(-1)); + } + + @Test + public void test_notPositiveIfPresent_Decimal_positive() { + assertThatIllegalArgumentException() + .isThrownBy(() -> ArgChecker.notPositiveIfPresent(Decimal.of(1), "name")) + .withMessageMatching(".*'name'.*positive.*"); + } + //------------------------------------------------------------------------- @Test public void test_notNegative_int_ok() { From 52d62b1402e1c12feb73bbc0b0cacda5f956f5dd Mon Sep 17 00:00:00 2001 From: Stephen Colebourne Date: Tue, 9 May 2023 13:57:07 +0100 Subject: [PATCH 005/116] Add CharMatchers (#2569) Provide standard character matchers --- .../strata/collect/CharMatchers.java | 103 ++++++++++++++++++ .../strata/collect/CharMatchersTest.java | 77 +++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 modules/collect/src/main/java/com/opengamma/strata/collect/CharMatchers.java create mode 100644 modules/collect/src/test/java/com/opengamma/strata/collect/CharMatchersTest.java diff --git a/modules/collect/src/main/java/com/opengamma/strata/collect/CharMatchers.java b/modules/collect/src/main/java/com/opengamma/strata/collect/CharMatchers.java new file mode 100644 index 0000000000..ae81f3b912 --- /dev/null +++ b/modules/collect/src/main/java/com/opengamma/strata/collect/CharMatchers.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2023 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.collect; + +import com.google.common.base.CharMatcher; + +/** + * Useful Guava character matchers. + */ +public final class CharMatchers { + + private static final CharMatcher UPPER_LETTERS = CharMatcher.inRange('A', 'Z'); + private static final CharMatcher LOWER_LETTERS = CharMatcher.inRange('a', 'z'); + private static final CharMatcher LETTERS = UPPER_LETTERS.or(LOWER_LETTERS); + private static final CharMatcher DIGITS = CharMatcher.inRange('0', '9'); + private static final CharMatcher LETTERS_DIGITS = LETTERS.or(DIGITS); + private static final CharMatcher UPPER_HEX = DIGITS.or(CharMatcher.inRange('A', 'F')); + private static final CharMatcher LOWER_HEX = DIGITS.or(CharMatcher.inRange('a', 'f')); + private static final CharMatcher HEX = UPPER_HEX.or(LOWER_HEX); + + /** + * Restricted constructor. + */ + private CharMatchers() { + } + + //------------------------------------------------------------------------- + /** + * Returns the matcher for ASCII upper case letters. + * + * @return the matcher for ASCII upper case letters + */ + public static CharMatcher upperLetters() { + return UPPER_LETTERS; + } + + /** + * Returns the matcher for ASCII upper case letters. + * + * @return the matcher for ASCII upper case letters + */ + public static CharMatcher lowerLetters() { + return LOWER_LETTERS; + } + + /** + * Returns the matcher for ASCII letters. + * + * @return the matcher for ASCII letters + */ + public static CharMatcher letters() { + return LETTERS; + } + + /** + * Returns the matcher for ASCII digits. + * + * @return the matcher for ASCII digits + */ + public static CharMatcher digits() { + return DIGITS; + } + + /** + * Returns the matcher for ASCII letters and digits. + * + * @return the matcher for ASCII letters and digits + */ + public static CharMatcher lettersAndDigits() { + return LETTERS_DIGITS; + } + + /** + * Returns the matcher for ASCII upper case hex characters. + * + * @return the matcher for ASCII upper case hex characters + */ + public static CharMatcher upperHex() { + return UPPER_HEX; + } + + /** + * Returns the matcher for ASCII upper case hex characters. + * + * @return the matcher for ASCII upper case hex characters + */ + public static CharMatcher lowerHex() { + return LOWER_HEX; + } + + /** + * Returns the matcher for ASCII hex characters. + * + * @return the matcher for ASCII hex characters + */ + public static CharMatcher hex() { + return HEX; + } + +} diff --git a/modules/collect/src/test/java/com/opengamma/strata/collect/CharMatchersTest.java b/modules/collect/src/test/java/com/opengamma/strata/collect/CharMatchersTest.java new file mode 100644 index 0000000000..182e919327 --- /dev/null +++ b/modules/collect/src/test/java/com/opengamma/strata/collect/CharMatchersTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2023 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.collect; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +/** + * Test CharMatchers. + */ +public class CharMatchersTest { + + @Test + public void test_upperLetters() { + assertThat(CharMatchers.upperLetters().matchesAllOf("ABCDEFGHIJKLMNOPQRSTUVWXYZ")); + assertThat(CharMatchers.upperLetters().matchesNoneOf("abcdefghijklmnopqrstuvwxyz")); + assertThat(CharMatchers.upperLetters().matchesNoneOf("0123456789")); + assertThat(CharMatchers.upperLetters().matchesNoneOf(" -_!\"£$%^&*()\\|,<.>/?;:'@#~[{]}=+")); + } + + @Test + public void test_lowerLetters() { + assertThat(CharMatchers.lowerLetters().matchesNoneOf("ABCDEFGHIJKLMNOPQRSTUVWXYZ")); + assertThat(CharMatchers.lowerLetters().matchesAllOf("abcdefghijklmnopqrstuvwxyz")); + assertThat(CharMatchers.lowerLetters().matchesNoneOf("0123456789")); + assertThat(CharMatchers.lowerLetters().matchesNoneOf(" -_!\"£$%^&*()\\|,<.>/?;:'@#~[{]}=+")); + } + + @Test + public void test_letters() { + assertThat(CharMatchers.letters().matchesAllOf("ABCDEFGHIJKLMNOPQRSTUVWXYZ")); + assertThat(CharMatchers.letters().matchesAllOf("abcdefghijklmnopqrstuvwxyz")); + assertThat(CharMatchers.letters().matchesNoneOf("0123456789")); + assertThat(CharMatchers.letters().matchesNoneOf(" -_!\"£$%^&*()\\|,<.>/?;:'@#~[{]}=+")); + } + + @Test + public void test_digits() { + assertThat(CharMatchers.digits().matchesNoneOf("ABCDEFGHIJKLMNOPQRSTUVWXYZ")); + assertThat(CharMatchers.digits().matchesNoneOf("abcdefghijklmnopqrstuvwxyz")); + assertThat(CharMatchers.digits().matchesAllOf("0123456789")); + assertThat(CharMatchers.digits().matchesNoneOf(" -_!\"£$%^&*()\\|,<.>/?;:'@#~[{]}=+")); + } + + @Test + public void test_lettersAndDigits() { + assertThat(CharMatchers.lettersAndDigits().matchesAllOf("ABCDEFGHIJKLMNOPQRSTUVWXYZ")); + assertThat(CharMatchers.lettersAndDigits().matchesAllOf("abcdefghijklmnopqrstuvwxyz")); + assertThat(CharMatchers.lettersAndDigits().matchesAllOf("0123456789")); + assertThat(CharMatchers.lettersAndDigits().matchesNoneOf(" -_!\"£$%^&*()\\|,<.>/?;:'@#~[{]}=+")); + } + + @Test + public void test_upperHex() { + assertThat(CharMatchers.upperHex().matchesAllOf("0123456789ABCDEF")); + assertThat(CharMatchers.upperHex().matchesNoneOf("abcdef")); + assertThat(CharMatchers.upperHex().matchesNoneOf(" -_!\"£$%^&*()\\|,<.>/?;:'@#~[{]}=+")); + } + + @Test + public void test_lowerHex() { + assertThat(CharMatchers.lowerHex().matchesAllOf("0123456789abcdef")); + assertThat(CharMatchers.lowerHex().matchesNoneOf("ABCDEF")); + assertThat(CharMatchers.lowerHex().matchesNoneOf(" -_!\"£$%^&*()\\|,<.>/?;:'@#~[{]}=+")); + } + + @Test + public void test_hex() { + assertThat(CharMatchers.hex().matchesAllOf("0123456789abcdefABCDEF")); + assertThat(CharMatchers.hex().matchesNoneOf(" -_!\"£$%^&*()\\|,<.>/?;:'@#~[{]}=+")); + } + +} From 6919d1220aa416d383022663fda2567d8084ea30 Mon Sep 17 00:00:00 2001 From: Alexandru Amarandei Stanescu <97905177+AlexandruOG@users.noreply.github.com> Date: Wed, 10 May 2023 11:47:55 +0100 Subject: [PATCH 006/116] Extend EtdIdUtils to create ContractSpecId directly from SecurityId (#2570) * Extend EtdIdUtils to create ContractSpecId directly from SecurityId * Added test and removed auto format * Small update * Typo --------- Co-authored-by: alexandruamarandeistanescu --- .../strata/product/etd/EtdIdUtils.java | 14 ++++++++++ .../strata/product/etd/EtdIdUtilsTest.java | 26 +++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/modules/product/src/main/java/com/opengamma/strata/product/etd/EtdIdUtils.java b/modules/product/src/main/java/com/opengamma/strata/product/etd/EtdIdUtils.java index bea4bcaf6e..5345f8ac78 100644 --- a/modules/product/src/main/java/com/opengamma/strata/product/etd/EtdIdUtils.java +++ b/modules/product/src/main/java/com/opengamma/strata/product/etd/EtdIdUtils.java @@ -82,6 +82,20 @@ public static EtdContractSpecId contractSpecId(EtdType type, ExchangeId exchange } } + /** + * Creates an identifier for a contract specification. + *

+ * This will have the format: + * {@code 'OG-ETD~F-ECAG-FGBS'} or {@code 'OG-ETD~O-ECAG-OGBS'}. + * + * @param securityId the security id + * @return the identifier + */ + public static EtdContractSpecId contractSpecId(SecurityId securityId) { + SplitEtdId splitEtdId = splitId(securityId); + return contractSpecId(splitEtdId.getType(), splitEtdId.getExchangeId(), splitEtdId.getContractCode()); + } + /** * Creates an identifier for an ETD future instrument. *

diff --git a/modules/product/src/test/java/com/opengamma/strata/product/etd/EtdIdUtilsTest.java b/modules/product/src/test/java/com/opengamma/strata/product/etd/EtdIdUtilsTest.java index 0600ac6c58..dabe2612ca 100644 --- a/modules/product/src/test/java/com/opengamma/strata/product/etd/EtdIdUtilsTest.java +++ b/modules/product/src/test/java/com/opengamma/strata/product/etd/EtdIdUtilsTest.java @@ -57,6 +57,32 @@ public void test_contractSpecId_option() { .build()); } + @Test + public void test_contractSpecId_future_from_securityId() { + EtdContractSpecId test = EtdIdUtils.contractSpecId(SecurityId.of(OG_ETD_SCHEME, "F-ECAG-FGBS-202305")); + assertThat(test.getStandardId()).isEqualTo(StandardId.of(OG_ETD_SCHEME, "F-ECAG-FGBS")); + assertThat(EtdIdUtils.splitId(test)) + .isEqualTo(SplitEtdContractSpecId.builder() + .specId(test) + .type(EtdType.FUTURE) + .exchangeId(ExchangeIds.ECAG) + .contractCode(FGBS) + .build()); + } + + @Test + public void test_contractSpecId_option_from_securityId() { + EtdContractSpecId test = EtdIdUtils.contractSpecId(SecurityId.of(OG_ETD_SCHEME, "O-ECAG-OGBS-202305-P1")); + assertThat(test.getStandardId()).isEqualTo(StandardId.of(OG_ETD_SCHEME, "O-ECAG-OGBS")); + assertThat(EtdIdUtils.splitId(test)) + .isEqualTo(SplitEtdContractSpecId.builder() + .specId(test) + .type(EtdType.OPTION) + .exchangeId(ExchangeIds.ECAG) + .contractCode(OGBS) + .build()); + } + //------------------------------------------------------------------------- @Test public void test_futureId_monthly() { From 71334f960650c826694b8c193b53eecf9e222551 Mon Sep 17 00:00:00 2001 From: Alexis Skitini Date: Fri, 12 May 2023 11:30:59 +0100 Subject: [PATCH 007/116] Add MarketQuote value type (#2571) Co-authored-by: Alexis Skitini --- .../src/main/java/com/opengamma/strata/market/ValueType.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/market/src/main/java/com/opengamma/strata/market/ValueType.java b/modules/market/src/main/java/com/opengamma/strata/market/ValueType.java index 30f37241b0..5ff3326089 100644 --- a/modules/market/src/main/java/com/opengamma/strata/market/ValueType.java +++ b/modules/market/src/main/java/com/opengamma/strata/market/ValueType.java @@ -134,7 +134,10 @@ public final class ValueType * Type used when each value is a correlation - 'CORRELATION'. */ public static final ValueType CORRELATION = of("CORRELATION"); - + /** + * Type used when each value is the market quote e.g. a par rate for bonds = 'MarketQuote'. + */ + public static final ValueType MARKET_QUOTE = of("MarketQuote"); //------------------------------------------------------------------------- /** * Obtains an instance from the specified name. From cb4975914b77b1146bd022a0885d9235228a9db5 Mon Sep 17 00:00:00 2001 From: Alexis Skitini Date: Fri, 12 May 2023 12:03:38 +0100 Subject: [PATCH 008/116] Add Nasdaq commodity exchange id (#2572) Co-authored-by: Alexis Skitini --- .../java/com/opengamma/strata/product/common/ExchangeIds.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/product/src/main/java/com/opengamma/strata/product/common/ExchangeIds.java b/modules/product/src/main/java/com/opengamma/strata/product/common/ExchangeIds.java index 09e456281d..85c56b1df4 100644 --- a/modules/product/src/main/java/com/opengamma/strata/product/common/ExchangeIds.java +++ b/modules/product/src/main/java/com/opengamma/strata/product/common/ExchangeIds.java @@ -147,6 +147,9 @@ public final class ExchangeIds { /** Zhengzhou Commodity Exchange. */ public static final ExchangeId XZCE = ExchangeId.of("XZCE"); + /** Nasdaq Commodity Exchange. */ + public static final ExchangeId NORX = ExchangeId.of("NORX"); + //------------------------------------------------------------------------- /** * Restricted constructor. From c742a576f1620c6e4a3cbd3ff0445caa76be4477 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Fri, 12 May 2023 11:15:24 +0000 Subject: [PATCH 009/116] [maven-release-plugin] prepare release v2.12.22 --- examples/pom.xml | 6 +++++- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 1bd81ed5a2..1b0c3a0315 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.22-SNAPSHOT + 2.12.22 jar Strata-Examples Example code to demonstrate use of Strata @@ -272,4 +272,8 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> + + + v2.12.22 + diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index 3ca4a920ba..ef1437c940 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.22-SNAPSHOT + 2.12.22 .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 0a148b1361..3f8fcc7606 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.22-SNAPSHOT + 2.12.22 .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 4b93c06425..64301f8663 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.22-SNAPSHOT + 2.12.22 .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 20b168d0ed..00c82559b8 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.22-SNAPSHOT + 2.12.22 .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 1469affc37..e4093242b7 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.22-SNAPSHOT + 2.12.22 .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 336b2a6223..a13f029db9 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.22-SNAPSHOT + 2.12.22 .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 9216787fc4..47e626bd30 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.22-SNAPSHOT + 2.12.22 .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 887ce770a7..69712bf392 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.22-SNAPSHOT + 2.12.22 .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 9b05e8cc72..4cb8e9da00 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.22-SNAPSHOT + 2.12.22 pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.22 diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 8a9cd0cc27..ccce3a15a0 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.22-SNAPSHOT + 2.12.22 .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 02cf09985c..baa515895f 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.22-SNAPSHOT + 2.12.22 .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index b833f6f260..30eee583c4 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.22-SNAPSHOT + 2.12.22 .. strata-report diff --git a/pom.xml b/pom.xml index 78a55ca574..dcc4ff7cc3 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.22-SNAPSHOT + 2.12.22 pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.22 From 11aa30829f5007311ff6936eb70b631f6d1b30ad Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Fri, 12 May 2023 11:15:25 +0000 Subject: [PATCH 010/116] [maven-release-plugin] prepare for next development iteration --- examples/pom.xml | 6 +----- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 1b0c3a0315..e9ea03ffd7 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.22 + 2.12.23-SNAPSHOT jar Strata-Examples Example code to demonstrate use of Strata @@ -272,8 +272,4 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> - - - v2.12.22 - diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index ef1437c940..c2b7011b86 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.22 + 2.12.23-SNAPSHOT .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 3f8fcc7606..2c654867fd 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.22 + 2.12.23-SNAPSHOT .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 64301f8663..88739ef904 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.22 + 2.12.23-SNAPSHOT .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 00c82559b8..bbed74b424 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.22 + 2.12.23-SNAPSHOT .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index e4093242b7..e55950ba82 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.22 + 2.12.23-SNAPSHOT .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index a13f029db9..3830f653c7 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.22 + 2.12.23-SNAPSHOT .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 47e626bd30..48c53b59e0 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.22 + 2.12.23-SNAPSHOT .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 69712bf392..e24950a3dc 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.22 + 2.12.23-SNAPSHOT .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 4cb8e9da00..e6b036c1a0 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.22 + 2.12.23-SNAPSHOT pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.22 + HEAD diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index ccce3a15a0..b97e8b1025 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.22 + 2.12.23-SNAPSHOT .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index baa515895f..0ff3c8c42a 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.22 + 2.12.23-SNAPSHOT .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 30eee583c4..7eeb87da95 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.22 + 2.12.23-SNAPSHOT .. strata-report diff --git a/pom.xml b/pom.xml index dcc4ff7cc3..182dd5bfb2 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.22 + 2.12.23-SNAPSHOT pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.22 + HEAD From 24fc863bed712b291454d1e2ed8a8a29446a7ea9 Mon Sep 17 00:00:00 2001 From: Yuki Iwashita Date: Tue, 16 May 2023 13:57:52 +0100 Subject: [PATCH 011/116] Small Year Fractions in SimpleDiscountFactors (#2573) --- .../strata/pricer/DiscountFactors.java | 2 +- .../strata/pricer/SimpleDiscountFactors.java | 83 ++++++++++++++----- .../pricer/ZeroRateDiscountFactors.java | 7 +- .../ZeroRatePeriodicDiscountFactors.java | 2 +- .../pricer/SimpleDiscountFactorsTest.java | 55 +++++++++--- 5 files changed, 113 insertions(+), 36 deletions(-) diff --git a/modules/pricer/src/main/java/com/opengamma/strata/pricer/DiscountFactors.java b/modules/pricer/src/main/java/com/opengamma/strata/pricer/DiscountFactors.java index b7b8ef6b7a..026df4a31c 100644 --- a/modules/pricer/src/main/java/com/opengamma/strata/pricer/DiscountFactors.java +++ b/modules/pricer/src/main/java/com/opengamma/strata/pricer/DiscountFactors.java @@ -5,7 +5,7 @@ */ package com.opengamma.strata.pricer; -import static com.opengamma.strata.pricer.SimpleDiscountFactors.EFFECTIVE_ZERO; +import static com.opengamma.strata.pricer.ZeroRatePeriodicDiscountFactors.EFFECTIVE_ZERO; import java.time.LocalDate; import java.util.Optional; diff --git a/modules/pricer/src/main/java/com/opengamma/strata/pricer/SimpleDiscountFactors.java b/modules/pricer/src/main/java/com/opengamma/strata/pricer/SimpleDiscountFactors.java index e930d331fe..0d2a0bea17 100644 --- a/modules/pricer/src/main/java/com/opengamma/strata/pricer/SimpleDiscountFactors.java +++ b/modules/pricer/src/main/java/com/opengamma/strata/pricer/SimpleDiscountFactors.java @@ -56,7 +56,7 @@ public final class SimpleDiscountFactors /** * Year fraction used as an effective zero. */ - static final double EFFECTIVE_ZERO = 1e-10; + private static final double EFFECTIVE_ZERO = 1e-8; /** * The currency that the discount factors are for. @@ -171,24 +171,18 @@ public double relativeYearFraction(LocalDate date) { @Override public double discountFactor(double yearFraction) { - if (yearFraction <= EFFECTIVE_ZERO) { - return 1d; - } - // read discount factor directly off curve return curve.yValue(yearFraction); } @Override public double discountFactorTimeDerivative(double yearFraction) { - if (yearFraction <= EFFECTIVE_ZERO) { - return 0d; - } return curve.firstDerivative(yearFraction); } @Override public double zeroRate(double yearFraction) { - double yearFractionMod = Math.max(EFFECTIVE_ZERO, yearFraction); + // zero rate is undefined in general for tiny year fractions. + double yearFractionMod = modifyYearFraction(yearFraction); double discountFactor = discountFactor(yearFractionMod); return -Math.log(discountFactor) / yearFractionMod; } @@ -196,24 +190,22 @@ public double zeroRate(double yearFraction) { //------------------------------------------------------------------------- @Override public ZeroRateSensitivity zeroRatePointSensitivity(double yearFraction, Currency sensitivityCurrency) { - double discountFactor = discountFactor(yearFraction); - if (yearFraction <= EFFECTIVE_ZERO) { - return ZeroRateSensitivity.of(currency, yearFraction, sensitivityCurrency, 0d); - } - return ZeroRateSensitivity.of(currency, yearFraction, sensitivityCurrency, -discountFactor * yearFraction); + // zero rate sensitivity is undefined in general for tiny year fractions. + double yearFractionMod = modifyYearFraction(yearFraction); + double discountFactor = discountFactor(yearFractionMod); + return ZeroRateSensitivity.of(currency, yearFraction, sensitivityCurrency, -discountFactor * yearFractionMod); } //------------------------------------------------------------------------- @Override public CurrencyParameterSensitivities parameterSensitivity(ZeroRateSensitivity pointSens) { - double yearFraction = pointSens.getYearFraction(); - if (yearFraction <= EFFECTIVE_ZERO) { - return CurrencyParameterSensitivities.empty(); - } - double discountFactor = discountFactor(yearFraction); - UnitParameterSensitivity unitSens = curve.yValueParameterSensitivity(yearFraction); + // zero rate sensitivity is undefined in general for tiny year fractions, + // thus parameter sensitivities will be inaccurate. + double yearFractionMod = modifyYearFraction(pointSens.getYearFraction()); + double discountFactor = discountFactor(yearFractionMod); + UnitParameterSensitivity unitSens = curve.yValueParameterSensitivity(yearFractionMod); CurrencyParameterSensitivity curSens = unitSens - .multipliedBy(-1d / (yearFraction * discountFactor)) + .multipliedBy(-1d / (yearFractionMod * discountFactor)) .multipliedBy(pointSens.getCurrency(), pointSens.getSensitivity()); return CurrencyParameterSensitivities.of(curSens); } @@ -223,6 +215,55 @@ public CurrencyParameterSensitivities createParameterSensitivity(Currency curren return CurrencyParameterSensitivities.of(curve.createParameterSensitivity(currency, sensitivities)); } + //------------------------------------------------------------------------- + @Override + public double discountFactorWithSpread( + double yearFraction, + double zSpread, + CompoundedRateType compoundedRateType, + int periodsPerYear) { + + double df = discountFactor(yearFraction); + if (compoundedRateType.equals(CompoundedRateType.PERIODIC)) { + ArgChecker.notNegativeOrZero(periodsPerYear, "periodPerYear"); + double yearFractionMod = modifyYearFraction(yearFraction); + double ratePeriodicAnnualPlusOne = + Math.pow(df, -1.0 / periodsPerYear / yearFractionMod) + zSpread / periodsPerYear; + return Math.pow(ratePeriodicAnnualPlusOne, -periodsPerYear * yearFractionMod); + } else { + return df * Math.exp(-zSpread * yearFraction); + } + } + + @Override + public ZeroRateSensitivity zeroRatePointSensitivityWithSpread( + double yearFraction, + Currency sensitivityCurrency, + double zSpread, + CompoundedRateType compoundedRateType, + int periodsPerYear) { + + ZeroRateSensitivity sensi = zeroRatePointSensitivity(yearFraction, sensitivityCurrency); + double factor; + if (compoundedRateType.equals(CompoundedRateType.PERIODIC)) { + double yearFractionMod = modifyYearFraction(yearFraction); + double df = discountFactor(yearFraction); + double dfRoot = Math.pow(df, -1d / periodsPerYear / yearFractionMod); + factor = dfRoot / df / Math.pow(dfRoot + zSpread / periodsPerYear, periodsPerYear * yearFractionMod + 1d); + } else { + factor = Math.exp(-zSpread * yearFraction); + } + return sensi.multipliedBy(factor); + } + + //------------------------------------------------------------------------- + private double modifyYearFraction(double yearFraction) { + if (Math.abs(yearFraction) < EFFECTIVE_ZERO) { + return yearFraction < 0d ? -EFFECTIVE_ZERO : EFFECTIVE_ZERO; + } + return yearFraction; + } + //------------------------------------------------------------------------- /** * Returns a new instance with a different curve. diff --git a/modules/pricer/src/main/java/com/opengamma/strata/pricer/ZeroRateDiscountFactors.java b/modules/pricer/src/main/java/com/opengamma/strata/pricer/ZeroRateDiscountFactors.java index 7934cd85b9..8813c152f4 100644 --- a/modules/pricer/src/main/java/com/opengamma/strata/pricer/ZeroRateDiscountFactors.java +++ b/modules/pricer/src/main/java/com/opengamma/strata/pricer/ZeroRateDiscountFactors.java @@ -5,8 +5,6 @@ */ package com.opengamma.strata.pricer; -import static com.opengamma.strata.pricer.SimpleDiscountFactors.EFFECTIVE_ZERO; - import java.io.Serializable; import java.time.LocalDate; import java.util.Map; @@ -56,6 +54,11 @@ public final class ZeroRateDiscountFactors implements DiscountFactors, ImmutableBean, Serializable { + /** + * Year fraction used as an effective zero. + */ + private static final double EFFECTIVE_ZERO = 1e-10; + /** * The currency that the discount factors are for. */ diff --git a/modules/pricer/src/main/java/com/opengamma/strata/pricer/ZeroRatePeriodicDiscountFactors.java b/modules/pricer/src/main/java/com/opengamma/strata/pricer/ZeroRatePeriodicDiscountFactors.java index 943927aba2..dd7560507d 100644 --- a/modules/pricer/src/main/java/com/opengamma/strata/pricer/ZeroRatePeriodicDiscountFactors.java +++ b/modules/pricer/src/main/java/com/opengamma/strata/pricer/ZeroRatePeriodicDiscountFactors.java @@ -56,7 +56,7 @@ public final class ZeroRatePeriodicDiscountFactors /** * Year fraction used as an effective zero. */ - private static final double EFFECTIVE_ZERO = 1e-10; + static final double EFFECTIVE_ZERO = 1e-10; /** * The currency that the discount factors are for. diff --git a/modules/pricer/src/test/java/com/opengamma/strata/pricer/SimpleDiscountFactorsTest.java b/modules/pricer/src/test/java/com/opengamma/strata/pricer/SimpleDiscountFactorsTest.java index 53c553f6fa..d83fa03089 100644 --- a/modules/pricer/src/test/java/com/opengamma/strata/pricer/SimpleDiscountFactorsTest.java +++ b/modules/pricer/src/test/java/com/opengamma/strata/pricer/SimpleDiscountFactorsTest.java @@ -32,6 +32,7 @@ import com.opengamma.strata.market.curve.interpolator.CurveInterpolator; import com.opengamma.strata.market.curve.interpolator.CurveInterpolators; import com.opengamma.strata.market.param.CurrencyParameterSensitivities; +import com.opengamma.strata.market.param.CurrencyParameterSensitivity; /** * Test {@link SimpleDiscountFactors}. @@ -55,6 +56,7 @@ public class SimpleDiscountFactorsTest { private static final double TOL = 1.0e-12; private static final double TOL_FD = 1.0e-8; private static final double EPS = 1.0e-6; + private static final double TOL_SMALL_YF = 1.0e-9; //------------------------------------------------------------------------- @Test @@ -146,7 +148,9 @@ public void test_discountFactor_withSpread_continuous() { @Test public void test_discountFactor_withSpread_continuous_beforeValDate() { SimpleDiscountFactors test = SimpleDiscountFactors.of(GBP, DATE_VAL, CURVE); - assertThat(test.discountFactorWithSpread(DATE_BEFORE, SPREAD, CONTINUOUS, 0)).isEqualTo(1d); + double relativeYearFraction = ACT_365F.relativeYearFraction(DATE_VAL, DATE_BEFORE); + double expected = CURVE.yValue(relativeYearFraction) * Math.exp(-SPREAD * relativeYearFraction); + assertThat(test.discountFactorWithSpread(DATE_BEFORE, SPREAD, CONTINUOUS, 0)).isCloseTo(expected, offset(TOL)); } @Test @@ -164,13 +168,18 @@ public void test_discountFactor_withSpread_periodic() { public void test_discountFactor_withSpread_periodic_beforeValDate() { int periodPerYear = 4; SimpleDiscountFactors test = SimpleDiscountFactors.of(GBP, DATE_VAL, CURVE); - assertThat(test.discountFactorWithSpread(DATE_BEFORE, SPREAD, PERIODIC, periodPerYear)).isEqualTo(1d); + double relativeYearFraction = ACT_365F.relativeYearFraction(DATE_VAL, DATE_BEFORE); + double discountFactorBase = test.discountFactor(DATE_BEFORE); + double rate = (Math.pow(discountFactorBase, -1d / periodPerYear / relativeYearFraction) - 1d) * periodPerYear; + double expected = discountFactorFromPeriodicallyCompoundedRate(rate + SPREAD, periodPerYear, relativeYearFraction); + assertThat(test.discountFactorWithSpread(DATE_BEFORE, SPREAD, PERIODIC, periodPerYear)).isCloseTo(expected, offset(TOL)); } @Test public void test_discountFactor_withSpread_smallYearFraction() { SimpleDiscountFactors test = SimpleDiscountFactors.of(GBP, DATE_VAL, CURVE); - assertThat(test.discountFactorWithSpread(DATE_VAL, SPREAD, PERIODIC, 2)).isEqualTo(1d); + assertThat(test.discountFactorWithSpread(DATE_VAL, SPREAD, PERIODIC, 2)) + .isCloseTo(1d, offset(TOL_SMALL_YF)); } private double discountFactorFromPeriodicallyCompoundedRate(double rate, double periodPerYear, double time) { @@ -191,7 +200,8 @@ public void test_zeroRatePointSensitivity() { public void test_zeroRatePointSensitivity_beforeValDate() { SimpleDiscountFactors test = SimpleDiscountFactors.of(GBP, DATE_VAL, CURVE); double relativeYearFraction = ACT_365F.relativeYearFraction(DATE_VAL, DATE_BEFORE); - ZeroRateSensitivity expected = ZeroRateSensitivity.of(GBP, relativeYearFraction, 0d); + double df = CURVE.yValue(relativeYearFraction); + ZeroRateSensitivity expected = ZeroRateSensitivity.of(GBP, relativeYearFraction, -df * relativeYearFraction); assertThat(test.zeroRatePointSensitivity(DATE_BEFORE)).isEqualTo(expected); } @@ -219,7 +229,8 @@ public void test_zeroRatePointSensitivityWithSpread_continuous_beforeValDate() { SimpleDiscountFactors test = SimpleDiscountFactors.of(GBP, DATE_VAL, CURVE); double relativeYearFraction = ACT_365F.relativeYearFraction(DATE_VAL, DATE_BEFORE); ZeroRateSensitivity expected = ZeroRateSensitivity.of(GBP, relativeYearFraction, 0d); - assertThat(test.zeroRatePointSensitivityWithSpread(DATE_BEFORE, SPREAD, CONTINUOUS, 0)).isEqualTo(expected); + assertThat(test.zeroRatePointSensitivityWithSpread(DATE_BEFORE, SPREAD, CONTINUOUS, 0).build() + .equalWithTolerance(expected.build(), TOL_SMALL_YF)); } @Test @@ -257,9 +268,17 @@ public void test_zeroRatePointSensitivityWithSpread_periodic_beforeValDate() { int periodPerYear = 4; SimpleDiscountFactors test = SimpleDiscountFactors.of(GBP, DATE_VAL, CURVE); double relativeYearFraction = ACT_365F.relativeYearFraction(DATE_VAL, DATE_BEFORE); + double df = CURVE.yValue(relativeYearFraction); + double discountFactorUp = df * Math.exp(-EPS * relativeYearFraction); + double discountFactorDw = df * Math.exp(EPS * relativeYearFraction); + double rateUp = (Math.pow(discountFactorUp, -1d / periodPerYear / relativeYearFraction) - 1d) * periodPerYear; + double rateDw = (Math.pow(discountFactorDw, -1d / periodPerYear / relativeYearFraction) - 1d) * periodPerYear; + double expectedValue = 0.5 / EPS * ( + discountFactorFromPeriodicallyCompoundedRate(rateUp + SPREAD, periodPerYear, relativeYearFraction) - + discountFactorFromPeriodicallyCompoundedRate(rateDw + SPREAD, periodPerYear, relativeYearFraction)); ZeroRateSensitivity computed = test.zeroRatePointSensitivityWithSpread( DATE_BEFORE, SPREAD, PERIODIC, periodPerYear); - assertThat(computed.getSensitivity()).isCloseTo(0d, offset(EPS)); + assertThat(computed.getSensitivity()).isCloseTo(expectedValue, offset(EPS)); assertThat(computed.getCurrency()).isEqualTo(GBP); assertThat(computed.getCurveCurrency()).isEqualTo(GBP); assertThat(computed.getYearFraction()).isEqualTo(relativeYearFraction); @@ -290,14 +309,16 @@ public void test_zeroRatePointSensitivityWithSpread_sensitivityCurrency_periodic public void test_zeroRatePointSensitivityWithSpread_smallYearFraction() { SimpleDiscountFactors test = SimpleDiscountFactors.of(GBP, DATE_VAL, CURVE); ZeroRateSensitivity expected = ZeroRateSensitivity.of(GBP, 0d, 0d); - assertThat(test.zeroRatePointSensitivityWithSpread(DATE_VAL, SPREAD, CONTINUOUS, 0)).isEqualTo(expected); + assertThat(test.zeroRatePointSensitivityWithSpread(DATE_VAL, SPREAD, CONTINUOUS, 0).build() + .equalWithTolerance(expected.build(), TOL_SMALL_YF)); } @Test public void test_zeroRatePointSensitivityWithSpread_sensitivityCurrency_smallYearFraction() { SimpleDiscountFactors test = SimpleDiscountFactors.of(GBP, DATE_VAL, CURVE); ZeroRateSensitivity expected = ZeroRateSensitivity.of(GBP, 0d, USD, 0d); - assertThat(test.zeroRatePointSensitivityWithSpread(DATE_VAL, USD, SPREAD, PERIODIC, 2)).isEqualTo(expected); + assertThat(test.zeroRatePointSensitivityWithSpread(DATE_VAL, USD, SPREAD, PERIODIC, 2).build() + .equalWithTolerance(expected.build(), TOL_SMALL_YF)); } //------------------------------------------------------------------------- @@ -319,16 +340,28 @@ public void test_currencyParameterSensitivity() { public void test_currencyParameterSensitivity_beforeValDate() { SimpleDiscountFactors test = SimpleDiscountFactors.of(GBP, DATE_VAL, CURVE); ZeroRateSensitivity sens = test.zeroRatePointSensitivity(DATE_BEFORE); - assertThat(test.parameterSensitivity(sens)).isEqualTo(CurrencyParameterSensitivities.empty()); + + double relativeYearFraction = ACT_365F.relativeYearFraction(DATE_VAL, DATE_BEFORE); + double discountFactor = CURVE.yValue(relativeYearFraction); + CurrencyParameterSensitivities expected = CurrencyParameterSensitivities.of( + CURVE.yValueParameterSensitivity(relativeYearFraction) + .multipliedBy(-1d / discountFactor / relativeYearFraction) + .multipliedBy(sens.getCurrency(), sens.getSensitivity())); + assertThat(test.parameterSensitivity(sens)).isEqualTo(expected); } //------------------------------------------------------------------------- @Test public void test_currencyParameterSensitivity_val_date() { - // Discount factor at valuation date is always 0, no sensitivity. SimpleDiscountFactors test = SimpleDiscountFactors.of(GBP, DATE_VAL, CURVE); ZeroRateSensitivity sens = test.zeroRatePointSensitivity(DATE_VAL); - assertThat(test.parameterSensitivity(sens)).isEqualTo(CurrencyParameterSensitivities.empty()); + + double relativeYearFraction = ACT_365F.relativeYearFraction(DATE_VAL, DATE_VAL); + double discountFactor = CURVE.yValue(relativeYearFraction); + CurrencyParameterSensitivities expected = CurrencyParameterSensitivities.of( + CurrencyParameterSensitivity.of(NAME, GBP, DoubleArray.of(1d, 0d))); + CurrencyParameterSensitivities tested = test.parameterSensitivity(sens); + assertThat(test.parameterSensitivity(sens).equalWithTolerance(expected, TOL)); } //------------------------------------------------------------------------- From 06f6efdf577f856447c85d31cb1d535027cbe968 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Wed, 17 May 2023 08:45:14 +0000 Subject: [PATCH 012/116] [maven-release-plugin] prepare release v2.12.23 --- examples/pom.xml | 6 +++++- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index e9ea03ffd7..5d78f93c62 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.23-SNAPSHOT + 2.12.23 jar Strata-Examples Example code to demonstrate use of Strata @@ -272,4 +272,8 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> + + + v2.12.23 + diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index c2b7011b86..f538bf95d6 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.23-SNAPSHOT + 2.12.23 .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 2c654867fd..02d172ed3b 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.23-SNAPSHOT + 2.12.23 .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 88739ef904..2eee784d99 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.23-SNAPSHOT + 2.12.23 .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index bbed74b424..8866945d1f 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.23-SNAPSHOT + 2.12.23 .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index e55950ba82..4c4a892295 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.23-SNAPSHOT + 2.12.23 .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 3830f653c7..ade4aac9ba 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.23-SNAPSHOT + 2.12.23 .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 48c53b59e0..4cf2175910 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.23-SNAPSHOT + 2.12.23 .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index e24950a3dc..5ba251887e 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.23-SNAPSHOT + 2.12.23 .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index e6b036c1a0..0a2bc69137 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.23-SNAPSHOT + 2.12.23 pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.23 diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index b97e8b1025..62d58df1be 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.23-SNAPSHOT + 2.12.23 .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 0ff3c8c42a..86414bb8bd 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.23-SNAPSHOT + 2.12.23 .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 7eeb87da95..2682a71a6b 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.23-SNAPSHOT + 2.12.23 .. strata-report diff --git a/pom.xml b/pom.xml index 182dd5bfb2..1e82219535 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.23-SNAPSHOT + 2.12.23 pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.23 From 8352de0af6c1c94b006a4d3037b25d8f71d3ddd8 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Wed, 17 May 2023 08:45:16 +0000 Subject: [PATCH 013/116] [maven-release-plugin] prepare for next development iteration --- examples/pom.xml | 6 +----- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 5d78f93c62..89c2af0cb8 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.23 + 2.12.24-SNAPSHOT jar Strata-Examples Example code to demonstrate use of Strata @@ -272,8 +272,4 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> - - - v2.12.23 - diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index f538bf95d6..b303a68426 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.23 + 2.12.24-SNAPSHOT .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 02d172ed3b..75f725c547 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.23 + 2.12.24-SNAPSHOT .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 2eee784d99..3ca29a7d2f 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.23 + 2.12.24-SNAPSHOT .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 8866945d1f..6caa11a7a1 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.23 + 2.12.24-SNAPSHOT .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 4c4a892295..5f05f668a7 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.23 + 2.12.24-SNAPSHOT .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index ade4aac9ba..cb475d21fc 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.23 + 2.12.24-SNAPSHOT .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 4cf2175910..324f9ce4fc 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.23 + 2.12.24-SNAPSHOT .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 5ba251887e..5966599f60 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.23 + 2.12.24-SNAPSHOT .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 0a2bc69137..24181178ac 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.23 + 2.12.24-SNAPSHOT pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.23 + HEAD diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 62d58df1be..8bf164413c 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.23 + 2.12.24-SNAPSHOT .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 86414bb8bd..381c077913 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.23 + 2.12.24-SNAPSHOT .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 2682a71a6b..567232f436 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.23 + 2.12.24-SNAPSHOT .. strata-report diff --git a/pom.xml b/pom.xml index 1e82219535..6a00d751b0 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.23 + 2.12.24-SNAPSHOT pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.23 + HEAD From 5a7f15db8b4c4f13ebe0a7346baedac9a06c79db Mon Sep 17 00:00:00 2001 From: Stephen Colebourne Date: Thu, 18 May 2023 09:40:18 +0100 Subject: [PATCH 014/116] Comparable Percentage/BasisPoints (#2574) --- .../com/opengamma/strata/collect/BasisPoints.java | 15 +++++++++++++-- .../com/opengamma/strata/collect/Percentage.java | 15 +++++++++++++-- .../opengamma/strata/collect/BasisPointsTest.java | 2 ++ .../opengamma/strata/collect/PercentageTest.java | 2 ++ 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/modules/collect/src/main/java/com/opengamma/strata/collect/BasisPoints.java b/modules/collect/src/main/java/com/opengamma/strata/collect/BasisPoints.java index 7aef8f40a7..7bbee27e3c 100644 --- a/modules/collect/src/main/java/com/opengamma/strata/collect/BasisPoints.java +++ b/modules/collect/src/main/java/com/opengamma/strata/collect/BasisPoints.java @@ -18,11 +18,11 @@ *

    *
  • decimal form - the form needed for mathematical calculations, as used by most parts of Strata *
  • percentage - where 1.2% is the same as the decimal 0.012 - *
  • basis points - where 120bps is the same as the decimal 0.012 + *
  • basis points - where 125bps is the same as the decimal 0.0125 *
* This class allows the use of basis points form to be explicit. */ -public final class BasisPoints { +public final class BasisPoints implements Comparable { /** A basis points of zero. */ public static final BasisPoints ZERO = new BasisPoints(Decimal.ZERO); @@ -181,6 +181,17 @@ public BasisPoints map(UnaryOperator mapper) { } //----------------------------------------------------------------------- + /** + * Compares this instance to another. + * + * @param other the other instance + * @return the comparison result + */ + @Override + public int compareTo(BasisPoints other) { + return amount.compareTo(other.amount); + } + /** * Checks if this instance equals another. * diff --git a/modules/collect/src/main/java/com/opengamma/strata/collect/Percentage.java b/modules/collect/src/main/java/com/opengamma/strata/collect/Percentage.java index 02285d44cc..8e662b575a 100644 --- a/modules/collect/src/main/java/com/opengamma/strata/collect/Percentage.java +++ b/modules/collect/src/main/java/com/opengamma/strata/collect/Percentage.java @@ -18,11 +18,11 @@ *
    *
  • decimal form - the form needed for mathematical calculations, as used by most parts of Strata *
  • percentage - where 1.2% is the same as the decimal 0.012 - *
  • basis points - where 120bps is the same as the decimal 0.012 + *
  • basis points - where 125bps is the same as the decimal 0.0125 *
* This class allows the use of percentage form to be explicit. */ -public final class Percentage { +public final class Percentage implements Comparable { /** A percentage of zero. */ public static final Percentage ZERO = new Percentage(Decimal.ZERO); @@ -183,6 +183,17 @@ public Percentage map(UnaryOperator mapper) { } //----------------------------------------------------------------------- + /** + * Compares this instance to another. + * + * @param other the other instance + * @return the comparison result + */ + @Override + public int compareTo(Percentage other) { + return amount.compareTo(other.amount); + } + /** * Checks if this instance equals another. * diff --git a/modules/collect/src/test/java/com/opengamma/strata/collect/BasisPointsTest.java b/modules/collect/src/test/java/com/opengamma/strata/collect/BasisPointsTest.java index 2b1bd3977c..4a8e82c9ff 100644 --- a/modules/collect/src/test/java/com/opengamma/strata/collect/BasisPointsTest.java +++ b/modules/collect/src/test/java/com/opengamma/strata/collect/BasisPointsTest.java @@ -41,6 +41,8 @@ void test_values(BasisPoints test, String str, Decimal value) { assertThat(BasisPoints.parse(str + "bps")).isEqualTo(test); assertThat(BasisPoints.parse(str + " bps")).isEqualTo(test); assertThat(BasisPoints.parse(str)).isEqualTo(test); + assertThat(BasisPoints.parse(str)).isLessThan(BasisPoints.parse("1000bps")); + assertThat(BasisPoints.parse(str)).isGreaterThan(BasisPoints.parse("-1000bps")); assertThat(test.plus(BasisPoints.ZERO)).isEqualTo(test); assertThat(test.minus(BasisPoints.ZERO)).isEqualTo(test); diff --git a/modules/collect/src/test/java/com/opengamma/strata/collect/PercentageTest.java b/modules/collect/src/test/java/com/opengamma/strata/collect/PercentageTest.java index 1970221db2..c4706b99e1 100644 --- a/modules/collect/src/test/java/com/opengamma/strata/collect/PercentageTest.java +++ b/modules/collect/src/test/java/com/opengamma/strata/collect/PercentageTest.java @@ -43,6 +43,8 @@ void test_values(Percentage test, String str, Decimal value) { assertThat(Percentage.parse(str + "pct")).isEqualTo(test); assertThat(Percentage.parse(str + " pct")).isEqualTo(test); assertThat(Percentage.parse(str)).isEqualTo(test); + assertThat(Percentage.parse(str)).isLessThan(Percentage.parse("1000%")); + assertThat(Percentage.parse(str)).isGreaterThan(Percentage.parse("-1000%")); assertThat(test.plus(Percentage.ZERO)).isEqualTo(test); assertThat(test.minus(Percentage.ZERO)).isEqualTo(test); From d53489595be3b8ae55300f148c924ca43b9c2ac7 Mon Sep 17 00:00:00 2001 From: Stephen Colebourne Date: Thu, 18 May 2023 13:41:42 +0100 Subject: [PATCH 015/116] Propagate cause of more exceptions (#2575) Unwrap cause for CompletionException and ExecutionException --- .../com/opengamma/strata/collect/Unchecked.java | 10 +++++++++- .../opengamma/strata/collect/UncheckedTest.java | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/modules/collect/src/main/java/com/opengamma/strata/collect/Unchecked.java b/modules/collect/src/main/java/com/opengamma/strata/collect/Unchecked.java index 9f9c0973fc..4075f2669a 100644 --- a/modules/collect/src/main/java/com/opengamma/strata/collect/Unchecked.java +++ b/modules/collect/src/main/java/com/opengamma/strata/collect/Unchecked.java @@ -9,6 +9,8 @@ import java.io.IOException; import java.io.UncheckedIOException; import java.lang.reflect.InvocationTargetException; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutionException; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.BiPredicate; @@ -334,6 +336,8 @@ public static Supplier supplier(CheckedSupplier supplier) { * Propagates {@code throwable} as-is if possible, or by wrapping in a {@code RuntimeException} if not. *
    *
  • If {@code throwable} is an {@code InvocationTargetException} the cause is extracted and processed recursively.
  • + *
  • If {@code throwable} is an {@code CompletionException} the cause is extracted and processed recursively.
  • + *
  • If {@code throwable} is an {@code ExecutionException} the cause is extracted and processed recursively.
  • *
  • If {@code throwable} is an {@code Error} or {@code RuntimeException} it is propagated as-is.
  • *
  • If {@code throwable} is an {@code IOException} it is wrapped in {@code UncheckedIOException} and thrown.
  • *
  • If {@code throwable} is an {@code ReflectiveOperationException} it is wrapped in @@ -353,11 +357,15 @@ public static Supplier supplier(CheckedSupplier supplier) { * * * @param throwable the {@code Throwable} to propagate - * @return nothing; this method always throws an exception + * @return never returns as an exception is always thrown */ public static RuntimeException propagate(Throwable throwable) { if (throwable instanceof InvocationTargetException) { throw propagate(((InvocationTargetException) throwable).getCause()); + } else if (throwable instanceof CompletionException) { + throw propagate(((CompletionException) throwable).getCause()); + } else if (throwable instanceof ExecutionException) { + throw propagate(((ExecutionException) throwable).getCause()); } else if (throwable instanceof IOException) { throw new UncheckedIOException((IOException) throwable); } else if (throwable instanceof ReflectiveOperationException) { diff --git a/modules/collect/src/test/java/com/opengamma/strata/collect/UncheckedTest.java b/modules/collect/src/test/java/com/opengamma/strata/collect/UncheckedTest.java index 1f00abcf91..3e5a77b8c7 100644 --- a/modules/collect/src/test/java/com/opengamma/strata/collect/UncheckedTest.java +++ b/modules/collect/src/test/java/com/opengamma/strata/collect/UncheckedTest.java @@ -14,6 +14,8 @@ import java.io.UncheckedIOException; import java.lang.reflect.InvocationTargetException; import java.net.URISyntaxException; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ExecutionException; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.BiPredicate; @@ -379,6 +381,20 @@ public void test_propagate() { assertThat(ex.getClass()).isEqualTo(RuntimeException.class); assertThat(ex.getCause()).isSameAs(namingEx); } + try { + Unchecked.propagate(new CompletionException(ioEx)); + fail("Expected UncheckedIOException"); + } catch (UncheckedIOException ex) { + assertThat(ex.getClass()).isEqualTo(UncheckedIOException.class); + assertThat(ex.getCause()).isSameAs(ioEx); + } + try { + Unchecked.propagate(new ExecutionException(ioEx)); + fail("Expected UncheckedIOException"); + } catch (UncheckedIOException ex) { + assertThat(ex.getClass()).isEqualTo(UncheckedIOException.class); + assertThat(ex.getCause()).isSameAs(ioEx); + } } } From a10729e484e1c12701d688a94ce7cc866f1b359c Mon Sep 17 00:00:00 2001 From: Aaron <110403946+aaron-og@users.noreply.github.com> Date: Wed, 24 May 2023 11:20:10 +0100 Subject: [PATCH 016/116] Created OvernightFutureOptionVolatilitiesId (#2576) --- .../OvernightFutureOptionVolatilitiesId.java | 153 ++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 modules/pricer/src/main/java/com/opengamma/strata/pricer/index/OvernightFutureOptionVolatilitiesId.java diff --git a/modules/pricer/src/main/java/com/opengamma/strata/pricer/index/OvernightFutureOptionVolatilitiesId.java b/modules/pricer/src/main/java/com/opengamma/strata/pricer/index/OvernightFutureOptionVolatilitiesId.java new file mode 100644 index 0000000000..10067ccaae --- /dev/null +++ b/modules/pricer/src/main/java/com/opengamma/strata/pricer/index/OvernightFutureOptionVolatilitiesId.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2023 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.pricer.index; + +import java.io.Serializable; +import java.lang.invoke.MethodHandles; + +import org.joda.beans.ImmutableBean; +import org.joda.beans.JodaBeanUtils; +import org.joda.beans.MetaBean; +import org.joda.beans.TypedMetaBean; +import org.joda.beans.gen.BeanDefinition; +import org.joda.beans.gen.PropertyDefinition; +import org.joda.beans.impl.light.LightMetaBean; + +import com.opengamma.strata.data.MarketDataName; +import com.opengamma.strata.data.NamedMarketDataId; + +/** + * An identifier used to access Overnight future option volatilities by name. + *

    + * This is used when there is a need to obtain an instance of {@link OvernightFutureOptionVolatilities}. + */ +@BeanDefinition(style = "light", cacheHashCode = true) +public final class OvernightFutureOptionVolatilitiesId + implements NamedMarketDataId, ImmutableBean, Serializable { + + /** + * The name of the volatilities. + */ + @PropertyDefinition(validate = "notNull") + private final OvernightFutureOptionVolatilitiesName name; + + //------------------------------------------------------------------------- + /** + * Obtains an identifier used to find Overnight future option volatilities. + * + * @param name the name + * @return an identifier for the volatilities + */ + public static OvernightFutureOptionVolatilitiesId of(String name) { + return new OvernightFutureOptionVolatilitiesId(OvernightFutureOptionVolatilitiesName.of(name)); + } + + /** + * Obtains an identifier used to find Overnight future option volatilities. + * + * @param name the name + * @return an identifier for the volatilities + */ + public static OvernightFutureOptionVolatilitiesId of(OvernightFutureOptionVolatilitiesName name) { + return new OvernightFutureOptionVolatilitiesId(name); + } + + //------------------------------------------------------------------------- + @Override + public Class getMarketDataType() { + return OvernightFutureOptionVolatilities.class; + } + + @Override + public MarketDataName getMarketDataName() { + return name; + } + + @Override + public String toString() { + return "OvernightFutureOptionVolatilitiesId:" + name; + } + + //------------------------- AUTOGENERATED START ------------------------- + /** + * The meta-bean for {@code OvernightFutureOptionVolatilitiesId}. + */ + private static final TypedMetaBean META_BEAN = + LightMetaBean.of( + OvernightFutureOptionVolatilitiesId.class, + MethodHandles.lookup(), + new String[] { + "name"}, + new Object[0]); + + /** + * The meta-bean for {@code OvernightFutureOptionVolatilitiesId}. + * @return the meta-bean, not null + */ + public static TypedMetaBean meta() { + return META_BEAN; + } + + static { + MetaBean.register(META_BEAN); + } + + /** + * The serialization version id. + */ + private static final long serialVersionUID = 1L; + + /** + * The cached hash code, using the racy single-check idiom. + */ + private transient int cacheHashCode; + + private OvernightFutureOptionVolatilitiesId( + OvernightFutureOptionVolatilitiesName name) { + JodaBeanUtils.notNull(name, "name"); + this.name = name; + } + + @Override + public TypedMetaBean metaBean() { + return META_BEAN; + } + + //----------------------------------------------------------------------- + /** + * Gets the name of the volatilities. + * @return the value of the property, not null + */ + public OvernightFutureOptionVolatilitiesName getName() { + return name; + } + + //----------------------------------------------------------------------- + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && obj.getClass() == this.getClass()) { + OvernightFutureOptionVolatilitiesId other = (OvernightFutureOptionVolatilitiesId) obj; + return JodaBeanUtils.equal(name, other.name); + } + return false; + } + + @Override + public int hashCode() { + int hash = cacheHashCode; + if (hash == 0) { + hash = getClass().hashCode(); + hash = hash * 31 + JodaBeanUtils.hashCode(name); + cacheHashCode = hash; + } + return hash; + } + + //-------------------------- AUTOGENERATED END -------------------------- +} From abddec21412e7f48e4e00cdde3c6e566ff119efe Mon Sep 17 00:00:00 2001 From: Aaron <110403946+aaron-og@users.noreply.github.com> Date: Wed, 24 May 2023 11:34:02 +0100 Subject: [PATCH 017/116] Create overnight future option market data and lookup in strata (#2577) * Created OvernightFutureOptionVolatilitiesId * Created overnight variants of index market data classes * checkstyle fix --------- Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- ...efaultOvernightFutureOptionMarketData.java | 171 +++++++++++++++ ...OvernightFutureOptionMarketDataLookup.java | 203 ++++++++++++++++++ ...ernightFutureOptionScenarioMarketData.java | 175 +++++++++++++++ .../OvernightFutureOptionMarketData.java | 68 ++++++ ...OvernightFutureOptionMarketDataLookup.java | 166 ++++++++++++++ ...ernightFutureOptionScenarioMarketData.java | 60 ++++++ ...nightFutureOptionMarketDataLookupTest.java | 124 +++++++++++ 7 files changed, 967 insertions(+) create mode 100644 modules/measure/src/main/java/com/opengamma/strata/measure/index/DefaultOvernightFutureOptionMarketData.java create mode 100644 modules/measure/src/main/java/com/opengamma/strata/measure/index/DefaultOvernightFutureOptionMarketDataLookup.java create mode 100644 modules/measure/src/main/java/com/opengamma/strata/measure/index/DefaultOvernightFutureOptionScenarioMarketData.java create mode 100644 modules/measure/src/main/java/com/opengamma/strata/measure/index/OvernightFutureOptionMarketData.java create mode 100644 modules/measure/src/main/java/com/opengamma/strata/measure/index/OvernightFutureOptionMarketDataLookup.java create mode 100644 modules/measure/src/main/java/com/opengamma/strata/measure/index/OvernightFutureOptionScenarioMarketData.java create mode 100644 modules/measure/src/test/java/com/opengamma/strata/measure/index/OvernightFutureOptionMarketDataLookupTest.java diff --git a/modules/measure/src/main/java/com/opengamma/strata/measure/index/DefaultOvernightFutureOptionMarketData.java b/modules/measure/src/main/java/com/opengamma/strata/measure/index/DefaultOvernightFutureOptionMarketData.java new file mode 100644 index 0000000000..9e9efc8345 --- /dev/null +++ b/modules/measure/src/main/java/com/opengamma/strata/measure/index/DefaultOvernightFutureOptionMarketData.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2023 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.measure.index; + +import java.io.Serializable; +import java.lang.invoke.MethodHandles; + +import org.joda.beans.ImmutableBean; +import org.joda.beans.JodaBeanUtils; +import org.joda.beans.MetaBean; +import org.joda.beans.TypedMetaBean; +import org.joda.beans.gen.BeanDefinition; +import org.joda.beans.gen.ImmutableConstructor; +import org.joda.beans.gen.PropertyDefinition; +import org.joda.beans.impl.light.LightMetaBean; + +import com.opengamma.strata.basics.index.OvernightIndex; +import com.opengamma.strata.collect.ArgChecker; +import com.opengamma.strata.data.MarketData; +import com.opengamma.strata.pricer.index.OvernightFutureOptionVolatilities; + +/** + * The default market data for Overnight future options. + *

    + * This uses a {@link OvernightFutureOptionMarketDataLookup} to provide a view on {@link MarketData}. + */ +@BeanDefinition(style = "light") +final class DefaultOvernightFutureOptionMarketData implements OvernightFutureOptionMarketData, ImmutableBean, Serializable { + + /** + * The lookup. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final OvernightFutureOptionMarketDataLookup lookup; + /** + * The market data. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final MarketData marketData; + + //------------------------------------------------------------------------- + /** + * Obtains an instance based on a lookup and market data. + *

    + * The lookup knows how to obtain the volatilities from the market data. + * This might involve accessing a surface or a cube. + * + * @param lookup the lookup + * @param marketData the market data + * @return the rates market view + */ + public static DefaultOvernightFutureOptionMarketData of( + OvernightFutureOptionMarketDataLookup lookup, + MarketData marketData) { + + return new DefaultOvernightFutureOptionMarketData(lookup, marketData); + } + + @ImmutableConstructor + private DefaultOvernightFutureOptionMarketData( + OvernightFutureOptionMarketDataLookup lookup, + MarketData marketData) { + + this.lookup = ArgChecker.notNull(lookup, "lookup"); + this.marketData = ArgChecker.notNull(marketData, "marketData"); + } + + //------------------------------------------------------------------------- + @Override + public OvernightFutureOptionMarketData withMarketData(MarketData marketData) { + return DefaultOvernightFutureOptionMarketData.of(lookup, marketData); + } + + //------------------------------------------------------------------------- + @Override + public OvernightFutureOptionVolatilities volatilities(OvernightIndex index) { + return lookup.volatilities(index, marketData); + } + + //------------------------- AUTOGENERATED START ------------------------- + /** + * The meta-bean for {@code DefaultOvernightFutureOptionMarketData}. + */ + private static final TypedMetaBean META_BEAN = + LightMetaBean.of( + DefaultOvernightFutureOptionMarketData.class, + MethodHandles.lookup(), + new String[] { + "lookup", + "marketData"}, + new Object[0]); + + /** + * The meta-bean for {@code DefaultOvernightFutureOptionMarketData}. + * @return the meta-bean, not null + */ + public static TypedMetaBean meta() { + return META_BEAN; + } + + static { + MetaBean.register(META_BEAN); + } + + /** + * The serialization version id. + */ + private static final long serialVersionUID = 1L; + + @Override + public TypedMetaBean metaBean() { + return META_BEAN; + } + + //----------------------------------------------------------------------- + /** + * Gets the lookup. + * @return the value of the property, not null + */ + @Override + public OvernightFutureOptionMarketDataLookup getLookup() { + return lookup; + } + + //----------------------------------------------------------------------- + /** + * Gets the market data. + * @return the value of the property, not null + */ + @Override + public MarketData getMarketData() { + return marketData; + } + + //----------------------------------------------------------------------- + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && obj.getClass() == this.getClass()) { + DefaultOvernightFutureOptionMarketData other = (DefaultOvernightFutureOptionMarketData) obj; + return JodaBeanUtils.equal(lookup, other.lookup) && + JodaBeanUtils.equal(marketData, other.marketData); + } + return false; + } + + @Override + public int hashCode() { + int hash = getClass().hashCode(); + hash = hash * 31 + JodaBeanUtils.hashCode(lookup); + hash = hash * 31 + JodaBeanUtils.hashCode(marketData); + return hash; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(96); + buf.append("DefaultOvernightFutureOptionMarketData{"); + buf.append("lookup").append('=').append(JodaBeanUtils.toString(lookup)).append(',').append(' '); + buf.append("marketData").append('=').append(JodaBeanUtils.toString(marketData)); + buf.append('}'); + return buf.toString(); + } + + //-------------------------- AUTOGENERATED END -------------------------- +} diff --git a/modules/measure/src/main/java/com/opengamma/strata/measure/index/DefaultOvernightFutureOptionMarketDataLookup.java b/modules/measure/src/main/java/com/opengamma/strata/measure/index/DefaultOvernightFutureOptionMarketDataLookup.java new file mode 100644 index 0000000000..00647bc00f --- /dev/null +++ b/modules/measure/src/main/java/com/opengamma/strata/measure/index/DefaultOvernightFutureOptionMarketDataLookup.java @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2023 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.measure.index; + +import java.io.Serializable; +import java.lang.invoke.MethodHandles; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.joda.beans.ImmutableBean; +import org.joda.beans.JodaBeanUtils; +import org.joda.beans.MetaBean; +import org.joda.beans.TypedMetaBean; +import org.joda.beans.gen.BeanDefinition; +import org.joda.beans.gen.PropertyDefinition; +import org.joda.beans.impl.light.LightMetaBean; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.opengamma.strata.basics.index.Index; +import com.opengamma.strata.basics.index.OvernightIndex; +import com.opengamma.strata.calc.CalculationRules; +import com.opengamma.strata.calc.runner.CalculationParameter; +import com.opengamma.strata.calc.runner.FunctionRequirements; +import com.opengamma.strata.collect.Messages; +import com.opengamma.strata.data.MarketData; +import com.opengamma.strata.data.MarketDataId; +import com.opengamma.strata.data.MarketDataNotFoundException; +import com.opengamma.strata.data.scenario.ScenarioMarketData; +import com.opengamma.strata.pricer.index.OvernightFutureOptionVolatilities; +import com.opengamma.strata.pricer.index.OvernightFutureOptionVolatilitiesId; + +/** + * The Overnight future option lookup, used to select volatilities for pricing. + *

    + * This provides Overnight future option volatilities by index. + *

    + * The lookup implements {@link CalculationParameter} and is used by passing it + * as an argument to {@link CalculationRules}. It provides the link between the + * data that the function needs and the data that is available in {@link ScenarioMarketData}. + */ +@BeanDefinition(style = "light") +final class DefaultOvernightFutureOptionMarketDataLookup + implements OvernightFutureOptionMarketDataLookup, ImmutableBean, Serializable { + + /** + * The volatility identifiers, keyed by index. + */ + @PropertyDefinition(validate = "notNull") + private final ImmutableMap volatilityIds; + + //------------------------------------------------------------------------- + /** + * Obtains an instance based on a single mapping from index to volatility identifier. + *

    + * The lookup provides volatilities for the specified index. + * + * @param index the Overnight index + * @param volatilityId the volatility identifier + * @return the Overnight future option lookup containing the specified mapping + */ + public static DefaultOvernightFutureOptionMarketDataLookup of(OvernightIndex index, OvernightFutureOptionVolatilitiesId volatilityId) { + return new DefaultOvernightFutureOptionMarketDataLookup(ImmutableMap.of(index, volatilityId)); + } + + /** + * Obtains an instance based on a map of volatility identifiers. + *

    + * The map is used to specify the appropriate volatilities to use for each index. + * + * @param volatilityIds the volatility identifiers, keyed by index + * @return the Overnight future option lookup containing the specified volatilities + */ + public static DefaultOvernightFutureOptionMarketDataLookup of(Map volatilityIds) { + return new DefaultOvernightFutureOptionMarketDataLookup(volatilityIds); + } + + //------------------------------------------------------------------------- + @Override + public ImmutableSet getVolatilityIndices() { + return volatilityIds.keySet(); + } + + @Override + public ImmutableSet> getVolatilityIds(OvernightIndex index) { + OvernightFutureOptionVolatilitiesId id = volatilityIds.get(index); + if (id == null) { + throw new IllegalArgumentException(msgIndexNotFound(index)); + } + return ImmutableSet.of(id); + } + + //------------------------------------------------------------------------- + @Override + public FunctionRequirements requirements(Set indices) { + Set volIds = new HashSet<>(); + for (Index index : indices) { + if (!volatilityIds.keySet().contains(index)) { + throw new IllegalArgumentException(msgIndexNotFound(index)); + } + volIds.add(volatilityIds.get(index)); + } + return FunctionRequirements.builder().valueRequirements(volIds).build(); + } + + //------------------------------------------------------------------------- + @Override + public OvernightFutureOptionVolatilities volatilities(OvernightIndex index, MarketData marketData) { + OvernightFutureOptionVolatilitiesId volatilityId = volatilityIds.get(index); + if (volatilityId == null) { + throw new MarketDataNotFoundException(msgIndexNotFound(index)); + } + return marketData.getValue(volatilityId); + } + + //------------------------------------------------------------------------- + private String msgIndexNotFound(Index index) { + return Messages.format("OvernightFutureOption lookup has no volatilities defined for index '{}'", index); + } + //------------------------- AUTOGENERATED START ------------------------- + /** + * The meta-bean for {@code DefaultOvernightFutureOptionMarketDataLookup}. + */ + private static final TypedMetaBean META_BEAN = + LightMetaBean.of( + DefaultOvernightFutureOptionMarketDataLookup.class, + MethodHandles.lookup(), + new String[] { + "volatilityIds"}, + ImmutableMap.of()); + + /** + * The meta-bean for {@code DefaultOvernightFutureOptionMarketDataLookup}. + * @return the meta-bean, not null + */ + public static TypedMetaBean meta() { + return META_BEAN; + } + + static { + MetaBean.register(META_BEAN); + } + + /** + * The serialization version id. + */ + private static final long serialVersionUID = 1L; + + private DefaultOvernightFutureOptionMarketDataLookup( + Map volatilityIds) { + JodaBeanUtils.notNull(volatilityIds, "volatilityIds"); + this.volatilityIds = ImmutableMap.copyOf(volatilityIds); + } + + @Override + public TypedMetaBean metaBean() { + return META_BEAN; + } + + //----------------------------------------------------------------------- + /** + * Gets the volatility identifiers, keyed by index. + * @return the value of the property, not null + */ + public ImmutableMap getVolatilityIds() { + return volatilityIds; + } + + //----------------------------------------------------------------------- + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && obj.getClass() == this.getClass()) { + DefaultOvernightFutureOptionMarketDataLookup other = (DefaultOvernightFutureOptionMarketDataLookup) obj; + return JodaBeanUtils.equal(volatilityIds, other.volatilityIds); + } + return false; + } + + @Override + public int hashCode() { + int hash = getClass().hashCode(); + hash = hash * 31 + JodaBeanUtils.hashCode(volatilityIds); + return hash; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(64); + buf.append("DefaultOvernightFutureOptionMarketDataLookup{"); + buf.append("volatilityIds").append('=').append(JodaBeanUtils.toString(volatilityIds)); + buf.append('}'); + return buf.toString(); + } + + //-------------------------- AUTOGENERATED END -------------------------- +} diff --git a/modules/measure/src/main/java/com/opengamma/strata/measure/index/DefaultOvernightFutureOptionScenarioMarketData.java b/modules/measure/src/main/java/com/opengamma/strata/measure/index/DefaultOvernightFutureOptionScenarioMarketData.java new file mode 100644 index 0000000000..776207083f --- /dev/null +++ b/modules/measure/src/main/java/com/opengamma/strata/measure/index/DefaultOvernightFutureOptionScenarioMarketData.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2023 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.measure.index; + +import java.io.Serializable; +import java.lang.invoke.MethodHandles; + +import org.joda.beans.ImmutableBean; +import org.joda.beans.JodaBeanUtils; +import org.joda.beans.MetaBean; +import org.joda.beans.TypedMetaBean; +import org.joda.beans.gen.BeanDefinition; +import org.joda.beans.gen.ImmutableConstructor; +import org.joda.beans.gen.PropertyDefinition; +import org.joda.beans.impl.light.LightMetaBean; + +import com.opengamma.strata.collect.ArgChecker; +import com.opengamma.strata.data.scenario.ScenarioMarketData; + +/** + * The default market data for Overnight future options, used for calculation across multiple scenarios. + *

    + * This uses a {@link OvernightFutureOptionMarketDataLookup} to provide a view on {@link ScenarioMarketData}. + */ +@BeanDefinition(style = "light") +final class DefaultOvernightFutureOptionScenarioMarketData + implements OvernightFutureOptionScenarioMarketData, ImmutableBean, Serializable { + + /** + * The lookup. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final OvernightFutureOptionMarketDataLookup lookup; + /** + * The market data. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final ScenarioMarketData marketData; + + //------------------------------------------------------------------------- + /** + * Obtains an instance based on a lookup and market data. + *

    + * The lookup knows how to obtain the volatilities from the market data. + * This might involve accessing a surface or a cube. + * + * @param lookup the lookup + * @param marketData the market data + * @return the rates market view + */ + public static DefaultOvernightFutureOptionScenarioMarketData of( + OvernightFutureOptionMarketDataLookup lookup, + ScenarioMarketData marketData) { + + return new DefaultOvernightFutureOptionScenarioMarketData(lookup, marketData); + } + + @ImmutableConstructor + private DefaultOvernightFutureOptionScenarioMarketData( + OvernightFutureOptionMarketDataLookup lookup, + ScenarioMarketData marketData) { + + this.lookup = ArgChecker.notNull(lookup, "lookup"); + this.marketData = ArgChecker.notNull(marketData, "marketData"); + } + + //------------------------------------------------------------------------- + @Override + public OvernightFutureOptionScenarioMarketData withMarketData(ScenarioMarketData marketData) { + return DefaultOvernightFutureOptionScenarioMarketData.of(lookup, marketData); + } + + //------------------------------------------------------------------------- + @Override + public int getScenarioCount() { + return marketData.getScenarioCount(); + } + + @Override + public OvernightFutureOptionMarketData scenario(int scenarioIndex) { + return lookup.marketDataView(marketData.scenario(scenarioIndex)); + } + + //------------------------- AUTOGENERATED START ------------------------- + /** + * The meta-bean for {@code DefaultOvernightFutureOptionScenarioMarketData}. + */ + private static final TypedMetaBean META_BEAN = + LightMetaBean.of( + DefaultOvernightFutureOptionScenarioMarketData.class, + MethodHandles.lookup(), + new String[] { + "lookup", + "marketData"}, + new Object[0]); + + /** + * The meta-bean for {@code DefaultOvernightFutureOptionScenarioMarketData}. + * @return the meta-bean, not null + */ + public static TypedMetaBean meta() { + return META_BEAN; + } + + static { + MetaBean.register(META_BEAN); + } + + /** + * The serialization version id. + */ + private static final long serialVersionUID = 1L; + + @Override + public TypedMetaBean metaBean() { + return META_BEAN; + } + + //----------------------------------------------------------------------- + /** + * Gets the lookup. + * @return the value of the property, not null + */ + @Override + public OvernightFutureOptionMarketDataLookup getLookup() { + return lookup; + } + + //----------------------------------------------------------------------- + /** + * Gets the market data. + * @return the value of the property, not null + */ + @Override + public ScenarioMarketData getMarketData() { + return marketData; + } + + //----------------------------------------------------------------------- + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && obj.getClass() == this.getClass()) { + DefaultOvernightFutureOptionScenarioMarketData other = (DefaultOvernightFutureOptionScenarioMarketData) obj; + return JodaBeanUtils.equal(lookup, other.lookup) && + JodaBeanUtils.equal(marketData, other.marketData); + } + return false; + } + + @Override + public int hashCode() { + int hash = getClass().hashCode(); + hash = hash * 31 + JodaBeanUtils.hashCode(lookup); + hash = hash * 31 + JodaBeanUtils.hashCode(marketData); + return hash; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(96); + buf.append("DefaultOvernightFutureOptionScenarioMarketData{"); + buf.append("lookup").append('=').append(JodaBeanUtils.toString(lookup)).append(',').append(' '); + buf.append("marketData").append('=').append(JodaBeanUtils.toString(marketData)); + buf.append('}'); + return buf.toString(); + } + + //-------------------------- AUTOGENERATED END -------------------------- +} diff --git a/modules/measure/src/main/java/com/opengamma/strata/measure/index/OvernightFutureOptionMarketData.java b/modules/measure/src/main/java/com/opengamma/strata/measure/index/OvernightFutureOptionMarketData.java new file mode 100644 index 0000000000..c7e09a8d56 --- /dev/null +++ b/modules/measure/src/main/java/com/opengamma/strata/measure/index/OvernightFutureOptionMarketData.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2023 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.measure.index; + +import java.time.LocalDate; + +import com.opengamma.strata.basics.index.OvernightIndex; +import com.opengamma.strata.data.MarketData; +import com.opengamma.strata.data.MarketDataNotFoundException; +import com.opengamma.strata.pricer.index.OvernightFutureOptionVolatilities; + +/** + * Market data for Overnight future options. + *

    + * This interface exposes the market data necessary for pricing an Overnight future option. + *

    + * Implementations of this interface must be immutable. + */ +public interface OvernightFutureOptionMarketData { + + /** + * Gets the valuation date. + * + * @return the valuation date + */ + public default LocalDate getValuationDate() { + return getMarketData().getValuationDate(); + } + + //------------------------------------------------------------------------- + /** + * Gets the lookup that provides access to Overnight future option volatilities. + * + * @return the Overnight future option lookup + */ + public abstract OvernightFutureOptionMarketDataLookup getLookup(); + + /** + * Gets the market data. + * + * @return the market data + */ + public abstract MarketData getMarketData(); + + /** + * Returns a copy of this instance with the specified market data. + * + * @param marketData the market data to use + * @return a market view based on the specified data + */ + public abstract OvernightFutureOptionMarketData withMarketData(MarketData marketData); + + //------------------------------------------------------------------------- + /** + * Gets the volatilities for the specified Overnight index. + *

    + * If the index is not found, an exception is thrown. + * + * @param index the Overnight index + * @return the volatilities for the index + * @throws MarketDataNotFoundException if the index is not found + */ + public abstract OvernightFutureOptionVolatilities volatilities(OvernightIndex index); + +} diff --git a/modules/measure/src/main/java/com/opengamma/strata/measure/index/OvernightFutureOptionMarketDataLookup.java b/modules/measure/src/main/java/com/opengamma/strata/measure/index/OvernightFutureOptionMarketDataLookup.java new file mode 100644 index 0000000000..c8c4a8690e --- /dev/null +++ b/modules/measure/src/main/java/com/opengamma/strata/measure/index/OvernightFutureOptionMarketDataLookup.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2023 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.measure.index; + +import java.util.Map; +import java.util.Set; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.opengamma.strata.basics.index.OvernightIndex; +import com.opengamma.strata.calc.CalculationRules; +import com.opengamma.strata.calc.runner.CalculationParameter; +import com.opengamma.strata.calc.runner.CalculationParameters; +import com.opengamma.strata.calc.runner.FunctionRequirements; +import com.opengamma.strata.data.MarketData; +import com.opengamma.strata.data.MarketDataId; +import com.opengamma.strata.data.MarketDataNotFoundException; +import com.opengamma.strata.data.scenario.ScenarioMarketData; +import com.opengamma.strata.pricer.index.OvernightFutureOptionVolatilities; +import com.opengamma.strata.pricer.index.OvernightFutureOptionVolatilitiesId; + +/** + * The lookup that provides access to Overnight future option volatilities in market data. + *

    + * The Overnight future option market lookup provides access to the volatilities used to price Overnight future options. + *

    + * The lookup implements {@link CalculationParameter} and is used by passing it + * as an argument to {@link CalculationRules}. It provides the link between the + * data that the function needs and the data that is available in {@link ScenarioMarketData}. + *

    + * Implementations of this interface must be immutable. + */ +public interface OvernightFutureOptionMarketDataLookup extends CalculationParameter { + + /** + * Obtains an instance based on a single mapping from index to volatility identifier. + *

    + * The lookup provides volatilities for the specified index. + * + * @param index the Overnight index + * @param volatilityId the volatility identifier + * @return the Overnight future option lookup containing the specified mapping + */ + public static OvernightFutureOptionMarketDataLookup of(OvernightIndex index, OvernightFutureOptionVolatilitiesId volatilityId) { + return DefaultOvernightFutureOptionMarketDataLookup.of(ImmutableMap.of(index, volatilityId)); + } + + /** + * Obtains an instance based on a map of volatility identifiers. + *

    + * The map is used to specify the appropriate volatilities to use for each index. + * + * @param volatilityIds the volatility identifiers, keyed by index + * @return the Overnight future option lookup containing the specified volatilities + */ + public static OvernightFutureOptionMarketDataLookup of(Map volatilityIds) { + return DefaultOvernightFutureOptionMarketDataLookup.of(volatilityIds); + } + + //------------------------------------------------------------------------- + /** + * Gets the type that the lookup will be queried by. + *

    + * This returns {@code OvernightFutureOptionMarketLookup.class}. + * When querying parameters using {@link CalculationParameters#findParameter(Class)}, + * {@code OvernightFutureOptionMarketLookup.class} must be passed in to find the instance. + * + * @return the type of the parameter implementation + */ + @Override + public default Class queryType() { + return OvernightFutureOptionMarketDataLookup.class; + } + + //------------------------------------------------------------------------- + /** + * Gets the set of indices that volatilities are provided for. + * + * @return the set of indices + */ + public abstract ImmutableSet getVolatilityIndices(); + + /** + * Gets the identifiers used to obtain the volatilities for the specified currency. + *

    + * The result will typically refer to a surface or cube. + * If the index is not found, an exception is thrown. + * + * @param index the index for which identifiers are required + * @return the set of market data identifiers + * @throws IllegalArgumentException if the index is not found + */ + public abstract ImmutableSet> getVolatilityIds(OvernightIndex index); + + //------------------------------------------------------------------------- + /** + * Creates market data requirements for the specified indices. + * + * @param indices the indices, for which volatilities are required + * @return the requirements + */ + public default FunctionRequirements requirements(OvernightIndex... indices) { + return requirements(ImmutableSet.copyOf(indices)); + } + + /** + * Creates market data requirements for the specified indices. + * + * @param indices the indices, for which volatilities are required + * @return the requirements + */ + public abstract FunctionRequirements requirements(Set indices); + + //------------------------------------------------------------------------- + /** + * Obtains a filtered view of the complete set of market data. + *

    + * This method returns an instance that binds the lookup to the market data. + * The input is {@link ScenarioMarketData}, which contains market data for all scenarios. + * + * @param marketData the complete set of market data for all scenarios + * @return the filtered market data + */ + public default OvernightFutureOptionScenarioMarketData marketDataView(ScenarioMarketData marketData) { + return DefaultOvernightFutureOptionScenarioMarketData.of(this, marketData); + } + + /** + * Obtains a filtered view of the complete set of market data. + *

    + * This method returns an instance that binds the lookup to the market data. + * The input is {@link MarketData}, which contains market data for one scenario. + * + * @param marketData the complete set of market data for one scenario + * @return the filtered market data + */ + public default OvernightFutureOptionMarketData marketDataView(MarketData marketData) { + return DefaultOvernightFutureOptionMarketData.of(this, marketData); + } + + //------------------------------------------------------------------------- + /** + * Obtains Overnight future option volatilities based on the specified market data. + *

    + * This provides {@link OvernightFutureOptionVolatilities} suitable for pricing an Overnight future option. + * Although this method can be used directly, it is typically invoked indirectly + * via {@link OvernightFutureOptionMarketData}: + *

    +   *  // bind the baseData to this lookup
    +   *  OvernightFutureOptionMarketData view = lookup.marketDataView(baseData);
    +   *
    +   *  // pass around OvernightFutureOptionMarketData within the function to use in pricing
    +   *  OvernightFutureOptionVolatilities vols = view.volatilities(index);
    +   * 
    + * + * @param index the Overnight index + * @param marketData the complete set of market data for one scenario + * @return the volatilities + * @throws MarketDataNotFoundException if the index is not found + */ + public abstract OvernightFutureOptionVolatilities volatilities(OvernightIndex index, MarketData marketData); + +} diff --git a/modules/measure/src/main/java/com/opengamma/strata/measure/index/OvernightFutureOptionScenarioMarketData.java b/modules/measure/src/main/java/com/opengamma/strata/measure/index/OvernightFutureOptionScenarioMarketData.java new file mode 100644 index 0000000000..f0ac64ac04 --- /dev/null +++ b/modules/measure/src/main/java/com/opengamma/strata/measure/index/OvernightFutureOptionScenarioMarketData.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2023 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.measure.index; + +import com.opengamma.strata.data.scenario.ScenarioMarketData; + +/** + * Market data for Overnight future options, used for calculation across multiple scenarios. + *

    + * This interface exposes the market data necessary for pricing an Overnight future option. + *

    + * Implementations of this interface must be immutable. + */ +public interface OvernightFutureOptionScenarioMarketData { + + /** + * Gets the lookup that provides access to Overnight future option volatilities. + * + * @return the Overnight future option lookup + */ + public abstract OvernightFutureOptionMarketDataLookup getLookup(); + + /** + * Gets the market data. + * + * @return the market data + */ + public abstract ScenarioMarketData getMarketData(); + + /** + * Returns a copy of this instance with the specified market data. + * + * @param marketData the market data to use + * @return a market view based on the specified data + */ + public abstract OvernightFutureOptionScenarioMarketData withMarketData(ScenarioMarketData marketData); + + //------------------------------------------------------------------------- + /** + * Gets the number of scenarios. + * + * @return the number of scenarios + */ + public abstract int getScenarioCount(); + + /** + * Returns market data for a single scenario. + *

    + * This returns a view of the market data for the specified scenario. + * + * @param scenarioIndex the scenario index + * @return the market data for the specified scenario + * @throws IndexOutOfBoundsException if the scenario index is invalid + */ + public abstract OvernightFutureOptionMarketData scenario(int scenarioIndex); + +} diff --git a/modules/measure/src/test/java/com/opengamma/strata/measure/index/OvernightFutureOptionMarketDataLookupTest.java b/modules/measure/src/test/java/com/opengamma/strata/measure/index/OvernightFutureOptionMarketDataLookupTest.java new file mode 100644 index 0000000000..a05ea88848 --- /dev/null +++ b/modules/measure/src/test/java/com/opengamma/strata/measure/index/OvernightFutureOptionMarketDataLookupTest.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2023 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.measure.index; + +import static com.opengamma.strata.basics.index.OvernightIndices.GBP_SONIA; +import static com.opengamma.strata.basics.index.OvernightIndices.USD_FED_FUND; +import static com.opengamma.strata.basics.index.OvernightIndices.USD_SOFR; +import static com.opengamma.strata.collect.TestHelper.assertSerialization; +import static com.opengamma.strata.collect.TestHelper.coverBeanEquals; +import static com.opengamma.strata.collect.TestHelper.coverImmutableBean; +import static com.opengamma.strata.collect.TestHelper.date; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.time.LocalDate; + +import org.joda.beans.ImmutableBean; +import org.junit.jupiter.api.Test; + +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; +import com.opengamma.strata.basics.index.OvernightIndex; +import com.opengamma.strata.calc.runner.FunctionRequirements; +import com.opengamma.strata.data.MarketData; +import com.opengamma.strata.data.scenario.ScenarioMarketData; +import com.opengamma.strata.measure.curve.TestMarketDataMap; +import com.opengamma.strata.pricer.index.OvernightFutureOptionVolatilities; +import com.opengamma.strata.pricer.index.OvernightFutureOptionVolatilitiesId; + +/** + * Test {@link OvernightFutureOptionMarketDataLookup}. + */ +public class OvernightFutureOptionMarketDataLookupTest { + + private static final OvernightFutureOptionVolatilitiesId VOL_ID1 = OvernightFutureOptionVolatilitiesId.of("USD1"); + private static final OvernightFutureOptionVolatilities MOCK_VOLS = mock(OvernightFutureOptionVolatilities.class); + private static final MarketData MOCK_MARKET_DATA = mock(MarketData.class); + private static final ScenarioMarketData MOCK_CALC_MARKET_DATA = mock(ScenarioMarketData.class); + + static { + when(MOCK_MARKET_DATA.getValue(VOL_ID1)).thenReturn(MOCK_VOLS); + } + + //------------------------------------------------------------------------- + @Test + public void test_of_single() { + OvernightFutureOptionMarketDataLookup test = OvernightFutureOptionMarketDataLookup.of(USD_SOFR, VOL_ID1); + assertThat(test.queryType()).isEqualTo(OvernightFutureOptionMarketDataLookup.class); + assertThat(test.getVolatilityIndices()).containsOnly(USD_SOFR); + assertThat(test.getVolatilityIds(USD_SOFR)).containsOnly(VOL_ID1); + assertThatIllegalArgumentException() + .isThrownBy(() -> test.getVolatilityIds(GBP_SONIA)); + + assertThat(test.requirements(USD_SOFR)).isEqualTo(FunctionRequirements.builder().valueRequirements(VOL_ID1).build()); + assertThat(test.requirements(ImmutableSet.of(USD_SOFR))) + .isEqualTo(FunctionRequirements.builder().valueRequirements(VOL_ID1).build()); + assertThatIllegalArgumentException() + .isThrownBy(() -> test.requirements(ImmutableSet.of(GBP_SONIA))); + } + + @Test + public void test_of_map() { + ImmutableMap ids = + ImmutableMap.of(USD_SOFR, VOL_ID1, USD_FED_FUND, VOL_ID1); + OvernightFutureOptionMarketDataLookup test = OvernightFutureOptionMarketDataLookup.of(ids); + assertThat(test.queryType()).isEqualTo(OvernightFutureOptionMarketDataLookup.class); + assertThat(test.getVolatilityIndices()).containsOnly(USD_SOFR, USD_FED_FUND); + assertThat(test.getVolatilityIds(USD_SOFR)).containsOnly(VOL_ID1); + assertThatIllegalArgumentException() + .isThrownBy(() -> test.getVolatilityIds(GBP_SONIA)); + + assertThat(test.requirements(USD_SOFR)).isEqualTo(FunctionRequirements.builder().valueRequirements(VOL_ID1).build()); + assertThat(test.requirements(ImmutableSet.of(USD_SOFR))) + .isEqualTo(FunctionRequirements.builder().valueRequirements(VOL_ID1).build()); + assertThatIllegalArgumentException() + .isThrownBy(() -> test.requirements(ImmutableSet.of(GBP_SONIA))); + + assertThat(test.volatilities(USD_SOFR, MOCK_MARKET_DATA)).isEqualTo(MOCK_VOLS); + assertThatIllegalArgumentException() + .isThrownBy(() -> test.volatilities(GBP_SONIA, MOCK_MARKET_DATA)); + } + + //------------------------------------------------------------------------- + @Test + public void test_marketDataView() { + OvernightFutureOptionMarketDataLookup test = OvernightFutureOptionMarketDataLookup.of(USD_SOFR, VOL_ID1); + LocalDate valDate = date(2015, 6, 30); + ScenarioMarketData md = new TestMarketDataMap(valDate, ImmutableMap.of(), ImmutableMap.of()); + OvernightFutureOptionScenarioMarketData multiScenario = test.marketDataView(md); + assertThat(multiScenario.getLookup()).isEqualTo(test); + assertThat(multiScenario.getMarketData()).isEqualTo(md); + assertThat(multiScenario.getScenarioCount()).isEqualTo(1); + OvernightFutureOptionMarketData scenario = multiScenario.scenario(0); + assertThat(scenario.getLookup()).isEqualTo(test); + assertThat(scenario.getMarketData()).isEqualTo(md.scenario(0)); + assertThat(scenario.getValuationDate()).isEqualTo(valDate); + } + + //------------------------------------------------------------------------- + @Test + public void coverage() { + DefaultOvernightFutureOptionMarketDataLookup test = + DefaultOvernightFutureOptionMarketDataLookup.of(ImmutableMap.of(USD_SOFR, VOL_ID1, USD_FED_FUND, VOL_ID1)); + coverImmutableBean(test); + DefaultOvernightFutureOptionMarketDataLookup test2 = DefaultOvernightFutureOptionMarketDataLookup.of(USD_SOFR, VOL_ID1); + coverBeanEquals(test, test2); + + coverImmutableBean((ImmutableBean) test.marketDataView(MOCK_CALC_MARKET_DATA)); + coverImmutableBean((ImmutableBean) test.marketDataView(MOCK_MARKET_DATA)); + } + + @Test + public void test_serialization() { + DefaultOvernightFutureOptionMarketDataLookup test = + DefaultOvernightFutureOptionMarketDataLookup.of(ImmutableMap.of(USD_SOFR, VOL_ID1, USD_FED_FUND, VOL_ID1)); + assertSerialization(test); + } + +} From e7457493f0c0195aaf806b97eed27a29054ba451 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Wed, 24 May 2023 12:28:06 +0000 Subject: [PATCH 018/116] [maven-release-plugin] prepare release v2.12.24 --- examples/pom.xml | 6 +++++- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 89c2af0cb8..9e74b3390e 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.24-SNAPSHOT + 2.12.24 jar Strata-Examples Example code to demonstrate use of Strata @@ -272,4 +272,8 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> + + + v2.12.24 + diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index b303a68426..e2e43770e3 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.24-SNAPSHOT + 2.12.24 .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 75f725c547..781a903403 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.24-SNAPSHOT + 2.12.24 .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 3ca29a7d2f..9d0f8a33d4 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.24-SNAPSHOT + 2.12.24 .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 6caa11a7a1..9bdfdabdac 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.24-SNAPSHOT + 2.12.24 .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 5f05f668a7..6c223ceefc 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.24-SNAPSHOT + 2.12.24 .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index cb475d21fc..912ea4e2ca 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.24-SNAPSHOT + 2.12.24 .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 324f9ce4fc..8a5a71acdb 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.24-SNAPSHOT + 2.12.24 .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 5966599f60..67af4df348 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.24-SNAPSHOT + 2.12.24 .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 24181178ac..99386dac33 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.24-SNAPSHOT + 2.12.24 pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.24 diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 8bf164413c..884d9e192d 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.24-SNAPSHOT + 2.12.24 .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 381c077913..7116ad53aa 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.24-SNAPSHOT + 2.12.24 .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 567232f436..bc464ec4bb 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.24-SNAPSHOT + 2.12.24 .. strata-report diff --git a/pom.xml b/pom.xml index 6a00d751b0..aa8b5b6874 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.24-SNAPSHOT + 2.12.24 pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.24 From d76f43c8898ae22b93623549d28010f2b237ff37 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Wed, 24 May 2023 12:28:07 +0000 Subject: [PATCH 019/116] [maven-release-plugin] prepare for next development iteration --- examples/pom.xml | 6 +----- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 9e74b3390e..38c1ce3bca 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.24 + 2.12.25-SNAPSHOT jar Strata-Examples Example code to demonstrate use of Strata @@ -272,8 +272,4 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> - - - v2.12.24 - diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index e2e43770e3..f7adc344ce 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.24 + 2.12.25-SNAPSHOT .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 781a903403..b54b070695 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.24 + 2.12.25-SNAPSHOT .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 9d0f8a33d4..53ab896238 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.24 + 2.12.25-SNAPSHOT .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 9bdfdabdac..81588b437b 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.24 + 2.12.25-SNAPSHOT .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 6c223ceefc..d18ebb5afb 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.24 + 2.12.25-SNAPSHOT .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 912ea4e2ca..bcffa93dbb 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.24 + 2.12.25-SNAPSHOT .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 8a5a71acdb..7e293da8ce 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.24 + 2.12.25-SNAPSHOT .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 67af4df348..d88fb550b5 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.24 + 2.12.25-SNAPSHOT .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 99386dac33..f6b29ff67f 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.24 + 2.12.25-SNAPSHOT pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.24 + HEAD diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 884d9e192d..589d72f3a2 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.24 + 2.12.25-SNAPSHOT .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 7116ad53aa..3c749c8044 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.24 + 2.12.25-SNAPSHOT .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index bc464ec4bb..9c8db07924 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.24 + 2.12.25-SNAPSHOT .. strata-report diff --git a/pom.xml b/pom.xml index aa8b5b6874..08905acb39 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.24 + 2.12.25-SNAPSHOT pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.24 + HEAD From 622a01e37a399485a0adeb0e9ced19854bebd3b0 Mon Sep 17 00:00:00 2001 From: Yuki Iwashita Date: Tue, 30 May 2023 13:11:43 +0100 Subject: [PATCH 020/116] Yield and Price Derivatives for Inflation Bonds (#2581) --- .../com/opengamma/strata/data/FieldName.java | 24 ++ .../opengamma/strata/data/FieldNameTest.java | 8 + ...untingCapitalIndexedBondProductPricer.java | 223 ++++++++++++++++-- ...ngCapitalIndexedBondProductPricerTest.java | 189 ++++++++++++++- .../CapitalIndexedBondYieldConvention.java | 4 +- 5 files changed, 423 insertions(+), 25 deletions(-) diff --git a/modules/data/src/main/java/com/opengamma/strata/data/FieldName.java b/modules/data/src/main/java/com/opengamma/strata/data/FieldName.java index dfd12fe764..185c12c22b 100644 --- a/modules/data/src/main/java/com/opengamma/strata/data/FieldName.java +++ b/modules/data/src/main/java/com/opengamma/strata/data/FieldName.java @@ -47,6 +47,18 @@ public final class FieldName * The clean price does not include the accrued interest. */ public static final FieldName CLEAN_PRICE = of("CleanPrice"); + /** + * The field name for the clean real price of a capital indexed bond. + *

    + * The clean real price does not include the accrued interest. + */ + public static final FieldName CLEAN_REAL_PRICE = of("CleanRealPrice"); + /** + * The field name for the clean nominal price of a capital indexed bond. + *

    + * The clean nominal price does not include the accrued interest. + */ + public static final FieldName CLEAN_NOMINAL_PRICE = of("CleanNominalPrice"); /** * The field name for the dirty price of a coupon bond. *

    @@ -63,6 +75,18 @@ public final class FieldName * This is used to refer to the yield of a coupon bond or bill. */ public static final FieldName YIELD_TO_MATURITY = of("YieldToMaturity"); + /** + * The field name for the real yield. + *

    + * This is used to refer to the real yield of a capital indexed bond. + */ + public static final FieldName REAL_YIELD_TO_MATURITY = of("RealYieldToMaturity"); + /** + * The field name for the nominal yield. + *

    + * This is used to refer to the yield of a coupon bond or bill. + */ + public static final FieldName NOMINAL_YIELD_TO_MATURITY = of("NominalYieldToMaturity"); /** * The field name for the par yield. *

    diff --git a/modules/data/src/test/java/com/opengamma/strata/data/FieldNameTest.java b/modules/data/src/test/java/com/opengamma/strata/data/FieldNameTest.java index 401d7deb22..03141b1120 100644 --- a/modules/data/src/test/java/com/opengamma/strata/data/FieldNameTest.java +++ b/modules/data/src/test/java/com/opengamma/strata/data/FieldNameTest.java @@ -22,6 +22,14 @@ public void test_of() { assertThat(yieldToMaturity).isEqualTo(FieldName.YIELD_TO_MATURITY); FieldName parYield = FieldName.of("ParYield"); assertThat(parYield).isEqualTo(FieldName.PAR_YIELD); + FieldName cleanRealPrice = FieldName.of("CleanRealPrice"); + assertThat(cleanRealPrice).isEqualTo(FieldName.CLEAN_REAL_PRICE); + FieldName cleanNominalPrice = FieldName.of("CleanNominalPrice"); + assertThat(cleanNominalPrice).isEqualTo(FieldName.CLEAN_NOMINAL_PRICE); + FieldName realYieldToMaturity = FieldName.of("RealYieldToMaturity"); + assertThat(realYieldToMaturity).isEqualTo(FieldName.REAL_YIELD_TO_MATURITY); + FieldName nominalYieldToMaturity = FieldName.of("NominalYieldToMaturity"); + assertThat(nominalYieldToMaturity).isEqualTo(FieldName.NOMINAL_YIELD_TO_MATURITY); } //----------------------------------------------------------------------- diff --git a/modules/pricer/src/main/java/com/opengamma/strata/pricer/bond/DiscountingCapitalIndexedBondProductPricer.java b/modules/pricer/src/main/java/com/opengamma/strata/pricer/bond/DiscountingCapitalIndexedBondProductPricer.java index b0ba43b1d4..263361245c 100644 --- a/modules/pricer/src/main/java/com/opengamma/strata/pricer/bond/DiscountingCapitalIndexedBondProductPricer.java +++ b/modules/pricer/src/main/java/com/opengamma/strata/pricer/bond/DiscountingCapitalIndexedBondProductPricer.java @@ -16,7 +16,9 @@ import com.opengamma.strata.basics.currency.Currency; import com.opengamma.strata.basics.currency.CurrencyAmount; import com.opengamma.strata.basics.currency.MultiCurrencyAmount; +import com.opengamma.strata.basics.value.ValueDerivatives; import com.opengamma.strata.collect.ArgChecker; +import com.opengamma.strata.collect.array.DoubleArray; import com.opengamma.strata.collect.timeseries.LocalDateDoubleTimeSeries; import com.opengamma.strata.market.sensitivity.PointSensitivityBuilder; import com.opengamma.strata.math.impl.rootfinding.BracketRoot; @@ -702,6 +704,154 @@ public double dirtyPriceFromRealYield( "The convention " + bond.getYieldConvention().toString() + " is not supported."); } + /** + * Computes the dirty price from the conventional real yield and its derivative wrt the yield. + *

    + * The resulting dirty price is real price or nominal price depending on the yield convention. + *

    + * The input yield and output are expressed in fraction. + * + * @param bond the product + * @param ratesProvider the rates provider, used to determine price index values + * @param settlementDate the settlement date + * @param yield the yield + * @return the dirty price of the product and its derivative + */ + public ValueDerivatives dirtyPriceFromRealYieldAd( + ResolvedCapitalIndexedBond bond, + RatesProvider ratesProvider, + LocalDate settlementDate, + double yield) { + + ArgChecker.isTrue(settlementDate.isBefore(bond.getUnadjustedEndDate()), + "settlement date must be before end date"); + int periodIndex = bond.findPeriodIndex(settlementDate) + .orElseThrow(() -> new IllegalArgumentException("Date outside range of bond")); + CapitalIndexedBondPaymentPeriod period = bond.getPeriodicPayments().get(periodIndex); + int nbCoupon = bond.getPeriodicPayments().size() - periodIndex; + double couponPerYear = bond.getFrequency().eventsPerYear(); + CapitalIndexedBondYieldConvention yieldConvention = bond.getYieldConvention(); + if (yieldConvention.equals(CapitalIndexedBondYieldConvention.US_IL_REAL)) { + double pvAtFirstCoupon; + double pvAtFirstCouponDeriv; + double cpnRate = bond.getPeriodicPayments().get(0).getRealCoupon(); + if (Math.abs(yield) > 1.0E-8) { + double factorOnPeriod = 1d + yield / couponPerYear; + double factorOnPeriodDeriv = 1d / couponPerYear; + double vn = Math.pow(factorOnPeriod, 1 - nbCoupon); + double vnDeriv = (1d - nbCoupon) * Math.pow(factorOnPeriod, -nbCoupon) * factorOnPeriodDeriv; + pvAtFirstCoupon = cpnRate * couponPerYear / yield * (factorOnPeriod - vn) + vn; + pvAtFirstCouponDeriv = -cpnRate * couponPerYear / yield / yield * (factorOnPeriod - vn) + + cpnRate * couponPerYear / yield * (factorOnPeriodDeriv - vnDeriv) + vnDeriv; + } else { + pvAtFirstCoupon = cpnRate * nbCoupon + 1d; + pvAtFirstCouponDeriv = (1d - nbCoupon) / couponPerYear + 0.5 * (1d - nbCoupon) * nbCoupon * cpnRate / couponPerYear; + } + double den = 1d + factorToNextCoupon(bond, settlementDate) * yield / couponPerYear; + double denDeriv = factorToNextCoupon(bond, settlementDate) / couponPerYear; + double price = pvAtFirstCoupon / den; + double priceDeriv = pvAtFirstCouponDeriv / den - pvAtFirstCoupon / den / den * denDeriv; + return ValueDerivatives.of(price, DoubleArray.of(priceDeriv)); + } + + double realRate = period.getRealCoupon(); + double firstYearFraction = bond.yearFraction(period.getUnadjustedStartDate(), period.getUnadjustedEndDate()); + double v = 1d / (1d + yield / couponPerYear); + double vDeriv = -v * v / couponPerYear; + double rs = ratioPeriodToNextCoupon(period, settlementDate); + if (yieldConvention.equals(CapitalIndexedBondYieldConvention.GB_IL_FLOAT)) { + RateComputation obs = period.getRateComputation(); + LocalDateDoubleTimeSeries ts = ratesProvider.priceIndexValues(bond.getRateCalculation().getIndex()).getFixings(); + YearMonth lastKnownFixingMonth = YearMonth.from(ts.getLatestDate()); + double indexRatio = ts.getLatestValue() / bond.getFirstIndexValue(); + YearMonth endFixingMonth = null; + if (obs instanceof InflationEndInterpolatedRateComputation) { + endFixingMonth = ((InflationEndInterpolatedRateComputation) obs).getEndSecondObservation().getFixingMonth(); + } else if (obs instanceof InflationEndMonthRateComputation) { + endFixingMonth = ((InflationEndMonthRateComputation) obs).getEndObservation().getFixingMonth(); + } else { + throw new IllegalArgumentException("The rate observation " + obs.toString() + " is not supported."); + } + double nbMonth = Math.abs(MONTHS.between(endFixingMonth, lastKnownFixingMonth)); + double u = Math.sqrt(1d / 1.03); + double a = indexRatio * Math.pow(u, nbMonth / 6d); + if (nbCoupon == 1) { + double price = (realRate + 1d) * a / u * Math.pow(u * v, rs); + double priceDeriv = (realRate + 1d) * a / u * Math.pow(u * v, rs - 1d) * rs * u * vDeriv; + return ValueDerivatives.of(price, DoubleArray.of(priceDeriv)); + } else { + double firstCashFlow = firstYearFraction * realRate * indexRatio * couponPerYear; + CapitalIndexedBondPaymentPeriod secondPeriod = bond.getPeriodicPayments().get(periodIndex + 1); + double secondYearFraction = bond.yearFraction(secondPeriod.getUnadjustedStartDate(), secondPeriod.getUnadjustedEndDate()); + double secondCashFlow = secondYearFraction * realRate * indexRatio * couponPerYear; + double vn = Math.pow(v, nbCoupon - 1); + double vnDeriv = (nbCoupon - 1d) * Math.pow(v, nbCoupon - 2) * vDeriv; + double pvAtFirstCoupon = + firstCashFlow + secondCashFlow * u * v + a * realRate * v * v * (1d - vn / v) / (1d - v) + a * vn; + double pvAtFirstCouponDeriv = + secondCashFlow * u * vDeriv + a * vnDeriv + + 2d * a * realRate * v * vDeriv * (1d - vn / v) / (1d - v) - + a * realRate * v * vnDeriv / (1d - v) + + a * realRate * vn * vDeriv / (1d - v) + + a * realRate * v * v * (1d - vn / v) / Math.pow(1d - v, 2) * vDeriv; + double price = pvAtFirstCoupon * Math.pow(u * v, rs); + double priceDeriv = pvAtFirstCouponDeriv * Math.pow(u * v, rs) + + rs * u * vDeriv * pvAtFirstCoupon * Math.pow(u * v, rs - 1); + return ValueDerivatives.of(price, DoubleArray.of(priceDeriv)); + } + } + if (yieldConvention.equals(CapitalIndexedBondYieldConvention.GB_IL_BOND)) { + double indexRatio = indexRatio(bond, ratesProvider, settlementDate); + double firstCashFlow = realRate * indexRatio * firstYearFraction * couponPerYear; + if (nbCoupon == 1) { + double price = Math.pow(v, rs) * (firstCashFlow + 1d); + double priceDeriv = rs * vDeriv * Math.pow(v, rs - 1d) * (firstCashFlow + 1d); + return ValueDerivatives.of(price, DoubleArray.of(priceDeriv)); + } else { + CapitalIndexedBondPaymentPeriod secondPeriod = bond.getPeriodicPayments().get(periodIndex + 1); + double secondYearFraction = bond.yearFraction(secondPeriod.getUnadjustedStartDate(), secondPeriod.getUnadjustedEndDate()); + double secondCashFlow = realRate * indexRatio * secondYearFraction * couponPerYear; + double vn = Math.pow(v, nbCoupon - 1); + double vnDeriv = (nbCoupon - 1d) * vDeriv * Math.pow(v, nbCoupon - 2); + double pvAtFirstCoupon = firstCashFlow + secondCashFlow * v + realRate * v * v * (1d - vn / v) / (1d - v) + vn; + double pvAtFirstCouponDeriv = secondCashFlow * vDeriv + vnDeriv + + 2d * realRate * v * vDeriv * (1d - vn / v) / (1d - v) - + realRate * v * vnDeriv / (1d - v) + + realRate * vDeriv * vn / (1d - v) + + realRate * v * v * vDeriv * (1d - vn / v) / Math.pow(1d - v, 2); + double price = pvAtFirstCoupon * Math.pow(v, rs); + double priceDeriv = pvAtFirstCouponDeriv * Math.pow(v, rs) + pvAtFirstCoupon * Math.pow(v, rs - 1) * vDeriv * rs; + return ValueDerivatives.of(price, DoubleArray.of(priceDeriv)); + } + } + if (yieldConvention.equals(CapitalIndexedBondYieldConvention.JP_IL_SIMPLE)) { + LocalDate maturityDate = bond.getEndDate(); + double maturity = bond.yearFraction(settlementDate, maturityDate); + double cleanPrice = (1d + realRate * couponPerYear * maturity) / (1d + yield * maturity); + double cleanPriceDeriv = -cleanPrice * maturity / (1d + yield * maturity); + double price = dirtyRealPriceFromCleanRealPrice(bond, settlementDate, cleanPrice); + return ValueDerivatives.of(price, DoubleArray.of(cleanPriceDeriv)); + } + if (yieldConvention.equals(CapitalIndexedBondYieldConvention.JP_IL_COMPOUND)) { + double pvAtFirstCoupon = 0d; + double pvAtFirstCouponDeriv = 0d; + for (int loopcpn = 0; loopcpn < nbCoupon; loopcpn++) { + CapitalIndexedBondPaymentPeriod paymentPeriod = bond.getPeriodicPayments().get(loopcpn + periodIndex); + pvAtFirstCoupon += paymentPeriod.getRealCoupon() * Math.pow(v, loopcpn); + pvAtFirstCouponDeriv += paymentPeriod.getRealCoupon() * loopcpn * Math.pow(v, loopcpn - 1) * vDeriv; + } + pvAtFirstCoupon += Math.pow(v, nbCoupon - 1); + pvAtFirstCouponDeriv += (nbCoupon - 1) * Math.pow(v, nbCoupon - 2) * vDeriv; + double factorToNext = factorToNextCoupon(bond, settlementDate); + double price = pvAtFirstCoupon * Math.pow(v, factorToNext); + double priceDeriv = pvAtFirstCouponDeriv * Math.pow(v, factorToNext) + + pvAtFirstCoupon * factorToNext * Math.pow(v, factorToNext - 1d) * vDeriv; + return ValueDerivatives.of(price, DoubleArray.of(priceDeriv)); + } + throw new IllegalArgumentException( + "The convention " + bond.getYieldConvention().toString() + " is not supported."); + } + /** * Computes the clean price from the conventional real yield. *

    @@ -724,9 +874,6 @@ public double cleanPriceFromRealYield( double yield) { double dirtyPrice = dirtyPriceFromRealYield(bond, ratesProvider, settlementDate, yield); - if (bond.getYieldConvention().equals(CapitalIndexedBondYieldConvention.GB_IL_FLOAT)) { - return cleanNominalPriceFromDirtyNominalPrice(bond, ratesProvider, settlementDate, dirtyPrice); - } return cleanRealPriceFromDirtyRealPrice(bond, settlementDate, dirtyPrice); } @@ -761,6 +908,38 @@ public Double apply(Double y) { return yield; } + /** + * Computes the conventional real yield from the dirty price and its derivaitve wrt the dirty price. + *

    + * The input dirty price should be real price or nominal price depending on the yield convention. This is coherent to + * the implementation of {@link #dirtyPriceFromRealYield(ResolvedCapitalIndexedBond, RatesProvider, LocalDate, double)}. + *

    + * The input price and output are expressed in fraction. + * + * @param bond the product + * @param ratesProvider the rates provider, used to determine price index values + * @param settlementDate the settlement date + * @param dirtyPrice the bond dirty price + * @return the yield of the product and its derivative + */ + public ValueDerivatives realYieldFromDirtyPriceAd( + ResolvedCapitalIndexedBond bond, + RatesProvider ratesProvider, + LocalDate settlementDate, + double dirtyPrice) { + + final Function priceResidual = new Function() { + @Override + public Double apply(Double y) { + return dirtyPriceFromRealYield(bond, ratesProvider, settlementDate, y) - dirtyPrice; + } + }; + double[] range = ROOT_BRACKETER.getBracketedPoints(priceResidual, -0.05, 0.10); + double yield = ROOT_FINDER.getRoot(priceResidual, range[0], range[1]); + ValueDerivatives priceDYield = dirtyPriceFromRealYieldAd(bond, ratesProvider, settlementDate, yield); + return ValueDerivatives.of(yield, DoubleArray.of(1.0 / priceDYield.getDerivative(0))); + } + /** * Computes the conventional real yield from the curves. *

    @@ -780,15 +959,10 @@ public double realYieldFromCurves( validate(ratesProvider, discountingProvider); LocalDate settlementDate = bond.calculateSettlementDateFromValuation(ratesProvider.getValuationDate(), refData); - double dirtyPrice; - if (bond.getYieldConvention().equals(CapitalIndexedBondYieldConvention.GB_IL_FLOAT)) { - dirtyPrice = dirtyNominalPriceFromCurves(bond, ratesProvider, discountingProvider, settlementDate); - } else { - double dirtyNominalPrice = - dirtyNominalPriceFromCurves(bond, ratesProvider, discountingProvider, settlementDate); - dirtyPrice = realPriceFromNominalPrice(bond, ratesProvider, settlementDate, dirtyNominalPrice); - } - return realYieldFromDirtyPrice(bond, ratesProvider, settlementDate, dirtyPrice); + double dirtyNominalPrice = + dirtyNominalPriceFromCurves(bond, ratesProvider, discountingProvider, settlementDate); + double dirtyRealPrice = realPriceFromNominalPrice(bond, ratesProvider, settlementDate, dirtyNominalPrice); + return realYieldFromDirtyPrice(bond, ratesProvider, settlementDate, dirtyRealPrice); } /** @@ -1068,6 +1242,28 @@ public double realPriceFromNominalPrice( return nominalPrice / indexRatio; } + /** + * Calculates the real price of the bond from its settlement date and nominal price + * and its derivative wrt the nominal price. + *

    + * The input and output prices are both clean or dirty. + * + * @param bond the product + * @param ratesProvider the rates provider, used to determine price index values + * @param settlementDate the settlement date + * @param nominalPrice the nominal price + * @return the price of the bond product and its derivative + */ + public ValueDerivatives realPriceFromNominalPriceAd( + ResolvedCapitalIndexedBond bond, + RatesProvider ratesProvider, + LocalDate settlementDate, + double nominalPrice) { + + double indexRatio = indexRatio(bond, ratesProvider, settlementDate); + return ValueDerivatives.of(nominalPrice / indexRatio, DoubleArray.of(1d / indexRatio)); + } + /** * Calculates the nominal price of the bond from its settlement date and real price. *

    @@ -1130,9 +1326,6 @@ public Double apply(Double z) { z, compoundedRateType, periodsPerYear); - if (bond.getYieldConvention().equals(CapitalIndexedBondYieldConvention.GB_IL_FLOAT)) { - return cleanNominalPriceFromDirtyNominalPrice(bond, ratesProvider, settlementDate, dirtyPrice) - cleanPrice; - } double dirtyRealPrice = realPriceFromNominalPrice(bond, ratesProvider, settlementDate, dirtyPrice); return cleanRealPriceFromDirtyRealPrice(bond, settlementDate, dirtyRealPrice) - cleanPrice; } diff --git a/modules/pricer/src/test/java/com/opengamma/strata/pricer/bond/DiscountingCapitalIndexedBondProductPricerTest.java b/modules/pricer/src/test/java/com/opengamma/strata/pricer/bond/DiscountingCapitalIndexedBondProductPricerTest.java index 73af939006..4fcb60cb35 100644 --- a/modules/pricer/src/test/java/com/opengamma/strata/pricer/bond/DiscountingCapitalIndexedBondProductPricerTest.java +++ b/modules/pricer/src/test/java/com/opengamma/strata/pricer/bond/DiscountingCapitalIndexedBondProductPricerTest.java @@ -45,6 +45,7 @@ import com.opengamma.strata.basics.schedule.RollConventions; import com.opengamma.strata.basics.schedule.Schedule; import com.opengamma.strata.basics.schedule.StubConvention; +import com.opengamma.strata.basics.value.ValueDerivatives; import com.opengamma.strata.basics.value.ValueSchedule; import com.opengamma.strata.collect.timeseries.LocalDateDoubleTimeSeries; import com.opengamma.strata.market.param.CurrencyParameterSensitivities; @@ -556,6 +557,13 @@ public void test_realPrice_nominalPrice_settleBefore() { double expected = realPrice * (refRate + 1d); assertThat(nominalPrice).isCloseTo(expected, offset(TOL)); assertThat(PRICER.realPriceFromNominalPrice(PRODUCT, RATES_PROVIDER_ON_PAY, refDate, nominalPrice)).isCloseTo(realPrice, offset(TOL)); + + ValueDerivatives realPriceAd = PRICER.realPriceFromNominalPriceAd(PRODUCT, RATES_PROVIDER_ON_PAY, refDate, nominalPrice); + assertThat(realPrice).isCloseTo(realPriceAd.getValue(), offset(TOL)); + double eps = 1.0e-5; + double dirtyPriceUp = PRICER.realPriceFromNominalPrice(PRODUCT, RATES_PROVIDER_ON_PAY, refDate, nominalPrice + eps); + double dirtyPriceDw = PRICER.realPriceFromNominalPrice(PRODUCT, RATES_PROVIDER_ON_PAY, refDate, nominalPrice - eps); + assertThat(realPriceAd.getDerivative(0)).isCloseTo(0.5 * (dirtyPriceUp - dirtyPriceDw) / eps, offset(eps)); } @Test @@ -568,6 +576,13 @@ public void test_realPrice_nominalPrice_settleAfter() { double expected = realPrice * (refRate + 1d); assertThat(nominalPrice).isCloseTo(expected, offset(TOL)); assertThat(PRICER.realPriceFromNominalPrice(PRODUCT, RATES_PROVIDER, refDate, nominalPrice)).isCloseTo(realPrice, offset(TOL)); + + ValueDerivatives realPriceAd = PRICER.realPriceFromNominalPriceAd(PRODUCT, RATES_PROVIDER, refDate, nominalPrice); + assertThat(realPrice).isCloseTo(realPriceAd.getValue(), offset(TOL)); + double eps = 1.0e-5; + double dirtyPriceUp = PRICER.realPriceFromNominalPrice(PRODUCT, RATES_PROVIDER, refDate, nominalPrice + eps); + double dirtyPriceDw = PRICER.realPriceFromNominalPrice(PRODUCT, RATES_PROVIDER, refDate, nominalPrice - eps); + assertThat(realPriceAd.getDerivative(0)).isCloseTo(0.5 * (dirtyPriceUp - dirtyPriceDw) / eps, offset(eps)); } @Test @@ -633,6 +648,36 @@ public void test_priceFromRealYield_us() { assertThat(computed).isEqualTo(cleanPrice); double yieldRe = PRICER.realYieldFromDirtyPrice(PRODUCT_US, RATES_PROVS_US, standardSettle, dirtyPrice); assertThat(yieldRe).isCloseTo(YIELD_US, offset(TOL)); + + ValueDerivatives dirtyPriceAd = PRICER.dirtyPriceFromRealYieldAd(PRODUCT_US, RATES_PROVS_US, standardSettle, YIELD_US); + assertThat(dirtyPrice).isCloseTo(dirtyPriceAd.getValue(), offset(TOL)); + double eps = 1.0e-5; + double dirtyPriceUp = PRICER.dirtyPriceFromRealYield(PRODUCT_US, RATES_PROVS_US, standardSettle, YIELD_US + eps); + double dirtyPriceDw = PRICER.dirtyPriceFromRealYield(PRODUCT_US, RATES_PROVS_US, standardSettle, YIELD_US - eps); + assertThat(dirtyPriceAd.getDerivative(0)).isCloseTo(0.5 * (dirtyPriceUp - dirtyPriceDw) / eps, offset(eps)); + ValueDerivatives realYieldAd = PRICER.realYieldFromDirtyPriceAd(PRODUCT_US, RATES_PROVS_US, standardSettle, dirtyPrice); + double realYieldUp = PRICER.realYieldFromDirtyPrice(PRODUCT_US, RATES_PROVS_US, standardSettle, dirtyPrice + eps); + double realYieldDw = PRICER.realYieldFromDirtyPrice(PRODUCT_US, RATES_PROVS_US, standardSettle, dirtyPrice - eps); + assertThat(realYieldAd.getDerivative(0)).isCloseTo(0.5 * (realYieldUp - realYieldDw) / eps, offset(eps)); + } + + @Test + public void test_priceFromRealYield_us_zeroYield() { + double yield = 0d; + LocalDate standardSettle = PRODUCT_US.getSettlementDateOffset().adjust(VAL_DATE, REF_DATA); + double dirtyPrice = PRICER.dirtyPriceFromRealYield(PRODUCT_US, RATES_PROVS_US, standardSettle, yield); + double yieldRe = PRICER.realYieldFromDirtyPrice(PRODUCT_US, RATES_PROVS_US, standardSettle, dirtyPrice); + assertThat(yieldRe).isCloseTo(yield, offset(TOL)); + ValueDerivatives dirtyPriceAd = PRICER.dirtyPriceFromRealYieldAd(PRODUCT_US, RATES_PROVS_US, standardSettle, yield); + assertThat(dirtyPrice).isCloseTo(dirtyPriceAd.getValue(), offset(TOL)); + double eps = 1.0e-5; + double dirtyPriceUp = PRICER.dirtyPriceFromRealYield(PRODUCT_US, RATES_PROVS_US, standardSettle, yield + eps); + double dirtyPriceDw = PRICER.dirtyPriceFromRealYield(PRODUCT_US, RATES_PROVS_US, standardSettle, yield - eps); + assertThat(dirtyPriceAd.getDerivative(0)).isCloseTo(0.5 * (dirtyPriceUp - dirtyPriceDw) / eps, offset(eps)); + ValueDerivatives realYieldAd = PRICER.realYieldFromDirtyPriceAd(PRODUCT_US, RATES_PROVS_US, standardSettle, dirtyPrice); + double realYieldUp = PRICER.realYieldFromDirtyPrice(PRODUCT_US, RATES_PROVS_US, standardSettle, dirtyPrice + eps); + double realYieldDw = PRICER.realYieldFromDirtyPrice(PRODUCT_US, RATES_PROVS_US, standardSettle, dirtyPrice - eps); + assertThat(realYieldAd.getDerivative(0)).isCloseTo(0.5 * (realYieldUp - realYieldDw) / eps, offset(eps)); } @Test @@ -706,6 +751,13 @@ public void test_accruedInterest_us() { private static final DaysAdjustment SETTLE_OFFSET_GB = DaysAdjustment.ofBusinessDays(1, GBLO); private static final PeriodicSchedule SCHEDULE_GOV = PeriodicSchedule.of(START_GOV, END_GOV, FREQUENCY, BUSINESS_ADJUST_GOV, StubConvention.NONE, RollConventions.NONE); + private static final PeriodicSchedule SCHEDULE_GOV_ONE_PERIOD = PeriodicSchedule.of( + LocalDate.of(2016, 3, 1), + LocalDate.of(2016, 9, 1), + FREQUENCY, + BUSINESS_ADJUST_GOV, + StubConvention.NONE, + RollConventions.NONE); private static final BusinessDayAdjustment EX_COUPON_ADJ_GOV = BusinessDayAdjustment.of(BusinessDayConventions.PRECEDING, GBLO); private static final DaysAdjustment EX_COUPON_GOV = DaysAdjustment.ofCalendarDays(-8, EX_COUPON_ADJ_GOV); @@ -722,6 +774,19 @@ public void test_accruedInterest_us() { .exCouponPeriod(EX_COUPON_GOV) .build() .resolve(REF_DATA); + private static final ResolvedCapitalIndexedBond PRODUCT_GOV_ONE_PERIOD = CapitalIndexedBond.builder() + .securityId(SECURITY_ID) + .notional(NTNL) + .currency(GBP) + .dayCount(ACT_ACT_ICMA) + .rateCalculation(RATE_CALC_GOV) + .legalEntityId(LEGAL_ENTITY) + .yieldConvention(GB_IL_FLOAT) + .settlementDateOffset(SETTLE_OFFSET_GB) + .accrualSchedule(SCHEDULE_GOV_ONE_PERIOD) + .exCouponPeriod(EX_COUPON_GOV) + .build() + .resolve(REF_DATA); private static final double YIELD_GOV = -0.01532; private static final double START_INDEX_GOV_OP = 81.623; @@ -748,16 +813,45 @@ public void test_accruedInterest_us() { public void test_priceFromRealYield_ukGov() { LocalDate standardSettle = PRODUCT_GOV.getSettlementDateOffset().adjust(VAL_DATE_GB, REF_DATA); double computed = PRICER.cleanPriceFromRealYield(PRODUCT_GOV, RATES_PROVS_GB, standardSettle, YIELD_GOV); - assertThat(computed).isCloseTo(3.60, offset(1.e-2)); + assertThat(computed).isCloseTo(3.60, offset(1.e-1)); double computedOnePeriod = PRICER.cleanPriceFromRealYield(PRODUCT_GOV_OP, RATES_PROVS_GB, PRODUCT_GOV_OP .getSettlementDateOffset().adjust(VAL_DATE_GB, REF_DATA), YIELD_GOV_OP); assertThat(computedOnePeriod).isCloseTo(3.21, offset(4.e-2)); double dirtyPrice = PRICER.dirtyPriceFromRealYield(PRODUCT_GOV, RATES_PROVS_GB, standardSettle, YIELD_GOV); - double cleanPrice = PRICER.cleanNominalPriceFromDirtyNominalPrice( - PRODUCT_GOV, RATES_PROVS_GB, standardSettle, dirtyPrice); + double cleanPrice = PRICER.cleanRealPriceFromDirtyRealPrice(PRODUCT_GOV, standardSettle, dirtyPrice); assertThat(computed).isEqualTo(cleanPrice); double yieldRe = PRICER.realYieldFromDirtyPrice(PRODUCT_GOV, RATES_PROVS_GB, standardSettle, dirtyPrice); assertThat(yieldRe).isCloseTo(YIELD_GOV, offset(TOL)); + + ValueDerivatives dirtyPriceAd = PRICER.dirtyPriceFromRealYieldAd(PRODUCT_GOV, RATES_PROVS_GB, standardSettle, YIELD_GOV); + assertThat(dirtyPrice).isCloseTo(dirtyPriceAd.getValue(), offset(TOL)); + double eps = 1.0e-5; + double dirtyPriceUp = PRICER.dirtyPriceFromRealYield(PRODUCT_GOV, RATES_PROVS_GB, standardSettle, YIELD_GOV + eps); + double dirtyPriceDw = PRICER.dirtyPriceFromRealYield(PRODUCT_GOV, RATES_PROVS_GB, standardSettle, YIELD_GOV - eps); + assertThat(dirtyPriceAd.getDerivative(0)).isCloseTo(0.5 * (dirtyPriceUp - dirtyPriceDw) / eps, offset(eps)); + ValueDerivatives realYieldAd = PRICER.realYieldFromDirtyPriceAd(PRODUCT_GOV, RATES_PROVS_GB, standardSettle, dirtyPrice); + double realYieldUp = PRICER.realYieldFromDirtyPrice(PRODUCT_GOV, RATES_PROVS_GB, standardSettle, dirtyPrice + eps); + double realYieldDw = PRICER.realYieldFromDirtyPrice(PRODUCT_GOV, RATES_PROVS_GB, standardSettle, dirtyPrice - eps); + assertThat(realYieldAd.getDerivative(0)).isCloseTo(0.5 * (realYieldUp - realYieldDw) / eps, offset(eps)); + } + + @Test + public void test_priceFromRealYield_ukGov_onePeriod() { + LocalDate standardSettle = PRODUCT_GOV_ONE_PERIOD.getSettlementDateOffset().adjust(VAL_DATE_GB, REF_DATA); + double dirtyPrice = PRICER.dirtyPriceFromRealYield(PRODUCT_GOV_ONE_PERIOD, RATES_PROVS_GB, standardSettle, YIELD_GOV); + double yieldRe = PRICER.realYieldFromDirtyPrice(PRODUCT_GOV_ONE_PERIOD, RATES_PROVS_GB, standardSettle, dirtyPrice); + assertThat(yieldRe).isCloseTo(YIELD_GOV, offset(TOL)); + + ValueDerivatives dirtyPriceAd = PRICER.dirtyPriceFromRealYieldAd(PRODUCT_GOV_ONE_PERIOD, RATES_PROVS_GB, standardSettle, YIELD_GOV); + assertThat(dirtyPrice).isCloseTo(dirtyPriceAd.getValue(), offset(TOL)); + double eps = 1.0e-5; + double dirtyPriceUp = PRICER.dirtyPriceFromRealYield(PRODUCT_GOV_ONE_PERIOD, RATES_PROVS_GB, standardSettle, YIELD_GOV + eps); + double dirtyPriceDw = PRICER.dirtyPriceFromRealYield(PRODUCT_GOV_ONE_PERIOD, RATES_PROVS_GB, standardSettle, YIELD_GOV - eps); + assertThat(dirtyPriceAd.getDerivative(0)).isCloseTo(0.5 * (dirtyPriceUp - dirtyPriceDw) / eps, offset(eps)); + ValueDerivatives realYieldAd = PRICER.realYieldFromDirtyPriceAd(PRODUCT_GOV_ONE_PERIOD, RATES_PROVS_GB, standardSettle, dirtyPrice); + double realYieldUp = PRICER.realYieldFromDirtyPrice(PRODUCT_GOV_ONE_PERIOD, RATES_PROVS_GB, standardSettle, dirtyPrice + eps); + double realYieldDw = PRICER.realYieldFromDirtyPrice(PRODUCT_GOV_ONE_PERIOD, RATES_PROVS_GB, standardSettle, dirtyPrice - eps); + assertThat(realYieldAd.getDerivative(0)).isCloseTo(0.5 * (realYieldUp - realYieldDw) / eps, offset(eps)); } @Test @@ -781,7 +875,8 @@ public void test_realYieldFromCurves_ukGov() { double computed = PRICER.realYieldFromCurves(PRODUCT_GOV, RATES_PROVS_GB, ISSUER_PROVS_GB, REF_DATA); double dirtyNominalPrice = PRICER.dirtyNominalPriceFromCurves( PRODUCT_GOV, RATES_PROVS_GB, ISSUER_PROVS_GB, REF_DATA); - double expected = PRICER.realYieldFromDirtyPrice(PRODUCT_GOV, RATES_PROVS_GB, standardSettle, dirtyNominalPrice); + double dirtyRealPrice = PRICER.realPriceFromNominalPrice(PRODUCT_GOV, RATES_PROVS_GB, standardSettle, dirtyNominalPrice); + double expected = PRICER.realYieldFromDirtyPrice(PRODUCT_GOV, RATES_PROVS_GB, standardSettle, dirtyRealPrice); assertThat(computed).isCloseTo(expected, offset(TOL)); } @@ -792,8 +887,10 @@ public void zSpreadFromCurvesAndCleanPrice_ukGov() { PRODUCT_GOV, RATES_PROVS_GB, ISSUER_PROVS_GB, REF_DATA, Z_SPREAD, PERIODIC, PERIOD_PER_YEAR); double cleanNominalPrice = PRICER.cleanNominalPriceFromDirtyNominalPrice(PRODUCT_GOV, RATES_PROVS_GB, standardSettle, dirtyNominalPrice); + double cleanRealPrice = + PRICER.realPriceFromNominalPrice(PRODUCT_GOV, RATES_PROVS_GB, standardSettle, cleanNominalPrice); double computed = PRICER.zSpreadFromCurvesAndCleanPrice( - PRODUCT_GOV, RATES_PROVS_GB, ISSUER_PROVS_GB, REF_DATA, cleanNominalPrice, PERIODIC, PERIOD_PER_YEAR); + PRODUCT_GOV, RATES_PROVS_GB, ISSUER_PROVS_GB, REF_DATA, cleanRealPrice, PERIODIC, PERIOD_PER_YEAR); assertThat(computed).isCloseTo(Z_SPREAD, offset(TOL)); } @@ -822,9 +919,20 @@ public void test_accruedInterest_ukGov() { private static final LocalDate END_CORP = LocalDate.of(2040, 3, 22); private static final BusinessDayAdjustment BUSINESS_ADJUST_CORP = BusinessDayAdjustment.of(BusinessDayConventions.FOLLOWING, GBLO); - private static final PeriodicSchedule SCHEDULE_CORP = - PeriodicSchedule.of(START_CORP, END_CORP, FREQUENCY, BUSINESS_ADJUST_CORP, StubConvention.NONE, - RollConventions.NONE); + private static final PeriodicSchedule SCHEDULE_CORP = PeriodicSchedule.of( + START_CORP, + END_CORP, + FREQUENCY, + BUSINESS_ADJUST_CORP, + StubConvention.NONE, + RollConventions.NONE); + private static final PeriodicSchedule SCHEDULE_CORP_ONE_PERIOD = PeriodicSchedule.of( + LocalDate.of(2016, 2, 15), + LocalDate.of(2016, 8, 15), + FREQUENCY, + BUSINESS_ADJUST_CORP, + StubConvention.NONE, + RollConventions.NONE); private static final BusinessDayAdjustment EX_COUPON_ADJ_CORP = BusinessDayAdjustment.of(BusinessDayConventions.PRECEDING, GBLO); private static final DaysAdjustment EX_COUPON_CORP = DaysAdjustment.ofCalendarDays(-8, EX_COUPON_ADJ_CORP); @@ -841,6 +949,19 @@ public void test_accruedInterest_ukGov() { .exCouponPeriod(EX_COUPON_CORP) .build() .resolve(REF_DATA); + private static final ResolvedCapitalIndexedBond PRODUCT_CORP_ONE_PERIOD = CapitalIndexedBond.builder() + .securityId(SECURITY_ID) + .notional(NTNL) + .currency(GBP) + .dayCount(ACT_ACT_ICMA) + .rateCalculation(RATE_CALC_CORP) + .legalEntityId(LEGAL_ENTITY) + .yieldConvention(GB_IL_BOND) + .settlementDateOffset(SETTLE_OFFSET_GB) + .accrualSchedule(SCHEDULE_CORP_ONE_PERIOD) + .exCouponPeriod(EX_COUPON_CORP) + .build() + .resolve(REF_DATA); private static final double YIELD_CORP = -0.00842; @Test @@ -856,6 +977,36 @@ public void test_priceFromRealYield_ukCorp() { assertThat(computed).isEqualTo(cleanPrice); double yieldRe = PRICER.realYieldFromDirtyPrice(PRODUCT_CORP, RATES_PROVS_GB, standardSettle, dirtyPrice); assertThat(yieldRe).isCloseTo(YIELD_CORP, offset(TOL)); + + ValueDerivatives dirtyPriceAd = PRICER.dirtyPriceFromRealYieldAd(PRODUCT_CORP, RATES_PROVS_GB, standardSettle, YIELD_CORP); + assertThat(dirtyPrice).isCloseTo(dirtyPriceAd.getValue(), offset(TOL)); + double eps = 1.0e-5; + double dirtyPriceUp = PRICER.dirtyPriceFromRealYield(PRODUCT_CORP, RATES_PROVS_GB, standardSettle, YIELD_CORP + eps); + double dirtyPriceDw = PRICER.dirtyPriceFromRealYield(PRODUCT_CORP, RATES_PROVS_GB, standardSettle, YIELD_CORP - eps); + assertThat(dirtyPriceAd.getDerivative(0)).isCloseTo(0.5 * (dirtyPriceUp - dirtyPriceDw) / eps, offset(eps)); + ValueDerivatives realYieldAd = PRICER.realYieldFromDirtyPriceAd(PRODUCT_CORP, RATES_PROVS_GB, standardSettle, dirtyPrice); + double realYieldUp = PRICER.realYieldFromDirtyPrice(PRODUCT_CORP, RATES_PROVS_GB, standardSettle, dirtyPrice + eps); + double realYieldDw = PRICER.realYieldFromDirtyPrice(PRODUCT_CORP, RATES_PROVS_GB, standardSettle, dirtyPrice - eps); + assertThat(realYieldAd.getDerivative(0)).isCloseTo(0.5 * (realYieldUp - realYieldDw) / eps, offset(eps)); + } + + @Test + public void test_priceFromRealYield_ukCorp_onePeriod() { + LocalDate standardSettle = PRODUCT_CORP_ONE_PERIOD.getSettlementDateOffset().adjust(VAL_DATE_GB, REF_DATA); + double dirtyPrice = PRICER.dirtyPriceFromRealYield(PRODUCT_CORP_ONE_PERIOD, RATES_PROVS_GB, standardSettle, YIELD_CORP); + double yieldRe = PRICER.realYieldFromDirtyPrice(PRODUCT_CORP_ONE_PERIOD, RATES_PROVS_GB, standardSettle, dirtyPrice); + assertThat(yieldRe).isCloseTo(YIELD_CORP, offset(TOL)); + + ValueDerivatives dirtyPriceAd = PRICER.dirtyPriceFromRealYieldAd(PRODUCT_CORP_ONE_PERIOD, RATES_PROVS_GB, standardSettle, YIELD_CORP); + assertThat(dirtyPrice).isCloseTo(dirtyPriceAd.getValue(), offset(TOL)); + double eps = 1.0e-5; + double dirtyPriceUp = PRICER.dirtyPriceFromRealYield(PRODUCT_CORP_ONE_PERIOD, RATES_PROVS_GB, standardSettle, YIELD_CORP + eps); + double dirtyPriceDw = PRICER.dirtyPriceFromRealYield(PRODUCT_CORP_ONE_PERIOD, RATES_PROVS_GB, standardSettle, YIELD_CORP - eps); + assertThat(dirtyPriceAd.getDerivative(0)).isCloseTo(0.5 * (dirtyPriceUp - dirtyPriceDw) / eps, offset(eps)); + ValueDerivatives realYieldAd = PRICER.realYieldFromDirtyPriceAd(PRODUCT_CORP_ONE_PERIOD, RATES_PROVS_GB, standardSettle, dirtyPrice); + double realYieldUp = PRICER.realYieldFromDirtyPrice(PRODUCT_CORP_ONE_PERIOD, RATES_PROVS_GB, standardSettle, dirtyPrice + eps); + double realYieldDw = PRICER.realYieldFromDirtyPrice(PRODUCT_CORP_ONE_PERIOD, RATES_PROVS_GB, standardSettle, dirtyPrice - eps); + assertThat(realYieldAd.getDerivative(0)).isCloseTo(0.5 * (realYieldUp - realYieldDw) / eps, offset(eps)); } @Test @@ -955,6 +1106,17 @@ public void test_priceFromRealYield_jpi() { assertThat(computed).isEqualTo(cleanPrice); double yieldRe = PRICER.realYieldFromDirtyPrice(PRODUCT_JPI, RATES_PROVS_JP, standardSettle, dirtyPrice); assertThat(yieldRe).isCloseTo(YIELD_JPI, offset(TOL)); + + ValueDerivatives dirtyPriceAd = PRICER.dirtyPriceFromRealYieldAd(PRODUCT_JPI, RATES_PROVS_JP, standardSettle, YIELD_JPI); + assertThat(dirtyPrice).isCloseTo(dirtyPriceAd.getValue(), offset(TOL)); + double eps = 1.0e-5; + double dirtyPriceUp = PRICER.dirtyPriceFromRealYield(PRODUCT_JPI, RATES_PROVS_JP, standardSettle, YIELD_JPI + eps); + double dirtyPriceDw = PRICER.dirtyPriceFromRealYield(PRODUCT_JPI, RATES_PROVS_JP, standardSettle, YIELD_JPI - eps); + assertThat(dirtyPriceAd.getDerivative(0)).isCloseTo(0.5 * (dirtyPriceUp - dirtyPriceDw) / eps, offset(eps)); + ValueDerivatives realYieldAd = PRICER.realYieldFromDirtyPriceAd(PRODUCT_JPI, RATES_PROVS_JP, standardSettle, dirtyPrice); + double realYieldUp = PRICER.realYieldFromDirtyPrice(PRODUCT_JPI, RATES_PROVS_JP, standardSettle, dirtyPrice + eps); + double realYieldDw = PRICER.realYieldFromDirtyPrice(PRODUCT_JPI, RATES_PROVS_JP, standardSettle, dirtyPrice - eps); + assertThat(realYieldAd.getDerivative(0)).isCloseTo(0.5 * (realYieldUp - realYieldDw) / eps, offset(eps)); } @Test @@ -1050,6 +1212,17 @@ public void test_priceFromRealYield_jpw() { assertThat(computed).isEqualTo(cleanPrice); double yieldRe = PRICER.realYieldFromDirtyPrice(PRODUCT_JPW, RATES_PROVS_JP, standardSettle, dirtyPrice); assertThat(yieldRe).isCloseTo(YIELD_JPW, offset(TOL)); + + ValueDerivatives dirtyPriceAd = PRICER.dirtyPriceFromRealYieldAd(PRODUCT_JPW, RATES_PROVS_JP, standardSettle, YIELD_JPW); + assertThat(dirtyPrice).isCloseTo(dirtyPriceAd.getValue(), offset(TOL)); + double eps = 1.0e-5; + double dirtyPriceUp = PRICER.dirtyPriceFromRealYield(PRODUCT_JPW, RATES_PROVS_JP, standardSettle, YIELD_JPW + eps); + double dirtyPriceDw = PRICER.dirtyPriceFromRealYield(PRODUCT_JPW, RATES_PROVS_JP, standardSettle, YIELD_JPW - eps); + assertThat(dirtyPriceAd.getDerivative(0)).isCloseTo(0.5 * (dirtyPriceUp - dirtyPriceDw) / eps, offset(eps)); + ValueDerivatives realYieldAd = PRICER.realYieldFromDirtyPriceAd(PRODUCT_JPW, RATES_PROVS_JP, standardSettle, dirtyPrice); + double realYieldUp = PRICER.realYieldFromDirtyPrice(PRODUCT_JPW, RATES_PROVS_JP, standardSettle, dirtyPrice + eps); + double realYieldDw = PRICER.realYieldFromDirtyPrice(PRODUCT_JPW, RATES_PROVS_JP, standardSettle, dirtyPrice - eps); + assertThat(realYieldAd.getDerivative(0)).isCloseTo(0.5 * (realYieldUp - realYieldDw) / eps, offset(eps)); } @Test diff --git a/modules/product/src/main/java/com/opengamma/strata/product/bond/CapitalIndexedBondYieldConvention.java b/modules/product/src/main/java/com/opengamma/strata/product/bond/CapitalIndexedBondYieldConvention.java index 0831f4b15e..fceac6a0af 100644 --- a/modules/product/src/main/java/com/opengamma/strata/product/bond/CapitalIndexedBondYieldConvention.java +++ b/modules/product/src/main/java/com/opengamma/strata/product/bond/CapitalIndexedBondYieldConvention.java @@ -40,12 +40,12 @@ public enum CapitalIndexedBondYieldConvention implements NamedEnum { GB_IL_BOND("GB-I/L-Bond"), /** - * The Japan simple yield convention for inflation index bond. + * The Japan simple real yield convention for inflation index bond. */ JP_IL_SIMPLE("JP-I/L-Simple"), /** - * The Japan compound yield convention for inflation index bond. + * The Japan compound real yield convention for inflation index bond. */ JP_IL_COMPOUND("JP-I/L-Compound"); From f0943827da276669121fa1d1ac77a62260ce8fb5 Mon Sep 17 00:00:00 2001 From: Alexis Skitini Date: Wed, 31 May 2023 15:48:18 +0100 Subject: [PATCH 021/116] Add Asian ETD option type (#2582) Co-authored-by: Alexis Skitini --- .../opengamma/strata/loader/csv/CsvLoaderUtils.java | 7 +++++-- .../strata/loader/csv/CsvLoaderUtilsTest.java | 3 +++ .../opengamma/strata/product/etd/EtdOptionType.java | 12 ++++++++++-- .../com/opengamma/strata/product/etd/EtdVariant.java | 4 ++-- .../strata/product/etd/EtdOptionTypeTest.java | 1 + 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/modules/loader/src/main/java/com/opengamma/strata/loader/csv/CsvLoaderUtils.java b/modules/loader/src/main/java/com/opengamma/strata/loader/csv/CsvLoaderUtils.java index 028914f9fd..f82cfc0be6 100644 --- a/modules/loader/src/main/java/com/opengamma/strata/loader/csv/CsvLoaderUtils.java +++ b/modules/loader/src/main/java/com/opengamma/strata/loader/csv/CsvLoaderUtils.java @@ -39,7 +39,6 @@ import com.opengamma.strata.collect.ArgChecker; import com.opengamma.strata.collect.Decimal; import com.opengamma.strata.collect.io.CsvRow; -import com.opengamma.strata.collect.result.FailureReason; import com.opengamma.strata.collect.result.ParseFailureException; import com.opengamma.strata.collect.tuple.DoublesPair; import com.opengamma.strata.collect.tuple.Pair; @@ -292,9 +291,13 @@ public static EtdOptionType parseEtdOptionType(String str) { case "EUROPEAN": case "E": return EtdOptionType.EUROPEAN; + case "ASIAN": + case "T": + return EtdOptionType.ASIAN; default: throw new ParseFailureException( - "Unable to parse ETD option type from '{value}', must be 'American', 'European', 'A' or 'E' (case insensitive)", str); + "Unable to parse ETD option type from '{value}', must be 'American', 'European', 'Asian', 'A', 'E' or " + + "'T' (case insensitive)", str); } } diff --git a/modules/loader/src/test/java/com/opengamma/strata/loader/csv/CsvLoaderUtilsTest.java b/modules/loader/src/test/java/com/opengamma/strata/loader/csv/CsvLoaderUtilsTest.java index efee10910f..c51ac09c53 100644 --- a/modules/loader/src/test/java/com/opengamma/strata/loader/csv/CsvLoaderUtilsTest.java +++ b/modules/loader/src/test/java/com/opengamma/strata/loader/csv/CsvLoaderUtilsTest.java @@ -53,6 +53,9 @@ public void test_parseEtdOptionType() { assertThat(CsvLoaderUtils.parseEtdOptionType("E")).isEqualTo(EtdOptionType.EUROPEAN); assertThat(CsvLoaderUtils.parseEtdOptionType("EUROPEAN")).isEqualTo(EtdOptionType.EUROPEAN); assertThat(CsvLoaderUtils.parseEtdOptionType("e")).isEqualTo(EtdOptionType.EUROPEAN); + assertThat(CsvLoaderUtils.parseEtdOptionType("T")).isEqualTo(EtdOptionType.ASIAN); + assertThat(CsvLoaderUtils.parseEtdOptionType("ASIAN")).isEqualTo(EtdOptionType.ASIAN); + assertThat(CsvLoaderUtils.parseEtdOptionType("t")).isEqualTo(EtdOptionType.ASIAN); assertThatExceptionOfType(ParseFailureException.class).isThrownBy(() -> CsvLoaderUtils.parseEtdOptionType("")); } diff --git a/modules/product/src/main/java/com/opengamma/strata/product/etd/EtdOptionType.java b/modules/product/src/main/java/com/opengamma/strata/product/etd/EtdOptionType.java index ee9fa2191c..e3060ef2f2 100644 --- a/modules/product/src/main/java/com/opengamma/strata/product/etd/EtdOptionType.java +++ b/modules/product/src/main/java/com/opengamma/strata/product/etd/EtdOptionType.java @@ -12,7 +12,7 @@ import com.opengamma.strata.collect.named.NamedEnum; /** - * The option expiry type, 'American' or 'European'. + * The option expiry type, 'American', 'European' or 'Asian'. */ public enum EtdOptionType implements NamedEnum { @@ -25,7 +25,13 @@ public enum EtdOptionType implements NamedEnum { * European option. * Can be exercised only on a single date. */ - EUROPEAN("E"); + EUROPEAN("E"), + /** + * Asian option. + * Payoff depends on the average price over a certain period of time. + * Sometimes referred as a Traded Average Price Option (TAPO). + */ + ASIAN("T"); // helper for name conversions private static final EnumNames NAMES = EnumNames.of(EtdOptionType.class); @@ -68,6 +74,8 @@ static EtdOptionType parseCode(String code) { return AMERICAN; case "E": return EUROPEAN; + case "T": + return ASIAN; default: throw new IllegalArgumentException("Unknown EtdOptionType code: " + code); } diff --git a/modules/product/src/main/java/com/opengamma/strata/product/etd/EtdVariant.java b/modules/product/src/main/java/com/opengamma/strata/product/etd/EtdVariant.java index ecb8c0e3a7..7e56654580 100644 --- a/modules/product/src/main/java/com/opengamma/strata/product/etd/EtdVariant.java +++ b/modules/product/src/main/java/com/opengamma/strata/product/etd/EtdVariant.java @@ -65,7 +65,7 @@ public final class EtdVariant @PropertyDefinition(get = "optional") private final EtdSettlementType settlementType; /** - * The optional option type, 'American' or 'European', populated for Flex Options. + * The optional option type, such as 'American' or 'European', populated for Flex Options. */ @PropertyDefinition(get = "optional") private final EtdOptionType optionType; @@ -288,7 +288,7 @@ public Optional getSettlementType() { //----------------------------------------------------------------------- /** - * Gets the optional option type, 'American' or 'European', populated for Flex Options. + * Gets the optional option type, such as 'American' or 'European', populated for Flex Options. * @return the optional value of the property, not null */ public Optional getOptionType() { diff --git a/modules/product/src/test/java/com/opengamma/strata/product/etd/EtdOptionTypeTest.java b/modules/product/src/test/java/com/opengamma/strata/product/etd/EtdOptionTypeTest.java index 7429c69264..fd4ab3f8cc 100644 --- a/modules/product/src/test/java/com/opengamma/strata/product/etd/EtdOptionTypeTest.java +++ b/modules/product/src/test/java/com/opengamma/strata/product/etd/EtdOptionTypeTest.java @@ -25,6 +25,7 @@ public static Object[][] data_name() { return new Object[][] { {EtdOptionType.AMERICAN, "American", "A"}, {EtdOptionType.EUROPEAN, "European", "E"}, + {EtdOptionType.ASIAN, "Asian", "T"}, }; } From 1a2c0af49ac0beae32cc7ea37ed5da8f16f5febc Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Wed, 31 May 2023 14:58:42 +0000 Subject: [PATCH 022/116] [maven-release-plugin] prepare release v2.12.25 --- examples/pom.xml | 6 +++++- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 38c1ce3bca..0679fef4a7 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.25-SNAPSHOT + 2.12.25 jar Strata-Examples Example code to demonstrate use of Strata @@ -272,4 +272,8 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> + + + v2.12.25 + diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index f7adc344ce..7d9f2fac56 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.25-SNAPSHOT + 2.12.25 .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index b54b070695..d3bb231322 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.25-SNAPSHOT + 2.12.25 .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 53ab896238..4232de4513 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.25-SNAPSHOT + 2.12.25 .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 81588b437b..f0df8797c2 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.25-SNAPSHOT + 2.12.25 .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index d18ebb5afb..befc44638b 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.25-SNAPSHOT + 2.12.25 .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index bcffa93dbb..2f718a289e 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.25-SNAPSHOT + 2.12.25 .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 7e293da8ce..206e49cfa8 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.25-SNAPSHOT + 2.12.25 .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index d88fb550b5..405cdf76aa 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.25-SNAPSHOT + 2.12.25 .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index f6b29ff67f..bbb4997226 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.25-SNAPSHOT + 2.12.25 pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.25 diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 589d72f3a2..821c1a8d8b 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.25-SNAPSHOT + 2.12.25 .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 3c749c8044..8c5ff43031 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.25-SNAPSHOT + 2.12.25 .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 9c8db07924..3921d92660 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.25-SNAPSHOT + 2.12.25 .. strata-report diff --git a/pom.xml b/pom.xml index 08905acb39..8027a110dc 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.25-SNAPSHOT + 2.12.25 pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.25 From 6653262414e66a1476af69449ec42a76e33f3214 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Wed, 31 May 2023 14:58:43 +0000 Subject: [PATCH 023/116] [maven-release-plugin] prepare for next development iteration --- examples/pom.xml | 6 +----- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 0679fef4a7..06f40f9108 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.25 + 2.12.26-SNAPSHOT jar Strata-Examples Example code to demonstrate use of Strata @@ -272,8 +272,4 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> - - - v2.12.25 - diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index 7d9f2fac56..1dcbfe95d8 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.25 + 2.12.26-SNAPSHOT .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index d3bb231322..f1d9da097f 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.25 + 2.12.26-SNAPSHOT .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 4232de4513..86210c7f12 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.25 + 2.12.26-SNAPSHOT .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index f0df8797c2..4c26454a63 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.25 + 2.12.26-SNAPSHOT .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index befc44638b..34c7b1224a 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.25 + 2.12.26-SNAPSHOT .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 2f718a289e..e2468a8548 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.25 + 2.12.26-SNAPSHOT .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 206e49cfa8..8f461479b7 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.25 + 2.12.26-SNAPSHOT .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 405cdf76aa..4e74f5535f 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.25 + 2.12.26-SNAPSHOT .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index bbb4997226..0b7de398f7 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.25 + 2.12.26-SNAPSHOT pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.25 + HEAD diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 821c1a8d8b..801a7fd71e 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.25 + 2.12.26-SNAPSHOT .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 8c5ff43031..be38b91efb 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.25 + 2.12.26-SNAPSHOT .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 3921d92660..f53fcfed47 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.25 + 2.12.26-SNAPSHOT .. strata-report diff --git a/pom.xml b/pom.xml index 8027a110dc..a92bc410bb 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.25 + 2.12.26-SNAPSHOT pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.25 + HEAD From 4f1520501f0a4c6b013d376f425c8ec1a72c20b6 Mon Sep 17 00:00:00 2001 From: Aaron <110403946+aaron-og@users.noreply.github.com> Date: Wed, 7 Jun 2023 09:30:26 +0100 Subject: [PATCH 024/116] Create OvernightFutureOption pricer (#2585) * created wrapper pricer class for overnight future options. This wraps the equivalent product pricer and is based of the existing ibor equivalent * checkstyle - new line at end of file --- ...rnightFutureOptionMarginedTradePricer.java | 257 ++++++++++++++++++ ...htFutureOptionMarginedTradePricerTest.java | 190 +++++++++++++ 2 files changed, 447 insertions(+) create mode 100644 modules/pricer/src/main/java/com/opengamma/strata/pricer/index/NormalOvernightFutureOptionMarginedTradePricer.java create mode 100644 modules/pricer/src/test/java/com/opengamma/strata/pricer/index/NormalOvernightFutureOptionMarginedTradePricerTest.java diff --git a/modules/pricer/src/main/java/com/opengamma/strata/pricer/index/NormalOvernightFutureOptionMarginedTradePricer.java b/modules/pricer/src/main/java/com/opengamma/strata/pricer/index/NormalOvernightFutureOptionMarginedTradePricer.java new file mode 100644 index 0000000000..e4c3551c18 --- /dev/null +++ b/modules/pricer/src/main/java/com/opengamma/strata/pricer/index/NormalOvernightFutureOptionMarginedTradePricer.java @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2023 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.pricer.index; + +import java.time.LocalDate; + +import com.opengamma.strata.basics.currency.CurrencyAmount; +import com.opengamma.strata.collect.ArgChecker; +import com.opengamma.strata.market.sensitivity.PointSensitivities; +import com.opengamma.strata.pricer.rate.RatesProvider; +import com.opengamma.strata.product.TradedPrice; +import com.opengamma.strata.product.index.OvernightFutureOption; +import com.opengamma.strata.product.index.ResolvedOvernightFuture; +import com.opengamma.strata.product.index.ResolvedOvernightFutureOption; +import com.opengamma.strata.product.index.ResolvedOvernightFutureOptionTrade; +import com.opengamma.strata.product.option.FutureOptionPremiumStyle; + +/** + * Pricer implementation for Overnight future option. + *

    + * This provides the ability to price an Overnight future option. + * The option must be based on {@linkplain FutureOptionPremiumStyle#DAILY_MARGIN daily margin}. + * + *

    Price

    + * The price of an Overnight future option is based on the price of the underlying future, the volatility + * and the time to expiry. The price of the at-the-money option tends to zero as expiry approaches. + *

    + * Strata uses decimal prices for Overnight future options in the trade model, pricers and market data. + * The decimal price is based on the decimal rate equivalent to the percentage. + * For example, an option price of 0.2 is related to a futures price of 99.32 that implies an + * interest rate of 0.68%. Strata represents the price of the future as 0.9932 and thus + * represents the price of the option as 0.002. + */ +public class NormalOvernightFutureOptionMarginedTradePricer { + + /** + * Default implementation. + */ + public static final NormalOvernightFutureOptionMarginedTradePricer DEFAULT = + new NormalOvernightFutureOptionMarginedTradePricer(NormalOvernightFutureOptionMarginedProductPricer.DEFAULT); + + /** + * Underlying option pricer. + */ + private final NormalOvernightFutureOptionMarginedProductPricer futureOptionPricer; + + /** + * Creates an instance. + * + * @param futureOptionPricer the pricer for {@link OvernightFutureOption} + */ + public NormalOvernightFutureOptionMarginedTradePricer( + NormalOvernightFutureOptionMarginedProductPricer futureOptionPricer) { + this.futureOptionPricer = ArgChecker.notNull(futureOptionPricer, "futureOptionPricer"); + } + + //------------------------------------------------------------------------- + /** + * Calculates the price of the Overnight future option trade. + *

    + * The price of the trade is the price on the valuation date. + * The price is calculated using the volatility model. + * + * @param trade the trade + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @return the price of the product, in decimal form + */ + public double price( + ResolvedOvernightFutureOptionTrade trade, + RatesProvider ratesProvider, + NormalOvernightFutureOptionVolatilities volatilities) { + + return futureOptionPricer.price(trade.getProduct(), ratesProvider, volatilities); + } + + //------------------------------------------------------------------------- + /** + * Calculates the present value of the Overnight future option trade from the current option price. + *

    + * The present value of the product is the value on the valuation date. + * The current price is specified, not calculated. + *

    + * This method calculates based on the difference between the specified current price and the + * last settlement price, or the trade price if traded on the valuation date. + * + * @param trade the trade + * @param valuationDate the valuation date; required to asses if the trade or last closing price should be used + * @param currentOptionPrice the current price for the option, in decimal form + * @param lastOptionSettlementPrice the last settlement price used for margining for the option, in decimal form + * @return the present value + */ + public CurrencyAmount presentValue( + ResolvedOvernightFutureOptionTrade trade, + LocalDate valuationDate, + double currentOptionPrice, + double lastOptionSettlementPrice) { + + ResolvedOvernightFutureOption option = trade.getProduct(); + double referencePrice = referencePrice(trade, valuationDate, lastOptionSettlementPrice); + double priceIndex = futureOptionPricer.marginIndex(option, currentOptionPrice); + double referenceIndex = futureOptionPricer.marginIndex(option, referencePrice); + double pv = (priceIndex - referenceIndex) * trade.getQuantity(); + return CurrencyAmount.of(option.getUnderlyingFuture().getCurrency(), pv); + } + + //------------------------------------------------------------------------- + /** + * Calculates the present value of the Overnight future option trade. + *

    + * The present value of the product is the value on the valuation date. + * The current price is calculated using the volatility model. + *

    + * This method calculates based on the difference between the model price and the + * last settlement price, or the trade price if traded on the valuation date. + * + * @param trade the trade + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @param lastOptionSettlementPrice the last settlement price used for margining for the option, in decimal form + * @return the present value + */ + public CurrencyAmount presentValue( + ResolvedOvernightFutureOptionTrade trade, + RatesProvider ratesProvider, + NormalOvernightFutureOptionVolatilities volatilities, + double lastOptionSettlementPrice) { + + double price = price(trade, ratesProvider, volatilities); + return presentValue(trade, ratesProvider.getValuationDate(), price, lastOptionSettlementPrice); + } + + //------------------------------------------------------------------------- + /** + * Calculates the present value of the Overnight future option trade from the underlying future price. + *

    + * The present value of the product is the value on the valuation date. + * The current price is calculated using the volatility model with a known future price. + *

    + * This method calculates based on the difference between the model price and the + * last settlement price, or the trade price if traded on the valuation date. + * + * @param trade the trade + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @param futurePrice the price of the underlying future, in decimal form + * @param lastOptionSettlementPrice the last settlement price used for margining for the option, in decimal form + * @return the present value + */ + public CurrencyAmount presentValue( + ResolvedOvernightFutureOptionTrade trade, + RatesProvider ratesProvider, + NormalOvernightFutureOptionVolatilities volatilities, + double futurePrice, + double lastOptionSettlementPrice) { + + double optionPrice = futureOptionPricer.price(trade.getProduct(), volatilities, futurePrice); + return presentValue(trade, ratesProvider.getValuationDate(), optionPrice, lastOptionSettlementPrice); + } + + //------------------------------------------------------------------------- + /** + * Calculates the present value sensitivity of the Overnight future option trade. + *

    + * The present value sensitivity of the trade is the sensitivity of the present value to + * the underlying curves. + * + * @param trade the trade + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @return the present value curve sensitivity of the trade + */ + public PointSensitivities presentValueSensitivityRates( + ResolvedOvernightFutureOptionTrade trade, + RatesProvider ratesProvider, + NormalOvernightFutureOptionVolatilities volatilities) { + + ResolvedOvernightFutureOption product = trade.getProduct(); + PointSensitivities priceSensi = + futureOptionPricer.priceSensitivityRatesStickyStrike(product, ratesProvider, volatilities); + PointSensitivities marginIndexSensi = futureOptionPricer.marginIndexSensitivity(product, priceSensi); + return marginIndexSensi.multipliedBy(trade.getQuantity()); + } + + //------------------------------------------------------------------------- + /** + * Computes the present value sensitivity to the normal volatility used in the pricing. + *

    + * The result is a single sensitivity to the volatility used. + * The volatility is associated with the expiry/delay/strike/future price key combination. + *

    + * This calculates the underlying future price using the future pricer. + * + * @param futureOptionTrade the trade + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @return the price sensitivity + */ + public OvernightFutureOptionSensitivity presentValueSensitivityModelParamsVolatility( + ResolvedOvernightFutureOptionTrade futureOptionTrade, + RatesProvider ratesProvider, + NormalOvernightFutureOptionVolatilities volatilities) { + + ResolvedOvernightFuture future = futureOptionTrade.getProduct().getUnderlyingFuture(); + double futurePrice = futureOptionPricer.getFuturePricer().price(future, ratesProvider); + return presentValueSensitivityModelParamsVolatility(futureOptionTrade, volatilities, futurePrice); + } + + //------------------------------------------------------------------------- + /** + * Computes the present value sensitivity to the normal volatility used in the pricing + * based on the price of the underlying future. + *

    + * The result is a single sensitivity to the volatility used. + * The volatility is associated with the expiry/delay/strike/future price key combination. + * + * @param futureOptionTrade the trade + * @param volatilities the volatilities + * @param futurePrice the price of the underlying future, in decimal form + * @return the price sensitivity + */ + public OvernightFutureOptionSensitivity presentValueSensitivityModelParamsVolatility( + ResolvedOvernightFutureOptionTrade futureOptionTrade, + NormalOvernightFutureOptionVolatilities volatilities, + double futurePrice) { + + ResolvedOvernightFutureOption product = futureOptionTrade.getProduct(); + OvernightFutureOptionSensitivity priceSensitivity = + futureOptionPricer.priceSensitivityModelParamsVolatility(product, volatilities, futurePrice); + double factor = futureOptionPricer.marginIndex(product, 1) * futureOptionTrade.getQuantity(); + return priceSensitivity.multipliedBy(factor); + } + + //------------------------------------------------------------------------- + /** + * Calculates the reference price for the trade. + *

    + * If the valuation date equals the trade date, then the reference price is the trade price. + * Otherwise, the reference price is the last settlement price used for margining. + * + * @param trade the trade + * @param valuationDate the date for which the reference price should be calculated + * @param lastSettlementPrice the last settlement price used for margining, in decimal form + * @return the reference price, in decimal form + */ + private double referencePrice(ResolvedOvernightFutureOptionTrade trade, LocalDate valuationDate, double lastSettlementPrice) { + ArgChecker.notNull(valuationDate, "valuationDate"); + return trade.getTradedPrice() + .filter(tp -> tp.getTradeDate().equals(valuationDate)) + .map(TradedPrice::getPrice) + .orElse(lastSettlementPrice); + } + +} diff --git a/modules/pricer/src/test/java/com/opengamma/strata/pricer/index/NormalOvernightFutureOptionMarginedTradePricerTest.java b/modules/pricer/src/test/java/com/opengamma/strata/pricer/index/NormalOvernightFutureOptionMarginedTradePricerTest.java new file mode 100644 index 0000000000..5507595b3f --- /dev/null +++ b/modules/pricer/src/test/java/com/opengamma/strata/pricer/index/NormalOvernightFutureOptionMarginedTradePricerTest.java @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2023 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.pricer.index; + +import static com.opengamma.strata.basics.date.DayCounts.ACT_365F; +import static com.opengamma.strata.basics.index.OvernightIndices.GBP_SONIA; +import static com.opengamma.strata.collect.TestHelper.date; +import static com.opengamma.strata.market.curve.interpolator.CurveInterpolators.LINEAR; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.data.Offset.offset; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZoneId; + +import org.junit.jupiter.api.Test; + +import com.opengamma.strata.basics.ReferenceData; +import com.opengamma.strata.basics.currency.CurrencyAmount; +import com.opengamma.strata.basics.index.OvernightIndexObservation; +import com.opengamma.strata.collect.array.DoubleArray; +import com.opengamma.strata.market.model.MoneynessType; +import com.opengamma.strata.market.sensitivity.PointSensitivities; +import com.opengamma.strata.market.surface.InterpolatedNodalSurface; +import com.opengamma.strata.market.surface.Surfaces; +import com.opengamma.strata.market.surface.interpolator.GridSurfaceInterpolator; +import com.opengamma.strata.market.surface.interpolator.SurfaceInterpolator; +import com.opengamma.strata.pricer.rate.OvernightIndexRates; +import com.opengamma.strata.pricer.rate.OvernightRateSensitivity; +import com.opengamma.strata.pricer.rate.SimpleRatesProvider; +import com.opengamma.strata.product.TradedPrice; +import com.opengamma.strata.product.index.ResolvedOvernightFutureOption; +import com.opengamma.strata.product.index.ResolvedOvernightFutureOptionTrade; + +/** + * Tests {@link NormalOvernightFutureOptionMarginedTradePricer} + */ +class NormalOvernightFutureOptionMarginedTradePricerTest { + + private static final ReferenceData REF_DATA = ReferenceData.standard(); + private static final SurfaceInterpolator INTERPOLATOR_2D = GridSurfaceInterpolator.of(LINEAR, LINEAR); + private static final DoubleArray TIMES = + DoubleArray.of(0.25, 0.25, 0.25, 0.25, 0.5, 0.5, 0.5, 0.5, 1.0, 1.0, 1.0, 1.0); + private static final DoubleArray MONEYNESS_PRICES = + DoubleArray.of(-0.02, -0.01, 0.0, 0.01, -0.02, -0.01, 0.0, 0.01, -0.02, -0.01, 0.0, 0.01); + private static final DoubleArray NORMAL_VOL = + DoubleArray.of(0.01, 0.011, 0.012, 0.010, 0.011, 0.012, 0.013, 0.012, 0.012, 0.013, 0.014, 0.014); + private static final InterpolatedNodalSurface PARAMETERS_PRICE = InterpolatedNodalSurface.of( + Surfaces.normalVolatilityByExpirySimpleMoneyness("Test", ACT_365F, MoneynessType.PRICE), + TIMES, + MONEYNESS_PRICES, + NORMAL_VOL, + INTERPOLATOR_2D); + + private static final LocalDate VAL_DATE = date(2015, 2, 17); + private static final LocalTime VAL_TIME = LocalTime.of(13, 45); + private static final ZoneId LONDON_ZONE = ZoneId.of("Europe/London"); + + private static final NormalOvernightFutureOptionVolatilities VOL_SIMPLE_MONEY_PRICE = + NormalOvernightFutureOptionExpirySimpleMoneynessVolatilities.of( + GBP_SONIA, VAL_DATE.atTime(VAL_TIME).atZone(LONDON_ZONE), PARAMETERS_PRICE); + + private static final ResolvedOvernightFutureOption OPTION = OvernightFutureDummyData.OVERNIGHT_FUTURE_OPTION_2.resolve(REF_DATA); + private static final LocalDate TRADE_DATE = date(2015, 2, 16); + private static final long OPTION_QUANTITY = 12345; + private static final double TRADE_PRICE = 0.0100; + private static final ResolvedOvernightFutureOptionTrade FUTURE_OPTION_TRADE_TD = ResolvedOvernightFutureOptionTrade.builder() + .product(OPTION) + .quantity(OPTION_QUANTITY) + .tradedPrice(TradedPrice.of(VAL_DATE, TRADE_PRICE)) + .build(); + private static final ResolvedOvernightFutureOptionTrade FUTURE_OPTION_TRADE = ResolvedOvernightFutureOptionTrade.builder() + .product(OPTION) + .quantity(OPTION_QUANTITY) + .tradedPrice(TradedPrice.of(TRADE_DATE, TRADE_PRICE)) + .build(); + + private static final double RATE = 0.015; + + private static final DiscountingOvernightFutureProductPricer FUTURE_PRICER = DiscountingOvernightFutureProductPricer.DEFAULT; + private static final NormalOvernightFutureOptionMarginedProductPricer OPTION_PRODUCT_PRICER = + new NormalOvernightFutureOptionMarginedProductPricer(FUTURE_PRICER); + private static final NormalOvernightFutureOptionMarginedTradePricer OPTION_TRADE_PRICER = + new NormalOvernightFutureOptionMarginedTradePricer(OPTION_PRODUCT_PRICER); + + private static final double TOLERANCE_PV = 1.0E-2; + private static final double TOLERANCE_PV_DELTA = 1.0E-1; + + // ---------- present value ---------- + + @Test + public void presentValue_from_option_price_trade_date() { + double optionPrice = 0.0125; + double lastClosingPrice = 0.0150; + CurrencyAmount pvComputed = OPTION_TRADE_PRICER + .presentValue(FUTURE_OPTION_TRADE_TD, VAL_DATE, optionPrice, lastClosingPrice); + double pvExpected = (OPTION_PRODUCT_PRICER.marginIndex(OPTION, optionPrice) - + OPTION_PRODUCT_PRICER.marginIndex(OPTION, TRADE_PRICE)) * OPTION_QUANTITY; + assertThat(pvComputed.getAmount()).isCloseTo(pvExpected, offset(TOLERANCE_PV)); + } + + @Test + public void presentValue_from_future_price() { + OvernightIndexRates mockOvernight = mock(OvernightIndexRates.class); + SimpleRatesProvider prov = new SimpleRatesProvider(VAL_DATE); + prov.setOvernightRates(mockOvernight); + when(mockOvernight.rate(any())).thenReturn(RATE); + + double futurePrice = 0.9875; + double lastClosingPrice = 0.0150; + CurrencyAmount pvComputed = OPTION_TRADE_PRICER + .presentValue(FUTURE_OPTION_TRADE, prov, VOL_SIMPLE_MONEY_PRICE, futurePrice, lastClosingPrice); + double optionPrice = + OPTION_PRODUCT_PRICER.price(OPTION, VOL_SIMPLE_MONEY_PRICE, futurePrice); + double pvExpected = (OPTION_PRODUCT_PRICER.marginIndex(OPTION, optionPrice) - + OPTION_PRODUCT_PRICER.marginIndex(OPTION, lastClosingPrice)) * OPTION_QUANTITY; + assertThat(pvComputed.getAmount()).isCloseTo(pvExpected, offset(TOLERANCE_PV)); + } + + @Test + public void presentValue_from_env() { + OvernightIndexRates mockOvernight = mock(OvernightIndexRates.class); + SimpleRatesProvider prov = new SimpleRatesProvider(VAL_DATE); + prov.setOvernightRates(mockOvernight); + when(mockOvernight.rate(any())).thenReturn(RATE); + when(mockOvernight.getValuationDate()).thenReturn(VAL_DATE); + + double lastClosingPrice = 0.0150; + CurrencyAmount pvComputed = OPTION_TRADE_PRICER + .presentValue(FUTURE_OPTION_TRADE, prov, VOL_SIMPLE_MONEY_PRICE, lastClosingPrice); + double optionPrice = + OPTION_PRODUCT_PRICER.price(OPTION, prov, VOL_SIMPLE_MONEY_PRICE); + double pvExpected = (OPTION_PRODUCT_PRICER.marginIndex(OPTION, optionPrice) - + OPTION_PRODUCT_PRICER.marginIndex(OPTION, lastClosingPrice)) * OPTION_QUANTITY; + assertThat(pvComputed.getAmount()).isCloseTo(pvExpected, offset(TOLERANCE_PV)); + } + + // ---------- present value sensitivity ---------- + + @Test + public void presentValueSensitivity_from_env() { + OvernightIndexRates mockOvernight = mock(OvernightIndexRates.class); + SimpleRatesProvider prov = new SimpleRatesProvider(); + prov.setOvernightRates(mockOvernight); + OvernightIndexObservation obs = OvernightIndexObservation.of( + GBP_SONIA, + LocalDate.of(2015, 6, 17), + REF_DATA); + when(mockOvernight.rate(any())).thenReturn(RATE); + when(mockOvernight.getValuationDate()).thenReturn(VAL_DATE); + when(mockOvernight.periodRatePointSensitivity(any(), any())) + .thenReturn(OvernightRateSensitivity.ofPeriod(obs, LocalDate.of(2015, 9, 16), 1d)); + //PointSensitivityBuilder Sensitivity = rates.periodRatePointSensitivity(obs, endDate); + + PointSensitivities psProduct = + OPTION_PRODUCT_PRICER.priceSensitivityRatesStickyStrike(OPTION, prov, VOL_SIMPLE_MONEY_PRICE); + PointSensitivities psExpected = psProduct + .multipliedBy(OPTION_PRODUCT_PRICER.marginIndex(OPTION, 1) * OPTION_QUANTITY); + PointSensitivities psComputed = OPTION_TRADE_PRICER + .presentValueSensitivityRates(FUTURE_OPTION_TRADE, prov, VOL_SIMPLE_MONEY_PRICE); + assertThat(psComputed.equalWithTolerance(psExpected, TOLERANCE_PV_DELTA)).isTrue(); + } + + // ---------- present value normal vol sensitivity ---------- + + @Test + public void presentvalue_normalVolSensitivity_from_env() { + OvernightIndexRates mockOvernight = mock(OvernightIndexRates.class); + SimpleRatesProvider prov = new SimpleRatesProvider(); + prov.setOvernightRates(mockOvernight); + when(mockOvernight.rate(any())).thenReturn(RATE); + when(mockOvernight.getValuationDate()).thenReturn(VAL_DATE); + + OvernightFutureOptionSensitivity psProduct = + OPTION_PRODUCT_PRICER.priceSensitivityModelParamsVolatility(OPTION, prov, VOL_SIMPLE_MONEY_PRICE); + OvernightFutureOptionSensitivity psExpected = psProduct.withSensitivity( + psProduct.getSensitivity() * OPTION_PRODUCT_PRICER.marginIndex(OPTION, 1) * OPTION_QUANTITY); + OvernightFutureOptionSensitivity psComputed = OPTION_TRADE_PRICER + .presentValueSensitivityModelParamsVolatility(FUTURE_OPTION_TRADE, prov, VOL_SIMPLE_MONEY_PRICE); + assertThat(psExpected.compareKey(psComputed) == 0).isTrue(); + assertThat(psComputed.getSensitivity()).isCloseTo(psExpected.getSensitivity(), offset(TOLERANCE_PV_DELTA)); + } + +} From d16ac601740d52e9e5825003e9c0c2f8b2612706 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Wed, 7 Jun 2023 08:32:33 +0000 Subject: [PATCH 025/116] [maven-release-plugin] prepare release v2.12.26 --- examples/pom.xml | 6 +++++- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 06f40f9108..34b9b9651e 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.26-SNAPSHOT + 2.12.26 jar Strata-Examples Example code to demonstrate use of Strata @@ -272,4 +272,8 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> + + + v2.12.26 + diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index 1dcbfe95d8..52e714f217 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.26-SNAPSHOT + 2.12.26 .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index f1d9da097f..7f2b63b271 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.26-SNAPSHOT + 2.12.26 .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 86210c7f12..2f2244f40c 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.26-SNAPSHOT + 2.12.26 .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 4c26454a63..684845fc67 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.26-SNAPSHOT + 2.12.26 .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 34c7b1224a..e3f306ff1a 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.26-SNAPSHOT + 2.12.26 .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index e2468a8548..11eb9907ea 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.26-SNAPSHOT + 2.12.26 .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 8f461479b7..7d3e397c27 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.26-SNAPSHOT + 2.12.26 .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 4e74f5535f..b65624779b 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.26-SNAPSHOT + 2.12.26 .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 0b7de398f7..12d9336949 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.26-SNAPSHOT + 2.12.26 pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.26 diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 801a7fd71e..edbd99ae8b 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.26-SNAPSHOT + 2.12.26 .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index be38b91efb..2579c9422d 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.26-SNAPSHOT + 2.12.26 .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index f53fcfed47..509bd472a2 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.26-SNAPSHOT + 2.12.26 .. strata-report diff --git a/pom.xml b/pom.xml index a92bc410bb..f69029b101 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.26-SNAPSHOT + 2.12.26 pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.26 From 211806b242b7e224323f74883fcc9ae2b17dd9c9 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Wed, 7 Jun 2023 08:32:35 +0000 Subject: [PATCH 026/116] [maven-release-plugin] prepare for next development iteration --- examples/pom.xml | 6 +----- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 34b9b9651e..5de5589b13 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.26 + 2.12.27-SNAPSHOT jar Strata-Examples Example code to demonstrate use of Strata @@ -272,8 +272,4 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> - - - v2.12.26 - diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index 52e714f217..e634f6c658 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.26 + 2.12.27-SNAPSHOT .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 7f2b63b271..4022345852 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.26 + 2.12.27-SNAPSHOT .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 2f2244f40c..2413f82c65 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.26 + 2.12.27-SNAPSHOT .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 684845fc67..a656877f03 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.26 + 2.12.27-SNAPSHOT .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index e3f306ff1a..62cd5061b8 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.26 + 2.12.27-SNAPSHOT .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 11eb9907ea..5d274028fe 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.26 + 2.12.27-SNAPSHOT .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 7d3e397c27..02b37716b1 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.26 + 2.12.27-SNAPSHOT .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index b65624779b..128813259a 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.26 + 2.12.27-SNAPSHOT .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 12d9336949..d888cf7b57 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.26 + 2.12.27-SNAPSHOT pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.26 + HEAD diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index edbd99ae8b..7d584aba11 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.26 + 2.12.27-SNAPSHOT .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 2579c9422d..a48df5f307 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.26 + 2.12.27-SNAPSHOT .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 509bd472a2..58b16221f9 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.26 + 2.12.27-SNAPSHOT .. strata-report diff --git a/pom.xml b/pom.xml index f69029b101..8036c3aa4e 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.26 + 2.12.27-SNAPSHOT pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.26 + HEAD From 7294b91a329f6191e8ddd34218e319f32c5991d0 Mon Sep 17 00:00:00 2001 From: Jordan Morrison <33151302+jordanmorrison476@users.noreply.github.com> Date: Thu, 8 Jun 2023 10:04:35 +0100 Subject: [PATCH 027/116] Updating Thailand Holiday Calendar - Coronation Day / Coronation Day Observed (#2587) Co-authored-by: jordanmorrison476 --- .../config/base/HolidayCalendarData.ini | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/modules/basics/src/main/resources/META-INF/com/opengamma/strata/config/base/HolidayCalendarData.ini b/modules/basics/src/main/resources/META-INF/com/opengamma/strata/config/base/HolidayCalendarData.ini index 8f4b7ad2d8..94afd8129f 100644 --- a/modules/basics/src/main/resources/META-INF/com/opengamma/strata/config/base/HolidayCalendarData.ini +++ b/modules/basics/src/main/resources/META-INF/com/opengamma/strata/config/base/HolidayCalendarData.ini @@ -47,17 +47,17 @@ 2020=Jan01,Feb10,Apr06,Apr13,Apr14,Apr15,May01,May06,Jul06,Jul28,Aug12,Oct13,Oct23,Dec07,Dec10,Dec31 2021=Jan01,Feb26,Apr06,Apr13,Apr14,Apr15,May03,May26,Jul26,Jul28,Aug12,Oct13,Oct25,Dec06,Dec10,Dec31 2022=Jan03,Feb16,Apr06,Apr13,Apr14,Apr15,May02,May16,Jul13,Jul28,Aug12,Oct13,Oct24,Dec05,Dec12 -2023=Jan02,Mar06,Apr06,Apr13,Apr14,May01,Jun05,Jul28,Aug01,Aug14,Oct13,Oct23,Dec05,Dec11 -2024=Jan01,Jan02,Feb26,Apr08,Apr15,Apr16,May01,May22,Jul22,Jul29,Aug12,Oct14,Oct23,Dec05,Dec10,Dec31 -2025=Jan01,Feb12,Apr07,Apr14,Apr15,May01,May12,Jul10,Jul28,Aug12,Oct13,Oct23,Dec05,Dec10,Dec31 -2026=Jan01,Jan02,Mar03,Apr06,Apr13,Apr14,Apr15,May01,Jun01,Jul28,Jul29,Aug12,Oct13,Oct23,Dec07,Dec10,Dec31 -2027=Jan01,Feb22,Apr06,Apr13,Apr14,Apr15,May03,May20,Jul19,Jul28,Aug12,Oct13,Oct25,Dec06,Dec10,Dec31 -2028=Jan03,Feb10,Apr06,Apr13,Apr14,May01,May08,Jul06,Jul28,Aug14,Oct13,Oct23,Dec05,Dec11 -2029=Jan01,Jan02,Feb27,Apr06,Apr13,Apr16,May01,May28,Jul25,Jul30,Aug13,Oct15,Oct23,Dec05,Dec10,Dec31 -2030=Jan01,Feb18,Apr08,Apr15,Apr16,May01,May16,Jul15,Jul29,Aug12,Oct14,Oct23,Dec05,Dec10,Dec31 -2031=Jan01,Mar07,Apr07,Apr14,Apr15,May01,Jun04,Jul28,Aug04,Aug12,Oct13,Oct23,Dec05,Dec10,Dec31 -2032=Jan01,Jan02,Feb25,Apr06,Apr13,Apr14,Apr15,May03,May24,Jul22,Jul28,Aug12,Oct13,Oct25,Dec06,Dec10,Dec31 -2033=Jan03,Feb14,Apr06,Apr13,Apr14,Apr15,May02,May13,Jul11,Jul28,Aug12,Oct13,Oct24,Dec05,Dec12 +2023=Jan02,Mar06,Apr06,Apr13,Apr14,May01,May04,May05,Jun05,Jul28,Aug01,Aug14,Oct13,Oct23,Dec05,Dec11 +2024=Jan01,Jan02,Feb26,Apr08,Apr15,Apr16,May01,May06,May22,Jul22,Jul29,Aug12,Oct14,Oct23,Dec05,Dec10,Dec31 +2025=Jan01,Feb12,Apr07,Apr14,Apr15,May01,May05,May12,Jul10,Jul28,Aug12,Oct13,Oct23,Dec05,Dec10,Dec31 +2026=Jan01,Jan02,Mar03,Apr06,Apr13,Apr14,Apr15,May01,May04,Jun01,Jul28,Jul29,Aug12,Oct13,Oct23,Dec07,Dec10,Dec31 +2027=Jan01,Feb22,Apr06,Apr13,Apr14,Apr15,May03,May04,May20,Jul19,Jul28,Aug12,Oct13,Oct25,Dec06,Dec10,Dec31 +2028=Jan03,Feb10,Apr06,Apr13,Apr14,May01,May04,May08,Jul06,Jul28,Aug14,Oct13,Oct23,Dec05,Dec11 +2029=Jan01,Jan02,Feb27,Apr06,Apr13,Apr16,May01,May04,May28,Jul25,Jul30,Aug13,Oct15,Oct23,Dec05,Dec10,Dec31 +2030=Jan01,Feb18,Apr08,Apr15,Apr16,May01,May06,May16,Jul15,Jul29,Aug12,Oct14,Oct23,Dec05,Dec10,Dec31 +2031=Jan01,Mar07,Apr07,Apr14,Apr15,May01,May04,Jun04,Jul28,Aug04,Aug12,Oct13,Oct23,Dec05,Dec10,Dec31 +2032=Jan01,Jan02,Feb25,Apr06,Apr13,Apr14,Apr15,May03,May04,May24,Jul22,Jul28,Aug12,Oct13,Oct25,Dec06,Dec10,Dec31 +2033=Jan03,Feb14,Apr06,Apr13,Apr14,Apr15,May02,May04,May13,Jul11,Jul28,Aug12,Oct13,Oct24,Dec05,Dec12 2034=Jan02,Mar06,Apr06,Apr13,Apr14,May01,Jun01,Jul28,Jul31,Aug14,Oct13,Oct23,Dec05,Dec11 2035=Jan01,Jan02,Feb22,Apr06,Apr13,Apr16,May01,May21,Jul20,Jul30,Aug13,Oct15,Oct23,Dec05,Dec10,Dec31 2036=Jan01,Feb12,Apr07,Apr14,Apr15,May01,May12,Jul08,Jul28,Aug12,Oct13,Oct23,Dec05,Dec10,Dec31 From 55bee3476f97a66ac130c3a0fbe7495d139575c5 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Thu, 8 Jun 2023 10:51:27 +0000 Subject: [PATCH 028/116] [maven-release-plugin] prepare release v2.12.27 --- examples/pom.xml | 6 +++++- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 5de5589b13..52a988704f 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.27-SNAPSHOT + 2.12.27 jar Strata-Examples Example code to demonstrate use of Strata @@ -272,4 +272,8 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> + + + v2.12.27 + diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index e634f6c658..7e0d4aa0c9 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.27-SNAPSHOT + 2.12.27 .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 4022345852..f39d245e2d 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.27-SNAPSHOT + 2.12.27 .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 2413f82c65..2521943872 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.27-SNAPSHOT + 2.12.27 .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index a656877f03..ba6fde40f2 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.27-SNAPSHOT + 2.12.27 .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 62cd5061b8..e517334f4d 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.27-SNAPSHOT + 2.12.27 .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 5d274028fe..83070e1d38 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.27-SNAPSHOT + 2.12.27 .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 02b37716b1..fa504ddfd2 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.27-SNAPSHOT + 2.12.27 .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 128813259a..32ad84b991 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.27-SNAPSHOT + 2.12.27 .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index d888cf7b57..ee5e6eba14 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.27-SNAPSHOT + 2.12.27 pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.27 diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 7d584aba11..8c27a35b6a 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.27-SNAPSHOT + 2.12.27 .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index a48df5f307..2d39cdf6dd 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.27-SNAPSHOT + 2.12.27 .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 58b16221f9..b61900c176 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.27-SNAPSHOT + 2.12.27 .. strata-report diff --git a/pom.xml b/pom.xml index 8036c3aa4e..c98fcf84eb 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.27-SNAPSHOT + 2.12.27 pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.27 From 35ee2b76b1d5da41774e5039bd03e51366dc4a47 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Thu, 8 Jun 2023 10:51:29 +0000 Subject: [PATCH 029/116] [maven-release-plugin] prepare for next development iteration --- examples/pom.xml | 6 +----- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 52a988704f..b6ad2a10ff 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.27 + 2.12.28-SNAPSHOT jar Strata-Examples Example code to demonstrate use of Strata @@ -272,8 +272,4 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> - - - v2.12.27 - diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index 7e0d4aa0c9..39a7eb1f6c 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.27 + 2.12.28-SNAPSHOT .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index f39d245e2d..8964500e31 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.27 + 2.12.28-SNAPSHOT .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 2521943872..e9e226d38b 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.27 + 2.12.28-SNAPSHOT .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index ba6fde40f2..aab122d3af 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.27 + 2.12.28-SNAPSHOT .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index e517334f4d..68e2ef56df 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.27 + 2.12.28-SNAPSHOT .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 83070e1d38..2723ec5c86 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.27 + 2.12.28-SNAPSHOT .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index fa504ddfd2..9ba8773682 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.27 + 2.12.28-SNAPSHOT .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 32ad84b991..e985e514a7 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.27 + 2.12.28-SNAPSHOT .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index ee5e6eba14..809a77995a 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.27 + 2.12.28-SNAPSHOT pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.27 + HEAD diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 8c27a35b6a..9f7e6219c0 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.27 + 2.12.28-SNAPSHOT .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 2d39cdf6dd..2ddfcc80e5 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.27 + 2.12.28-SNAPSHOT .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index b61900c176..b37c441e24 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.27 + 2.12.28-SNAPSHOT .. strata-report diff --git a/pom.xml b/pom.xml index c98fcf84eb..fa8730e497 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.27 + 2.12.28-SNAPSHOT pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.27 + HEAD From 3652c88f9f4935b50ab6bf5cc785fbd2f02a5e5c Mon Sep 17 00:00:00 2001 From: Ujjwal Tyagi <56214203+tyagi-data-wizard@users.noreply.github.com> Date: Mon, 19 Jun 2023 02:12:10 +0530 Subject: [PATCH 030/116] Update DerivedCalculationFunctionTest.java (#2589) #2507 According to the issue, not best practice to return statement in @Test methods, so removed the annotation --- .../strata/calc/runner/DerivedCalculationFunctionTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/calc/src/test/java/com/opengamma/strata/calc/runner/DerivedCalculationFunctionTest.java b/modules/calc/src/test/java/com/opengamma/strata/calc/runner/DerivedCalculationFunctionTest.java index 895d87e00d..74715bb2d0 100644 --- a/modules/calc/src/test/java/com/opengamma/strata/calc/runner/DerivedCalculationFunctionTest.java +++ b/modules/calc/src/test/java/com/opengamma/strata/calc/runner/DerivedCalculationFunctionTest.java @@ -286,7 +286,6 @@ final class TestTarget implements CalculationTarget { // CSIGNORE this.value = value; } - @Test public int getValue() { return value; } From 2f5d583aa57c72d35331074ed0e56c5fd36174aa Mon Sep 17 00:00:00 2001 From: Yuki Iwashita Date: Tue, 1 Aug 2023 17:18:34 +0100 Subject: [PATCH 031/116] public access to maps (#2594) --- .../pricer/credit/ImmutableCreditRatesProvider.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/pricer/src/main/java/com/opengamma/strata/pricer/credit/ImmutableCreditRatesProvider.java b/modules/pricer/src/main/java/com/opengamma/strata/pricer/credit/ImmutableCreditRatesProvider.java index 27e63c42f7..722bc072f8 100644 --- a/modules/pricer/src/main/java/com/opengamma/strata/pricer/credit/ImmutableCreditRatesProvider.java +++ b/modules/pricer/src/main/java/com/opengamma/strata/pricer/credit/ImmutableCreditRatesProvider.java @@ -61,21 +61,21 @@ public final class ImmutableCreditRatesProvider *

    * The curve data, predicting the survival probability, associated with each legal entity and currency. */ - @PropertyDefinition(validate = "notNull", get = "private") + @PropertyDefinition(validate = "notNull") private final ImmutableMap, LegalEntitySurvivalProbabilities> creditCurves; /** * The discounting curves. *

    * The curve data, predicting the discount factor, associated with each currency. */ - @PropertyDefinition(validate = "notEmpty", get = "private") + @PropertyDefinition(validate = "notEmpty") private final ImmutableMap discountCurves; /** * The credit rate curves. *

    * The curve date, predicting the recovery rate, associated with each legal entity. */ - @PropertyDefinition(validate = "notEmpty", get = "private") + @PropertyDefinition(validate = "notEmpty") private final ImmutableMap recoveryRateCurves; //------------------------------------------------------------------------- @@ -269,7 +269,7 @@ public LocalDate getValuationDate() { * The curve data, predicting the survival probability, associated with each legal entity and currency. * @return the value of the property, not null */ - private ImmutableMap, LegalEntitySurvivalProbabilities> getCreditCurves() { + public ImmutableMap, LegalEntitySurvivalProbabilities> getCreditCurves() { return creditCurves; } @@ -280,7 +280,7 @@ private ImmutableMap, LegalEntitySurvivalProbabilitie * The curve data, predicting the discount factor, associated with each currency. * @return the value of the property, not empty */ - private ImmutableMap getDiscountCurves() { + public ImmutableMap getDiscountCurves() { return discountCurves; } @@ -291,7 +291,7 @@ private ImmutableMap getDiscountCurves() { * The curve date, predicting the recovery rate, associated with each legal entity. * @return the value of the property, not empty */ - private ImmutableMap getRecoveryRateCurves() { + public ImmutableMap getRecoveryRateCurves() { return recoveryRateCurves; } From 104e44bc6f8035b42b7e5cc101a4f1f99625b0fc Mon Sep 17 00:00:00 2001 From: George Luca <25393853+BATja20@users.noreply.github.com> Date: Wed, 2 Aug 2023 12:17:00 +0300 Subject: [PATCH 032/116] PROD-26241: EtdVariant datecode now refers to day of month for DAILY (#2595) Co-authored-by: George Luca Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> --- .../java/com/opengamma/strata/product/etd/EtdVariant.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/product/src/main/java/com/opengamma/strata/product/etd/EtdVariant.java b/modules/product/src/main/java/com/opengamma/strata/product/etd/EtdVariant.java index 7e56654580..ab08ebafd8 100644 --- a/modules/product/src/main/java/com/opengamma/strata/product/etd/EtdVariant.java +++ b/modules/product/src/main/java/com/opengamma/strata/product/etd/EtdVariant.java @@ -55,7 +55,7 @@ public final class EtdVariant /** * The optional date code, populated for Weekly and Daily. *

    - * This will be the week number for Weekly and the day-of-week for Daily. + * This will be the week number for Weekly and the day-of-month for Daily. */ @PropertyDefinition(get = "optional") private final Integer dateCode; @@ -270,7 +270,7 @@ public EtdExpiryType getType() { /** * Gets the optional date code, populated for Weekly and Daily. *

    - * This will be the week number for Weekly and the day-of-week for Daily. + * This will be the week number for Weekly and the day-of-month for Daily. * @return the optional value of the property, not null */ public OptionalInt getDateCode() { From 9275b0e9f5992f05eac32ad22e8e70f55d6a9ceb Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Thu, 3 Aug 2023 07:32:32 +0000 Subject: [PATCH 033/116] [maven-release-plugin] prepare release v2.12.28 --- examples/pom.xml | 6 +++++- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index b6ad2a10ff..eaf5ce9406 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.28-SNAPSHOT + 2.12.28 jar Strata-Examples Example code to demonstrate use of Strata @@ -272,4 +272,8 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> + + + v2.12.28 + diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index 39a7eb1f6c..d08b553e22 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.28-SNAPSHOT + 2.12.28 .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 8964500e31..a766db444b 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.28-SNAPSHOT + 2.12.28 .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index e9e226d38b..50d2ebcb3d 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.28-SNAPSHOT + 2.12.28 .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index aab122d3af..e6b78185e2 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.28-SNAPSHOT + 2.12.28 .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 68e2ef56df..e34177d78d 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.28-SNAPSHOT + 2.12.28 .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 2723ec5c86..25e56ba2db 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.28-SNAPSHOT + 2.12.28 .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 9ba8773682..036871f979 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.28-SNAPSHOT + 2.12.28 .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index e985e514a7..76d4831400 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.28-SNAPSHOT + 2.12.28 .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 809a77995a..d328759277 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.28-SNAPSHOT + 2.12.28 pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.28 diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 9f7e6219c0..94b525d959 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.28-SNAPSHOT + 2.12.28 .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 2ddfcc80e5..8e639d6f64 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.28-SNAPSHOT + 2.12.28 .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index b37c441e24..0ea3ba41c1 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.28-SNAPSHOT + 2.12.28 .. strata-report diff --git a/pom.xml b/pom.xml index fa8730e497..4641c36de6 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.28-SNAPSHOT + 2.12.28 pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.28 From dd9980c35054258743b8258acd8182c0ba3f3710 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Thu, 3 Aug 2023 07:32:34 +0000 Subject: [PATCH 034/116] [maven-release-plugin] prepare for next development iteration --- examples/pom.xml | 6 +----- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index eaf5ce9406..6a1ee2738b 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.28 + 2.12.29-SNAPSHOT jar Strata-Examples Example code to demonstrate use of Strata @@ -272,8 +272,4 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> - - - v2.12.28 - diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index d08b553e22..a3c5f6d38d 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.28 + 2.12.29-SNAPSHOT .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index a766db444b..b9d18490b7 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.28 + 2.12.29-SNAPSHOT .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 50d2ebcb3d..e7ce1cbdd5 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.28 + 2.12.29-SNAPSHOT .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index e6b78185e2..a4676fdffb 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.28 + 2.12.29-SNAPSHOT .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index e34177d78d..34397be2ac 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.28 + 2.12.29-SNAPSHOT .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 25e56ba2db..331e802d4d 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.28 + 2.12.29-SNAPSHOT .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 036871f979..ca28d78796 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.28 + 2.12.29-SNAPSHOT .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 76d4831400..5e1a9834f5 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.28 + 2.12.29-SNAPSHOT .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index d328759277..16bafe3623 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.28 + 2.12.29-SNAPSHOT pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.28 + HEAD diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 94b525d959..9e166caa8e 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.28 + 2.12.29-SNAPSHOT .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 8e639d6f64..9e545a2b26 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.28 + 2.12.29-SNAPSHOT .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 0ea3ba41c1..40bc0bbc31 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.28 + 2.12.29-SNAPSHOT .. strata-report diff --git a/pom.xml b/pom.xml index 4641c36de6..a64c951135 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.28 + 2.12.29-SNAPSHOT pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.28 + HEAD From aadda1cc94bb6f846ef06bfa79e9c155af5a0f8e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 7 Aug 2023 09:22:41 +0100 Subject: [PATCH 035/116] Bump com.google.guava:guava from 31.1-jre to 32.1.2-jre (#2596) Bumps [com.google.guava:guava](https://github.com/google/guava) from 31.1-jre to 32.1.2-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) --- updated-dependencies: - dependency-name: com.google.guava:guava dependency-type: direct:production ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pom.xml b/modules/pom.xml index 16bafe3623..bc04e91e99 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -765,7 +765,7 @@ 9.5 3.24.2 1.6.Final - 31.1-jre + 32.1.2-jre 26.0-jre 1.78 2.2.3 From fe6576477250d5c03cf65400ba8c9011b5d19a12 Mon Sep 17 00:00:00 2001 From: Victor Patentasu Date: Tue, 29 Aug 2023 15:20:00 +0300 Subject: [PATCH 036/116] Add ShiftType.FIXED (#2599) Co-authored-by: Victor Patentasu --- .../opengamma/strata/market/ShiftType.java | 22 +++++++++++++++++++ .../strata/market/ShiftTypeTest.java | 9 ++++++++ 2 files changed, 31 insertions(+) diff --git a/modules/market/src/main/java/com/opengamma/strata/market/ShiftType.java b/modules/market/src/main/java/com/opengamma/strata/market/ShiftType.java index 36c20caf72..c790c89087 100644 --- a/modules/market/src/main/java/com/opengamma/strata/market/ShiftType.java +++ b/modules/market/src/main/java/com/opengamma/strata/market/ShiftType.java @@ -89,6 +89,28 @@ public ValueAdjustment toValueAdjustment(double shiftAmount) { public double computeShift(double baseValue, double shiftedValue) { return shiftedValue / baseValue; } + }, + + /** + * A fixed shift where the value becomes the shift amount. + *

    + * {@code shiftedValue = shiftAmount} + */ + FIXED { + @Override + public double applyShift(double value, double shiftAmount) { + return shiftAmount; + } + + @Override + public ValueAdjustment toValueAdjustment(double shiftAmount) { + return ValueAdjustment.ofReplace(shiftAmount); + } + + @Override + public double computeShift(double baseValue, double shiftedValue) { + return shiftedValue; + } }; // helper for name conversions diff --git a/modules/market/src/test/java/com/opengamma/strata/market/ShiftTypeTest.java b/modules/market/src/test/java/com/opengamma/strata/market/ShiftTypeTest.java index 313ce2ca59..9981f1cc9d 100644 --- a/modules/market/src/test/java/com/opengamma/strata/market/ShiftTypeTest.java +++ b/modules/market/src/test/java/com/opengamma/strata/market/ShiftTypeTest.java @@ -21,6 +21,7 @@ public void test_applyShift() { assertThat(ShiftType.ABSOLUTE.applyShift(2, 0.1)).isEqualTo(2.1); assertThat(ShiftType.RELATIVE.applyShift(2, 0.1)).isEqualTo(2.2); assertThat(ShiftType.SCALED.applyShift(2, 1.1)).isEqualTo(2.2); + assertThat(ShiftType.FIXED.applyShift(2, 3)).isEqualTo(3); } @Test @@ -28,6 +29,7 @@ public void test_toValueAdjustment() { assertThat(ShiftType.ABSOLUTE.toValueAdjustment(0.1).adjust(2)).isEqualTo(2.1); assertThat(ShiftType.RELATIVE.toValueAdjustment(0.1).adjust(2)).isEqualTo(2.2); assertThat(ShiftType.SCALED.toValueAdjustment(1.1).adjust(2)).isEqualTo(2.2); + assertThat(ShiftType.FIXED.toValueAdjustment(3).adjust(2)).isEqualTo(3); } @Test @@ -35,15 +37,20 @@ public void test_computeShift() { double tol = 1.0e-15; double base = 2.0; double shifted = 2.1; + assertThat(ShiftType.ABSOLUTE.computeShift(base, shifted)).isCloseTo(0.1, offset(tol)); assertThat(ShiftType.RELATIVE.computeShift(base, shifted)).isCloseTo(0.05, offset(tol)); assertThat(ShiftType.SCALED.computeShift(base, shifted)).isCloseTo(1.05, offset(tol)); + assertThat(ShiftType.FIXED.computeShift(base, shifted)).isCloseTo(shifted, offset(tol)); + assertThat(ShiftType.ABSOLUTE.applyShift(base, ShiftType.ABSOLUTE.computeShift(base, shifted))) .isCloseTo(shifted, offset(tol)); assertThat(ShiftType.RELATIVE.applyShift(base, ShiftType.RELATIVE.computeShift(base, shifted))) .isCloseTo(shifted, offset(tol)); assertThat(ShiftType.SCALED.applyShift(base, ShiftType.SCALED.computeShift(base, shifted))) .isCloseTo(shifted, offset(tol)); + assertThat(ShiftType.FIXED.applyShift(base, ShiftType.FIXED.computeShift(base, shifted))) + .isCloseTo(shifted, offset(tol)); } @Test @@ -51,6 +58,7 @@ public void test_name() { assertThat(ShiftType.ABSOLUTE.name()).isEqualTo("ABSOLUTE"); assertThat(ShiftType.RELATIVE.name()).isEqualTo("RELATIVE"); assertThat(ShiftType.SCALED.name()).isEqualTo("SCALED"); + assertThat(ShiftType.FIXED.name()).isEqualTo("FIXED"); } @Test @@ -58,6 +66,7 @@ public void test_toString() { assertThat(ShiftType.ABSOLUTE.toString()).isEqualTo("Absolute"); assertThat(ShiftType.RELATIVE.toString()).isEqualTo("Relative"); assertThat(ShiftType.SCALED.toString()).isEqualTo("Scaled"); + assertThat(ShiftType.FIXED.toString()).isEqualTo("Fixed"); } @Test From 5f862d1554fb085084c150718ef39f0a5af0803e Mon Sep 17 00:00:00 2001 From: Christopher Bond <11727490+ChristopherBond@users.noreply.github.com> Date: Thu, 31 Aug 2023 12:07:56 +0100 Subject: [PATCH 037/116] Update ogbot.yml (#2600) --- .github/workflows/ogbot.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ogbot.yml b/.github/workflows/ogbot.yml index 0ed824e2ec..18aa9333ca 100644 --- a/.github/workflows/ogbot.yml +++ b/.github/workflows/ogbot.yml @@ -7,6 +7,7 @@ on: jobs: pr: runs-on: ubuntu-latest + permissions: write-all steps: - uses: OpenGamma/OGBot@main with: From 7bf764e2a18eca67b9b421f72a368c9aedd15b41 Mon Sep 17 00:00:00 2001 From: Akshai Shah Date: Tue, 5 Sep 2023 08:30:45 +0100 Subject: [PATCH 038/116] CsvRow - Reword exception for missing value (#2601) --- .../src/main/java/com/opengamma/strata/collect/io/CsvRow.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/collect/src/main/java/com/opengamma/strata/collect/io/CsvRow.java b/modules/collect/src/main/java/com/opengamma/strata/collect/io/CsvRow.java index 6255adec3e..c936c8bd06 100644 --- a/modules/collect/src/main/java/com/opengamma/strata/collect/io/CsvRow.java +++ b/modules/collect/src/main/java/com/opengamma/strata/collect/io/CsvRow.java @@ -271,7 +271,7 @@ public Optional findField(Pattern headerPattern) { public String getValue(String header) { String value = getField(header); if (value.isEmpty()) { - throw new ParseFailureException("No value was found for '{header}'", header); + throw new ParseFailureException("No value was found in column '{header}'", header); } return value; } From 6b83478b6e1d39af3ef38736af08a2c2f81ca557 Mon Sep 17 00:00:00 2001 From: Yuki Iwashita Date: Tue, 12 Sep 2023 15:40:22 +0100 Subject: [PATCH 039/116] Nodal Recovery Rates (#2602) --- .../pricer/credit/NodalRecoveryRates.java | 407 ++++++++++++++++++ .../strata/pricer/credit/RecoveryRates.java | 14 +- .../pricer/credit/NodalRecoveryRatesTest.java | 86 ++++ 3 files changed, 504 insertions(+), 3 deletions(-) create mode 100644 modules/pricer/src/main/java/com/opengamma/strata/pricer/credit/NodalRecoveryRates.java create mode 100644 modules/pricer/src/test/java/com/opengamma/strata/pricer/credit/NodalRecoveryRatesTest.java diff --git a/modules/pricer/src/main/java/com/opengamma/strata/pricer/credit/NodalRecoveryRates.java b/modules/pricer/src/main/java/com/opengamma/strata/pricer/credit/NodalRecoveryRates.java new file mode 100644 index 0000000000..f4ba8a752b --- /dev/null +++ b/modules/pricer/src/main/java/com/opengamma/strata/pricer/credit/NodalRecoveryRates.java @@ -0,0 +1,407 @@ +/* + * Copyright (C) 2023 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.pricer.credit; + +import java.io.Serializable; +import java.time.LocalDate; +import java.util.NoSuchElementException; +import java.util.Optional; + +import org.joda.beans.ImmutableBean; +import org.joda.beans.JodaBeanUtils; +import org.joda.beans.MetaBean; +import org.joda.beans.MetaProperty; +import org.joda.beans.TypedMetaBean; +import org.joda.beans.gen.BeanDefinition; +import org.joda.beans.gen.ImmutableConstructor; +import org.joda.beans.gen.PropertyDefinition; +import org.joda.beans.impl.direct.DirectFieldsBeanBuilder; +import org.joda.beans.impl.direct.MinimalMetaBean; + +import com.opengamma.strata.basics.StandardId; +import com.opengamma.strata.basics.date.DayCount; +import com.opengamma.strata.collect.ArgChecker; +import com.opengamma.strata.data.MarketDataName; +import com.opengamma.strata.market.ValueType; +import com.opengamma.strata.market.curve.CurveInfoType; +import com.opengamma.strata.market.curve.InterpolatedNodalCurve; +import com.opengamma.strata.market.curve.NodalCurve; +import com.opengamma.strata.market.param.ParameterMetadata; +import com.opengamma.strata.market.param.ParameterPerturbation; + +/** + * The recovery rates based on a nodal curve. + *

    + * The underlying curve must contain {@linkplain ValueType#YEAR_FRACTION year fractions} + * against {@linkplain ValueType#RECOVERY_RATE recovery rates}, and the day count must be present. + */ +@BeanDefinition(style = "minimal") +public final class NodalRecoveryRates + implements RecoveryRates, ImmutableBean, Serializable { + + /** + * The legal entity identifier. + *

    + * This identifier is used for the reference legal entity of a credit derivative. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final StandardId legalEntityId; + /** + * The valuation date. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final LocalDate valuationDate; + /** + * The underlying curve. + *

    + * The metadata of the curve must define a day count. + */ + @PropertyDefinition(validate = "notNull") + private final NodalCurve curve; + /** + * The day count convention of the curve. + */ + private final transient DayCount dayCount; // cached, not a property + + //------------------------------------------------------------------------- + + /** + * Obtains an instance. + *

    + * The curve is specified by an instance of {@link NodalCurve}, such as {@link InterpolatedNodalCurve}. + * The curve must contain {@linkplain ValueType#YEAR_FRACTION year fractions} + * against {@linkplain ValueType#RECOVERY_RATE recovery rates}, and the day count must be present. + * + * @param legalEntityId the legalEntity ID + * @param valuationDate the valuation date for which the curve is valid + * @param curve the underlying curve + * @return the instance + */ + public static NodalRecoveryRates of(StandardId legalEntityId, LocalDate valuationDate, NodalCurve curve) { + return new NodalRecoveryRates(legalEntityId, valuationDate, curve); + } + + @ImmutableConstructor + private NodalRecoveryRates(StandardId legalEntityId, LocalDate valuationDate, NodalCurve curve) { + + ArgChecker.notNull(legalEntityId, "legalEntityId"); + ArgChecker.notNull(valuationDate, "valuationDate"); + ArgChecker.notNull(curve, "curve"); + curve.getMetadata().getXValueType().checkEquals( + ValueType.YEAR_FRACTION, "Incorrect x-value type for recovery rate curve"); + curve.getMetadata().getYValueType().checkEquals( + ValueType.RECOVERY_RATE, "Incorrect y-value type for recovery rate curve"); + DayCount dayCount = curve.getMetadata().findInfo(CurveInfoType.DAY_COUNT) + .orElseThrow(() -> new IllegalArgumentException("Incorrect curve metadata, missing DayCount")); + + this.legalEntityId = legalEntityId; + this.valuationDate = valuationDate; + this.curve = curve; + this.dayCount = dayCount; + } + + //------------------------------------------------------------------------- + + @Override + public double recoveryRate(LocalDate date) { + double yearFraction = dayCount.relativeYearFraction(valuationDate, date); + return curve.yValue(yearFraction); + } + + @Override + public Optional findData(MarketDataName name) { + if (curve.getName().equals(name)) { + return Optional.of(name.getMarketDataType().cast(curve)); + } + return Optional.empty(); + } + + @Override + public int getParameterCount() { + return curve.getParameterCount(); + } + + @Override + public double getParameter(int parameterIndex) { + return curve.getParameter(parameterIndex); + } + + @Override + public ParameterMetadata getParameterMetadata(int parameterIndex) { + return curve.getParameterMetadata(parameterIndex); + } + + @Override + public NodalRecoveryRates withParameter(int parameterIndex, double newValue) { + return withCurve(curve.withParameter(parameterIndex, newValue)); + } + + @Override + public NodalRecoveryRates withPerturbation(ParameterPerturbation perturbation) { + return withCurve(curve.withPerturbation(perturbation)); + } + + //------------------------------------------------------------------------- + + /** + * Returns a new instance with a different curve. + * + * @param curve the new curve + * @return the new instance + */ + public NodalRecoveryRates withCurve(NodalCurve curve) { + return new NodalRecoveryRates(legalEntityId, valuationDate, curve); + } + + //------------------------- AUTOGENERATED START ------------------------- + /** + * The meta-bean for {@code NodalRecoveryRates}. + */ + private static final TypedMetaBean META_BEAN = + MinimalMetaBean.of( + NodalRecoveryRates.class, + new String[] { + "legalEntityId", + "valuationDate", + "curve"}, + () -> new NodalRecoveryRates.Builder(), + b -> b.getLegalEntityId(), + b -> b.getValuationDate(), + b -> b.getCurve()); + + /** + * The meta-bean for {@code NodalRecoveryRates}. + * @return the meta-bean, not null + */ + public static TypedMetaBean meta() { + return META_BEAN; + } + + static { + MetaBean.register(META_BEAN); + } + + /** + * The serialization version id. + */ + private static final long serialVersionUID = 1L; + + /** + * Returns a builder used to create an instance of the bean. + * @return the builder, not null + */ + public static NodalRecoveryRates.Builder builder() { + return new NodalRecoveryRates.Builder(); + } + + @Override + public TypedMetaBean metaBean() { + return META_BEAN; + } + + //----------------------------------------------------------------------- + /** + * Gets the legal entity identifier. + *

    + * This identifier is used for the reference legal entity of a credit derivative. + * @return the value of the property, not null + */ + @Override + public StandardId getLegalEntityId() { + return legalEntityId; + } + + //----------------------------------------------------------------------- + /** + * Gets the valuation date. + * @return the value of the property, not null + */ + @Override + public LocalDate getValuationDate() { + return valuationDate; + } + + //----------------------------------------------------------------------- + /** + * Gets the underlying curve. + *

    + * The metadata of the curve must define a day count. + * @return the value of the property, not null + */ + public NodalCurve getCurve() { + return curve; + } + + //----------------------------------------------------------------------- + /** + * Returns a builder that allows this bean to be mutated. + * @return the mutable builder, not null + */ + public Builder toBuilder() { + return new Builder(this); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && obj.getClass() == this.getClass()) { + NodalRecoveryRates other = (NodalRecoveryRates) obj; + return JodaBeanUtils.equal(legalEntityId, other.legalEntityId) && + JodaBeanUtils.equal(valuationDate, other.valuationDate) && + JodaBeanUtils.equal(curve, other.curve); + } + return false; + } + + @Override + public int hashCode() { + int hash = getClass().hashCode(); + hash = hash * 31 + JodaBeanUtils.hashCode(legalEntityId); + hash = hash * 31 + JodaBeanUtils.hashCode(valuationDate); + hash = hash * 31 + JodaBeanUtils.hashCode(curve); + return hash; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(128); + buf.append("NodalRecoveryRates{"); + buf.append("legalEntityId").append('=').append(JodaBeanUtils.toString(legalEntityId)).append(',').append(' '); + buf.append("valuationDate").append('=').append(JodaBeanUtils.toString(valuationDate)).append(',').append(' '); + buf.append("curve").append('=').append(JodaBeanUtils.toString(curve)); + buf.append('}'); + return buf.toString(); + } + + //----------------------------------------------------------------------- + /** + * The bean-builder for {@code NodalRecoveryRates}. + */ + public static final class Builder extends DirectFieldsBeanBuilder { + + private StandardId legalEntityId; + private LocalDate valuationDate; + private NodalCurve curve; + + /** + * Restricted constructor. + */ + private Builder() { + } + + /** + * Restricted copy constructor. + * @param beanToCopy the bean to copy from, not null + */ + private Builder(NodalRecoveryRates beanToCopy) { + this.legalEntityId = beanToCopy.getLegalEntityId(); + this.valuationDate = beanToCopy.getValuationDate(); + this.curve = beanToCopy.getCurve(); + } + + //----------------------------------------------------------------------- + @Override + public Object get(String propertyName) { + switch (propertyName.hashCode()) { + case 866287159: // legalEntityId + return legalEntityId; + case 113107279: // valuationDate + return valuationDate; + case 95027439: // curve + return curve; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + } + + @Override + public Builder set(String propertyName, Object newValue) { + switch (propertyName.hashCode()) { + case 866287159: // legalEntityId + this.legalEntityId = (StandardId) newValue; + break; + case 113107279: // valuationDate + this.valuationDate = (LocalDate) newValue; + break; + case 95027439: // curve + this.curve = (NodalCurve) newValue; + break; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + return this; + } + + @Override + public Builder set(MetaProperty property, Object value) { + super.set(property, value); + return this; + } + + @Override + public NodalRecoveryRates build() { + return new NodalRecoveryRates( + legalEntityId, + valuationDate, + curve); + } + + //----------------------------------------------------------------------- + /** + * Sets the legal entity identifier. + *

    + * This identifier is used for the reference legal entity of a credit derivative. + * @param legalEntityId the new value, not null + * @return this, for chaining, not null + */ + public Builder legalEntityId(StandardId legalEntityId) { + JodaBeanUtils.notNull(legalEntityId, "legalEntityId"); + this.legalEntityId = legalEntityId; + return this; + } + + /** + * Sets the valuation date. + * @param valuationDate the new value, not null + * @return this, for chaining, not null + */ + public Builder valuationDate(LocalDate valuationDate) { + JodaBeanUtils.notNull(valuationDate, "valuationDate"); + this.valuationDate = valuationDate; + return this; + } + + /** + * Sets the underlying curve. + *

    + * The metadata of the curve must define a day count. + * @param curve the new value, not null + * @return this, for chaining, not null + */ + public Builder curve(NodalCurve curve) { + JodaBeanUtils.notNull(curve, "curve"); + this.curve = curve; + return this; + } + + //----------------------------------------------------------------------- + @Override + public String toString() { + StringBuilder buf = new StringBuilder(128); + buf.append("NodalRecoveryRates.Builder{"); + buf.append("legalEntityId").append('=').append(JodaBeanUtils.toString(legalEntityId)).append(',').append(' '); + buf.append("valuationDate").append('=').append(JodaBeanUtils.toString(valuationDate)).append(',').append(' '); + buf.append("curve").append('=').append(JodaBeanUtils.toString(curve)); + buf.append('}'); + return buf.toString(); + } + + } + + //-------------------------- AUTOGENERATED END -------------------------- +} diff --git a/modules/pricer/src/main/java/com/opengamma/strata/pricer/credit/RecoveryRates.java b/modules/pricer/src/main/java/com/opengamma/strata/pricer/credit/RecoveryRates.java index 97988dbbac..6a859d411c 100644 --- a/modules/pricer/src/main/java/com/opengamma/strata/pricer/credit/RecoveryRates.java +++ b/modules/pricer/src/main/java/com/opengamma/strata/pricer/credit/RecoveryRates.java @@ -12,6 +12,7 @@ import com.opengamma.strata.market.ValueType; import com.opengamma.strata.market.curve.ConstantCurve; import com.opengamma.strata.market.curve.Curve; +import com.opengamma.strata.market.curve.NodalCurve; import com.opengamma.strata.market.param.ParameterPerturbation; import com.opengamma.strata.market.param.ParameterizedData; @@ -26,7 +27,8 @@ public interface RecoveryRates /** * Obtains an instance from a curve. *

    - * If the curve is {@code ConstantCurve}, {@code ConstantRecoveryRates} is always instantiated. + * If the curve is {@code ConstantCurve}, {@code ConstantRecoveryRates} is always instantiated. + * If the curve is {@code NodalCurve}, {@code NodalRecoveryRates} is always instantiated. * * @param legalEntityId the legal entity identifier * @param valuationDate the valuation date for which the curve is valid @@ -35,8 +37,14 @@ public interface RecoveryRates */ public static RecoveryRates of(StandardId legalEntityId, LocalDate valuationDate, Curve curve) { if (curve.getMetadata().getYValueType().equals(ValueType.RECOVERY_RATE)) { - ConstantCurve constantCurve = (ConstantCurve) curve; - return ConstantRecoveryRates.of(legalEntityId, valuationDate, constantCurve.getYValue()); + if (curve instanceof ConstantCurve) { + ConstantCurve constantCurve = (ConstantCurve) curve; + return ConstantRecoveryRates.of(legalEntityId, valuationDate, constantCurve.getYValue()); + } + if (curve instanceof NodalCurve) { + NodalCurve nodalCurve = (NodalCurve) curve; + return NodalRecoveryRates.of(legalEntityId, valuationDate, nodalCurve); + } } throw new IllegalArgumentException("Unknown curve type"); } diff --git a/modules/pricer/src/test/java/com/opengamma/strata/pricer/credit/NodalRecoveryRatesTest.java b/modules/pricer/src/test/java/com/opengamma/strata/pricer/credit/NodalRecoveryRatesTest.java new file mode 100644 index 0000000000..f9ce449c6d --- /dev/null +++ b/modules/pricer/src/test/java/com/opengamma/strata/pricer/credit/NodalRecoveryRatesTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2023 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.pricer.credit; + +import static com.opengamma.strata.basics.date.DayCounts.ACT_360; +import static com.opengamma.strata.collect.TestHelper.coverBeanEquals; +import static com.opengamma.strata.collect.TestHelper.coverImmutableBean; +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.LocalDate; +import java.util.Optional; + +import org.junit.jupiter.api.Test; + +import com.opengamma.strata.basics.StandardId; +import com.opengamma.strata.collect.array.DoubleArray; +import com.opengamma.strata.market.ValueType; +import com.opengamma.strata.market.curve.ConstantNodalCurve; +import com.opengamma.strata.market.curve.CurveName; +import com.opengamma.strata.market.curve.DefaultCurveMetadata; +import com.opengamma.strata.market.curve.InterpolatedNodalCurve; +import com.opengamma.strata.market.curve.interpolator.CurveInterpolators; +import com.opengamma.strata.market.surface.SurfaceName; + +/** + * Test {@link NodalRecoveryRates}. + */ +public class NodalRecoveryRatesTest { + + private static final LocalDate VALUATION_DATE = LocalDate.of(2016, 5, 6); + private static final StandardId LEGAL_ENTITY = StandardId.of("OG", "ABC"); + private static final LocalDate DATE_AFTER = LocalDate.of(2017, 2, 24); + + private static final InterpolatedNodalCurve CURVE = InterpolatedNodalCurve.of( + DefaultCurveMetadata.builder() + .curveName("test") + .dayCount(ACT_360) + .xValueType(ValueType.YEAR_FRACTION) + .yValueType(ValueType.RECOVERY_RATE) + .build(), + DoubleArray.of(1.0, 3.0, 5.0, 10.0), + DoubleArray.of(0.4, 0.35, 0.35, 0.3), + CurveInterpolators.LINEAR); + + @Test + public void test_of() { + NodalRecoveryRates test = NodalRecoveryRates.of(LEGAL_ENTITY, VALUATION_DATE, CURVE); + assertThat(test.getLegalEntityId()).isEqualTo(LEGAL_ENTITY); + assertThat(test.getValuationDate()).isEqualTo(VALUATION_DATE); + assertThat(test.recoveryRate(DATE_AFTER)).isEqualTo( + CURVE.yValue(ACT_360.relativeYearFraction(VALUATION_DATE, DATE_AFTER))); + assertThat(test.findData(CurveName.of("test"))).isEqualTo(Optional.of(CURVE)); + assertThat(test.findData(SurfaceName.of("foo"))).isEqualTo(Optional.empty()); + assertThat(test.getParameter(1)).isEqualTo(0.35); + assertThat(test.getParameterCount()).isEqualTo(4); + assertThat(test.getParameterMetadata(3)).isEqualTo(CURVE.getParameterMetadata(3)); + assertThat(test.withParameter(2, 0.5)).isEqualTo( + NodalRecoveryRates.of(LEGAL_ENTITY, VALUATION_DATE, CURVE.withParameter(2, 0.5))); + assertThat(test.withPerturbation((i, v, m) -> 2d * v)).isEqualTo( + NodalRecoveryRates.of(LEGAL_ENTITY, VALUATION_DATE, CURVE.withPerturbation((i, v, m) -> 2d * v))); + RecoveryRates test2 = RecoveryRates.of(LEGAL_ENTITY, VALUATION_DATE, CURVE); + assertThat(test).isEqualTo(test2); + } + + //------------------------------------------------------------------------- + + @Test + public void coverage() { + NodalRecoveryRates test1 = NodalRecoveryRates.of(LEGAL_ENTITY, VALUATION_DATE, CURVE); + coverImmutableBean(test1); + NodalRecoveryRates test2 = NodalRecoveryRates.of( + StandardId.of("OG", "DEF"), + DATE_AFTER, + ConstantNodalCurve.of( + DefaultCurveMetadata.builder().curveName("other") + .dayCount(ACT_360) + .xValueType(ValueType.YEAR_FRACTION) + .yValueType(ValueType.RECOVERY_RATE).build(), + 5.0, 0.2)); + coverBeanEquals(test1, test2); + } + +} From 5ad2e5cab6f9dfd8528c10fc24a17d5121ef4094 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 27 Sep 2023 14:07:19 +0100 Subject: [PATCH 040/116] Bump org.joda:joda-beans from 2.8.3 to 2.10.0 (#2604) Bumps [org.joda:joda-beans](https://github.com/JodaOrg/joda-beans) from 2.8.3 to 2.10.0. - [Release notes](https://github.com/JodaOrg/joda-beans/releases) - [Changelog](https://github.com/JodaOrg/joda-beans/blob/main/RELEASE-NOTES.txt) - [Commits](https://github.com/JodaOrg/joda-beans/compare/v2.8.3...v2.10.0) --- updated-dependencies: - dependency-name: org.joda:joda-beans dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pom.xml b/modules/pom.xml index bc04e91e99..c577e6a273 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -769,7 +769,7 @@ 26.0-jre 1.78 2.2.3 - 2.8.3 + 2.10.0 ${joda-beans.version} 5.9.3 4.9.0 From 740c2dd92e33b61dee361172e7ffbe26c8fa7d1c Mon Sep 17 00:00:00 2001 From: Guillaume Santoro <31656059+santorog@users.noreply.github.com> Date: Thu, 28 Sep 2023 12:34:51 +0200 Subject: [PATCH 041/116] Add notEmpty to ArgChecker for DoubleArray (#2605) * Add notEmpty to ArgChecker for DoubleArray * Generify and test * Revert autoformat * Fix Matrix test as using incorrect object --------- Co-authored-by: Guillaume Santoro --- .../opengamma/strata/collect/ArgChecker.java | 25 ++++++++++++++++++ .../strata/collect/ArgCheckerTest.java | 26 ++++++++++++++++++- 2 files changed, 50 insertions(+), 1 deletion(-) diff --git a/modules/collect/src/main/java/com/opengamma/strata/collect/ArgChecker.java b/modules/collect/src/main/java/com/opengamma/strata/collect/ArgChecker.java index 35afca14f9..664c7df8ad 100644 --- a/modules/collect/src/main/java/com/opengamma/strata/collect/ArgChecker.java +++ b/modules/collect/src/main/java/com/opengamma/strata/collect/ArgChecker.java @@ -14,6 +14,7 @@ import com.google.common.base.CharMatcher; import com.google.common.math.DoubleMath; +import com.opengamma.strata.collect.array.Matrix; /** * Contains utility methods for checking inputs to methods. @@ -438,6 +439,30 @@ public static T[] notEmpty(T[] argument, String name) { return argument; } + /** + * Checks that the specified argument is non-null and not empty. + *

    + * Given the input argument, this returns only if it is non-null and contains + * at least one element. The element is not validated and may be null. + * For example, in a constructor: + *

    +   *  this.names = ArgChecker.notEmpty(names, "names");
    +   * 
    + * + * @param the type of the argument reflected in the result + * @param argument the argument to check, null or empty throws an exception + * @param name the name of the argument to use in the error message, not null + * @return the input {@code argument}, not null + * @throws IllegalArgumentException if the input is null or empty + */ + public static T notEmpty(T argument, String name) { + notNull(argument, name); + if (argument.size() == 0) { + throw new IllegalArgumentException(notEmptyArrayMsg(name)); + } + return argument; + } + // extracted to aid inlining performance private static String notEmptyArrayMsg(String name) { return "Argument array '" + name + "' must not be empty"; diff --git a/modules/collect/src/test/java/com/opengamma/strata/collect/ArgCheckerTest.java b/modules/collect/src/test/java/com/opengamma/strata/collect/ArgCheckerTest.java index 29e1fa58aa..2d384ebba3 100644 --- a/modules/collect/src/test/java/com/opengamma/strata/collect/ArgCheckerTest.java +++ b/modules/collect/src/test/java/com/opengamma/strata/collect/ArgCheckerTest.java @@ -24,6 +24,8 @@ import com.google.common.base.CharMatcher; import com.google.common.collect.ImmutableSortedMap; +import com.opengamma.strata.collect.array.DoubleArray; +import com.opengamma.strata.collect.array.Matrix; /** * Test ArgChecker. @@ -267,7 +269,29 @@ public void test_notEmpty_String_null() { @Test public void test_notEmpty_String_empty() { assertThatIllegalArgumentException() - .isThrownBy(() -> ArgChecker.notEmpty("", "name")) + .isThrownBy(() -> ArgChecker.notEmpty(DoubleArray.of(), "name")) + .withMessageMatching(".*'name'.*empty.*"); + } + + //------------------------------------------------------------------------- + @Test + public void test_notEmpty_Matrix_ok() { + DoubleArray expected = DoubleArray.of(1); + DoubleArray result = ArgChecker.notEmpty(expected, "name"); + assertThat(result).isEqualTo(expected); + } + + @Test + public void test_notEmpty_Matrix_null() { + assertThatIllegalArgumentException() + .isThrownBy(() -> ArgChecker.notEmpty((Matrix) null, "name")) + .withMessageMatching(".*'name'.*null.*"); + } + + @Test + public void test_notEmpty_Matrix_empty() { + assertThatIllegalArgumentException() + .isThrownBy(() -> ArgChecker.notEmpty(DoubleArray.of(), "name")) .withMessageMatching(".*'name'.*empty.*"); } From 1395a830a2841cce83f34e32b6e2441df3fe88f0 Mon Sep 17 00:00:00 2001 From: Guillaume Santoro <31656059+santorog@users.noreply.github.com> Date: Mon, 23 Oct 2023 12:57:27 +0200 Subject: [PATCH 042/116] Do not throw exception when no ids are found for a currency pair in the FxOptionMarketDataLookup (#2608) --- .../measure/fxopt/DefaultFxOptionMarketDataLookup.java | 2 +- .../strata/measure/fxopt/FxOptionMarketDataLookup.java | 5 ++--- .../strata/measure/fxopt/FxOptionMarketDataLookupTest.java | 6 ++---- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/modules/measure/src/main/java/com/opengamma/strata/measure/fxopt/DefaultFxOptionMarketDataLookup.java b/modules/measure/src/main/java/com/opengamma/strata/measure/fxopt/DefaultFxOptionMarketDataLookup.java index 5ddbd75acc..a18c8c8f46 100644 --- a/modules/measure/src/main/java/com/opengamma/strata/measure/fxopt/DefaultFxOptionMarketDataLookup.java +++ b/modules/measure/src/main/java/com/opengamma/strata/measure/fxopt/DefaultFxOptionMarketDataLookup.java @@ -87,7 +87,7 @@ public ImmutableSet getVolatilityCurrencyPairs() { public ImmutableSet> getVolatilityIds(CurrencyPair currencyPair) { FxOptionVolatilitiesId id = volatilityIds.get(currencyPair); if (id == null) { - throw new IllegalArgumentException(msgPairNotFound(currencyPair)); + return ImmutableSet.of(); } return ImmutableSet.of(id); } diff --git a/modules/measure/src/main/java/com/opengamma/strata/measure/fxopt/FxOptionMarketDataLookup.java b/modules/measure/src/main/java/com/opengamma/strata/measure/fxopt/FxOptionMarketDataLookup.java index c75a8e8ce2..5f37900d55 100644 --- a/modules/measure/src/main/java/com/opengamma/strata/measure/fxopt/FxOptionMarketDataLookup.java +++ b/modules/measure/src/main/java/com/opengamma/strata/measure/fxopt/FxOptionMarketDataLookup.java @@ -87,11 +87,10 @@ public default Class queryType() { * Gets the identifiers used to obtain the volatilities for the specified currency pair. *

    * The result will typically refer to a surface or cube. - * If the currency pair is not found, an exception is thrown. + * If the currency pair is not found, an empty set is returned. * * @param currencyPair the currency pair for which identifiers are required - * @return the set of market data identifiers - * @throws IllegalArgumentException if the currency pair is not found + * @return the set of market data identifiers, that can be empty */ public abstract ImmutableSet> getVolatilityIds(CurrencyPair currencyPair); diff --git a/modules/measure/src/test/java/com/opengamma/strata/measure/fxopt/FxOptionMarketDataLookupTest.java b/modules/measure/src/test/java/com/opengamma/strata/measure/fxopt/FxOptionMarketDataLookupTest.java index c45bd716db..aa0343df60 100644 --- a/modules/measure/src/test/java/com/opengamma/strata/measure/fxopt/FxOptionMarketDataLookupTest.java +++ b/modules/measure/src/test/java/com/opengamma/strata/measure/fxopt/FxOptionMarketDataLookupTest.java @@ -56,8 +56,7 @@ public void test_of_single() { assertThat(test.queryType()).isEqualTo(FxOptionMarketDataLookup.class); assertThat(test.getVolatilityCurrencyPairs()).containsOnly(EUR_USD); assertThat(test.getVolatilityIds(EUR_USD)).containsOnly(VOL_ID1); - assertThatIllegalArgumentException() - .isThrownBy(() -> test.getVolatilityIds(GBP_USD)); + assertThat(test.getVolatilityIds(GBP_USD)).isEmpty(); assertThat(test.requirements(EUR_USD)).isEqualTo(FunctionRequirements.builder().valueRequirements(VOL_ID1).build()); assertThat(test.requirements(ImmutableSet.of(EUR_USD))) @@ -73,8 +72,7 @@ public void test_of_map() { assertThat(test.queryType()).isEqualTo(FxOptionMarketDataLookup.class); assertThat(test.getVolatilityCurrencyPairs()).containsOnly(EUR_USD, GBP_USD); assertThat(test.getVolatilityIds(EUR_USD)).containsOnly(VOL_ID1); - assertThatIllegalArgumentException() - .isThrownBy(() -> test.getVolatilityIds(EUR_GBP)); + assertThat(test.getVolatilityIds(EUR_GBP)).isEmpty(); assertThat(test.requirements(EUR_USD)).isEqualTo(FunctionRequirements.builder().valueRequirements(VOL_ID1).build()); assertThat(test.requirements(ImmutableSet.of(EUR_USD))) From e40557741079905a95097f288801d563ecd00fe1 Mon Sep 17 00:00:00 2001 From: Guillaume Santoro <31656059+santorog@users.noreply.github.com> Date: Mon, 23 Oct 2023 13:29:43 +0200 Subject: [PATCH 043/116] Revert "Do not throw exception when no ids are found for a currency pair in the FxOptionMarketDataLookup (#2608)" (#2609) This reverts commit 1395a830a2841cce83f34e32b6e2441df3fe88f0. --- .../measure/fxopt/DefaultFxOptionMarketDataLookup.java | 2 +- .../strata/measure/fxopt/FxOptionMarketDataLookup.java | 5 +++-- .../strata/measure/fxopt/FxOptionMarketDataLookupTest.java | 6 ++++-- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/modules/measure/src/main/java/com/opengamma/strata/measure/fxopt/DefaultFxOptionMarketDataLookup.java b/modules/measure/src/main/java/com/opengamma/strata/measure/fxopt/DefaultFxOptionMarketDataLookup.java index a18c8c8f46..5ddbd75acc 100644 --- a/modules/measure/src/main/java/com/opengamma/strata/measure/fxopt/DefaultFxOptionMarketDataLookup.java +++ b/modules/measure/src/main/java/com/opengamma/strata/measure/fxopt/DefaultFxOptionMarketDataLookup.java @@ -87,7 +87,7 @@ public ImmutableSet getVolatilityCurrencyPairs() { public ImmutableSet> getVolatilityIds(CurrencyPair currencyPair) { FxOptionVolatilitiesId id = volatilityIds.get(currencyPair); if (id == null) { - return ImmutableSet.of(); + throw new IllegalArgumentException(msgPairNotFound(currencyPair)); } return ImmutableSet.of(id); } diff --git a/modules/measure/src/main/java/com/opengamma/strata/measure/fxopt/FxOptionMarketDataLookup.java b/modules/measure/src/main/java/com/opengamma/strata/measure/fxopt/FxOptionMarketDataLookup.java index 5f37900d55..c75a8e8ce2 100644 --- a/modules/measure/src/main/java/com/opengamma/strata/measure/fxopt/FxOptionMarketDataLookup.java +++ b/modules/measure/src/main/java/com/opengamma/strata/measure/fxopt/FxOptionMarketDataLookup.java @@ -87,10 +87,11 @@ public default Class queryType() { * Gets the identifiers used to obtain the volatilities for the specified currency pair. *

    * The result will typically refer to a surface or cube. - * If the currency pair is not found, an empty set is returned. + * If the currency pair is not found, an exception is thrown. * * @param currencyPair the currency pair for which identifiers are required - * @return the set of market data identifiers, that can be empty + * @return the set of market data identifiers + * @throws IllegalArgumentException if the currency pair is not found */ public abstract ImmutableSet> getVolatilityIds(CurrencyPair currencyPair); diff --git a/modules/measure/src/test/java/com/opengamma/strata/measure/fxopt/FxOptionMarketDataLookupTest.java b/modules/measure/src/test/java/com/opengamma/strata/measure/fxopt/FxOptionMarketDataLookupTest.java index aa0343df60..c45bd716db 100644 --- a/modules/measure/src/test/java/com/opengamma/strata/measure/fxopt/FxOptionMarketDataLookupTest.java +++ b/modules/measure/src/test/java/com/opengamma/strata/measure/fxopt/FxOptionMarketDataLookupTest.java @@ -56,7 +56,8 @@ public void test_of_single() { assertThat(test.queryType()).isEqualTo(FxOptionMarketDataLookup.class); assertThat(test.getVolatilityCurrencyPairs()).containsOnly(EUR_USD); assertThat(test.getVolatilityIds(EUR_USD)).containsOnly(VOL_ID1); - assertThat(test.getVolatilityIds(GBP_USD)).isEmpty(); + assertThatIllegalArgumentException() + .isThrownBy(() -> test.getVolatilityIds(GBP_USD)); assertThat(test.requirements(EUR_USD)).isEqualTo(FunctionRequirements.builder().valueRequirements(VOL_ID1).build()); assertThat(test.requirements(ImmutableSet.of(EUR_USD))) @@ -72,7 +73,8 @@ public void test_of_map() { assertThat(test.queryType()).isEqualTo(FxOptionMarketDataLookup.class); assertThat(test.getVolatilityCurrencyPairs()).containsOnly(EUR_USD, GBP_USD); assertThat(test.getVolatilityIds(EUR_USD)).containsOnly(VOL_ID1); - assertThat(test.getVolatilityIds(EUR_GBP)).isEmpty(); + assertThatIllegalArgumentException() + .isThrownBy(() -> test.getVolatilityIds(EUR_GBP)); assertThat(test.requirements(EUR_USD)).isEqualTo(FunctionRequirements.builder().valueRequirements(VOL_ID1).build()); assertThat(test.requirements(ImmutableSet.of(EUR_USD))) From 8735326a07481f089f65ec2132bd3ed1e1c1b42d Mon Sep 17 00:00:00 2001 From: James White <118170713+James-OpenGamma@users.noreply.github.com> Date: Wed, 1 Nov 2023 16:06:22 +0000 Subject: [PATCH 044/116] QUANT-1213: Add OMIClear exchange id (#2610) Co-authored-by: James White --- .../java/com/opengamma/strata/product/common/ExchangeIds.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/product/src/main/java/com/opengamma/strata/product/common/ExchangeIds.java b/modules/product/src/main/java/com/opengamma/strata/product/common/ExchangeIds.java index 85c56b1df4..efda22d6f5 100644 --- a/modules/product/src/main/java/com/opengamma/strata/product/common/ExchangeIds.java +++ b/modules/product/src/main/java/com/opengamma/strata/product/common/ExchangeIds.java @@ -150,6 +150,9 @@ public final class ExchangeIds { /** Nasdaq Commodity Exchange. */ public static final ExchangeId NORX = ExchangeId.of("NORX"); + /** OMIClear Exchange. */ + public static final ExchangeId OMIC = ExchangeId.of("OMIC"); + //------------------------------------------------------------------------- /** * Restricted constructor. From 368816c3468f25dd2aff62d940010d4edd35a95c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 08:45:54 +0000 Subject: [PATCH 045/116] Bump org.junit:junit-bom from 5.9.3 to 5.10.1 (#2611) Bumps [org.junit:junit-bom](https://github.com/junit-team/junit5) from 5.9.3 to 5.10.1. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.9.3...r5.10.1) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pom.xml b/modules/pom.xml index c577e6a273..ce71933a8b 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -771,7 +771,7 @@ 2.2.3 2.10.0 ${joda-beans.version} - 5.9.3 + 5.10.1 4.9.0 1.7.36 From 5fdb7b9ae7f997471d1307a227ab5c28a15776f4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 6 Nov 2023 11:44:50 +0000 Subject: [PATCH 046/116] Bump com.google.guava:guava from 32.1.2-jre to 32.1.3-jre (#2607) Bumps [com.google.guava:guava](https://github.com/google/guava) from 32.1.2-jre to 32.1.3-jre. - [Release notes](https://github.com/google/guava/releases) - [Commits](https://github.com/google/guava/commits) --- updated-dependencies: - dependency-name: com.google.guava:guava dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pom.xml b/modules/pom.xml index ce71933a8b..0076f57b52 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -765,7 +765,7 @@ 9.5 3.24.2 1.6.Final - 32.1.2-jre + 32.1.3-jre 26.0-jre 1.78 2.2.3 From eb05ddc86bc16902e8f5c6eb175b5fec0d0ce0f1 Mon Sep 17 00:00:00 2001 From: Victor Patentasu Date: Tue, 14 Nov 2023 09:40:01 +0200 Subject: [PATCH 047/116] Add support for splitting contract specs and security IDs with hyphen ("-") in the contract code (#2612) * Add support for splitting contract spec ID when contract code has hyphen * Add support for splitting contract codes with hyphen in the name * Update javadoc comment * Add XNSE as exchange and test for option with hyphen --------- Co-authored-by: Victor Patentasu --- .../strata/product/common/ExchangeIds.java | 3 + .../strata/product/etd/EtdIdUtils.java | 70 +++++++++++++++---- .../strata/product/etd/EtdIdUtilsTest.java | 64 +++++++++++++++-- 3 files changed, 117 insertions(+), 20 deletions(-) diff --git a/modules/product/src/main/java/com/opengamma/strata/product/common/ExchangeIds.java b/modules/product/src/main/java/com/opengamma/strata/product/common/ExchangeIds.java index efda22d6f5..3b4a0329de 100644 --- a/modules/product/src/main/java/com/opengamma/strata/product/common/ExchangeIds.java +++ b/modules/product/src/main/java/com/opengamma/strata/product/common/ExchangeIds.java @@ -153,6 +153,9 @@ public final class ExchangeIds { /** OMIClear Exchange. */ public static final ExchangeId OMIC = ExchangeId.of("OMIC"); + /** National Stock Exchange Of India. */ + public static final ExchangeId XNSE = ExchangeId.of("XNSE"); + //------------------------------------------------------------------------- /** * Restricted constructor. diff --git a/modules/product/src/main/java/com/opengamma/strata/product/etd/EtdIdUtils.java b/modules/product/src/main/java/com/opengamma/strata/product/etd/EtdIdUtils.java index 5345f8ac78..d88b2cd103 100644 --- a/modules/product/src/main/java/com/opengamma/strata/product/etd/EtdIdUtils.java +++ b/modules/product/src/main/java/com/opengamma/strata/product/etd/EtdIdUtils.java @@ -14,10 +14,14 @@ import java.time.format.DateTimeFormatterBuilder; import java.util.List; import java.util.Locale; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import com.google.common.base.Splitter; +import com.opengamma.strata.basics.StandardId; import com.opengamma.strata.basics.StandardSchemes; import com.opengamma.strata.collect.ArgChecker; +import com.opengamma.strata.collect.Messages; import com.opengamma.strata.product.SecurityId; import com.opengamma.strata.product.common.ExchangeId; import com.opengamma.strata.product.common.PutCall; @@ -32,6 +36,21 @@ */ public final class EtdIdUtils { + /** + * Separator that is always present between the contract details and expiry + option details. + * Only applies to identifiers with {@link StandardSchemes#OG_ETD_SCHEME}. + *

    + * Example separator "-202304" in "F-IFEN-ABC-202304" or "O-IFEN-ABC-202304-PM12.34-U202309" + */ + private static final String GROUPS_SEPARATOR = "-(?=\\d{6})"; + private static final String CONTRACT_DETAILS_REGEX_GROUP_NAME = "contractDetails"; + private static final String EXPIRY_AND_OPTION_DETAILS_GROUP_NAME = "expiryAndOptionDetails"; + private static final Pattern SECURITY_ID_PATTERN = Pattern.compile(Messages.format( + "^(?<{}>.*){}(?<{}>.*)$", + CONTRACT_DETAILS_REGEX_GROUP_NAME, + GROUPS_SEPARATOR, + EXPIRY_AND_OPTION_DETAILS_GROUP_NAME)); + /** * Scheme used for ETDs. */ @@ -242,8 +261,13 @@ public static SplitEtdContractSpecId splitId(EtdContractSpecId specId) { if (!specId.getStandardId().getScheme().equals(ETD_SCHEME)) { throw new IllegalArgumentException("ETD ID cannot be parsed: " + specId); } - List split = Splitter.on('-').splitToList(specId.getStandardId().getValue()); - if (split.size() != 3) { + String value = specId.getStandardId().getValue(); + List split = Splitter.on('-') + // sometimes a contract code can have "-" in the name, like F-IFEN-BAJAJ-AUTO, so we need + // limit the split to 3: type, exchangeId, and contract code + .limit(3) + .splitToList(value); + if (split.size() < 3) { throw new IllegalArgumentException("ETD ID cannot be parsed: " + specId); } EtdType type = null; @@ -274,17 +298,31 @@ public static SplitEtdContractSpecId splitId(EtdContractSpecId specId) { */ public static SplitEtdId splitId(SecurityId securityId) { ArgChecker.notNull(securityId, "securityId"); - if (!securityId.getStandardId().getScheme().equals(ETD_SCHEME)) { + StandardId standardId = securityId.getStandardId(); + if (!standardId.getScheme().equals(ETD_SCHEME)) { throw new IllegalArgumentException("ETD ID cannot be parsed: " + securityId); } - List split = Splitter.on('-').splitToList(securityId.getStandardId().getValue()); - if (split.size() < 4) { + + Matcher matcher = SECURITY_ID_PATTERN.matcher(standardId.getValue()); + if (!matcher.matches()) { throw new IllegalArgumentException("ETD ID cannot be parsed: " + securityId); } + + // Example: F-IFEN-ABC or F-IFEN-ABC-XYZ + String contractDetailsSubstring = matcher.group(CONTRACT_DETAILS_REGEX_GROUP_NAME); + List contractDetailsSplit = Splitter.on('-').limit(3).splitToList(contractDetailsSubstring); + if (contractDetailsSplit.size() != 3) { + throw new IllegalArgumentException("ETD ID cannot be parsed: " + securityId); + } + // common fields - ExchangeId exchangeId = ExchangeId.of(split.get(1)); - EtdContractCode contractCode = EtdContractCode.of(split.get(2)); - String dateStr = split.get(3); + ExchangeId exchangeId = ExchangeId.of(contractDetailsSplit.get(1)); + EtdContractCode contractCode = EtdContractCode.of(contractDetailsSplit.get(2)); + + // Example: 20230412 for futures or 202304-V3-PM12.43-U202304 for options + String expiryAndOptionDetailsSubstring = matcher.group(EXPIRY_AND_OPTION_DETAILS_GROUP_NAME); + List expiryAndOptionDetailsSplit = Splitter.on("-").splitToList(expiryAndOptionDetailsSubstring); + String dateStr = expiryAndOptionDetailsSplit.get(0); if (dateStr.length() < 6) { throw new IllegalArgumentException("ETD ID cannot be parsed: " + securityId); } @@ -296,11 +334,13 @@ public static SplitEtdId splitId(SecurityId securityId) { .contractCode(contractCode) .expiry(month) .variant(variant); + // future vs option - if (securityId.getStandardId().getValue().startsWith(FUT_PREFIX) && split.size() == 4) { + if (standardId.getValue().startsWith(FUT_PREFIX) && expiryAndOptionDetailsSplit.size() == 1) { return parsed.build(); - } else if (securityId.getStandardId().getValue().startsWith(OPT_PREFIX) && split.size() > 4) { - SplitEtdOption parsedOption = parseEtdOptionId(split, securityId); + } else if (standardId.getValue().startsWith(OPT_PREFIX) && expiryAndOptionDetailsSplit.size() > 1) { + List optionDetailsSplit = expiryAndOptionDetailsSplit.subList(1, expiryAndOptionDetailsSplit.size()); + SplitEtdOption parsedOption = parseEtdOptionId(optionDetailsSplit, securityId); return parsed.option(parsedOption).build(); } else { throw new IllegalArgumentException("ETD ID cannot be parsed: " + securityId); @@ -308,10 +348,10 @@ public static SplitEtdId splitId(SecurityId securityId) { } // parses an option - private static SplitEtdOption parseEtdOptionId(List split, SecurityId securityId) { - String versionStr = split.get(4); - String putCallStrikeStr = split.size() > 5 ? split.get(5) : ""; - String underlyingMonthStr = split.size() > 6 ? split.get(6) : ""; + private static SplitEtdOption parseEtdOptionId(List optionDetailsSplit, SecurityId securityId) { + String versionStr = optionDetailsSplit.get(0); + String putCallStrikeStr = optionDetailsSplit.size() > 1 ? optionDetailsSplit.get(1) : ""; + String underlyingMonthStr = optionDetailsSplit.size() > 2 ? optionDetailsSplit.get(2) : ""; int version = 0; if (versionStr.startsWith("V")) { version = Integer.parseInt(versionStr.substring(1)); diff --git a/modules/product/src/test/java/com/opengamma/strata/product/etd/EtdIdUtilsTest.java b/modules/product/src/test/java/com/opengamma/strata/product/etd/EtdIdUtilsTest.java index dabe2612ca..72f4b04522 100644 --- a/modules/product/src/test/java/com/opengamma/strata/product/etd/EtdIdUtilsTest.java +++ b/modules/product/src/test/java/com/opengamma/strata/product/etd/EtdIdUtilsTest.java @@ -9,11 +9,9 @@ import static com.opengamma.strata.collect.TestHelper.coverPrivateConstructor; import static com.opengamma.strata.product.etd.EtdVariant.MONTHLY; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import java.time.YearMonth; -import java.time.format.DateTimeParseException; import org.junit.jupiter.api.Test; @@ -30,6 +28,7 @@ public class EtdIdUtilsTest { private static final YearMonth EXPIRY = YearMonth.of(2017, 6); private static final EtdContractCode OGBS = EtdContractCode.of("OGBS"); private static final EtdContractCode FGBS = EtdContractCode.of("FGBS"); + private static final EtdContractCode BAJAJ_AUTO = EtdContractCode.of("BAJAJ-AUTO"); @Test public void test_contractSpecId_future() { @@ -44,6 +43,19 @@ public void test_contractSpecId_future() { .build()); } + @Test + void test_contractSpecIdWithExtraHyphen_future() { + EtdContractSpecId test = EtdIdUtils.contractSpecId(EtdType.FUTURE, ExchangeIds.XNSE, BAJAJ_AUTO); + assertThat(test.getStandardId()).isEqualTo(StandardId.of(OG_ETD_SCHEME, "F-XNSE-BAJAJ-AUTO")); + assertThat(EtdIdUtils.splitId(test)) + .isEqualTo(SplitEtdContractSpecId.builder() + .specId(test) + .type(EtdType.FUTURE) + .exchangeId(ExchangeIds.XNSE) + .contractCode(BAJAJ_AUTO) + .build()); + } + @Test public void test_contractSpecId_option() { EtdContractSpecId test = EtdIdUtils.contractSpecId(EtdType.OPTION, ExchangeIds.ECAG, OGBS); @@ -57,6 +69,19 @@ public void test_contractSpecId_option() { .build()); } + @Test + void test_contractSpecIdWithExtraHyphen_option() { + EtdContractSpecId test = EtdIdUtils.contractSpecId(EtdType.OPTION, ExchangeIds.XNSE, BAJAJ_AUTO); + assertThat(test.getStandardId()).isEqualTo(StandardId.of(OG_ETD_SCHEME, "O-XNSE-BAJAJ-AUTO")); + assertThat(EtdIdUtils.splitId(test)) + .isEqualTo(SplitEtdContractSpecId.builder() + .specId(test) + .type(EtdType.OPTION) + .exchangeId(ExchangeIds.XNSE) + .contractCode(BAJAJ_AUTO) + .build()); + } + @Test public void test_contractSpecId_future_from_securityId() { EtdContractSpecId test = EtdIdUtils.contractSpecId(SecurityId.of(OG_ETD_SCHEME, "F-ECAG-FGBS-202305")); @@ -98,6 +123,20 @@ public void test_futureId_monthly() { .build()); } + @Test + public void test_futureIdWithExtraHyphen_monthly() { + SecurityId test = EtdIdUtils.futureId(ExchangeIds.XNSE, BAJAJ_AUTO, EXPIRY, MONTHLY); + assertThat(test.getStandardId()).isEqualTo(StandardId.of(OG_ETD_SCHEME, "F-XNSE-BAJAJ-AUTO-201706")); + assertThat(EtdIdUtils.splitId(test)) + .isEqualTo(SplitEtdId.builder() + .securityId(test) + .exchangeId(ExchangeIds.XNSE) + .contractCode(BAJAJ_AUTO) + .expiry(EXPIRY) + .variant(MONTHLY) + .build()); + } + @Test public void test_futureId_weekly() { EtdVariant variant = EtdVariant.ofWeekly(2); @@ -228,6 +267,23 @@ public void test_optionIdUnderlying_monthly() { .build()); } + @Test + public void test_optionIdUnderlyingWithHyphen_monthly() { + YearMonth underlyingMonth = YearMonth.of(2017, 9); + SecurityId test = EtdIdUtils.optionId( + ExchangeIds.XNSE, BAJAJ_AUTO, EXPIRY, MONTHLY, 0, PutCall.PUT, 12.34, underlyingMonth); + assertThat(test.getStandardId()).isEqualTo(StandardId.of(OG_ETD_SCHEME, "O-XNSE-BAJAJ-AUTO-201706-P12.34-U201709")); + assertThat(EtdIdUtils.splitId(test)) + .isEqualTo(SplitEtdId.builder() + .securityId(test) + .exchangeId(ExchangeIds.XNSE) + .contractCode(BAJAJ_AUTO) + .expiry(EXPIRY) + .variant(MONTHLY) + .option(SplitEtdOption.of(0, PutCall.PUT, 12.34, underlyingMonth)) + .build()); + } + @Test public void test_optionIdUnderlying_monthlySameMonth() { SecurityId test = EtdIdUtils.optionId( @@ -305,8 +361,6 @@ public void test_splitContractSpec() { .isThrownBy(() -> EtdIdUtils.splitId(EtdContractSpecId.of("A", "B"))); assertThatIllegalArgumentException() .isThrownBy(() -> EtdIdUtils.splitId(EtdContractSpecId.of(OG_ETD_SCHEME, "B"))); - assertThatIllegalArgumentException() - .isThrownBy(() -> EtdIdUtils.splitId(EtdContractSpecId.of(OG_ETD_SCHEME, "F-ECAG-AB-ABCDEF"))); } @Test @@ -315,7 +369,7 @@ public void test_split() { .isThrownBy(() -> EtdIdUtils.splitId(SecurityId.of("A", "B"))); assertThatIllegalArgumentException() .isThrownBy(() -> EtdIdUtils.splitId(SecurityId.of(OG_ETD_SCHEME, "B"))); - assertThatExceptionOfType(DateTimeParseException.class) + assertThatIllegalArgumentException() .isThrownBy(() -> EtdIdUtils.splitId(SecurityId.of(OG_ETD_SCHEME, "F-ECAG-AB-ABCDEF"))); assertThatIllegalArgumentException() .isThrownBy(() -> EtdIdUtils.splitId(SecurityId.of(OG_ETD_SCHEME, "F-ECAG-AB-20206"))); From cbabb0a506d9d20f7c692e5df6e2118b53ffc855 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Tue, 14 Nov 2023 12:29:25 +0000 Subject: [PATCH 048/116] [maven-release-plugin] prepare release v2.12.29 --- examples/pom.xml | 6 +++++- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 6a1ee2738b..8626f7e623 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.29-SNAPSHOT + 2.12.29 jar Strata-Examples Example code to demonstrate use of Strata @@ -272,4 +272,8 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> + + + v2.12.29 + diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index a3c5f6d38d..a020d704a4 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.29-SNAPSHOT + 2.12.29 .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index b9d18490b7..5831a4f558 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.29-SNAPSHOT + 2.12.29 .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index e7ce1cbdd5..0bf582f7c5 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.29-SNAPSHOT + 2.12.29 .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index a4676fdffb..0833f8c2ca 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.29-SNAPSHOT + 2.12.29 .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 34397be2ac..c5c4a11014 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.29-SNAPSHOT + 2.12.29 .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 331e802d4d..e1966f16a6 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.29-SNAPSHOT + 2.12.29 .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index ca28d78796..854efb6b07 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.29-SNAPSHOT + 2.12.29 .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 5e1a9834f5..56f15a4a21 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.29-SNAPSHOT + 2.12.29 .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 0076f57b52..6e1579b9f0 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.29-SNAPSHOT + 2.12.29 pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.29 diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 9e166caa8e..abbf7d21e5 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.29-SNAPSHOT + 2.12.29 .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 9e545a2b26..bcb9a7f982 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.29-SNAPSHOT + 2.12.29 .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 40bc0bbc31..b530b6a995 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.29-SNAPSHOT + 2.12.29 .. strata-report diff --git a/pom.xml b/pom.xml index a64c951135..e3f4e1906f 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.29-SNAPSHOT + 2.12.29 pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.29 From 7c367b33e37c5c80ee2f0c50f6702dbef003be0d Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Tue, 14 Nov 2023 12:29:26 +0000 Subject: [PATCH 049/116] [maven-release-plugin] prepare for next development iteration --- examples/pom.xml | 6 +----- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 8626f7e623..cea9c476e0 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.29 + 2.12.30-SNAPSHOT jar Strata-Examples Example code to demonstrate use of Strata @@ -272,8 +272,4 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> - - - v2.12.29 - diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index a020d704a4..6de2ee3960 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.29 + 2.12.30-SNAPSHOT .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 5831a4f558..08a63153f4 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.29 + 2.12.30-SNAPSHOT .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 0bf582f7c5..e19786266e 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.29 + 2.12.30-SNAPSHOT .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 0833f8c2ca..298dd3ee5b 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.29 + 2.12.30-SNAPSHOT .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index c5c4a11014..bbbd8e6987 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.29 + 2.12.30-SNAPSHOT .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index e1966f16a6..a4505398c6 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.29 + 2.12.30-SNAPSHOT .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 854efb6b07..6d2a908de4 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.29 + 2.12.30-SNAPSHOT .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 56f15a4a21..88bf103e2a 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.29 + 2.12.30-SNAPSHOT .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 6e1579b9f0..3b78d79194 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.29 + 2.12.30-SNAPSHOT pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.29 + HEAD diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index abbf7d21e5..7abdf46eb0 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.29 + 2.12.30-SNAPSHOT .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index bcb9a7f982..06ee3d9cf5 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.29 + 2.12.30-SNAPSHOT .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index b530b6a995..3069e1ef2c 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.29 + 2.12.30-SNAPSHOT .. strata-report diff --git a/pom.xml b/pom.xml index e3f4e1906f..1b93b9900f 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.29 + 2.12.30-SNAPSHOT pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.29 + HEAD From c08bf4cf9c8f131bf6cd0e9638b8f898192363e2 Mon Sep 17 00:00:00 2001 From: Yuki Iwashita Date: Wed, 15 Nov 2023 18:56:21 +0900 Subject: [PATCH 050/116] Hitting Barrier in BlackFxSingleBarrierOptionProductPricer (#2613) --- ...ackFxSingleBarrierOptionProductPricer.java | 221 ++++++++++++++++-- ...xSingleBarrierOptionProductPricerTest.java | 168 +++++++++++++ 2 files changed, 374 insertions(+), 15 deletions(-) diff --git a/modules/pricer/src/main/java/com/opengamma/strata/pricer/fxopt/BlackFxSingleBarrierOptionProductPricer.java b/modules/pricer/src/main/java/com/opengamma/strata/pricer/fxopt/BlackFxSingleBarrierOptionProductPricer.java index 9fd6698a0b..fc94b45e6b 100644 --- a/modules/pricer/src/main/java/com/opengamma/strata/pricer/fxopt/BlackFxSingleBarrierOptionProductPricer.java +++ b/modules/pricer/src/main/java/com/opengamma/strata/pricer/fxopt/BlackFxSingleBarrierOptionProductPricer.java @@ -8,18 +8,25 @@ import java.time.LocalDate; import java.time.ZonedDateTime; +import com.opengamma.strata.basics.ReferenceData; import com.opengamma.strata.basics.currency.Currency; import com.opengamma.strata.basics.currency.CurrencyAmount; import com.opengamma.strata.basics.currency.CurrencyPair; import com.opengamma.strata.basics.currency.FxRate; import com.opengamma.strata.basics.currency.MultiCurrencyAmount; +import com.opengamma.strata.basics.date.DaysAdjustment; +import com.opengamma.strata.basics.date.HolidayCalendarId; +import com.opengamma.strata.basics.date.HolidayCalendarIds; +import com.opengamma.strata.basics.index.FxIndex; import com.opengamma.strata.basics.value.ValueDerivatives; import com.opengamma.strata.collect.ArgChecker; import com.opengamma.strata.collect.array.DoubleArray; +import com.opengamma.strata.market.sensitivity.PointSensitivities; import com.opengamma.strata.market.sensitivity.PointSensitivityBuilder; import com.opengamma.strata.pricer.DiscountFactors; import com.opengamma.strata.pricer.ZeroRateSensitivity; import com.opengamma.strata.pricer.impl.option.BlackBarrierPriceFormulaRepository; +import com.opengamma.strata.pricer.impl.option.BlackFormulaRepository; import com.opengamma.strata.pricer.impl.option.BlackOneTouchAssetPriceFormulaRepository; import com.opengamma.strata.pricer.impl.option.BlackOneTouchCashPriceFormulaRepository; import com.opengamma.strata.pricer.rate.RatesProvider; @@ -33,7 +40,7 @@ *

    * This function provides the ability to price an {@link ResolvedFxSingleBarrierOption}. *

    - * All of the computation is be based on the counter currency of the underlying FX transaction. + * All the computation is based on the counter currency of the underlying FX transaction. * For example, price, PV and risk measures of the product will be expressed in USD for an option on EUR/USD. */ public class BlackFxSingleBarrierOptionProductPricer { @@ -57,6 +64,11 @@ public class BlackFxSingleBarrierOptionProductPricer { */ private static final BlackOneTouchCashPriceFormulaRepository CASH_REBATE_PRICER = new BlackOneTouchCashPriceFormulaRepository(); + /** + * Pricer for underlying vanilla option. + */ + private static final BlackFxVanillaOptionProductPricer VANILLA_OPTION_PRICER = + BlackFxVanillaOptionProductPricer.DEFAULT; /** * Creates an instance. @@ -110,26 +122,38 @@ public double price( validate(option, ratesProvider, volatilities); SimpleConstantContinuousBarrier barrier = (SimpleConstantContinuousBarrier) option.getBarrier(); ResolvedFxVanillaOption underlyingOption = option.getUnderlyingOption(); - if (volatilities.relativeTime(underlyingOption.getExpiry()) < 0d) { + double timeToExpiry = volatilities.relativeTime(underlyingOption.getExpiry()); + if (timeToExpiry < 0d) { return 0d; } ResolvedFxSingle underlyingFx = underlyingOption.getUnderlying(); + CurrencyPair currencyPair = underlyingFx.getCurrencyPair(); + double todayFx = ratesProvider.fxRate(currencyPair); Currency ccyBase = underlyingFx.getBaseCurrencyPayment().getCurrency(); Currency ccyCounter = underlyingFx.getCounterCurrencyPayment().getCurrency(); - CurrencyPair currencyPair = underlyingFx.getCurrencyPair(); + if (alreadyTouched(todayFx, barrier)) { + if (barrier.getKnockType().isKnockIn()) { + return VANILLA_OPTION_PRICER.price(underlyingOption, ratesProvider, volatilities); + } else if (option.getRebate().isPresent()) { + CurrencyAmount rebate = option.getRebate().get(); + DaysAdjustment spotLag = spotAdjustment(currencyPair); + LocalDate paymentDate = spotLag.adjust(ratesProvider.getValuationDate(), ReferenceData.standard()); + double rebatePrice = rebate.getAmount() * ratesProvider.discountFactor(rebate.getCurrency(), paymentDate) / + Math.abs(underlyingFx.getBaseCurrencyPayment().getAmount()); + return rebate.getCurrency().equals(ccyCounter) ? rebatePrice : todayFx * rebatePrice; + } + return 0d; + } DiscountFactors baseDiscountFactors = ratesProvider.discountFactors(ccyBase); DiscountFactors counterDiscountFactors = ratesProvider.discountFactors(ccyCounter); - double rateBase = baseDiscountFactors.zeroRate(underlyingFx.getPaymentDate()); double rateCounter = counterDiscountFactors.zeroRate(underlyingFx.getPaymentDate()); double costOfCarry = rateCounter - rateBase; double dfBase = baseDiscountFactors.discountFactor(underlyingFx.getPaymentDate()); double dfCounter = counterDiscountFactors.discountFactor(underlyingFx.getPaymentDate()); - double todayFx = ratesProvider.fxRate(currencyPair); double strike = underlyingOption.getStrike(); double forward = todayFx * dfBase / dfCounter; double volatility = volatilities.volatility(currencyPair, underlyingOption.getExpiry(), strike, forward); - double timeToExpiry = volatilities.relativeTime(underlyingOption.getExpiry()); double price = BARRIER_PRICER.price( todayFx, strike, timeToExpiry, costOfCarry, rateCounter, volatility, underlyingOption.getPutCall().isCall(), barrier); if (option.getRebate().isPresent()) { @@ -162,12 +186,33 @@ public PointSensitivityBuilder presentValueSensitivityRatesStickyStrike( BlackFxOptionVolatilities volatilities) { ResolvedFxVanillaOption underlyingOption = option.getUnderlyingOption(); - if (volatilities.relativeTime(underlyingOption.getExpiry()) <= 0d) { + double timeToExpiry = volatilities.relativeTime(underlyingOption.getExpiry()); + if (timeToExpiry <= 0d) { return PointSensitivityBuilder.none(); } - ValueDerivatives priceDerivatives = priceDerivatives(option, ratesProvider, volatilities); + SimpleConstantContinuousBarrier barrier = (SimpleConstantContinuousBarrier) option.getBarrier(); ResolvedFxSingle underlyingFx = underlyingOption.getUnderlying(); CurrencyPair currencyPair = underlyingFx.getCurrencyPair(); + double todayFx = ratesProvider.fxRate(currencyPair); + if (alreadyTouched(todayFx, barrier)) { + if (barrier.getKnockType().isKnockIn()) { + PointSensitivities underlyingOptionSensitivity = VANILLA_OPTION_PRICER.presentValueSensitivityRatesStickyStrike( + option.getUnderlyingOption(), ratesProvider, volatilities); + return PointSensitivityBuilder.of(underlyingOptionSensitivity.getSensitivities()); + } else if (option.getRebate().isPresent()) { + CurrencyAmount rebate = option.getRebate().get(); + DaysAdjustment spotLag = spotAdjustment(currencyPair); + LocalDate paymentDate = spotLag.adjust(ratesProvider.getValuationDate(), ReferenceData.standard()); + ZeroRateSensitivity rebaseSensitivity = ratesProvider.discountFactors(rebate.getCurrency()) + .zeroRatePointSensitivity(paymentDate); + Currency ccyCounter = underlyingFx.getCounterCurrencyPayment().getCurrency(); + return rebate.getCurrency().equals(ccyCounter) ? + rebaseSensitivity.multipliedBy(rebate.getAmount()) : + rebaseSensitivity.multipliedBy(rebate.getAmount() * todayFx).withCurrency(ccyCounter); + } + return PointSensitivityBuilder.none(); + } + ValueDerivatives priceDerivatives = priceDerivatives(option, ratesProvider, volatilities); double signedNotional = signedNotional(underlyingOption); double counterYearFraction = ratesProvider.discountFactors(currencyPair.getCounter()).relativeYearFraction(underlyingFx.getPaymentDate()); @@ -221,7 +266,27 @@ public double delta( RatesProvider ratesProvider, BlackFxOptionVolatilities volatilities) { - if (volatilities.relativeTime(option.getUnderlyingOption().getExpiry()) < 0d) { + ResolvedFxVanillaOption underlyingOption = option.getUnderlyingOption(); + if (volatilities.relativeTime(underlyingOption.getExpiry()) < 0d) { + return 0d; + } + SimpleConstantContinuousBarrier barrier = (SimpleConstantContinuousBarrier) option.getBarrier(); + ResolvedFxSingle underlyingFx = underlyingOption.getUnderlying(); + CurrencyPair currencyPair = underlyingFx.getCurrencyPair(); + double todayFx = ratesProvider.fxRate(currencyPair); + if (alreadyTouched(todayFx, barrier)) { + if (barrier.getKnockType().isKnockIn()) { + return VANILLA_OPTION_PRICER.delta(underlyingOption, ratesProvider, volatilities); + } else if (option.getRebate().isPresent()) { + Currency ccyCounter = underlyingFx.getCounterCurrencyPayment().getCurrency(); + CurrencyAmount rebate = option.getRebate().get(); + if (!rebate.getCurrency().equals(ccyCounter)) { + DaysAdjustment spotLag = spotAdjustment(currencyPair); + LocalDate paymentDate = spotLag.adjust(ratesProvider.getValuationDate(), ReferenceData.standard()); + return rebate.getAmount() * ratesProvider.discountFactor(rebate.getCurrency(), paymentDate) / + Math.abs(underlyingFx.getBaseCurrencyPayment().getAmount()); + } + } return 0d; } ValueDerivatives priceDerivatives = priceDerivatives(option, ratesProvider, volatilities); @@ -264,6 +329,20 @@ public double gamma( RatesProvider ratesProvider, BlackFxOptionVolatilities volatilities) { + ResolvedFxVanillaOption underlyingOption = option.getUnderlyingOption(); + if (volatilities.relativeTime(underlyingOption.getExpiry()) <= 0d) { + return 0d; + } + SimpleConstantContinuousBarrier barrier = (SimpleConstantContinuousBarrier) option.getBarrier(); + ResolvedFxSingle underlyingFx = underlyingOption.getUnderlying(); + CurrencyPair currencyPair = underlyingFx.getCurrencyPair(); + double todayFx = ratesProvider.fxRate(currencyPair); + if (alreadyTouched(todayFx, barrier)) { + if (barrier.getKnockType().isKnockIn()) { + return VANILLA_OPTION_PRICER.gamma(underlyingOption, ratesProvider, volatilities); + } + return 0d; + } ValueDerivatives priceDerivatives = priceDerivatives(option, ratesProvider, volatilities); return priceDerivatives.getDerivative(6); } @@ -285,22 +364,31 @@ public PointSensitivityBuilder presentValueSensitivityModelParamsVolatility( BlackFxOptionVolatilities volatilities) { ResolvedFxVanillaOption underlyingOption = option.getUnderlyingOption(); - if (volatilities.relativeTime(underlyingOption.getExpiry()) <= 0d) { + double timeToExpiry = volatilities.relativeTime(underlyingOption.getExpiry()); + if (timeToExpiry <= 0d) { return PointSensitivityBuilder.none(); } - ValueDerivatives priceDerivatives = priceDerivatives(option, ratesProvider, volatilities); + SimpleConstantContinuousBarrier barrier = (SimpleConstantContinuousBarrier) option.getBarrier(); ResolvedFxSingle underlyingFx = underlyingOption.getUnderlying(); CurrencyPair currencyPair = underlyingFx.getCurrencyPair(); + double todayFx = ratesProvider.fxRate(currencyPair); + if (alreadyTouched(todayFx, barrier)) { + if (barrier.getKnockType().isKnockIn()) { + return VANILLA_OPTION_PRICER.presentValueSensitivityModelParamsVolatility( + option.getUnderlyingOption(), ratesProvider, volatilities); + } + return PointSensitivityBuilder.none(); + } + ValueDerivatives priceDerivatives = priceDerivatives(option, ratesProvider, volatilities); Currency ccyBase = currencyPair.getBase(); Currency ccyCounter = currencyPair.getCounter(); double dfBase = ratesProvider.discountFactor(ccyBase, underlyingFx.getPaymentDate()); double dfCounter = ratesProvider.discountFactor(ccyCounter, underlyingFx.getPaymentDate()); - double todayFx = ratesProvider.fxRate(currencyPair); double forward = todayFx * dfBase / dfCounter; return FxOptionSensitivity.of( volatilities.getName(), currencyPair, - volatilities.relativeTime(underlyingOption.getExpiry()), + timeToExpiry, underlyingOption.getStrike(), forward, ccyCounter, @@ -322,6 +410,20 @@ public double vega( RatesProvider ratesProvider, BlackFxOptionVolatilities volatilities) { + ResolvedFxVanillaOption underlyingOption = option.getUnderlyingOption(); + if (volatilities.relativeTime(underlyingOption.getExpiry()) <= 0d) { + return 0d; + } + SimpleConstantContinuousBarrier barrier = (SimpleConstantContinuousBarrier) option.getBarrier(); + ResolvedFxSingle underlyingFx = underlyingOption.getUnderlying(); + CurrencyPair currencyPair = underlyingFx.getCurrencyPair(); + double todayFx = ratesProvider.fxRate(currencyPair); + if (alreadyTouched(todayFx, barrier)) { + if (barrier.getKnockType().isKnockIn()) { + return VANILLA_OPTION_PRICER.vega(underlyingOption, ratesProvider, volatilities); + } + return 0d; + } ValueDerivatives priceDerivatives = priceDerivatives(option, ratesProvider, volatilities); return priceDerivatives.getDerivative(4); } @@ -362,6 +464,46 @@ public double theta( RatesProvider ratesProvider, BlackFxOptionVolatilities volatilities) { + ResolvedFxVanillaOption underlyingOption = option.getUnderlyingOption(); + double timeToExpiry = volatilities.relativeTime(underlyingOption.getExpiry()); + if (timeToExpiry <= 0d) { + return 0d; + } + SimpleConstantContinuousBarrier barrier = (SimpleConstantContinuousBarrier) option.getBarrier(); + ResolvedFxSingle underlyingFx = underlyingOption.getUnderlying(); + CurrencyPair currencyPair = underlyingFx.getCurrencyPair(); + double todayFx = ratesProvider.fxRate(currencyPair); + if (alreadyTouched(todayFx, barrier)) { + if (barrier.getKnockType().isKnockIn()) { + Currency ccyBase = underlyingFx.getBaseCurrencyPayment().getCurrency(); + Currency ccyCounter = underlyingFx.getCounterCurrencyPayment().getCurrency(); + DiscountFactors baseDiscountFactors = ratesProvider.discountFactors(ccyBase); + DiscountFactors counterDiscountFactors = ratesProvider.discountFactors(ccyCounter); + double rateBase = baseDiscountFactors.zeroRate(underlyingFx.getPaymentDate()); + double rateCounter = counterDiscountFactors.zeroRate(underlyingFx.getPaymentDate()); + double costOfCarry = rateCounter - rateBase; + double dfBase = baseDiscountFactors.discountFactor(underlyingFx.getPaymentDate()); + double dfCounter = counterDiscountFactors.discountFactor(underlyingFx.getPaymentDate()); + double strike = underlyingOption.getStrike(); + double forward = todayFx * dfBase / dfCounter; + double volatility = volatilities.volatility(currencyPair, timeToExpiry, strike, forward); + boolean isCall = underlyingOption.getPutCall().isCall(); + double fwdPrice = BlackFormulaRepository.price(forward, strike, timeToExpiry, volatility, isCall); + double fwdTheta = BlackFormulaRepository.driftlessTheta(forward, strike, timeToExpiry, volatility); + double fwdDelta = BlackFormulaRepository.delta(forward, strike, timeToExpiry, volatility, isCall); + return dfCounter * (fwdTheta + rateCounter * fwdPrice - costOfCarry * forward * fwdDelta); + } else if (option.getRebate().isPresent()) { + CurrencyAmount rebate = option.getRebate().get(); + Currency ccyCounter = underlyingFx.getCounterCurrencyPayment().getCurrency(); + DaysAdjustment spotLag = spotAdjustment(currencyPair); + LocalDate paymentDate = spotLag.adjust(ratesProvider.getValuationDate(), ReferenceData.standard()); + DiscountFactors discountFactors = ratesProvider.discountFactors(rebate.getCurrency()); + double rebateTheta = discountFactors.zeroRate(paymentDate) * rebate.getAmount() * + discountFactors.discountFactor(paymentDate) / Math.abs(underlyingFx.getBaseCurrencyPayment().getAmount()); + return rebate.getCurrency().equals(ccyCounter) ? rebateTheta : todayFx * rebateTheta; + } + return 0d; + } ValueDerivatives priceDerivatives = priceDerivatives(option, ratesProvider, volatilities); return -priceDerivatives.getDerivative(5); } @@ -425,11 +567,28 @@ public MultiCurrencyAmount currencyExposure( if (volatilities.relativeTime(underlyingOption.getExpiry()) < 0d) { return MultiCurrencyAmount.empty(); } + SimpleConstantContinuousBarrier barrier = (SimpleConstantContinuousBarrier) option.getBarrier(); + ResolvedFxSingle underlyingFx = underlyingOption.getUnderlying(); + CurrencyPair currencyPair = underlyingFx.getCurrencyPair(); + double todayFx = ratesProvider.fxRate(currencyPair); + if (alreadyTouched(todayFx, barrier)) { + if (barrier.getKnockType().isKnockIn()) { + return VANILLA_OPTION_PRICER.currencyExposure(underlyingOption, ratesProvider, volatilities); + } else if (option.getRebate().isPresent()) { + CurrencyAmount rebate = option.getRebate().get(); + DaysAdjustment spotLag = spotAdjustment(currencyPair); + LocalDate paymentDate = spotLag.adjust(ratesProvider.getValuationDate(), ReferenceData.standard()); + double pv = (option.getUnderlyingOption().getLongShort().isLong() ? 1d : -1d) * rebate.getAmount() * + ratesProvider.discountFactor(rebate.getCurrency(), paymentDate); + Currency ccyCounter = underlyingFx.getCounterCurrencyPayment().getCurrency(); + double ceAmount = rebate.getCurrency().equals(ccyCounter) ? pv : todayFx * pv; + return MultiCurrencyAmount.of(ccyCounter, ceAmount); + } + return MultiCurrencyAmount.empty(); + } ValueDerivatives priceDerivatives = priceDerivatives(option, ratesProvider, volatilities); double price = priceDerivatives.getValue(); double delta = priceDerivatives.getDerivative(0); - CurrencyPair currencyPair = underlyingOption.getUnderlying().getCurrencyPair(); - double todayFx = ratesProvider.fxRate(currencyPair); double signedNotional = signedNotional(underlyingOption); CurrencyAmount domestic = CurrencyAmount.of(currencyPair.getCounter(), (price - delta * todayFx) * signedNotional); CurrencyAmount foreign = CurrencyAmount.of(currencyPair.getBase(), delta * signedNotional); @@ -486,6 +645,31 @@ private ValueDerivatives priceDerivatives( return ValueDerivatives.of(price, DoubleArray.ofUnsafe(derivatives)); } + //------------------------------------------------------------------------- + // calculate spot lag for rebate + private DaysAdjustment spotAdjustment(CurrencyPair currencyPair) { + return FxIndex.extendedEnum().lookupAll().values().stream() + .filter(index -> index.getCurrencyPair().equals(currencyPair)) + .findFirst() + .map(FxIndex::getFixingDateOffset) + .map(adjustment -> adjustment.toBuilder().days(-adjustment.getDays()).build()) + .orElseGet(() -> DaysAdjustment.ofBusinessDays(2, calendarForPair(currencyPair))); + } + + private HolidayCalendarId calendarForPair(CurrencyPair pair) { + return pair.toSet().stream() + .map(currency -> defaultByCurrencyOrNoHolidays(currency)) + .reduce(HolidayCalendarIds.NO_HOLIDAYS, HolidayCalendarId::combinedWith); + } + + private HolidayCalendarId defaultByCurrencyOrNoHolidays(Currency currency) { + try { + return HolidayCalendarId.defaultByCurrency(currency); + } catch (IllegalArgumentException e) { + return HolidayCalendarIds.NO_HOLIDAYS; + } + } + //------------------------------------------------------------------------- private void validate(ResolvedFxSingleBarrierOption option, RatesProvider ratesProvider, @@ -503,4 +687,11 @@ private double signedNotional(ResolvedFxVanillaOption option) { Math.abs(option.getUnderlying().getBaseCurrencyPayment().getAmount()); } + private boolean alreadyTouched(double fxRate, SimpleConstantContinuousBarrier barrier) { + if (barrier.getBarrierType().isDown()) { + return fxRate <= barrier.getBarrierLevel(); + } + return fxRate >= barrier.getBarrierLevel(); + } + } diff --git a/modules/pricer/src/test/java/com/opengamma/strata/pricer/fxopt/BlackFxSingleBarrierOptionProductPricerTest.java b/modules/pricer/src/test/java/com/opengamma/strata/pricer/fxopt/BlackFxSingleBarrierOptionProductPricerTest.java index 66e3fc85d1..64c727ca7f 100644 --- a/modules/pricer/src/test/java/com/opengamma/strata/pricer/fxopt/BlackFxSingleBarrierOptionProductPricerTest.java +++ b/modules/pricer/src/test/java/com/opengamma/strata/pricer/fxopt/BlackFxSingleBarrierOptionProductPricerTest.java @@ -16,10 +16,13 @@ import java.time.LocalDate; import java.time.ZoneId; import java.time.ZonedDateTime; +import java.util.Optional; +import org.assertj.core.data.Offset; import org.junit.jupiter.api.Test; import com.google.common.math.DoubleMath; +import com.opengamma.strata.basics.currency.Currency; import com.opengamma.strata.basics.currency.CurrencyAmount; import com.opengamma.strata.basics.currency.CurrencyPair; import com.opengamma.strata.basics.currency.FxMatrix; @@ -824,4 +827,169 @@ public void regression_currencyExposure() { assertThat(pvPutBase.getAmount(USD).getAmount()).isCloseTo(35358.56586522361, offset(NOTIONAL * TOL)); } + //------------------------------------------------------------------------- + @Test + public void test_continuity_at_barrier() { + double eps = 1e-5; + for (ResolvedFxSingleBarrierOption option : OPTION_ALL) { + double barrier = option.getBarrier().getBarrierLevel(VAL_DATE); + double rateUp = barrier + eps; + double rateDw = barrier - eps; + ImmutableRatesProvider providerUp = ratesProviderWithFxRate(option, RATE_PROVIDER, rateUp); + ImmutableRatesProvider providerDw = ratesProviderWithFxRate(option, RATE_PROVIDER, rateDw); + double priceUp = PRICER.price(option, providerUp, VOLS); + double priceDw = PRICER.price(option, providerDw, VOLS); + double pvUp = PRICER.presentValue(option, providerUp, VOLS).getAmount(); + double pvDw = PRICER.presentValue(option, providerDw, VOLS).getAmount(); + assertThat(priceUp).isCloseTo(priceDw, Offset.strictOffset(eps * 10d)); + double referenceAmount = option.getUnderlyingOption().getUnderlying().getReceiveCurrencyAmount().getAmount(); + assertThat(pvUp).isCloseTo(pvDw, Offset.strictOffset(eps * referenceAmount * 10d)); + } + } + + @Test + public void test_delta_gamma_touched() { + for (ResolvedFxSingleBarrierOption option : OPTION_ALL) { + double barrier = option.getBarrier().getBarrierLevel(VAL_DATE); + double fxRateTouched = option.getBarrier().getBarrierType().isDown() ? barrier * 0.9 : barrier * 1.1; + ImmutableRatesProvider ratesProviderTouched = ratesProviderWithFxRate(option, RATE_PROVIDER, fxRateTouched); + double rateUp = fxRateTouched + FD_EPS; + double rateDw = fxRateTouched - FD_EPS; + ImmutableRatesProvider providerUp = ratesProviderWithFxRate(option, RATE_PROVIDER, rateUp); + ImmutableRatesProvider providerDw = ratesProviderWithFxRate(option, RATE_PROVIDER, rateDw); + double deltaComputed = PRICER.delta(option, ratesProviderTouched, VOLS_FLAT); + double gammaComputed = PRICER.gamma(option, ratesProviderTouched, VOLS_FLAT); + double priceUp = PRICER.price(option, providerUp, VOLS_FLAT); + double priceDw = PRICER.price(option, providerDw, VOLS_FLAT); + double deltaExpected = 0.5 * (priceUp - priceDw) / FD_EPS; + assertThat(deltaComputed).isCloseTo(deltaExpected, Offset.strictOffset(FD_EPS * 10d)); + double deltaUp = PRICER.delta(option, providerUp, VOLS_FLAT); + double deltaDw = PRICER.delta(option, providerDw, VOLS_FLAT); + double gammaExpected = 0.5 * (deltaUp - deltaDw) / FD_EPS; + assertThat(gammaComputed).isCloseTo(gammaExpected, Offset.strictOffset(FD_EPS * 10d)); + } + } + + @Test + public void test_theta_touched() { + for (ResolvedFxSingleBarrierOption option : OPTION_ALL) { + double barrier = option.getBarrier().getBarrierLevel(VAL_DATE); + double fxRateTouched = option.getBarrier().getBarrierType().isDown() ? barrier * 0.9 : barrier * 1.1; + ImmutableRatesProvider ratesProviderTouched = ratesProviderWithFxRate( + option, + RatesProviderFxDataSets.createProviderEurUsdFlat(VAL_DATE), + fxRateTouched); + ImmutableRatesProvider providerUp = ratesProviderWithFxRate( + option, + RatesProviderFxDataSets.createProviderEurUsdFlat(VAL_DATE.plusDays(1)), + fxRateTouched); + ImmutableRatesProvider providerDw = ratesProviderWithFxRate( + option, + RatesProviderFxDataSets.createProviderEurUsdFlat(VAL_DATE.minusDays(1)), + fxRateTouched); + BlackFxOptionSmileVolatilities volsUp = FxVolatilitySmileDataSet.createVolatilitySmileProvider5Flat( + VAL_DATETIME.plusDays(1)); + BlackFxOptionSmileVolatilities volsDw = FxVolatilitySmileDataSet.createVolatilitySmileProvider5Flat( + VAL_DATETIME.minusDays(1)); + double thetaComputed = PRICER.theta(option, ratesProviderTouched, VOLS_FLAT); + double priceUp = PRICER.price(option, providerUp, volsUp); + double priceDw = PRICER.price(option, providerDw, volsDw); + double thetaExpected = 0.5 * (priceUp - priceDw) * 365d; + assertThat(thetaComputed).isCloseTo(thetaExpected, Offset.strictOffset(0.1 / 365d)); + } + } + + @Test + public void test_presentValueSensitivityRatesStickyStrike_touched() { + for (ResolvedFxSingleBarrierOption option : OPTION_ALL) { + double barrier = option.getBarrier().getBarrierLevel(VAL_DATE); + double fxRateTouched = option.getBarrier().getBarrierType().isDown() ? barrier * 0.9 : barrier * 1.1; + ImmutableRatesProvider ratesProviderTouched = ratesProviderWithFxRate(option, RATE_PROVIDER, fxRateTouched); + PointSensitivityBuilder point = PRICER.presentValueSensitivityRatesStickyStrike( + option, ratesProviderTouched, VOLS_FLAT); + CurrencyParameterSensitivities computed = ratesProviderTouched.parameterSensitivity(point.build()); + CurrencyParameterSensitivities expected = FD_CAL.sensitivity( + ratesProviderTouched, p -> PRICER.presentValue(option, p, VOLS_FLAT)); + double referenceAmount = option.getUnderlyingOption().getUnderlying().getReceiveCurrencyAmount().getAmount(); + assertThat(computed.equalWithTolerance(expected, referenceAmount * FD_EPS * 10d)).isTrue(); + } + } + + @Test + public void test_presentValueSensitivityModelParamsVolatility_touched() { + for (ResolvedFxSingleBarrierOption option : OPTION_ALL) { + double barrier = option.getBarrier().getBarrierLevel(VAL_DATE); + double fxRateTouched = option.getBarrier().getBarrierType().isDown() ? barrier * 0.9 : barrier * 1.1; + ImmutableRatesProvider ratesProviderTouched = ratesProviderWithFxRate(option, RATE_PROVIDER, fxRateTouched); + PointSensitivityBuilder points = PRICER.presentValueSensitivityModelParamsVolatility( + option, ratesProviderTouched, VOLS_FLAT); + CurrencyParameterSensitivities computed = VOLS_FLAT.parameterSensitivity(points.build()); + double referenceAmount = option.getUnderlyingOption().getUnderlying().getReceiveCurrencyAmount().getAmount(); + Optional optSensi = computed.findSensitivity( + VOLS_FLAT.getName(), option.getUnderlyingOption().getCurrencyPair().getCounter()); + double totalComputed = optSensi.isPresent() ? optSensi.get().getSensitivity().sum() : 0d; + BlackFxOptionSmileVolatilities volsUp = VOLS_FLAT.withPerturbation((index, vol, metadata) -> vol + FD_EPS); + BlackFxOptionSmileVolatilities volsDw = VOLS_FLAT.withPerturbation((index, vol, metadata) -> vol - FD_EPS); + CurrencyAmount pvUp = PRICER.presentValue(option, ratesProviderTouched, volsUp); + CurrencyAmount pvDw = PRICER.presentValue(option, ratesProviderTouched, volsDw); + double totalExpected = 0.5 * (pvUp.getAmount() - pvDw.getAmount()) / FD_EPS; + assertThat(totalComputed).isCloseTo( + totalExpected, Offset.strictOffset(referenceAmount * FD_EPS)); + double signedNotional = (option.getUnderlyingOption().getLongShort().isLong() ? 1d : -1d) * + Math.abs(option.getUnderlyingOption().getUnderlying().getBaseCurrencyPayment().getAmount()); + double vegaComputed = PRICER.vega(option, ratesProviderTouched, VOLS_FLAT); + assertThat(vegaComputed).isCloseTo(totalComputed / signedNotional, Offset.strictOffset(TOL)); + } + } + + @Test + public void test_currencyExposure_touched() { + Currency foreignCurrency = Currency.GBP; + double eurGbpStart = 0.80; + for (ResolvedFxSingleBarrierOption option : OPTION_ALL) { + double barrier = option.getBarrier().getBarrierLevel(VAL_DATE); + CurrencyPair currencyPair = option.getCurrencyPair(); + double spotTouched = option.getBarrier().getBarrierType().isDown() ? barrier * 0.9 : barrier * 1.1; + double spot = currencyPair.getBase().equals(EUR) ? spotTouched : 1d / spotTouched; + ImmutableRatesProvider ratesProvider = ratesProviderWithFxRate(option, RATE_PROVIDER, spot); + FxMatrix fxMatrixStart = FxMatrix.builder().addRate(EUR, USD, spot) + .addRate(EUR, foreignCurrency, eurGbpStart).build(); + FxMatrix fxMatrixEurGbpUp = fxMatrixStart.toBuilder() + .addRate(USD, EUR, 1.0d / spot + FD_EPS).build(); // EUR updated + ImmutableRatesProvider rateProvideEurGbpUp = ratesProvider.toImmutableRatesProvider().toBuilder() + .fxRateProvider(fxMatrixEurGbpUp).build(); + FxMatrix fxMatrixGbpUsdUp = fxMatrixStart.toBuilder() + .addRate(EUR, USD, spot + FD_EPS).build(); // USD updated + ImmutableRatesProvider rateProvideGbpUsdUp = ratesProvider.toImmutableRatesProvider().toBuilder() + .fxRateProvider(fxMatrixGbpUsdUp).build(); + double referenceAmount = option.getUnderlyingOption().getUnderlying().getReceiveCurrencyAmount().getAmount(); + Offset offset = Offset.strictOffset(referenceAmount * FD_EPS); + CurrencyAmount pv = PRICER.presentValue(option, ratesProvider, VOLS_FLAT); + MultiCurrencyAmount ce = PRICER.currencyExposure(option, ratesProvider, VOLS_FLAT); + assertThat(pv.convertedTo(foreignCurrency, fxMatrixStart).getAmount()) + .isCloseTo(ce.convertedTo(foreignCurrency, fxMatrixStart).getAmount(), offset); + CurrencyAmount pvEurGbpUp = PRICER.presentValue(option, rateProvideEurGbpUp, VOLS_FLAT); + CurrencyAmount plPvEurGbpUp = pvEurGbpUp.convertedTo(foreignCurrency, fxMatrixEurGbpUp) + .minus(pv.convertedTo(foreignCurrency, fxMatrixStart)); + CurrencyAmount plCeEurGbpUp = ce.convertedTo(foreignCurrency, fxMatrixEurGbpUp) + .minus(ce.convertedTo(foreignCurrency, fxMatrixStart)); + assertThat(plPvEurGbpUp.getAmount()).isCloseTo(plCeEurGbpUp.getAmount(), offset); + CurrencyAmount pvGbpUsdUp = PRICER.presentValue(option, rateProvideGbpUsdUp, VOLS_FLAT); + CurrencyAmount plPvGbpUsdUp = pvGbpUsdUp.convertedTo(foreignCurrency, fxMatrixGbpUsdUp) + .minus(pv.convertedTo(foreignCurrency, fxMatrixStart)); + CurrencyAmount plCeGbpUsdUp = ce.convertedTo(foreignCurrency, fxMatrixGbpUsdUp) + .minus(ce.convertedTo(foreignCurrency, fxMatrixStart)); + assertThat(plPvGbpUsdUp.getAmount()).isCloseTo(plCeGbpUsdUp.getAmount(), offset); + } + } + + private ImmutableRatesProvider ratesProviderWithFxRate( + ResolvedFxSingleBarrierOption option, + ImmutableRatesProvider baseRatesProvider, + double fxRate) { + + FxMatrix fxMatrix = FxMatrix.builder().addRate(option.getCurrencyPair(), fxRate).build(); + return baseRatesProvider.toBuilder().fxRateProvider(fxMatrix).build(); + } + } From f1b408f027f9fc30d5da81bd43733440af9c53db Mon Sep 17 00:00:00 2001 From: lfathimakn <141994361+lfathimakn@users.noreply.github.com> Date: Thu, 23 Nov 2023 15:54:17 +0530 Subject: [PATCH 051/116] Fix for duplicate dates removal if combinePeriodsIfNecessary is set to true (#2603) * Fix for duplicate dates removal if combinePeriodsIfNecessary is set to true * Test case for fixing duplicate dates removal if combinePeriodsIfNecessary is set to true Test case for fixing duplicate dates removal if combinePeriodsIfNecessary is set to true * Fix for duplicate dates removal if combinePeriodsIfNecessary is set to true Fix for duplicate dates removal if combinePeriodsIfNecessary is set to true * Update FixedCouponBond.java Update FixedCouponBond to combine periods always --- .../basics/schedule/PeriodicSchedule.java | 2 +- .../basics/schedule/PeriodicScheduleTest.java | 45 +++++++++++++++++++ .../strata/product/bond/FixedCouponBond.java | 10 ++++- 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/modules/basics/src/main/java/com/opengamma/strata/basics/schedule/PeriodicSchedule.java b/modules/basics/src/main/java/com/opengamma/strata/basics/schedule/PeriodicSchedule.java index c49d6dcb62..f798bf5ead 100644 --- a/modules/basics/src/main/java/com/opengamma/strata/basics/schedule/PeriodicSchedule.java +++ b/modules/basics/src/main/java/com/opengamma/strata/basics/schedule/PeriodicSchedule.java @@ -454,7 +454,7 @@ public Schedule createSchedule(ReferenceData refData, boolean combinePeriodsIfNe adj = new ArrayList<>(adj); unadj = new ArrayList<>(unadj); for (int i = 0; i < adj.size() - 1; i++) { - if (adj.get(i).equals(adj.get(i + 1))) { + while (i < adj.size() - 1 && adj.get(i).equals(adj.get(i + 1))) { adj.remove(i); unadj.remove(i); } diff --git a/modules/basics/src/test/java/com/opengamma/strata/basics/schedule/PeriodicScheduleTest.java b/modules/basics/src/test/java/com/opengamma/strata/basics/schedule/PeriodicScheduleTest.java index 53fbe9140d..76e864dba7 100644 --- a/modules/basics/src/test/java/com/opengamma/strata/basics/schedule/PeriodicScheduleTest.java +++ b/modules/basics/src/test/java/com/opengamma/strata/basics/schedule/PeriodicScheduleTest.java @@ -13,6 +13,7 @@ import static com.opengamma.strata.basics.date.HolidayCalendarIds.NO_HOLIDAYS; import static com.opengamma.strata.basics.date.HolidayCalendarIds.SAT_SUN; import static com.opengamma.strata.basics.schedule.Frequency.P12M; +import static com.opengamma.strata.basics.schedule.Frequency.P1D; import static com.opengamma.strata.basics.schedule.Frequency.P1M; import static com.opengamma.strata.basics.schedule.Frequency.P1W; import static com.opengamma.strata.basics.schedule.Frequency.P2M; @@ -73,6 +74,7 @@ import com.opengamma.strata.basics.date.BusinessDayConvention; import com.opengamma.strata.basics.date.HolidayCalendar; import com.opengamma.strata.basics.date.HolidayCalendarId; +import com.opengamma.strata.basics.date.HolidayCalendarIds; import com.opengamma.strata.basics.date.HolidayCalendars; /** @@ -1208,6 +1210,49 @@ public HolidayCalendarId getId() { assertThat(schedule.getPeriod(2).getStartDate()).isEqualTo(date(2020, 10, 9)); } + @Test + public void test_combinePeriodsWhenNecessary_1d_createSchedule_duplicate_exception() { + HolidayCalendarId id = SAT_SUN; + HolidayCalendar calendar = HolidayCalendars.SAT_SUN; + + ReferenceData referenceData = ImmutableReferenceData.of(id, calendar); + BusinessDayAdjustment businessDayAdjustment = BusinessDayAdjustment.of(MODIFIED_FOLLOWING, id); + PeriodicSchedule defn = PeriodicSchedule.builder() + .startDate(date(2020, 9, 18)) + .endDate(date(2020, 12, 18)) + .frequency(P1D) + .businessDayAdjustment(businessDayAdjustment) + .stubConvention(SHORT_FINAL) + .rollConvention(null) + .build(); + + Schedule schedule = defn.createSchedule(referenceData, true); + assertThat(schedule.getPeriods()).hasSize(65); + assertThat(schedule.getPeriod(0).getStartDate()).isEqualTo(date(2020, 9, 18)); + assertThat(schedule.getPeriod(0).getEndDate()).isEqualTo(date(2020, 9, 21)); + } + + @Test + public void test_combinePeriodsWhenNecessary_1d_createSchedule() { + HolidayCalendarId id = SAT_SUN; + HolidayCalendar calendar = HolidayCalendars.SAT_SUN; + + ReferenceData referenceData = ImmutableReferenceData.of(id, calendar); + BusinessDayAdjustment businessDayAdjustment = BusinessDayAdjustment.of(MODIFIED_FOLLOWING, id); + PeriodicSchedule defn = PeriodicSchedule.builder() + .startDate(date(2020, 9, 18)) + .endDate(date(2020, 12, 18)) + .frequency(P1D) + .businessDayAdjustment(businessDayAdjustment) + .stubConvention(SHORT_FINAL) + .rollConvention(null) + .build(); + + assertThatExceptionOfType(ScheduleException.class) + .isThrownBy(() -> defn.createSchedule(referenceData, false)) + .withMessageMatching(".*duplicate adjusted dates.*"); + } + @Test public void test_emptyWhenAdjusted_twoPeriods_createUnadjustedDates() { PeriodicSchedule defn = PeriodicSchedule.builder() diff --git a/modules/product/src/main/java/com/opengamma/strata/product/bond/FixedCouponBond.java b/modules/product/src/main/java/com/opengamma/strata/product/bond/FixedCouponBond.java index 7ee1c591b7..6199d8f423 100644 --- a/modules/product/src/main/java/com/opengamma/strata/product/bond/FixedCouponBond.java +++ b/modules/product/src/main/java/com/opengamma/strata/product/bond/FixedCouponBond.java @@ -161,10 +161,16 @@ private void validate() { "The ex-coupon period is measured from the payment date, thus the days must be non-positive"); } - //------------------------------------------------------------------------- + /** + * Resolves fixed coupon bond using specified reference data. + * @param refData the reference data to use when resolving + * @return the resolved instance + * @throws ReferenceDataNotFoundException if an identifier cannot be resolved in the reference data + * @throws RuntimeException if unable to resolve due to an invalid definition + */ @Override public ResolvedFixedCouponBond resolve(ReferenceData refData) { - Schedule adjustedSchedule = accrualSchedule.createSchedule(refData); + Schedule adjustedSchedule = accrualSchedule.createSchedule(refData, true); Schedule unadjustedSchedule = adjustedSchedule.toUnadjusted(); DateAdjuster exCouponPeriodAdjuster = exCouponPeriod.resolve(refData); From d15c39dacd602e6d7b7ec75159dd12f3dff8fd4a Mon Sep 17 00:00:00 2001 From: Michael Rollins Date: Thu, 23 Nov 2023 12:39:34 +0000 Subject: [PATCH 052/116] Return all countries from getAvailableCountries (#2615) * Return all countries from getAvailableCountries * PR comments * Unused imports * Updating test --------- Co-authored-by: Michael Rollins --- .../strata/basics/location/Country.java | 29 ++++++++++--------- .../strata/basics/location/CountryTest.java | 9 ++++++ 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/modules/basics/src/main/java/com/opengamma/strata/basics/location/Country.java b/modules/basics/src/main/java/com/opengamma/strata/basics/location/Country.java index 8af117582f..655701d345 100644 --- a/modules/basics/src/main/java/com/opengamma/strata/basics/location/Country.java +++ b/modules/basics/src/main/java/com/opengamma/strata/basics/location/Country.java @@ -9,8 +9,8 @@ import java.util.Locale; import java.util.Optional; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ConcurrentSkipListMap; import org.joda.convert.FromString; import org.joda.convert.ToString; @@ -19,8 +19,9 @@ import com.google.common.base.Supplier; import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableBiMap; -import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableSortedSet; import com.opengamma.strata.collect.ArgChecker; +import com.opengamma.strata.collect.MapStream; import com.opengamma.strata.collect.io.PropertiesFile; import com.opengamma.strata.collect.io.ResourceLocator; @@ -41,15 +42,17 @@ public final class Country /** * Loads the ISO alpha-2 and alpha-3 country codes into a bidirectional map. */ - private static final Supplier> COUNTRY_CODES = Suppliers.memoize(() -> - ImmutableBiMap.copyOf(PropertiesFile.of( - ResourceLocator.ofClasspath(Country.class, "country.properties").getCharSource()) - .getProperties().asMap())); + private static final Supplier> COUNTRY_CODES = Suppliers.memoize(() -> + ImmutableBiMap.copyOf(MapStream.of(PropertiesFile.of( + ResourceLocator.ofClasspath(Country.class, "country.properties").getCharSource()) + .getProperties().asMap()) + .mapValues(Country::of) + .toMap())); /** * A cache of instances. */ - private static final ConcurrentMap CACHE = new ConcurrentHashMap<>(); + private static final ConcurrentMap CACHE = new ConcurrentSkipListMap<>(); /** * The matcher for the code. */ @@ -256,11 +259,12 @@ public final class Country *

    * This contains all the countries that have been defined at the point * that the method is called. - * + * * @return an immutable set containing all registered countries */ public static Set getAvailableCountries() { - return ImmutableSet.copyOf(CACHE.values()); + COUNTRY_CODES.get(); + return ImmutableSortedSet.copyOf(CACHE.values()); } //------------------------------------------------------------------------- @@ -316,9 +320,8 @@ public static Country parse(String countryCode) { * @throws IllegalArgumentException if the country code is invalid */ public static Country of3Char(String countryCode) { - ArgChecker.matches(CODE_MATCHER, 3, 3, countryCode, "countryCode", "[A-Z][A-Z]"); + ArgChecker.matches(CODE_MATCHER, 3, 3, countryCode, "countryCode", "[A-Z][A-Z][A-Z]"); return Optional.ofNullable(COUNTRY_CODES.get().get(countryCode)) - .map(alpha2Code -> of(alpha2Code.toUpperCase(Locale.ENGLISH))) .orElseThrow(() -> new IllegalArgumentException("Unknown country code: " + countryCode)); } @@ -359,8 +362,8 @@ public String getCode() { * @throws IllegalArgumentException if the country is invalid */ public String getCode3Char() { - if (COUNTRY_CODES.get().containsValue(this.getCode())) { - return COUNTRY_CODES.get().inverse().get(this.getCode()); + if (COUNTRY_CODES.get().containsValue(this)) { + return COUNTRY_CODES.get().inverse().get(this); } else { throw new IllegalArgumentException("Unknown country: " + this.getCode()); } diff --git a/modules/basics/src/test/java/com/opengamma/strata/basics/location/CountryTest.java b/modules/basics/src/test/java/com/opengamma/strata/basics/location/CountryTest.java index 95cce89239..3ef76ee17a 100644 --- a/modules/basics/src/test/java/com/opengamma/strata/basics/location/CountryTest.java +++ b/modules/basics/src/test/java/com/opengamma/strata/basics/location/CountryTest.java @@ -87,6 +87,15 @@ public void test_getAvailable() { assertThat(available.contains(Country.CA)).isTrue(); } + @Test + public void test_new_Country_included_in_getAvailable() { + Set available = Country.getAvailableCountries(); + assertThat(available.size()).isGreaterThan(0); + Country.of("XZ"); + Set updatedAvailable = Country.getAvailableCountries(); + assertThat(updatedAvailable.size() - available.size()).isEqualTo(1); + } + //----------------------------------------------------------------------- @Test public void test_of_String() { From 2f4411f8b4c6fcf260353d79c20e7dfb0deae94b Mon Sep 17 00:00:00 2001 From: Iain Robertson <46352224+IDRob@users.noreply.github.com> Date: Mon, 4 Dec 2023 15:10:19 +0000 Subject: [PATCH 053/116] Add INSE Exchange Id (NSE International Exchange) (#2614) Co-authored-by: Iain Robertson Co-authored-by: Alexis Skitini --- .../java/com/opengamma/strata/product/common/ExchangeIds.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/product/src/main/java/com/opengamma/strata/product/common/ExchangeIds.java b/modules/product/src/main/java/com/opengamma/strata/product/common/ExchangeIds.java index 3b4a0329de..b517b14b88 100644 --- a/modules/product/src/main/java/com/opengamma/strata/product/common/ExchangeIds.java +++ b/modules/product/src/main/java/com/opengamma/strata/product/common/ExchangeIds.java @@ -156,6 +156,9 @@ public final class ExchangeIds { /** National Stock Exchange Of India. */ public static final ExchangeId XNSE = ExchangeId.of("XNSE"); + /** NSE International Exchange. */ + public static final ExchangeId INSE = ExchangeId.of("INSE"); + //------------------------------------------------------------------------- /** * Restricted constructor. From 22ded08fa685033bbf1b7019c81081f28d61d938 Mon Sep 17 00:00:00 2001 From: Marc Henrard Date: Mon, 4 Dec 2023 15:25:04 +0000 Subject: [PATCH 054/116] Implied vol for intrinsic value close to 0. (#2616) * Implied vol for intrinsic value close to 0. * PR comment --- .../impl/option/BlackFormulaRepository.java | 13 ++++++++----- .../impl/option/BlackFormulaRepositoryTest.java | 16 ++++++++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/modules/pricer/src/main/java/com/opengamma/strata/pricer/impl/option/BlackFormulaRepository.java b/modules/pricer/src/main/java/com/opengamma/strata/pricer/impl/option/BlackFormulaRepository.java index b3832ab6f0..81b38121ae 100644 --- a/modules/pricer/src/main/java/com/opengamma/strata/pricer/impl/option/BlackFormulaRepository.java +++ b/modules/pricer/src/main/java/com/opengamma/strata/pricer/impl/option/BlackFormulaRepository.java @@ -1137,7 +1137,7 @@ public static double impliedVolatility( double timeToExpiry, boolean isCall) { - ArgChecker.isTrue(price >= 0d, "negative/NaN price; have {}", price); + ArgChecker.isTrue(price >= -NEAR_ZERO * forward, "negative/NaN price; have {}", price); ArgChecker.isTrue(forward > 0d, "negative/NaN forward; have {}", forward); ArgChecker.isTrue(strike >= 0d, "negative/NaN strike; have {}", strike); ArgChecker.isTrue(timeToExpiry >= 0d, "negative/NaN timeToExpiry; have {}", timeToExpiry); @@ -1172,7 +1172,7 @@ public static ValueDerivatives impliedVolatilityAdjoint( double timeToExpiry, boolean isCall) { - ArgChecker.isTrue(price >= 0d, "negative/NaN price; have {}", price); + ArgChecker.isTrue(price >= -NEAR_ZERO * forward, "negative/NaN price; have {}", price); ArgChecker.isTrue(forward > 0d, "negative/NaN forward; have {}", forward); ArgChecker.isTrue(strike >= 0d, "negative/NaN strike; have {}", strike); ArgChecker.isTrue(timeToExpiry >= 0d, "negative/NaN timeToExpiry; have {}", timeToExpiry); @@ -1211,7 +1211,7 @@ public static double impliedVolatility( double timeToExpiry, double volGuess) { - ArgChecker.isTrue(otmPrice >= 0d, "negative/NaN otmPrice; have {}", otmPrice); + ArgChecker.isTrue(otmPrice >= -NEAR_ZERO * forward, "negative/NaN otmPrice; have {}", otmPrice); ArgChecker.isTrue(forward >= 0d, "negative/NaN forward; have {}", forward); ArgChecker.isTrue(strike >= 0d, "negative/NaN strike; have {}", strike); ArgChecker.isTrue(timeToExpiry >= 0d, "negative/NaN timeToExpiry; have {}", timeToExpiry); @@ -1223,8 +1223,8 @@ public static double impliedVolatility( ArgChecker.isFalse(Double.isInfinite(timeToExpiry), "timeToExpiry is Infinity"); ArgChecker.isFalse(Double.isInfinite(volGuess), "volGuess is Infinity"); - if (otmPrice == 0) { - return 0; + if (Math.abs(otmPrice) < NEAR_ZERO * forward) { + return 0.0d; } ArgChecker.isTrue(otmPrice < Math.min(forward, strike), "otmPrice of {} exceeded upper bound of {}", otmPrice, Math.min(forward, strike)); @@ -1274,6 +1274,9 @@ public static ValueDerivatives impliedVolatilityAdjoint( double timeToExpiry, double volGuess) { + if (Math.abs(otmPrice) < NEAR_ZERO * forward) { + return ValueDerivatives.of(0.0d, DoubleArray.of(0.0d)); + } double impliedVolatility = impliedVolatility(otmPrice, forward, strike, timeToExpiry, volGuess); boolean isCall = strike >= forward; ValueDerivatives price = priceAdjoint(forward, strike, timeToExpiry, impliedVolatility, isCall); diff --git a/modules/pricer/src/test/java/com/opengamma/strata/pricer/impl/option/BlackFormulaRepositoryTest.java b/modules/pricer/src/test/java/com/opengamma/strata/pricer/impl/option/BlackFormulaRepositoryTest.java index 9e677dd78f..06cdce6551 100644 --- a/modules/pricer/src/test/java/com/opengamma/strata/pricer/impl/option/BlackFormulaRepositoryTest.java +++ b/modules/pricer/src/test/java/com/opengamma/strata/pricer/impl/option/BlackFormulaRepositoryTest.java @@ -8313,6 +8313,22 @@ public void impliedVolTest() { } } + /* Implied vol computation with limit cases option price near intrinsic price */ + @Test + public void impliedVol_near_intrinsic() { + double optionPrice = 19.98d; + double forward = 79.98d; + double strike = 60.00d; + double timeToExpiry = 0.0d; + double iv = BlackFormulaRepository.impliedVolatility(optionPrice, forward, strike, timeToExpiry, true); + assertThat(iv).isCloseTo(0.0, offset(1e-12)); + ValueDerivatives ivAdj = BlackFormulaRepository + .impliedVolatilityAdjoint(optionPrice, forward, strike, timeToExpiry, true); + assertThat(ivAdj.getValue()).isCloseTo(0.0, offset(1e-12)); + assertThat(ivAdj.getDerivatives().size()).isEqualTo(1); + assertThat(ivAdj.getDerivative(0)).isCloseTo(0.0, offset(1e-12)); + } + @Test public void implied_volatility_adjoint() { double vol = 0.4342; // Deliberately picked an arbitrary vol From 253b82ad9cf644a43502e9b9af0abb88ca12547a Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Fri, 8 Dec 2023 12:08:18 +0000 Subject: [PATCH 055/116] [maven-release-plugin] prepare release v2.12.30 --- examples/pom.xml | 6 +++++- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index cea9c476e0..4983ad3cc5 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.30-SNAPSHOT + 2.12.30 jar Strata-Examples Example code to demonstrate use of Strata @@ -272,4 +272,8 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> + + + v2.12.30 + diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index 6de2ee3960..980ad18e90 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.30-SNAPSHOT + 2.12.30 .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 08a63153f4..1b9948d0c8 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.30-SNAPSHOT + 2.12.30 .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index e19786266e..377217b209 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.30-SNAPSHOT + 2.12.30 .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 298dd3ee5b..622696c2da 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.30-SNAPSHOT + 2.12.30 .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index bbbd8e6987..79c35a4a84 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.30-SNAPSHOT + 2.12.30 .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index a4505398c6..c58d9c86a6 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.30-SNAPSHOT + 2.12.30 .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 6d2a908de4..af1be77266 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.30-SNAPSHOT + 2.12.30 .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 88bf103e2a..f4379ed1e6 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.30-SNAPSHOT + 2.12.30 .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 3b78d79194..f9b8a054eb 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.30-SNAPSHOT + 2.12.30 pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.30 diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 7abdf46eb0..b21853cda1 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.30-SNAPSHOT + 2.12.30 .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 06ee3d9cf5..3c933b798c 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.30-SNAPSHOT + 2.12.30 .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 3069e1ef2c..f0874ab90e 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.30-SNAPSHOT + 2.12.30 .. strata-report diff --git a/pom.xml b/pom.xml index 1b93b9900f..79c87bb4eb 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.30-SNAPSHOT + 2.12.30 pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.30 From 8a93921f3b8b45f9917f194b0efe5cfa4b6acc79 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Fri, 8 Dec 2023 12:08:20 +0000 Subject: [PATCH 056/116] [maven-release-plugin] prepare for next development iteration --- examples/pom.xml | 6 +----- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 4983ad3cc5..0af8e0c7de 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.30 + 2.12.31-SNAPSHOT jar Strata-Examples Example code to demonstrate use of Strata @@ -272,8 +272,4 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> - - - v2.12.30 - diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index 980ad18e90..a7f17f1ee4 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.30 + 2.12.31-SNAPSHOT .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 1b9948d0c8..437d65db03 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.30 + 2.12.31-SNAPSHOT .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 377217b209..31ae0eff70 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.30 + 2.12.31-SNAPSHOT .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 622696c2da..da6b72a3c1 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.30 + 2.12.31-SNAPSHOT .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 79c35a4a84..8e566c7caa 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.30 + 2.12.31-SNAPSHOT .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index c58d9c86a6..68f498a904 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.30 + 2.12.31-SNAPSHOT .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index af1be77266..10166a49db 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.30 + 2.12.31-SNAPSHOT .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index f4379ed1e6..1aec71ef54 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.30 + 2.12.31-SNAPSHOT .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index f9b8a054eb..b6ef7f6bfa 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.30 + 2.12.31-SNAPSHOT pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.30 + HEAD diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index b21853cda1..8914597d45 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.30 + 2.12.31-SNAPSHOT .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 3c933b798c..6adc8bc18f 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.30 + 2.12.31-SNAPSHOT .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index f0874ab90e..d897c64ab2 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.30 + 2.12.31-SNAPSHOT .. strata-report diff --git a/pom.xml b/pom.xml index 79c87bb4eb..16192cf489 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.30 + 2.12.31-SNAPSHOT pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.30 + HEAD From b3b9bbb7ba72804a2bb7372217c6bd989b23083b Mon Sep 17 00:00:00 2001 From: Alexis Skitini Date: Fri, 8 Dec 2023 13:01:08 +0000 Subject: [PATCH 057/116] Adding missing import for ReferenceDataNotFoundException (#2617) Co-authored-by: Alexis Skitini --- .../java/com/opengamma/strata/product/bond/FixedCouponBond.java | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/product/src/main/java/com/opengamma/strata/product/bond/FixedCouponBond.java b/modules/product/src/main/java/com/opengamma/strata/product/bond/FixedCouponBond.java index 6199d8f423..cb5635c88c 100644 --- a/modules/product/src/main/java/com/opengamma/strata/product/bond/FixedCouponBond.java +++ b/modules/product/src/main/java/com/opengamma/strata/product/bond/FixedCouponBond.java @@ -25,6 +25,7 @@ import com.google.common.collect.ImmutableList; import com.opengamma.strata.basics.ReferenceData; +import com.opengamma.strata.basics.ReferenceDataNotFoundException; import com.opengamma.strata.basics.Resolvable; import com.opengamma.strata.basics.StandardId; import com.opengamma.strata.basics.currency.Currency; From adbce72ab89d1d9380082f8f206e778d0bbc61a1 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Fri, 8 Dec 2023 14:11:38 +0000 Subject: [PATCH 058/116] [maven-release-plugin] prepare release v2.12.31 --- examples/pom.xml | 6 +++++- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 0af8e0c7de..a2ef8fda6a 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.31-SNAPSHOT + 2.12.31 jar Strata-Examples Example code to demonstrate use of Strata @@ -272,4 +272,8 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> + + + v2.12.31 + diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index a7f17f1ee4..0af71f31a8 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.31-SNAPSHOT + 2.12.31 .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 437d65db03..1c8a692cb9 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.31-SNAPSHOT + 2.12.31 .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 31ae0eff70..c75f26a332 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.31-SNAPSHOT + 2.12.31 .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index da6b72a3c1..93aee2c7e8 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.31-SNAPSHOT + 2.12.31 .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 8e566c7caa..f38e9fc053 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.31-SNAPSHOT + 2.12.31 .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 68f498a904..21a16e8800 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.31-SNAPSHOT + 2.12.31 .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 10166a49db..27cbee357f 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.31-SNAPSHOT + 2.12.31 .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 1aec71ef54..e80919256d 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.31-SNAPSHOT + 2.12.31 .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index b6ef7f6bfa..0fb38e811a 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.31-SNAPSHOT + 2.12.31 pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.31 diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 8914597d45..0e60bf9695 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.31-SNAPSHOT + 2.12.31 .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 6adc8bc18f..325b45b44e 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.31-SNAPSHOT + 2.12.31 .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index d897c64ab2..ea058a803a 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.31-SNAPSHOT + 2.12.31 .. strata-report diff --git a/pom.xml b/pom.xml index 16192cf489..0384c89eba 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.31-SNAPSHOT + 2.12.31 pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.31 From 0bb54966483f4ea8f43c969d2db3ed72129d062d Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Fri, 8 Dec 2023 14:11:40 +0000 Subject: [PATCH 059/116] [maven-release-plugin] prepare for next development iteration --- examples/pom.xml | 6 +----- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index a2ef8fda6a..5c9c392fa7 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.31 + 2.12.32-SNAPSHOT jar Strata-Examples Example code to demonstrate use of Strata @@ -272,8 +272,4 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> - - - v2.12.31 - diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index 0af71f31a8..c0a08295a6 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.31 + 2.12.32-SNAPSHOT .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 1c8a692cb9..cc3cba48e3 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.31 + 2.12.32-SNAPSHOT .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index c75f26a332..84745756b9 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.31 + 2.12.32-SNAPSHOT .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 93aee2c7e8..743c5a0ac5 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.31 + 2.12.32-SNAPSHOT .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index f38e9fc053..ce6c4888da 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.31 + 2.12.32-SNAPSHOT .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 21a16e8800..a6ca35769b 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.31 + 2.12.32-SNAPSHOT .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 27cbee357f..ade5d387db 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.31 + 2.12.32-SNAPSHOT .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index e80919256d..e758421670 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.31 + 2.12.32-SNAPSHOT .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 0fb38e811a..cd19f13624 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.31 + 2.12.32-SNAPSHOT pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.31 + HEAD diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 0e60bf9695..630662c40e 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.31 + 2.12.32-SNAPSHOT .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 325b45b44e..65b8ac898a 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.31 + 2.12.32-SNAPSHOT .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index ea058a803a..b7cbcac397 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.31 + 2.12.32-SNAPSHOT .. strata-report diff --git a/pom.xml b/pom.xml index 0384c89eba..01d3f1a489 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.31 + 2.12.32-SNAPSHOT pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.31 + HEAD From d84e54a4e915c4ca5c573f917d55eed9cb89eee0 Mon Sep 17 00:00:00 2001 From: Alexis Skitini Date: Mon, 11 Dec 2023 14:27:31 +0000 Subject: [PATCH 060/116] Revert "CsvRow - Reword exception for missing value (#2601)" (#2619) This reverts commit 7bf764e2a18eca67b9b421f72a368c9aedd15b41. --- .../src/main/java/com/opengamma/strata/collect/io/CsvRow.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/collect/src/main/java/com/opengamma/strata/collect/io/CsvRow.java b/modules/collect/src/main/java/com/opengamma/strata/collect/io/CsvRow.java index c936c8bd06..6255adec3e 100644 --- a/modules/collect/src/main/java/com/opengamma/strata/collect/io/CsvRow.java +++ b/modules/collect/src/main/java/com/opengamma/strata/collect/io/CsvRow.java @@ -271,7 +271,7 @@ public Optional findField(Pattern headerPattern) { public String getValue(String header) { String value = getField(header); if (value.isEmpty()) { - throw new ParseFailureException("No value was found in column '{header}'", header); + throw new ParseFailureException("No value was found for '{header}'", header); } return value; } From 800c7c2183b1481cc90088c4cc964d01ca3f5f5e Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Mon, 11 Dec 2023 14:59:47 +0000 Subject: [PATCH 061/116] [maven-release-plugin] prepare release v2.12.32 --- examples/pom.xml | 6 +++++- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 5c9c392fa7..dbc32d446d 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.32-SNAPSHOT + 2.12.32 jar Strata-Examples Example code to demonstrate use of Strata @@ -272,4 +272,8 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> + + + v2.12.32 + diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index c0a08295a6..987bde85ee 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.32-SNAPSHOT + 2.12.32 .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index cc3cba48e3..15e944b2fd 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.32-SNAPSHOT + 2.12.32 .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 84745756b9..0270b3521f 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.32-SNAPSHOT + 2.12.32 .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 743c5a0ac5..5142c706d8 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.32-SNAPSHOT + 2.12.32 .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index ce6c4888da..6a7b7da9a7 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.32-SNAPSHOT + 2.12.32 .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index a6ca35769b..a1e782f73f 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.32-SNAPSHOT + 2.12.32 .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index ade5d387db..876d9be320 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.32-SNAPSHOT + 2.12.32 .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index e758421670..8594bcff51 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.32-SNAPSHOT + 2.12.32 .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index cd19f13624..21f5f91667 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.32-SNAPSHOT + 2.12.32 pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.32 diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 630662c40e..ad5d2d27bf 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.32-SNAPSHOT + 2.12.32 .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 65b8ac898a..957f4d9bc6 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.32-SNAPSHOT + 2.12.32 .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index b7cbcac397..f1ae22f43e 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.32-SNAPSHOT + 2.12.32 .. strata-report diff --git a/pom.xml b/pom.xml index 01d3f1a489..84eee17d01 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.32-SNAPSHOT + 2.12.32 pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.32 From db56007cd38b89b7fc8cc55aec6aa86bfee80291 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Mon, 11 Dec 2023 14:59:48 +0000 Subject: [PATCH 062/116] [maven-release-plugin] prepare for next development iteration --- examples/pom.xml | 6 +----- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index dbc32d446d..984de3e02e 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.32 + 2.12.33-SNAPSHOT jar Strata-Examples Example code to demonstrate use of Strata @@ -272,8 +272,4 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> - - - v2.12.32 - diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index 987bde85ee..3efead0d13 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.32 + 2.12.33-SNAPSHOT .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 15e944b2fd..e9028ba593 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.32 + 2.12.33-SNAPSHOT .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 0270b3521f..eb0d5cccc3 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.32 + 2.12.33-SNAPSHOT .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 5142c706d8..ae3e2b16a7 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.32 + 2.12.33-SNAPSHOT .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 6a7b7da9a7..b2e6999fc8 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.32 + 2.12.33-SNAPSHOT .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index a1e782f73f..cc89c49303 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.32 + 2.12.33-SNAPSHOT .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 876d9be320..b9cf54a472 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.32 + 2.12.33-SNAPSHOT .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 8594bcff51..deb5791337 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.32 + 2.12.33-SNAPSHOT .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 21f5f91667..cf3e28a0dc 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.32 + 2.12.33-SNAPSHOT pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.32 + HEAD diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index ad5d2d27bf..d760227134 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.32 + 2.12.33-SNAPSHOT .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 957f4d9bc6..7e5a0d5611 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.32 + 2.12.33-SNAPSHOT .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index f1ae22f43e..4ce821db77 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.32 + 2.12.33-SNAPSHOT .. strata-report diff --git a/pom.xml b/pom.xml index 84eee17d01..f785715e1d 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.32 + 2.12.33-SNAPSHOT pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.32 + HEAD From 21cff275be52f380616344fe3da784db6720aaf1 Mon Sep 17 00:00:00 2001 From: MilenOrfeev <124578252+milenOG@users.noreply.github.com> Date: Wed, 3 Jan 2024 14:50:48 +0000 Subject: [PATCH 063/116] Use defaults instead of null in IborRateSwapLegConvention (#2622) * PROD-29409: default stub convention to SI * PROD-29409: use getters everywhere * default only stub convention * small copy paste fix * another copy paste fix --- .../strata/product/swap/type/FixedRateSwapLegConvention.java | 2 +- .../strata/product/swap/type/IborRateSwapLegConvention.java | 2 +- .../product/swap/type/IborRateSwapLegConventionTest.java | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/product/src/main/java/com/opengamma/strata/product/swap/type/FixedRateSwapLegConvention.java b/modules/product/src/main/java/com/opengamma/strata/product/swap/type/FixedRateSwapLegConvention.java index d4acb97b47..07e440fc0e 100644 --- a/modules/product/src/main/java/com/opengamma/strata/product/swap/type/FixedRateSwapLegConvention.java +++ b/modules/product/src/main/java/com/opengamma/strata/product/swap/type/FixedRateSwapLegConvention.java @@ -344,7 +344,7 @@ public RateCalculationSwapLeg toLeg( .businessDayAdjustment(accrualBusinessDayAdjustment) .startDateBusinessDayAdjustment(startDateBusinessDayAdjustment) .endDateBusinessDayAdjustment(endDateBusinessDayAdjustment) - .stubConvention(stubConvention) + .stubConvention(getStubConvention()) .rollConvention(rollConvention) .build()) .paymentSchedule(PaymentSchedule.builder() diff --git a/modules/product/src/main/java/com/opengamma/strata/product/swap/type/IborRateSwapLegConvention.java b/modules/product/src/main/java/com/opengamma/strata/product/swap/type/IborRateSwapLegConvention.java index 41980246da..7a647eb024 100644 --- a/modules/product/src/main/java/com/opengamma/strata/product/swap/type/IborRateSwapLegConvention.java +++ b/modules/product/src/main/java/com/opengamma/strata/product/swap/type/IborRateSwapLegConvention.java @@ -498,7 +498,7 @@ public RateCalculationSwapLeg toLeg( .businessDayAdjustment(getAccrualBusinessDayAdjustment()) .startDateBusinessDayAdjustment(startDateBusinessDayAdjustment) .endDateBusinessDayAdjustment(endDateBusinessDayAdjustment) - .stubConvention(stubConvention) + .stubConvention(getStubConvention()) .rollConvention(rollConvention) .build()) .paymentSchedule(PaymentSchedule.builder() diff --git a/modules/product/src/test/java/com/opengamma/strata/product/swap/type/IborRateSwapLegConventionTest.java b/modules/product/src/test/java/com/opengamma/strata/product/swap/type/IborRateSwapLegConventionTest.java index a8f9cea145..8664334204 100644 --- a/modules/product/src/test/java/com/opengamma/strata/product/swap/type/IborRateSwapLegConventionTest.java +++ b/modules/product/src/test/java/com/opengamma/strata/product/swap/type/IborRateSwapLegConventionTest.java @@ -16,6 +16,7 @@ import static com.opengamma.strata.basics.schedule.Frequency.P3M; import static com.opengamma.strata.basics.schedule.Frequency.P6M; import static com.opengamma.strata.basics.schedule.StubConvention.LONG_INITIAL; +import static com.opengamma.strata.basics.schedule.StubConvention.SMART_INITIAL; import static com.opengamma.strata.collect.TestHelper.assertSerialization; import static com.opengamma.strata.collect.TestHelper.coverBeanEquals; import static com.opengamma.strata.collect.TestHelper.coverImmutableBean; @@ -152,6 +153,7 @@ public void test_toLeg() { .startDate(startDate) .endDate(endDate) .businessDayAdjustment(BDA_MOD_FOLLOW) + .stubConvention(SMART_INITIAL) .build()) .paymentSchedule(PaymentSchedule.builder() .paymentFrequency(P3M) @@ -178,6 +180,7 @@ public void test_toLeg_withSpread() { .startDate(startDate) .endDate(endDate) .businessDayAdjustment(BDA_MOD_FOLLOW) + .stubConvention(SMART_INITIAL) .build()) .paymentSchedule(PaymentSchedule.builder() .paymentFrequency(P3M) From 2075f6b084fef5761b630665b20438d625b253f1 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Wed, 3 Jan 2024 15:11:24 +0000 Subject: [PATCH 064/116] [maven-release-plugin] prepare release v2.12.33 --- examples/pom.xml | 6 +++++- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 984de3e02e..6c52c18549 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.33-SNAPSHOT + 2.12.33 jar Strata-Examples Example code to demonstrate use of Strata @@ -272,4 +272,8 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> + + + v2.12.33 + diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index 3efead0d13..8d2452e459 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.33-SNAPSHOT + 2.12.33 .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index e9028ba593..9abda7cd92 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.33-SNAPSHOT + 2.12.33 .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index eb0d5cccc3..3b6097c737 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.33-SNAPSHOT + 2.12.33 .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index ae3e2b16a7..91c5eae23e 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.33-SNAPSHOT + 2.12.33 .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index b2e6999fc8..6f2d230943 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.33-SNAPSHOT + 2.12.33 .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index cc89c49303..0d3d7c4038 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.33-SNAPSHOT + 2.12.33 .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index b9cf54a472..89bff0b2c0 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.33-SNAPSHOT + 2.12.33 .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index deb5791337..5ce4998284 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.33-SNAPSHOT + 2.12.33 .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index cf3e28a0dc..4f7f605f5a 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.33-SNAPSHOT + 2.12.33 pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.33 diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index d760227134..2dc57bdd8a 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.33-SNAPSHOT + 2.12.33 .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 7e5a0d5611..dce0c83f6e 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.33-SNAPSHOT + 2.12.33 .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 4ce821db77..477ceb43d1 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.33-SNAPSHOT + 2.12.33 .. strata-report diff --git a/pom.xml b/pom.xml index f785715e1d..c5b0e3b3ec 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.33-SNAPSHOT + 2.12.33 pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.33 From c1094c6924f0623cd6c2668ae1a3b0c9400a3335 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Wed, 3 Jan 2024 15:11:26 +0000 Subject: [PATCH 065/116] [maven-release-plugin] prepare for next development iteration --- examples/pom.xml | 6 +----- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 6c52c18549..678246d9b8 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.33 + 2.12.34-SNAPSHOT jar Strata-Examples Example code to demonstrate use of Strata @@ -272,8 +272,4 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> - - - v2.12.33 - diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index 8d2452e459..dc6b47a804 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.33 + 2.12.34-SNAPSHOT .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 9abda7cd92..b90902fde2 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.33 + 2.12.34-SNAPSHOT .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 3b6097c737..73cf3a7cb9 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.33 + 2.12.34-SNAPSHOT .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 91c5eae23e..db2156ed33 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.33 + 2.12.34-SNAPSHOT .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 6f2d230943..63c4b72463 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.33 + 2.12.34-SNAPSHOT .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 0d3d7c4038..185261ff88 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.33 + 2.12.34-SNAPSHOT .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 89bff0b2c0..57e771d548 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.33 + 2.12.34-SNAPSHOT .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 5ce4998284..6a765ac9d5 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.33 + 2.12.34-SNAPSHOT .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 4f7f605f5a..4c0332a0f8 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.33 + 2.12.34-SNAPSHOT pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.33 + HEAD diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 2dc57bdd8a..679c43acfb 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.33 + 2.12.34-SNAPSHOT .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index dce0c83f6e..a00e8a2753 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.33 + 2.12.34-SNAPSHOT .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 477ceb43d1..b7061fde78 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.33 + 2.12.34-SNAPSHOT .. strata-report diff --git a/pom.xml b/pom.xml index c5b0e3b3ec..7766ffae5c 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.33 + 2.12.34-SNAPSHOT pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.33 + HEAD From f4819ebaef41ceedfb23fff9af1554148ac9d7c9 Mon Sep 17 00:00:00 2001 From: Guillaume Santoro <31656059+santorog@users.noreply.github.com> Date: Fri, 26 Jan 2024 12:20:51 +0000 Subject: [PATCH 066/116] Fix calendar of xccy conventions containing USD-SOFR (#2627) Co-authored-by: Guillaume Santoro --- ...XCcyOvernightOvernightSwapConventions.java | 38 +++++++++---------- ...OvernightOvernightSwapConventionsTest.java | 26 ++++++------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/modules/product/src/main/java/com/opengamma/strata/product/swap/type/StandardXCcyOvernightOvernightSwapConventions.java b/modules/product/src/main/java/com/opengamma/strata/product/swap/type/StandardXCcyOvernightOvernightSwapConventions.java index 50ab1469b7..d51e8fd671 100644 --- a/modules/product/src/main/java/com/opengamma/strata/product/swap/type/StandardXCcyOvernightOvernightSwapConventions.java +++ b/modules/product/src/main/java/com/opengamma/strata/product/swap/type/StandardXCcyOvernightOvernightSwapConventions.java @@ -9,7 +9,7 @@ import static com.opengamma.strata.basics.date.HolidayCalendarIds.EUTA; import static com.opengamma.strata.basics.date.HolidayCalendarIds.GBLO; import static com.opengamma.strata.basics.date.HolidayCalendarIds.JPTO; -import static com.opengamma.strata.basics.date.HolidayCalendarIds.USNY; +import static com.opengamma.strata.basics.date.HolidayCalendarIds.USGS; import com.opengamma.strata.basics.date.BusinessDayAdjustment; import com.opengamma.strata.basics.date.DaysAdjustment; @@ -29,10 +29,10 @@ final class StandardXCcyOvernightOvernightSwapConventions { // Join calendar with the main currencies - private static final HolidayCalendarId EUTA_USNY = EUTA.combinedWith(USNY); - private static final HolidayCalendarId GBLO_USNY = GBLO.combinedWith(USNY); + private static final HolidayCalendarId EUTA_USGS = EUTA.combinedWith(USGS); + private static final HolidayCalendarId GBLO_USGS = GBLO.combinedWith(USGS); private static final HolidayCalendarId GBLO_EUTA = GBLO.combinedWith(EUTA); - private static final HolidayCalendarId JPTO_USNY = JPTO.combinedWith(USNY); + private static final HolidayCalendarId JPTO_USGS = JPTO.combinedWith(USGS); /** * EUR ESTR 3M v USD SOFR 3M. @@ -45,20 +45,20 @@ final class StandardXCcyOvernightOvernightSwapConventions { .index(OvernightIndices.EUR_ESTR) .paymentFrequency(Frequency.P3M) .accrualFrequency(Frequency.P3M) - .paymentDateOffset(DaysAdjustment.ofBusinessDays(2, EUTA_USNY)) + .paymentDateOffset(DaysAdjustment.ofBusinessDays(2, EUTA_USGS)) .stubConvention(StubConvention.SMART_INITIAL) - .accrualBusinessDayAdjustment(BusinessDayAdjustment.of(MODIFIED_FOLLOWING, EUTA_USNY)) + .accrualBusinessDayAdjustment(BusinessDayAdjustment.of(MODIFIED_FOLLOWING, EUTA_USGS)) .notionalExchange(true) .build()) .flatLeg(OvernightRateSwapLegConvention.builder() .index(OvernightIndices.USD_SOFR) .paymentFrequency(Frequency.P3M) .accrualFrequency(Frequency.P3M) - .paymentDateOffset(DaysAdjustment.ofBusinessDays(2, EUTA_USNY)) - .accrualBusinessDayAdjustment(BusinessDayAdjustment.of(MODIFIED_FOLLOWING, EUTA_USNY)) + .paymentDateOffset(DaysAdjustment.ofBusinessDays(2, EUTA_USGS)) + .accrualBusinessDayAdjustment(BusinessDayAdjustment.of(MODIFIED_FOLLOWING, EUTA_USGS)) .notionalExchange(true) .build()) - .spotDateOffset(DaysAdjustment.ofBusinessDays(2, EUTA_USNY)) + .spotDateOffset(DaysAdjustment.ofBusinessDays(2, EUTA_USGS)) .build(); /** @@ -72,20 +72,20 @@ final class StandardXCcyOvernightOvernightSwapConventions { .index(OvernightIndices.GBP_SONIA) .paymentFrequency(Frequency.P3M) .accrualFrequency(Frequency.P3M) - .paymentDateOffset(DaysAdjustment.ofBusinessDays(2, GBLO_USNY)) + .paymentDateOffset(DaysAdjustment.ofBusinessDays(2, GBLO_USGS)) .stubConvention(StubConvention.SMART_INITIAL) - .accrualBusinessDayAdjustment(BusinessDayAdjustment.of(MODIFIED_FOLLOWING, GBLO_USNY)) + .accrualBusinessDayAdjustment(BusinessDayAdjustment.of(MODIFIED_FOLLOWING, GBLO_USGS)) .notionalExchange(true) .build()) .flatLeg(OvernightRateSwapLegConvention.builder() .index(OvernightIndices.USD_SOFR) .paymentFrequency(Frequency.P3M) .accrualFrequency(Frequency.P3M) - .paymentDateOffset(DaysAdjustment.ofBusinessDays(2, GBLO_USNY)) - .accrualBusinessDayAdjustment(BusinessDayAdjustment.of(MODIFIED_FOLLOWING, GBLO_USNY)) + .paymentDateOffset(DaysAdjustment.ofBusinessDays(2, GBLO_USGS)) + .accrualBusinessDayAdjustment(BusinessDayAdjustment.of(MODIFIED_FOLLOWING, GBLO_USGS)) .notionalExchange(true) .build()) - .spotDateOffset(DaysAdjustment.ofBusinessDays(2, GBLO_USNY)) + .spotDateOffset(DaysAdjustment.ofBusinessDays(2, GBLO_USGS)) .build(); /** @@ -126,20 +126,20 @@ final class StandardXCcyOvernightOvernightSwapConventions { .index(OvernightIndices.JPY_TONAR) .paymentFrequency(Frequency.P3M) .accrualFrequency(Frequency.P3M) - .paymentDateOffset(DaysAdjustment.ofBusinessDays(2, JPTO_USNY)) + .paymentDateOffset(DaysAdjustment.ofBusinessDays(2, JPTO_USGS)) .stubConvention(StubConvention.SMART_INITIAL) - .accrualBusinessDayAdjustment(BusinessDayAdjustment.of(MODIFIED_FOLLOWING, JPTO_USNY)) + .accrualBusinessDayAdjustment(BusinessDayAdjustment.of(MODIFIED_FOLLOWING, JPTO_USGS)) .notionalExchange(true) .build()) .flatLeg(OvernightRateSwapLegConvention.builder() .index(OvernightIndices.USD_SOFR) .paymentFrequency(Frequency.P3M) .accrualFrequency(Frequency.P3M) - .paymentDateOffset(DaysAdjustment.ofBusinessDays(2, JPTO_USNY)) - .accrualBusinessDayAdjustment(BusinessDayAdjustment.of(MODIFIED_FOLLOWING, JPTO_USNY)) + .paymentDateOffset(DaysAdjustment.ofBusinessDays(2, JPTO_USGS)) + .accrualBusinessDayAdjustment(BusinessDayAdjustment.of(MODIFIED_FOLLOWING, JPTO_USGS)) .notionalExchange(true) .build()) - .spotDateOffset(DaysAdjustment.ofBusinessDays(2, JPTO_USNY)) + .spotDateOffset(DaysAdjustment.ofBusinessDays(2, JPTO_USGS)) .build(); //------------------------------------------------------------------------- diff --git a/modules/product/src/test/java/com/opengamma/strata/product/swap/type/XCcyOvernightOvernightSwapConventionsTest.java b/modules/product/src/test/java/com/opengamma/strata/product/swap/type/XCcyOvernightOvernightSwapConventionsTest.java index f1f101ef1f..7159b0643b 100644 --- a/modules/product/src/test/java/com/opengamma/strata/product/swap/type/XCcyOvernightOvernightSwapConventionsTest.java +++ b/modules/product/src/test/java/com/opengamma/strata/product/swap/type/XCcyOvernightOvernightSwapConventionsTest.java @@ -9,7 +9,7 @@ import static com.opengamma.strata.basics.date.HolidayCalendarIds.EUTA; import static com.opengamma.strata.basics.date.HolidayCalendarIds.GBLO; import static com.opengamma.strata.basics.date.HolidayCalendarIds.JPTO; -import static com.opengamma.strata.basics.date.HolidayCalendarIds.USNY; +import static com.opengamma.strata.basics.date.HolidayCalendarIds.USGS; import static com.opengamma.strata.collect.TestHelper.coverPrivateConstructor; import static org.assertj.core.api.Assertions.assertThat; @@ -31,10 +31,10 @@ */ public class XCcyOvernightOvernightSwapConventionsTest { - private static final HolidayCalendarId EUTA_USNY = EUTA.combinedWith(USNY); - private static final HolidayCalendarId GBLO_USNY = GBLO.combinedWith(USNY); + private static final HolidayCalendarId EUTA_USGS = EUTA.combinedWith(USGS); + private static final HolidayCalendarId GBLO_USGS = GBLO.combinedWith(USGS); private static final HolidayCalendarId GBLO_EUTA = GBLO.combinedWith(EUTA); - private static final HolidayCalendarId JPTO_USNY = JPTO.combinedWith(USNY); + private static final HolidayCalendarId JPTO_USGS = JPTO.combinedWith(USGS); public static Object[][] data_spot_lag() { return new Object[][] { @@ -86,10 +86,10 @@ public void test_float_leg(XCcyOvernightOvernightSwapConvention convention, Over //------------------------------------------------------------------------- public static Object[][] data_spread_leg_bda() { return new Object[][] { - {XCcyOvernightOvernightSwapConventions.EUR_ESTR_3M_USD_SOFR_3M, BusinessDayAdjustment.of(MODIFIED_FOLLOWING, EUTA_USNY)}, - {XCcyOvernightOvernightSwapConventions.GBP_SONIA_3M_USD_SOFR_3M, BusinessDayAdjustment.of(MODIFIED_FOLLOWING, GBLO_USNY)}, + {XCcyOvernightOvernightSwapConventions.EUR_ESTR_3M_USD_SOFR_3M, BusinessDayAdjustment.of(MODIFIED_FOLLOWING, EUTA_USGS)}, + {XCcyOvernightOvernightSwapConventions.GBP_SONIA_3M_USD_SOFR_3M, BusinessDayAdjustment.of(MODIFIED_FOLLOWING, GBLO_USGS)}, {XCcyOvernightOvernightSwapConventions.GBP_SONIA_3M_EUR_ESTR_3M, BusinessDayAdjustment.of(MODIFIED_FOLLOWING, GBLO_EUTA)}, - {XCcyOvernightOvernightSwapConventions.JPY_TONA_3M_USD_SOFR_3M, BusinessDayAdjustment.of(MODIFIED_FOLLOWING, JPTO_USNY)} + {XCcyOvernightOvernightSwapConventions.JPY_TONA_3M_USD_SOFR_3M, BusinessDayAdjustment.of(MODIFIED_FOLLOWING, JPTO_USGS)} }; } @@ -118,10 +118,10 @@ public void test_flat_leg(XCcyOvernightOvernightSwapConvention convention, Overn //------------------------------------------------------------------------- public static Object[][] data_flat_leg_bda() { return new Object[][] { - {XCcyOvernightOvernightSwapConventions.EUR_ESTR_3M_USD_SOFR_3M, BusinessDayAdjustment.of(MODIFIED_FOLLOWING, EUTA_USNY)}, - {XCcyOvernightOvernightSwapConventions.GBP_SONIA_3M_USD_SOFR_3M, BusinessDayAdjustment.of(MODIFIED_FOLLOWING, GBLO_USNY)}, + {XCcyOvernightOvernightSwapConventions.EUR_ESTR_3M_USD_SOFR_3M, BusinessDayAdjustment.of(MODIFIED_FOLLOWING, EUTA_USGS)}, + {XCcyOvernightOvernightSwapConventions.GBP_SONIA_3M_USD_SOFR_3M, BusinessDayAdjustment.of(MODIFIED_FOLLOWING, GBLO_USGS)}, {XCcyOvernightOvernightSwapConventions.GBP_SONIA_3M_EUR_ESTR_3M, BusinessDayAdjustment.of(MODIFIED_FOLLOWING, GBLO_EUTA)}, - {XCcyOvernightOvernightSwapConventions.JPY_TONA_3M_USD_SOFR_3M, BusinessDayAdjustment.of(MODIFIED_FOLLOWING, JPTO_USNY)} + {XCcyOvernightOvernightSwapConventions.JPY_TONA_3M_USD_SOFR_3M, BusinessDayAdjustment.of(MODIFIED_FOLLOWING, JPTO_USGS)} }; } @@ -150,10 +150,10 @@ public void test_day_convention(XCcyOvernightOvernightSwapConvention convention, //------------------------------------------------------------------------- public static Object[][] data_paymentlag() { return new Object[][] { - {XCcyOvernightOvernightSwapConventions.EUR_ESTR_3M_USD_SOFR_3M, DaysAdjustment.ofBusinessDays(2, EUTA_USNY)}, - {XCcyOvernightOvernightSwapConventions.GBP_SONIA_3M_USD_SOFR_3M, DaysAdjustment.ofBusinessDays(2, GBLO_USNY)}, + {XCcyOvernightOvernightSwapConventions.EUR_ESTR_3M_USD_SOFR_3M, DaysAdjustment.ofBusinessDays(2, EUTA_USGS)}, + {XCcyOvernightOvernightSwapConventions.GBP_SONIA_3M_USD_SOFR_3M, DaysAdjustment.ofBusinessDays(2, GBLO_USGS)}, {XCcyOvernightOvernightSwapConventions.GBP_SONIA_3M_EUR_ESTR_3M, DaysAdjustment.ofBusinessDays(2, GBLO_EUTA)}, - {XCcyOvernightOvernightSwapConventions.JPY_TONA_3M_USD_SOFR_3M, DaysAdjustment.ofBusinessDays(2, JPTO_USNY)} + {XCcyOvernightOvernightSwapConventions.JPY_TONA_3M_USD_SOFR_3M, DaysAdjustment.ofBusinessDays(2, JPTO_USGS)} }; } From bf0639bd4a5fb606d2baf2c67b58a4c37a85f9cc Mon Sep 17 00:00:00 2001 From: Chris Davies <42296718+cd223@users.noreply.github.com> Date: Mon, 29 Jan 2024 15:25:03 +0000 Subject: [PATCH 067/116] Ensure build works on Java 21 (#2628) Co-authored-by: Christopher Davies --- .circleci/config.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.circleci/config.yml b/.circleci/config.yml index 832e0b5740..46208cb707 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -32,6 +32,14 @@ executors: JAVA_TOOL_OPTIONS: -XX:MaxRAM=3572m MAVEN_OPTS: -Xmx1g + #---------------------------------------------------------------------------- + jdk21: + docker: + - image: cimg/openjdk:21.0 + working_directory: ~/repo + environment: + JAVA_TOOL_OPTIONS: -XX:MaxRAM=3572m + MAVEN_OPTS: -Xmx1g ############################################################################# # reusable commands @@ -263,6 +271,15 @@ jobs: - maven_install - maven_test + build21: + executor: jdk21 + steps: + - checkout + - with_maven: + actions: + - maven_install + - maven_test + #---------------------------------------------------------------------------- release: executor: jdk8 @@ -318,6 +335,8 @@ workflows: context: OG-OSS - build17: context: OG-OSS + - build21: + context: OG-OSS #---------------------------------------------------------------------------- # release based on a tag From 6320689e6d725193b83b589e53d3fa469ba191b3 Mon Sep 17 00:00:00 2001 From: James White <118170713+James-OpenGamma@users.noreply.github.com> Date: Mon, 5 Feb 2024 10:20:03 +0000 Subject: [PATCH 068/116] Added exchange ids for MEFF power and Cboe Clear Digital (#2633) Co-authored-by: James White --- .../com/opengamma/strata/product/common/ExchangeIds.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/modules/product/src/main/java/com/opengamma/strata/product/common/ExchangeIds.java b/modules/product/src/main/java/com/opengamma/strata/product/common/ExchangeIds.java index b517b14b88..3a361a94c3 100644 --- a/modules/product/src/main/java/com/opengamma/strata/product/common/ExchangeIds.java +++ b/modules/product/src/main/java/com/opengamma/strata/product/common/ExchangeIds.java @@ -24,6 +24,9 @@ public final class ExchangeIds { /** Chicago Board Options Exchange. */ public static final ExchangeId XCBO = ExchangeId.of("XCBO"); + /** Cboe Clear Digital. */ + public static final ExchangeId XCBD = ExchangeId.of("XCBD"); + /** New York Mercantile Exchange (NYMEX). */ public static final ExchangeId XNYM = ExchangeId.of("XNYM"); @@ -81,6 +84,9 @@ public final class ExchangeIds { /** Mercado Español de Futuros Financiero (MEFF). */ public static final ExchangeId XMRV = ExchangeId.of("XMRV"); + /** Meff Power Derivatives Exchange. */ + public static final ExchangeId XMPW = ExchangeId.of("XMPW"); + /** Bursa Malaysia. */ public static final ExchangeId XKLS = ExchangeId.of("XKLS"); From 6e4f0a6ad84372c70fcd7a4259372cad12358c4c Mon Sep 17 00:00:00 2001 From: Hashim Saleem <109087109+hsaleem06@users.noreply.github.com> Date: Mon, 5 Feb 2024 11:24:39 +0000 Subject: [PATCH 069/116] Updating Thailand Holiday Calendar - 2023 & 2024 New Year Special Public Holiday (#2634) Co-authored-by: Guillaume Santoro <31656059+santorog@users.noreply.github.com> --- .../com/opengamma/strata/config/base/HolidayCalendarData.ini | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/basics/src/main/resources/META-INF/com/opengamma/strata/config/base/HolidayCalendarData.ini b/modules/basics/src/main/resources/META-INF/com/opengamma/strata/config/base/HolidayCalendarData.ini index 94afd8129f..4eba085617 100644 --- a/modules/basics/src/main/resources/META-INF/com/opengamma/strata/config/base/HolidayCalendarData.ini +++ b/modules/basics/src/main/resources/META-INF/com/opengamma/strata/config/base/HolidayCalendarData.ini @@ -47,8 +47,8 @@ 2020=Jan01,Feb10,Apr06,Apr13,Apr14,Apr15,May01,May06,Jul06,Jul28,Aug12,Oct13,Oct23,Dec07,Dec10,Dec31 2021=Jan01,Feb26,Apr06,Apr13,Apr14,Apr15,May03,May26,Jul26,Jul28,Aug12,Oct13,Oct25,Dec06,Dec10,Dec31 2022=Jan03,Feb16,Apr06,Apr13,Apr14,Apr15,May02,May16,Jul13,Jul28,Aug12,Oct13,Oct24,Dec05,Dec12 -2023=Jan02,Mar06,Apr06,Apr13,Apr14,May01,May04,May05,Jun05,Jul28,Aug01,Aug14,Oct13,Oct23,Dec05,Dec11 -2024=Jan01,Jan02,Feb26,Apr08,Apr15,Apr16,May01,May06,May22,Jul22,Jul29,Aug12,Oct14,Oct23,Dec05,Dec10,Dec31 +2023=Jan02,Mar06,Apr06,Apr13,Apr14,May01,May04,May05,Jun05,Jul28,Aug01,Aug14,Oct13,Oct23,Dec05,Dec11,Dec29 +2024=Jan01,Jan02,Feb26,Apr08,Apr15,Apr16,May01,May06,May22,Jul22,Jul29,Aug12,Oct14,Oct23,Dec05,Dec10,Dec30,Dec31 2025=Jan01,Feb12,Apr07,Apr14,Apr15,May01,May05,May12,Jul10,Jul28,Aug12,Oct13,Oct23,Dec05,Dec10,Dec31 2026=Jan01,Jan02,Mar03,Apr06,Apr13,Apr14,Apr15,May01,May04,Jun01,Jul28,Jul29,Aug12,Oct13,Oct23,Dec07,Dec10,Dec31 2027=Jan01,Feb22,Apr06,Apr13,Apr14,Apr15,May03,May04,May20,Jul19,Jul28,Aug12,Oct13,Oct25,Dec06,Dec10,Dec31 From 5ef41f3158f8c0108f309f778df5240e6d16b64c Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Mon, 5 Feb 2024 15:01:04 +0000 Subject: [PATCH 070/116] [maven-release-plugin] prepare release v2.12.34 --- examples/pom.xml | 6 +++++- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 678246d9b8..e60d95f2bb 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.34-SNAPSHOT + 2.12.34 jar Strata-Examples Example code to demonstrate use of Strata @@ -272,4 +272,8 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> + + + v2.12.34 + diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index dc6b47a804..bfaa7ab125 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.34-SNAPSHOT + 2.12.34 .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index b90902fde2..2b9d3b0459 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.34-SNAPSHOT + 2.12.34 .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 73cf3a7cb9..a2f67bf5d5 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.34-SNAPSHOT + 2.12.34 .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index db2156ed33..2a7fa983b5 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.34-SNAPSHOT + 2.12.34 .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 63c4b72463..b6c4df4c10 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.34-SNAPSHOT + 2.12.34 .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 185261ff88..019549a67a 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.34-SNAPSHOT + 2.12.34 .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 57e771d548..2ff808da55 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.34-SNAPSHOT + 2.12.34 .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 6a765ac9d5..87cd4ea74a 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.34-SNAPSHOT + 2.12.34 .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 4c0332a0f8..eb95f67817 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.34-SNAPSHOT + 2.12.34 pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.34 diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 679c43acfb..d804f48bde 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.34-SNAPSHOT + 2.12.34 .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index a00e8a2753..055feea1f2 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.34-SNAPSHOT + 2.12.34 .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index b7061fde78..0b23f6bde6 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.34-SNAPSHOT + 2.12.34 .. strata-report diff --git a/pom.xml b/pom.xml index 7766ffae5c..a3c76c4581 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.34-SNAPSHOT + 2.12.34 pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.34 From 07d7fbfbe6c7acb69f0dce960da1a9ceba9824cc Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Mon, 5 Feb 2024 15:01:05 +0000 Subject: [PATCH 071/116] [maven-release-plugin] prepare for next development iteration --- examples/pom.xml | 6 +----- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index e60d95f2bb..79a9099714 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.34 + 2.12.35-SNAPSHOT jar Strata-Examples Example code to demonstrate use of Strata @@ -272,8 +272,4 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> - - - v2.12.34 - diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index bfaa7ab125..b5663a8262 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.34 + 2.12.35-SNAPSHOT .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 2b9d3b0459..aa92e12b1e 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.34 + 2.12.35-SNAPSHOT .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index a2f67bf5d5..1c77d4900c 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.34 + 2.12.35-SNAPSHOT .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 2a7fa983b5..bf1750639a 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.34 + 2.12.35-SNAPSHOT .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index b6c4df4c10..219caaf877 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.34 + 2.12.35-SNAPSHOT .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 019549a67a..b56f2538f9 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.34 + 2.12.35-SNAPSHOT .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 2ff808da55..ad6d041d09 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.34 + 2.12.35-SNAPSHOT .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 87cd4ea74a..2b8d09e4ff 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.34 + 2.12.35-SNAPSHOT .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index eb95f67817..3d1c179d93 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.34 + 2.12.35-SNAPSHOT pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.34 + HEAD diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index d804f48bde..bff7a966ed 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.34 + 2.12.35-SNAPSHOT .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 055feea1f2..768771e94f 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.34 + 2.12.35-SNAPSHOT .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 0b23f6bde6..3c53cf5674 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.34 + 2.12.35-SNAPSHOT .. strata-report diff --git a/pom.xml b/pom.xml index a3c76c4581..32572675e3 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.34 + 2.12.35-SNAPSHOT pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.34 + HEAD From 720b23142e7447f493861076cee65a4e6cedb6c4 Mon Sep 17 00:00:00 2001 From: James White <118170713+James-OpenGamma@users.noreply.github.com> Date: Fri, 9 Feb 2024 15:16:39 +0000 Subject: [PATCH 072/116] Added to combine as map methods to value with failures (#2635) Co-authored-by: James White --- .../collect/result/ValueWithFailures.java | 72 +++++++++++++++++++ .../collect/result/ValueWithFailuresTest.java | 46 ++++++++++++ 2 files changed, 118 insertions(+) diff --git a/modules/collect/src/main/java/com/opengamma/strata/collect/result/ValueWithFailures.java b/modules/collect/src/main/java/com/opengamma/strata/collect/result/ValueWithFailures.java index a559fc1b39..3b0ecd796c 100644 --- a/modules/collect/src/main/java/com/opengamma/strata/collect/result/ValueWithFailures.java +++ b/modules/collect/src/main/java/com/opengamma/strata/collect/result/ValueWithFailures.java @@ -37,6 +37,7 @@ import com.google.common.collect.ImmutableCollection; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.opengamma.strata.collect.ArgChecker; @@ -232,6 +233,44 @@ public static BinaryOperator> combiningValues(BinaryOpe StreamBuilder::build); } + /** + * Returns a collector that can be used to create a combined {@code ValueWithFailure} + * from a stream of entries where the values contain {@code Result} instances. + *

    + * This collects a {@code Stream>>} to a {@code ValueWithFailures>}. + * + * @param the type of the map key + * @param the type of the success map values + * @throws IllegalArgumentException if duplicate keys are collected + * @return a {@link Collector} + */ + public static Collector>, ? , ValueWithFailures>> toCombinedResultsAsMap() { + return Collector.of( + () -> new MapStreamBuilder<>(ImmutableMap.builder()), + MapStreamBuilder::addResult, + MapStreamBuilder::combine, + MapStreamBuilder::build); + } + + /** + * Returns a collector that creates a combined {@code ValueWithFailure} from a stream + * of entries where the values contain {@code ValueWithFailure} instances. + *

    + * This collects a {@code Stream>} to a {@code ValueWithFailures>}. + * + * @param the type of the map key + * @param the type of the entry success values in the {@link ValueWithFailures} + * @throws IllegalArgumentException if duplicate keys are collected + * @return a {@link Collector} + */ + public static Collector>, ? , ValueWithFailures>> toCombinedValuesAsMap() { + return Collector.of( + () -> new MapStreamBuilder<>(ImmutableMap.builder()), + MapStreamBuilder::add, + MapStreamBuilder::combine, + MapStreamBuilder::build); + } + /** * Combines separate instances of {@code ValueWithFailure} into a single instance, * using a list to collect the values. @@ -315,6 +354,39 @@ private > ValueWithFailures build() { } } + private static final class MapStreamBuilder> { + + private final B values; + private final ImmutableList.Builder failures = ImmutableList.builder(); + + private MapStreamBuilder(B values) { + this.values = values; + } + + private void add(Map.Entry> item) { + values.put(item.getKey(), item.getValue().getValue()); + failures.addAll(item.getValue().getFailures()); + } + + private void addResult(Map.Entry> item) { + Result itemValue = item.getValue(); + itemValue.ifSuccess(value -> values.put(item.getKey(), value)); + itemValue.ifFailure(failure -> failures.addAll(failure.getItems())); + } + + private MapStreamBuilder combine(MapStreamBuilder builder) { + values.putAll(builder.values.build()); + failures.addAll(builder.failures.build()); + return this; + } + + // cast to the right collection type, can assume the methods in this class are using the correct types + @SuppressWarnings("unchecked") + private > ValueWithFailures build() { + return (ValueWithFailures) ValueWithFailures.of(values.buildOrThrow(), failures.build()); + } + } + //------------------------------------------------------------------------- /** * Checks if there are any failures. diff --git a/modules/collect/src/test/java/com/opengamma/strata/collect/result/ValueWithFailuresTest.java b/modules/collect/src/test/java/com/opengamma/strata/collect/result/ValueWithFailuresTest.java index f7421db040..e72498644e 100644 --- a/modules/collect/src/test/java/com/opengamma/strata/collect/result/ValueWithFailuresTest.java +++ b/modules/collect/src/test/java/com/opengamma/strata/collect/result/ValueWithFailuresTest.java @@ -13,14 +13,17 @@ import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.stream.Stream; import org.junit.jupiter.api.Test; import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.opengamma.strata.collect.Guavate; +import com.opengamma.strata.collect.MapStream; import com.opengamma.strata.collect.Messages; /** @@ -259,6 +262,49 @@ public void test_toCombinedResultsAsList() { assertThat(failures.get(0).getMessage()).isEqualTo("Uh oh"); } + @Test + public void test_toCombinedResultAsMap() { + Map> resultsMap = ImmutableMap.of( + "key 1", Result.success("success 1"), + "key 2", Result.failure(FAILURE1), + "key 3", Result.success("success 2")); + + ValueWithFailures> valuesWithFailures = MapStream.of(resultsMap) + .collect(ValueWithFailures.toCombinedResultsAsMap()); + + Map expectedResult = ImmutableMap.of( + "key 1", "success 1", + "key 3", "success 2"); + + assertThat(valuesWithFailures.getValue()).isEqualTo(expectedResult); + + assertThat(valuesWithFailures.getFailures()) + .singleElement() + .isEqualTo(FAILURE1); + } + + @Test + public void test_toCombinedValuesAsMap() { + Map> resultsMap = ImmutableMap.of( + "key 1", ValueWithFailures.of("success 1", FAILURE1), + "key 2", ValueWithFailures.of("success 2", FAILURE2), + "key 3", ValueWithFailures.of("success 3")); + + ValueWithFailures> valuesWithFailures = MapStream.of(resultsMap) + .collect(ValueWithFailures.toCombinedValuesAsMap()); + + Map expectedResult = ImmutableMap.of( + "key 1", "success 1", + "key 2", "success 2", + "key 3", "success 3"); + + assertThat(valuesWithFailures.getValue()).isEqualTo(expectedResult); + + assertThat(valuesWithFailures.getFailures()) + .hasSize(2) + .containsExactly(FAILURE1, FAILURE2); + } + @Test public void test_combineAsList() { ImmutableList> listOfValueWithFailures = Stream.of(5d, 6d, 7d) From 5c5fccd50702158eae93f131c9ad554b67eb77cb Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Tue, 13 Feb 2024 11:17:20 +0000 Subject: [PATCH 073/116] [maven-release-plugin] prepare release v2.12.35 --- examples/pom.xml | 6 +++++- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 79a9099714..ca8e00005b 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.35-SNAPSHOT + 2.12.35 jar Strata-Examples Example code to demonstrate use of Strata @@ -272,4 +272,8 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> + + + v2.12.35 + diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index b5663a8262..24f80159ee 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.35-SNAPSHOT + 2.12.35 .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index aa92e12b1e..04daf46e47 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.35-SNAPSHOT + 2.12.35 .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 1c77d4900c..dcfc92ae7a 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.35-SNAPSHOT + 2.12.35 .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index bf1750639a..f4c3425660 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.35-SNAPSHOT + 2.12.35 .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 219caaf877..e688e58936 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.35-SNAPSHOT + 2.12.35 .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index b56f2538f9..cbf61e34e8 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.35-SNAPSHOT + 2.12.35 .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index ad6d041d09..5756c60e16 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.35-SNAPSHOT + 2.12.35 .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 2b8d09e4ff..d9e0d65f8b 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.35-SNAPSHOT + 2.12.35 .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 3d1c179d93..cf439a78a4 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.35-SNAPSHOT + 2.12.35 pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.35 diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index bff7a966ed..6fd608302d 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.35-SNAPSHOT + 2.12.35 .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 768771e94f..8dd4dd7543 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.35-SNAPSHOT + 2.12.35 .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 3c53cf5674..78e642dd01 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.35-SNAPSHOT + 2.12.35 .. strata-report diff --git a/pom.xml b/pom.xml index 32572675e3..206cb4d012 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.35-SNAPSHOT + 2.12.35 pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.35 From 09c95a63d406f87ab7ac59113869a01f617e991e Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Tue, 13 Feb 2024 11:17:22 +0000 Subject: [PATCH 074/116] [maven-release-plugin] prepare for next development iteration --- examples/pom.xml | 6 +----- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index ca8e00005b..a6342f71af 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.35 + 2.12.36-SNAPSHOT jar Strata-Examples Example code to demonstrate use of Strata @@ -272,8 +272,4 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> - - - v2.12.35 - diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index 24f80159ee..e08c6d6740 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.35 + 2.12.36-SNAPSHOT .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 04daf46e47..2561a6a9cf 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.35 + 2.12.36-SNAPSHOT .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index dcfc92ae7a..28f7383fe4 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.35 + 2.12.36-SNAPSHOT .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index f4c3425660..2a10c31448 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.35 + 2.12.36-SNAPSHOT .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index e688e58936..68e3d94f38 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.35 + 2.12.36-SNAPSHOT .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index cbf61e34e8..e2933f4fa0 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.35 + 2.12.36-SNAPSHOT .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 5756c60e16..b732f153b4 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.35 + 2.12.36-SNAPSHOT .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index d9e0d65f8b..9c5cf09e5e 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.35 + 2.12.36-SNAPSHOT .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index cf439a78a4..46c60dfce1 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.35 + 2.12.36-SNAPSHOT pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.35 + HEAD diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 6fd608302d..1865ae37a8 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.35 + 2.12.36-SNAPSHOT .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 8dd4dd7543..32325a36a0 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.35 + 2.12.36-SNAPSHOT .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 78e642dd01..86547f4c0f 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.35 + 2.12.36-SNAPSHOT .. strata-report diff --git a/pom.xml b/pom.xml index 206cb4d012..a571b1df21 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.35 + 2.12.36-SNAPSHOT pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.35 + HEAD From 16f41103981b53a14530e9ed5da4cd6e842b36f7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Feb 2024 15:54:23 +0000 Subject: [PATCH 075/116] Bump org.assertj:assertj-core from 3.24.2 to 3.25.3 (#2632) Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.24.2 to 3.25.3. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.24.2...assertj-build-3.25.3) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pom.xml b/modules/pom.xml index 46c60dfce1..de8ba30204 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -763,7 +763,7 @@ ${project.basedir}/.. 9.5 - 3.24.2 + 3.25.3 1.6.Final 32.1.3-jre 26.0-jre From 5daac5d263fa2d9b15445938fcb5b96dd2752db9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 19 Feb 2024 17:16:57 +0000 Subject: [PATCH 076/116] Bump org.junit:junit-bom from 5.10.1 to 5.10.2 (#2631) Bumps [org.junit:junit-bom](https://github.com/junit-team/junit5) from 5.10.1 to 5.10.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.10.1...r5.10.2) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Stephen Colebourne --- modules/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pom.xml b/modules/pom.xml index de8ba30204..fb6c03a4b0 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -771,7 +771,7 @@ 2.2.3 2.10.0 ${joda-beans.version} - 5.10.1 + 5.10.2 4.9.0 1.7.36 From ca2b49b05c039e3ad1ddc8bc9be7f7a58c404073 Mon Sep 17 00:00:00 2001 From: Stephen Colebourne Date: Tue, 20 Feb 2024 08:41:16 +0000 Subject: [PATCH 077/116] Provide the ability to capture an OutputStream (#2636) * Add method that allows an `OutputStream` to be captured * Uses `ByteArrayOutputStream` internally --- .../strata/collect/io/ArrayByteSource.java | 23 +++++++++++++++++++ .../collect/io/ArrayByteSourceTest.java | 22 ++++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/modules/collect/src/main/java/com/opengamma/strata/collect/io/ArrayByteSource.java b/modules/collect/src/main/java/com/opengamma/strata/collect/io/ArrayByteSource.java index aaf06c4939..a215cc9a2f 100644 --- a/modules/collect/src/main/java/com/opengamma/strata/collect/io/ArrayByteSource.java +++ b/modules/collect/src/main/java/com/opengamma/strata/collect/io/ArrayByteSource.java @@ -8,6 +8,7 @@ import static com.google.common.base.Preconditions.checkArgument; import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -50,6 +51,7 @@ import com.google.common.primitives.Bytes; import com.opengamma.strata.collect.ArgChecker; import com.opengamma.strata.collect.Unchecked; +import com.opengamma.strata.collect.function.CheckedConsumer; import com.opengamma.strata.collect.function.CheckedSupplier; /** @@ -295,6 +297,27 @@ public static ArrayByteSource from(InputStream inputStream, int expectedSize) th return new ArrayByteSource(result); } + //------------------------------------------------------------------------- + /** + * Obtains an instance that captures the contents of an output stream. + *

    + * This method provides an output stream. + * When bytes are written to the output stream, they are captured in the resulting byte source. + * The caller is not responsible for closing the stream. + * + * @param handler the handler that writes to the output stream + * @return the byte source + * @throws UncheckedIOException if an IO error occurs + */ + public static ArrayByteSource fromOutput(CheckedConsumer handler) { + return Unchecked.wrap(() -> { + try (ByteArrayOutputStream baos = new ByteArrayOutputStream(1024)) { + handler.accept(baos); + return new ArrayByteSource(baos.toByteArray()); + } + }); + } + //------------------------------------------------------------------------- /** * Obtains an instance from a base-64 encoded string. diff --git a/modules/collect/src/test/java/com/opengamma/strata/collect/io/ArrayByteSourceTest.java b/modules/collect/src/test/java/com/opengamma/strata/collect/io/ArrayByteSourceTest.java index daba31fa4e..496d926140 100644 --- a/modules/collect/src/test/java/com/opengamma/strata/collect/io/ArrayByteSourceTest.java +++ b/modules/collect/src/test/java/com/opengamma/strata/collect/io/ArrayByteSourceTest.java @@ -13,6 +13,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; import java.io.UncheckedIOException; import java.net.MalformedURLException; import java.nio.charset.StandardCharsets; @@ -29,6 +30,7 @@ import com.google.common.io.Files; import com.google.common.io.MoreFiles; import com.google.common.io.Resources; +import com.opengamma.strata.collect.function.CheckedConsumer; import com.opengamma.strata.collect.function.CheckedSupplier; /** @@ -242,6 +244,26 @@ public void test_from_InputStream_sizeTooBig() throws IOException { assertThat(test.read()).containsExactly(1, 2, 3, 4, 5); } + //------------------------------------------------------------------------- + @Test + public void test_fromOutput_Consumer() { + byte[] bytes = new byte[] {1, 2, 3}; + ArrayByteSource test = ArrayByteSource.fromOutput(outputStream -> outputStream.write(bytes)); + assertThat(test.size()).isEqualTo(3); + assertThat(test.getFileName()).isEmpty(); + assertThat(test.read()[0]).isEqualTo((byte) 1); + assertThat(test.read()[1]).isEqualTo((byte) 2); + assertThat(test.read()[2]).isEqualTo((byte) 3); + } + + @Test + public void test_fromOutput_ConsumerExceptionOnWrite() { + CheckedConsumer consumer = out -> { + throw new IOException(); + }; + assertThatExceptionOfType(UncheckedIOException.class).isThrownBy(() -> ArrayByteSource.fromOutput(consumer)); + } + //------------------------------------------------------------------------- @Test public void test_withFileName() { From b3539368410107a88a598baf57f66136c72809a4 Mon Sep 17 00:00:00 2001 From: Stephen Colebourne Date: Fri, 23 Feb 2024 10:27:46 +0000 Subject: [PATCH 078/116] Additional try-catch wrappers (#2637) * tryCatchToOptional() that allows the exception to be observed * inTryCatchIgnore() that allows ignoring exceptions in for-each --- .../com/opengamma/strata/collect/Guavate.java | 68 +++++++++++++++++-- .../opengamma/strata/collect/GuavateTest.java | 42 ++++++++++++ 2 files changed, 105 insertions(+), 5 deletions(-) diff --git a/modules/collect/src/main/java/com/opengamma/strata/collect/Guavate.java b/modules/collect/src/main/java/com/opengamma/strata/collect/Guavate.java index 4bd0894fff..5d5c73e606 100644 --- a/modules/collect/src/main/java/com/opengamma/strata/collect/Guavate.java +++ b/modules/collect/src/main/java/com/opengamma/strata/collect/Guavate.java @@ -51,6 +51,7 @@ import com.google.common.collect.Lists; import com.google.common.collect.MoreCollectors; import com.google.common.util.concurrent.ThreadFactoryBuilder; +import com.opengamma.strata.collect.function.CheckedSupplier; import com.opengamma.strata.collect.tuple.ObjIntPair; import com.opengamma.strata.collect.tuple.Pair; @@ -201,17 +202,43 @@ public static ImmutableMap combineMapsOverwriting( /** * Wraps a try-catch block around an expression, avoiding exceptions. *

    - * This converts an exception throwing method into an optional returning one by discarding the exception. - * In most cases it is better to add a `findXxx()` method to the code you want to call. + * This converts an exception throwing method into a method that returns an optional by discarding the exception. + * In most cases it is better to write a `findXxx()` or 'tryXxx()' method to the code you want to call. + *

    + * To handle checked exceptions, use {@link Unchecked#supplier(CheckedSupplier)}. * * @param the type of the result in the optional - * @param supplier the supplier that might throw an exception + * @param resultSupplier the supplier that might throw an exception + * @return the value wrapped in an optional, empty if the method returns null or an exception is thrown + */ + public static Optional tryCatchToOptional(Supplier resultSupplier) { + try { + return Optional.ofNullable(resultSupplier.get()); + } catch (RuntimeException ex) { + return Optional.empty(); + } + } + + /** + * Wraps a try-catch block around an expression, avoiding exceptions. + *

    + * This variant allows the exception to be observed, such as for logging. + *

    + * This converts an exception throwing method into a method that returns an optional by discarding the exception. + * In most cases it is better to write a `findXxx()` or 'tryXxx()' method to the code you want to call. + *

    + * To handle checked exceptions, use {@link Unchecked#supplier(CheckedSupplier)}. + * + * @param the type of the result in the optional + * @param resultSupplier the supplier that might throw an exception + * @param exceptionHandler the exception handler * @return the value wrapped in an optional, empty if the method returns null or an exception is thrown */ - public static Optional tryCatchToOptional(Supplier supplier) { + public static Optional tryCatchToOptional(Supplier resultSupplier, Consumer exceptionHandler) { try { - return Optional.ofNullable(supplier.get()); + return Optional.ofNullable(resultSupplier.get()); } catch (RuntimeException ex) { + exceptionHandler.accept(ex); return Optional.empty(); } } @@ -484,6 +511,37 @@ public static Iterable inNullable(T nullable) { } } + /** + * Converts an expression for use in the for-each statement wrapping it with a try-catch block to avoid exceptions. + *

    + * This allows a method that throws an exception to be used with the for-each statement. + * In most cases it is better to write a `findXxx()` or 'tryXxx()' method to the code you want to call. + * The typical use case is for parsing, where the parser throws an exception if invalid. + *

    + * This method is intended for use with the for-each statement: + *

    + *

    +   *  for (Item item : inTryCatchIgnore(() -> parse(str))) {
    +   *    // use the value, code not called if parse(str) threw an exception
    +   *  }
    +   * 
    + *

    + * NOTE: This method is intended only for use with the for-each statement. + * It does in fact return a general purpose {@code Iterable}, but the method name + * is focussed on the for-each use case. + * + * @param the type of the result in the optional + * @param supplier the supplier that might throw an exception + * @return the value wrapped in an optional, empty if the method returns null or an exception is thrown + */ + public static Iterable inTryCatchIgnore(Supplier supplier) { + try { + return inNullable(supplier.get()); + } catch (RuntimeException ex) { + return ImmutableList.of(); + } + } + //------------------------------------------------------------------------- /** * Creates a stream that wraps a stream with the index. diff --git a/modules/collect/src/test/java/com/opengamma/strata/collect/GuavateTest.java b/modules/collect/src/test/java/com/opengamma/strata/collect/GuavateTest.java index 97945f95cd..7c349ef250 100644 --- a/modules/collect/src/test/java/com/opengamma/strata/collect/GuavateTest.java +++ b/modules/collect/src/test/java/com/opengamma/strata/collect/GuavateTest.java @@ -18,6 +18,7 @@ import java.time.Duration; import java.time.LocalDate; +import java.time.format.DateTimeParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; @@ -36,6 +37,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Consumer; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -163,6 +165,18 @@ public void test_tryCatchToOptional() { assertThat(Guavate.tryCatchToOptional(() -> LocalDate.parse("XXX"))).isEmpty(); } + @Test + public void test_tryCatchToOptional_observed() { + List extracted = new ArrayList<>(); + Consumer handler = ex -> extracted.add(ex); + assertThat(Guavate.tryCatchToOptional(() -> LocalDate.parse("2020-06-01"), handler)).hasValue(LocalDate.of(2020, 6, 1)); + assertThat(extracted).isEmpty(); + assertThat(Guavate.tryCatchToOptional(() -> null, handler)).isEmpty(); + assertThat(extracted).isEmpty(); + assertThat(Guavate.tryCatchToOptional(() -> LocalDate.parse("XXX"), handler)).isEmpty(); + assertThat(extracted).singleElement().isInstanceOf(DateTimeParseException.class); + } + //------------------------------------------------------------------------- @Test public void test_firstNonEmpty_supplierMatch1() { @@ -308,6 +322,34 @@ public void test_inNullable_null() { assertThat(extracted).isEmpty(); } + @Test + public void test_inTryCatchIgnore_present() { + List extracted = new ArrayList<>(); + for (String str : Guavate.inTryCatchIgnore(() -> "a")) { + extracted.add(str); + } + assertThat(extracted).containsExactly("a"); + } + + @Test + public void test_inTryCatchIgnore_null() { + List extracted = new ArrayList<>(); + Supplier supplier = () -> null; + for (String str : Guavate.inTryCatchIgnore(supplier)) { + extracted.add(str); + } + assertThat(extracted).isEmpty(); + } + + @Test + public void test_inTryCatchIgnore_exception() { + List extracted = new ArrayList<>(); + for (LocalDate str : Guavate.inTryCatchIgnore(() -> LocalDate.parse("XXX"))) { + extracted.add(str); + } + assertThat(extracted).isEmpty(); + } + //------------------------------------------------------------------------- @Test public void test_zipWithIndex() { From 2af390ca8aeea3dd59df46ec6f89087964e1d494 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Tue, 5 Mar 2024 10:16:52 +0000 Subject: [PATCH 079/116] [maven-release-plugin] prepare release v2.12.36 --- examples/pom.xml | 6 +++++- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index a6342f71af..03351c66d4 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.36-SNAPSHOT + 2.12.36 jar Strata-Examples Example code to demonstrate use of Strata @@ -272,4 +272,8 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> + + + v2.12.36 + diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index e08c6d6740..c30aa296dd 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.36-SNAPSHOT + 2.12.36 .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 2561a6a9cf..9538250781 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.36-SNAPSHOT + 2.12.36 .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 28f7383fe4..38abc30494 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.36-SNAPSHOT + 2.12.36 .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 2a10c31448..c2a479168e 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.36-SNAPSHOT + 2.12.36 .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 68e3d94f38..a469a454a8 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.36-SNAPSHOT + 2.12.36 .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index e2933f4fa0..a432cbba2e 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.36-SNAPSHOT + 2.12.36 .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index b732f153b4..21b6ecfbbf 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.36-SNAPSHOT + 2.12.36 .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 9c5cf09e5e..2c4c34b097 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.36-SNAPSHOT + 2.12.36 .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index fb6c03a4b0..05066e6324 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.36-SNAPSHOT + 2.12.36 pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.36 diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 1865ae37a8..1cf5bae288 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.36-SNAPSHOT + 2.12.36 .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 32325a36a0..9e39a37c1c 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.36-SNAPSHOT + 2.12.36 .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 86547f4c0f..7af4986229 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.36-SNAPSHOT + 2.12.36 .. strata-report diff --git a/pom.xml b/pom.xml index a571b1df21..84670eb9bc 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.36-SNAPSHOT + 2.12.36 pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.36 From b30cfd9ff270f3226950e1bad75286fe206d108d Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Tue, 5 Mar 2024 10:16:53 +0000 Subject: [PATCH 080/116] [maven-release-plugin] prepare for next development iteration --- examples/pom.xml | 6 +----- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 03351c66d4..4df97cb1c7 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.36 + 2.12.37-SNAPSHOT jar Strata-Examples Example code to demonstrate use of Strata @@ -272,8 +272,4 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> - - - v2.12.36 - diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index c30aa296dd..e44801fe46 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.36 + 2.12.37-SNAPSHOT .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 9538250781..f4045230b3 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.36 + 2.12.37-SNAPSHOT .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 38abc30494..2b1934ea90 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.36 + 2.12.37-SNAPSHOT .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index c2a479168e..6c739eb804 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.36 + 2.12.37-SNAPSHOT .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index a469a454a8..15906decf4 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.36 + 2.12.37-SNAPSHOT .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index a432cbba2e..c8d59f54b7 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.36 + 2.12.37-SNAPSHOT .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 21b6ecfbbf..98cea7d00a 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.36 + 2.12.37-SNAPSHOT .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 2c4c34b097..62a9a225da 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.36 + 2.12.37-SNAPSHOT .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 05066e6324..c2cb286384 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.36 + 2.12.37-SNAPSHOT pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.36 + HEAD diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 1cf5bae288..45acbee5cb 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.36 + 2.12.37-SNAPSHOT .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 9e39a37c1c..8ce7900426 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.36 + 2.12.37-SNAPSHOT .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 7af4986229..3a5a77dfa8 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.36 + 2.12.37-SNAPSHOT .. strata-report diff --git a/pom.xml b/pom.xml index 84670eb9bc..a1ffda516a 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.36 + 2.12.37-SNAPSHOT pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.36 + HEAD From e4ad3958eb21d341c0f8d4e4350c2d4398f2ce77 Mon Sep 17 00:00:00 2001 From: Brian Weller Date: Tue, 19 Mar 2024 08:47:11 +0000 Subject: [PATCH 081/116] Remove redundant check in CurrencyAmount.negated() (#2639) * Remove redundant check in CurrencyAmount.negated() This is already handled in the constructor * Remove comment --------- Co-authored-by: Brian Weller --- .../com/opengamma/strata/basics/currency/CurrencyAmount.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/basics/src/main/java/com/opengamma/strata/basics/currency/CurrencyAmount.java b/modules/basics/src/main/java/com/opengamma/strata/basics/currency/CurrencyAmount.java index cf3c7e4171..5298c0a2b0 100644 --- a/modules/basics/src/main/java/com/opengamma/strata/basics/currency/CurrencyAmount.java +++ b/modules/basics/src/main/java/com/opengamma/strata/basics/currency/CurrencyAmount.java @@ -314,8 +314,7 @@ public boolean isNegative() { * @return an amount based on this with the amount negated */ public CurrencyAmount negated() { - // Zero is treated as a special case to avoid creating -0.0 which produces surprising equality behaviour - return new CurrencyAmount(currency, amount == 0d ? 0d : -amount); + return new CurrencyAmount(currency, -amount); } /** From 41972390957f10fdedf6bae17559e8a969aa4b64 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Mar 2024 08:48:11 +0000 Subject: [PATCH 082/116] Bump com.ragedunicorn.tools.maven:github-release-maven-plugin (#2621) Bumps [com.ragedunicorn.tools.maven:github-release-maven-plugin](https://github.com/RagedUnicorn/github-release-maven-plugin) from 1.0.6 to 1.0.7. - [Release notes](https://github.com/RagedUnicorn/github-release-maven-plugin/releases) - [Changelog](https://github.com/RagedUnicorn/github-release-maven-plugin/blob/master/RELEASE.md) - [Commits](https://github.com/RagedUnicorn/github-release-maven-plugin/compare/v1.0.6...v1.0.7) --- updated-dependencies: - dependency-name: com.ragedunicorn.tools.maven:github-release-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index a1ffda516a..86251cf27b 100644 --- a/pom.xml +++ b/pom.xml @@ -100,7 +100,7 @@ com.ragedunicorn.tools.maven github-release-maven-plugin - 1.0.6 + 1.0.7 OpenGamma Strata From 4b912f23b87f9d558c4c1ceab7558b9ae9550d61 Mon Sep 17 00:00:00 2001 From: Stephen Colebourne Date: Thu, 4 Apr 2024 13:27:51 +0100 Subject: [PATCH 083/116] Additional utility methods (#2641) * Get an optional from a list returning empty if multiple elements * Query exchange ID from ETD ID without the baggage --- .../com/opengamma/strata/collect/Guavate.java | 66 ++++++++++++++++++- .../opengamma/strata/collect/GuavateTest.java | 20 +++++- .../strata/product/etd/EtdIdUtils.java | 30 +++++++++ .../strata/product/etd/EtdIdUtilsTest.java | 15 +++++ 4 files changed, 129 insertions(+), 2 deletions(-) diff --git a/modules/collect/src/main/java/com/opengamma/strata/collect/Guavate.java b/modules/collect/src/main/java/com/opengamma/strata/collect/Guavate.java index 5d5c73e606..d5a90ada35 100644 --- a/modules/collect/src/main/java/com/opengamma/strata/collect/Guavate.java +++ b/modules/collect/src/main/java/com/opengamma/strata/collect/Guavate.java @@ -20,6 +20,7 @@ import java.util.OptionalDouble; import java.util.OptionalInt; import java.util.OptionalLong; +import java.util.Set; import java.util.Spliterator; import java.util.Spliterators; import java.util.TreeMap; @@ -27,6 +28,7 @@ import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; +import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.BinaryOperator; import java.util.function.Consumer; @@ -305,6 +307,18 @@ public static Optional first(Iterable iterable) { return it.hasNext() ? Optional.of(it.next()) : Optional.empty(); } + /** + * Gets the only element from the collection, returning empty if the collection is empty or has more than one element. + * + * @param the type of element in the optional + * @param iterable the iterable to query + * @return the first value, empty if empty or more than one element + */ + public static Optional only(Iterable iterable) { + Iterator it = iterable.iterator(); + return it.hasNext() ? Optional.of(it.next()).filter(element -> !it.hasNext()) : Optional.empty(); + } + //------------------------------------------------------------------------- /** * Creates a single {@code Map.Entry}. @@ -762,12 +776,62 @@ public static Function, Stream> filteringOptional() { * The collector throws {@code NullPointerException} if the stream consists of a null element. * * @param the type of element in the list - * @return the immutable list collector + * @return the optional collector */ public static Collector> toOptional() { return MoreCollectors.toOptional(); } + /** + * Collector used at the end of a stream to extract one element. + *

    + * A collector is used to gather data at the end of a stream operation. + * This method returns a collector allowing streams to be gathered into an {@link Optional}. + * The collector throws {@code NullPointerException} if the stream consists of a null element. + * The collector returns empty if the stream consists of zero, two or more elements. + * + * @param the type of element in the list + * @return the collector + */ + public static Collector> toOnly() { + return new OnlyCollector(); + } + + static class OnlyCollector implements Collector, Optional> { + private T value; + private int count; + + @Override + public Supplier> supplier() { + return () -> this; + } + + @Override + public BiConsumer, T> accumulator() { + return (state, value) -> { + state.value = value; + state.count++; + }; + } + + @Override + public BinaryOperator> combiner() { + return (a, b) -> { + throw new UnsupportedOperationException("OnlyCollector does not support parallel processing"); + }; + } + + @Override + public Function, Optional> finisher() { + return state -> state.count == 1 ? Optional.of(state.value) : Optional.empty(); + } + + @Override + public Set characteristics() { + return ImmutableSet.of(); + } + } + /** * Collector used at the end of a stream to build an immutable list. *

    diff --git a/modules/collect/src/test/java/com/opengamma/strata/collect/GuavateTest.java b/modules/collect/src/test/java/com/opengamma/strata/collect/GuavateTest.java index 7c349ef250..176748dfa9 100644 --- a/modules/collect/src/test/java/com/opengamma/strata/collect/GuavateTest.java +++ b/modules/collect/src/test/java/com/opengamma/strata/collect/GuavateTest.java @@ -224,11 +224,19 @@ public void test_firstNonEmpty_optionalMatchNone() { //------------------------------------------------------------------------- @Test public void test_first() { - assertThat(Guavate.first(ImmutableSet.of())).isEqualTo(Optional.empty()); + assertThat(Guavate.first(ImmutableSet.of())).isEmpty(); assertThat(Guavate.first(ImmutableSet.of("a"))).hasValue("a"); assertThat(Guavate.first(ImmutableSet.of("a", "b"))).hasValue("a"); } + //------------------------------------------------------------------------- + @Test + public void test_only() { + assertThat(Guavate.only(ImmutableSet.of())).isEmpty(); + assertThat(Guavate.only(ImmutableSet.of("a"))).hasValue("a"); + assertThat(Guavate.only(ImmutableSet.of("a", "b"))).isEmpty(); + } + //------------------------------------------------------------------------- @Test public void test_list() { @@ -456,6 +464,16 @@ public void test_toOptional() { assertThatNullPointerException().isThrownBy(() -> Stream.of((String[]) null).collect(Guavate.toOptional())); } + //------------------------------------------------------------------------- + @Test + public void test_toOnly() { + List list = Arrays.asList("a", "ab"); + assertThat(list.stream().filter(s -> s.length() == 1).collect(Guavate.toOnly())).hasValue("a"); + assertThat(list.stream().filter(s -> s.length() == 0).collect(Guavate.toOnly())).isEmpty(); + assertThat(list.stream().collect(Guavate.toOnly())).isEmpty(); + assertThatNullPointerException().isThrownBy(() -> Stream.of((String[]) null).collect(Guavate.toOnly())); + } + //------------------------------------------------------------------------- @Test public void test_toImmutableList() { diff --git a/modules/product/src/main/java/com/opengamma/strata/product/etd/EtdIdUtils.java b/modules/product/src/main/java/com/opengamma/strata/product/etd/EtdIdUtils.java index d88b2cd103..b46e195b54 100644 --- a/modules/product/src/main/java/com/opengamma/strata/product/etd/EtdIdUtils.java +++ b/modules/product/src/main/java/com/opengamma/strata/product/etd/EtdIdUtils.java @@ -347,6 +347,36 @@ public static SplitEtdId splitId(SecurityId securityId) { } } + /** + * Splits an OG-ETD identifier to obtain the exchange ID. + * + * @param securityId the security ID + * @return the exchange ID + * @throws IllegalArgumentException if the ID is not of the right scheme or format + */ + public static ExchangeId splitIdToExchangeId(SecurityId securityId) { + ArgChecker.notNull(securityId, "securityId"); + StandardId standardId = securityId.getStandardId(); + if (!standardId.getScheme().equals(ETD_SCHEME)) { + throw new IllegalArgumentException("ETD ID cannot be parsed: " + securityId); + } + + Matcher matcher = SECURITY_ID_PATTERN.matcher(standardId.getValue()); + if (!matcher.matches()) { + throw new IllegalArgumentException("ETD ID cannot be parsed: " + securityId); + } + + // Example: F-IFEN-ABC or F-IFEN-ABC-XYZ + String contractDetailsSubstring = matcher.group(CONTRACT_DETAILS_REGEX_GROUP_NAME); + List contractDetailsSplit = Splitter.on('-').limit(3).splitToList(contractDetailsSubstring); + if (contractDetailsSplit.size() != 3) { + throw new IllegalArgumentException("ETD ID cannot be parsed: " + securityId); + } + + // common fields + return ExchangeId.of(contractDetailsSplit.get(1)); + } + // parses an option private static SplitEtdOption parseEtdOptionId(List optionDetailsSplit, SecurityId securityId) { String versionStr = optionDetailsSplit.get(0); diff --git a/modules/product/src/test/java/com/opengamma/strata/product/etd/EtdIdUtilsTest.java b/modules/product/src/test/java/com/opengamma/strata/product/etd/EtdIdUtilsTest.java index 72f4b04522..d96b83b5fa 100644 --- a/modules/product/src/test/java/com/opengamma/strata/product/etd/EtdIdUtilsTest.java +++ b/modules/product/src/test/java/com/opengamma/strata/product/etd/EtdIdUtilsTest.java @@ -121,6 +121,7 @@ public void test_futureId_monthly() { .expiry(EXPIRY) .variant(MONTHLY) .build()); + assertThat(EtdIdUtils.splitIdToExchangeId(test)).isEqualTo(ExchangeIds.ECAG); } @Test @@ -135,6 +136,7 @@ public void test_futureIdWithExtraHyphen_monthly() { .expiry(EXPIRY) .variant(MONTHLY) .build()); + assertThat(EtdIdUtils.splitIdToExchangeId(test)).isEqualTo(ExchangeIds.XNSE); } @Test @@ -150,6 +152,7 @@ public void test_futureId_weekly() { .expiry(EXPIRY) .variant(variant) .build()); + assertThat(EtdIdUtils.splitIdToExchangeId(test)).isEqualTo(ExchangeIds.ECAG); } @Test @@ -165,6 +168,7 @@ public void test_futureId_daily() { .expiry(EXPIRY) .variant(variant) .build()); + assertThat(EtdIdUtils.splitIdToExchangeId(test)).isEqualTo(ExchangeIds.ECAG); } @Test @@ -180,6 +184,7 @@ public void test_futureId_flex() { .expiry(EXPIRY) .variant(variant) .build()); + assertThat(EtdIdUtils.splitIdToExchangeId(test)).isEqualTo(ExchangeIds.ECAG); } //------------------------------------------------------------------------- @@ -196,6 +201,7 @@ public void test_optionId_monthly() { .variant(MONTHLY) .option(SplitEtdOption.of(0, PutCall.PUT, 12.34)) .build()); + assertThat(EtdIdUtils.splitIdToExchangeId(test)).isEqualTo(ExchangeIds.ECAG); } @Test @@ -213,6 +219,7 @@ public void test_optionId_weekly() { .variant(variant) .option(SplitEtdOption.of(0, PutCall.CALL, -1.45)) .build()); + assertThat(EtdIdUtils.splitIdToExchangeId(test)).isEqualTo(ExchangeIds.ECAG); } @Test @@ -230,6 +237,7 @@ public void test_optionId_daily9_version() { .variant(variant) .option(SplitEtdOption.of(3, PutCall.PUT, 12.34)) .build()); + assertThat(EtdIdUtils.splitIdToExchangeId(test)).isEqualTo(ExchangeIds.ECAG); } @Test @@ -247,6 +255,7 @@ public void test_optionId_daily21_version() { .variant(variant) .option(SplitEtdOption.of(11, PutCall.PUT, 12.34)) .build()); + assertThat(EtdIdUtils.splitIdToExchangeId(test)).isEqualTo(ExchangeIds.ECAG); } //------------------------------------------------------------------------- @@ -265,6 +274,7 @@ public void test_optionIdUnderlying_monthly() { .variant(MONTHLY) .option(SplitEtdOption.of(0, PutCall.PUT, 12.34, underlyingMonth)) .build()); + assertThat(EtdIdUtils.splitIdToExchangeId(test)).isEqualTo(ExchangeIds.ECAG); } @Test @@ -282,6 +292,7 @@ public void test_optionIdUnderlyingWithHyphen_monthly() { .variant(MONTHLY) .option(SplitEtdOption.of(0, PutCall.PUT, 12.34, underlyingMonth)) .build()); + assertThat(EtdIdUtils.splitIdToExchangeId(test)).isEqualTo(ExchangeIds.XNSE); } @Test @@ -298,6 +309,7 @@ public void test_optionIdUnderlying_monthlySameMonth() { .variant(MONTHLY) .option(SplitEtdOption.of(0, PutCall.PUT, 12.34)) .build()); + assertThat(EtdIdUtils.splitIdToExchangeId(test)).isEqualTo(ExchangeIds.ECAG); } @Test @@ -316,6 +328,7 @@ public void test_optionIdUnderlying_weekly() { .variant(variant) .option(SplitEtdOption.of(0, PutCall.CALL, -1.45, underlyingMonth)) .build()); + assertThat(EtdIdUtils.splitIdToExchangeId(test)).isEqualTo(ExchangeIds.ECAG); } @Test @@ -334,6 +347,7 @@ public void test_optionIdUnderlying_daily9_version() { .variant(variant) .option(SplitEtdOption.of(3, PutCall.PUT, 12.34, underlyingMonth)) .build()); + assertThat(EtdIdUtils.splitIdToExchangeId(test)).isEqualTo(ExchangeIds.ECAG); } @Test @@ -352,6 +366,7 @@ public void test_optionIdUnderlying_daily21_version() { .variant(variant) .option(SplitEtdOption.of(11, PutCall.PUT, 12.34, underlyingMonth)) .build()); + assertThat(EtdIdUtils.splitIdToExchangeId(test)).isEqualTo(ExchangeIds.ECAG); } //------------------------------------------------------------------------- From 9b9d3468fa30577a199bb569b6fc29c1f835f400 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Thu, 4 Apr 2024 12:29:30 +0000 Subject: [PATCH 084/116] [maven-release-plugin] prepare release v2.12.37 --- examples/pom.xml | 6 +++++- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 4df97cb1c7..91ce72622c 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.37-SNAPSHOT + 2.12.37 jar Strata-Examples Example code to demonstrate use of Strata @@ -272,4 +272,8 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> + + + v2.12.37 + diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index e44801fe46..0112422051 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.37-SNAPSHOT + 2.12.37 .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index f4045230b3..8749e27f82 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.37-SNAPSHOT + 2.12.37 .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 2b1934ea90..6b7ceeade5 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.37-SNAPSHOT + 2.12.37 .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 6c739eb804..f4860db3a8 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.37-SNAPSHOT + 2.12.37 .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 15906decf4..82d701381f 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.37-SNAPSHOT + 2.12.37 .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index c8d59f54b7..2bbfd4fb40 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.37-SNAPSHOT + 2.12.37 .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 98cea7d00a..87da859a69 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.37-SNAPSHOT + 2.12.37 .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 62a9a225da..d3d3e35fb6 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.37-SNAPSHOT + 2.12.37 .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index c2cb286384..03b56bec22 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.37-SNAPSHOT + 2.12.37 pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.37 diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 45acbee5cb..c64fe86252 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.37-SNAPSHOT + 2.12.37 .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 8ce7900426..8c17ed8adc 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.37-SNAPSHOT + 2.12.37 .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 3a5a77dfa8..0e2d8f25ae 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.37-SNAPSHOT + 2.12.37 .. strata-report diff --git a/pom.xml b/pom.xml index 86251cf27b..7904a94fde 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.37-SNAPSHOT + 2.12.37 pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.37 From 4a8a06bebeeb0a43850af61ead225f8d616e54ae Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Thu, 4 Apr 2024 12:29:32 +0000 Subject: [PATCH 085/116] [maven-release-plugin] prepare for next development iteration --- examples/pom.xml | 6 +----- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 91ce72622c..70525533ac 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.37 + 2.12.38-SNAPSHOT jar Strata-Examples Example code to demonstrate use of Strata @@ -272,8 +272,4 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> - - - v2.12.37 - diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index 0112422051..b5ce91cdad 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.37 + 2.12.38-SNAPSHOT .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 8749e27f82..d7d822d4e3 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.37 + 2.12.38-SNAPSHOT .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 6b7ceeade5..ba18e5a3dd 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.37 + 2.12.38-SNAPSHOT .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index f4860db3a8..826026eab0 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.37 + 2.12.38-SNAPSHOT .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 82d701381f..07bc5a8add 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.37 + 2.12.38-SNAPSHOT .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 2bbfd4fb40..4332739800 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.37 + 2.12.38-SNAPSHOT .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 87da859a69..1c4e7e4579 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.37 + 2.12.38-SNAPSHOT .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index d3d3e35fb6..668579b79e 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.37 + 2.12.38-SNAPSHOT .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 03b56bec22..f18b1b5639 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.37 + 2.12.38-SNAPSHOT pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.37 + HEAD diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index c64fe86252..a0dce07d66 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.37 + 2.12.38-SNAPSHOT .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 8c17ed8adc..6d21e1e4fe 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.37 + 2.12.38-SNAPSHOT .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 0e2d8f25ae..0571a228df 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.37 + 2.12.38-SNAPSHOT .. strata-report diff --git a/pom.xml b/pom.xml index 7904a94fde..324524e653 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.37 + 2.12.38-SNAPSHOT pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.37 + HEAD From ffddbebde877df4464f2cf6a1d3ae4f8c67215c5 Mon Sep 17 00:00:00 2001 From: Yuki Iwashita Date: Mon, 22 Apr 2024 16:13:52 +0100 Subject: [PATCH 086/116] Swaption Volatility Cube (#2642) --- .../opengamma/strata/market/cube/Cube.java | 163 ++++ .../strata/market/cube/CubeInfoType.java | 70 ++ .../strata/market/cube/CubeMetadata.java | 171 ++++ .../strata/market/cube/CubeName.java | 64 ++ .../opengamma/strata/market/cube/Cubes.java | 62 ++ .../market/cube/DefaultCubeMetadata.java | 677 +++++++++++++ .../cube/DefaultCubeMetadataBuilder.java | 268 ++++++ .../market/cube/InterpolatedNodalCube.java | 860 +++++++++++++++++ .../strata/market/cube/NodalCube.java | 121 +++ .../cube/SimpleCubeParameterMetadata.java | 507 ++++++++++ .../interpolator/BoundCubeInterpolator.java | 64 ++ .../cube/interpolator/CubeInterpolator.java | 33 + .../interpolator/GridCubeInterpolator.java | 900 ++++++++++++++++++ .../TenorTenorStrikeParameterMetadata.java | 431 +++++++++ .../strata/market/cube/CubeInfoTypeTest.java | 38 + .../strata/market/cube/CubeNameTest.java | 26 + .../strata/market/cube/CubesTest.java | 51 + .../market/cube/DefaultCubeMetadataTest.java | 207 ++++ .../cube/InterpolatedNodalCubeTest.java | 222 +++++ .../cube/SimpleCubeParameterMetadataTest.java | 54 ++ .../GridCubeInterpolatorTest.java | 233 +++++ ...TenorTenorStrikeParameterMetadataTest.java | 108 +++ ...SwaptionExpiryTenorStrikeVolatilities.java | 571 +++++++++++ ...tionExpiryTenorStrikeVolatilitiesTest.java | 212 +++++ 24 files changed, 6113 insertions(+) create mode 100644 modules/market/src/main/java/com/opengamma/strata/market/cube/Cube.java create mode 100644 modules/market/src/main/java/com/opengamma/strata/market/cube/CubeInfoType.java create mode 100644 modules/market/src/main/java/com/opengamma/strata/market/cube/CubeMetadata.java create mode 100644 modules/market/src/main/java/com/opengamma/strata/market/cube/CubeName.java create mode 100644 modules/market/src/main/java/com/opengamma/strata/market/cube/Cubes.java create mode 100644 modules/market/src/main/java/com/opengamma/strata/market/cube/DefaultCubeMetadata.java create mode 100644 modules/market/src/main/java/com/opengamma/strata/market/cube/DefaultCubeMetadataBuilder.java create mode 100644 modules/market/src/main/java/com/opengamma/strata/market/cube/InterpolatedNodalCube.java create mode 100644 modules/market/src/main/java/com/opengamma/strata/market/cube/NodalCube.java create mode 100644 modules/market/src/main/java/com/opengamma/strata/market/cube/SimpleCubeParameterMetadata.java create mode 100644 modules/market/src/main/java/com/opengamma/strata/market/cube/interpolator/BoundCubeInterpolator.java create mode 100644 modules/market/src/main/java/com/opengamma/strata/market/cube/interpolator/CubeInterpolator.java create mode 100644 modules/market/src/main/java/com/opengamma/strata/market/cube/interpolator/GridCubeInterpolator.java create mode 100644 modules/market/src/main/java/com/opengamma/strata/market/param/TenorTenorStrikeParameterMetadata.java create mode 100644 modules/market/src/test/java/com/opengamma/strata/market/cube/CubeInfoTypeTest.java create mode 100644 modules/market/src/test/java/com/opengamma/strata/market/cube/CubeNameTest.java create mode 100644 modules/market/src/test/java/com/opengamma/strata/market/cube/CubesTest.java create mode 100644 modules/market/src/test/java/com/opengamma/strata/market/cube/DefaultCubeMetadataTest.java create mode 100644 modules/market/src/test/java/com/opengamma/strata/market/cube/InterpolatedNodalCubeTest.java create mode 100644 modules/market/src/test/java/com/opengamma/strata/market/cube/SimpleCubeParameterMetadataTest.java create mode 100644 modules/market/src/test/java/com/opengamma/strata/market/cube/interpolator/GridCubeInterpolatorTest.java create mode 100644 modules/market/src/test/java/com/opengamma/strata/market/param/TenorTenorStrikeParameterMetadataTest.java create mode 100644 modules/pricer/src/main/java/com/opengamma/strata/pricer/swaption/NormalSwaptionExpiryTenorStrikeVolatilities.java create mode 100644 modules/pricer/src/test/java/com/opengamma/strata/pricer/swaption/NormalSwaptionExpiryTenorStrikeVolatilitiesTest.java diff --git a/modules/market/src/main/java/com/opengamma/strata/market/cube/Cube.java b/modules/market/src/main/java/com/opengamma/strata/market/cube/Cube.java new file mode 100644 index 0000000000..1e14f45585 --- /dev/null +++ b/modules/market/src/main/java/com/opengamma/strata/market/cube/Cube.java @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.market.cube; + +import static com.opengamma.strata.collect.Guavate.toImmutableList; + +import java.util.List; +import java.util.OptionalInt; +import java.util.stream.IntStream; + +import com.opengamma.strata.basics.currency.Currency; +import com.opengamma.strata.basics.value.ValueDerivatives; +import com.opengamma.strata.collect.array.DoubleArray; +import com.opengamma.strata.market.param.CurrencyParameterSensitivity; +import com.opengamma.strata.market.param.ParameterMetadata; +import com.opengamma.strata.market.param.ParameterPerturbation; +import com.opengamma.strata.market.param.ParameterizedData; +import com.opengamma.strata.market.param.UnitParameterSensitivity; + +/** + * A cube that maps a {@code double} x-value, y-value, z-value to a {@code double} w-value. + *

    + * Implementations of this interface provide the ability to find a w-value on the cube + * from the x-value, y-value, z-value. + *

    + * Each implementation will be backed by a number of parameters. + * The meaning of the parameters is implementation dependent. + * The sensitivity of the result to each of the parameters can also be obtained. + * + * @see InterpolatedNodalCube + */ +public interface Cube extends ParameterizedData { + + /** + * Gets the cube metadata. + *

    + * This method returns metadata about the cube and the cube parameters. + *

    + * The metadata includes an optional list of parameter metadata. + * If parameter metadata is present, the size of the list will match the number of parameters of this cube. + * + * @return the metadata + */ + public abstract CubeMetadata getMetadata(); + + /** + * Returns a new cube with the specified metadata. + *

    + * This allows the metadata of the cube to be changed while retaining all other information. + * If parameter metadata is present, the size of the list must match the number of parameters of this cube. + * + * @param metadata the new metadata for the cube + * @return the new cube + */ + public abstract Cube withMetadata(CubeMetadata metadata); + + /** + * Gets the cube name. + * + * @return the cube name + */ + public default CubeName getName() { + return getMetadata().getCubeName(); + } + + @Override + public default ParameterMetadata getParameterMetadata(int parameterIndex) { + return getMetadata().getParameterMetadata(parameterIndex); + } + + @Override + public default OptionalInt findParameterIndex(ParameterMetadata metadata) { + return getMetadata().findParameterIndex(metadata); + } + + @Override + public abstract Cube withParameter(int parameterIndex, double newValue); + + @Override + public default Cube withPerturbation(ParameterPerturbation perturbation) { + return (Cube) ParameterizedData.super.withPerturbation(perturbation); + } + + //------------------------------------------------------------------------- + /** + * Computes the w-value for the specified x-value, y-value, z-value. + * + * @param x the x-value to find the w-value for + * @param y the y-value to find the w-value for + * @param z the z-value to find the w-value for + * @return the value at the (x,y,z) point + */ + public abstract double wValue(double x, double y, double z); + + /** + * Computes the sensitivity of the w-value with respect to the cube parameters. + *

    + * This returns an array with one element for each x-y-z parameter of the cube. + * The array contains one a sensitivity value for each parameter used to create the cube. + * + * @param x the x-value at which the parameter sensitivity is computed + * @param y the y-value at which the parameter sensitivity is computed + * @param z the z-value at which the parameter sensitivity is computed + * @return the sensitivity at the x/y/z point + * @throws RuntimeException if the sensitivity cannot be calculated + */ + public abstract UnitParameterSensitivity wValueParameterSensitivity(double x, double y, double z); + + /** + * Computes the partial derivatives of the cube. + *

    + * The first derivatives are {@code dw/dx, dw/dy, dw/dz}. + * The derivatives are in the following order: + *

      + *
    • [0] derivative with respect to x + *
    • [1] derivative with respect to y + *
    • [2] derivative with respect to z + *
    + * + * @param x the x-value at which the partial derivative is taken + * @param y the y-value at which the partial derivative is taken + * @param z the z-value at which the partial derivative is taken + * @return the w-value and it's partial first derivatives + * @throws RuntimeException if the derivative cannot be calculated + */ + public abstract ValueDerivatives firstPartialDerivatives(double x, double y, double z); + + //------------------------------------------------------------------------- + /** + * Creates a parameter sensitivity instance for this cube when the sensitivity values are known. + *

    + * It can be useful to create a {@link UnitParameterSensitivity} from pre-computed sensitivity values. + * + * @param sensitivities the sensitivity values, which must match the parameter count of the cube + * @return the sensitivity + */ + public default UnitParameterSensitivity createParameterSensitivity(DoubleArray sensitivities) { + List paramMeta = IntStream.range(0, getParameterCount()) + .mapToObj(i -> getParameterMetadata(i)) + .collect(toImmutableList()); + return UnitParameterSensitivity.of(getName(), paramMeta, sensitivities); + } + + /** + * Creates a parameter sensitivity instance for this cube when the sensitivity values are known. + *

    + * It can be useful to create a {@link CurrencyParameterSensitivity} from pre-computed sensitivity values. + * + * @param currency the currency + * @param sensitivities the sensitivity values, which must match the parameter count of the cube + * @return the sensitivity + */ + public default CurrencyParameterSensitivity createParameterSensitivity(Currency currency, DoubleArray sensitivities) { + List paramMeta = IntStream.range(0, getParameterCount()) + .mapToObj(i -> getParameterMetadata(i)) + .collect(toImmutableList()); + return CurrencyParameterSensitivity.of(getName(), paramMeta, currency, sensitivities); + } + +} diff --git a/modules/market/src/main/java/com/opengamma/strata/market/cube/CubeInfoType.java b/modules/market/src/main/java/com/opengamma/strata/market/cube/CubeInfoType.java new file mode 100644 index 0000000000..8b16e13dac --- /dev/null +++ b/modules/market/src/main/java/com/opengamma/strata/market/cube/CubeInfoType.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.market.cube; + +import org.joda.convert.FromString; + +import com.opengamma.strata.basics.date.DayCount; +import com.opengamma.strata.collect.TypedString; +import com.opengamma.strata.market.model.MoneynessType; + +/** + * The type that provides meaning to additional cube information. + *

    + * Additional cube information is stored in {@link CubeMetadata}. + * It provides the ability to associate arbitrary information with a cube in a key-value map. + * For example, it might be used to provide information about one of the axes. + *

    + * Applications that wish to use cube information should declare a static + * constant declaring the {@code CubeInfoType} instance, the type parameter + * and an UpperCamelCase name. For example: + *

    + *  public static final CubeInfoType<String> OWNER = CubeInfoType.of("Owner");
    + * 
    + * + * @param the type of the associated value + */ +public final class CubeInfoType + extends TypedString> { + + /** + * Key used to access information about the {@link DayCount}. + */ + public static final CubeInfoType DAY_COUNT = CubeInfoType.of("DayCount"); + + /** + * Key used to access information about the type of moneyness. + */ + public static final CubeInfoType MONEYNESS_TYPE = CubeInfoType.of("MoneynessType"); + + /** Serialization version. */ + private static final long serialVersionUID = 1L; + + //------------------------------------------------------------------------- + /** + * Obtains an instance from the specified name. + *

    + * The name may contain any character, but must not be empty. + * + * @param the type associated with the info + * @param name the name + * @return a type instance with the specified name + */ + @FromString + public static CubeInfoType of(String name) { + return new CubeInfoType(name); + } + + /** + * Creates an instance. + * + * @param name the name + */ + private CubeInfoType(String name) { + super(name); + } + +} diff --git a/modules/market/src/main/java/com/opengamma/strata/market/cube/CubeMetadata.java b/modules/market/src/main/java/com/opengamma/strata/market/cube/CubeMetadata.java new file mode 100644 index 0000000000..2ba3120776 --- /dev/null +++ b/modules/market/src/main/java/com/opengamma/strata/market/cube/CubeMetadata.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.market.cube; + +import java.util.List; +import java.util.Optional; +import java.util.OptionalInt; + +import com.opengamma.strata.basics.date.Tenor; +import com.opengamma.strata.collect.Messages; +import com.opengamma.strata.market.ValueType; +import com.opengamma.strata.market.param.ParameterMetadata; + +/** + * Metadata about a cube and cube parameters. + *

    + * Implementations of this interface are used to store metadata about a cube. + * For example, a cube may be defined based on financial instruments. + * The parameters might represent 1 day, 1 week, 1 month, 3 month and 6 months. + * The metadata could be used to describe each parameter in terms of a {@link Tenor}. + *

    + * This metadata can be used by applications to interpret the parameters of the cube. + * For example, the scenario framework uses the data when applying perturbations. + */ +public interface CubeMetadata { + + /** + * Gets the cube name. + * + * @return the cube name + */ + public abstract CubeName getCubeName(); + + /** + * Gets the x-value type, providing meaning to the x-values of the cube. + *

    + * This type provides meaning to the x-values. For example, the x-value might + * represent a year fraction, as represented using {@link ValueType#YEAR_FRACTION}. + * + * @return the x-value type + */ + public abstract ValueType getXValueType(); + + /** + * Gets the y-value type, providing meaning to the y-values of the cube. + *

    + * This type provides meaning to the y-values. + * + * @return the y-value type + */ + public abstract ValueType getYValueType(); + + /** + * Gets the z-value type, providing meaning to the z-values of the cube. + *

    + * This type provides meaning to the z-values. + * + * @return the z-value type + */ + public abstract ValueType getZValueType(); + + /** + * Gets the w-value type, providing meaning to the w-values of the cube. + *

    + * This type provides meaning to the w-values. + * + * @return the w-value type + */ + public abstract ValueType getWValueType(); + + //------------------------------------------------------------------------- + + /** + * Gets cube information of a specific type. + *

    + * If the information is not found, an exception is thrown. + * + * @param the type of the info + * @param type the type to find + * @return the cube information + * @throws IllegalArgumentException if the information is not found + */ + public default T getInfo(CubeInfoType type) { + return findInfo(type).orElseThrow(() -> new IllegalArgumentException( + Messages.format("Cube info not found for type '{}'", type))); + } + + /** + * Finds cube information of a specific type. + *

    + * If the info is not found, optional empty is returned. + * + * @param the type of the info + * @param type the type to find + * @return the cube information + */ + public abstract Optional findInfo(CubeInfoType type); + + /** + * Gets the metadata of the parameter at the specified index. + *

    + * If there is no specific parameter metadata, an empty instance will be returned. + * + * @param parameterIndex the zero-based index of the parameter to get + * @return the metadata of the parameter + * @throws IndexOutOfBoundsException if the index is invalid + */ + public default ParameterMetadata getParameterMetadata(int parameterIndex) { + return getParameterMetadata().map(pm -> pm.get(parameterIndex)).orElse(ParameterMetadata.empty()); + } + + /** + * Gets metadata about each parameter underlying the cube, optional. + *

    + * If present, the parameter metadata will match the number of parameters on the cube. + * + * @return the parameter metadata + */ + public abstract Optional> getParameterMetadata(); + + /** + * Finds the parameter index of the specified metadata. + *

    + * If the parameter metadata is not matched, an empty optional will be returned. + * + * @param metadata the parameter metadata to find the index of + * @return the index of the parameter + */ + public default OptionalInt findParameterIndex(ParameterMetadata metadata) { + if (!ParameterMetadata.empty().equals(metadata)) { + Optional> pmOpt = getParameterMetadata(); + if (pmOpt.isPresent()) { + int index = pmOpt.get().indexOf(metadata); + if (index >= 0) { + return OptionalInt.of(index); + } + } + } + return OptionalInt.empty(); + } + + //------------------------------------------------------------------------- + + /** + * Returns an instance where the specified additional information has been added. + *

    + * The additional information is stored in the result using {@code Map.put} semantics, + * removing the key if the instance is null. + * + * @param the type of the info + * @param type the type to store under + * @param value the value to store, may be null + * @return the new cube metadata + */ + public abstract DefaultCubeMetadata withInfo(CubeInfoType type, T value); + + /** + * Returns an instance where the parameter metadata has been changed. + *

    + * The result will contain the specified parameter metadata. + * A null value is accepted and causes the result to have no parameter metadata. + * + * @param parameterMetadata the new parameter metadata, may be null + * @return the new cube metadata + */ + public abstract CubeMetadata withParameterMetadata(List parameterMetadata); + +} diff --git a/modules/market/src/main/java/com/opengamma/strata/market/cube/CubeName.java b/modules/market/src/main/java/com/opengamma/strata/market/cube/CubeName.java new file mode 100644 index 0000000000..dc8639b767 --- /dev/null +++ b/modules/market/src/main/java/com/opengamma/strata/market/cube/CubeName.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.market.cube; + +import java.io.Serializable; + +import org.joda.convert.FromString; + +import com.opengamma.strata.collect.ArgChecker; +import com.opengamma.strata.data.MarketDataName; + +/** + * The name of a cube. + */ +public class CubeName + extends MarketDataName + implements Serializable { + + /** Serialization version. */ + private static final long serialVersionUID = 1L; + + /** + * The name. + */ + private final String name; + + //------------------------------------------------------------------------- + /** + * Obtains an instance from the specified name. + *

    + * Cube names may contain any character, but must not be empty. + * + * @param name the name of the cube + * @return a cube name instance with the specified name + */ + @FromString + public static CubeName of(String name) { + return new CubeName(name); + } + + /** + * Creates an instance. + * + * @param name the name of the cube + */ + private CubeName(String name) { + this.name = ArgChecker.notEmpty(name, "name"); + } + + //------------------------------------------------------------------------- + @Override + public Class getMarketDataType() { + return Cube.class; + } + + @Override + public String getName() { + return name; + } + +} diff --git a/modules/market/src/main/java/com/opengamma/strata/market/cube/Cubes.java b/modules/market/src/main/java/com/opengamma/strata/market/cube/Cubes.java new file mode 100644 index 0000000000..d16f25c2a1 --- /dev/null +++ b/modules/market/src/main/java/com/opengamma/strata/market/cube/Cubes.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.market.cube; + +import com.opengamma.strata.basics.date.DayCount; +import com.opengamma.strata.market.ValueType; + +/** + * Helper for creating common types of cubes. + */ +public final class Cubes { + + /** + * Restricted constructor. + */ + private Cubes() { + } + + //------------------------------------------------------------------------- + /** + * Creates metadata for a cube providing normal expiry-tenor-strike volatility. + *

    + * The x-values represent time to expiry year fractions as defined by the specified day count. + * The y-values represent tenor year fractions. + * The z-values represent strike. + * The z-values represent normal volatility. + * + * @param name the cube name + * @param dayCount the day count + * @return the cube metadata + */ + public static CubeMetadata normalVolatilityByExpiryTenorStrike(String name, DayCount dayCount) { + return normalVolatilityByExpiryTenorStrike(CubeName.of(name), dayCount); + } + + /** + * Creates metadata for a cube providing normal expiry-tenor-strike volatility. + *

    + * The x-values represent time to expiry year fractions as defined by the specified day count. + * The y-values represent tenor year fractions. + * The z-values represent strike. + * The w-values represent normal volatility. + * + * @param name the cube name + * @param dayCount the day count + * @return the cube metadata + */ + public static CubeMetadata normalVolatilityByExpiryTenorStrike(CubeName name, DayCount dayCount) { + return DefaultCubeMetadata.builder() + .cubeName(name) + .xValueType(ValueType.YEAR_FRACTION) + .yValueType(ValueType.YEAR_FRACTION) + .zValueType(ValueType.STRIKE) + .wValueType(ValueType.NORMAL_VOLATILITY) + .dayCount(dayCount) + .build(); + } + +} diff --git a/modules/market/src/main/java/com/opengamma/strata/market/cube/DefaultCubeMetadata.java b/modules/market/src/main/java/com/opengamma/strata/market/cube/DefaultCubeMetadata.java new file mode 100644 index 0000000000..f17a4eb52b --- /dev/null +++ b/modules/market/src/main/java/com/opengamma/strata/market/cube/DefaultCubeMetadata.java @@ -0,0 +1,677 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.market.cube; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Optional; + +import org.joda.beans.Bean; +import org.joda.beans.BeanBuilder; +import org.joda.beans.ImmutableBean; +import org.joda.beans.JodaBeanUtils; +import org.joda.beans.MetaBean; +import org.joda.beans.MetaProperty; +import org.joda.beans.gen.BeanDefinition; +import org.joda.beans.gen.ImmutableDefaults; +import org.joda.beans.gen.PropertyDefinition; +import org.joda.beans.impl.direct.DirectMetaBean; +import org.joda.beans.impl.direct.DirectMetaProperty; +import org.joda.beans.impl.direct.DirectMetaPropertyMap; +import org.joda.beans.impl.direct.DirectPrivateBeanBuilder; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.opengamma.strata.collect.Messages; +import com.opengamma.strata.market.ValueType; +import com.opengamma.strata.market.param.ParameterMetadata; + +/** + * Default metadata for a cube. + *

    + * This implementation of {@link CubeMetadata} provides the cube name and nodes. + */ +@BeanDefinition(builderScope = "private", constructorScope = "package") +public final class DefaultCubeMetadata + implements CubeMetadata, ImmutableBean, Serializable { + + /** + * The cube name. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final CubeName cubeName; + /** + * The x-value type, providing meaning to the x-values of the cube. + *

    + * This type provides meaning to the x-values. For example, the x-value might + * represent a year fraction, as represented using {@link ValueType#YEAR_FRACTION}. + *

    + * If using the builder, this defaults to {@link ValueType#UNKNOWN}. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final ValueType xValueType; + /** + * The y-value type, providing meaning to the y-values of the cube. + *

    + * This type provides meaning to the y-values. + *

    + * If using the builder, this defaults to {@link ValueType#UNKNOWN}. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final ValueType yValueType; + /** + * The z-value type, providing meaning to the z-values of the cube. + *

    + * This type provides meaning to the z-values. + *

    + * If using the builder, this defaults to {@link ValueType#UNKNOWN}. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final ValueType zValueType; + /** + * The w-value type, providing meaning to the w-values of the cube. + *

    + * This type provides meaning to the w-values. + *

    + * If using the builder, this defaults to {@link ValueType#UNKNOWN}. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final ValueType wValueType; + /** + * The additional cube information. + *

    + * This stores additional information for the cube. + */ + @PropertyDefinition(validate = "notNull") + private final ImmutableMap, Object> info; + /** + * The metadata about the parameters. + *

    + * If present, the parameter metadata should match the number of parameters on the cube. + */ + @PropertyDefinition(get = "optional", overrideGet = true, type = "List<>", builderType = "List") + private final ImmutableList parameterMetadata; + + //------------------------------------------------------------------------- + /** + * Creates the metadata. + *

    + * No information will be available for the x-values, y-values, z-values, w-values or parameters. + * + * @param name the cube name + * @return the metadata + */ + public static DefaultCubeMetadata of(String name) { + return of(CubeName.of(name)); + } + + /** + * Creates the metadata. + *

    + * No information will be available for the x-values, y-values, z-values or parameters. + * + * @param name the cube name + * @return the metadata + */ + public static DefaultCubeMetadata of(CubeName name) { + return new DefaultCubeMetadata( + name, ValueType.UNKNOWN, ValueType.UNKNOWN, ValueType.UNKNOWN, ValueType.UNKNOWN, ImmutableMap.of(), null); + } + + /** + * Returns a builder used to create an instance of the bean. + * + * @return the builder, not null + */ + public static DefaultCubeMetadataBuilder builder() { + return new DefaultCubeMetadataBuilder(); + } + + //------------------------------------------------------------------------- + @ImmutableDefaults + private static void applyDefaults(Builder builder) { + builder.xValueType = ValueType.UNKNOWN; + builder.yValueType = ValueType.UNKNOWN; + builder.zValueType = ValueType.UNKNOWN; + builder.wValueType = ValueType.UNKNOWN; + } + + //------------------------------------------------------------------------- + @Override + public T getInfo(CubeInfoType type) { + // overridden for performance + @SuppressWarnings("unchecked") + T value = (T) info.get(type); + if (value == null) { + throw new IllegalArgumentException(Messages.format("Cube info not found for type '{}'", type)); + } + return value; + } + + @SuppressWarnings("unchecked") + @Override + public Optional findInfo(CubeInfoType type) { + return Optional.ofNullable((T) info.get(type)); + } + + //------------------------------------------------------------------------- + @Override + public DefaultCubeMetadata withInfo(CubeInfoType type, T value) { + return toBuilder().addInfo(type, value).build(); + } + + @Override + public DefaultCubeMetadata withParameterMetadata(List parameterMetadata) { + if (parameterMetadata == null) { + return this.parameterMetadata != null ? toBuilder().clearParameterMetadata().build() : this; + } + return toBuilder().parameterMetadata(parameterMetadata).build(); + } + + //------------------------------------------------------------------------- + /** + * Returns a mutable builder initialized with the state of this bean. + * + * @return the mutable builder, not null + */ + public DefaultCubeMetadataBuilder toBuilder() { + return new DefaultCubeMetadataBuilder(this); + } + + //------------------------- AUTOGENERATED START ------------------------- + /** + * The meta-bean for {@code DefaultCubeMetadata}. + * @return the meta-bean, not null + */ + public static DefaultCubeMetadata.Meta meta() { + return DefaultCubeMetadata.Meta.INSTANCE; + } + + static { + MetaBean.register(DefaultCubeMetadata.Meta.INSTANCE); + } + + /** + * The serialization version id. + */ + private static final long serialVersionUID = 1L; + + /** + * Creates an instance. + * @param cubeName the value of the property, not null + * @param xValueType the value of the property, not null + * @param yValueType the value of the property, not null + * @param zValueType the value of the property, not null + * @param wValueType the value of the property, not null + * @param info the value of the property, not null + * @param parameterMetadata the value of the property + */ + DefaultCubeMetadata( + CubeName cubeName, + ValueType xValueType, + ValueType yValueType, + ValueType zValueType, + ValueType wValueType, + Map, Object> info, + List parameterMetadata) { + JodaBeanUtils.notNull(cubeName, "cubeName"); + JodaBeanUtils.notNull(xValueType, "xValueType"); + JodaBeanUtils.notNull(yValueType, "yValueType"); + JodaBeanUtils.notNull(zValueType, "zValueType"); + JodaBeanUtils.notNull(wValueType, "wValueType"); + JodaBeanUtils.notNull(info, "info"); + this.cubeName = cubeName; + this.xValueType = xValueType; + this.yValueType = yValueType; + this.zValueType = zValueType; + this.wValueType = wValueType; + this.info = ImmutableMap.copyOf(info); + this.parameterMetadata = (parameterMetadata != null ? ImmutableList.copyOf(parameterMetadata) : null); + } + + @Override + public DefaultCubeMetadata.Meta metaBean() { + return DefaultCubeMetadata.Meta.INSTANCE; + } + + //----------------------------------------------------------------------- + /** + * Gets the cube name. + * @return the value of the property, not null + */ + @Override + public CubeName getCubeName() { + return cubeName; + } + + //----------------------------------------------------------------------- + /** + * Gets the x-value type, providing meaning to the x-values of the cube. + *

    + * This type provides meaning to the x-values. For example, the x-value might + * represent a year fraction, as represented using {@link ValueType#YEAR_FRACTION}. + *

    + * If using the builder, this defaults to {@link ValueType#UNKNOWN}. + * @return the value of the property, not null + */ + @Override + public ValueType getXValueType() { + return xValueType; + } + + //----------------------------------------------------------------------- + /** + * Gets the y-value type, providing meaning to the y-values of the cube. + *

    + * This type provides meaning to the y-values. + *

    + * If using the builder, this defaults to {@link ValueType#UNKNOWN}. + * @return the value of the property, not null + */ + @Override + public ValueType getYValueType() { + return yValueType; + } + + //----------------------------------------------------------------------- + /** + * Gets the z-value type, providing meaning to the z-values of the cube. + *

    + * This type provides meaning to the z-values. + *

    + * If using the builder, this defaults to {@link ValueType#UNKNOWN}. + * @return the value of the property, not null + */ + @Override + public ValueType getZValueType() { + return zValueType; + } + + //----------------------------------------------------------------------- + /** + * Gets the w-value type, providing meaning to the w-values of the cube. + *

    + * This type provides meaning to the w-values. + *

    + * If using the builder, this defaults to {@link ValueType#UNKNOWN}. + * @return the value of the property, not null + */ + @Override + public ValueType getWValueType() { + return wValueType; + } + + //----------------------------------------------------------------------- + /** + * Gets the additional cube information. + *

    + * This stores additional information for the cube. + * @return the value of the property, not null + */ + public ImmutableMap, Object> getInfo() { + return info; + } + + //----------------------------------------------------------------------- + /** + * Gets the metadata about the parameters. + *

    + * If present, the parameter metadata should match the number of parameters on the cube. + * @return the optional value of the property, not null + */ + @Override + public Optional> getParameterMetadata() { + return Optional.ofNullable(parameterMetadata); + } + + //----------------------------------------------------------------------- + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && obj.getClass() == this.getClass()) { + DefaultCubeMetadata other = (DefaultCubeMetadata) obj; + return JodaBeanUtils.equal(cubeName, other.cubeName) && + JodaBeanUtils.equal(xValueType, other.xValueType) && + JodaBeanUtils.equal(yValueType, other.yValueType) && + JodaBeanUtils.equal(zValueType, other.zValueType) && + JodaBeanUtils.equal(wValueType, other.wValueType) && + JodaBeanUtils.equal(info, other.info) && + JodaBeanUtils.equal(parameterMetadata, other.parameterMetadata); + } + return false; + } + + @Override + public int hashCode() { + int hash = getClass().hashCode(); + hash = hash * 31 + JodaBeanUtils.hashCode(cubeName); + hash = hash * 31 + JodaBeanUtils.hashCode(xValueType); + hash = hash * 31 + JodaBeanUtils.hashCode(yValueType); + hash = hash * 31 + JodaBeanUtils.hashCode(zValueType); + hash = hash * 31 + JodaBeanUtils.hashCode(wValueType); + hash = hash * 31 + JodaBeanUtils.hashCode(info); + hash = hash * 31 + JodaBeanUtils.hashCode(parameterMetadata); + return hash; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(256); + buf.append("DefaultCubeMetadata{"); + buf.append("cubeName").append('=').append(JodaBeanUtils.toString(cubeName)).append(',').append(' '); + buf.append("xValueType").append('=').append(JodaBeanUtils.toString(xValueType)).append(',').append(' '); + buf.append("yValueType").append('=').append(JodaBeanUtils.toString(yValueType)).append(',').append(' '); + buf.append("zValueType").append('=').append(JodaBeanUtils.toString(zValueType)).append(',').append(' '); + buf.append("wValueType").append('=').append(JodaBeanUtils.toString(wValueType)).append(',').append(' '); + buf.append("info").append('=').append(JodaBeanUtils.toString(info)).append(',').append(' '); + buf.append("parameterMetadata").append('=').append(JodaBeanUtils.toString(parameterMetadata)); + buf.append('}'); + return buf.toString(); + } + + //----------------------------------------------------------------------- + /** + * The meta-bean for {@code DefaultCubeMetadata}. + */ + public static final class Meta extends DirectMetaBean { + /** + * The singleton instance of the meta-bean. + */ + static final Meta INSTANCE = new Meta(); + + /** + * The meta-property for the {@code cubeName} property. + */ + private final MetaProperty cubeName = DirectMetaProperty.ofImmutable( + this, "cubeName", DefaultCubeMetadata.class, CubeName.class); + /** + * The meta-property for the {@code xValueType} property. + */ + private final MetaProperty xValueType = DirectMetaProperty.ofImmutable( + this, "xValueType", DefaultCubeMetadata.class, ValueType.class); + /** + * The meta-property for the {@code yValueType} property. + */ + private final MetaProperty yValueType = DirectMetaProperty.ofImmutable( + this, "yValueType", DefaultCubeMetadata.class, ValueType.class); + /** + * The meta-property for the {@code zValueType} property. + */ + private final MetaProperty zValueType = DirectMetaProperty.ofImmutable( + this, "zValueType", DefaultCubeMetadata.class, ValueType.class); + /** + * The meta-property for the {@code wValueType} property. + */ + private final MetaProperty wValueType = DirectMetaProperty.ofImmutable( + this, "wValueType", DefaultCubeMetadata.class, ValueType.class); + /** + * The meta-property for the {@code info} property. + */ + @SuppressWarnings({"unchecked", "rawtypes" }) + private final MetaProperty, Object>> info = DirectMetaProperty.ofImmutable( + this, "info", DefaultCubeMetadata.class, (Class) ImmutableMap.class); + /** + * The meta-property for the {@code parameterMetadata} property. + */ + @SuppressWarnings({"unchecked", "rawtypes" }) + private final MetaProperty> parameterMetadata = DirectMetaProperty.ofImmutable( + this, "parameterMetadata", DefaultCubeMetadata.class, (Class) List.class); + /** + * The meta-properties. + */ + private final Map> metaPropertyMap$ = new DirectMetaPropertyMap( + this, null, + "cubeName", + "xValueType", + "yValueType", + "zValueType", + "wValueType", + "info", + "parameterMetadata"); + + /** + * Restricted constructor. + */ + private Meta() { + } + + @Override + protected MetaProperty metaPropertyGet(String propertyName) { + switch (propertyName.hashCode()) { + case 104632416: // cubeName + return cubeName; + case -868509005: // xValueType + return xValueType; + case -1065022510: // yValueType + return yValueType; + case -1261536015: // zValueType + return zValueType; + case -671995500: // wValueType + return wValueType; + case 3237038: // info + return info; + case -1169106440: // parameterMetadata + return parameterMetadata; + } + return super.metaPropertyGet(propertyName); + } + + @Override + public BeanBuilder builder() { + return new DefaultCubeMetadata.Builder(); + } + + @Override + public Class beanType() { + return DefaultCubeMetadata.class; + } + + @Override + public Map> metaPropertyMap() { + return metaPropertyMap$; + } + + //----------------------------------------------------------------------- + /** + * The meta-property for the {@code cubeName} property. + * @return the meta-property, not null + */ + public MetaProperty cubeName() { + return cubeName; + } + + /** + * The meta-property for the {@code xValueType} property. + * @return the meta-property, not null + */ + public MetaProperty xValueType() { + return xValueType; + } + + /** + * The meta-property for the {@code yValueType} property. + * @return the meta-property, not null + */ + public MetaProperty yValueType() { + return yValueType; + } + + /** + * The meta-property for the {@code zValueType} property. + * @return the meta-property, not null + */ + public MetaProperty zValueType() { + return zValueType; + } + + /** + * The meta-property for the {@code wValueType} property. + * @return the meta-property, not null + */ + public MetaProperty wValueType() { + return wValueType; + } + + /** + * The meta-property for the {@code info} property. + * @return the meta-property, not null + */ + public MetaProperty, Object>> info() { + return info; + } + + /** + * The meta-property for the {@code parameterMetadata} property. + * @return the meta-property, not null + */ + public MetaProperty> parameterMetadata() { + return parameterMetadata; + } + + //----------------------------------------------------------------------- + @Override + protected Object propertyGet(Bean bean, String propertyName, boolean quiet) { + switch (propertyName.hashCode()) { + case 104632416: // cubeName + return ((DefaultCubeMetadata) bean).getCubeName(); + case -868509005: // xValueType + return ((DefaultCubeMetadata) bean).getXValueType(); + case -1065022510: // yValueType + return ((DefaultCubeMetadata) bean).getYValueType(); + case -1261536015: // zValueType + return ((DefaultCubeMetadata) bean).getZValueType(); + case -671995500: // wValueType + return ((DefaultCubeMetadata) bean).getWValueType(); + case 3237038: // info + return ((DefaultCubeMetadata) bean).getInfo(); + case -1169106440: // parameterMetadata + return ((DefaultCubeMetadata) bean).parameterMetadata; + } + return super.propertyGet(bean, propertyName, quiet); + } + + @Override + protected void propertySet(Bean bean, String propertyName, Object newValue, boolean quiet) { + metaProperty(propertyName); + if (quiet) { + return; + } + throw new UnsupportedOperationException("Property cannot be written: " + propertyName); + } + + } + + //----------------------------------------------------------------------- + /** + * The bean-builder for {@code DefaultCubeMetadata}. + */ + private static final class Builder extends DirectPrivateBeanBuilder { + + private CubeName cubeName; + private ValueType xValueType; + private ValueType yValueType; + private ValueType zValueType; + private ValueType wValueType; + private Map, Object> info = ImmutableMap.of(); + private List parameterMetadata; + + /** + * Restricted constructor. + */ + private Builder() { + applyDefaults(this); + } + + //----------------------------------------------------------------------- + @Override + public Object get(String propertyName) { + switch (propertyName.hashCode()) { + case 104632416: // cubeName + return cubeName; + case -868509005: // xValueType + return xValueType; + case -1065022510: // yValueType + return yValueType; + case -1261536015: // zValueType + return zValueType; + case -671995500: // wValueType + return wValueType; + case 3237038: // info + return info; + case -1169106440: // parameterMetadata + return parameterMetadata; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + } + + @SuppressWarnings("unchecked") + @Override + public Builder set(String propertyName, Object newValue) { + switch (propertyName.hashCode()) { + case 104632416: // cubeName + this.cubeName = (CubeName) newValue; + break; + case -868509005: // xValueType + this.xValueType = (ValueType) newValue; + break; + case -1065022510: // yValueType + this.yValueType = (ValueType) newValue; + break; + case -1261536015: // zValueType + this.zValueType = (ValueType) newValue; + break; + case -671995500: // wValueType + this.wValueType = (ValueType) newValue; + break; + case 3237038: // info + this.info = (Map, Object>) newValue; + break; + case -1169106440: // parameterMetadata + this.parameterMetadata = (List) newValue; + break; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + return this; + } + + @Override + public DefaultCubeMetadata build() { + return new DefaultCubeMetadata( + cubeName, + xValueType, + yValueType, + zValueType, + wValueType, + info, + parameterMetadata); + } + + //----------------------------------------------------------------------- + @Override + public String toString() { + StringBuilder buf = new StringBuilder(256); + buf.append("DefaultCubeMetadata.Builder{"); + buf.append("cubeName").append('=').append(JodaBeanUtils.toString(cubeName)).append(',').append(' '); + buf.append("xValueType").append('=').append(JodaBeanUtils.toString(xValueType)).append(',').append(' '); + buf.append("yValueType").append('=').append(JodaBeanUtils.toString(yValueType)).append(',').append(' '); + buf.append("zValueType").append('=').append(JodaBeanUtils.toString(zValueType)).append(',').append(' '); + buf.append("wValueType").append('=').append(JodaBeanUtils.toString(wValueType)).append(',').append(' '); + buf.append("info").append('=').append(JodaBeanUtils.toString(info)).append(',').append(' '); + buf.append("parameterMetadata").append('=').append(JodaBeanUtils.toString(parameterMetadata)); + buf.append('}'); + return buf.toString(); + } + + } + + //-------------------------- AUTOGENERATED END -------------------------- +} diff --git a/modules/market/src/main/java/com/opengamma/strata/market/cube/DefaultCubeMetadataBuilder.java b/modules/market/src/main/java/com/opengamma/strata/market/cube/DefaultCubeMetadataBuilder.java new file mode 100644 index 0000000000..434700e154 --- /dev/null +++ b/modules/market/src/main/java/com/opengamma/strata/market/cube/DefaultCubeMetadataBuilder.java @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.market.cube; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.google.common.collect.ImmutableList; +import com.opengamma.strata.basics.date.DayCount; +import com.opengamma.strata.collect.ArgChecker; +import com.opengamma.strata.market.ValueType; +import com.opengamma.strata.market.param.ParameterMetadata; + +/** + * Builder for cube metadata. + *

    + * This is created using {@link DefaultCubeMetadata#builder()}. + */ +public final class DefaultCubeMetadataBuilder { + + /** + * The cube name. + */ + private CubeName cubeName; + /** + * The x-value type, providing meaning to the x-values of the cube. + *

    + * This type provides meaning to the x-values. + * It defaults to {@link ValueType#UNKNOWN}. + */ + private ValueType xValueType = ValueType.UNKNOWN; + /** + * The y-value type, providing meaning to the y-values of the cube. + *

    + * This type provides meaning to the y-values. + * It defaults to {@link ValueType#UNKNOWN}. + */ + private ValueType yValueType = ValueType.UNKNOWN; + /** + * The z-value type, providing meaning to the z-values of the cube. + *

    + * This type provides meaning to the z-values. + * It defaults to {@link ValueType#UNKNOWN}. + */ + private ValueType zValueType = ValueType.UNKNOWN; + /** + * The w-value type, providing meaning to the w-values of the cube. + *

    + * This type provides meaning to the w-values. + * It defaults to {@link ValueType#UNKNOWN}. + */ + private ValueType wValueType = ValueType.UNKNOWN; + /** + * The additional cube information. + *

    + * This stores additional information for the cube. + */ + private final Map, Object> info = new HashMap<>(); + /** + * The metadata about the parameters. + *

    + * If present, the parameter metadata will match the number of parameters on the cube. + */ + private List parameterMetadata; + + /** + * Restricted constructor. + */ + DefaultCubeMetadataBuilder() { + } + + /** + * Restricted copy constructor. + * + * @param beanToCopy the bean to copy from + */ + DefaultCubeMetadataBuilder(DefaultCubeMetadata beanToCopy) { + this.cubeName = beanToCopy.getCubeName(); + this.xValueType = beanToCopy.getXValueType(); + this.yValueType = beanToCopy.getYValueType(); + this.zValueType = beanToCopy.getZValueType(); + this.wValueType = beanToCopy.getWValueType(); + this.info.putAll(beanToCopy.getInfo()); + this.parameterMetadata = beanToCopy.getParameterMetadata().orElse(null); + } + + //----------------------------------------------------------------------- + /** + * Sets the cube name. + * + * @param cubeName the cube name + * @return this, for chaining + */ + public DefaultCubeMetadataBuilder cubeName(String cubeName) { + this.cubeName = CubeName.of(cubeName); + return this; + } + + /** + * Sets the cube name. + * + * @param cubeName the cube name + * @return this, for chaining + */ + public DefaultCubeMetadataBuilder cubeName(CubeName cubeName) { + this.cubeName = ArgChecker.notNull(cubeName, "cubeName"); + return this; + } + + //------------------------------------------------------------------------- + /** + * Sets the x-value type, providing meaning to the x-values of the cube. + *

    + * This type provides meaning to the x-values. + *

    + * If using the builder, this defaults to {@link ValueType#UNKNOWN}. + * + * @param xValueType the x-value type + * @return this, for chaining + */ + public DefaultCubeMetadataBuilder xValueType(ValueType xValueType) { + this.xValueType = ArgChecker.notNull(xValueType, "xValueType"); + return this; + } + + //------------------------------------------------------------------------- + /** + * Sets the y-value type, providing meaning to the y-values of the cube. + *

    + * This type provides meaning to the y-values. + *

    + * If using the builder, this defaults to {@link ValueType#UNKNOWN}. + * + * @param yValueType the y-value type + * @return this, for chaining + */ + public DefaultCubeMetadataBuilder yValueType(ValueType yValueType) { + this.yValueType = ArgChecker.notNull(yValueType, "yValueType"); + return this; + } + + //------------------------------------------------------------------------- + /** + * Sets the z-value type, providing meaning to the z-values of the cube. + *

    + * This type provides meaning to the z-values. + *

    + * If using the builder, this defaults to {@link ValueType#UNKNOWN}. + * + * @param zValueType the z-value type + * @return this, for chaining + */ + public DefaultCubeMetadataBuilder zValueType(ValueType zValueType) { + this.zValueType = ArgChecker.notNull(zValueType, "zValueType"); + return this; + } + + //------------------------------------------------------------------------- + /** + * Sets the w-value type, providing meaning to the w-values of the cube. + *

    + * This type provides meaning to the w-values. + *

    + * If using the builder, this defaults to {@link ValueType#UNKNOWN}. + * + * @param wValueType the w-value type + * @return this, for chaining + */ + public DefaultCubeMetadataBuilder wValueType(ValueType wValueType) { + this.wValueType = ArgChecker.notNull(wValueType, "wValueType"); + return this; + } + + //------------------------------------------------------------------------- + /** + * Sets the day count. + *

    + * This stores the day count in the additional information map using the + * key {@link CubeInfoType#DAY_COUNT}. + *

    + * This is stored in the additional information map using {@code Map.put} semantics, + * removing the key if the day count is null. + * + * @param dayCount the day count, may be null + * @return this, for chaining + */ + public DefaultCubeMetadataBuilder dayCount(DayCount dayCount) { + return addInfo(CubeInfoType.DAY_COUNT, dayCount); + } + + //------------------------------------------------------------------------- + /** + * Adds a single piece of additional information. + *

    + * This is stored in the additional information map using {@code Map.put} semantics, + * removing the key if the instance is null. + * + * @param the type of the info + * @param type the type to store under + * @param value the value to store, may be null + * @return this, for chaining + */ + public DefaultCubeMetadataBuilder addInfo(CubeInfoType type, T value) { + ArgChecker.notNull(type, "type"); + if (value != null) { + this.info.put(type, value); + } else { + this.info.remove(type); + } + return this; + } + + //------------------------------------------------------------------------- + /** + * Sets the parameter-level metadata. + *

    + * The parameter metadata must match the number of parameters on the cube. + * This will replace the existing parameter-level metadata. + * + * @param parameterMetadata the parameter metadata + * @return this, for chaining + */ + public DefaultCubeMetadataBuilder parameterMetadata(List parameterMetadata) { + this.parameterMetadata = ImmutableList.copyOf(parameterMetadata); + return this; + } + + /** + * Sets the parameter-level metadata. + *

    + * The parameter metadata must match the number of parameters on the cube. + * This will replace the existing parameter-level metadata. + * + * @param parameterMetadata the parameter metadata + * @return this, for chaining + */ + public DefaultCubeMetadataBuilder parameterMetadata(ParameterMetadata... parameterMetadata) { + this.parameterMetadata = ImmutableList.copyOf(parameterMetadata); + return this; + } + + /** + * Clears the parameter-level metadata. + *

    + * The existing parameter-level metadata will be removed. + * + * @return this, for chaining + */ + public DefaultCubeMetadataBuilder clearParameterMetadata() { + this.parameterMetadata = null; + return this; + } + + //------------------------------------------------------------------------- + /** + * Builds the metadata instance. + * + * @return the instance + */ + public DefaultCubeMetadata build() { + return new DefaultCubeMetadata(cubeName, xValueType, yValueType, zValueType, wValueType, info, parameterMetadata); + } + +} diff --git a/modules/market/src/main/java/com/opengamma/strata/market/cube/InterpolatedNodalCube.java b/modules/market/src/main/java/com/opengamma/strata/market/cube/InterpolatedNodalCube.java new file mode 100644 index 0000000000..c8ad6f392c --- /dev/null +++ b/modules/market/src/main/java/com/opengamma/strata/market/cube/InterpolatedNodalCube.java @@ -0,0 +1,860 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.market.cube; + +import static com.opengamma.strata.collect.Guavate.toImmutableList; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.TreeMap; +import java.util.stream.IntStream; + +import org.joda.beans.Bean; +import org.joda.beans.ImmutableBean; +import org.joda.beans.JodaBeanUtils; +import org.joda.beans.MetaBean; +import org.joda.beans.MetaProperty; +import org.joda.beans.gen.BeanDefinition; +import org.joda.beans.gen.ImmutableConstructor; +import org.joda.beans.gen.PropertyDefinition; +import org.joda.beans.impl.direct.DirectFieldsBeanBuilder; +import org.joda.beans.impl.direct.DirectMetaBean; +import org.joda.beans.impl.direct.DirectMetaProperty; +import org.joda.beans.impl.direct.DirectMetaPropertyMap; + +import com.opengamma.strata.basics.currency.Currency; +import com.opengamma.strata.basics.value.ValueDerivatives; +import com.opengamma.strata.collect.ArgChecker; +import com.opengamma.strata.collect.array.DoubleArray; +import com.opengamma.strata.collect.tuple.ObjDoublePair; +import com.opengamma.strata.collect.tuple.Triple; +import com.opengamma.strata.market.cube.interpolator.BoundCubeInterpolator; +import com.opengamma.strata.market.cube.interpolator.CubeInterpolator; +import com.opengamma.strata.market.param.CurrencyParameterSensitivity; +import com.opengamma.strata.market.param.ParameterMetadata; +import com.opengamma.strata.market.param.ParameterPerturbation; +import com.opengamma.strata.market.param.UnitParameterSensitivity; + +/** + * A cube based on interpolation between a number of nodal points. + *

    + * This class defines a cube in terms of a fixed number of nodes, referred to as parameters. + *

    + * Each node has x-value, y-value, z-value, w-value. + * The interface is focused on finding the w-value for a given x-value, y-value, z-value. + * An interpolator is used to find w-values for x-values, y-values, z-values between nodes. + */ +@BeanDefinition +public final class InterpolatedNodalCube + implements NodalCube, ImmutableBean, Serializable { + + /** + * The cube metadata. + *

    + * The metadata includes an optional list of parameter metadata. + * If present, the size of the parameter metadata list will match the number of parameters of this cube. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final CubeMetadata metadata; + /** + * The array of x-values, one for each point. + *

    + * This array will contains at least two elements. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final DoubleArray xValues; + /** + * The array of y-values, one for each point. + *

    + * This array will contains at least two elements and be of the same length as x-values. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final DoubleArray yValues; + /** + * The array of z-values, one for each point. + *

    + * This array will contains at least two elements and be of the same length as x-values. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final DoubleArray zValues; + /** + * The array of w-values, one for each point. + *

    + * This array will contains at least two elements and be of the same length as x-values. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final DoubleArray wValues; + /** + * The underlying interpolator. + */ + @PropertyDefinition(validate = "notNull") + private final CubeInterpolator interpolator; + /** + * The bound interpolator. + */ + private final transient BoundCubeInterpolator boundInterpolator; // derived and cached, not a property + /** + * The parameter metadata. + */ + private final transient List parameterMetadata; // derived, not a property + + //------------------------------------------------------------------------- + + /** + * Creates an interpolated cube with metadata. + *

    + * The value arrays must be sorted, by x-values then y-values, z-values. + * An exception is thrown if they are not sorted. + * + * @param metadata the cube metadata + * @param xValues the x-values, must be sorted from low to high + * @param yValues the y-values, must be sorted from low to high within x + * @param zValues the z-values, must be sorted from low to high within x, y + * @param wValues the w-values + * @param interpolator the interpolator + * @return the cube + */ + public static InterpolatedNodalCube of( + CubeMetadata metadata, + DoubleArray xValues, + DoubleArray yValues, + DoubleArray zValues, + DoubleArray wValues, + CubeInterpolator interpolator) { + + return new InterpolatedNodalCube(metadata, xValues, yValues, zValues, wValues, interpolator); + } + + /** + * Creates an interpolated cube with metadata, where the values are not sorted. + *

    + * The value arrays will be sorted, by x-values then y-values, z-values. + * Both the w-values and parameter metadata will be sorted along with the x, y, z values. + * + * @param metadata the cube metadata + * @param xValues the x-values + * @param yValues the y-values + * @param zValues the z-values + * @param wValues the w-values + * @param interpolator the interpolator + * @return the cube + */ + public static InterpolatedNodalCube ofUnsorted( + CubeMetadata metadata, + DoubleArray xValues, + DoubleArray yValues, + DoubleArray zValues, + DoubleArray wValues, + CubeInterpolator interpolator) { + + return new InterpolatedNodalCube(metadata, xValues, yValues, zValues, wValues, interpolator, true); + } + + //------------------------------------------------------------------------- + // restricted constructor + @ImmutableConstructor + private InterpolatedNodalCube( + CubeMetadata metadata, + DoubleArray xValues, + DoubleArray yValues, + DoubleArray zValues, + DoubleArray wValues, + CubeInterpolator interpolator) { + + validateInputs(metadata, xValues, yValues, zValues, wValues, interpolator); + for (int i = 1; i < xValues.size(); i++) { + if (xValues.get(i) < xValues.get(i - 1)) { + throw new IllegalArgumentException("Array of x-values must be sorted"); + } + if (xValues.get(i) == xValues.get(i - 1) && yValues.get(i) < yValues.get(i - 1)) { + throw new IllegalArgumentException("Array of y-values must be sorted"); + } + if (xValues.get(i) == xValues.get(i - 1) && yValues.get(i) == yValues.get(i - 1) && zValues.get(i) < zValues.get(i - 1)) { + throw new IllegalArgumentException("Array of z-values must be sorted"); + } + } + this.metadata = metadata; + this.xValues = xValues; + this.yValues = yValues; + this.zValues = zValues; + this.wValues = wValues; + this.interpolator = interpolator; + this.boundInterpolator = interpolator.bind(xValues, yValues, zValues, wValues); + this.parameterMetadata = IntStream.range(0, getParameterCount()) + .mapToObj(i -> metadata.getParameterMetadata(i)) + .collect(toImmutableList()); + } + + // constructor that sorts (artificial boolean flag) + private InterpolatedNodalCube( + CubeMetadata metadata, + DoubleArray xValues, + DoubleArray yValues, + DoubleArray zValues, + DoubleArray wValues, + CubeInterpolator interpolator, + boolean sort) { + + validateInputs(metadata, xValues, yValues, zValues, wValues, interpolator); + // sort inputs + Map, ObjDoublePair> sorted = new TreeMap<>(); + for (int i = 0; i < xValues.size(); i++) { + ParameterMetadata pm = metadata.getParameterMetadata(i); + sorted.put(Triple.of(xValues.get(i), yValues.get(i), zValues.get(i)), ObjDoublePair.of(pm, wValues.get(i))); + } + double[] sortedX = new double[sorted.size()]; + double[] sortedY = new double[sorted.size()]; + double[] sortedZ = new double[sorted.size()]; + double[] sortedW = new double[sorted.size()]; + ParameterMetadata[] sortedPm = new ParameterMetadata[sorted.size()]; + int pos = 0; + for (Map.Entry, ObjDoublePair> entry : sorted.entrySet()) { + sortedX[pos] = entry.getKey().getFirst(); + sortedY[pos] = entry.getKey().getSecond(); + sortedZ[pos] = entry.getKey().getThird(); + sortedW[pos] = entry.getValue().getSecond(); + sortedPm[pos] = entry.getValue().getFirst(); + pos++; + } + // assign + CubeMetadata sortedMetadata = metadata.withParameterMetadata(Arrays.asList(sortedPm)); + this.metadata = sortedMetadata; + this.xValues = DoubleArray.ofUnsafe(sortedX); + this.yValues = DoubleArray.ofUnsafe(sortedY); + this.zValues = DoubleArray.ofUnsafe(sortedZ); + this.wValues = DoubleArray.ofUnsafe(sortedW); + this.interpolator = interpolator; + this.boundInterpolator = interpolator.bind(this.xValues, this.yValues, this.zValues, this.wValues); + this.parameterMetadata = IntStream.range(0, getParameterCount()) + .mapToObj(i -> sortedMetadata.getParameterMetadata(i)) + .collect(toImmutableList()); + } + + // basic validation + private void validateInputs( + CubeMetadata metadata, + DoubleArray xValues, + DoubleArray yValues, + DoubleArray zValues, + DoubleArray wValues, + CubeInterpolator interpolator) { + + ArgChecker.notNull(metadata, "metadata"); + ArgChecker.notNull(xValues, "xValues"); + ArgChecker.notNull(yValues, "yValues"); + ArgChecker.notNull(zValues, "zValues"); + ArgChecker.notNull(wValues, "wValues"); + ArgChecker.notNull(interpolator, "interpolator"); + if (xValues.size() < 2) { + throw new IllegalArgumentException("Length of x-values must be at least 2"); + } + if (xValues.size() != yValues.size()) { + throw new IllegalArgumentException("Length of x-values and y-values must match"); + } + if (xValues.size() != zValues.size()) { + throw new IllegalArgumentException("Length of x-values and z-values must match"); + } + if (xValues.size() != wValues.size()) { + throw new IllegalArgumentException("Length of x-values and w-values must match"); + } + metadata.getParameterMetadata().ifPresent(params -> { + if (xValues.size() != params.size()) { + throw new IllegalArgumentException("Length of x-values and parameter metadata must match when metadata present"); + } + }); + } + + // ensure standard constructor is invoked + private Object readResolve() { + return new InterpolatedNodalCube(metadata, xValues, yValues, zValues, wValues, interpolator); + } + + //------------------------------------------------------------------------- + @Override + public int getParameterCount() { + return wValues.size(); + } + + @Override + public double getParameter(int parameterIndex) { + return wValues.get(parameterIndex); + } + + @Override + public InterpolatedNodalCube withParameter(int parameterIndex, double newValue) { + return withWValues(wValues.with(parameterIndex, newValue)); + } + + @Override + public InterpolatedNodalCube withPerturbation(ParameterPerturbation perturbation) { + int size = wValues.size(); + DoubleArray perturbedValues = DoubleArray.of( + size, i -> perturbation.perturbParameter(i, wValues.get(i), getParameterMetadata(i))); + return withWValues(perturbedValues); + } + + //------------------------------------------------------------------------- + @Override + public double wValue(double x, double y, double z) { + return boundInterpolator.interpolate(x, y, z); + } + + @Override + public UnitParameterSensitivity wValueParameterSensitivity(double x, double y, double z) { + DoubleArray sensitivityValues = boundInterpolator.parameterSensitivity(x, y, z); + return createParameterSensitivity(sensitivityValues); + } + + //------------------------------------------------------------------------- + @Override + public ValueDerivatives firstPartialDerivatives(double x, double y, double z) { + return boundInterpolator.firstPartialDerivatives(x, y, z); + } + + //------------------------------------------------------------------------- + @Override + public InterpolatedNodalCube withMetadata(CubeMetadata metadata) { + return new InterpolatedNodalCube(metadata, xValues, yValues, zValues, wValues, interpolator); + } + + @Override + public InterpolatedNodalCube withWValues(DoubleArray wValues) { + return new InterpolatedNodalCube(metadata, xValues, yValues, zValues, wValues, interpolator); + } + + //------------------------------------------------------------------------- + @Override + public UnitParameterSensitivity createParameterSensitivity(DoubleArray sensitivities) { + return UnitParameterSensitivity.of(getName(), parameterMetadata, sensitivities); + } + + @Override + public CurrencyParameterSensitivity createParameterSensitivity(Currency currency, DoubleArray sensitivities) { + return CurrencyParameterSensitivity.of(getName(), parameterMetadata, currency, sensitivities); + } + + //------------------------- AUTOGENERATED START ------------------------- + /** + * The meta-bean for {@code InterpolatedNodalCube}. + * @return the meta-bean, not null + */ + public static InterpolatedNodalCube.Meta meta() { + return InterpolatedNodalCube.Meta.INSTANCE; + } + + static { + MetaBean.register(InterpolatedNodalCube.Meta.INSTANCE); + } + + /** + * The serialization version id. + */ + private static final long serialVersionUID = 1L; + + /** + * Returns a builder used to create an instance of the bean. + * @return the builder, not null + */ + public static InterpolatedNodalCube.Builder builder() { + return new InterpolatedNodalCube.Builder(); + } + + @Override + public InterpolatedNodalCube.Meta metaBean() { + return InterpolatedNodalCube.Meta.INSTANCE; + } + + //----------------------------------------------------------------------- + /** + * Gets the cube metadata. + *

    + * The metadata includes an optional list of parameter metadata. + * If present, the size of the parameter metadata list will match the number of parameters of this cube. + * @return the value of the property, not null + */ + @Override + public CubeMetadata getMetadata() { + return metadata; + } + + //----------------------------------------------------------------------- + /** + * Gets the array of x-values, one for each point. + *

    + * This array will contains at least two elements. + * @return the value of the property, not null + */ + @Override + public DoubleArray getXValues() { + return xValues; + } + + //----------------------------------------------------------------------- + /** + * Gets the array of y-values, one for each point. + *

    + * This array will contains at least two elements and be of the same length as x-values. + * @return the value of the property, not null + */ + @Override + public DoubleArray getYValues() { + return yValues; + } + + //----------------------------------------------------------------------- + /** + * Gets the array of z-values, one for each point. + *

    + * This array will contains at least two elements and be of the same length as x-values. + * @return the value of the property, not null + */ + @Override + public DoubleArray getZValues() { + return zValues; + } + + //----------------------------------------------------------------------- + /** + * Gets the array of w-values, one for each point. + *

    + * This array will contains at least two elements and be of the same length as x-values. + * @return the value of the property, not null + */ + @Override + public DoubleArray getWValues() { + return wValues; + } + + //----------------------------------------------------------------------- + /** + * Gets the underlying interpolator. + * @return the value of the property, not null + */ + public CubeInterpolator getInterpolator() { + return interpolator; + } + + //----------------------------------------------------------------------- + /** + * Returns a builder that allows this bean to be mutated. + * @return the mutable builder, not null + */ + public Builder toBuilder() { + return new Builder(this); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && obj.getClass() == this.getClass()) { + InterpolatedNodalCube other = (InterpolatedNodalCube) obj; + return JodaBeanUtils.equal(metadata, other.metadata) && + JodaBeanUtils.equal(xValues, other.xValues) && + JodaBeanUtils.equal(yValues, other.yValues) && + JodaBeanUtils.equal(zValues, other.zValues) && + JodaBeanUtils.equal(wValues, other.wValues) && + JodaBeanUtils.equal(interpolator, other.interpolator); + } + return false; + } + + @Override + public int hashCode() { + int hash = getClass().hashCode(); + hash = hash * 31 + JodaBeanUtils.hashCode(metadata); + hash = hash * 31 + JodaBeanUtils.hashCode(xValues); + hash = hash * 31 + JodaBeanUtils.hashCode(yValues); + hash = hash * 31 + JodaBeanUtils.hashCode(zValues); + hash = hash * 31 + JodaBeanUtils.hashCode(wValues); + hash = hash * 31 + JodaBeanUtils.hashCode(interpolator); + return hash; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(224); + buf.append("InterpolatedNodalCube{"); + buf.append("metadata").append('=').append(JodaBeanUtils.toString(metadata)).append(',').append(' '); + buf.append("xValues").append('=').append(JodaBeanUtils.toString(xValues)).append(',').append(' '); + buf.append("yValues").append('=').append(JodaBeanUtils.toString(yValues)).append(',').append(' '); + buf.append("zValues").append('=').append(JodaBeanUtils.toString(zValues)).append(',').append(' '); + buf.append("wValues").append('=').append(JodaBeanUtils.toString(wValues)).append(',').append(' '); + buf.append("interpolator").append('=').append(JodaBeanUtils.toString(interpolator)); + buf.append('}'); + return buf.toString(); + } + + //----------------------------------------------------------------------- + /** + * The meta-bean for {@code InterpolatedNodalCube}. + */ + public static final class Meta extends DirectMetaBean { + /** + * The singleton instance of the meta-bean. + */ + static final Meta INSTANCE = new Meta(); + + /** + * The meta-property for the {@code metadata} property. + */ + private final MetaProperty metadata = DirectMetaProperty.ofImmutable( + this, "metadata", InterpolatedNodalCube.class, CubeMetadata.class); + /** + * The meta-property for the {@code xValues} property. + */ + private final MetaProperty xValues = DirectMetaProperty.ofImmutable( + this, "xValues", InterpolatedNodalCube.class, DoubleArray.class); + /** + * The meta-property for the {@code yValues} property. + */ + private final MetaProperty yValues = DirectMetaProperty.ofImmutable( + this, "yValues", InterpolatedNodalCube.class, DoubleArray.class); + /** + * The meta-property for the {@code zValues} property. + */ + private final MetaProperty zValues = DirectMetaProperty.ofImmutable( + this, "zValues", InterpolatedNodalCube.class, DoubleArray.class); + /** + * The meta-property for the {@code wValues} property. + */ + private final MetaProperty wValues = DirectMetaProperty.ofImmutable( + this, "wValues", InterpolatedNodalCube.class, DoubleArray.class); + /** + * The meta-property for the {@code interpolator} property. + */ + private final MetaProperty interpolator = DirectMetaProperty.ofImmutable( + this, "interpolator", InterpolatedNodalCube.class, CubeInterpolator.class); + /** + * The meta-properties. + */ + private final Map> metaPropertyMap$ = new DirectMetaPropertyMap( + this, null, + "metadata", + "xValues", + "yValues", + "zValues", + "wValues", + "interpolator"); + + /** + * Restricted constructor. + */ + private Meta() { + } + + @Override + protected MetaProperty metaPropertyGet(String propertyName) { + switch (propertyName.hashCode()) { + case -450004177: // metadata + return metadata; + case 1681280954: // xValues + return xValues; + case -1726182661: // yValues + return yValues; + case -838678980: // zValues + return zValues; + case 793777273: // wValues + return wValues; + case 2096253127: // interpolator + return interpolator; + } + return super.metaPropertyGet(propertyName); + } + + @Override + public InterpolatedNodalCube.Builder builder() { + return new InterpolatedNodalCube.Builder(); + } + + @Override + public Class beanType() { + return InterpolatedNodalCube.class; + } + + @Override + public Map> metaPropertyMap() { + return metaPropertyMap$; + } + + //----------------------------------------------------------------------- + /** + * The meta-property for the {@code metadata} property. + * @return the meta-property, not null + */ + public MetaProperty metadata() { + return metadata; + } + + /** + * The meta-property for the {@code xValues} property. + * @return the meta-property, not null + */ + public MetaProperty xValues() { + return xValues; + } + + /** + * The meta-property for the {@code yValues} property. + * @return the meta-property, not null + */ + public MetaProperty yValues() { + return yValues; + } + + /** + * The meta-property for the {@code zValues} property. + * @return the meta-property, not null + */ + public MetaProperty zValues() { + return zValues; + } + + /** + * The meta-property for the {@code wValues} property. + * @return the meta-property, not null + */ + public MetaProperty wValues() { + return wValues; + } + + /** + * The meta-property for the {@code interpolator} property. + * @return the meta-property, not null + */ + public MetaProperty interpolator() { + return interpolator; + } + + //----------------------------------------------------------------------- + @Override + protected Object propertyGet(Bean bean, String propertyName, boolean quiet) { + switch (propertyName.hashCode()) { + case -450004177: // metadata + return ((InterpolatedNodalCube) bean).getMetadata(); + case 1681280954: // xValues + return ((InterpolatedNodalCube) bean).getXValues(); + case -1726182661: // yValues + return ((InterpolatedNodalCube) bean).getYValues(); + case -838678980: // zValues + return ((InterpolatedNodalCube) bean).getZValues(); + case 793777273: // wValues + return ((InterpolatedNodalCube) bean).getWValues(); + case 2096253127: // interpolator + return ((InterpolatedNodalCube) bean).getInterpolator(); + } + return super.propertyGet(bean, propertyName, quiet); + } + + @Override + protected void propertySet(Bean bean, String propertyName, Object newValue, boolean quiet) { + metaProperty(propertyName); + if (quiet) { + return; + } + throw new UnsupportedOperationException("Property cannot be written: " + propertyName); + } + + } + + //----------------------------------------------------------------------- + /** + * The bean-builder for {@code InterpolatedNodalCube}. + */ + public static final class Builder extends DirectFieldsBeanBuilder { + + private CubeMetadata metadata; + private DoubleArray xValues; + private DoubleArray yValues; + private DoubleArray zValues; + private DoubleArray wValues; + private CubeInterpolator interpolator; + + /** + * Restricted constructor. + */ + private Builder() { + } + + /** + * Restricted copy constructor. + * @param beanToCopy the bean to copy from, not null + */ + private Builder(InterpolatedNodalCube beanToCopy) { + this.metadata = beanToCopy.getMetadata(); + this.xValues = beanToCopy.getXValues(); + this.yValues = beanToCopy.getYValues(); + this.zValues = beanToCopy.getZValues(); + this.wValues = beanToCopy.getWValues(); + this.interpolator = beanToCopy.getInterpolator(); + } + + //----------------------------------------------------------------------- + @Override + public Object get(String propertyName) { + switch (propertyName.hashCode()) { + case -450004177: // metadata + return metadata; + case 1681280954: // xValues + return xValues; + case -1726182661: // yValues + return yValues; + case -838678980: // zValues + return zValues; + case 793777273: // wValues + return wValues; + case 2096253127: // interpolator + return interpolator; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + } + + @Override + public Builder set(String propertyName, Object newValue) { + switch (propertyName.hashCode()) { + case -450004177: // metadata + this.metadata = (CubeMetadata) newValue; + break; + case 1681280954: // xValues + this.xValues = (DoubleArray) newValue; + break; + case -1726182661: // yValues + this.yValues = (DoubleArray) newValue; + break; + case -838678980: // zValues + this.zValues = (DoubleArray) newValue; + break; + case 793777273: // wValues + this.wValues = (DoubleArray) newValue; + break; + case 2096253127: // interpolator + this.interpolator = (CubeInterpolator) newValue; + break; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + return this; + } + + @Override + public Builder set(MetaProperty property, Object value) { + super.set(property, value); + return this; + } + + @Override + public InterpolatedNodalCube build() { + return new InterpolatedNodalCube( + metadata, + xValues, + yValues, + zValues, + wValues, + interpolator); + } + + //----------------------------------------------------------------------- + /** + * Sets the cube metadata. + *

    + * The metadata includes an optional list of parameter metadata. + * If present, the size of the parameter metadata list will match the number of parameters of this cube. + * @param metadata the new value, not null + * @return this, for chaining, not null + */ + public Builder metadata(CubeMetadata metadata) { + JodaBeanUtils.notNull(metadata, "metadata"); + this.metadata = metadata; + return this; + } + + /** + * Sets the array of x-values, one for each point. + *

    + * This array will contains at least two elements. + * @param xValues the new value, not null + * @return this, for chaining, not null + */ + public Builder xValues(DoubleArray xValues) { + JodaBeanUtils.notNull(xValues, "xValues"); + this.xValues = xValues; + return this; + } + + /** + * Sets the array of y-values, one for each point. + *

    + * This array will contains at least two elements and be of the same length as x-values. + * @param yValues the new value, not null + * @return this, for chaining, not null + */ + public Builder yValues(DoubleArray yValues) { + JodaBeanUtils.notNull(yValues, "yValues"); + this.yValues = yValues; + return this; + } + + /** + * Sets the array of z-values, one for each point. + *

    + * This array will contains at least two elements and be of the same length as x-values. + * @param zValues the new value, not null + * @return this, for chaining, not null + */ + public Builder zValues(DoubleArray zValues) { + JodaBeanUtils.notNull(zValues, "zValues"); + this.zValues = zValues; + return this; + } + + /** + * Sets the array of w-values, one for each point. + *

    + * This array will contains at least two elements and be of the same length as x-values. + * @param wValues the new value, not null + * @return this, for chaining, not null + */ + public Builder wValues(DoubleArray wValues) { + JodaBeanUtils.notNull(wValues, "wValues"); + this.wValues = wValues; + return this; + } + + /** + * Sets the underlying interpolator. + * @param interpolator the new value, not null + * @return this, for chaining, not null + */ + public Builder interpolator(CubeInterpolator interpolator) { + JodaBeanUtils.notNull(interpolator, "interpolator"); + this.interpolator = interpolator; + return this; + } + + //----------------------------------------------------------------------- + @Override + public String toString() { + StringBuilder buf = new StringBuilder(224); + buf.append("InterpolatedNodalCube.Builder{"); + buf.append("metadata").append('=').append(JodaBeanUtils.toString(metadata)).append(',').append(' '); + buf.append("xValues").append('=').append(JodaBeanUtils.toString(xValues)).append(',').append(' '); + buf.append("yValues").append('=').append(JodaBeanUtils.toString(yValues)).append(',').append(' '); + buf.append("zValues").append('=').append(JodaBeanUtils.toString(zValues)).append(',').append(' '); + buf.append("wValues").append('=').append(JodaBeanUtils.toString(wValues)).append(',').append(' '); + buf.append("interpolator").append('=').append(JodaBeanUtils.toString(interpolator)); + buf.append('}'); + return buf.toString(); + } + + } + + //-------------------------- AUTOGENERATED END -------------------------- +} diff --git a/modules/market/src/main/java/com/opengamma/strata/market/cube/NodalCube.java b/modules/market/src/main/java/com/opengamma/strata/market/cube/NodalCube.java new file mode 100644 index 0000000000..b3b1847a96 --- /dev/null +++ b/modules/market/src/main/java/com/opengamma/strata/market/cube/NodalCube.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.market.cube; + +import com.opengamma.strata.collect.array.DoubleArray; +import com.opengamma.strata.market.param.ParameterMetadata; +import com.opengamma.strata.market.param.ParameterPerturbation; + +/** + * A cube based on {@code double} nodal points. + *

    + * This provides access to a cube mapping a {@code double} x-value, + * {@code double} y-value, {@code double} z-value to a {@code double} w-value. + *

    + * The parameters of an x-y-z cube are the x-y-z values. + * The values themselves are returned by {@link #getXValues()}, {@link #getYValues()}, + * {@link #getZValues()}, {@link #getWValues()}. + * The metadata is returned by {@link #getMetadata()}. + * + * @see InterpolatedNodalCube + */ +public interface NodalCube + extends Cube { + + /** + * Returns a new cube with the specified metadata. + *

    + * This allows the metadata of the cube to be changed while retaining all other information. + * If parameter metadata is present, the size of the list must match the number of parameters of this cube. + * + * @param metadata the new metadata for the cube + * @return the new cube + */ + @Override + public abstract NodalCube withMetadata(CubeMetadata metadata); + + /** + * Gets the metadata of the parameter at the specified index. + *

    + * If there is no specific parameter metadata, {@link SimpleCubeParameterMetadata} will be created. + * + * @param parameterIndex the zero-based index of the parameter to get + * @return the metadata of the parameter + * @throws IndexOutOfBoundsException if the index is invalid + */ + @Override + public default ParameterMetadata getParameterMetadata(int parameterIndex) { + return getMetadata().getParameterMetadata().map(pm -> pm.get(parameterIndex)) + .orElse(SimpleCubeParameterMetadata.of( + getMetadata().getXValueType(), + getXValues().get(parameterIndex), + getMetadata().getYValueType(), + getYValues().get(parameterIndex), + getMetadata().getZValueType(), + getZValues().get(parameterIndex))); + } + + /** + * Gets the known x-values of the cube. + *

    + * This method returns the fixed x-values used to define the cube. + * This will be of the same size as the y-values, z-values and w-values. + * + * @return the x-values + */ + public abstract DoubleArray getXValues(); + + /** + * Gets the known y-values of the cube. + *

    + * This method returns the fixed y-values used to define the cube. + * This will be of the same size as the y-values, z-values and w-values. + * + * @return the y-values + */ + public abstract DoubleArray getYValues(); + + /** + * Gets the known z-values of the cube. + *

    + * This method returns the fixed z-values used to define the cube. + * This will be of the same size as the x-values, y-values and w-values. + * + * @return the z-values + */ + public abstract DoubleArray getZValues(); + + /** + * Gets the known w-values of the cube. + *

    + * This method returns the fixed w-values used to define the cube. + * This will be of the same size as the x-values, y-values and z-values. + * + * @return the w-values + */ + public abstract DoubleArray getWValues(); + + /** + * Returns a new cube with the specified values. + *

    + * This allows the w-values of the cube to be changed while retaining the + * same x-values, y-values, z-values. + * + * @param values the new w-values for the cube + * @return the new cube + */ + public abstract NodalCube withWValues(DoubleArray values); + + //------------------------------------------------------------------------- + @Override + public abstract NodalCube withParameter(int parameterIndex, double newValue); + + @Override + public default NodalCube withPerturbation(ParameterPerturbation perturbation) { + return (NodalCube) Cube.super.withPerturbation(perturbation); + } + +} diff --git a/modules/market/src/main/java/com/opengamma/strata/market/cube/SimpleCubeParameterMetadata.java b/modules/market/src/main/java/com/opengamma/strata/market/cube/SimpleCubeParameterMetadata.java new file mode 100644 index 0000000000..6cfb0b746e --- /dev/null +++ b/modules/market/src/main/java/com/opengamma/strata/market/cube/SimpleCubeParameterMetadata.java @@ -0,0 +1,507 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.market.cube; + +import java.io.Serializable; +import java.util.Map; +import java.util.NoSuchElementException; + +import org.joda.beans.Bean; +import org.joda.beans.BeanBuilder; +import org.joda.beans.ImmutableBean; +import org.joda.beans.JodaBeanUtils; +import org.joda.beans.MetaBean; +import org.joda.beans.MetaProperty; +import org.joda.beans.gen.BeanDefinition; +import org.joda.beans.gen.PropertyDefinition; +import org.joda.beans.impl.direct.DirectMetaBean; +import org.joda.beans.impl.direct.DirectMetaProperty; +import org.joda.beans.impl.direct.DirectMetaPropertyMap; +import org.joda.beans.impl.direct.DirectPrivateBeanBuilder; + +import com.opengamma.strata.market.ValueType; +import com.opengamma.strata.market.param.ParameterMetadata; + +/** + * Simple parameter metadata containing the x, y, z values and type. + */ +@BeanDefinition(builderScope = "private") +public final class SimpleCubeParameterMetadata + implements ParameterMetadata, ImmutableBean, Serializable { + + /** + * The type of the x-value. + */ + @PropertyDefinition(validate = "notNull") + private final ValueType xValueType; + /** + * The x-value. + */ + @PropertyDefinition + private final double xValue; + /** + * The type of the y-value. + */ + @PropertyDefinition(validate = "notNull") + private final ValueType yValueType; + /** + * The y-value. + */ + @PropertyDefinition + private final double yValue; + /** + * The type of the z-value. + */ + @PropertyDefinition(validate = "notNull") + private final ValueType zValueType; + /** + * The z-value. + */ + @PropertyDefinition + private final double zValue; + + //------------------------------------------------------------------------- + /** + * Obtains an instance specifying information. + * + * @param xValueType the x-value type + * @param xValue the x-value + * @param yValueType the x-value type + * @param yValue the x-value + * @param zValueType the z-value type + * @param zValue the z-value + * @return the parameter metadata based on the date and label + */ + public static SimpleCubeParameterMetadata of( + ValueType xValueType, + double xValue, + ValueType yValueType, + double yValue, + ValueType zValueType, + double zValue) { + + return new SimpleCubeParameterMetadata(xValueType, xValue, yValueType, yValue, zValueType, zValue); + } + + //------------------------------------------------------------------------- + @Override + public String getLabel() { + return xValueType + "=" + xValue + ", " + yValueType + "=" + yValue + ", " + zValueType + "=" + zValue; + } + + @Override + public String getIdentifier() { + return getLabel(); + } + + //------------------------- AUTOGENERATED START ------------------------- + /** + * The meta-bean for {@code SimpleCubeParameterMetadata}. + * @return the meta-bean, not null + */ + public static SimpleCubeParameterMetadata.Meta meta() { + return SimpleCubeParameterMetadata.Meta.INSTANCE; + } + + static { + MetaBean.register(SimpleCubeParameterMetadata.Meta.INSTANCE); + } + + /** + * The serialization version id. + */ + private static final long serialVersionUID = 1L; + + private SimpleCubeParameterMetadata( + ValueType xValueType, + double xValue, + ValueType yValueType, + double yValue, + ValueType zValueType, + double zValue) { + JodaBeanUtils.notNull(xValueType, "xValueType"); + JodaBeanUtils.notNull(yValueType, "yValueType"); + JodaBeanUtils.notNull(zValueType, "zValueType"); + this.xValueType = xValueType; + this.xValue = xValue; + this.yValueType = yValueType; + this.yValue = yValue; + this.zValueType = zValueType; + this.zValue = zValue; + } + + @Override + public SimpleCubeParameterMetadata.Meta metaBean() { + return SimpleCubeParameterMetadata.Meta.INSTANCE; + } + + //----------------------------------------------------------------------- + /** + * Gets the type of the x-value. + * @return the value of the property, not null + */ + public ValueType getXValueType() { + return xValueType; + } + + //----------------------------------------------------------------------- + /** + * Gets the x-value. + * @return the value of the property + */ + public double getXValue() { + return xValue; + } + + //----------------------------------------------------------------------- + /** + * Gets the type of the y-value. + * @return the value of the property, not null + */ + public ValueType getYValueType() { + return yValueType; + } + + //----------------------------------------------------------------------- + /** + * Gets the y-value. + * @return the value of the property + */ + public double getYValue() { + return yValue; + } + + //----------------------------------------------------------------------- + /** + * Gets the type of the z-value. + * @return the value of the property, not null + */ + public ValueType getZValueType() { + return zValueType; + } + + //----------------------------------------------------------------------- + /** + * Gets the z-value. + * @return the value of the property + */ + public double getZValue() { + return zValue; + } + + //----------------------------------------------------------------------- + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && obj.getClass() == this.getClass()) { + SimpleCubeParameterMetadata other = (SimpleCubeParameterMetadata) obj; + return JodaBeanUtils.equal(xValueType, other.xValueType) && + JodaBeanUtils.equal(xValue, other.xValue) && + JodaBeanUtils.equal(yValueType, other.yValueType) && + JodaBeanUtils.equal(yValue, other.yValue) && + JodaBeanUtils.equal(zValueType, other.zValueType) && + JodaBeanUtils.equal(zValue, other.zValue); + } + return false; + } + + @Override + public int hashCode() { + int hash = getClass().hashCode(); + hash = hash * 31 + JodaBeanUtils.hashCode(xValueType); + hash = hash * 31 + JodaBeanUtils.hashCode(xValue); + hash = hash * 31 + JodaBeanUtils.hashCode(yValueType); + hash = hash * 31 + JodaBeanUtils.hashCode(yValue); + hash = hash * 31 + JodaBeanUtils.hashCode(zValueType); + hash = hash * 31 + JodaBeanUtils.hashCode(zValue); + return hash; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(224); + buf.append("SimpleCubeParameterMetadata{"); + buf.append("xValueType").append('=').append(JodaBeanUtils.toString(xValueType)).append(',').append(' '); + buf.append("xValue").append('=').append(JodaBeanUtils.toString(xValue)).append(',').append(' '); + buf.append("yValueType").append('=').append(JodaBeanUtils.toString(yValueType)).append(',').append(' '); + buf.append("yValue").append('=').append(JodaBeanUtils.toString(yValue)).append(',').append(' '); + buf.append("zValueType").append('=').append(JodaBeanUtils.toString(zValueType)).append(',').append(' '); + buf.append("zValue").append('=').append(JodaBeanUtils.toString(zValue)); + buf.append('}'); + return buf.toString(); + } + + //----------------------------------------------------------------------- + /** + * The meta-bean for {@code SimpleCubeParameterMetadata}. + */ + public static final class Meta extends DirectMetaBean { + /** + * The singleton instance of the meta-bean. + */ + static final Meta INSTANCE = new Meta(); + + /** + * The meta-property for the {@code xValueType} property. + */ + private final MetaProperty xValueType = DirectMetaProperty.ofImmutable( + this, "xValueType", SimpleCubeParameterMetadata.class, ValueType.class); + /** + * The meta-property for the {@code xValue} property. + */ + private final MetaProperty xValue = DirectMetaProperty.ofImmutable( + this, "xValue", SimpleCubeParameterMetadata.class, Double.TYPE); + /** + * The meta-property for the {@code yValueType} property. + */ + private final MetaProperty yValueType = DirectMetaProperty.ofImmutable( + this, "yValueType", SimpleCubeParameterMetadata.class, ValueType.class); + /** + * The meta-property for the {@code yValue} property. + */ + private final MetaProperty yValue = DirectMetaProperty.ofImmutable( + this, "yValue", SimpleCubeParameterMetadata.class, Double.TYPE); + /** + * The meta-property for the {@code zValueType} property. + */ + private final MetaProperty zValueType = DirectMetaProperty.ofImmutable( + this, "zValueType", SimpleCubeParameterMetadata.class, ValueType.class); + /** + * The meta-property for the {@code zValue} property. + */ + private final MetaProperty zValue = DirectMetaProperty.ofImmutable( + this, "zValue", SimpleCubeParameterMetadata.class, Double.TYPE); + /** + * The meta-properties. + */ + private final Map> metaPropertyMap$ = new DirectMetaPropertyMap( + this, null, + "xValueType", + "xValue", + "yValueType", + "yValue", + "zValueType", + "zValue"); + + /** + * Restricted constructor. + */ + private Meta() { + } + + @Override + protected MetaProperty metaPropertyGet(String propertyName) { + switch (propertyName.hashCode()) { + case -868509005: // xValueType + return xValueType; + case -777049127: // xValue + return xValue; + case -1065022510: // yValueType + return yValueType; + case -748419976: // yValue + return yValue; + case -1261536015: // zValueType + return zValueType; + case -719790825: // zValue + return zValue; + } + return super.metaPropertyGet(propertyName); + } + + @Override + public BeanBuilder builder() { + return new SimpleCubeParameterMetadata.Builder(); + } + + @Override + public Class beanType() { + return SimpleCubeParameterMetadata.class; + } + + @Override + public Map> metaPropertyMap() { + return metaPropertyMap$; + } + + //----------------------------------------------------------------------- + /** + * The meta-property for the {@code xValueType} property. + * @return the meta-property, not null + */ + public MetaProperty xValueType() { + return xValueType; + } + + /** + * The meta-property for the {@code xValue} property. + * @return the meta-property, not null + */ + public MetaProperty xValue() { + return xValue; + } + + /** + * The meta-property for the {@code yValueType} property. + * @return the meta-property, not null + */ + public MetaProperty yValueType() { + return yValueType; + } + + /** + * The meta-property for the {@code yValue} property. + * @return the meta-property, not null + */ + public MetaProperty yValue() { + return yValue; + } + + /** + * The meta-property for the {@code zValueType} property. + * @return the meta-property, not null + */ + public MetaProperty zValueType() { + return zValueType; + } + + /** + * The meta-property for the {@code zValue} property. + * @return the meta-property, not null + */ + public MetaProperty zValue() { + return zValue; + } + + //----------------------------------------------------------------------- + @Override + protected Object propertyGet(Bean bean, String propertyName, boolean quiet) { + switch (propertyName.hashCode()) { + case -868509005: // xValueType + return ((SimpleCubeParameterMetadata) bean).getXValueType(); + case -777049127: // xValue + return ((SimpleCubeParameterMetadata) bean).getXValue(); + case -1065022510: // yValueType + return ((SimpleCubeParameterMetadata) bean).getYValueType(); + case -748419976: // yValue + return ((SimpleCubeParameterMetadata) bean).getYValue(); + case -1261536015: // zValueType + return ((SimpleCubeParameterMetadata) bean).getZValueType(); + case -719790825: // zValue + return ((SimpleCubeParameterMetadata) bean).getZValue(); + } + return super.propertyGet(bean, propertyName, quiet); + } + + @Override + protected void propertySet(Bean bean, String propertyName, Object newValue, boolean quiet) { + metaProperty(propertyName); + if (quiet) { + return; + } + throw new UnsupportedOperationException("Property cannot be written: " + propertyName); + } + + } + + //----------------------------------------------------------------------- + /** + * The bean-builder for {@code SimpleCubeParameterMetadata}. + */ + private static final class Builder extends DirectPrivateBeanBuilder { + + private ValueType xValueType; + private double xValue; + private ValueType yValueType; + private double yValue; + private ValueType zValueType; + private double zValue; + + /** + * Restricted constructor. + */ + private Builder() { + } + + //----------------------------------------------------------------------- + @Override + public Object get(String propertyName) { + switch (propertyName.hashCode()) { + case -868509005: // xValueType + return xValueType; + case -777049127: // xValue + return xValue; + case -1065022510: // yValueType + return yValueType; + case -748419976: // yValue + return yValue; + case -1261536015: // zValueType + return zValueType; + case -719790825: // zValue + return zValue; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + } + + @Override + public Builder set(String propertyName, Object newValue) { + switch (propertyName.hashCode()) { + case -868509005: // xValueType + this.xValueType = (ValueType) newValue; + break; + case -777049127: // xValue + this.xValue = (Double) newValue; + break; + case -1065022510: // yValueType + this.yValueType = (ValueType) newValue; + break; + case -748419976: // yValue + this.yValue = (Double) newValue; + break; + case -1261536015: // zValueType + this.zValueType = (ValueType) newValue; + break; + case -719790825: // zValue + this.zValue = (Double) newValue; + break; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + return this; + } + + @Override + public SimpleCubeParameterMetadata build() { + return new SimpleCubeParameterMetadata( + xValueType, + xValue, + yValueType, + yValue, + zValueType, + zValue); + } + + //----------------------------------------------------------------------- + @Override + public String toString() { + StringBuilder buf = new StringBuilder(224); + buf.append("SimpleCubeParameterMetadata.Builder{"); + buf.append("xValueType").append('=').append(JodaBeanUtils.toString(xValueType)).append(',').append(' '); + buf.append("xValue").append('=').append(JodaBeanUtils.toString(xValue)).append(',').append(' '); + buf.append("yValueType").append('=').append(JodaBeanUtils.toString(yValueType)).append(',').append(' '); + buf.append("yValue").append('=').append(JodaBeanUtils.toString(yValue)).append(',').append(' '); + buf.append("zValueType").append('=').append(JodaBeanUtils.toString(zValueType)).append(',').append(' '); + buf.append("zValue").append('=').append(JodaBeanUtils.toString(zValue)); + buf.append('}'); + return buf.toString(); + } + + } + + //-------------------------- AUTOGENERATED END -------------------------- +} diff --git a/modules/market/src/main/java/com/opengamma/strata/market/cube/interpolator/BoundCubeInterpolator.java b/modules/market/src/main/java/com/opengamma/strata/market/cube/interpolator/BoundCubeInterpolator.java new file mode 100644 index 0000000000..af4600c9d4 --- /dev/null +++ b/modules/market/src/main/java/com/opengamma/strata/market/cube/interpolator/BoundCubeInterpolator.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.market.cube.interpolator; + +import com.opengamma.strata.basics.value.ValueDerivatives; +import com.opengamma.strata.collect.array.DoubleArray; + +/** + * A cube interpolator that has been bound to a specific cube. + *

    + * A bound interpolator is created from a {@link CubeInterpolator}. + * The bind process takes the definition of the interpolator and combines it with the x-y-z-w values. + * This allows implementations to optimize interpolation calculations. + */ +public interface BoundCubeInterpolator { + + /** + * Computes the w-value for the specified x-y-z value by interpolation. + * + * @param x the x-value to find the w-value for + * @param y the y-value to find the w-value for + * @param z the z-value to find the w-value for + * @return the value at the x-y-value + * @throws RuntimeException if the z-value cannot be calculated + */ + public abstract double interpolate(double x, double y, double z); + + /** + * Computes the partial derivatives of the cube. + *

    + * The first derivatives are {@code dw/dx, dw/dy, dw/dz}. + * The derivatives are in the following order: + *

      + *
    • [0] derivative with respect to x + *
    • [1] derivative with respect to y + *
    • [2] derivative with respect to z + *
    + * + * @param x the x-value at which the partial derivative is taken + * @param y the y-value at which the partial derivative is taken + * @param z the z-value at which the partial derivative is taken + * @return the w-value and it's partial first derivatives + * @throws RuntimeException if the derivative cannot be calculated + */ + public abstract ValueDerivatives firstPartialDerivatives(double x, double y, double z); + + /** + * Computes the sensitivity of the x-y-z-value with respect to the cube parameters. + *

    + * This returns an array with one element for each parameter of the cube. + * The array contains the sensitivity of the w-value at the specified x-y-z-value to each parameter. + * + * @param x the x-value at which the parameter sensitivity is computed + * @param y the y-value at which the parameter sensitivity is computed + * @param z the z-value at which the parameter sensitivity is computed + * @return the sensitivity + * @throws RuntimeException if the sensitivity cannot be calculated + */ + public abstract DoubleArray parameterSensitivity(double x, double y, double z); + +} diff --git a/modules/market/src/main/java/com/opengamma/strata/market/cube/interpolator/CubeInterpolator.java b/modules/market/src/main/java/com/opengamma/strata/market/cube/interpolator/CubeInterpolator.java new file mode 100644 index 0000000000..5c27379352 --- /dev/null +++ b/modules/market/src/main/java/com/opengamma/strata/market/cube/interpolator/CubeInterpolator.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.market.cube.interpolator; + +import com.opengamma.strata.collect.array.DoubleArray; + +/** + * Interface for interpolators that interpolate a cube. + */ +public interface CubeInterpolator { + + /** + * Binds this interpolator to a cube. + *

    + * The bind process takes the definition of the interpolator and combines it with the x-y-z-w values. + * This allows implementations to optimize interpolation calculations. + * + * @param xValues the x-values of the cube, must be sorted from low to high + * @param yValues the y-values of the cube, must be sorted from low to high within x + * @param zValues the z-values of the cube, must be sorted from low to high within x,y + * @param wValues the w-values of the cube + * @return the bound interpolator + */ + public abstract BoundCubeInterpolator bind( + DoubleArray xValues, + DoubleArray yValues, + DoubleArray zValues, + DoubleArray wValues); + +} diff --git a/modules/market/src/main/java/com/opengamma/strata/market/cube/interpolator/GridCubeInterpolator.java b/modules/market/src/main/java/com/opengamma/strata/market/cube/interpolator/GridCubeInterpolator.java new file mode 100644 index 0000000000..e9ea491184 --- /dev/null +++ b/modules/market/src/main/java/com/opengamma/strata/market/cube/interpolator/GridCubeInterpolator.java @@ -0,0 +1,900 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.market.cube.interpolator; + +import static com.opengamma.strata.market.curve.interpolator.CurveExtrapolators.FLAT; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.Map; +import java.util.NoSuchElementException; + +import org.joda.beans.Bean; +import org.joda.beans.BeanBuilder; +import org.joda.beans.ImmutableBean; +import org.joda.beans.JodaBeanUtils; +import org.joda.beans.MetaBean; +import org.joda.beans.MetaProperty; +import org.joda.beans.gen.BeanDefinition; +import org.joda.beans.gen.PropertyDefinition; +import org.joda.beans.impl.direct.DirectMetaBean; +import org.joda.beans.impl.direct.DirectMetaProperty; +import org.joda.beans.impl.direct.DirectMetaPropertyMap; +import org.joda.beans.impl.direct.DirectPrivateBeanBuilder; + +import com.google.common.collect.ImmutableList; +import com.opengamma.strata.basics.value.ValueDerivatives; +import com.opengamma.strata.collect.array.DoubleArray; +import com.opengamma.strata.market.curve.interpolator.CurveExtrapolator; +import com.opengamma.strata.market.curve.interpolator.CurveInterpolator; +import com.opengamma.strata.market.surface.interpolator.BoundSurfaceInterpolator; +import com.opengamma.strata.market.surface.interpolator.GridSurfaceInterpolator; + +/** + * A cube interpolator that is based on three curve interpolators. + *

    + * The interpolation operates in two stages. + * First, the parameters are grouped into sets, each with the same x value. + * Second, the y-z surface interpolator is used on each set of y-z values. + * Finally, the x curve interpolator is used on the results of the y-z surface interpolation. + *

    + * There should be at least two different y-values for each x-value, two different z-values for each y-value. + * If there is only one, then the associated w-value will always be returned. + */ +@BeanDefinition(builderScope = "private") +public final class GridCubeInterpolator + implements CubeInterpolator, ImmutableBean, Serializable { + + /** + * The x-value interpolator. + */ + @PropertyDefinition + private final CurveInterpolator xInterpolator; + /** + * The x-value left extrapolator. + */ + @PropertyDefinition + private final CurveExtrapolator xExtrapolatorLeft; + /** + * The x-value right extrapolator. + */ + @PropertyDefinition + private final CurveExtrapolator xExtrapolatorRight; + /** + * The y-value interpolator. + */ + @PropertyDefinition + private final CurveInterpolator yInterpolator; + /** + * The y-value left extrapolator. + */ + @PropertyDefinition + private final CurveExtrapolator yExtrapolatorLeft; + /** + * The y-value right extrapolator. + */ + @PropertyDefinition + private final CurveExtrapolator yExtrapolatorRight; + /** + * The z-value interpolator. + */ + @PropertyDefinition + private final CurveInterpolator zInterpolator; + /** + * The z-value left extrapolator. + */ + @PropertyDefinition + private final CurveExtrapolator zExtrapolatorLeft; + /** + * The z-value right extrapolator. + */ + @PropertyDefinition + private final CurveExtrapolator zExtrapolatorRight; + + //------------------------------------------------------------------------- + + /** + * Obtains an instance from the specified interpolators, using flat extrapolation. + * + * @param xInterpolator the x-value interpolator + * @param yInterpolator the y-value interpolator + * @param zInterpolator the z-value interpolator + * @return the index + * @throws IllegalArgumentException if the name is not known + */ + public static GridCubeInterpolator of( + CurveInterpolator xInterpolator, + CurveInterpolator yInterpolator, + CurveInterpolator zInterpolator) { + + return new GridCubeInterpolator(xInterpolator, FLAT, FLAT, yInterpolator, FLAT, FLAT, zInterpolator, FLAT, FLAT); + } + + /** + * Obtains an instance from the specified interpolators and extrapolators. + * + * @param xInterpolator the x-value interpolator + * @param xExtrapolator the x-value extrapolator + * @param yInterpolator the y-value interpolator + * @param yExtrapolator the y-value extrapolator + * @param zInterpolator the z-value interpolator + * @param zExtrapolator the z-value extrapolator + * @return the index + * @throws IllegalArgumentException if the name is not known + */ + public static GridCubeInterpolator of( + CurveInterpolator xInterpolator, + CurveExtrapolator xExtrapolator, + CurveInterpolator yInterpolator, + CurveExtrapolator yExtrapolator, + CurveInterpolator zInterpolator, + CurveExtrapolator zExtrapolator) { + + return new GridCubeInterpolator( + xInterpolator, + xExtrapolator, + xExtrapolator, + yInterpolator, + yExtrapolator, + yExtrapolator, + zInterpolator, + zExtrapolator, + zExtrapolator); + } + + /** + * Obtains an instance from the specified interpolators and extrapolators. + * + * @param xInterpolator the x-value interpolator + * @param xExtrapolatorLeft the x-value left extrapolator + * @param xExtrapolatorRight the x-value right extrapolator + * @param yInterpolator the y-value interpolator + * @param yExtrapolatorLeft the y-value left extrapolator + * @param yExtrapolatorRight the y-value right extrapolator + * @param zInterpolator the z-value interpolator + * @param zExtrapolatorLeft the z-value left extrapolator + * @param zExtrapolatorRight the z-value right extrapolator + * @return the index + * @throws IllegalArgumentException if the name is not known + */ + public static GridCubeInterpolator of( + CurveInterpolator xInterpolator, + CurveExtrapolator xExtrapolatorLeft, + CurveExtrapolator xExtrapolatorRight, + CurveInterpolator yInterpolator, + CurveExtrapolator yExtrapolatorLeft, + CurveExtrapolator yExtrapolatorRight, + CurveInterpolator zInterpolator, + CurveExtrapolator zExtrapolatorLeft, + CurveExtrapolator zExtrapolatorRight) { + + return new GridCubeInterpolator( + xInterpolator, + xExtrapolatorLeft, + xExtrapolatorRight, + yInterpolator, + yExtrapolatorLeft, + yExtrapolatorRight, + zInterpolator, + zExtrapolatorLeft, + zExtrapolatorRight); + } + + //------------------------------------------------------------------------- + @Override + public BoundCubeInterpolator bind( + DoubleArray xValues, + DoubleArray yValues, + DoubleArray zValues, + DoubleArray wValues) { + + // single loop around all parameters, collecting data + int size = xValues.size(); + int countUniqueX = 0; + double[] uniqueX = new double[size]; + double[] tempY = new double[size]; + double[] tempZ = new double[size]; + double[] tempW = new double[size]; + ImmutableList.Builder yzInterpBuilder = ImmutableList.builder(); + int i = 0; + while (i < size) { + double currentX = xValues.get(i); + uniqueX[countUniqueX] = currentX; + if (countUniqueX > 0 && uniqueX[countUniqueX - 1] > uniqueX[countUniqueX]) { + throw new IllegalArgumentException("Array of x-values must be sorted"); + } + int countSameX = 0; + while (i < size && xValues.get(i) == currentX) { + tempY[countSameX] = yValues.get(i); + tempZ[countSameX] = zValues.get(i); + tempW[countSameX] = wValues.get(i); + if (countSameX > 0 && tempY[countSameX - 1] > tempY[countSameX]) { + throw new IllegalArgumentException("Array of y-values must be sorted"); + } + countSameX++; + i++; + } + // create a surface for the same x-value + if (countSameX == 1) { + // when there is only one point, there is not enough data for a surface + // so the value must be returned without using the configured interpolator or extrapolator + yzInterpBuilder.add(new GridCubeInterpolator.ConstantSurfaceInterpolator(tempZ[0])); + } else { + // normal case, where the surface is created + DoubleArray yValuesSameX = DoubleArray.ofUnsafe(Arrays.copyOf(tempY, countSameX)); + DoubleArray zValuesSameX = DoubleArray.ofUnsafe(Arrays.copyOf(tempZ, countSameX)); + DoubleArray wValuesSameX = DoubleArray.ofUnsafe(Arrays.copyOf(tempW, countSameX)); + yzInterpBuilder.add(GridSurfaceInterpolator.of( + yInterpolator, + yExtrapolatorLeft, + yExtrapolatorRight, + zInterpolator, + zExtrapolatorLeft, + zExtrapolatorRight) + .bind(yValuesSameX, zValuesSameX, wValuesSameX)); + } + countUniqueX++; + } + if (countUniqueX == 1) { + throw new IllegalArgumentException("Cube interpolator requires at least two different x-values"); + } + DoubleArray uniqueXArray = DoubleArray.ofUnsafe(Arrays.copyOf(uniqueX, countUniqueX)); + BoundSurfaceInterpolator[] yzInterps = yzInterpBuilder.build().toArray(new BoundSurfaceInterpolator[0]); + return new GridCubeInterpolator.Bound( + xInterpolator, + xExtrapolatorLeft, + xExtrapolatorRight, + size, + uniqueXArray, + yzInterps); + } + + //------------------------------------------------------------------------- + + /** + * Bound interpolator. + */ + static class Bound implements BoundCubeInterpolator { + + private final CurveInterpolator xInterpolator; + private final CurveExtrapolator xExtrapolatorLeft; + private final CurveExtrapolator xExtrapolatorRight; + private final DoubleArray xValuesUnique; + private final int paramSize; + private final BoundSurfaceInterpolator[] yzInterpolators; + + Bound( + CurveInterpolator xInterpolator, + CurveExtrapolator xExtrapolatorLeft, + CurveExtrapolator xExtrapolatorRight, + int paramSize, + DoubleArray xValuesUnique, + BoundSurfaceInterpolator[] yzInterpolators) { + + this.xInterpolator = xInterpolator; + this.xExtrapolatorLeft = xExtrapolatorLeft; + this.xExtrapolatorRight = xExtrapolatorRight; + this.xValuesUnique = xValuesUnique; + this.paramSize = paramSize; + this.yzInterpolators = yzInterpolators; + } + + //------------------------------------------------------------------------- + @Override + public double interpolate(double x, double y, double z) { + // use each yz-interpolator to find the w-value for each unique x + DoubleArray wValuesEffective = DoubleArray.of(yzInterpolators.length, i -> yzInterpolators[i].interpolate(y, z)); + // interpolate unique x-values against derived w-values + return xInterpolator.bind(xValuesUnique, wValuesEffective, xExtrapolatorLeft, xExtrapolatorRight).interpolate(x); + } + + @Override + public DoubleArray parameterSensitivity(double x, double y, double z) { + int uniqueX = yzInterpolators.length; + final DoubleArray[] yzSens = new DoubleArray[uniqueX]; + // use each yz-interpolator to find the w-value sensitivity for each unique x + for (int i = 0; i < uniqueX; i++) { + yzSens[i] = yzInterpolators[i].parameterSensitivity(y, z); + } + // use each yz-interpolator to find the w-value for each unique x + DoubleArray wValuesEffective = DoubleArray.of(uniqueX, i -> yzInterpolators[i].interpolate(y, z)); + // find the sensitivity of the unique x-values against derived w-values + DoubleArray xSens = xInterpolator + .bind(xValuesUnique, wValuesEffective, xExtrapolatorLeft, xExtrapolatorRight) + .parameterSensitivity(x); + + return project(xSens, yzSens); + } + + //------------------------------------------------------------------------- + @Override + public ValueDerivatives firstPartialDerivatives(double x, double y, double z) { + int uniqueX = yzInterpolators.length; + DoubleArray wValuesEffective = DoubleArray.of(uniqueX, i -> yzInterpolators[i].interpolate(y, z)); + double xDerivative = + xInterpolator.bind(xValuesUnique, wValuesEffective, xExtrapolatorLeft, xExtrapolatorRight).firstDerivative(x); + DoubleArray yDerivatives = + DoubleArray.of(uniqueX, i -> yzInterpolators[i].firstPartialDerivatives(y, z).getDerivative(0)); + DoubleArray zDerivatives = + DoubleArray.of(uniqueX, i -> yzInterpolators[i].firstPartialDerivatives(y, z).getDerivative(1)); + double yDerivative = + xInterpolator.bind(xValuesUnique, yDerivatives, xExtrapolatorLeft, xExtrapolatorRight).interpolate(x); + double zDerivative = + xInterpolator.bind(xValuesUnique, zDerivatives, xExtrapolatorLeft, xExtrapolatorRight).interpolate(x); + double wValue = interpolate(x, y, z); + return ValueDerivatives.of(wValue, DoubleArray.of(xDerivative, yDerivative, zDerivative)); + } + + // project sensitivities back to parameters + private DoubleArray project(DoubleArray xSens, DoubleArray[] yzSens) { + int countParam = 0; + double[] paramSens = new double[paramSize]; + for (int i = 0; i < xSens.size(); i++) { + double xs = xSens.get(i); + DoubleArray yzs = yzSens[i]; + for (int j = 0; j < yzs.size(); j++) { + paramSens[countParam++] = xs * yzs.get(j); + } + } + return DoubleArray.ofUnsafe(paramSens); + } + } + + //------------------------------------------------------------------------- + + /** + * An interpolator that returns the single known value. + */ + static class ConstantSurfaceInterpolator implements BoundSurfaceInterpolator { + + private final double value; + + public ConstantSurfaceInterpolator(double value) { + this.value = value; + } + + @Override + public double interpolate(double x, double y) { + return value; + } + + @Override + public ValueDerivatives firstPartialDerivatives(double x, double y) { + return ValueDerivatives.of(value, DoubleArray.of(0d, 0d)); + } + + @Override + public DoubleArray parameterSensitivity(double x, double y) { + return DoubleArray.of(1); + } + + } + + //------------------------- AUTOGENERATED START ------------------------- + /** + * The meta-bean for {@code GridCubeInterpolator}. + * @return the meta-bean, not null + */ + public static GridCubeInterpolator.Meta meta() { + return GridCubeInterpolator.Meta.INSTANCE; + } + + static { + MetaBean.register(GridCubeInterpolator.Meta.INSTANCE); + } + + /** + * The serialization version id. + */ + private static final long serialVersionUID = 1L; + + private GridCubeInterpolator( + CurveInterpolator xInterpolator, + CurveExtrapolator xExtrapolatorLeft, + CurveExtrapolator xExtrapolatorRight, + CurveInterpolator yInterpolator, + CurveExtrapolator yExtrapolatorLeft, + CurveExtrapolator yExtrapolatorRight, + CurveInterpolator zInterpolator, + CurveExtrapolator zExtrapolatorLeft, + CurveExtrapolator zExtrapolatorRight) { + this.xInterpolator = xInterpolator; + this.xExtrapolatorLeft = xExtrapolatorLeft; + this.xExtrapolatorRight = xExtrapolatorRight; + this.yInterpolator = yInterpolator; + this.yExtrapolatorLeft = yExtrapolatorLeft; + this.yExtrapolatorRight = yExtrapolatorRight; + this.zInterpolator = zInterpolator; + this.zExtrapolatorLeft = zExtrapolatorLeft; + this.zExtrapolatorRight = zExtrapolatorRight; + } + + @Override + public GridCubeInterpolator.Meta metaBean() { + return GridCubeInterpolator.Meta.INSTANCE; + } + + //----------------------------------------------------------------------- + /** + * Gets the x-value interpolator. + * @return the value of the property + */ + public CurveInterpolator getXInterpolator() { + return xInterpolator; + } + + //----------------------------------------------------------------------- + /** + * Gets the x-value left extrapolator. + * @return the value of the property + */ + public CurveExtrapolator getXExtrapolatorLeft() { + return xExtrapolatorLeft; + } + + //----------------------------------------------------------------------- + /** + * Gets the x-value right extrapolator. + * @return the value of the property + */ + public CurveExtrapolator getXExtrapolatorRight() { + return xExtrapolatorRight; + } + + //----------------------------------------------------------------------- + /** + * Gets the y-value interpolator. + * @return the value of the property + */ + public CurveInterpolator getYInterpolator() { + return yInterpolator; + } + + //----------------------------------------------------------------------- + /** + * Gets the y-value left extrapolator. + * @return the value of the property + */ + public CurveExtrapolator getYExtrapolatorLeft() { + return yExtrapolatorLeft; + } + + //----------------------------------------------------------------------- + /** + * Gets the y-value right extrapolator. + * @return the value of the property + */ + public CurveExtrapolator getYExtrapolatorRight() { + return yExtrapolatorRight; + } + + //----------------------------------------------------------------------- + /** + * Gets the z-value interpolator. + * @return the value of the property + */ + public CurveInterpolator getZInterpolator() { + return zInterpolator; + } + + //----------------------------------------------------------------------- + /** + * Gets the z-value left extrapolator. + * @return the value of the property + */ + public CurveExtrapolator getZExtrapolatorLeft() { + return zExtrapolatorLeft; + } + + //----------------------------------------------------------------------- + /** + * Gets the z-value right extrapolator. + * @return the value of the property + */ + public CurveExtrapolator getZExtrapolatorRight() { + return zExtrapolatorRight; + } + + //----------------------------------------------------------------------- + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && obj.getClass() == this.getClass()) { + GridCubeInterpolator other = (GridCubeInterpolator) obj; + return JodaBeanUtils.equal(xInterpolator, other.xInterpolator) && + JodaBeanUtils.equal(xExtrapolatorLeft, other.xExtrapolatorLeft) && + JodaBeanUtils.equal(xExtrapolatorRight, other.xExtrapolatorRight) && + JodaBeanUtils.equal(yInterpolator, other.yInterpolator) && + JodaBeanUtils.equal(yExtrapolatorLeft, other.yExtrapolatorLeft) && + JodaBeanUtils.equal(yExtrapolatorRight, other.yExtrapolatorRight) && + JodaBeanUtils.equal(zInterpolator, other.zInterpolator) && + JodaBeanUtils.equal(zExtrapolatorLeft, other.zExtrapolatorLeft) && + JodaBeanUtils.equal(zExtrapolatorRight, other.zExtrapolatorRight); + } + return false; + } + + @Override + public int hashCode() { + int hash = getClass().hashCode(); + hash = hash * 31 + JodaBeanUtils.hashCode(xInterpolator); + hash = hash * 31 + JodaBeanUtils.hashCode(xExtrapolatorLeft); + hash = hash * 31 + JodaBeanUtils.hashCode(xExtrapolatorRight); + hash = hash * 31 + JodaBeanUtils.hashCode(yInterpolator); + hash = hash * 31 + JodaBeanUtils.hashCode(yExtrapolatorLeft); + hash = hash * 31 + JodaBeanUtils.hashCode(yExtrapolatorRight); + hash = hash * 31 + JodaBeanUtils.hashCode(zInterpolator); + hash = hash * 31 + JodaBeanUtils.hashCode(zExtrapolatorLeft); + hash = hash * 31 + JodaBeanUtils.hashCode(zExtrapolatorRight); + return hash; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(320); + buf.append("GridCubeInterpolator{"); + buf.append("xInterpolator").append('=').append(JodaBeanUtils.toString(xInterpolator)).append(',').append(' '); + buf.append("xExtrapolatorLeft").append('=').append(JodaBeanUtils.toString(xExtrapolatorLeft)).append(',').append(' '); + buf.append("xExtrapolatorRight").append('=').append(JodaBeanUtils.toString(xExtrapolatorRight)).append(',').append(' '); + buf.append("yInterpolator").append('=').append(JodaBeanUtils.toString(yInterpolator)).append(',').append(' '); + buf.append("yExtrapolatorLeft").append('=').append(JodaBeanUtils.toString(yExtrapolatorLeft)).append(',').append(' '); + buf.append("yExtrapolatorRight").append('=').append(JodaBeanUtils.toString(yExtrapolatorRight)).append(',').append(' '); + buf.append("zInterpolator").append('=').append(JodaBeanUtils.toString(zInterpolator)).append(',').append(' '); + buf.append("zExtrapolatorLeft").append('=').append(JodaBeanUtils.toString(zExtrapolatorLeft)).append(',').append(' '); + buf.append("zExtrapolatorRight").append('=').append(JodaBeanUtils.toString(zExtrapolatorRight)); + buf.append('}'); + return buf.toString(); + } + + //----------------------------------------------------------------------- + /** + * The meta-bean for {@code GridCubeInterpolator}. + */ + public static final class Meta extends DirectMetaBean { + /** + * The singleton instance of the meta-bean. + */ + static final Meta INSTANCE = new Meta(); + + /** + * The meta-property for the {@code xInterpolator} property. + */ + private final MetaProperty xInterpolator = DirectMetaProperty.ofImmutable( + this, "xInterpolator", GridCubeInterpolator.class, CurveInterpolator.class); + /** + * The meta-property for the {@code xExtrapolatorLeft} property. + */ + private final MetaProperty xExtrapolatorLeft = DirectMetaProperty.ofImmutable( + this, "xExtrapolatorLeft", GridCubeInterpolator.class, CurveExtrapolator.class); + /** + * The meta-property for the {@code xExtrapolatorRight} property. + */ + private final MetaProperty xExtrapolatorRight = DirectMetaProperty.ofImmutable( + this, "xExtrapolatorRight", GridCubeInterpolator.class, CurveExtrapolator.class); + /** + * The meta-property for the {@code yInterpolator} property. + */ + private final MetaProperty yInterpolator = DirectMetaProperty.ofImmutable( + this, "yInterpolator", GridCubeInterpolator.class, CurveInterpolator.class); + /** + * The meta-property for the {@code yExtrapolatorLeft} property. + */ + private final MetaProperty yExtrapolatorLeft = DirectMetaProperty.ofImmutable( + this, "yExtrapolatorLeft", GridCubeInterpolator.class, CurveExtrapolator.class); + /** + * The meta-property for the {@code yExtrapolatorRight} property. + */ + private final MetaProperty yExtrapolatorRight = DirectMetaProperty.ofImmutable( + this, "yExtrapolatorRight", GridCubeInterpolator.class, CurveExtrapolator.class); + /** + * The meta-property for the {@code zInterpolator} property. + */ + private final MetaProperty zInterpolator = DirectMetaProperty.ofImmutable( + this, "zInterpolator", GridCubeInterpolator.class, CurveInterpolator.class); + /** + * The meta-property for the {@code zExtrapolatorLeft} property. + */ + private final MetaProperty zExtrapolatorLeft = DirectMetaProperty.ofImmutable( + this, "zExtrapolatorLeft", GridCubeInterpolator.class, CurveExtrapolator.class); + /** + * The meta-property for the {@code zExtrapolatorRight} property. + */ + private final MetaProperty zExtrapolatorRight = DirectMetaProperty.ofImmutable( + this, "zExtrapolatorRight", GridCubeInterpolator.class, CurveExtrapolator.class); + /** + * The meta-properties. + */ + private final Map> metaPropertyMap$ = new DirectMetaPropertyMap( + this, null, + "xInterpolator", + "xExtrapolatorLeft", + "xExtrapolatorRight", + "yInterpolator", + "yExtrapolatorLeft", + "yExtrapolatorRight", + "zInterpolator", + "zExtrapolatorLeft", + "zExtrapolatorRight"); + + /** + * Restricted constructor. + */ + private Meta() { + } + + @Override + protected MetaProperty metaPropertyGet(String propertyName) { + switch (propertyName.hashCode()) { + case 1411950943: // xInterpolator + return xInterpolator; + case -382665134: // xExtrapolatorLeft + return xExtrapolatorLeft; + case 1027943729: // xExtrapolatorRight + return xExtrapolatorRight; + case 1118547936: // yInterpolator + return yInterpolator; + case 970644563: // yExtrapolatorLeft + return yExtrapolatorLeft; + case 30871376: // yExtrapolatorRight + return yExtrapolatorRight; + case 825144929: // zInterpolator + return zInterpolator; + case -1971013036: // zExtrapolatorLeft + return zExtrapolatorLeft; + case -966200977: // zExtrapolatorRight + return zExtrapolatorRight; + } + return super.metaPropertyGet(propertyName); + } + + @Override + public BeanBuilder builder() { + return new GridCubeInterpolator.Builder(); + } + + @Override + public Class beanType() { + return GridCubeInterpolator.class; + } + + @Override + public Map> metaPropertyMap() { + return metaPropertyMap$; + } + + //----------------------------------------------------------------------- + /** + * The meta-property for the {@code xInterpolator} property. + * @return the meta-property, not null + */ + public MetaProperty xInterpolator() { + return xInterpolator; + } + + /** + * The meta-property for the {@code xExtrapolatorLeft} property. + * @return the meta-property, not null + */ + public MetaProperty xExtrapolatorLeft() { + return xExtrapolatorLeft; + } + + /** + * The meta-property for the {@code xExtrapolatorRight} property. + * @return the meta-property, not null + */ + public MetaProperty xExtrapolatorRight() { + return xExtrapolatorRight; + } + + /** + * The meta-property for the {@code yInterpolator} property. + * @return the meta-property, not null + */ + public MetaProperty yInterpolator() { + return yInterpolator; + } + + /** + * The meta-property for the {@code yExtrapolatorLeft} property. + * @return the meta-property, not null + */ + public MetaProperty yExtrapolatorLeft() { + return yExtrapolatorLeft; + } + + /** + * The meta-property for the {@code yExtrapolatorRight} property. + * @return the meta-property, not null + */ + public MetaProperty yExtrapolatorRight() { + return yExtrapolatorRight; + } + + /** + * The meta-property for the {@code zInterpolator} property. + * @return the meta-property, not null + */ + public MetaProperty zInterpolator() { + return zInterpolator; + } + + /** + * The meta-property for the {@code zExtrapolatorLeft} property. + * @return the meta-property, not null + */ + public MetaProperty zExtrapolatorLeft() { + return zExtrapolatorLeft; + } + + /** + * The meta-property for the {@code zExtrapolatorRight} property. + * @return the meta-property, not null + */ + public MetaProperty zExtrapolatorRight() { + return zExtrapolatorRight; + } + + //----------------------------------------------------------------------- + @Override + protected Object propertyGet(Bean bean, String propertyName, boolean quiet) { + switch (propertyName.hashCode()) { + case 1411950943: // xInterpolator + return ((GridCubeInterpolator) bean).getXInterpolator(); + case -382665134: // xExtrapolatorLeft + return ((GridCubeInterpolator) bean).getXExtrapolatorLeft(); + case 1027943729: // xExtrapolatorRight + return ((GridCubeInterpolator) bean).getXExtrapolatorRight(); + case 1118547936: // yInterpolator + return ((GridCubeInterpolator) bean).getYInterpolator(); + case 970644563: // yExtrapolatorLeft + return ((GridCubeInterpolator) bean).getYExtrapolatorLeft(); + case 30871376: // yExtrapolatorRight + return ((GridCubeInterpolator) bean).getYExtrapolatorRight(); + case 825144929: // zInterpolator + return ((GridCubeInterpolator) bean).getZInterpolator(); + case -1971013036: // zExtrapolatorLeft + return ((GridCubeInterpolator) bean).getZExtrapolatorLeft(); + case -966200977: // zExtrapolatorRight + return ((GridCubeInterpolator) bean).getZExtrapolatorRight(); + } + return super.propertyGet(bean, propertyName, quiet); + } + + @Override + protected void propertySet(Bean bean, String propertyName, Object newValue, boolean quiet) { + metaProperty(propertyName); + if (quiet) { + return; + } + throw new UnsupportedOperationException("Property cannot be written: " + propertyName); + } + + } + + //----------------------------------------------------------------------- + /** + * The bean-builder for {@code GridCubeInterpolator}. + */ + private static final class Builder extends DirectPrivateBeanBuilder { + + private CurveInterpolator xInterpolator; + private CurveExtrapolator xExtrapolatorLeft; + private CurveExtrapolator xExtrapolatorRight; + private CurveInterpolator yInterpolator; + private CurveExtrapolator yExtrapolatorLeft; + private CurveExtrapolator yExtrapolatorRight; + private CurveInterpolator zInterpolator; + private CurveExtrapolator zExtrapolatorLeft; + private CurveExtrapolator zExtrapolatorRight; + + /** + * Restricted constructor. + */ + private Builder() { + } + + //----------------------------------------------------------------------- + @Override + public Object get(String propertyName) { + switch (propertyName.hashCode()) { + case 1411950943: // xInterpolator + return xInterpolator; + case -382665134: // xExtrapolatorLeft + return xExtrapolatorLeft; + case 1027943729: // xExtrapolatorRight + return xExtrapolatorRight; + case 1118547936: // yInterpolator + return yInterpolator; + case 970644563: // yExtrapolatorLeft + return yExtrapolatorLeft; + case 30871376: // yExtrapolatorRight + return yExtrapolatorRight; + case 825144929: // zInterpolator + return zInterpolator; + case -1971013036: // zExtrapolatorLeft + return zExtrapolatorLeft; + case -966200977: // zExtrapolatorRight + return zExtrapolatorRight; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + } + + @Override + public Builder set(String propertyName, Object newValue) { + switch (propertyName.hashCode()) { + case 1411950943: // xInterpolator + this.xInterpolator = (CurveInterpolator) newValue; + break; + case -382665134: // xExtrapolatorLeft + this.xExtrapolatorLeft = (CurveExtrapolator) newValue; + break; + case 1027943729: // xExtrapolatorRight + this.xExtrapolatorRight = (CurveExtrapolator) newValue; + break; + case 1118547936: // yInterpolator + this.yInterpolator = (CurveInterpolator) newValue; + break; + case 970644563: // yExtrapolatorLeft + this.yExtrapolatorLeft = (CurveExtrapolator) newValue; + break; + case 30871376: // yExtrapolatorRight + this.yExtrapolatorRight = (CurveExtrapolator) newValue; + break; + case 825144929: // zInterpolator + this.zInterpolator = (CurveInterpolator) newValue; + break; + case -1971013036: // zExtrapolatorLeft + this.zExtrapolatorLeft = (CurveExtrapolator) newValue; + break; + case -966200977: // zExtrapolatorRight + this.zExtrapolatorRight = (CurveExtrapolator) newValue; + break; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + return this; + } + + @Override + public GridCubeInterpolator build() { + return new GridCubeInterpolator( + xInterpolator, + xExtrapolatorLeft, + xExtrapolatorRight, + yInterpolator, + yExtrapolatorLeft, + yExtrapolatorRight, + zInterpolator, + zExtrapolatorLeft, + zExtrapolatorRight); + } + + //----------------------------------------------------------------------- + @Override + public String toString() { + StringBuilder buf = new StringBuilder(320); + buf.append("GridCubeInterpolator.Builder{"); + buf.append("xInterpolator").append('=').append(JodaBeanUtils.toString(xInterpolator)).append(',').append(' '); + buf.append("xExtrapolatorLeft").append('=').append(JodaBeanUtils.toString(xExtrapolatorLeft)).append(',').append(' '); + buf.append("xExtrapolatorRight").append('=').append(JodaBeanUtils.toString(xExtrapolatorRight)).append(',').append(' '); + buf.append("yInterpolator").append('=').append(JodaBeanUtils.toString(yInterpolator)).append(',').append(' '); + buf.append("yExtrapolatorLeft").append('=').append(JodaBeanUtils.toString(yExtrapolatorLeft)).append(',').append(' '); + buf.append("yExtrapolatorRight").append('=').append(JodaBeanUtils.toString(yExtrapolatorRight)).append(',').append(' '); + buf.append("zInterpolator").append('=').append(JodaBeanUtils.toString(zInterpolator)).append(',').append(' '); + buf.append("zExtrapolatorLeft").append('=').append(JodaBeanUtils.toString(zExtrapolatorLeft)).append(',').append(' '); + buf.append("zExtrapolatorRight").append('=').append(JodaBeanUtils.toString(zExtrapolatorRight)); + buf.append('}'); + return buf.toString(); + } + + } + + //-------------------------- AUTOGENERATED END -------------------------- +} diff --git a/modules/market/src/main/java/com/opengamma/strata/market/param/TenorTenorStrikeParameterMetadata.java b/modules/market/src/main/java/com/opengamma/strata/market/param/TenorTenorStrikeParameterMetadata.java new file mode 100644 index 0000000000..37480682cc --- /dev/null +++ b/modules/market/src/main/java/com/opengamma/strata/market/param/TenorTenorStrikeParameterMetadata.java @@ -0,0 +1,431 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.market.param; + +import java.io.Serializable; +import java.util.Map; +import java.util.NoSuchElementException; + +import org.joda.beans.Bean; +import org.joda.beans.BeanBuilder; +import org.joda.beans.ImmutableBean; +import org.joda.beans.JodaBeanUtils; +import org.joda.beans.MetaBean; +import org.joda.beans.MetaProperty; +import org.joda.beans.gen.BeanDefinition; +import org.joda.beans.gen.ImmutablePreBuild; +import org.joda.beans.gen.PropertyDefinition; +import org.joda.beans.impl.direct.DirectMetaBean; +import org.joda.beans.impl.direct.DirectMetaProperty; +import org.joda.beans.impl.direct.DirectMetaPropertyMap; +import org.joda.beans.impl.direct.DirectPrivateBeanBuilder; + +import com.opengamma.strata.basics.date.Tenor; +import com.opengamma.strata.collect.tuple.Triple; + +/** + * Parameter metadata based on an expiry tenor, an underlying tenor and strike value. + */ +@BeanDefinition(builderScope = "private") +public final class TenorTenorStrikeParameterMetadata + implements ParameterMetadata, ImmutableBean, Serializable { + + /** + * The expiry tenor associated with the parameter. + */ + @PropertyDefinition(validate = "notNull") + private final Tenor expiryTenor; + /** + * The underlying tenor associated with the parameter. + */ + @PropertyDefinition(validate = "notNull") + private final Tenor underlyingTenor; + /** + * The strike value associated with the parameter. + */ + @PropertyDefinition + private final double strike; + /** + * The label that describes the parameter, defaulted to the both tenors and strike. + */ + @PropertyDefinition(validate = "notEmpty", overrideGet = true) + private final String label; + + //------------------------------------------------------------------------- + + /** + * Creates node metadata with expiry tenor, underlying tenor and strike. + * + * @param expiryTenor the expiry tenor + * @param underlyingTenor the underlying + * @param strike the strike + * @return the metadata + */ + public static TenorTenorStrikeParameterMetadata of(Tenor expiryTenor, Tenor underlyingTenor, double strike) { + String label = Triple.of(expiryTenor, underlyingTenor, strike).toString(); + return new TenorTenorStrikeParameterMetadata(expiryTenor, underlyingTenor, strike, label); + } + + /** + * Creates node metadata with expiry tenor, underlying tenor, strike and label. + * + * @param expiryTenor the expiry tenor + * @param underlyingTenor the underlying + * @param strike the strike + * @param label the label + * @return the metadata + */ + public static TenorTenorStrikeParameterMetadata of( + Tenor expiryTenor, + Tenor underlyingTenor, + double strike, + String label) { + + return new TenorTenorStrikeParameterMetadata(expiryTenor, underlyingTenor, strike, label); + } + + @ImmutablePreBuild + private static void preBuild(Builder builder) { + if (builder.label == null) { + builder.label = Triple.of(builder.expiryTenor, builder.underlyingTenor, builder.strike).toString(); + } + } + + @Override + public Triple getIdentifier() { + return Triple.of(expiryTenor, underlyingTenor, strike); + } + + //------------------------- AUTOGENERATED START ------------------------- + /** + * The meta-bean for {@code TenorTenorStrikeParameterMetadata}. + * @return the meta-bean, not null + */ + public static TenorTenorStrikeParameterMetadata.Meta meta() { + return TenorTenorStrikeParameterMetadata.Meta.INSTANCE; + } + + static { + MetaBean.register(TenorTenorStrikeParameterMetadata.Meta.INSTANCE); + } + + /** + * The serialization version id. + */ + private static final long serialVersionUID = 1L; + + private TenorTenorStrikeParameterMetadata( + Tenor expiryTenor, + Tenor underlyingTenor, + double strike, + String label) { + JodaBeanUtils.notNull(expiryTenor, "expiryTenor"); + JodaBeanUtils.notNull(underlyingTenor, "underlyingTenor"); + JodaBeanUtils.notEmpty(label, "label"); + this.expiryTenor = expiryTenor; + this.underlyingTenor = underlyingTenor; + this.strike = strike; + this.label = label; + } + + @Override + public TenorTenorStrikeParameterMetadata.Meta metaBean() { + return TenorTenorStrikeParameterMetadata.Meta.INSTANCE; + } + + //----------------------------------------------------------------------- + /** + * Gets the expiry tenor associated with the parameter. + * @return the value of the property, not null + */ + public Tenor getExpiryTenor() { + return expiryTenor; + } + + //----------------------------------------------------------------------- + /** + * Gets the underlying tenor associated with the parameter. + * @return the value of the property, not null + */ + public Tenor getUnderlyingTenor() { + return underlyingTenor; + } + + //----------------------------------------------------------------------- + /** + * Gets the strike value associated with the parameter. + * @return the value of the property + */ + public double getStrike() { + return strike; + } + + //----------------------------------------------------------------------- + /** + * Gets the label that describes the parameter, defaulted to the both tenors and strike. + * @return the value of the property, not empty + */ + @Override + public String getLabel() { + return label; + } + + //----------------------------------------------------------------------- + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && obj.getClass() == this.getClass()) { + TenorTenorStrikeParameterMetadata other = (TenorTenorStrikeParameterMetadata) obj; + return JodaBeanUtils.equal(expiryTenor, other.expiryTenor) && + JodaBeanUtils.equal(underlyingTenor, other.underlyingTenor) && + JodaBeanUtils.equal(strike, other.strike) && + JodaBeanUtils.equal(label, other.label); + } + return false; + } + + @Override + public int hashCode() { + int hash = getClass().hashCode(); + hash = hash * 31 + JodaBeanUtils.hashCode(expiryTenor); + hash = hash * 31 + JodaBeanUtils.hashCode(underlyingTenor); + hash = hash * 31 + JodaBeanUtils.hashCode(strike); + hash = hash * 31 + JodaBeanUtils.hashCode(label); + return hash; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(160); + buf.append("TenorTenorStrikeParameterMetadata{"); + buf.append("expiryTenor").append('=').append(JodaBeanUtils.toString(expiryTenor)).append(',').append(' '); + buf.append("underlyingTenor").append('=').append(JodaBeanUtils.toString(underlyingTenor)).append(',').append(' '); + buf.append("strike").append('=').append(JodaBeanUtils.toString(strike)).append(',').append(' '); + buf.append("label").append('=').append(JodaBeanUtils.toString(label)); + buf.append('}'); + return buf.toString(); + } + + //----------------------------------------------------------------------- + /** + * The meta-bean for {@code TenorTenorStrikeParameterMetadata}. + */ + public static final class Meta extends DirectMetaBean { + /** + * The singleton instance of the meta-bean. + */ + static final Meta INSTANCE = new Meta(); + + /** + * The meta-property for the {@code expiryTenor} property. + */ + private final MetaProperty expiryTenor = DirectMetaProperty.ofImmutable( + this, "expiryTenor", TenorTenorStrikeParameterMetadata.class, Tenor.class); + /** + * The meta-property for the {@code underlyingTenor} property. + */ + private final MetaProperty underlyingTenor = DirectMetaProperty.ofImmutable( + this, "underlyingTenor", TenorTenorStrikeParameterMetadata.class, Tenor.class); + /** + * The meta-property for the {@code strike} property. + */ + private final MetaProperty strike = DirectMetaProperty.ofImmutable( + this, "strike", TenorTenorStrikeParameterMetadata.class, Double.TYPE); + /** + * The meta-property for the {@code label} property. + */ + private final MetaProperty label = DirectMetaProperty.ofImmutable( + this, "label", TenorTenorStrikeParameterMetadata.class, String.class); + /** + * The meta-properties. + */ + private final Map> metaPropertyMap$ = new DirectMetaPropertyMap( + this, null, + "expiryTenor", + "underlyingTenor", + "strike", + "label"); + + /** + * Restricted constructor. + */ + private Meta() { + } + + @Override + protected MetaProperty metaPropertyGet(String propertyName) { + switch (propertyName.hashCode()) { + case 465802573: // expiryTenor + return expiryTenor; + case -824175261: // underlyingTenor + return underlyingTenor; + case -891985998: // strike + return strike; + case 102727412: // label + return label; + } + return super.metaPropertyGet(propertyName); + } + + @Override + public BeanBuilder builder() { + return new TenorTenorStrikeParameterMetadata.Builder(); + } + + @Override + public Class beanType() { + return TenorTenorStrikeParameterMetadata.class; + } + + @Override + public Map> metaPropertyMap() { + return metaPropertyMap$; + } + + //----------------------------------------------------------------------- + /** + * The meta-property for the {@code expiryTenor} property. + * @return the meta-property, not null + */ + public MetaProperty expiryTenor() { + return expiryTenor; + } + + /** + * The meta-property for the {@code underlyingTenor} property. + * @return the meta-property, not null + */ + public MetaProperty underlyingTenor() { + return underlyingTenor; + } + + /** + * The meta-property for the {@code strike} property. + * @return the meta-property, not null + */ + public MetaProperty strike() { + return strike; + } + + /** + * The meta-property for the {@code label} property. + * @return the meta-property, not null + */ + public MetaProperty label() { + return label; + } + + //----------------------------------------------------------------------- + @Override + protected Object propertyGet(Bean bean, String propertyName, boolean quiet) { + switch (propertyName.hashCode()) { + case 465802573: // expiryTenor + return ((TenorTenorStrikeParameterMetadata) bean).getExpiryTenor(); + case -824175261: // underlyingTenor + return ((TenorTenorStrikeParameterMetadata) bean).getUnderlyingTenor(); + case -891985998: // strike + return ((TenorTenorStrikeParameterMetadata) bean).getStrike(); + case 102727412: // label + return ((TenorTenorStrikeParameterMetadata) bean).getLabel(); + } + return super.propertyGet(bean, propertyName, quiet); + } + + @Override + protected void propertySet(Bean bean, String propertyName, Object newValue, boolean quiet) { + metaProperty(propertyName); + if (quiet) { + return; + } + throw new UnsupportedOperationException("Property cannot be written: " + propertyName); + } + + } + + //----------------------------------------------------------------------- + /** + * The bean-builder for {@code TenorTenorStrikeParameterMetadata}. + */ + private static final class Builder extends DirectPrivateBeanBuilder { + + private Tenor expiryTenor; + private Tenor underlyingTenor; + private double strike; + private String label; + + /** + * Restricted constructor. + */ + private Builder() { + } + + //----------------------------------------------------------------------- + @Override + public Object get(String propertyName) { + switch (propertyName.hashCode()) { + case 465802573: // expiryTenor + return expiryTenor; + case -824175261: // underlyingTenor + return underlyingTenor; + case -891985998: // strike + return strike; + case 102727412: // label + return label; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + } + + @Override + public Builder set(String propertyName, Object newValue) { + switch (propertyName.hashCode()) { + case 465802573: // expiryTenor + this.expiryTenor = (Tenor) newValue; + break; + case -824175261: // underlyingTenor + this.underlyingTenor = (Tenor) newValue; + break; + case -891985998: // strike + this.strike = (Double) newValue; + break; + case 102727412: // label + this.label = (String) newValue; + break; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + return this; + } + + @Override + public TenorTenorStrikeParameterMetadata build() { + preBuild(this); + return new TenorTenorStrikeParameterMetadata( + expiryTenor, + underlyingTenor, + strike, + label); + } + + //----------------------------------------------------------------------- + @Override + public String toString() { + StringBuilder buf = new StringBuilder(160); + buf.append("TenorTenorStrikeParameterMetadata.Builder{"); + buf.append("expiryTenor").append('=').append(JodaBeanUtils.toString(expiryTenor)).append(',').append(' '); + buf.append("underlyingTenor").append('=').append(JodaBeanUtils.toString(underlyingTenor)).append(',').append(' '); + buf.append("strike").append('=').append(JodaBeanUtils.toString(strike)).append(',').append(' '); + buf.append("label").append('=').append(JodaBeanUtils.toString(label)); + buf.append('}'); + return buf.toString(); + } + + } + + //-------------------------- AUTOGENERATED END -------------------------- +} diff --git a/modules/market/src/test/java/com/opengamma/strata/market/cube/CubeInfoTypeTest.java b/modules/market/src/test/java/com/opengamma/strata/market/cube/CubeInfoTypeTest.java new file mode 100644 index 0000000000..7aa1ca3357 --- /dev/null +++ b/modules/market/src/test/java/com/opengamma/strata/market/cube/CubeInfoTypeTest.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.market.cube; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +import com.opengamma.strata.basics.date.DayCount; +import com.opengamma.strata.market.model.MoneynessType; + +/** + * Test {@link CubeInfoType}. + */ +public class CubeInfoTypeTest { + + @Test + public void test_DAY_COUNT() { + CubeInfoType test = CubeInfoType.DAY_COUNT; + assertThat(test.toString()).isEqualTo("DayCount"); + } + + @Test + public void test_MONEYNESS_TYPE() { + CubeInfoType test = CubeInfoType.MONEYNESS_TYPE; + assertThat(test.toString()).isEqualTo("MoneynessType"); + } + + @Test + public void coverage() { + CubeInfoType test = CubeInfoType.of("Foo"); + assertThat(test.toString()).isEqualTo("Foo"); + } + +} diff --git a/modules/market/src/test/java/com/opengamma/strata/market/cube/CubeNameTest.java b/modules/market/src/test/java/com/opengamma/strata/market/cube/CubeNameTest.java new file mode 100644 index 0000000000..adfedee509 --- /dev/null +++ b/modules/market/src/test/java/com/opengamma/strata/market/cube/CubeNameTest.java @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.market.cube; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +/** + * Test {@link CubeName}. + */ +public class CubeNameTest { + + @Test + public void test_of() { + CubeName test = CubeName.of("Foo"); + assertThat(test.getName()).isEqualTo("Foo"); + assertThat(test.getMarketDataType()).isEqualTo(Cube.class); + assertThat(test.toString()).isEqualTo("Foo"); + assertThat(test.compareTo(CubeName.of("Goo")) < 0).isTrue(); + } + +} diff --git a/modules/market/src/test/java/com/opengamma/strata/market/cube/CubesTest.java b/modules/market/src/test/java/com/opengamma/strata/market/cube/CubesTest.java new file mode 100644 index 0000000000..4391ac5ed7 --- /dev/null +++ b/modules/market/src/test/java/com/opengamma/strata/market/cube/CubesTest.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.market.cube; + +import static com.opengamma.strata.basics.date.DayCounts.ACT_360; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +import com.opengamma.strata.market.ValueType; + +/** + * Test {@link Cubes}. + */ +public class CubesTest { + + private static final String NAME = "Foo"; + private static final CubeName CUBE_NAME = CubeName.of(NAME); + + @Test + public void test_normalVolatilityByExpiryTenorStrike_string() { + CubeMetadata test = Cubes.normalVolatilityByExpiryTenorStrike(NAME, ACT_360); + CubeMetadata expected = DefaultCubeMetadata.builder() + .cubeName(CUBE_NAME) + .xValueType(ValueType.YEAR_FRACTION) + .yValueType(ValueType.YEAR_FRACTION) + .zValueType(ValueType.STRIKE) + .wValueType(ValueType.NORMAL_VOLATILITY) + .dayCount(ACT_360) + .build(); + assertThat(test).isEqualTo(expected); + } + + @Test + public void test_normalVolatilityByExpiryTenorStrike_cubeName() { + CubeMetadata test = Cubes.normalVolatilityByExpiryTenorStrike(CUBE_NAME, ACT_360); + CubeMetadata expected = DefaultCubeMetadata.builder() + .cubeName(CUBE_NAME) + .xValueType(ValueType.YEAR_FRACTION) + .yValueType(ValueType.YEAR_FRACTION) + .zValueType(ValueType.STRIKE) + .wValueType(ValueType.NORMAL_VOLATILITY) + .dayCount(ACT_360) + .build(); + assertThat(test).isEqualTo(expected); + } + +} diff --git a/modules/market/src/test/java/com/opengamma/strata/market/cube/DefaultCubeMetadataTest.java b/modules/market/src/test/java/com/opengamma/strata/market/cube/DefaultCubeMetadataTest.java new file mode 100644 index 0000000000..f783190f34 --- /dev/null +++ b/modules/market/src/test/java/com/opengamma/strata/market/cube/DefaultCubeMetadataTest.java @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.market.cube; + +import static com.opengamma.strata.basics.date.DayCounts.ACT_360; +import static com.opengamma.strata.basics.date.DayCounts.ACT_365F; +import static com.opengamma.strata.collect.TestHelper.assertSerialization; +import static com.opengamma.strata.collect.TestHelper.coverBeanEquals; +import static com.opengamma.strata.collect.TestHelper.coverImmutableBean; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +import java.util.Optional; + +import org.junit.jupiter.api.Test; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.opengamma.strata.market.ValueType; +import com.opengamma.strata.market.param.LabelParameterMetadata; +import com.opengamma.strata.market.param.ParameterMetadata; + +/** + * Test {@link DefaultCubeMetadata}. + */ +public class DefaultCubeMetadataTest { + + private static final String NAME = "TestCube"; + private static final CubeName CUBE_NAME = CubeName.of(NAME); + private static final LabelParameterMetadata LABEL_METADATA = LabelParameterMetadata.of("LABEL"); + private static final LabelParameterMetadata LABEL_METADATA2 = LabelParameterMetadata.of("LABEL2"); + private static final CubeInfoType DESCRIPTION = CubeInfoType.of("Description"); + + //------------------------------------------------------------------------- + @Test + public void test_of_String_noMetadata() { + DefaultCubeMetadata test = DefaultCubeMetadata.of(NAME); + assertThat(test.getCubeName()).isEqualTo(CUBE_NAME); + assertThat(test.getXValueType()).isEqualTo(ValueType.UNKNOWN); + assertThat(test.getYValueType()).isEqualTo(ValueType.UNKNOWN); + assertThat(test.getZValueType()).isEqualTo(ValueType.UNKNOWN); + assertThat(test.getWValueType()).isEqualTo(ValueType.UNKNOWN); + assertThat(test.getInfo()).isEqualTo(ImmutableMap.of()); + assertThat(test.getParameterMetadata().isPresent()).isFalse(); + } + + @Test + public void test_of_CubeName_noMetadata() { + DefaultCubeMetadata test = DefaultCubeMetadata.of(CUBE_NAME); + assertThat(test.getCubeName()).isEqualTo(CUBE_NAME); + assertThat(test.getXValueType()).isEqualTo(ValueType.UNKNOWN); + assertThat(test.getYValueType()).isEqualTo(ValueType.UNKNOWN); + assertThat(test.getZValueType()).isEqualTo(ValueType.UNKNOWN); + assertThat(test.getWValueType()).isEqualTo(ValueType.UNKNOWN); + assertThat(test.getInfo()).isEqualTo(ImmutableMap.of()); + assertThat(test.getParameterMetadata().isPresent()).isFalse(); + assertThat(test.findParameterIndex(ParameterMetadata.empty())).isEmpty(); + assertThat(test.findParameterIndex(LABEL_METADATA)).isEmpty(); + } + + @Test + public void test_builder1() { + DefaultCubeMetadata test = DefaultCubeMetadata.builder() + .cubeName(CUBE_NAME.toString()) + .xValueType(ValueType.YEAR_FRACTION) + .yValueType(ValueType.STRIKE) + .zValueType(ValueType.DISCOUNT_FACTOR) + .wValueType(ValueType.ZERO_RATE) + .dayCount(ACT_365F) + .addInfo(DESCRIPTION, "Hello") + .parameterMetadata(ImmutableList.of(ParameterMetadata.empty())) + .build(); + assertThat(test.getCubeName()).isEqualTo(CUBE_NAME); + assertThat(test.getXValueType()).isEqualTo(ValueType.YEAR_FRACTION); + assertThat(test.getYValueType()).isEqualTo(ValueType.STRIKE); + assertThat(test.getZValueType()).isEqualTo(ValueType.DISCOUNT_FACTOR); + assertThat(test.getWValueType()).isEqualTo(ValueType.ZERO_RATE); + assertThat(test.getInfo(CubeInfoType.DAY_COUNT)).isEqualTo(ACT_365F); + assertThat(test.findInfo(CubeInfoType.DAY_COUNT)).isEqualTo(Optional.of(ACT_365F)); + assertThat(test.getInfo(DESCRIPTION)).isEqualTo("Hello"); + assertThat(test.findInfo(DESCRIPTION)).isEqualTo(Optional.of("Hello")); + assertThat(test.findInfo(CubeInfoType.of("Rubbish"))).isEqualTo(Optional.empty()); + assertThat(test.getParameterMetadata().isPresent()).isTrue(); + assertThat(test.getParameterMetadata().get()).containsExactly(ParameterMetadata.empty()); + } + + @Test + public void test_builder2() { + DefaultCubeMetadata test = DefaultCubeMetadata.builder() + .cubeName(CUBE_NAME) + .xValueType(ValueType.YEAR_FRACTION) + .yValueType(ValueType.DISCOUNT_FACTOR) + .zValueType(ValueType.STRIKE) + .wValueType(ValueType.ZERO_RATE) + .dayCount(ACT_365F) + .addInfo(CubeInfoType.DAY_COUNT, null) + .addInfo(DESCRIPTION, "Hello") + .parameterMetadata(ImmutableList.of(LABEL_METADATA)) + .build(); + assertThat(test.getCubeName()).isEqualTo(CUBE_NAME); + assertThat(test.getXValueType()).isEqualTo(ValueType.YEAR_FRACTION); + assertThat(test.getYValueType()).isEqualTo(ValueType.DISCOUNT_FACTOR); + assertThat(test.getZValueType()).isEqualTo(ValueType.STRIKE); + assertThat(test.getWValueType()).isEqualTo(ValueType.ZERO_RATE); + assertThatIllegalArgumentException() + .isThrownBy(() -> test.getInfo(CubeInfoType.DAY_COUNT)); + assertThat(test.findInfo(CubeInfoType.DAY_COUNT)).isEmpty(); + assertThat(test.getInfo(DESCRIPTION)).isEqualTo("Hello"); + assertThat(test.findInfo(DESCRIPTION)).isEqualTo(Optional.of("Hello")); + assertThat(test.findInfo(CubeInfoType.of("Rubbish"))).isEqualTo(Optional.empty()); + assertThat(test.getParameterMetadata().isPresent()).isTrue(); + assertThat(test.getParameterMetadata().get()).containsExactly(LABEL_METADATA); + assertThat(test.findParameterIndex(ParameterMetadata.empty()).isPresent()).isFalse(); + assertThat(test.findParameterIndex(LABEL_METADATA)).hasValue(0); + assertThat(test.findParameterIndex(LABEL_METADATA2)).isEmpty(); + } + + @Test + public void test_builder3() { + DefaultCubeMetadata test = DefaultCubeMetadata.builder() + .cubeName(CUBE_NAME) + .parameterMetadata(ImmutableList.of(ParameterMetadata.empty())) + .clearParameterMetadata() + .build(); + assertThat(test.getCubeName()).isEqualTo(CUBE_NAME); + assertThat(test.getXValueType()).isEqualTo(ValueType.UNKNOWN); + assertThat(test.getYValueType()).isEqualTo(ValueType.UNKNOWN); + assertThat(test.getZValueType()).isEqualTo(ValueType.UNKNOWN); + assertThat(test.getWValueType()).isEqualTo(ValueType.UNKNOWN); + assertThat(test.getParameterMetadata().isPresent()).isFalse(); + } + + //------------------------------------------------------------------------- + @Test + public void test_withInfo() { + DefaultCubeMetadata base = DefaultCubeMetadata.of(CUBE_NAME); + assertThat(base.findInfo(CubeInfoType.DAY_COUNT).isPresent()).isFalse(); + DefaultCubeMetadata test = base.withInfo(CubeInfoType.DAY_COUNT, ACT_360); + assertThat(base.findInfo(CubeInfoType.DAY_COUNT).isPresent()).isFalse(); + assertThat(test.findInfo(CubeInfoType.DAY_COUNT).isPresent()).isTrue(); + } + + //------------------------------------------------------------------------- + @Test + public void test_withParameterMetadata() { + DefaultCubeMetadata test = DefaultCubeMetadata.of(CUBE_NAME) + .withParameterMetadata(ImmutableList.of(ParameterMetadata.empty())); + assertThat(test.getCubeName()).isEqualTo(CUBE_NAME); + assertThat(test.getXValueType()).isEqualTo(ValueType.UNKNOWN); + assertThat(test.getYValueType()).isEqualTo(ValueType.UNKNOWN); + assertThat(test.getZValueType()).isEqualTo(ValueType.UNKNOWN); + assertThat(test.getWValueType()).isEqualTo(ValueType.UNKNOWN); + assertThat(test.getParameterMetadata().isPresent()).isTrue(); + assertThat(test.getParameterMetadata().get()).containsExactly(ParameterMetadata.empty()); + } + + @Test + public void test_withParameterMetadata_clearWhenEmpty() { + DefaultCubeMetadata test = DefaultCubeMetadata.of(CUBE_NAME).withParameterMetadata(null); + assertThat(test.getCubeName()).isEqualTo(CUBE_NAME); + assertThat(test.getXValueType()).isEqualTo(ValueType.UNKNOWN); + assertThat(test.getYValueType()).isEqualTo(ValueType.UNKNOWN); + assertThat(test.getZValueType()).isEqualTo(ValueType.UNKNOWN); + assertThat(test.getWValueType()).isEqualTo(ValueType.UNKNOWN); + assertThat(test.getParameterMetadata().isPresent()).isFalse(); + } + + @Test + public void test_withParameterMetadata_clearWhenNonEmpty() { + DefaultCubeMetadata test = DefaultCubeMetadata.of(CUBE_NAME) + .withParameterMetadata(ImmutableList.of(ParameterMetadata.empty())) + .withParameterMetadata(null); + assertThat(test.getCubeName()).isEqualTo(CUBE_NAME); + assertThat(test.getXValueType()).isEqualTo(ValueType.UNKNOWN); + assertThat(test.getYValueType()).isEqualTo(ValueType.UNKNOWN); + assertThat(test.getZValueType()).isEqualTo(ValueType.UNKNOWN); + assertThat(test.getWValueType()).isEqualTo(ValueType.UNKNOWN); + assertThat(test.getParameterMetadata().isPresent()).isFalse(); + } + + //------------------------------------------------------------------------- + @Test + public void coverage() { + DefaultCubeMetadata test = DefaultCubeMetadata.of(CUBE_NAME); + coverImmutableBean(test); + DefaultCubeMetadata test2 = DefaultCubeMetadata.builder() + .cubeName(CubeName.of("Test")) + .xValueType(ValueType.YEAR_FRACTION) + .yValueType(ValueType.STRIKE) + .zValueType(ValueType.DISCOUNT_FACTOR) + .wValueType(ValueType.ZERO_RATE) + .dayCount(ACT_365F) + .parameterMetadata(ParameterMetadata.empty()) + .build(); + coverBeanEquals(test, test2); + } + + @Test + public void test_serialization() { + DefaultCubeMetadata test = DefaultCubeMetadata.of(CUBE_NAME); + assertSerialization(test); + } + +} diff --git a/modules/market/src/test/java/com/opengamma/strata/market/cube/InterpolatedNodalCubeTest.java b/modules/market/src/test/java/com/opengamma/strata/market/cube/InterpolatedNodalCubeTest.java new file mode 100644 index 0000000000..8d66782818 --- /dev/null +++ b/modules/market/src/test/java/com/opengamma/strata/market/cube/InterpolatedNodalCubeTest.java @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.market.cube; + +import static com.opengamma.strata.basics.date.DayCounts.ACT_365F; +import static com.opengamma.strata.collect.TestHelper.assertSerialization; +import static com.opengamma.strata.collect.TestHelper.coverBeanEquals; +import static com.opengamma.strata.collect.TestHelper.coverImmutableBean; +import static com.opengamma.strata.market.curve.interpolator.CurveExtrapolators.FLAT; +import static com.opengamma.strata.market.curve.interpolator.CurveInterpolators.DOUBLE_QUADRATIC; +import static com.opengamma.strata.market.curve.interpolator.CurveInterpolators.LINEAR; +import static com.opengamma.strata.market.curve.interpolator.CurveInterpolators.PCHIP; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +import org.junit.jupiter.api.Test; + +import com.opengamma.strata.collect.array.DoubleArray; +import com.opengamma.strata.market.cube.interpolator.BoundCubeInterpolator; +import com.opengamma.strata.market.cube.interpolator.GridCubeInterpolator; +import com.opengamma.strata.market.param.ParameterMetadata; + +/** + * Test {@link InterpolatedNodalCube}. + */ +public class InterpolatedNodalCubeTest { + + private static final int SIZE = 18; + private static final String NAME = "TestCube"; + private static final CubeName CUBE_NAME = CubeName.of(NAME); + private static final CubeMetadata METADATA = DefaultCubeMetadata.of(CUBE_NAME); + private static final CubeMetadata METADATA_ENTRIES = DefaultCubeMetadata.builder() + .cubeName(CUBE_NAME) + .dayCount(ACT_365F) + .parameterMetadata(ParameterMetadata.listOfEmpty(SIZE)) + .build(); + private static final CubeMetadata METADATA_ENTRIES2 = DefaultCubeMetadata.builder() + .cubeName(CUBE_NAME) + .dayCount(ACT_365F) + .parameterMetadata(ParameterMetadata.listOfEmpty(SIZE + 2)) + .build(); + private static final DoubleArray XVALUES = DoubleArray.of(0d, 0d, 0d, 0d, 0d, 0d, 2d, 2d, 2d, 2d, 2d, 2d, 4d, 4d, 4d, 4d, 4d, 4d); + private static final DoubleArray XVALUES2 = DoubleArray.of(1d, 1d, 1d, 1d, 1d, 1d, 2d, 2d, 2d, 2d, 2d, 2d, 3d, 3d, 3d, 3d, 3d, 3d); + private static final DoubleArray YVALUES = DoubleArray.of(0d, 0d, 3d, 3d, 4d, 4d, 0d, 0d, 3d, 3d, 4d, 4d, 0d, 0d, 3d, 3d, 4d, 4d); + private static final DoubleArray YVALUES2 = DoubleArray.of(3d, 3d, 4d, 4d, 5d, 5d, 3d, 3d, 4d, 4d, 5d, 5d, 3d, 3d, 4d, 4d, 5d, 5d); + private static final DoubleArray ZVALUES = DoubleArray.of(5d, 7d, 5d, 7d, 5d, 7d, 5d, 7d, 5d, 7d, 5d, 7d, 5d, 7d, 5d, 7d, 5d, 7d); + private static final DoubleArray ZVALUES2 = DoubleArray.of(3d, 4d, 3d, 4d, 3d, 4d, 3d, 4d, 3d, 4d, 3d, 4d, 3d, 4d, 3d, 4d, 3d, 4d); + private static final DoubleArray WVALUES = DoubleArray.of(5d, 7d, 8d, 6d, 7d, 8d, 8d, 7d, 8d, 5d, 7d, 8d, 6d, 7d, 8d, 8d, 7d, 8d); + private static final DoubleArray WVALUES_BUMPED = DoubleArray.of(3d, 5d, 6d, 4d, 5d, 6d, 6d, 5d, 6d, 3d, 5d, 6d, 4d, 5d, 6d, 6d, 5d, 6d); + private static final GridCubeInterpolator INTERPOLATOR = GridCubeInterpolator.of(LINEAR, LINEAR, LINEAR); + + //------------------------------------------------------------------------- + @Test + public void test_of_CubeMetadata() { + InterpolatedNodalCube test = InterpolatedNodalCube.of( + METADATA_ENTRIES, + XVALUES, + YVALUES, + ZVALUES, + WVALUES, + INTERPOLATOR); + assertThat(test.getName()).isEqualTo(CUBE_NAME); + assertThat(test.getParameterCount()).isEqualTo(SIZE); + assertThat(test.getParameter(0)).isEqualTo(ZVALUES.get(0)); + assertThat(test.getParameter(1)).isEqualTo(ZVALUES.get(1)); + assertThat(test.getParameterMetadata(0)).isSameAs(METADATA_ENTRIES.getParameterMetadata().get().get(0)); + assertThat(test.getParameterMetadata(1)).isSameAs(METADATA_ENTRIES.getParameterMetadata().get().get(1)); + assertThat(test.withParameter(0, 2d)).isEqualTo( + InterpolatedNodalCube.of(METADATA_ENTRIES, XVALUES, YVALUES, ZVALUES, WVALUES.with(0, 2d), INTERPOLATOR)); + assertThat(test.withPerturbation((i, v, m) -> v - 2d)).isEqualTo( + InterpolatedNodalCube.of(METADATA_ENTRIES, XVALUES, YVALUES, ZVALUES, WVALUES_BUMPED, INTERPOLATOR)); + assertThat(test.getInterpolator()).isEqualTo(INTERPOLATOR); + assertThat(test.getMetadata()).isEqualTo(METADATA_ENTRIES); + assertThat(test.getXValues()).isEqualTo(XVALUES); + assertThat(test.getYValues()).isEqualTo(YVALUES); + assertThat(test.getZValues()).isEqualTo(ZVALUES); + assertThat(test.getWValues()).isEqualTo(WVALUES); + } + + @Test + public void test_of_invalid() { + // not enough nodes + assertThatIllegalArgumentException() + .isThrownBy(() -> InterpolatedNodalCube.of( + METADATA, DoubleArray.of(1d), DoubleArray.of(2d), DoubleArray.of(3d), DoubleArray.of(3d), INTERPOLATOR)); + // x node size != y node size + assertThatIllegalArgumentException() + .isThrownBy(() -> InterpolatedNodalCube.of( + METADATA, XVALUES, DoubleArray.of(1d, 3d, 4d, 3d), ZVALUES, WVALUES, INTERPOLATOR)); + // x node size != z node size + assertThatIllegalArgumentException() + .isThrownBy(() -> InterpolatedNodalCube.of( + METADATA, XVALUES, YVALUES, DoubleArray.of(1d, 3d), WVALUES, INTERPOLATOR)); + // x node size != w node size + assertThatIllegalArgumentException() + .isThrownBy(() -> InterpolatedNodalCube.of( + METADATA, XVALUES, YVALUES, WVALUES, DoubleArray.of(1d, 3d), INTERPOLATOR)); + // parameter metadata size != node size + assertThatIllegalArgumentException() + .isThrownBy(() -> InterpolatedNodalCube.of( + METADATA_ENTRIES, + DoubleArray.of(1d, 3d), + DoubleArray.of(1d, 3d), + DoubleArray.of(1d, 3d), + DoubleArray.of(1d, 3d), + INTERPOLATOR)); + // x not in order + assertThatIllegalArgumentException() + .isThrownBy(() -> InterpolatedNodalCube.of( + METADATA, + DoubleArray.of(2d, 1d), + DoubleArray.of(1d, 1d), + DoubleArray.of(2d, 3d), + DoubleArray.of(2d, 3d), + INTERPOLATOR)); + // y not in order + assertThatIllegalArgumentException() + .isThrownBy(() -> InterpolatedNodalCube.of( + METADATA, + DoubleArray.of(1d, 1d), + DoubleArray.of(2d, 1d), + DoubleArray.of(2d, 3d), + DoubleArray.of(2d, 3d), + INTERPOLATOR)); + // z not in order + assertThatIllegalArgumentException() + .isThrownBy(() -> InterpolatedNodalCube.of( + METADATA, + DoubleArray.of(1d, 1d), + DoubleArray.of(1d, 1d), + DoubleArray.of(4d, 3d), + DoubleArray.of(2d, 3d), + INTERPOLATOR)); + } + + //------------------------------------------------------------------------- + @Test + public void test_lookup() { + InterpolatedNodalCube test = InterpolatedNodalCube.of(METADATA, XVALUES, YVALUES, ZVALUES, WVALUES, INTERPOLATOR); + assertThat(test.wValue(XVALUES.get(0), YVALUES.get(0), ZVALUES.get(0))).isEqualTo(WVALUES.get(0)); + assertThat(test.wValue(XVALUES.get(1), YVALUES.get(1), ZVALUES.get(1))).isEqualTo(WVALUES.get(1)); + assertThat(test.wValue(XVALUES.get(2), YVALUES.get(2), ZVALUES.get(2))).isEqualTo(WVALUES.get(2)); + assertThat(test.wValue(0d, 1.5d, 5.5d)).isEqualTo(6.5d); + assertThat(test.wValue(1d, 3d, 6.5d)).isEqualTo(6.125d); + + BoundCubeInterpolator bound = INTERPOLATOR.bind(XVALUES, YVALUES, ZVALUES, WVALUES); + assertThat(test.wValue(1.5d, 3.7d, 5.2d)).isEqualTo(bound.interpolate(1.5d, 3.7d, 5.2d)); + DoubleArray sensiValues = test.wValueParameterSensitivity(1.5d, 1.5d, 5.6d).getSensitivity(); + DoubleArray sensiValuesInterp = bound.parameterSensitivity(1.5d, 1.5d, 5.6d); + assertThat(sensiValues.equalWithTolerance(sensiValuesInterp, 1e-8)).isTrue(); + } + + //------------------------------------------------------------------------- + @Test + public void test_withMetadata() { + InterpolatedNodalCube base = InterpolatedNodalCube.of(METADATA, XVALUES, YVALUES, ZVALUES, WVALUES, INTERPOLATOR); + InterpolatedNodalCube test = base.withMetadata(METADATA_ENTRIES); + assertThat(test.getName()).isEqualTo(CUBE_NAME); + assertThat(test.getParameterCount()).isEqualTo(SIZE); + assertThat(test.getMetadata()).isEqualTo(METADATA_ENTRIES); + assertThat(test.getXValues()).isEqualTo(XVALUES); + assertThat(test.getYValues()).isEqualTo(YVALUES); + assertThat(test.getZValues()).isEqualTo(ZVALUES); + assertThat(test.getWValues()).isEqualTo(WVALUES); + } + + @Test + public void test_withMetadata_badSize() { + InterpolatedNodalCube base = InterpolatedNodalCube.of(METADATA, XVALUES, YVALUES, ZVALUES, WVALUES, INTERPOLATOR); + assertThatIllegalArgumentException() + .isThrownBy(() -> base.withMetadata(METADATA_ENTRIES2)); + } + + //------------------------------------------------------------------------- + @Test + public void test_withZValues() { + InterpolatedNodalCube base = InterpolatedNodalCube.of(METADATA, XVALUES, YVALUES, ZVALUES, WVALUES, INTERPOLATOR); + InterpolatedNodalCube test = base.withWValues(WVALUES_BUMPED); + assertThat(test.getName()).isEqualTo(CUBE_NAME); + assertThat(test.getParameterCount()).isEqualTo(SIZE); + assertThat(test.getMetadata()).isEqualTo(METADATA); + assertThat(test.getXValues()).isEqualTo(XVALUES); + assertThat(test.getYValues()).isEqualTo(YVALUES); + assertThat(test.getZValues()).isEqualTo(ZVALUES); + assertThat(test.getWValues()).isEqualTo(WVALUES_BUMPED); + } + + @Test + public void test_withZValues_badSize() { + InterpolatedNodalCube base = InterpolatedNodalCube.of(METADATA, XVALUES, YVALUES, ZVALUES, WVALUES, INTERPOLATOR); + assertThatIllegalArgumentException() + .isThrownBy(() -> base.withWValues(DoubleArray.EMPTY)); + assertThatIllegalArgumentException() + .isThrownBy(() -> base.withWValues(DoubleArray.of(4d, 6d))); + } + + //------------------------------------------------------------------------- + @Test + public void coverage() { + InterpolatedNodalCube test = InterpolatedNodalCube.of(METADATA, XVALUES, YVALUES, ZVALUES, WVALUES, INTERPOLATOR); + coverImmutableBean(test); + InterpolatedNodalCube test2 = InterpolatedNodalCube.builder() + .metadata(METADATA_ENTRIES) + .xValues(XVALUES2) + .yValues(YVALUES2) + .zValues(ZVALUES2) + .wValues(WVALUES_BUMPED) + .interpolator(GridCubeInterpolator.of(DOUBLE_QUADRATIC, FLAT, FLAT, LINEAR, FLAT, FLAT, PCHIP, FLAT, FLAT)) + .build(); + coverBeanEquals(test, test2); + } + + @Test + public void test_serialization() { + InterpolatedNodalCube test = InterpolatedNodalCube.of(METADATA, XVALUES, YVALUES, ZVALUES, WVALUES, INTERPOLATOR); + assertSerialization(test); + } + +} diff --git a/modules/market/src/test/java/com/opengamma/strata/market/cube/SimpleCubeParameterMetadataTest.java b/modules/market/src/test/java/com/opengamma/strata/market/cube/SimpleCubeParameterMetadataTest.java new file mode 100644 index 0000000000..ffb5e8a384 --- /dev/null +++ b/modules/market/src/test/java/com/opengamma/strata/market/cube/SimpleCubeParameterMetadataTest.java @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.market.cube; + +import static com.opengamma.strata.collect.TestHelper.assertSerialization; +import static com.opengamma.strata.collect.TestHelper.coverBeanEquals; +import static com.opengamma.strata.collect.TestHelper.coverImmutableBean; +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; + +import com.opengamma.strata.market.ValueType; + +/** + * Test {@link SimpleCubeParameterMetadata}. + */ +public class SimpleCubeParameterMetadataTest { + + @Test + public void test_of() { + SimpleCubeParameterMetadata test = SimpleCubeParameterMetadata.of( + ValueType.YEAR_FRACTION, 1d, ValueType.STRIKE, 3d, ValueType.NORMAL_VOLATILITY, 2d); + assertThat(test.getXValueType()).isEqualTo(ValueType.YEAR_FRACTION); + assertThat(test.getXValue()).isEqualTo(1d); + assertThat(test.getYValueType()).isEqualTo(ValueType.STRIKE); + assertThat(test.getYValue()).isEqualTo(3d); + assertThat(test.getZValueType()).isEqualTo(ValueType.NORMAL_VOLATILITY); + assertThat(test.getZValue()).isEqualTo(2d); + assertThat(test.getLabel()).isEqualTo("YearFraction=1.0, Strike=3.0, NormalVolatility=2.0"); + assertThat(test.getIdentifier()).isEqualTo("YearFraction=1.0, Strike=3.0, NormalVolatility=2.0"); + } + + //------------------------------------------------------------------------- + @Test + public void coverage() { + SimpleCubeParameterMetadata test = SimpleCubeParameterMetadata.of( + ValueType.YEAR_FRACTION, 1d, ValueType.STRIKE, 3d, ValueType.NORMAL_VOLATILITY, 2d); + coverImmutableBean(test); + SimpleCubeParameterMetadata test2 = SimpleCubeParameterMetadata.of( + ValueType.ZERO_RATE, 2d, ValueType.SIMPLE_MONEYNESS, 4d, ValueType.LOCAL_VOLATILITY, 7d); + coverBeanEquals(test, test2); + } + + @Test + public void test_serialization() { + SimpleCubeParameterMetadata test = SimpleCubeParameterMetadata.of( + ValueType.YEAR_FRACTION, 1d, ValueType.STRIKE, 3d, ValueType.NORMAL_VOLATILITY, 2d); + assertSerialization(test); + } + +} diff --git a/modules/market/src/test/java/com/opengamma/strata/market/cube/interpolator/GridCubeInterpolatorTest.java b/modules/market/src/test/java/com/opengamma/strata/market/cube/interpolator/GridCubeInterpolatorTest.java new file mode 100644 index 0000000000..2a22d7eed2 --- /dev/null +++ b/modules/market/src/test/java/com/opengamma/strata/market/cube/interpolator/GridCubeInterpolatorTest.java @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.market.cube.interpolator; + +import static com.opengamma.strata.collect.TestHelper.assertSerialization; +import static com.opengamma.strata.collect.TestHelper.coverBeanEquals; +import static com.opengamma.strata.collect.TestHelper.coverImmutableBean; +import static com.opengamma.strata.market.curve.interpolator.CurveExtrapolators.EXPONENTIAL; +import static com.opengamma.strata.market.curve.interpolator.CurveExtrapolators.FLAT; +import static com.opengamma.strata.market.curve.interpolator.CurveExtrapolators.QUADRATIC_LEFT; +import static com.opengamma.strata.market.curve.interpolator.CurveInterpolators.DOUBLE_QUADRATIC; +import static com.opengamma.strata.market.curve.interpolator.CurveInterpolators.LINEAR; +import static com.opengamma.strata.market.curve.interpolator.CurveInterpolators.NATURAL_CUBIC_SPLINE; +import static com.opengamma.strata.market.curve.interpolator.CurveInterpolators.NATURAL_SPLINE; +import static com.opengamma.strata.market.curve.interpolator.CurveInterpolators.NATURAL_SPLINE_NONNEGATIVITY_CUBIC; +import static com.opengamma.strata.market.curve.interpolator.CurveInterpolators.PCHIP; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; +import static org.assertj.core.data.Offset.offset; + +import org.assertj.core.data.Offset; +import org.junit.jupiter.api.Test; + +import com.opengamma.strata.basics.value.ValueDerivatives; +import com.opengamma.strata.collect.array.DoubleArray; +import com.opengamma.strata.market.curve.interpolator.CurveExtrapolators; +import com.opengamma.strata.market.surface.interpolator.GridSurfaceInterpolator; + +/** + * Test {@link GridCubeInterpolator} + */ +public class GridCubeInterpolatorTest { + + private static final DoubleArray X_DATA = DoubleArray.of( + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, + 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, + 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0, 2.0); + private static final DoubleArray Y_DATA = DoubleArray.of( + 3.0, 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, 4.0, 5.0, 5.0, 5.0, 5.0, + 3.0, 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, 4.0, 5.0, 5.0, 5.0, 5.0, + 3.0, 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, 4.0, 5.0, 5.0, 5.0, 5.0); + private static final DoubleArray Z_DATA = DoubleArray.of( + -3.0, 1.0, 3.0, 9.0, -3.0, 1.0, 3.0, 9.0, -3.0, 1.0, 3.0, 9.0, + -3.0, 1.0, 3.0, 9.0, -3.0, 1.0, 3.0, 9.0, -3.0, 1.0, 3.0, 9.0, + -3.0, 1.0, 3.0, 9.0, -3.0, 1.0, 3.0, 9.0, -3.0, 1.0, 3.0, 9.0); + private static final DoubleArray W_DATA = DoubleArray.of( + 3.0, 5.0, 3.1, 2.0, 4.0, 3.5, 2.1, -4.0, -3.0, 2.9, 4.0, 3.0, + 2.0, 4.0, 3.0, 3.5, 2.1, 5.0, 3.5, 2.1, 3.0, -0.5, -2.1, -4.0, + 1.5, 4.5, 2.5, 1.5, -2.2, -4.0, 3.5, 2.1, -4.0, 3.0, 3.5, 2.1); + + private static final DoubleArray X_TEST = DoubleArray.of(0.2, 1.3, 2.5, -1.2); + private static final DoubleArray Y_TEST = DoubleArray.of(3.4, 4.1, 4.5, 1.2); + private static final DoubleArray Z_TEST = DoubleArray.of(-1.2, 1.3, 6.5, 11.0); + + private static final DoubleArray W_TEST = DoubleArray.of( + ((3.0 + (2.0 - 3.0) * 0.2) * (1.0 + 1.2) / (1.0 + 3.0) + + (5.0 + (4.0 - 5.0) * 0.2) * (-1.2 + 3.0) / (1.0 + 3.0)) * (4.0 - 3.4) + + ((4.0 + (2.1 - 4.0) * 0.2) * (1.0 + 1.2) / (1.0 + 3.0) + + (3.5 + (5.0 - 3.5) * 0.2) * (-1.2 + 3.0) / (1.0 + 3.0)) * (3.4 - 3.0), + ((5.0 + (-4.0 - 5.0) * (1.3 - 1.0)) * (3.0 - 1.3) / (3.0 - 1.0) + + 3.5 * (1.3 - 1.0) / (3.0 - 1.0)) * (5.0 - 4.1) + + ((-0.5 + (3.0 + 0.5) * (1.3 - 1.0)) * (3.0 - 1.3) / (3.0 - 1.0) + + (-2.1 + (3.5 + 2.1) * (1.3 - 1.0)) * (1.3 - 1.0) / (3.0 - 1.0)) * (4.1 - 4.0), + GridSurfaceInterpolator.of(LINEAR, LINEAR).bind( + Y_DATA.subArray(25, 36), + Z_DATA.subArray(25, 36), + W_DATA.subArray(25, 36)).interpolate(4.5, 6.5), + 2.0); + + private static final Offset TOL = Offset.strictOffset(1e-12); + + @Test + public void test_of3() { + GridCubeInterpolator test = GridCubeInterpolator.of(LINEAR, PCHIP, NATURAL_SPLINE); + assertThat(test.getXInterpolator()).isEqualTo(LINEAR); + assertThat(test.getXExtrapolatorLeft()).isEqualTo(FLAT); + assertThat(test.getXExtrapolatorRight()).isEqualTo(FLAT); + assertThat(test.getYInterpolator()).isEqualTo(PCHIP); + assertThat(test.getYExtrapolatorLeft()).isEqualTo(FLAT); + assertThat(test.getYExtrapolatorRight()).isEqualTo(FLAT); + assertThat(test.getZInterpolator()).isEqualTo(NATURAL_SPLINE); + assertThat(test.getZExtrapolatorLeft()).isEqualTo(FLAT); + assertThat(test.getZExtrapolatorRight()).isEqualTo(FLAT); + } + + @Test + public void test_of6() { + GridCubeInterpolator test = GridCubeInterpolator.of(LINEAR, EXPONENTIAL, NATURAL_SPLINE, EXPONENTIAL, PCHIP, FLAT); + assertThat(test.getXInterpolator()).isEqualTo(LINEAR); + assertThat(test.getXExtrapolatorLeft()).isEqualTo(EXPONENTIAL); + assertThat(test.getXExtrapolatorRight()).isEqualTo(EXPONENTIAL); + assertThat(test.getYInterpolator()).isEqualTo(NATURAL_SPLINE); + assertThat(test.getYExtrapolatorLeft()).isEqualTo(EXPONENTIAL); + assertThat(test.getYExtrapolatorRight()).isEqualTo(EXPONENTIAL); + assertThat(test.getZInterpolator()).isEqualTo(PCHIP); + assertThat(test.getZExtrapolatorLeft()).isEqualTo(FLAT); + assertThat(test.getZExtrapolatorRight()).isEqualTo(FLAT); + } + + @Test + public void test_of9() { + GridCubeInterpolator test = GridCubeInterpolator.of( + LINEAR, + QUADRATIC_LEFT, + EXPONENTIAL, + NATURAL_CUBIC_SPLINE, + FLAT, + EXPONENTIAL, + NATURAL_SPLINE_NONNEGATIVITY_CUBIC, + FLAT, + EXPONENTIAL); + assertThat(test.getXInterpolator()).isEqualTo(LINEAR); + assertThat(test.getXExtrapolatorLeft()).isEqualTo(QUADRATIC_LEFT); + assertThat(test.getXExtrapolatorRight()).isEqualTo(EXPONENTIAL); + assertThat(test.getYInterpolator()).isEqualTo(NATURAL_CUBIC_SPLINE); + assertThat(test.getYExtrapolatorLeft()).isEqualTo(FLAT); + assertThat(test.getYExtrapolatorRight()).isEqualTo(EXPONENTIAL); + assertThat(test.getZInterpolator()).isEqualTo(NATURAL_SPLINE_NONNEGATIVITY_CUBIC); + assertThat(test.getZExtrapolatorLeft()).isEqualTo(FLAT); + assertThat(test.getZExtrapolatorRight()).isEqualTo(EXPONENTIAL); + } + + @Test + public void test_bind_invalidXValues() { + GridCubeInterpolator test = GridCubeInterpolator.of(LINEAR, LINEAR, LINEAR); + assertThatIllegalArgumentException() + .isThrownBy(() -> test.bind( + DoubleArray.of(1d, 1d, 1d, 1d), + DoubleArray.of(1d, 1d, 2d, 2d), + DoubleArray.of(3d, 4d, 3d, 4d), + DoubleArray.of(1d, 1d, 1d, 1d))); + } + + @Test + public void test_bind_invalidOrder() { + GridCubeInterpolator test = GridCubeInterpolator.of(LINEAR, LINEAR, LINEAR); + assertThatIllegalArgumentException() + .isThrownBy(() -> test.bind( + DoubleArray.of(1d, 1d, 1d, 1d, 0d, 0d, 0d, 0d), + DoubleArray.of(1d, 1d, 2d, 2d, 1d, 1d, 2d, 2d), + DoubleArray.of(1d, 2d, 1d, 2d, 1d, 2d, 1d, 2d), + DoubleArray.of(1d, 1d, 1d, 1d, 1d, 1d, 1d, 1d))); + assertThatIllegalArgumentException() + .isThrownBy(() -> test.bind( + DoubleArray.of(1d, 1d, 1d, 1d, 2d, 2d, 2d, 2d), + DoubleArray.of(1d, 1d, 2d, 2d, 0d, 0d, 0d, 0d), + DoubleArray.of(1d, 2d, 1d, 2d, 1d, 2d, 1d, 2d), + DoubleArray.of(1d, 1d, 1d, 1d, 1d, 1d, 1d, 1d))); + } + + @Test + public void test_interpolation() { + GridCubeInterpolator test = GridCubeInterpolator.of(LINEAR, LINEAR, LINEAR); + BoundCubeInterpolator bci = test.bind(X_DATA, Y_DATA, Z_DATA, W_DATA); + for (int i = 0; i < X_DATA.size(); i++) { + assertThat(bci.interpolate(X_DATA.get(i), Y_DATA.get(i), Z_DATA.get(i))).isCloseTo(W_DATA.get(i), TOL); + } + for (int i = 0; i < X_TEST.size(); i++) { + assertThat(bci.interpolate(X_TEST.get(i), Y_TEST.get(i), Z_TEST.get(i))).isCloseTo(W_TEST.get(i), TOL); + } + } + + @Test + public void test_firstDerivativeInterpolator() { + GridCubeInterpolator test = GridCubeInterpolator.of(LINEAR, LINEAR, LINEAR); + BoundCubeInterpolator bci = test.bind(X_DATA, Y_DATA, Z_DATA, W_DATA); + double eps = 1e-8; + for (int i = 0; i < X_TEST.size(); i++) { + ValueDerivatives computed = bci.firstPartialDerivatives(X_TEST.get(i), Y_TEST.get(i), Z_TEST.get(i)); + double upX = bci.interpolate(X_TEST.get(i) + eps, Y_TEST.get(i), Z_TEST.get(i)); + double downX = bci.interpolate(X_TEST.get(i) - eps, Y_TEST.get(i), Z_TEST.get(i)); + double upY = bci.interpolate(X_TEST.get(i), Y_TEST.get(i) + eps, Z_TEST.get(i)); + double downY = bci.interpolate(X_TEST.get(i), Y_TEST.get(i) - eps, Z_TEST.get(i)); + double upZ = bci.interpolate(X_TEST.get(i), Y_TEST.get(i), Z_TEST.get(i) + eps); + double downZ = bci.interpolate(X_TEST.get(i), Y_TEST.get(i), Z_TEST.get(i) - eps); + double expectedX = 0.5 * (upX - downX) / eps; + double expectedY = 0.5 * (upY - downY) / eps; + double expectedZ = 0.5 * (upZ - downZ) / eps; + assertThat(computed.getDerivative(0)).isCloseTo(expectedX, offset(eps * 10)); + assertThat(computed.getDerivative(1)).isCloseTo(expectedY, offset(eps * 10)); + assertThat(computed.getDerivative(2)).isCloseTo(expectedZ, offset(eps * 10)); + } + } + + @Test + public void test_parameterSensitivity() { + GridCubeInterpolator test = GridCubeInterpolator.of(LINEAR, LINEAR, LINEAR); + BoundCubeInterpolator bci = test.bind(X_DATA, Y_DATA, Z_DATA, W_DATA); + double eps = 1e-8; + for (int i = 0; i < X_TEST.size(); i++) { + DoubleArray computed = bci.parameterSensitivity(X_TEST.get(i), Y_TEST.get(i), Z_TEST.get(i)); + assertThat(computed.size()).isEqualTo(X_DATA.size()); + for (int j = 0; j < X_DATA.size(); j++) { + BoundCubeInterpolator bciUp = test.bind(X_DATA, Y_DATA, Z_DATA, W_DATA.with(j, W_DATA.get(j) + eps)); + double up = bciUp.interpolate(X_TEST.get(i), Y_TEST.get(i), Z_TEST.get(i)); + BoundCubeInterpolator bciDw = test.bind(X_DATA, Y_DATA, Z_DATA, W_DATA.with(j, W_DATA.get(j) - eps)); + double dw = bciDw.interpolate(X_TEST.get(i), Y_TEST.get(i), Z_TEST.get(i)); + double expected = 0.5 * (up - dw) / eps; + assertThat(computed.get(j)).isCloseTo(expected, offset(eps * 10)); + } + } + } + + //------------------------------------------------------------------------- + @Test + public void coverage() { + GridCubeInterpolator test = GridCubeInterpolator.of( + LINEAR, FLAT, FLAT, LINEAR, FLAT, FLAT, LINEAR, FLAT, FLAT); + coverImmutableBean(test); + GridCubeInterpolator test2 = GridCubeInterpolator.of( + DOUBLE_QUADRATIC, + CurveExtrapolators.LINEAR, + CurveExtrapolators.LINEAR, + DOUBLE_QUADRATIC, + CurveExtrapolators.LINEAR, + CurveExtrapolators.LINEAR, + DOUBLE_QUADRATIC, + CurveExtrapolators.LINEAR, + CurveExtrapolators.LINEAR); + coverBeanEquals(test, test2); + } + + @Test + public void test_serialization() { + GridCubeInterpolator test = GridCubeInterpolator.of( + LINEAR, FLAT, FLAT, LINEAR, FLAT, FLAT, LINEAR, FLAT, FLAT); + assertSerialization(test); + } + +} diff --git a/modules/market/src/test/java/com/opengamma/strata/market/param/TenorTenorStrikeParameterMetadataTest.java b/modules/market/src/test/java/com/opengamma/strata/market/param/TenorTenorStrikeParameterMetadataTest.java new file mode 100644 index 0000000000..229b2b0993 --- /dev/null +++ b/modules/market/src/test/java/com/opengamma/strata/market/param/TenorTenorStrikeParameterMetadataTest.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.market.param; + +import static com.opengamma.strata.basics.date.Tenor.TENOR_10Y; +import static com.opengamma.strata.basics.date.Tenor.TENOR_20Y; +import static com.opengamma.strata.basics.date.Tenor.TENOR_30Y; +import static com.opengamma.strata.basics.date.Tenor.TENOR_40Y; +import static com.opengamma.strata.collect.TestHelper.assertSerialization; +import static com.opengamma.strata.collect.TestHelper.coverBeanEquals; +import static com.opengamma.strata.collect.TestHelper.coverImmutableBean; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +import org.joda.beans.BeanBuilder; +import org.junit.jupiter.api.Test; + +import com.opengamma.strata.collect.tuple.Triple; + +/** + * Test {@link TenorTenorStrikeParameterMetadata}. + */ +public class TenorTenorStrikeParameterMetadataTest { + + @Test + public void test_of_noLabel() { + TenorTenorStrikeParameterMetadata test = TenorTenorStrikeParameterMetadata.of(TENOR_10Y, TENOR_20Y, 0.015); + assertThat(test.getExpiryTenor()).isEqualTo(TENOR_10Y); + assertThat(test.getUnderlyingTenor()).isEqualTo(TENOR_20Y); + assertThat(test.getStrike()).isEqualTo(0.015); + + assertThat(test.getIdentifier()).isEqualTo(Triple.of(TENOR_10Y, TENOR_20Y, 0.015)); + assertThat(test.getLabel()).isEqualTo("[10Y, 20Y, 0.015]"); + } + + @Test + public void test_of_label() { + TenorTenorStrikeParameterMetadata test = TenorTenorStrikeParameterMetadata.of( + TENOR_10Y, + TENOR_20Y, + 0.011, + "10Y to 20Y on 0.011"); + assertThat(test.getExpiryTenor()).isEqualTo(TENOR_10Y); + assertThat(test.getUnderlyingTenor()).isEqualTo(TENOR_20Y); + assertThat(test.getStrike()).isEqualTo(0.011); + + assertThat(test.getIdentifier()).isEqualTo(Triple.of(TENOR_10Y, TENOR_20Y, 0.011)); + assertThat(test.getLabel()).isEqualTo("10Y to 20Y on 0.011"); + } + + @Test + public void test_builder_defaultLabel() { + BeanBuilder builder = TenorTenorStrikeParameterMetadata.meta().builder(); + builder.set(TenorTenorStrikeParameterMetadata.meta().expiryTenor(), TENOR_10Y); + builder.set(TenorTenorStrikeParameterMetadata.meta().underlyingTenor(), TENOR_20Y); + builder.set(TenorTenorStrikeParameterMetadata.meta().strike(), -0.01); + + TenorTenorStrikeParameterMetadata test = builder.build(); + assertThat(test.getExpiryTenor()).isEqualTo(TENOR_10Y); + assertThat(test.getUnderlyingTenor()).isEqualTo(TENOR_20Y); + assertThat(test.getStrike()).isEqualTo(-0.01); + + assertThat(test.getIdentifier()).isEqualTo(Triple.of(TENOR_10Y, TENOR_20Y, -0.01)); + assertThat(test.getLabel()).isEqualTo("[10Y, 20Y, -0.01]"); + } + + @Test + public void test_builder_specifyLabel() { + BeanBuilder builder = TenorTenorStrikeParameterMetadata.meta().builder(); + builder.set(TenorTenorStrikeParameterMetadata.meta().expiryTenor(), TENOR_10Y); + builder.set(TenorTenorStrikeParameterMetadata.meta().underlyingTenor(), TENOR_20Y); + builder.set(TenorTenorStrikeParameterMetadata.meta().strike(), 0.01); + builder.set(TenorTenorStrikeParameterMetadata.meta().label(), "10Y to 20Y, ATM"); + + TenorTenorStrikeParameterMetadata test = builder.build(); + assertThat(test.getExpiryTenor()).isEqualTo(TENOR_10Y); + assertThat(test.getUnderlyingTenor()).isEqualTo(TENOR_20Y); + assertThat(test.getStrike()).isEqualTo(0.01); + + assertThat(test.getIdentifier()).isEqualTo(Triple.of(TENOR_10Y, TENOR_20Y, 0.01)); + assertThat(test.getLabel()).isEqualTo("10Y to 20Y, ATM"); + } + + @Test + public void test_builder_incomplete() { + BeanBuilder builder = TenorTenorStrikeParameterMetadata.meta().builder(); + assertThatIllegalArgumentException().isThrownBy(builder::build); + } + + //------------------------------------------------------------------------- + @Test + public void coverage() { + TenorTenorStrikeParameterMetadata test = TenorTenorStrikeParameterMetadata.of(TENOR_10Y, TENOR_20Y, 0.015); + coverImmutableBean(test); + TenorTenorStrikeParameterMetadata test2 = TenorTenorStrikeParameterMetadata.of(TENOR_30Y, TENOR_40Y, 0.011); + coverBeanEquals(test, test2); + } + + @Test + public void test_serialization() { + TenorTenorStrikeParameterMetadata test = TenorTenorStrikeParameterMetadata.of(TENOR_10Y, TENOR_20Y, 0.014); + assertSerialization(test); + } + +} diff --git a/modules/pricer/src/main/java/com/opengamma/strata/pricer/swaption/NormalSwaptionExpiryTenorStrikeVolatilities.java b/modules/pricer/src/main/java/com/opengamma/strata/pricer/swaption/NormalSwaptionExpiryTenorStrikeVolatilities.java new file mode 100644 index 0000000000..1cf8c3e3a2 --- /dev/null +++ b/modules/pricer/src/main/java/com/opengamma/strata/pricer/swaption/NormalSwaptionExpiryTenorStrikeVolatilities.java @@ -0,0 +1,571 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.pricer.swaption; + +import java.io.Serializable; +import java.time.LocalDate; +import java.time.ZonedDateTime; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.OptionalInt; + +import org.joda.beans.Bean; +import org.joda.beans.BeanBuilder; +import org.joda.beans.ImmutableBean; +import org.joda.beans.JodaBeanUtils; +import org.joda.beans.MetaBean; +import org.joda.beans.MetaProperty; +import org.joda.beans.gen.BeanDefinition; +import org.joda.beans.gen.ImmutableConstructor; +import org.joda.beans.gen.PropertyDefinition; +import org.joda.beans.impl.direct.DirectMetaBean; +import org.joda.beans.impl.direct.DirectMetaProperty; +import org.joda.beans.impl.direct.DirectMetaPropertyMap; +import org.joda.beans.impl.direct.DirectPrivateBeanBuilder; + +import com.opengamma.strata.basics.date.DayCount; +import com.opengamma.strata.collect.ArgChecker; +import com.opengamma.strata.data.MarketDataName; +import com.opengamma.strata.market.ValueType; +import com.opengamma.strata.market.cube.Cube; +import com.opengamma.strata.market.cube.CubeInfoType; +import com.opengamma.strata.market.cube.Cubes; +import com.opengamma.strata.market.cube.InterpolatedNodalCube; +import com.opengamma.strata.market.param.CurrencyParameterSensitivities; +import com.opengamma.strata.market.param.CurrencyParameterSensitivity; +import com.opengamma.strata.market.param.ParameterMetadata; +import com.opengamma.strata.market.param.ParameterPerturbation; +import com.opengamma.strata.market.param.UnitParameterSensitivity; +import com.opengamma.strata.market.sensitivity.PointSensitivities; +import com.opengamma.strata.market.sensitivity.PointSensitivity; +import com.opengamma.strata.pricer.impl.option.NormalFormulaRepository; +import com.opengamma.strata.product.common.PutCall; +import com.opengamma.strata.product.swap.type.FixedFloatSwapConvention; + +/** + * Volatility for swaptions in the normal or Bachelier model based on a cube. + *

    + * The volatility is represented by a cube on the expiry, swap tenor and strike dimensions. + */ +@BeanDefinition(builderScope = "private") +public final class NormalSwaptionExpiryTenorStrikeVolatilities + implements NormalSwaptionVolatilities, ImmutableBean, Serializable { + + /** + * The swap convention that the volatilities are to be used for. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final FixedFloatSwapConvention convention; + /** + * The valuation date-time. + *

    + * The volatilities are calibrated for this date-time. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final ZonedDateTime valuationDateTime; + /** + * The normal volatility cube. + *

    + * The x-value of the cube is the expiry, as a year fraction. + * The y-value of the cube is the swap tenor, as a year fraction rounded to the month. + * The z-value of the cube is the strike, as a rate. + */ + @PropertyDefinition(validate = "notNull") + private final Cube cube; + /** + * The day count convention of the cube. + */ + private final transient DayCount dayCount; // cached, not a property + + //------------------------------------------------------------------------- + + /** + * Obtains an instance from the implied volatility cube and the date-time for which it is valid. + *

    + * The cube is specified by an instance of {@link Cube}, such as {@link InterpolatedNodalCube}. + * The cube must contain the correct metadata: + *

      + *
    • The x-value type must be {@link ValueType#YEAR_FRACTION} + *
    • The y-value type must be {@link ValueType#YEAR_FRACTION} + *
    • The z-value type must be {@link ValueType#STRIKE} + *
    • The w-value type must be {@link ValueType#NORMAL_VOLATILITY} + *
    • The day count must be set in the additional information using {@link CubeInfoType#DAY_COUNT} + *
    + * Suitable cube metadata can be created using + * {@link Cubes#normalVolatilityByExpiryTenorStrike(String, DayCount)}. + * + * @param convention the swap convention that the volatilities are to be used for + * @param valuationDateTime the valuation date-time + * @param cube the implied volatility cube + * @return the volatilities + */ + public static NormalSwaptionExpiryTenorStrikeVolatilities of( + FixedFloatSwapConvention convention, + ZonedDateTime valuationDateTime, + Cube cube) { + + return new NormalSwaptionExpiryTenorStrikeVolatilities(convention, valuationDateTime, cube); + } + + @ImmutableConstructor + private NormalSwaptionExpiryTenorStrikeVolatilities( + FixedFloatSwapConvention convention, + ZonedDateTime valuationDateTime, + Cube cube) { + + ArgChecker.notNull(convention, "convention"); + ArgChecker.notNull(cube, "valuationDateTime"); + ArgChecker.notNull(cube, "cube"); + cube.getMetadata().getXValueType().checkEquals( + ValueType.YEAR_FRACTION, "Incorrect x-value type for Normal volatilities"); + cube.getMetadata().getYValueType().checkEquals( + ValueType.YEAR_FRACTION, "Incorrect y-value type for Normal volatilities"); + cube.getMetadata().getZValueType().checkEquals( + ValueType.STRIKE, "Incorrect z-value type for Normal volatilities"); + cube.getMetadata().getWValueType().checkEquals( + ValueType.NORMAL_VOLATILITY, "Incorrect w-value type for Normal volatilities"); + DayCount dayCount = cube.getMetadata().findInfo(CubeInfoType.DAY_COUNT) + .orElseThrow(() -> new IllegalArgumentException("Incorrect cube metadata, missing DayCount")); + + this.valuationDateTime = valuationDateTime; + this.cube = cube; + this.convention = convention; + this.dayCount = dayCount; + } + + // ensure standard constructor is invoked + private Object readResolve() { + return new NormalSwaptionExpiryTenorStrikeVolatilities(convention, valuationDateTime, cube); + } + + //------------------------------------------------------------------------- + @Override + public SwaptionVolatilitiesName getName() { + return SwaptionVolatilitiesName.of(cube.getName().getName()); + } + + @Override + public Optional findData(MarketDataName name) { + if (cube.getName().equals(name)) { + return Optional.of(name.getMarketDataType().cast(cube)); + } + return Optional.empty(); + } + + @Override + public int getParameterCount() { + return cube.getParameterCount(); + } + + @Override + public double getParameter(int parameterIndex) { + return cube.getParameter(parameterIndex); + } + + @Override + public ParameterMetadata getParameterMetadata(int parameterIndex) { + return cube.getParameterMetadata(parameterIndex); + } + + @Override + public OptionalInt findParameterIndex(ParameterMetadata metadata) { + return cube.findParameterIndex(metadata); + } + + @Override + public NormalSwaptionExpiryTenorStrikeVolatilities withParameter(int parameterIndex, double newValue) { + return new NormalSwaptionExpiryTenorStrikeVolatilities( + convention, valuationDateTime, cube.withParameter(parameterIndex, newValue)); + } + + @Override + public NormalSwaptionExpiryTenorStrikeVolatilities withPerturbation(ParameterPerturbation perturbation) { + return new NormalSwaptionExpiryTenorStrikeVolatilities( + convention, valuationDateTime, cube.withPerturbation(perturbation)); + } + + //------------------------------------------------------------------------- + @Override + public double volatility(double expiry, double tenor, double strike, double forwardRate) { + return cube.wValue(expiry, tenor, strike); + } + + @Override + public CurrencyParameterSensitivities parameterSensitivity(PointSensitivities pointSensitivities) { + CurrencyParameterSensitivities sens = CurrencyParameterSensitivities.empty(); + for (PointSensitivity point : pointSensitivities.getSensitivities()) { + if (point instanceof SwaptionSensitivity) { + SwaptionSensitivity pt = (SwaptionSensitivity) point; + if (pt.getVolatilitiesName().equals(getName())) { + sens = sens.combinedWith(parameterSensitivity(pt)); + } + } + } + return sens; + } + + private CurrencyParameterSensitivity parameterSensitivity(SwaptionSensitivity point) { + double expiry = point.getExpiry(); + double tenor = point.getTenor(); + double strike = point.getStrike(); + UnitParameterSensitivity unitSens = cube.wValueParameterSensitivity(expiry, tenor, strike); + return unitSens.multipliedBy(point.getCurrency(), point.getSensitivity()); + } + + //------------------------------------------------------------------------- + @Override + public double price(double expiry, double tenor, PutCall putCall, double strike, double forward, double volatility) { + return NormalFormulaRepository.price(forward, strike, expiry, volatility, putCall); + } + + @Override + public double priceDelta( + double expiry, + double tenor, + PutCall putCall, + double strike, + double forward, + double volatility) { + + return NormalFormulaRepository.delta(forward, strike, expiry, volatility, putCall); + } + + @Override + public double priceGamma( + double expiry, + double tenor, + PutCall putCall, + double strike, + double forward, + double volatility) { + + return NormalFormulaRepository.gamma(forward, strike, expiry, volatility, putCall); + } + + @Override + public double priceTheta( + double expiry, + double tenor, + PutCall putCall, + double strike, + double forward, + double volatility) { + + return NormalFormulaRepository.theta(forward, strike, expiry, volatility, putCall); + } + + @Override + public double priceVega( + double expiry, + double tenor, + PutCall putCall, + double strike, + double forward, + double volatility) { + + return NormalFormulaRepository.vega(forward, strike, expiry, volatility, putCall); + } + + //------------------------------------------------------------------------- + @Override + public double relativeTime(ZonedDateTime dateTime) { + ArgChecker.notNull(dateTime, "dateTime"); + LocalDate valuationDate = valuationDateTime.toLocalDate(); + LocalDate date = dateTime.toLocalDate(); + return dayCount.relativeYearFraction(valuationDate, date); + } + + @Override + public double tenor(LocalDate startDate, LocalDate endDate) { + // rounded number of months. the rounding is to ensure that an integer number of year even with holidays/leap year + return Math.round((endDate.toEpochDay() - startDate.toEpochDay()) / 365.25 * 12) / 12; + } + + //------------------------- AUTOGENERATED START ------------------------- + /** + * The meta-bean for {@code NormalSwaptionExpiryTenorStrikeVolatilities}. + * @return the meta-bean, not null + */ + public static NormalSwaptionExpiryTenorStrikeVolatilities.Meta meta() { + return NormalSwaptionExpiryTenorStrikeVolatilities.Meta.INSTANCE; + } + + static { + MetaBean.register(NormalSwaptionExpiryTenorStrikeVolatilities.Meta.INSTANCE); + } + + /** + * The serialization version id. + */ + private static final long serialVersionUID = 1L; + + @Override + public NormalSwaptionExpiryTenorStrikeVolatilities.Meta metaBean() { + return NormalSwaptionExpiryTenorStrikeVolatilities.Meta.INSTANCE; + } + + //----------------------------------------------------------------------- + /** + * Gets the swap convention that the volatilities are to be used for. + * @return the value of the property, not null + */ + @Override + public FixedFloatSwapConvention getConvention() { + return convention; + } + + //----------------------------------------------------------------------- + /** + * Gets the valuation date-time. + *

    + * The volatilities are calibrated for this date-time. + * @return the value of the property, not null + */ + @Override + public ZonedDateTime getValuationDateTime() { + return valuationDateTime; + } + + //----------------------------------------------------------------------- + /** + * Gets the normal volatility cube. + *

    + * The x-value of the cube is the expiry, as a year fraction. + * The y-value of the cube is the swap tenor, as a year fraction rounded to the month. + * The z-value of the cube is the strike, as a rate. + * @return the value of the property, not null + */ + public Cube getCube() { + return cube; + } + + //----------------------------------------------------------------------- + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && obj.getClass() == this.getClass()) { + NormalSwaptionExpiryTenorStrikeVolatilities other = (NormalSwaptionExpiryTenorStrikeVolatilities) obj; + return JodaBeanUtils.equal(convention, other.convention) && + JodaBeanUtils.equal(valuationDateTime, other.valuationDateTime) && + JodaBeanUtils.equal(cube, other.cube); + } + return false; + } + + @Override + public int hashCode() { + int hash = getClass().hashCode(); + hash = hash * 31 + JodaBeanUtils.hashCode(convention); + hash = hash * 31 + JodaBeanUtils.hashCode(valuationDateTime); + hash = hash * 31 + JodaBeanUtils.hashCode(cube); + return hash; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(128); + buf.append("NormalSwaptionExpiryTenorStrikeVolatilities{"); + buf.append("convention").append('=').append(JodaBeanUtils.toString(convention)).append(',').append(' '); + buf.append("valuationDateTime").append('=').append(JodaBeanUtils.toString(valuationDateTime)).append(',').append(' '); + buf.append("cube").append('=').append(JodaBeanUtils.toString(cube)); + buf.append('}'); + return buf.toString(); + } + + //----------------------------------------------------------------------- + /** + * The meta-bean for {@code NormalSwaptionExpiryTenorStrikeVolatilities}. + */ + public static final class Meta extends DirectMetaBean { + /** + * The singleton instance of the meta-bean. + */ + static final Meta INSTANCE = new Meta(); + + /** + * The meta-property for the {@code convention} property. + */ + private final MetaProperty convention = DirectMetaProperty.ofImmutable( + this, "convention", NormalSwaptionExpiryTenorStrikeVolatilities.class, FixedFloatSwapConvention.class); + /** + * The meta-property for the {@code valuationDateTime} property. + */ + private final MetaProperty valuationDateTime = DirectMetaProperty.ofImmutable( + this, "valuationDateTime", NormalSwaptionExpiryTenorStrikeVolatilities.class, ZonedDateTime.class); + /** + * The meta-property for the {@code cube} property. + */ + private final MetaProperty cube = DirectMetaProperty.ofImmutable( + this, "cube", NormalSwaptionExpiryTenorStrikeVolatilities.class, Cube.class); + /** + * The meta-properties. + */ + private final Map> metaPropertyMap$ = new DirectMetaPropertyMap( + this, null, + "convention", + "valuationDateTime", + "cube"); + + /** + * Restricted constructor. + */ + private Meta() { + } + + @Override + protected MetaProperty metaPropertyGet(String propertyName) { + switch (propertyName.hashCode()) { + case 2039569265: // convention + return convention; + case -949589828: // valuationDateTime + return valuationDateTime; + case 3064885: // cube + return cube; + } + return super.metaPropertyGet(propertyName); + } + + @Override + public BeanBuilder builder() { + return new NormalSwaptionExpiryTenorStrikeVolatilities.Builder(); + } + + @Override + public Class beanType() { + return NormalSwaptionExpiryTenorStrikeVolatilities.class; + } + + @Override + public Map> metaPropertyMap() { + return metaPropertyMap$; + } + + //----------------------------------------------------------------------- + /** + * The meta-property for the {@code convention} property. + * @return the meta-property, not null + */ + public MetaProperty convention() { + return convention; + } + + /** + * The meta-property for the {@code valuationDateTime} property. + * @return the meta-property, not null + */ + public MetaProperty valuationDateTime() { + return valuationDateTime; + } + + /** + * The meta-property for the {@code cube} property. + * @return the meta-property, not null + */ + public MetaProperty cube() { + return cube; + } + + //----------------------------------------------------------------------- + @Override + protected Object propertyGet(Bean bean, String propertyName, boolean quiet) { + switch (propertyName.hashCode()) { + case 2039569265: // convention + return ((NormalSwaptionExpiryTenorStrikeVolatilities) bean).getConvention(); + case -949589828: // valuationDateTime + return ((NormalSwaptionExpiryTenorStrikeVolatilities) bean).getValuationDateTime(); + case 3064885: // cube + return ((NormalSwaptionExpiryTenorStrikeVolatilities) bean).getCube(); + } + return super.propertyGet(bean, propertyName, quiet); + } + + @Override + protected void propertySet(Bean bean, String propertyName, Object newValue, boolean quiet) { + metaProperty(propertyName); + if (quiet) { + return; + } + throw new UnsupportedOperationException("Property cannot be written: " + propertyName); + } + + } + + //----------------------------------------------------------------------- + /** + * The bean-builder for {@code NormalSwaptionExpiryTenorStrikeVolatilities}. + */ + private static final class Builder extends DirectPrivateBeanBuilder { + + private FixedFloatSwapConvention convention; + private ZonedDateTime valuationDateTime; + private Cube cube; + + /** + * Restricted constructor. + */ + private Builder() { + } + + //----------------------------------------------------------------------- + @Override + public Object get(String propertyName) { + switch (propertyName.hashCode()) { + case 2039569265: // convention + return convention; + case -949589828: // valuationDateTime + return valuationDateTime; + case 3064885: // cube + return cube; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + } + + @Override + public Builder set(String propertyName, Object newValue) { + switch (propertyName.hashCode()) { + case 2039569265: // convention + this.convention = (FixedFloatSwapConvention) newValue; + break; + case -949589828: // valuationDateTime + this.valuationDateTime = (ZonedDateTime) newValue; + break; + case 3064885: // cube + this.cube = (Cube) newValue; + break; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + return this; + } + + @Override + public NormalSwaptionExpiryTenorStrikeVolatilities build() { + return new NormalSwaptionExpiryTenorStrikeVolatilities( + convention, + valuationDateTime, + cube); + } + + //----------------------------------------------------------------------- + @Override + public String toString() { + StringBuilder buf = new StringBuilder(128); + buf.append("NormalSwaptionExpiryTenorStrikeVolatilities.Builder{"); + buf.append("convention").append('=').append(JodaBeanUtils.toString(convention)).append(',').append(' '); + buf.append("valuationDateTime").append('=').append(JodaBeanUtils.toString(valuationDateTime)).append(',').append(' '); + buf.append("cube").append('=').append(JodaBeanUtils.toString(cube)); + buf.append('}'); + return buf.toString(); + } + + } + + //-------------------------- AUTOGENERATED END -------------------------- +} diff --git a/modules/pricer/src/test/java/com/opengamma/strata/pricer/swaption/NormalSwaptionExpiryTenorStrikeVolatilitiesTest.java b/modules/pricer/src/test/java/com/opengamma/strata/pricer/swaption/NormalSwaptionExpiryTenorStrikeVolatilitiesTest.java new file mode 100644 index 0000000000..d082ee0521 --- /dev/null +++ b/modules/pricer/src/test/java/com/opengamma/strata/pricer/swaption/NormalSwaptionExpiryTenorStrikeVolatilitiesTest.java @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.pricer.swaption; + +import static com.opengamma.strata.basics.currency.Currency.GBP; +import static com.opengamma.strata.basics.date.DayCounts.ACT_365F; +import static com.opengamma.strata.collect.TestHelper.coverBeanEquals; +import static com.opengamma.strata.collect.TestHelper.coverImmutableBean; +import static com.opengamma.strata.collect.TestHelper.date; +import static com.opengamma.strata.collect.TestHelper.dateUtc; +import static com.opengamma.strata.market.curve.interpolator.CurveInterpolators.LINEAR; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.data.Offset.offset; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.junit.jupiter.api.Test; + +import com.google.common.collect.ImmutableList; +import com.opengamma.strata.basics.date.Tenor; +import com.opengamma.strata.collect.array.DoubleArray; +import com.opengamma.strata.collect.tuple.Triple; +import com.opengamma.strata.market.cube.CubeMetadata; +import com.opengamma.strata.market.cube.CubeName; +import com.opengamma.strata.market.cube.Cubes; +import com.opengamma.strata.market.cube.InterpolatedNodalCube; +import com.opengamma.strata.market.cube.interpolator.CubeInterpolator; +import com.opengamma.strata.market.cube.interpolator.GridCubeInterpolator; +import com.opengamma.strata.market.param.CurrencyParameterSensitivities; +import com.opengamma.strata.market.param.CurrencyParameterSensitivity; +import com.opengamma.strata.market.param.ParameterMetadata; +import com.opengamma.strata.market.param.TenorTenorStrikeParameterMetadata; +import com.opengamma.strata.product.swap.type.FixedIborSwapConvention; +import com.opengamma.strata.product.swap.type.FixedIborSwapConventions; + +/** + * Test {@link NormalSwaptionExpiryTenorStrikeVolatilities}. + */ +public class NormalSwaptionExpiryTenorStrikeVolatilitiesTest { + + private static final CubeInterpolator INTERPOLATOR_3D = GridCubeInterpolator.of(LINEAR, LINEAR, LINEAR); + private static final DoubleArray TIME = DoubleArray.of( + 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, 0.25, + 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + private static final DoubleArray TENOR = DoubleArray.of( + 3, 3, 3, 3, 5, 5, 5, 5, 7, 7, 7, 7, 10, 10, 10, 10, + 3, 3, 3, 3, 5, 5, 5, 5, 7, 7, 7, 7, 10, 10, 10, 10, + 3, 3, 3, 3, 5, 5, 5, 5, 7, 7, 7, 7, 10, 10, 10, 10); + private static final DoubleArray STRIKE = DoubleArray.of( + 0.025, 0.03, 0.035, 0.04, 0.025, 0.03, 0.035, 0.04, 0.025, 0.03, 0.035, 0.04, 0.025, 0.03, 0.035, 0.04, + 0.025, 0.03, 0.035, 0.04, 0.025, 0.03, 0.035, 0.04, 0.025, 0.03, 0.035, 0.04, 0.025, 0.03, 0.035, 0.04, + 0.025, 0.03, 0.035, 0.04, 0.025, 0.03, 0.035, 0.04, 0.025, 0.03, 0.035, 0.04, 0.025, 0.03, 0.035, 0.04); + private static final DoubleArray VOL = DoubleArray.of( + 0.018, 0.015, 0.013, 0.012, 0.017, 0.014, 0.013, 0.012, 0.016, 0.013, 0.011, 0.01, 0.015, 0.012, 0.01, 0.009, + 0.015, 0.012, 0.011, 0.01, 0.016, 0.013, 0.012, 0.011, 0.015, 0.012, 0.011, 0.01, 0.014, 0.011, 0.01, 0.009, + 0.013, 0.01, 0.009, 0.008, 0.014, 0.012, 0.011, 0.01, 0.013, 0.011, 0.01, 0.009, 0.012, 0.01, 0.009, 0.007); + + private static final FixedIborSwapConvention CONVENTION = FixedIborSwapConventions.GBP_FIXED_1Y_LIBOR_3M; + private static final CubeMetadata METADATA; + private static final ImmutableList EXPIRY_TENOR; + + static { + ImmutableList.Builder paramList = ImmutableList.builder(); + ImmutableList.Builder expiryTenorList = ImmutableList.builder(); + int nData = TIME.size(); + for (int i = 0; i < nData; ++i) { + Tenor expiryTenor = TIME.get(i) == 0.25 ? Tenor.TENOR_3M : TIME.get(i) == 0.5 ? Tenor.TENOR_6M : Tenor.TENOR_1Y; + expiryTenorList.add(expiryTenor); + TenorTenorStrikeParameterMetadata parameterMetadata = + TenorTenorStrikeParameterMetadata.of(expiryTenor, Tenor.ofYears((int) TENOR.get(i)), STRIKE.get(i)); + paramList.add(parameterMetadata); + } + METADATA = Cubes.normalVolatilityByExpiryTenorStrike( + "GOVT1-SWAPTION-VOL", + ACT_365F).withParameterMetadata(paramList.build()); + EXPIRY_TENOR = expiryTenorList.build(); + } + + private static final InterpolatedNodalCube CUBE = + InterpolatedNodalCube.of(METADATA, TIME, TENOR, STRIKE, VOL, INTERPOLATOR_3D); + private static final LocalDate VAL_DATE = date(2015, 2, 17); + private static final LocalTime VAL_TIME = LocalTime.of(13, 45); + private static final ZoneId LONDON_ZONE = ZoneId.of("Europe/London"); + private static final ZonedDateTime VAL_DATE_TIME = VAL_DATE.atTime(VAL_TIME).atZone(LONDON_ZONE); + private static final NormalSwaptionExpiryTenorStrikeVolatilities VOLS = + NormalSwaptionExpiryTenorStrikeVolatilities.of(CONVENTION, VAL_DATE_TIME, CUBE); + + private static final ZonedDateTime[] TEST_OPTION_EXPIRY = new ZonedDateTime[]{ + dateUtc(2015, 2, 17), dateUtc(2015, 5, 17), dateUtc(2015, 6, 17), dateUtc(2017, 2, 17)}; + private static final int NB_TEST = TEST_OPTION_EXPIRY.length; + private static final double[] TEST_TENOR = new double[]{2.0, 6.0, 7.0, 15.0}; + private static final double[] TEST_SENSITIVITY = new double[]{1.0, 1.0, 1.0, 1.0}; + private static final double[] TEST_STRIKE = new double[]{0.01, 0.027, 0.037, 0.05}; + private static final double TEST_FORWARD = 0.025; // not used internally + + private static final double TOLERANCE_VOL = 1.0E-10; + + //------------------------------------------------------------------------- + @Test + public void test_valuationDate() { + assertThat(VOLS.getValuationDateTime()).isEqualTo(VAL_DATE_TIME); + } + + @Test + public void test_swapConvention() { + assertThat(VOLS.getConvention()).isEqualTo(CONVENTION); + } + + @Test + public void test_findData() { + assertThat(VOLS.findData(CUBE.getName())).isEqualTo(Optional.of(CUBE)); + assertThat(VOLS.findData(CubeName.of("Rubbish"))).isEqualTo(Optional.empty()); + } + + @Test + public void test_tenor() { + double test1 = VOLS.tenor(VAL_DATE, VAL_DATE); + assertThat(test1).isEqualTo(0d); + double test2 = VOLS.tenor(VAL_DATE, date(2018, 2, 28)); + assertThat(test2).isEqualTo(3d); + double test3 = VOLS.tenor(VAL_DATE, date(2018, 2, 10)); + assertThat(test3).isEqualTo(3d); + } + + @Test + public void test_relativeTime() { + double test1 = VOLS.relativeTime(VAL_DATE_TIME); + assertThat(test1).isEqualTo(0d); + double test2 = VOLS.relativeTime(date(2018, 2, 17).atStartOfDay(LONDON_ZONE)); + double test3 = VOLS.relativeTime(date(2012, 2, 17).atStartOfDay(LONDON_ZONE)); + assertThat(test2).isEqualTo(-test3); // consistency checked + } + + @Test + public void test_volatility() { + for (int i = 0; i < NB_TEST; i++) { + double expiryTime = VOLS.relativeTime(TEST_OPTION_EXPIRY[i]); + double volExpected = CUBE.wValue(expiryTime, TEST_TENOR[i], TEST_STRIKE[i]); + double volComputed = VOLS.volatility(TEST_OPTION_EXPIRY[i], TEST_TENOR[i], TEST_STRIKE[i], TEST_FORWARD); + assertThat(volComputed).isCloseTo(volExpected, offset(TOLERANCE_VOL)); + } + } + + @Test + public void test_volatility_sensitivity() { + double eps = 1.0e-6; + int nData = TIME.size(); + for (int i = 0; i < NB_TEST; i++) { + double expiryTime = VOLS.relativeTime(TEST_OPTION_EXPIRY[i]); + SwaptionSensitivity point = SwaptionSensitivity.of( + VOLS.getName(), expiryTime, TEST_TENOR[i], TEST_STRIKE[i], TEST_FORWARD, GBP, TEST_SENSITIVITY[i]); + CurrencyParameterSensitivities sensActual = VOLS.parameterSensitivity(point); + CurrencyParameterSensitivity sensi = sensActual.getSensitivity(CUBE.getName(), GBP); + DoubleArray computed = sensi.getSensitivity(); + + Map, Double> map = new HashMap<>(); + for (int j = 0; j < nData; ++j) { + DoubleArray volDataUp = VOL.subArray(0, nData).with(j, VOL.get(j) + eps); + DoubleArray volDataDw = VOL.subArray(0, nData).with(j, VOL.get(j) - eps); + InterpolatedNodalCube paramUp = + InterpolatedNodalCube.of(METADATA, TIME, TENOR, STRIKE, volDataUp, INTERPOLATOR_3D); + InterpolatedNodalCube paramDw = + InterpolatedNodalCube.of(METADATA, TIME, TENOR, STRIKE, volDataDw, INTERPOLATOR_3D); + NormalSwaptionExpiryTenorStrikeVolatilities provUp = + NormalSwaptionExpiryTenorStrikeVolatilities.of(CONVENTION, VAL_DATE_TIME, paramUp); + NormalSwaptionExpiryTenorStrikeVolatilities provDw = + NormalSwaptionExpiryTenorStrikeVolatilities.of(CONVENTION, VAL_DATE_TIME, paramDw); + double volUp = provUp.volatility(TEST_OPTION_EXPIRY[i], TEST_TENOR[i], TEST_STRIKE[i], TEST_FORWARD); + double volDw = provDw.volatility(TEST_OPTION_EXPIRY[i], TEST_TENOR[i], TEST_STRIKE[i], TEST_FORWARD); + double fd = 0.5 * (volUp - volDw) / eps; + map.put(Triple.of(EXPIRY_TENOR.get(j), Tenor.ofYears((int) TENOR.get(j)), STRIKE.get(j)), fd); + } + List list = sensi.getParameterMetadata(); + assertThat(computed.size()).isEqualTo(nData); + for (int j = 0; j < list.size(); ++j) { + TenorTenorStrikeParameterMetadata metadata = + (TenorTenorStrikeParameterMetadata) list.get(i); + double expected = map.get(Triple.of( + metadata.getExpiryTenor(), + metadata.getUnderlyingTenor(), + metadata.getStrike())); + assertThat(computed.get(i)).isCloseTo(expected, offset(eps)); + } + } + } + + //------------------------------------------------------------------------- + @Test + public void coverage() { + NormalSwaptionExpiryTenorStrikeVolatilities test1 = + NormalSwaptionExpiryTenorStrikeVolatilities.of(CONVENTION, VAL_DATE_TIME, CUBE); + coverImmutableBean(test1); + NormalSwaptionExpiryTenorStrikeVolatilities test2 = NormalSwaptionExpiryTenorStrikeVolatilities.of( + FixedIborSwapConventions.USD_FIXED_1Y_LIBOR_3M, + VAL_DATE.atStartOfDay(ZoneOffset.UTC), + CUBE.withPerturbation((i, v, m) -> 2d * v)); + coverBeanEquals(test1, test2); + } + +} From f4c91c4cbef9e67d0db06fa91b82ca4846faad87 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Mon, 22 Apr 2024 15:29:22 +0000 Subject: [PATCH 087/116] [maven-release-plugin] prepare release v2.12.38 --- examples/pom.xml | 6 +++++- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 70525533ac..536b6a11e1 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.38-SNAPSHOT + 2.12.38 jar Strata-Examples Example code to demonstrate use of Strata @@ -272,4 +272,8 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> + + + v2.12.38 + diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index b5ce91cdad..6b5c70e80e 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.38-SNAPSHOT + 2.12.38 .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index d7d822d4e3..1a793df6f4 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.38-SNAPSHOT + 2.12.38 .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index ba18e5a3dd..fa9a7b6dd7 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.38-SNAPSHOT + 2.12.38 .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 826026eab0..a90b915ac1 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.38-SNAPSHOT + 2.12.38 .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 07bc5a8add..c27c18bba9 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.38-SNAPSHOT + 2.12.38 .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 4332739800..175d2b29b4 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.38-SNAPSHOT + 2.12.38 .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 1c4e7e4579..639c371ade 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.38-SNAPSHOT + 2.12.38 .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 668579b79e..6a77ec8dac 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.38-SNAPSHOT + 2.12.38 .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index f18b1b5639..4637a90809 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.38-SNAPSHOT + 2.12.38 pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.38 diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index a0dce07d66..d566cfa500 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.38-SNAPSHOT + 2.12.38 .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 6d21e1e4fe..af480ae660 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.38-SNAPSHOT + 2.12.38 .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 0571a228df..781ea0110b 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.38-SNAPSHOT + 2.12.38 .. strata-report diff --git a/pom.xml b/pom.xml index 324524e653..c17031fd27 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.38-SNAPSHOT + 2.12.38 pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.38 From 2c097d0bf95aaf0dc9b8e2d8a0a29715fddd36bd Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Mon, 22 Apr 2024 15:29:23 +0000 Subject: [PATCH 088/116] [maven-release-plugin] prepare for next development iteration --- examples/pom.xml | 6 +----- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 536b6a11e1..c38e948478 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.38 + 2.12.39-SNAPSHOT jar Strata-Examples Example code to demonstrate use of Strata @@ -272,8 +272,4 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> - - - v2.12.38 - diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index 6b5c70e80e..cc4811f21d 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.38 + 2.12.39-SNAPSHOT .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 1a793df6f4..8a4be58e0e 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.38 + 2.12.39-SNAPSHOT .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index fa9a7b6dd7..713d632eb2 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.38 + 2.12.39-SNAPSHOT .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index a90b915ac1..6a8312543d 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.38 + 2.12.39-SNAPSHOT .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index c27c18bba9..5ebfa5354b 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.38 + 2.12.39-SNAPSHOT .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 175d2b29b4..4e874ad06c 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.38 + 2.12.39-SNAPSHOT .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 639c371ade..649d2532c8 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.38 + 2.12.39-SNAPSHOT .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 6a77ec8dac..9769df09df 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.38 + 2.12.39-SNAPSHOT .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 4637a90809..beed65f8ac 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.38 + 2.12.39-SNAPSHOT pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.38 + HEAD diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index d566cfa500..afa669286b 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.38 + 2.12.39-SNAPSHOT .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index af480ae660..dae52883a4 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.38 + 2.12.39-SNAPSHOT .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 781ea0110b..15e0c22f04 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.38 + 2.12.39-SNAPSHOT .. strata-report diff --git a/pom.xml b/pom.xml index c17031fd27..e99871bfc7 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.38 + 2.12.39-SNAPSHOT pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.38 + HEAD From 355b84a39bbfc487ec5f971500b52590454a6e4e Mon Sep 17 00:00:00 2001 From: Michael Rollins Date: Tue, 4 Jun 2024 14:10:26 +0100 Subject: [PATCH 089/116] PROD-38570: Fixing ValueStepSequence resolving with RollConvensions (#2653) Co-authored-by: Michael Rollins --- .../strata/basics/value/ValueStepSequence.java | 11 ++++++----- .../strata/basics/value/ValueStepSequenceTest.java | 12 ++++++++++++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/modules/basics/src/main/java/com/opengamma/strata/basics/value/ValueStepSequence.java b/modules/basics/src/main/java/com/opengamma/strata/basics/value/ValueStepSequence.java index 3fe6fd9dc3..a48cf2eb37 100644 --- a/modules/basics/src/main/java/com/opengamma/strata/basics/value/ValueStepSequence.java +++ b/modules/basics/src/main/java/com/opengamma/strata/basics/value/ValueStepSequence.java @@ -120,17 +120,18 @@ private void validate() { List resolve(List existingSteps, RollConvention rollConv) { ImmutableList.Builder steps = ImmutableList.builder(); steps.addAll(existingSteps); - LocalDate prev = firstStepDate; - LocalDate date = firstStepDate; - while (!date.isAfter(lastStepDate)) { + LocalDate prev = rollConv.adjust(firstStepDate); + LocalDate date = rollConv.adjust(firstStepDate); + LocalDate adjustedLastStepDate = rollConv.adjust(lastStepDate); + while (!date.isAfter(adjustedLastStepDate)) { steps.add(ValueStep.of(date, adjustment)); prev = date; date = rollConv.next(date, frequency); } - if (!prev.equals(lastStepDate)) { + if (!prev.equals(adjustedLastStepDate)) { throw new IllegalArgumentException(Messages.format( "ValueStepSequence lastStepDate did not match frequency '{}' using roll convention '{}', {} != {}", - frequency, rollConv, lastStepDate, prev)); + frequency, rollConv, adjustedLastStepDate, prev)); } return steps.build(); } diff --git a/modules/basics/src/test/java/com/opengamma/strata/basics/value/ValueStepSequenceTest.java b/modules/basics/src/test/java/com/opengamma/strata/basics/value/ValueStepSequenceTest.java index 260d8b9ebf..bed6a7dcde 100644 --- a/modules/basics/src/test/java/com/opengamma/strata/basics/value/ValueStepSequenceTest.java +++ b/modules/basics/src/test/java/com/opengamma/strata/basics/value/ValueStepSequenceTest.java @@ -59,6 +59,18 @@ public void test_resolve() { assertThat(steps.get(3)).isEqualTo(ValueStep.of(date(2016, 10, 20), ADJ)); } + @Test + public void test_resolve_with_roll_convention() { + ValueStepSequence test = ValueStepSequence.of(date(2022, 9, 21), date(2026, 9, 21), Frequency.P12M, ADJ); + List steps = test.resolve(ImmutableList.of(), RollConventions.IMM); + assertThat(steps.size()).isEqualTo(5); + assertThat(steps.get(0)).isEqualTo(ValueStep.of(date(2022, 9, 21), ADJ)); + assertThat(steps.get(1)).isEqualTo(ValueStep.of(date(2023, 9, 20), ADJ)); + assertThat(steps.get(2)).isEqualTo(ValueStep.of(date(2024, 9, 18), ADJ)); + assertThat(steps.get(3)).isEqualTo(ValueStep.of(date(2025, 9, 17), ADJ)); + assertThat(steps.get(4)).isEqualTo(ValueStep.of(date(2026, 9, 16), ADJ)); + } + @Test public void test_resolve_invalid() { ValueStepSequence test = ValueStepSequence.of(date(2016, 4, 20), date(2016, 10, 20), Frequency.P12M, ADJ); From 8a62cb39d9ed8ff0b596d5f356d7d7daadce801e Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Wed, 5 Jun 2024 10:01:44 +0000 Subject: [PATCH 090/116] [maven-release-plugin] prepare release v2.12.39 --- examples/pom.xml | 6 +++++- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index c38e948478..5e42856ae5 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.39-SNAPSHOT + 2.12.39 jar Strata-Examples Example code to demonstrate use of Strata @@ -272,4 +272,8 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> + + + v2.12.39 + diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index cc4811f21d..836708f887 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.39-SNAPSHOT + 2.12.39 .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 8a4be58e0e..3495a4b279 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.39-SNAPSHOT + 2.12.39 .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 713d632eb2..a8d8e919ca 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.39-SNAPSHOT + 2.12.39 .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 6a8312543d..aed8623d00 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.39-SNAPSHOT + 2.12.39 .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 5ebfa5354b..301f7869da 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.39-SNAPSHOT + 2.12.39 .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 4e874ad06c..7596613c17 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.39-SNAPSHOT + 2.12.39 .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 649d2532c8..1b2580e392 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.39-SNAPSHOT + 2.12.39 .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 9769df09df..487f8f17e5 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.39-SNAPSHOT + 2.12.39 .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index beed65f8ac..7383d9b18e 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.39-SNAPSHOT + 2.12.39 pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.39 diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index afa669286b..22e20227b5 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.39-SNAPSHOT + 2.12.39 .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index dae52883a4..f271188071 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.39-SNAPSHOT + 2.12.39 .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 15e0c22f04..86408d4ddf 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.39-SNAPSHOT + 2.12.39 .. strata-report diff --git a/pom.xml b/pom.xml index e99871bfc7..5ae7b5e211 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.39-SNAPSHOT + 2.12.39 pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.39 From 502bb6aae7309aad109e3ac20f1cc90293c0802c Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Wed, 5 Jun 2024 10:01:46 +0000 Subject: [PATCH 091/116] [maven-release-plugin] prepare for next development iteration --- examples/pom.xml | 6 +----- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 5e42856ae5..bb4a1f63a3 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.39 + 2.12.40-SNAPSHOT jar Strata-Examples Example code to demonstrate use of Strata @@ -272,8 +272,4 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> - - - v2.12.39 - diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index 836708f887..dae20a84b1 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.39 + 2.12.40-SNAPSHOT .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 3495a4b279..e46b488b0e 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.39 + 2.12.40-SNAPSHOT .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index a8d8e919ca..d804b2fbf0 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.39 + 2.12.40-SNAPSHOT .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index aed8623d00..fc8142897e 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.39 + 2.12.40-SNAPSHOT .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 301f7869da..b291c36a81 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.39 + 2.12.40-SNAPSHOT .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 7596613c17..97ca3c9d3b 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.39 + 2.12.40-SNAPSHOT .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 1b2580e392..a20242da6b 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.39 + 2.12.40-SNAPSHOT .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 487f8f17e5..13467a506b 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.39 + 2.12.40-SNAPSHOT .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 7383d9b18e..381ff39e20 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.39 + 2.12.40-SNAPSHOT pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.39 + HEAD diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 22e20227b5..57f9dd038e 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.39 + 2.12.40-SNAPSHOT .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index f271188071..a7e592b3f9 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.39 + 2.12.40-SNAPSHOT .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 86408d4ddf..7b63fa9089 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.39 + 2.12.40-SNAPSHOT .. strata-report diff --git a/pom.xml b/pom.xml index 5ae7b5e211..019935a7db 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.39 + 2.12.40-SNAPSHOT pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.39 + HEAD From 2ed984ca8ffbdefed222cfbe5c66b73af5b5804e Mon Sep 17 00:00:00 2001 From: James White <118170713+James-OpenGamma@users.noreply.github.com> Date: Thu, 6 Jun 2024 12:03:59 +0100 Subject: [PATCH 092/116] Added custom message to ensure only one (#2644) Co-authored-by: James White Co-authored-by: Stephen Colebourne --- .../com/opengamma/strata/collect/Guavate.java | 26 +++++++++++++++++++ .../opengamma/strata/collect/GuavateTest.java | 11 ++++++++ 2 files changed, 37 insertions(+) diff --git a/modules/collect/src/main/java/com/opengamma/strata/collect/Guavate.java b/modules/collect/src/main/java/com/opengamma/strata/collect/Guavate.java index d5a90ada35..95bf48d9ee 100644 --- a/modules/collect/src/main/java/com/opengamma/strata/collect/Guavate.java +++ b/modules/collect/src/main/java/com/opengamma/strata/collect/Guavate.java @@ -682,6 +682,7 @@ public static Predicate not(Predicate predicate) { * * @param the type of element in the stream * @return the operator + * @throws IllegalArgumentException if more than one element is present */ public static BinaryOperator ensureOnlyOne() { return (a, b) -> { @@ -690,6 +691,31 @@ public static BinaryOperator ensureOnlyOne() { }; } + /** + * Reducer used in a stream to ensure there is no more than one matching element. + *

    + * This method returns an operator that can be used with {@link Stream#reduce(BinaryOperator)} + * that returns either zero or one elements from the stream. Unlike {@link Stream#findFirst()} + * or {@link Stream#findAny()}, this approach ensures an exception is thrown if there + * is more than one element in the stream. + *

    + * This would be used as follows (with a static import): + *

    +   *   stream.filter(...).reduce(ensureOnlyOne()).get();
    +   * 
    + * + * @param the type of element in the stream + * @param message the message template for the {@link IllegalArgumentException} with "{}" placeholders + * @param args the arguments for the message + * @return the operator + * @throws IllegalArgumentException if more than one element is present + */ + public static BinaryOperator ensureOnlyOne(String message, Object... args) { + return (a, b) -> { + throw new IllegalArgumentException(Messages.format(message, args)); + }; + } + //------------------------------------------------------------------------- /** * Function used in a stream to cast instances to a particular type without filtering. diff --git a/modules/collect/src/test/java/com/opengamma/strata/collect/GuavateTest.java b/modules/collect/src/test/java/com/opengamma/strata/collect/GuavateTest.java index 176748dfa9..a0363c1f69 100644 --- a/modules/collect/src/test/java/com/opengamma/strata/collect/GuavateTest.java +++ b/modules/collect/src/test/java/com/opengamma/strata/collect/GuavateTest.java @@ -424,6 +424,17 @@ public void test_ensureOnlyOne() { assertThatIllegalArgumentException().isThrownBy(() -> Stream.of("a", "b").reduce(Guavate.ensureOnlyOne())); } + @Test + public void test_ensureOnlyOne_withCustomMessage() { + String message = "Expected one letter but found multiple for date {}"; + LocalDate arg = LocalDate.of(2024, 4, 24); + assertThat(Stream.empty().reduce(Guavate.ensureOnlyOne(message, arg))).isEqualTo(Optional.empty()); + assertThat(Stream.of("a").reduce(Guavate.ensureOnlyOne(message, arg))).isEqualTo(Optional.of("a")); + assertThatIllegalArgumentException().isThrownBy(() -> Stream.of("a", "b") + .reduce(Guavate.ensureOnlyOne(message, arg))) + .withMessage(Messages.format(message, arg)); + } + //------------------------------------------------------------------------- @Test public void test_casting() { From 5c41a5042c5a8ec8559943fdb70bef8aef22da31 Mon Sep 17 00:00:00 2001 From: James White <118170713+James-OpenGamma@users.noreply.github.com> Date: Thu, 6 Jun 2024 12:35:41 +0100 Subject: [PATCH 093/116] Added Result of optional method (#2645) * Added Result of optional method * Updated javadoc and moved argument --------- Co-authored-by: James White Co-authored-by: Stephen Colebourne --- .../strata/collect/result/Result.java | 41 +++++++++++++++++++ .../strata/collect/result/ResultTest.java | 24 +++++++++++ 2 files changed, 65 insertions(+) diff --git a/modules/collect/src/main/java/com/opengamma/strata/collect/result/Result.java b/modules/collect/src/main/java/com/opengamma/strata/collect/result/Result.java index d164e7cdb2..733fc85a28 100644 --- a/modules/collect/src/main/java/com/opengamma/strata/collect/result/Result.java +++ b/modules/collect/src/main/java/com/opengamma/strata/collect/result/Result.java @@ -460,6 +460,47 @@ public static Result ofNullable(R value) { return ofNullable(value, FailureReason.MISSING_DATA, "Found null where a value was expected"); } + /** + * Returns a success result containing the value if present, else returns a failure result + * with the specified reason and message. + *

    + * The message is produced using a template that contains zero to many "{}" placeholders. + * Each placeholder is replaced by the next available argument. + * If there are too few arguments, then the message will be left with placeholders. + * If there are too many arguments, then the excess arguments are appended to the + * end of the message. No attempt is made to format the arguments. + * See {@link Messages#format(String, Object...)} for more details. + * + * @param the expected type of the result + * @param value the potentially null value + * @param reason the reason for the failure + * @param message a message explaining the failure, uses "{}" for inserting {@code messageArgs} + * @param messageArgs the arguments for the message + * @return a success result if the value is non-null, else a failure result + */ + public static Result ofOptional( + Optional value, + FailureReason reason, + String message, + Object... messageArgs) { + + return value + .map(Result::success) + .orElse(Result.failure(reason, message, messageArgs)); + } + + /** + * Returns a success result containing the value if present, else returns a failure result + * with a reason of {@link FailureReason#MISSING_DATA} and message to say an unexpected empty value was found. + * + * @param the expected type of the result + * @param value the potentially null value + * @return a success result if the value is non-null, else a failure result + */ + public static Result ofOptional(Optional value) { + return ofOptional(value, FailureReason.MISSING_DATA, "Found empty where a value was expected"); + } + //------------------------------------------------------------------------- /** * Checks if all the results are successful. diff --git a/modules/collect/src/test/java/com/opengamma/strata/collect/result/ResultTest.java b/modules/collect/src/test/java/com/opengamma/strata/collect/result/ResultTest.java index 7945a900d4..42c309563c 100644 --- a/modules/collect/src/test/java/com/opengamma/strata/collect/result/ResultTest.java +++ b/modules/collect/src/test/java/com/opengamma/strata/collect/result/ResultTest.java @@ -18,6 +18,7 @@ import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.function.BiFunction; import java.util.function.Function; @@ -424,6 +425,29 @@ public void ofNullable_null() { } //------------------------------------------------------------------------- + + @Test + public void ofOptional_nonEmpty() { + Result test = Result.ofOptional(Optional.of(6)); + assertThat(test.isFailure()).isFalse(); + assertThat(test.getValue().intValue()).isEqualTo(6); + } + + @Test + public void ofOptional_empty() { + Result test = Result.ofOptional(Optional.empty()); + assertThat(test.isFailure()).isTrue(); + assertThat(test.getFailure().getMessage()).isEqualTo("Found empty where a value was expected"); + assertThat(test.getFailure().getItems().size()).isEqualTo(1); + FailureItem item = test.getFailure().getItems().iterator().next(); + assertThat(item.getReason()).isEqualTo(MISSING_DATA); + assertThat(item.getMessage()).isEqualTo("Found empty where a value was expected"); + assertThat(item.getCauseType().isPresent()).isEqualTo(false); + assertThat(item.getStackTrace()).isNotNull(); + } + + //------------------------------------------------------------------------- + @Test public void of_with_success() { From 352723d58186eeb9572219b40132df7f956fe5b7 Mon Sep 17 00:00:00 2001 From: NikolaiSalnikovRev Date: Fri, 5 Jul 2024 09:13:15 +0100 Subject: [PATCH 094/116] Fixed accrual period calculation for swap leg for a case when after date adjustment resulted period is empty. (#2656) --- .../product/swap/RateCalculationSwapLeg.java | 6 +-- .../swap/RateCalculationSwapLegTest.java | 53 +++++++++++++++++++ 2 files changed, 56 insertions(+), 3 deletions(-) diff --git a/modules/product/src/main/java/com/opengamma/strata/product/swap/RateCalculationSwapLeg.java b/modules/product/src/main/java/com/opengamma/strata/product/swap/RateCalculationSwapLeg.java index 272debdeb6..fbd5aa5f40 100644 --- a/modules/product/src/main/java/com/opengamma/strata/product/swap/RateCalculationSwapLeg.java +++ b/modules/product/src/main/java/com/opengamma/strata/product/swap/RateCalculationSwapLeg.java @@ -144,7 +144,7 @@ public void collectIndices(ImmutableSet.Builder builder) { * Returns an instance based on this leg with the start date replaced. *

    * This uses {@link PeriodicSchedule#replaceStartDate(LocalDate)}. - * + * * @throws IllegalArgumentException if the start date cannot be replaced with the proposed start date */ @Override @@ -157,7 +157,7 @@ public RateCalculationSwapLeg replaceStartDate(LocalDate adjustedStartDate) { *

    * An {@link ResolvedSwapLeg} represents the same data as this leg, but with * a complete schedule of dates defined using {@link RatePaymentPeriod}. - * + * * @return the equivalent resolved swap leg * @throws ReferenceDataNotFoundException if an identifier cannot be resolved in the reference data * @throws RuntimeException if unable to resolve due to an invalid swap schedule or definition @@ -165,7 +165,7 @@ public RateCalculationSwapLeg replaceStartDate(LocalDate adjustedStartDate) { @Override public ResolvedSwapLeg resolve(ReferenceData refData) { DayCount dayCount = calculation.getDayCount(); - Schedule resolvedAccruals = accrualSchedule.createSchedule(refData); + Schedule resolvedAccruals = accrualSchedule.createSchedule(refData, true); Schedule resolvedPayments = paymentSchedule.createSchedule(resolvedAccruals, refData); List accrualPeriods = calculation.createAccrualPeriods(resolvedAccruals, resolvedPayments, refData); List payPeriods = paymentSchedule.createPaymentPeriods( diff --git a/modules/product/src/test/java/com/opengamma/strata/product/swap/RateCalculationSwapLegTest.java b/modules/product/src/test/java/com/opengamma/strata/product/swap/RateCalculationSwapLegTest.java index eb7ba4760d..1b77d94670 100644 --- a/modules/product/src/test/java/com/opengamma/strata/product/swap/RateCalculationSwapLegTest.java +++ b/modules/product/src/test/java/com/opengamma/strata/product/swap/RateCalculationSwapLegTest.java @@ -7,11 +7,13 @@ import static com.opengamma.strata.basics.currency.Currency.EUR; import static com.opengamma.strata.basics.currency.Currency.GBP; +import static com.opengamma.strata.basics.currency.Currency.USD; import static com.opengamma.strata.basics.date.BusinessDayConventions.FOLLOWING; import static com.opengamma.strata.basics.date.DayCounts.ACT_360; import static com.opengamma.strata.basics.date.DayCounts.ACT_365F; import static com.opengamma.strata.basics.date.DayCounts.ONE_ONE; import static com.opengamma.strata.basics.date.HolidayCalendarIds.GBLO; +import static com.opengamma.strata.basics.date.HolidayCalendarIds.USGS; import static com.opengamma.strata.basics.index.FxIndices.EUR_GBP_ECB; import static com.opengamma.strata.basics.index.IborIndices.GBP_LIBOR_1M; import static com.opengamma.strata.basics.index.IborIndices.GBP_LIBOR_3M; @@ -20,6 +22,7 @@ import static com.opengamma.strata.basics.schedule.Frequency.P1M; import static com.opengamma.strata.basics.schedule.Frequency.P2M; import static com.opengamma.strata.basics.schedule.Frequency.P3M; +import static com.opengamma.strata.basics.schedule.StubConvention.SHORT_FINAL; import static com.opengamma.strata.basics.schedule.StubConvention.SMART_INITIAL; import static com.opengamma.strata.collect.TestHelper.assertSerialization; import static com.opengamma.strata.collect.TestHelper.coverBeanEquals; @@ -27,6 +30,7 @@ import static com.opengamma.strata.collect.TestHelper.date; import static com.opengamma.strata.product.common.PayReceive.PAY; import static com.opengamma.strata.product.common.PayReceive.RECEIVE; +import static com.opengamma.strata.product.swap.CompoundingMethod.NONE; import static com.opengamma.strata.product.swap.CompoundingMethod.STRAIGHT; import static com.opengamma.strata.product.swap.PriceIndexCalculationMethod.INTERPOLATED; import static com.opengamma.strata.product.swap.PriceIndexCalculationMethod.MONTHLY; @@ -88,6 +92,8 @@ public class RateCalculationSwapLegTest { private static final LocalDate DATE_06_09 = date(2014, 6, 9); private static final LocalDate DATE_14_06_09 = date(2014, 6, 9); private static final LocalDate DATE_19_06_09 = date(2019, 6, 9); + private static final LocalDate DATE_24_07_05 = date(2024, 7, 5); + private static final LocalDate DATE_25_07_07 = date(2025, 7, 7); private static final DaysAdjustment PLUS_THREE_DAYS = DaysAdjustment.ofBusinessDays(3, GBLO); private static final DaysAdjustment PLUS_TWO_DAYS = DaysAdjustment.ofBusinessDays(2, GBLO); private static final DaysAdjustment MINUS_TWO_DAYS = DaysAdjustment.ofBusinessDays(-2, GBLO); @@ -528,6 +534,53 @@ public void test_resolve_threeAccrualsPerPayment() { .build()); } + @Test + public void test_resolve_combinePeriods() { + // test case + RateCalculationSwapLeg test = RateCalculationSwapLeg.builder() + .payReceive(PAY) + .accrualSchedule(PeriodicSchedule.builder() + .startDate(DATE_24_07_05) + .endDate(DATE_25_07_07) + .frequency(P12M) + .businessDayAdjustment(BusinessDayAdjustment.of(FOLLOWING, USGS)) + .stubConvention(SHORT_FINAL) + .build()) + .paymentSchedule(PaymentSchedule.builder() + .paymentFrequency(P12M) + .paymentDateOffset(DaysAdjustment.ofBusinessDays(0, USGS)) + .compoundingMethod(NONE) + .build()) + .notionalSchedule(NotionalSchedule.of(USD, 1000d)) + .calculation(FixedRateCalculation.builder() + .dayCount(ACT_360) + .rate(ValueSchedule.of(0.025d)) + .build()) + .build(); + // expected + RatePaymentPeriod rpp1 = RatePaymentPeriod.builder() + .paymentDate(DATE_25_07_07) + .accrualPeriods( + RateAccrualPeriod.builder() + .startDate(DATE_24_07_05) + .endDate(DATE_25_07_07) + .unadjustedStartDate(DATE_24_07_05) + .yearFraction(ACT_360.yearFraction(DATE_24_07_05, DATE_25_07_07)) + .rateComputation(FixedRateComputation.of(0.025d)) + .build()) + .dayCount(ACT_360) + .currency(USD) + .notional(-1000d) + .compoundingMethod(NONE) + .build(); + // assertion + assertThat(test.resolve(REF_DATA)).isEqualTo(ResolvedSwapLeg.builder() + .type(FIXED) + .payReceive(PAY) + .paymentPeriods(rpp1) + .build()); + } + //------------------------------------------------------------------------- @Test public void test_resolve_oneAccrualPerPayment_fxReset() { From 84a4fb79e9cc280011e402aee015bd4ee9062c97 Mon Sep 17 00:00:00 2001 From: Alexis Skitini Date: Wed, 10 Jul 2024 17:43:53 +0100 Subject: [PATCH 095/116] Make DiscreteQuantileMethod abstract methods protected (#2657) Co-authored-by: Alexis Skitini --- .../statistics/descriptive/DiscreteQuantileMethod.java | 10 +++++----- .../descriptive/IndexAboveQuantileMethod.java | 6 +++--- .../descriptive/NearestIndexQuantileMethod.java | 4 ++-- .../SamplePlusOneNearestIndexQuantileMethod.java | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/modules/math/src/main/java/com/opengamma/strata/math/impl/statistics/descriptive/DiscreteQuantileMethod.java b/modules/math/src/main/java/com/opengamma/strata/math/impl/statistics/descriptive/DiscreteQuantileMethod.java index 566ef241b7..8157022922 100644 --- a/modules/math/src/main/java/com/opengamma/strata/math/impl/statistics/descriptive/DiscreteQuantileMethod.java +++ b/modules/math/src/main/java/com/opengamma/strata/math/impl/statistics/descriptive/DiscreteQuantileMethod.java @@ -62,29 +62,29 @@ protected QuantileResult expectedShortfall(double level, DoubleArray sample) { //------------------------------------------------------------------------- /** - * Internal method computing the index for a give quantile multiply by sample size. + * Computes the index for a given quantile multiplied by sample size. *

    * The quantile size is given by quantile * sample size. * * @param quantileSize the quantile size * @return the index in the sample */ - abstract int index(double quantileSize); + protected abstract int index(double quantileSize); /** - * Internal method returning the sample size correction for the specific implementation. + * Returns the sample size correction for the specific implementation. * * @param sampleSize the sample size * @return the correction */ - abstract int sampleCorrection(int sampleSize); + protected abstract int sampleCorrection(int sampleSize); /** * Shift added to/subtracted from index during intermediate steps in the expected shortfall computation. * * @return the index shift */ - abstract double indexShift(); + protected abstract double indexShift(); /** * Generate an index of doubles. diff --git a/modules/math/src/main/java/com/opengamma/strata/math/impl/statistics/descriptive/IndexAboveQuantileMethod.java b/modules/math/src/main/java/com/opengamma/strata/math/impl/statistics/descriptive/IndexAboveQuantileMethod.java index 388de35349..214240c64a 100644 --- a/modules/math/src/main/java/com/opengamma/strata/math/impl/statistics/descriptive/IndexAboveQuantileMethod.java +++ b/modules/math/src/main/java/com/opengamma/strata/math/impl/statistics/descriptive/IndexAboveQuantileMethod.java @@ -20,17 +20,17 @@ public final class IndexAboveQuantileMethod public static final IndexAboveQuantileMethod DEFAULT = new IndexAboveQuantileMethod(); @Override - int index(double quantileSize) { + protected int index(double quantileSize) { return (int) Math.ceil(quantileSize); } @Override - int sampleCorrection(int sampleSize) { + protected int sampleCorrection(int sampleSize) { return sampleSize; } @Override - double indexShift() { + protected double indexShift() { return 0d; } } diff --git a/modules/math/src/main/java/com/opengamma/strata/math/impl/statistics/descriptive/NearestIndexQuantileMethod.java b/modules/math/src/main/java/com/opengamma/strata/math/impl/statistics/descriptive/NearestIndexQuantileMethod.java index 412b24af85..1f4d5dceac 100644 --- a/modules/math/src/main/java/com/opengamma/strata/math/impl/statistics/descriptive/NearestIndexQuantileMethod.java +++ b/modules/math/src/main/java/com/opengamma/strata/math/impl/statistics/descriptive/NearestIndexQuantileMethod.java @@ -21,12 +21,12 @@ public final class NearestIndexQuantileMethod public static final NearestIndexQuantileMethod DEFAULT = new NearestIndexQuantileMethod(); @Override - int index(double quantileSize) { + protected int index(double quantileSize) { return (int) Math.round(quantileSize); } @Override - int sampleCorrection(int sampleSize) { + protected int sampleCorrection(int sampleSize) { return sampleSize; } diff --git a/modules/math/src/main/java/com/opengamma/strata/math/impl/statistics/descriptive/SamplePlusOneNearestIndexQuantileMethod.java b/modules/math/src/main/java/com/opengamma/strata/math/impl/statistics/descriptive/SamplePlusOneNearestIndexQuantileMethod.java index c972d4f003..10fe73d6d6 100644 --- a/modules/math/src/main/java/com/opengamma/strata/math/impl/statistics/descriptive/SamplePlusOneNearestIndexQuantileMethod.java +++ b/modules/math/src/main/java/com/opengamma/strata/math/impl/statistics/descriptive/SamplePlusOneNearestIndexQuantileMethod.java @@ -21,12 +21,12 @@ public final class SamplePlusOneNearestIndexQuantileMethod public static final SamplePlusOneNearestIndexQuantileMethod DEFAULT = new SamplePlusOneNearestIndexQuantileMethod(); @Override - int index(double quantileSize) { + protected int index(double quantileSize) { return (int) Math.round(quantileSize); } @Override - int sampleCorrection(int sampleSize) { + protected int sampleCorrection(int sampleSize) { return sampleSize + 1; } From f6f61ff541fdfdd0c9e04337951e815425fe51be Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Thu, 11 Jul 2024 10:32:45 +0000 Subject: [PATCH 096/116] [maven-release-plugin] prepare release v2.12.40 --- examples/pom.xml | 6 +++++- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index bb4a1f63a3..87d540deb9 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.40-SNAPSHOT + 2.12.40 jar Strata-Examples Example code to demonstrate use of Strata @@ -272,4 +272,8 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> + + + v2.12.40 + diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index dae20a84b1..f7ce7775ef 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.40-SNAPSHOT + 2.12.40 .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index e46b488b0e..d77eb34a10 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.40-SNAPSHOT + 2.12.40 .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index d804b2fbf0..d8fb38dde8 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.40-SNAPSHOT + 2.12.40 .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index fc8142897e..9d45160e16 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.40-SNAPSHOT + 2.12.40 .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index b291c36a81..76bde772fc 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.40-SNAPSHOT + 2.12.40 .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 97ca3c9d3b..d5157e8281 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.40-SNAPSHOT + 2.12.40 .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index a20242da6b..158b77a991 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.40-SNAPSHOT + 2.12.40 .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 13467a506b..d05ed5c33e 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.40-SNAPSHOT + 2.12.40 .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 381ff39e20..5fdcef8415 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.40-SNAPSHOT + 2.12.40 pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.40 diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 57f9dd038e..853d4b0abc 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.40-SNAPSHOT + 2.12.40 .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index a7e592b3f9..e83505c59a 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.40-SNAPSHOT + 2.12.40 .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 7b63fa9089..34cf7b7369 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.40-SNAPSHOT + 2.12.40 .. strata-report diff --git a/pom.xml b/pom.xml index 019935a7db..4941cd9f2e 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.40-SNAPSHOT + 2.12.40 pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.40 From 2e724ec9575351324cfd8a03ef77f949569c65d5 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Thu, 11 Jul 2024 10:32:47 +0000 Subject: [PATCH 097/116] [maven-release-plugin] prepare for next development iteration --- examples/pom.xml | 6 +----- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 87d540deb9..5bac8bcc5a 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.40 + 2.12.41-SNAPSHOT jar Strata-Examples Example code to demonstrate use of Strata @@ -272,8 +272,4 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> - - - v2.12.40 - diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index f7ce7775ef..61813d94f4 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.40 + 2.12.41-SNAPSHOT .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index d77eb34a10..f335bbe5d4 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.40 + 2.12.41-SNAPSHOT .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index d8fb38dde8..445f0416da 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.40 + 2.12.41-SNAPSHOT .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 9d45160e16..9454f9446a 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.40 + 2.12.41-SNAPSHOT .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 76bde772fc..2a0f64a368 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.40 + 2.12.41-SNAPSHOT .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index d5157e8281..f3a6813e64 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.40 + 2.12.41-SNAPSHOT .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 158b77a991..046b6d9fbb 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.40 + 2.12.41-SNAPSHOT .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index d05ed5c33e..fb6a9cb7a8 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.40 + 2.12.41-SNAPSHOT .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 5fdcef8415..511bc2a393 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.40 + 2.12.41-SNAPSHOT pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.40 + HEAD diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 853d4b0abc..570e133a16 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.40 + 2.12.41-SNAPSHOT .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index e83505c59a..656b9f8302 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.40 + 2.12.41-SNAPSHOT .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 34cf7b7369..c14191da6d 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.40 + 2.12.41-SNAPSHOT .. strata-report diff --git a/pom.xml b/pom.xml index 4941cd9f2e..d118af1a12 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.40 + 2.12.41-SNAPSHOT pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.40 + HEAD From 3be49e3ed0226e41bcbce74262ac3f0ea43a5d80 Mon Sep 17 00:00:00 2001 From: Alexis Skitini Date: Tue, 16 Jul 2024 18:26:11 +0100 Subject: [PATCH 098/116] Bump Joda-Beans to 2.11.0 (#2658) Co-authored-by: Alexis Skitini --- modules/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pom.xml b/modules/pom.xml index 511bc2a393..cb39e6d626 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -769,7 +769,7 @@ 26.0-jre 1.78 2.2.3 - 2.10.0 + 2.11.0 ${joda-beans.version} 5.10.2 4.9.0 From 925a8521041f0afc00eed454d6b7bd40c7e8a577 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Tue, 16 Jul 2024 17:46:23 +0000 Subject: [PATCH 099/116] [maven-release-plugin] prepare release v2.12.41 --- examples/pom.xml | 6 +++++- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 5bac8bcc5a..f2496631e8 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.41-SNAPSHOT + 2.12.41 jar Strata-Examples Example code to demonstrate use of Strata @@ -272,4 +272,8 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> + + + v2.12.41 + diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index 61813d94f4..db02084c7c 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.41-SNAPSHOT + 2.12.41 .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index f335bbe5d4..e9f2a44cf5 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.41-SNAPSHOT + 2.12.41 .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 445f0416da..1b3497e1a8 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.41-SNAPSHOT + 2.12.41 .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 9454f9446a..1b497e2eab 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.41-SNAPSHOT + 2.12.41 .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 2a0f64a368..ebef401efc 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.41-SNAPSHOT + 2.12.41 .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index f3a6813e64..5c005c690f 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.41-SNAPSHOT + 2.12.41 .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 046b6d9fbb..331dbae291 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.41-SNAPSHOT + 2.12.41 .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index fb6a9cb7a8..7495bb2fb5 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.41-SNAPSHOT + 2.12.41 .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index cb39e6d626..31df2ef80e 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.41-SNAPSHOT + 2.12.41 pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.41 diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 570e133a16..1b884f1405 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.41-SNAPSHOT + 2.12.41 .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 656b9f8302..4d41a3bfdf 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.41-SNAPSHOT + 2.12.41 .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index c14191da6d..0f138e4c6d 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.41-SNAPSHOT + 2.12.41 .. strata-report diff --git a/pom.xml b/pom.xml index d118af1a12..23ea40a171 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.41-SNAPSHOT + 2.12.41 pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.41 From 1039f5a8d5b7536abea634b2c32997a2eadc1fe1 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Tue, 16 Jul 2024 17:46:25 +0000 Subject: [PATCH 100/116] [maven-release-plugin] prepare for next development iteration --- examples/pom.xml | 6 +----- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index f2496631e8..59152ac8ad 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.41 + 2.12.42-SNAPSHOT jar Strata-Examples Example code to demonstrate use of Strata @@ -272,8 +272,4 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> - - - v2.12.41 - diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index db02084c7c..c46914670c 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.41 + 2.12.42-SNAPSHOT .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index e9f2a44cf5..32a5769e52 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.41 + 2.12.42-SNAPSHOT .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 1b3497e1a8..3bb57365d7 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.41 + 2.12.42-SNAPSHOT .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 1b497e2eab..bcb8272ab2 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.41 + 2.12.42-SNAPSHOT .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index ebef401efc..9f26593859 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.41 + 2.12.42-SNAPSHOT .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 5c005c690f..ef3910df18 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.41 + 2.12.42-SNAPSHOT .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 331dbae291..a98acd197f 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.41 + 2.12.42-SNAPSHOT .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 7495bb2fb5..069169a041 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.41 + 2.12.42-SNAPSHOT .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 31df2ef80e..7641c4d6eb 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.41 + 2.12.42-SNAPSHOT pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.41 + HEAD diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 1b884f1405..f9e746e558 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.41 + 2.12.42-SNAPSHOT .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 4d41a3bfdf..43d4967edd 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.41 + 2.12.42-SNAPSHOT .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 0f138e4c6d..5f9129e618 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.41 + 2.12.42-SNAPSHOT .. strata-report diff --git a/pom.xml b/pom.xml index 23ea40a171..924db250d2 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.41 + 2.12.42-SNAPSHOT pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.41 + HEAD From 2db9da18eb37c26128f4e5617f0aa5e040229dfb Mon Sep 17 00:00:00 2001 From: James White <118170713+James-OpenGamma@users.noreply.github.com> Date: Mon, 5 Aug 2024 16:56:31 +0100 Subject: [PATCH 101/116] Ensure toOnly collector supplier returns a new instance (#2659) Co-authored-by: James White --- .../src/main/java/com/opengamma/strata/collect/Guavate.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/collect/src/main/java/com/opengamma/strata/collect/Guavate.java b/modules/collect/src/main/java/com/opengamma/strata/collect/Guavate.java index 95bf48d9ee..cf18c1f704 100644 --- a/modules/collect/src/main/java/com/opengamma/strata/collect/Guavate.java +++ b/modules/collect/src/main/java/com/opengamma/strata/collect/Guavate.java @@ -829,7 +829,7 @@ static class OnlyCollector implements Collector, Optional @Override public Supplier> supplier() { - return () -> this; + return OnlyCollector::new; } @Override From 3ad86e0b4a54475d1b0a5b4f8aa44294708a9971 Mon Sep 17 00:00:00 2001 From: Stephen Colebourne Date: Mon, 12 Aug 2024 14:34:47 +0100 Subject: [PATCH 102/116] PROD-40335: Update Mergify (#2660) * Remove ogbot --- .github/dependabot.yml | 1 + .github/mergify.yml | 7 +++++-- .github/workflows/ogbot.yml | 14 -------------- 3 files changed, 6 insertions(+), 16 deletions(-) delete mode 100644 .github/workflows/ogbot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 6248ec7410..337d92e55c 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,6 +6,7 @@ updates: interval: weekly time: "02:30" open-pull-requests-limit: 20 + rebase-strategy: "disabled" reviewers: - jodastephen assignees: diff --git a/.github/mergify.yml b/.github/mergify.yml index e4a474701a..aa8e092142 100644 --- a/.github/mergify.yml +++ b/.github/mergify.yml @@ -1,11 +1,13 @@ queue_rules: - name: default - conditions: + merge_conditions: - "label=auto-merge" - "check-success=build" + merge_method: squash pull_request_rules: - name: Auto-Merge + description: Merge branch once conditions pass conditions: - "label=auto-merge" - "status-success=build" @@ -14,9 +16,10 @@ pull_request_rules: - "title~=^((?!(wip|WIP)).)*$" actions: queue: - method: squash name: default + - name: Delete-Branch + description: Delete branch once PR merged conditions: - "merged" actions: diff --git a/.github/workflows/ogbot.yml b/.github/workflows/ogbot.yml deleted file mode 100644 index 18aa9333ca..0000000000 --- a/.github/workflows/ogbot.yml +++ /dev/null @@ -1,14 +0,0 @@ -name: ogbot - -on: - pull_request: - types: [opened, reopened, edited, synchronize] - -jobs: - pr: - runs-on: ubuntu-latest - permissions: write-all - steps: - - uses: OpenGamma/OGBot@main - with: - token: ${{ secrets.GITHUB_TOKEN }} From c7dd74505165ca4417495c277a3f1ef79b03fe54 Mon Sep 17 00:00:00 2001 From: Anand <49917470+anand-uk@users.noreply.github.com> Date: Tue, 27 Aug 2024 17:03:14 +0100 Subject: [PATCH 103/116] Enhance argument capture in failure items (#2667) * Enhance argument capture in failure items * fix checkstyle * tests --- .../strata/collect/result/Failure.java | 3 +- .../strata/collect/result/FailureItem.java | 10 ++-- .../strata/collect/result/Result.java | 3 +- .../collect/result/FailureItemTest.java | 46 +++++++++++++++++++ 4 files changed, 54 insertions(+), 8 deletions(-) diff --git a/modules/collect/src/main/java/com/opengamma/strata/collect/result/Failure.java b/modules/collect/src/main/java/com/opengamma/strata/collect/result/Failure.java index f4daed7501..a7762b21cc 100644 --- a/modules/collect/src/main/java/com/opengamma/strata/collect/result/Failure.java +++ b/modules/collect/src/main/java/com/opengamma/strata/collect/result/Failure.java @@ -83,8 +83,7 @@ public final class Failure * @return the failure */ public static Failure of(FailureReason reason, String message, Object... messageArgs) { - String msg = Messages.format(message, messageArgs); - return Failure.of(FailureItem.ofAutoStackTrace(reason, msg, 1)); + return Failure.of(FailureItem.ofAutoStackTrace(1, reason, message, messageArgs)); } /** diff --git a/modules/collect/src/main/java/com/opengamma/strata/collect/result/FailureItem.java b/modules/collect/src/main/java/com/opengamma/strata/collect/result/FailureItem.java index 07e4fb0a78..34e595b4f6 100644 --- a/modules/collect/src/main/java/com/opengamma/strata/collect/result/FailureItem.java +++ b/modules/collect/src/main/java/com/opengamma/strata/collect/result/FailureItem.java @@ -121,16 +121,18 @@ public static FailureItem of(FailureReason reason, String message, Object... mes *

    * The failure will still have a stack trace, but the cause type will not be present. * + * @param skipFrames the number of caller frames to skip, not including this one * @param reason the reason * @param message the failure message, not empty - * @param skipFrames the number of caller frames to skip, not including this one + * @param messageArgs the arguments for the message * @return the failure */ - static FailureItem ofAutoStackTrace(FailureReason reason, String message, int skipFrames) { + static FailureItem ofAutoStackTrace(int skipFrames, FailureReason reason, String message, Object... messageArgs) { ArgChecker.notNull(reason, "reason"); ArgChecker.notEmpty(message, "message"); - String stackTrace = localGetStackTraceAsString(message, skipFrames); - return new FailureItem(reason, message, ImmutableMap.of(), stackTrace, null); + Pair> messageArgPair = Messages.formatWithAttributes(message, messageArgs); + String stackTrace = localGetStackTraceAsString(messageArgPair.getFirst(), skipFrames); + return new FailureItem(reason, messageArgPair.getFirst(), messageArgPair.getSecond(), stackTrace, null); } /** diff --git a/modules/collect/src/main/java/com/opengamma/strata/collect/result/Result.java b/modules/collect/src/main/java/com/opengamma/strata/collect/result/Result.java index 733fc85a28..03492199de 100644 --- a/modules/collect/src/main/java/com/opengamma/strata/collect/result/Result.java +++ b/modules/collect/src/main/java/com/opengamma/strata/collect/result/Result.java @@ -113,8 +113,7 @@ public static Result success(R value) { * @return a failure result */ public static Result failure(FailureReason reason, String message, Object... messageArgs) { - String msg = Messages.format(message, messageArgs); - return new Result<>(Failure.of(FailureItem.ofAutoStackTrace(reason, msg, 1))); + return new Result<>(Failure.of(FailureItem.ofAutoStackTrace(1, reason, message, messageArgs))); } /** diff --git a/modules/collect/src/test/java/com/opengamma/strata/collect/result/FailureItemTest.java b/modules/collect/src/test/java/com/opengamma/strata/collect/result/FailureItemTest.java index e28ea5af65..66e9ea8659 100644 --- a/modules/collect/src/test/java/com/opengamma/strata/collect/result/FailureItemTest.java +++ b/modules/collect/src/test/java/com/opengamma/strata/collect/result/FailureItemTest.java @@ -46,6 +46,52 @@ public void test_of_reasonMessageShortStackTrace() { assertThat(test.toString()).isEqualTo("INVALID: my issue: Short stack trace"); } + //------------------------------------------------------------------------- + @Test + public void test_of_stackTraceErrorMessageWithNamedAttributes() { + FailureItem testItem = FailureItem.ofAutoStackTrace( + 1, + FailureReason.UNSUPPORTED, + "This {value} is unsupported for {name}", + "someValue", + "someName"); + assertThat(testItem.getMessageTemplate()).isEqualTo("This {value} is unsupported for {name}"); + assertThat(testItem.getAttributes()) + .containsEntry("value", "someValue") + .containsEntry("name", "someName"); + assertThat(testItem.getMessage()).isEqualTo("This someValue is unsupported for someName"); + assertThat(testItem.getStackTrace()) + .startsWith("com.opengamma.strata.collect.result.FailureItem: This someValue is unsupported for someName"); + } + + @Test + public void test_of_stackTraceErrorMessageWithUnnamedAttributes() { + FailureItem testItem = FailureItem.ofAutoStackTrace( + 1, + FailureReason.UNSUPPORTED, + "This {} is unsupported for {}", + "someValue", + "someName"); + assertThat(testItem.getMessageTemplate()).isEqualTo("This someValue is unsupported for someName"); + assertThat(testItem.getMessage()).isEqualTo("This someValue is unsupported for someName"); + assertThat(testItem.getAttributes()).isEmpty(); + assertThat(testItem.getStackTrace()) + .startsWith("com.opengamma.strata.collect.result.FailureItem: This someValue is unsupported for someName"); + } + + @Test + public void test_of_stackTraceErrorMessageWithoutAttributes() { + FailureItem testItem = FailureItem.ofAutoStackTrace( + 1, + FailureReason.UNSUPPORTED, + "This value is unsupported for name"); + assertThat(testItem.getMessageTemplate()).isEqualTo("This value is unsupported for name"); + assertThat(testItem.getMessage()).isEqualTo("This value is unsupported for name"); + assertThat(testItem.getAttributes()).isEmpty(); + assertThat(testItem.getStackTrace()) + .startsWith("com.opengamma.strata.collect.result.FailureItem: This value is unsupported for name"); + } + //------------------------------------------------------------------------- @Test public void test_of_reasonException() { From cca359f166c1cc374c40bcb174bbe6940915dd84 Mon Sep 17 00:00:00 2001 From: Michael Rollins Date: Wed, 28 Aug 2024 17:12:28 +0100 Subject: [PATCH 104/116] Making LEG_1_PAYMENT_DATE_FIELD public (#2668) Co-authored-by: Michael Rollins --- .../java/com/opengamma/strata/loader/csv/CsvLoaderColumns.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/loader/src/main/java/com/opengamma/strata/loader/csv/CsvLoaderColumns.java b/modules/loader/src/main/java/com/opengamma/strata/loader/csv/CsvLoaderColumns.java index 0af52db09a..dd5bfc831e 100644 --- a/modules/loader/src/main/java/com/opengamma/strata/loader/csv/CsvLoaderColumns.java +++ b/modules/loader/src/main/java/com/opengamma/strata/loader/csv/CsvLoaderColumns.java @@ -96,7 +96,7 @@ public final class CsvLoaderColumns { /** CSV header. */ public static final String PAYMENT_DATE_FIELD = "Payment Date"; /** CSV header. */ - static final String LEG_1_PAYMENT_DATE_FIELD = "Leg 1 " + PAYMENT_DATE_FIELD; + public static final String LEG_1_PAYMENT_DATE_FIELD = "Leg 1 " + PAYMENT_DATE_FIELD; /** CSV header. */ public static final String LEG_2_PAYMENT_DATE_FIELD = "Leg 2 " + PAYMENT_DATE_FIELD; /** CSV header. */ From d24103f52b2b2319411357200b0fd76872444568 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 14 Oct 2024 08:49:45 +0000 Subject: [PATCH 105/116] Bump org.junit:junit-bom from 5.10.2 to 5.11.2 (#2674) Bumps [org.junit:junit-bom](https://github.com/junit-team/junit5) from 5.10.2 to 5.11.2. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.10.2...r5.11.2) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- modules/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/pom.xml b/modules/pom.xml index 7641c4d6eb..f71ddad74f 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -771,7 +771,7 @@ 2.2.3 2.11.0 ${joda-beans.version} - 5.10.2 + 5.11.2 4.9.0 1.7.36 From cfa248e5da9694018efc957d2de57cb8c6bed547 Mon Sep 17 00:00:00 2001 From: Yuki Iwashita Date: Wed, 16 Oct 2024 09:55:48 +0100 Subject: [PATCH 106/116] Overnight Rate Cap Floor Model (#2677) * overnight cap product * tests * javadoc * line * clean * white spaces * failing test for accrual --- .../opengamma/strata/product/ProductType.java | 7 + .../capfloor/OvernightInArrearsCapFloor.java | 398 ++++++++ .../OvernightInArrearsCapFloorLeg.java | 888 ++++++++++++++++++ .../OvernightInArrearsCapFloorTrade.java | 516 ++++++++++ ...vernightInArrearsCapletFloorletPeriod.java | 2 +- .../ResolvedOvernightInArrearsCapFloor.java | 420 +++++++++ ...ResolvedOvernightInArrearsCapFloorLeg.java | 468 +++++++++ ...solvedOvernightInArrearsCapFloorTrade.java | 449 +++++++++ .../OvernightInArrearsCapFloorLegTest.java | 305 ++++++ .../OvernightInArrearsCapFloorTest.java | 167 ++++ .../OvernightInArrearsCapFloorTradeTest.java | 194 ++++ ...lvedOvernightInArrearsCapFloorLegTest.java | 186 ++++ ...esolvedOvernightInArrearsCapFloorTest.java | 176 ++++ ...edOvernightInArrearsCapFloorTradeTest.java | 80 ++ 14 files changed, 4255 insertions(+), 1 deletion(-) create mode 100644 modules/product/src/main/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapFloor.java create mode 100644 modules/product/src/main/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapFloorLeg.java create mode 100644 modules/product/src/main/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapFloorTrade.java create mode 100644 modules/product/src/main/java/com/opengamma/strata/product/capfloor/ResolvedOvernightInArrearsCapFloor.java create mode 100644 modules/product/src/main/java/com/opengamma/strata/product/capfloor/ResolvedOvernightInArrearsCapFloorLeg.java create mode 100644 modules/product/src/main/java/com/opengamma/strata/product/capfloor/ResolvedOvernightInArrearsCapFloorTrade.java create mode 100644 modules/product/src/test/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapFloorLegTest.java create mode 100644 modules/product/src/test/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapFloorTest.java create mode 100644 modules/product/src/test/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapFloorTradeTest.java create mode 100644 modules/product/src/test/java/com/opengamma/strata/product/capfloor/ResolvedOvernightInArrearsCapFloorLegTest.java create mode 100644 modules/product/src/test/java/com/opengamma/strata/product/capfloor/ResolvedOvernightInArrearsCapFloorTest.java create mode 100644 modules/product/src/test/java/com/opengamma/strata/product/capfloor/ResolvedOvernightInArrearsCapFloorTradeTest.java diff --git a/modules/product/src/main/java/com/opengamma/strata/product/ProductType.java b/modules/product/src/main/java/com/opengamma/strata/product/ProductType.java index 270f7fd3ce..5d37f1aa5d 100644 --- a/modules/product/src/main/java/com/opengamma/strata/product/ProductType.java +++ b/modules/product/src/main/java/com/opengamma/strata/product/ProductType.java @@ -16,6 +16,7 @@ import com.opengamma.strata.product.bond.CapitalIndexedBond; import com.opengamma.strata.product.bond.FixedCouponBond; import com.opengamma.strata.product.capfloor.IborCapFloor; +import com.opengamma.strata.product.capfloor.OvernightInArrearsCapFloor; import com.opengamma.strata.product.cms.Cms; import com.opengamma.strata.product.credit.Cds; import com.opengamma.strata.product.credit.CdsIndex; @@ -110,6 +111,12 @@ public final class ProductType * A {@link IborCapFloor}. */ public static final ProductType IBOR_CAP_FLOOR = ProductType.of("IborCapFloor", "Cap/Floor"); + /** + * A {@link OvernightInArrearsCapFloor}. + */ + public static final ProductType OVERNIGHT_IN_ARREARS_CAP_FLOOR = ProductType.of( + "OvernightInArrearsCapFloor", + "Overnight In Arrears Cap/Floor"); /** * A {@link IborFuture}. */ diff --git a/modules/product/src/main/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapFloor.java b/modules/product/src/main/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapFloor.java new file mode 100644 index 0000000000..e47673bb9d --- /dev/null +++ b/modules/product/src/main/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapFloor.java @@ -0,0 +1,398 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.product.capfloor; + +import java.io.Serializable; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Optional; + +import org.joda.beans.Bean; +import org.joda.beans.BeanBuilder; +import org.joda.beans.ImmutableBean; +import org.joda.beans.JodaBeanUtils; +import org.joda.beans.MetaBean; +import org.joda.beans.MetaProperty; +import org.joda.beans.gen.BeanDefinition; +import org.joda.beans.gen.ImmutableValidator; +import org.joda.beans.gen.PropertyDefinition; +import org.joda.beans.impl.direct.DirectMetaBean; +import org.joda.beans.impl.direct.DirectMetaProperty; +import org.joda.beans.impl.direct.DirectMetaPropertyMap; +import org.joda.beans.impl.direct.DirectPrivateBeanBuilder; + +import com.google.common.collect.ImmutableSet; +import com.opengamma.strata.basics.ReferenceData; +import com.opengamma.strata.basics.Resolvable; +import com.opengamma.strata.basics.currency.Currency; +import com.opengamma.strata.basics.index.Index; +import com.opengamma.strata.collect.ArgChecker; +import com.opengamma.strata.product.Product; +import com.opengamma.strata.product.swap.SwapLeg; + +/** + * An overnight rate in arrears cap/floor product. + *

    + * The overnight rate in arrears cap/floor product consists of two legs, a cap/floor leg and a pay leg. + * The cap/floor leg involves a set of call/put options on successive compounded overnight index rates. + * The pay leg is any swap leg from a standard interest rate swap. + * The pay leg is absent for typical overnight rate in arrears cap/floor products, + * with the premium paid upfront instead, as defined in {@link OvernightInArrearsCapFloorTrade}. + */ +@BeanDefinition(builderScope = "private") +public final class OvernightInArrearsCapFloor + implements Product, Resolvable, ImmutableBean, Serializable { + + /** + * The cap/floor leg of the product. + *

    + * This is associated with periodic payments based on overnight index rate. + * The payments are caplets or floorlets. + */ + @PropertyDefinition(validate = "notNull") + private final OvernightInArrearsCapFloorLeg capFloorLeg; + /** + * The optional pay leg of the product. + *

    + * These periodic payments are not made for typical cap/floor products. + * Instead the premium is paid upfront. + */ + @PropertyDefinition(get = "optional") + private final SwapLeg payLeg; + + //------------------------------------------------------------------------- + /** + * Obtains an instance from a cap/floor leg with no pay leg. + *

    + * The pay leg is absent in the resulting cap/floor. + * + * @param capFloorLeg the cap/floor leg + * @return the cap/floor + */ + public static OvernightInArrearsCapFloor of(OvernightInArrearsCapFloorLeg capFloorLeg) { + return new OvernightInArrearsCapFloor(capFloorLeg, null); + } + + /** + * Obtains an instance from a cap/floor leg and a pay leg. + * + * @param capFloorLeg the cap/floor leg + * @param payLeg the pay leg + * @return the cap/floor + */ + public static OvernightInArrearsCapFloor of(OvernightInArrearsCapFloorLeg capFloorLeg, SwapLeg payLeg) { + return new OvernightInArrearsCapFloor(capFloorLeg, payLeg); + } + + //------------------------------------------------------------------------- + @ImmutableValidator + private void validate() { + if (payLeg != null) { + ArgChecker.isFalse( + payLeg.getPayReceive().equals(capFloorLeg.getPayReceive()), + "Legs must have different Pay/Receive flag, but both were {}", payLeg.getPayReceive()); + } + } + + //------------------------------------------------------------------------- + @Override + public ImmutableSet allPaymentCurrencies() { + if (payLeg == null) { + return ImmutableSet.of(capFloorLeg.getCurrency()); + } + return ImmutableSet.of(capFloorLeg.getCurrency(), payLeg.getCurrency()); + } + + @Override + public ImmutableSet allCurrencies() { + if (payLeg == null) { + return ImmutableSet.of(capFloorLeg.getCurrency()); + } + ImmutableSet.Builder builder = ImmutableSet.builder(); + builder.add(capFloorLeg.getCurrency()); + builder.addAll(payLeg.allCurrencies()); + return builder.build(); + } + + /** + * Returns the set of indices referred to by the cap/floor. + *

    + * A cap/floor will typically refer to one index, such as 'GBP-SONIA'. + * Calling this method will return the complete list of indices. + * + * @return the set of indices referred to by this cap/floor + */ + public ImmutableSet allIndices() { + ImmutableSet.Builder builder = ImmutableSet.builder(); + builder.add(capFloorLeg.getCalculation().getIndex()); + if (payLeg != null) { + payLeg.collectIndices(builder); + } + return builder.build(); + } + + //------------------------------------------------------------------------- + @Override + public ResolvedOvernightInArrearsCapFloor resolve(ReferenceData refData) { + if (payLeg == null) { + return ResolvedOvernightInArrearsCapFloor.of(capFloorLeg.resolve(refData)); + } + return ResolvedOvernightInArrearsCapFloor.of(capFloorLeg.resolve(refData), payLeg.resolve(refData)); + } + + //------------------------- AUTOGENERATED START ------------------------- + /** + * The meta-bean for {@code OvernightInArrearsCapFloor}. + * @return the meta-bean, not null + */ + public static OvernightInArrearsCapFloor.Meta meta() { + return OvernightInArrearsCapFloor.Meta.INSTANCE; + } + + static { + MetaBean.register(OvernightInArrearsCapFloor.Meta.INSTANCE); + } + + /** + * The serialization version id. + */ + private static final long serialVersionUID = 1L; + + private OvernightInArrearsCapFloor( + OvernightInArrearsCapFloorLeg capFloorLeg, + SwapLeg payLeg) { + JodaBeanUtils.notNull(capFloorLeg, "capFloorLeg"); + this.capFloorLeg = capFloorLeg; + this.payLeg = payLeg; + validate(); + } + + @Override + public OvernightInArrearsCapFloor.Meta metaBean() { + return OvernightInArrearsCapFloor.Meta.INSTANCE; + } + + //----------------------------------------------------------------------- + /** + * Gets the cap/floor leg of the product. + *

    + * This is associated with periodic payments based on overnight index rate. + * The payments are caplets or floorlets. + * @return the value of the property, not null + */ + public OvernightInArrearsCapFloorLeg getCapFloorLeg() { + return capFloorLeg; + } + + //----------------------------------------------------------------------- + /** + * Gets the optional pay leg of the product. + *

    + * These periodic payments are not made for typical cap/floor products. + * Instead the premium is paid upfront. + * @return the optional value of the property, not null + */ + public Optional getPayLeg() { + return Optional.ofNullable(payLeg); + } + + //----------------------------------------------------------------------- + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && obj.getClass() == this.getClass()) { + OvernightInArrearsCapFloor other = (OvernightInArrearsCapFloor) obj; + return JodaBeanUtils.equal(capFloorLeg, other.capFloorLeg) && + JodaBeanUtils.equal(payLeg, other.payLeg); + } + return false; + } + + @Override + public int hashCode() { + int hash = getClass().hashCode(); + hash = hash * 31 + JodaBeanUtils.hashCode(capFloorLeg); + hash = hash * 31 + JodaBeanUtils.hashCode(payLeg); + return hash; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(96); + buf.append("OvernightInArrearsCapFloor{"); + buf.append("capFloorLeg").append('=').append(JodaBeanUtils.toString(capFloorLeg)).append(',').append(' '); + buf.append("payLeg").append('=').append(JodaBeanUtils.toString(payLeg)); + buf.append('}'); + return buf.toString(); + } + + //----------------------------------------------------------------------- + /** + * The meta-bean for {@code OvernightInArrearsCapFloor}. + */ + public static final class Meta extends DirectMetaBean { + /** + * The singleton instance of the meta-bean. + */ + static final Meta INSTANCE = new Meta(); + + /** + * The meta-property for the {@code capFloorLeg} property. + */ + private final MetaProperty capFloorLeg = DirectMetaProperty.ofImmutable( + this, "capFloorLeg", OvernightInArrearsCapFloor.class, OvernightInArrearsCapFloorLeg.class); + /** + * The meta-property for the {@code payLeg} property. + */ + private final MetaProperty payLeg = DirectMetaProperty.ofImmutable( + this, "payLeg", OvernightInArrearsCapFloor.class, SwapLeg.class); + /** + * The meta-properties. + */ + private final Map> metaPropertyMap$ = new DirectMetaPropertyMap( + this, null, + "capFloorLeg", + "payLeg"); + + /** + * Restricted constructor. + */ + private Meta() { + } + + @Override + protected MetaProperty metaPropertyGet(String propertyName) { + switch (propertyName.hashCode()) { + case 2124672084: // capFloorLeg + return capFloorLeg; + case -995239866: // payLeg + return payLeg; + } + return super.metaPropertyGet(propertyName); + } + + @Override + public BeanBuilder builder() { + return new OvernightInArrearsCapFloor.Builder(); + } + + @Override + public Class beanType() { + return OvernightInArrearsCapFloor.class; + } + + @Override + public Map> metaPropertyMap() { + return metaPropertyMap$; + } + + //----------------------------------------------------------------------- + /** + * The meta-property for the {@code capFloorLeg} property. + * @return the meta-property, not null + */ + public MetaProperty capFloorLeg() { + return capFloorLeg; + } + + /** + * The meta-property for the {@code payLeg} property. + * @return the meta-property, not null + */ + public MetaProperty payLeg() { + return payLeg; + } + + //----------------------------------------------------------------------- + @Override + protected Object propertyGet(Bean bean, String propertyName, boolean quiet) { + switch (propertyName.hashCode()) { + case 2124672084: // capFloorLeg + return ((OvernightInArrearsCapFloor) bean).getCapFloorLeg(); + case -995239866: // payLeg + return ((OvernightInArrearsCapFloor) bean).payLeg; + } + return super.propertyGet(bean, propertyName, quiet); + } + + @Override + protected void propertySet(Bean bean, String propertyName, Object newValue, boolean quiet) { + metaProperty(propertyName); + if (quiet) { + return; + } + throw new UnsupportedOperationException("Property cannot be written: " + propertyName); + } + + } + + //----------------------------------------------------------------------- + /** + * The bean-builder for {@code OvernightInArrearsCapFloor}. + */ + private static final class Builder extends DirectPrivateBeanBuilder { + + private OvernightInArrearsCapFloorLeg capFloorLeg; + private SwapLeg payLeg; + + /** + * Restricted constructor. + */ + private Builder() { + } + + //----------------------------------------------------------------------- + @Override + public Object get(String propertyName) { + switch (propertyName.hashCode()) { + case 2124672084: // capFloorLeg + return capFloorLeg; + case -995239866: // payLeg + return payLeg; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + } + + @Override + public Builder set(String propertyName, Object newValue) { + switch (propertyName.hashCode()) { + case 2124672084: // capFloorLeg + this.capFloorLeg = (OvernightInArrearsCapFloorLeg) newValue; + break; + case -995239866: // payLeg + this.payLeg = (SwapLeg) newValue; + break; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + return this; + } + + @Override + public OvernightInArrearsCapFloor build() { + return new OvernightInArrearsCapFloor( + capFloorLeg, + payLeg); + } + + //----------------------------------------------------------------------- + @Override + public String toString() { + StringBuilder buf = new StringBuilder(96); + buf.append("OvernightInArrearsCapFloor.Builder{"); + buf.append("capFloorLeg").append('=').append(JodaBeanUtils.toString(capFloorLeg)).append(',').append(' '); + buf.append("payLeg").append('=').append(JodaBeanUtils.toString(payLeg)); + buf.append('}'); + return buf.toString(); + } + + } + + //-------------------------- AUTOGENERATED END -------------------------- +} diff --git a/modules/product/src/main/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapFloorLeg.java b/modules/product/src/main/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapFloorLeg.java new file mode 100644 index 0000000000..af60401eb9 --- /dev/null +++ b/modules/product/src/main/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapFloorLeg.java @@ -0,0 +1,888 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.product.capfloor; + +import java.io.Serializable; +import java.time.LocalDate; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Optional; + +import org.joda.beans.Bean; +import org.joda.beans.ImmutableBean; +import org.joda.beans.JodaBeanUtils; +import org.joda.beans.MetaBean; +import org.joda.beans.MetaProperty; +import org.joda.beans.gen.BeanDefinition; +import org.joda.beans.gen.ImmutableConstructor; +import org.joda.beans.gen.ImmutableDefaults; +import org.joda.beans.gen.PropertyDefinition; +import org.joda.beans.impl.direct.DirectFieldsBeanBuilder; +import org.joda.beans.impl.direct.DirectMetaBean; +import org.joda.beans.impl.direct.DirectMetaProperty; +import org.joda.beans.impl.direct.DirectMetaPropertyMap; + +import com.google.common.collect.ImmutableList; +import com.opengamma.strata.basics.ReferenceData; +import com.opengamma.strata.basics.Resolvable; +import com.opengamma.strata.basics.currency.Currency; +import com.opengamma.strata.basics.date.AdjustableDate; +import com.opengamma.strata.basics.date.DateAdjuster; +import com.opengamma.strata.basics.date.DaysAdjustment; +import com.opengamma.strata.basics.index.OvernightIndex; +import com.opengamma.strata.basics.schedule.PeriodicSchedule; +import com.opengamma.strata.basics.schedule.Schedule; +import com.opengamma.strata.basics.schedule.SchedulePeriod; +import com.opengamma.strata.basics.schedule.StubConvention; +import com.opengamma.strata.basics.value.ValueSchedule; +import com.opengamma.strata.collect.ArgChecker; +import com.opengamma.strata.collect.array.DoubleArray; +import com.opengamma.strata.product.common.PayReceive; +import com.opengamma.strata.product.rate.OvernightCompoundedRateComputation; +import com.opengamma.strata.product.swap.OvernightAccrualMethod; +import com.opengamma.strata.product.swap.OvernightRateCalculation; +import com.opengamma.strata.product.swap.RateAccrualPeriod; + +/** + * An overnight rate in arrears cap/floor leg of a cap/floor product. + *

    + * This defines a single cap/floor leg for an overnight rate in arrears cap/floor product. + * The cap/floor instruments are defined as a set of call/put options on successive compounded overnight index rates. + *

    + * The periodic payments in the resolved leg are caplets or floorlets depending on the data in this leg. + * The {@code capSchedule} field is used to represent strike values of individual caplets, + * whereas {@code floorSchedule} is used to represent strike values of individual floorlets. + * Either {@code capSchedule} or {@code floorSchedule} must be present, and not both. + */ +@BeanDefinition +public final class OvernightInArrearsCapFloorLeg + implements Resolvable, ImmutableBean, Serializable { + + /** + * Whether the leg is pay or receive. + *

    + * A value of 'Pay' implies that the resulting amount is paid to the counterparty. + * A value of 'Receive' implies that the resulting amount is received from the counterparty. + */ + @PropertyDefinition(validate = "notNull") + private final PayReceive payReceive; + /** + * The periodic payment schedule. + *

    + * This is used to define the periodic payment periods. + * These are used directly or indirectly to determine other dates in the leg. + */ + @PropertyDefinition(validate = "notNull") + private final PeriodicSchedule paymentSchedule; + /** + * The offset of payment from the base calculation period date, defaulted to 'None'. + *

    + * The offset is applied to the adjusted end date of each payment period. + * Offset can be based on calendar days or business days. + */ + @PropertyDefinition(validate = "notNull") + private final DaysAdjustment paymentDateOffset; + /** + * The currency of the leg associated with the notional. + *

    + * This is the currency of the leg and the currency that payoff calculation is made in. + * The amounts of the notional are expressed in terms of this currency. + */ + @PropertyDefinition(validate = "notNull") + private final Currency currency; + /** + * The notional amount, must be non-negative. + *

    + * The notional amount applicable during the period. + * The currency of the notional is specified by {@code currency}. + */ + @PropertyDefinition(validate = "notNull") + private final ValueSchedule notional; + /** + * The interest rate accrual calculation. + *

    + * The interest rate accrual is based on overnight index. + * The overnight rate accrual method should be compounded. + */ + @PropertyDefinition(validate = "notNull") + private final OvernightRateCalculation calculation; + /** + * The cap schedule, optional. + *

    + * This defines the strike value of a cap as an initial value and a list of adjustments. + * Thus individual caplets may have different strike values. + * The cap rate is only allowed to change at payment period boundaries. + *

    + * If the product is not a cap, the cap schedule will be absent. + */ + @PropertyDefinition(get = "optional") + private final ValueSchedule capSchedule; + /** + * The floor schedule, optional. + *

    + * This defines the strike value of a floor as an initial value and a list of adjustments. + * Thus individual floorlets may have different strike values. + * The floor rate is only allowed to change at payment period boundaries. + *

    + * If the product is not a floor, the floor schedule will be absent. + */ + @PropertyDefinition(get = "optional") + private final ValueSchedule floorSchedule; + + //------------------------------------------------------------------------- + @ImmutableDefaults + private static void applyDefaults(Builder builder) { + builder.paymentDateOffset(DaysAdjustment.NONE); + } + + @ImmutableConstructor + private OvernightInArrearsCapFloorLeg( + PayReceive payReceive, + PeriodicSchedule paymentSchedule, + DaysAdjustment paymentDateOffset, + Currency currency, + ValueSchedule notional, + OvernightRateCalculation calculation, + ValueSchedule capSchedule, + ValueSchedule floorSchedule) { + + this.payReceive = ArgChecker.notNull(payReceive, "payReceive"); + this.paymentSchedule = ArgChecker.notNull(paymentSchedule, "paymentSchedule"); + this.paymentDateOffset = ArgChecker.notNull(paymentDateOffset, "paymentDateOffset"); + this.currency = currency != null ? currency : calculation.getIndex().getCurrency(); + this.notional = notional; + this.calculation = ArgChecker.notNull(calculation, "calculation"); + this.capSchedule = capSchedule; + this.floorSchedule = floorSchedule; + ArgChecker.isTrue(!this.getPaymentSchedule().getStubConvention().isPresent() || + this.getPaymentSchedule().getStubConvention().get().equals(StubConvention.NONE), "Stub period is not allowed"); + ArgChecker.isFalse(this.getCapSchedule().isPresent() == this.getFloorSchedule().isPresent(), + "One of cap schedule and floor schedule should be empty"); + ArgChecker.isTrue(this.getCalculation().getAccrualMethod().equals(OvernightAccrualMethod.COMPOUNDED), + "Overnight accrual method should be compounded"); + } + + //------------------------------------------------------------------------- + /** + * Gets the accrual start date of the leg. + *

    + * This is the first accrual date in the leg, often known as the effective date. + * + * @return the start date of the leg + */ + public AdjustableDate getStartDate() { + return paymentSchedule.calculatedStartDate(); + } + + /** + * Gets the accrual end date of the leg. + *

    + * This is the last accrual date in the leg, often known as the termination date. + * + * @return the end date of the leg + */ + public AdjustableDate getEndDate() { + return paymentSchedule.calculatedEndDate(); + } + + /** + * Gets the overnight index. + *

    + * The rate to be paid is based on this index + * It will be a well known market index such as 'GBP-SONIA'. + * + * @return the overnight index + */ + public OvernightIndex getIndex() { + return calculation.getIndex(); + } + + //------------------------------------------------------------------------- + @Override + public ResolvedOvernightInArrearsCapFloorLeg resolve(ReferenceData refData) { + Schedule adjustedSchedule = paymentSchedule.createSchedule(refData); + DoubleArray cap = getCapSchedule().isPresent() ? capSchedule.resolveValues(adjustedSchedule) : null; + DoubleArray floor = getFloorSchedule().isPresent() ? floorSchedule.resolveValues(adjustedSchedule) : null; + DoubleArray notionals = notional.resolveValues(adjustedSchedule); + List accrualPeriods = calculation.createAccrualPeriods(adjustedSchedule, adjustedSchedule, refData); + DateAdjuster paymentDateAdjuster = paymentDateOffset.resolve(refData); + ImmutableList.Builder periodsBuild = ImmutableList.builder(); + for (int i = 0; i < adjustedSchedule.size(); i++) { + SchedulePeriod period = adjustedSchedule.getPeriod(i); + LocalDate paymentDate = paymentDateAdjuster.adjust(period.getEndDate()); + double signedNotional = payReceive.normalize(notionals.get(i)); + periodsBuild.add(OvernightInArrearsCapletFloorletPeriod.builder() + .unadjustedStartDate(period.getUnadjustedStartDate()) + .unadjustedEndDate(period.getUnadjustedEndDate()) + .startDate(period.getStartDate()) + .endDate(period.getEndDate()) + .overnightRate((OvernightCompoundedRateComputation) accrualPeriods.get(i).getRateComputation()) // arg checked + .paymentDate(paymentDate) + .notional(signedNotional) + .currency(currency) + .yearFraction(period.yearFraction(calculation.getDayCount(), adjustedSchedule)) + .caplet(cap != null ? cap.get(i) : null) + .floorlet(floor != null ? floor.get(i) : null) + .build()); + } + return ResolvedOvernightInArrearsCapFloorLeg.builder() + .capletFloorletPeriods(periodsBuild.build()) + .payReceive(payReceive) + .build(); + } + + //------------------------- AUTOGENERATED START ------------------------- + /** + * The meta-bean for {@code OvernightInArrearsCapFloorLeg}. + * @return the meta-bean, not null + */ + public static OvernightInArrearsCapFloorLeg.Meta meta() { + return OvernightInArrearsCapFloorLeg.Meta.INSTANCE; + } + + static { + MetaBean.register(OvernightInArrearsCapFloorLeg.Meta.INSTANCE); + } + + /** + * The serialization version id. + */ + private static final long serialVersionUID = 1L; + + /** + * Returns a builder used to create an instance of the bean. + * @return the builder, not null + */ + public static OvernightInArrearsCapFloorLeg.Builder builder() { + return new OvernightInArrearsCapFloorLeg.Builder(); + } + + @Override + public OvernightInArrearsCapFloorLeg.Meta metaBean() { + return OvernightInArrearsCapFloorLeg.Meta.INSTANCE; + } + + //----------------------------------------------------------------------- + /** + * Gets whether the leg is pay or receive. + *

    + * A value of 'Pay' implies that the resulting amount is paid to the counterparty. + * A value of 'Receive' implies that the resulting amount is received from the counterparty. + * @return the value of the property, not null + */ + public PayReceive getPayReceive() { + return payReceive; + } + + //----------------------------------------------------------------------- + /** + * Gets the periodic payment schedule. + *

    + * This is used to define the periodic payment periods. + * These are used directly or indirectly to determine other dates in the leg. + * @return the value of the property, not null + */ + public PeriodicSchedule getPaymentSchedule() { + return paymentSchedule; + } + + //----------------------------------------------------------------------- + /** + * Gets the offset of payment from the base calculation period date, defaulted to 'None'. + *

    + * The offset is applied to the adjusted end date of each payment period. + * Offset can be based on calendar days or business days. + * @return the value of the property, not null + */ + public DaysAdjustment getPaymentDateOffset() { + return paymentDateOffset; + } + + //----------------------------------------------------------------------- + /** + * Gets the currency of the leg associated with the notional. + *

    + * This is the currency of the leg and the currency that payoff calculation is made in. + * The amounts of the notional are expressed in terms of this currency. + * @return the value of the property, not null + */ + public Currency getCurrency() { + return currency; + } + + //----------------------------------------------------------------------- + /** + * Gets the notional amount, must be non-negative. + *

    + * The notional amount applicable during the period. + * The currency of the notional is specified by {@code currency}. + * @return the value of the property, not null + */ + public ValueSchedule getNotional() { + return notional; + } + + //----------------------------------------------------------------------- + /** + * Gets the interest rate accrual calculation. + *

    + * The interest rate accrual is based on overnight index. + * The overnight rate accrual method should be compounded. + * @return the value of the property, not null + */ + public OvernightRateCalculation getCalculation() { + return calculation; + } + + //----------------------------------------------------------------------- + /** + * Gets the cap schedule, optional. + *

    + * This defines the strike value of a cap as an initial value and a list of adjustments. + * Thus individual caplets may have different strike values. + * The cap rate is only allowed to change at payment period boundaries. + *

    + * If the product is not a cap, the cap schedule will be absent. + * @return the optional value of the property, not null + */ + public Optional getCapSchedule() { + return Optional.ofNullable(capSchedule); + } + + //----------------------------------------------------------------------- + /** + * Gets the floor schedule, optional. + *

    + * This defines the strike value of a floor as an initial value and a list of adjustments. + * Thus individual floorlets may have different strike values. + * The floor rate is only allowed to change at payment period boundaries. + *

    + * If the product is not a floor, the floor schedule will be absent. + * @return the optional value of the property, not null + */ + public Optional getFloorSchedule() { + return Optional.ofNullable(floorSchedule); + } + + //----------------------------------------------------------------------- + /** + * Returns a builder that allows this bean to be mutated. + * @return the mutable builder, not null + */ + public Builder toBuilder() { + return new Builder(this); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && obj.getClass() == this.getClass()) { + OvernightInArrearsCapFloorLeg other = (OvernightInArrearsCapFloorLeg) obj; + return JodaBeanUtils.equal(payReceive, other.payReceive) && + JodaBeanUtils.equal(paymentSchedule, other.paymentSchedule) && + JodaBeanUtils.equal(paymentDateOffset, other.paymentDateOffset) && + JodaBeanUtils.equal(currency, other.currency) && + JodaBeanUtils.equal(notional, other.notional) && + JodaBeanUtils.equal(calculation, other.calculation) && + JodaBeanUtils.equal(capSchedule, other.capSchedule) && + JodaBeanUtils.equal(floorSchedule, other.floorSchedule); + } + return false; + } + + @Override + public int hashCode() { + int hash = getClass().hashCode(); + hash = hash * 31 + JodaBeanUtils.hashCode(payReceive); + hash = hash * 31 + JodaBeanUtils.hashCode(paymentSchedule); + hash = hash * 31 + JodaBeanUtils.hashCode(paymentDateOffset); + hash = hash * 31 + JodaBeanUtils.hashCode(currency); + hash = hash * 31 + JodaBeanUtils.hashCode(notional); + hash = hash * 31 + JodaBeanUtils.hashCode(calculation); + hash = hash * 31 + JodaBeanUtils.hashCode(capSchedule); + hash = hash * 31 + JodaBeanUtils.hashCode(floorSchedule); + return hash; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(288); + buf.append("OvernightInArrearsCapFloorLeg{"); + buf.append("payReceive").append('=').append(JodaBeanUtils.toString(payReceive)).append(',').append(' '); + buf.append("paymentSchedule").append('=').append(JodaBeanUtils.toString(paymentSchedule)).append(',').append(' '); + buf.append("paymentDateOffset").append('=').append(JodaBeanUtils.toString(paymentDateOffset)).append(',').append(' '); + buf.append("currency").append('=').append(JodaBeanUtils.toString(currency)).append(',').append(' '); + buf.append("notional").append('=').append(JodaBeanUtils.toString(notional)).append(',').append(' '); + buf.append("calculation").append('=').append(JodaBeanUtils.toString(calculation)).append(',').append(' '); + buf.append("capSchedule").append('=').append(JodaBeanUtils.toString(capSchedule)).append(',').append(' '); + buf.append("floorSchedule").append('=').append(JodaBeanUtils.toString(floorSchedule)); + buf.append('}'); + return buf.toString(); + } + + //----------------------------------------------------------------------- + /** + * The meta-bean for {@code OvernightInArrearsCapFloorLeg}. + */ + public static final class Meta extends DirectMetaBean { + /** + * The singleton instance of the meta-bean. + */ + static final Meta INSTANCE = new Meta(); + + /** + * The meta-property for the {@code payReceive} property. + */ + private final MetaProperty payReceive = DirectMetaProperty.ofImmutable( + this, "payReceive", OvernightInArrearsCapFloorLeg.class, PayReceive.class); + /** + * The meta-property for the {@code paymentSchedule} property. + */ + private final MetaProperty paymentSchedule = DirectMetaProperty.ofImmutable( + this, "paymentSchedule", OvernightInArrearsCapFloorLeg.class, PeriodicSchedule.class); + /** + * The meta-property for the {@code paymentDateOffset} property. + */ + private final MetaProperty paymentDateOffset = DirectMetaProperty.ofImmutable( + this, "paymentDateOffset", OvernightInArrearsCapFloorLeg.class, DaysAdjustment.class); + /** + * The meta-property for the {@code currency} property. + */ + private final MetaProperty currency = DirectMetaProperty.ofImmutable( + this, "currency", OvernightInArrearsCapFloorLeg.class, Currency.class); + /** + * The meta-property for the {@code notional} property. + */ + private final MetaProperty notional = DirectMetaProperty.ofImmutable( + this, "notional", OvernightInArrearsCapFloorLeg.class, ValueSchedule.class); + /** + * The meta-property for the {@code calculation} property. + */ + private final MetaProperty calculation = DirectMetaProperty.ofImmutable( + this, "calculation", OvernightInArrearsCapFloorLeg.class, OvernightRateCalculation.class); + /** + * The meta-property for the {@code capSchedule} property. + */ + private final MetaProperty capSchedule = DirectMetaProperty.ofImmutable( + this, "capSchedule", OvernightInArrearsCapFloorLeg.class, ValueSchedule.class); + /** + * The meta-property for the {@code floorSchedule} property. + */ + private final MetaProperty floorSchedule = DirectMetaProperty.ofImmutable( + this, "floorSchedule", OvernightInArrearsCapFloorLeg.class, ValueSchedule.class); + /** + * The meta-properties. + */ + private final Map> metaPropertyMap$ = new DirectMetaPropertyMap( + this, null, + "payReceive", + "paymentSchedule", + "paymentDateOffset", + "currency", + "notional", + "calculation", + "capSchedule", + "floorSchedule"); + + /** + * Restricted constructor. + */ + private Meta() { + } + + @Override + protected MetaProperty metaPropertyGet(String propertyName) { + switch (propertyName.hashCode()) { + case -885469925: // payReceive + return payReceive; + case -1499086147: // paymentSchedule + return paymentSchedule; + case -716438393: // paymentDateOffset + return paymentDateOffset; + case 575402001: // currency + return currency; + case 1585636160: // notional + return notional; + case -934682935: // calculation + return calculation; + case -596212599: // capSchedule + return capSchedule; + case -1562227005: // floorSchedule + return floorSchedule; + } + return super.metaPropertyGet(propertyName); + } + + @Override + public OvernightInArrearsCapFloorLeg.Builder builder() { + return new OvernightInArrearsCapFloorLeg.Builder(); + } + + @Override + public Class beanType() { + return OvernightInArrearsCapFloorLeg.class; + } + + @Override + public Map> metaPropertyMap() { + return metaPropertyMap$; + } + + //----------------------------------------------------------------------- + /** + * The meta-property for the {@code payReceive} property. + * @return the meta-property, not null + */ + public MetaProperty payReceive() { + return payReceive; + } + + /** + * The meta-property for the {@code paymentSchedule} property. + * @return the meta-property, not null + */ + public MetaProperty paymentSchedule() { + return paymentSchedule; + } + + /** + * The meta-property for the {@code paymentDateOffset} property. + * @return the meta-property, not null + */ + public MetaProperty paymentDateOffset() { + return paymentDateOffset; + } + + /** + * The meta-property for the {@code currency} property. + * @return the meta-property, not null + */ + public MetaProperty currency() { + return currency; + } + + /** + * The meta-property for the {@code notional} property. + * @return the meta-property, not null + */ + public MetaProperty notional() { + return notional; + } + + /** + * The meta-property for the {@code calculation} property. + * @return the meta-property, not null + */ + public MetaProperty calculation() { + return calculation; + } + + /** + * The meta-property for the {@code capSchedule} property. + * @return the meta-property, not null + */ + public MetaProperty capSchedule() { + return capSchedule; + } + + /** + * The meta-property for the {@code floorSchedule} property. + * @return the meta-property, not null + */ + public MetaProperty floorSchedule() { + return floorSchedule; + } + + //----------------------------------------------------------------------- + @Override + protected Object propertyGet(Bean bean, String propertyName, boolean quiet) { + switch (propertyName.hashCode()) { + case -885469925: // payReceive + return ((OvernightInArrearsCapFloorLeg) bean).getPayReceive(); + case -1499086147: // paymentSchedule + return ((OvernightInArrearsCapFloorLeg) bean).getPaymentSchedule(); + case -716438393: // paymentDateOffset + return ((OvernightInArrearsCapFloorLeg) bean).getPaymentDateOffset(); + case 575402001: // currency + return ((OvernightInArrearsCapFloorLeg) bean).getCurrency(); + case 1585636160: // notional + return ((OvernightInArrearsCapFloorLeg) bean).getNotional(); + case -934682935: // calculation + return ((OvernightInArrearsCapFloorLeg) bean).getCalculation(); + case -596212599: // capSchedule + return ((OvernightInArrearsCapFloorLeg) bean).capSchedule; + case -1562227005: // floorSchedule + return ((OvernightInArrearsCapFloorLeg) bean).floorSchedule; + } + return super.propertyGet(bean, propertyName, quiet); + } + + @Override + protected void propertySet(Bean bean, String propertyName, Object newValue, boolean quiet) { + metaProperty(propertyName); + if (quiet) { + return; + } + throw new UnsupportedOperationException("Property cannot be written: " + propertyName); + } + + } + + //----------------------------------------------------------------------- + /** + * The bean-builder for {@code OvernightInArrearsCapFloorLeg}. + */ + public static final class Builder extends DirectFieldsBeanBuilder { + + private PayReceive payReceive; + private PeriodicSchedule paymentSchedule; + private DaysAdjustment paymentDateOffset; + private Currency currency; + private ValueSchedule notional; + private OvernightRateCalculation calculation; + private ValueSchedule capSchedule; + private ValueSchedule floorSchedule; + + /** + * Restricted constructor. + */ + private Builder() { + applyDefaults(this); + } + + /** + * Restricted copy constructor. + * @param beanToCopy the bean to copy from, not null + */ + private Builder(OvernightInArrearsCapFloorLeg beanToCopy) { + this.payReceive = beanToCopy.getPayReceive(); + this.paymentSchedule = beanToCopy.getPaymentSchedule(); + this.paymentDateOffset = beanToCopy.getPaymentDateOffset(); + this.currency = beanToCopy.getCurrency(); + this.notional = beanToCopy.getNotional(); + this.calculation = beanToCopy.getCalculation(); + this.capSchedule = beanToCopy.capSchedule; + this.floorSchedule = beanToCopy.floorSchedule; + } + + //----------------------------------------------------------------------- + @Override + public Object get(String propertyName) { + switch (propertyName.hashCode()) { + case -885469925: // payReceive + return payReceive; + case -1499086147: // paymentSchedule + return paymentSchedule; + case -716438393: // paymentDateOffset + return paymentDateOffset; + case 575402001: // currency + return currency; + case 1585636160: // notional + return notional; + case -934682935: // calculation + return calculation; + case -596212599: // capSchedule + return capSchedule; + case -1562227005: // floorSchedule + return floorSchedule; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + } + + @Override + public Builder set(String propertyName, Object newValue) { + switch (propertyName.hashCode()) { + case -885469925: // payReceive + this.payReceive = (PayReceive) newValue; + break; + case -1499086147: // paymentSchedule + this.paymentSchedule = (PeriodicSchedule) newValue; + break; + case -716438393: // paymentDateOffset + this.paymentDateOffset = (DaysAdjustment) newValue; + break; + case 575402001: // currency + this.currency = (Currency) newValue; + break; + case 1585636160: // notional + this.notional = (ValueSchedule) newValue; + break; + case -934682935: // calculation + this.calculation = (OvernightRateCalculation) newValue; + break; + case -596212599: // capSchedule + this.capSchedule = (ValueSchedule) newValue; + break; + case -1562227005: // floorSchedule + this.floorSchedule = (ValueSchedule) newValue; + break; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + return this; + } + + @Override + public Builder set(MetaProperty property, Object value) { + super.set(property, value); + return this; + } + + @Override + public OvernightInArrearsCapFloorLeg build() { + return new OvernightInArrearsCapFloorLeg( + payReceive, + paymentSchedule, + paymentDateOffset, + currency, + notional, + calculation, + capSchedule, + floorSchedule); + } + + //----------------------------------------------------------------------- + /** + * Sets whether the leg is pay or receive. + *

    + * A value of 'Pay' implies that the resulting amount is paid to the counterparty. + * A value of 'Receive' implies that the resulting amount is received from the counterparty. + * @param payReceive the new value, not null + * @return this, for chaining, not null + */ + public Builder payReceive(PayReceive payReceive) { + JodaBeanUtils.notNull(payReceive, "payReceive"); + this.payReceive = payReceive; + return this; + } + + /** + * Sets the periodic payment schedule. + *

    + * This is used to define the periodic payment periods. + * These are used directly or indirectly to determine other dates in the leg. + * @param paymentSchedule the new value, not null + * @return this, for chaining, not null + */ + public Builder paymentSchedule(PeriodicSchedule paymentSchedule) { + JodaBeanUtils.notNull(paymentSchedule, "paymentSchedule"); + this.paymentSchedule = paymentSchedule; + return this; + } + + /** + * Sets the offset of payment from the base calculation period date, defaulted to 'None'. + *

    + * The offset is applied to the adjusted end date of each payment period. + * Offset can be based on calendar days or business days. + * @param paymentDateOffset the new value, not null + * @return this, for chaining, not null + */ + public Builder paymentDateOffset(DaysAdjustment paymentDateOffset) { + JodaBeanUtils.notNull(paymentDateOffset, "paymentDateOffset"); + this.paymentDateOffset = paymentDateOffset; + return this; + } + + /** + * Sets the currency of the leg associated with the notional. + *

    + * This is the currency of the leg and the currency that payoff calculation is made in. + * The amounts of the notional are expressed in terms of this currency. + * @param currency the new value, not null + * @return this, for chaining, not null + */ + public Builder currency(Currency currency) { + JodaBeanUtils.notNull(currency, "currency"); + this.currency = currency; + return this; + } + + /** + * Sets the notional amount, must be non-negative. + *

    + * The notional amount applicable during the period. + * The currency of the notional is specified by {@code currency}. + * @param notional the new value, not null + * @return this, for chaining, not null + */ + public Builder notional(ValueSchedule notional) { + JodaBeanUtils.notNull(notional, "notional"); + this.notional = notional; + return this; + } + + /** + * Sets the interest rate accrual calculation. + *

    + * The interest rate accrual is based on overnight index. + * The overnight rate accrual method should be compounded. + * @param calculation the new value, not null + * @return this, for chaining, not null + */ + public Builder calculation(OvernightRateCalculation calculation) { + JodaBeanUtils.notNull(calculation, "calculation"); + this.calculation = calculation; + return this; + } + + /** + * Sets the cap schedule, optional. + *

    + * This defines the strike value of a cap as an initial value and a list of adjustments. + * Thus individual caplets may have different strike values. + * The cap rate is only allowed to change at payment period boundaries. + *

    + * If the product is not a cap, the cap schedule will be absent. + * @param capSchedule the new value + * @return this, for chaining, not null + */ + public Builder capSchedule(ValueSchedule capSchedule) { + this.capSchedule = capSchedule; + return this; + } + + /** + * Sets the floor schedule, optional. + *

    + * This defines the strike value of a floor as an initial value and a list of adjustments. + * Thus individual floorlets may have different strike values. + * The floor rate is only allowed to change at payment period boundaries. + *

    + * If the product is not a floor, the floor schedule will be absent. + * @param floorSchedule the new value + * @return this, for chaining, not null + */ + public Builder floorSchedule(ValueSchedule floorSchedule) { + this.floorSchedule = floorSchedule; + return this; + } + + //----------------------------------------------------------------------- + @Override + public String toString() { + StringBuilder buf = new StringBuilder(288); + buf.append("OvernightInArrearsCapFloorLeg.Builder{"); + buf.append("payReceive").append('=').append(JodaBeanUtils.toString(payReceive)).append(',').append(' '); + buf.append("paymentSchedule").append('=').append(JodaBeanUtils.toString(paymentSchedule)).append(',').append(' '); + buf.append("paymentDateOffset").append('=').append(JodaBeanUtils.toString(paymentDateOffset)).append(',').append(' '); + buf.append("currency").append('=').append(JodaBeanUtils.toString(currency)).append(',').append(' '); + buf.append("notional").append('=').append(JodaBeanUtils.toString(notional)).append(',').append(' '); + buf.append("calculation").append('=').append(JodaBeanUtils.toString(calculation)).append(',').append(' '); + buf.append("capSchedule").append('=').append(JodaBeanUtils.toString(capSchedule)).append(',').append(' '); + buf.append("floorSchedule").append('=').append(JodaBeanUtils.toString(floorSchedule)); + buf.append('}'); + return buf.toString(); + } + + } + + //-------------------------- AUTOGENERATED END -------------------------- +} diff --git a/modules/product/src/main/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapFloorTrade.java b/modules/product/src/main/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapFloorTrade.java new file mode 100644 index 0000000000..e9c195814a --- /dev/null +++ b/modules/product/src/main/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapFloorTrade.java @@ -0,0 +1,516 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.product.capfloor; + +import java.io.Serializable; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Optional; + +import org.joda.beans.Bean; +import org.joda.beans.ImmutableBean; +import org.joda.beans.JodaBeanUtils; +import org.joda.beans.MetaBean; +import org.joda.beans.MetaProperty; +import org.joda.beans.gen.BeanDefinition; +import org.joda.beans.gen.ImmutableDefaults; +import org.joda.beans.gen.PropertyDefinition; +import org.joda.beans.impl.direct.DirectFieldsBeanBuilder; +import org.joda.beans.impl.direct.DirectMetaBean; +import org.joda.beans.impl.direct.DirectMetaProperty; +import org.joda.beans.impl.direct.DirectMetaPropertyMap; + +import com.opengamma.strata.basics.ReferenceData; +import com.opengamma.strata.basics.currency.AdjustablePayment; +import com.opengamma.strata.product.PortfolioItemInfo; +import com.opengamma.strata.product.PortfolioItemSummary; +import com.opengamma.strata.product.ProductTrade; +import com.opengamma.strata.product.ProductType; +import com.opengamma.strata.product.ResolvableTrade; +import com.opengamma.strata.product.TradeInfo; +import com.opengamma.strata.product.common.SummarizerUtils; + +/** + * A trade in an overnight rate in arrears cap/floor. + *

    + * An Over-The-Counter (OTC) trade in a {@link OvernightInArrearsCapFloor}. + *

    + * An overnight rate in arrears cap/floor is a financial instrument that provides a set of call/put options on + * successive compounded overnight index rates. + */ +@BeanDefinition +public final class OvernightInArrearsCapFloorTrade + implements ProductTrade, ResolvableTrade, ImmutableBean, Serializable { + + /** + * The additional trade information, defaulted to an empty instance. + *

    + * This allows additional information to be attached to the trade. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final TradeInfo info; + /** + * The cap/floor product that was agreed when the trade occurred. + *

    + * The product captures the contracted financial details of the trade. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final OvernightInArrearsCapFloor product; + /** + * The optional premium of the product. + *

    + * For most cap/floor products, a premium is paid upfront. This typically occurs instead + * of periodic payments based on fixed or rate index rates over the lifetime of the product. + *

    + * The premium sign must be compatible with the product Pay/Receive flag. + */ + @PropertyDefinition(get = "optional") + private final AdjustablePayment premium; + + //------------------------------------------------------------------------- + @ImmutableDefaults + private static void applyDefaults(Builder builder) { + builder.info = TradeInfo.empty(); + } + + //------------------------------------------------------------------------- + @Override + public OvernightInArrearsCapFloorTrade withInfo(PortfolioItemInfo info) { + return new OvernightInArrearsCapFloorTrade(TradeInfo.from(info), product, premium); + } + + //------------------------------------------------------------------------- + @Override + public PortfolioItemSummary summarize() { + // 5Y USD 2mm Rec Compounded USD-SOFR Cap 1% / Pay Premium : 21Jan17-21Jan22 + StringBuilder buf = new StringBuilder(96); + OvernightInArrearsCapFloorLeg mainLeg = product.getCapFloorLeg(); + buf.append( + SummarizerUtils.datePeriod( + mainLeg.getStartDate().getUnadjusted(), + mainLeg.getEndDate().getUnadjusted())); + buf.append(' '); + buf.append(SummarizerUtils.amount(mainLeg.getCurrency(), mainLeg.getNotional().getInitialValue())); + buf.append(' '); + if (mainLeg.getPayReceive().isReceive()) { + buf.append("Rec "); + summarizeMainLeg(mainLeg, buf); + buf.append(getPremium().isPresent() ? + " / Pay Premium" : + (product.getPayLeg().isPresent() ? " / Pay Periodic" : "")); + } else { + buf.append(getPremium().isPresent() ? + "Rec Premium / Pay " : + (product.getPayLeg().isPresent() ? "Rec Periodic / Pay " : "")); + summarizeMainLeg(mainLeg, buf); + } + buf.append(" : "); + buf.append(SummarizerUtils.dateRange(mainLeg.getStartDate().getUnadjusted(), mainLeg.getEndDate().getUnadjusted())); + return SummarizerUtils.summary( + this, + ProductType.OVERNIGHT_IN_ARREARS_CAP_FLOOR, + buf.toString(), + mainLeg.getCurrency()); + } + + // summarize the main leg + private void summarizeMainLeg(OvernightInArrearsCapFloorLeg mainLeg, StringBuilder buf) { + buf.append(mainLeg.getCalculation().getAccrualMethod()); + buf.append(' '); + buf.append(mainLeg.getIndex()); + buf.append(' '); + if (mainLeg.getCapSchedule().isPresent()) { + buf.append("Cap "); + buf.append(SummarizerUtils.percent(mainLeg.getCapSchedule().get().getInitialValue())); + } + if (mainLeg.getFloorSchedule().isPresent()) { + buf.append("Floor "); + buf.append(SummarizerUtils.percent(mainLeg.getFloorSchedule().get().getInitialValue())); + } + } + + @Override + public ResolvedOvernightInArrearsCapFloorTrade resolve(ReferenceData refData) { + return ResolvedOvernightInArrearsCapFloorTrade.builder() + .info(info) + .product(product.resolve(refData)) + .premium(premium != null ? premium.resolve(refData) : null) + .build(); + } + + //------------------------- AUTOGENERATED START ------------------------- + /** + * The meta-bean for {@code OvernightInArrearsCapFloorTrade}. + * @return the meta-bean, not null + */ + public static OvernightInArrearsCapFloorTrade.Meta meta() { + return OvernightInArrearsCapFloorTrade.Meta.INSTANCE; + } + + static { + MetaBean.register(OvernightInArrearsCapFloorTrade.Meta.INSTANCE); + } + + /** + * The serialization version id. + */ + private static final long serialVersionUID = 1L; + + /** + * Returns a builder used to create an instance of the bean. + * @return the builder, not null + */ + public static OvernightInArrearsCapFloorTrade.Builder builder() { + return new OvernightInArrearsCapFloorTrade.Builder(); + } + + private OvernightInArrearsCapFloorTrade( + TradeInfo info, + OvernightInArrearsCapFloor product, + AdjustablePayment premium) { + JodaBeanUtils.notNull(info, "info"); + JodaBeanUtils.notNull(product, "product"); + this.info = info; + this.product = product; + this.premium = premium; + } + + @Override + public OvernightInArrearsCapFloorTrade.Meta metaBean() { + return OvernightInArrearsCapFloorTrade.Meta.INSTANCE; + } + + //----------------------------------------------------------------------- + /** + * Gets the additional trade information, defaulted to an empty instance. + *

    + * This allows additional information to be attached to the trade. + * @return the value of the property, not null + */ + @Override + public TradeInfo getInfo() { + return info; + } + + //----------------------------------------------------------------------- + /** + * Gets the cap/floor product that was agreed when the trade occurred. + *

    + * The product captures the contracted financial details of the trade. + * @return the value of the property, not null + */ + @Override + public OvernightInArrearsCapFloor getProduct() { + return product; + } + + //----------------------------------------------------------------------- + /** + * Gets the optional premium of the product. + *

    + * For most cap/floor products, a premium is paid upfront. This typically occurs instead + * of periodic payments based on fixed or rate index rates over the lifetime of the product. + *

    + * The premium sign must be compatible with the product Pay/Receive flag. + * @return the optional value of the property, not null + */ + public Optional getPremium() { + return Optional.ofNullable(premium); + } + + //----------------------------------------------------------------------- + /** + * Returns a builder that allows this bean to be mutated. + * @return the mutable builder, not null + */ + public Builder toBuilder() { + return new Builder(this); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && obj.getClass() == this.getClass()) { + OvernightInArrearsCapFloorTrade other = (OvernightInArrearsCapFloorTrade) obj; + return JodaBeanUtils.equal(info, other.info) && + JodaBeanUtils.equal(product, other.product) && + JodaBeanUtils.equal(premium, other.premium); + } + return false; + } + + @Override + public int hashCode() { + int hash = getClass().hashCode(); + hash = hash * 31 + JodaBeanUtils.hashCode(info); + hash = hash * 31 + JodaBeanUtils.hashCode(product); + hash = hash * 31 + JodaBeanUtils.hashCode(premium); + return hash; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(128); + buf.append("OvernightInArrearsCapFloorTrade{"); + buf.append("info").append('=').append(JodaBeanUtils.toString(info)).append(',').append(' '); + buf.append("product").append('=').append(JodaBeanUtils.toString(product)).append(',').append(' '); + buf.append("premium").append('=').append(JodaBeanUtils.toString(premium)); + buf.append('}'); + return buf.toString(); + } + + //----------------------------------------------------------------------- + /** + * The meta-bean for {@code OvernightInArrearsCapFloorTrade}. + */ + public static final class Meta extends DirectMetaBean { + /** + * The singleton instance of the meta-bean. + */ + static final Meta INSTANCE = new Meta(); + + /** + * The meta-property for the {@code info} property. + */ + private final MetaProperty info = DirectMetaProperty.ofImmutable( + this, "info", OvernightInArrearsCapFloorTrade.class, TradeInfo.class); + /** + * The meta-property for the {@code product} property. + */ + private final MetaProperty product = DirectMetaProperty.ofImmutable( + this, "product", OvernightInArrearsCapFloorTrade.class, OvernightInArrearsCapFloor.class); + /** + * The meta-property for the {@code premium} property. + */ + private final MetaProperty premium = DirectMetaProperty.ofImmutable( + this, "premium", OvernightInArrearsCapFloorTrade.class, AdjustablePayment.class); + /** + * The meta-properties. + */ + private final Map> metaPropertyMap$ = new DirectMetaPropertyMap( + this, null, + "info", + "product", + "premium"); + + /** + * Restricted constructor. + */ + private Meta() { + } + + @Override + protected MetaProperty metaPropertyGet(String propertyName) { + switch (propertyName.hashCode()) { + case 3237038: // info + return info; + case -309474065: // product + return product; + case -318452137: // premium + return premium; + } + return super.metaPropertyGet(propertyName); + } + + @Override + public OvernightInArrearsCapFloorTrade.Builder builder() { + return new OvernightInArrearsCapFloorTrade.Builder(); + } + + @Override + public Class beanType() { + return OvernightInArrearsCapFloorTrade.class; + } + + @Override + public Map> metaPropertyMap() { + return metaPropertyMap$; + } + + //----------------------------------------------------------------------- + /** + * The meta-property for the {@code info} property. + * @return the meta-property, not null + */ + public MetaProperty info() { + return info; + } + + /** + * The meta-property for the {@code product} property. + * @return the meta-property, not null + */ + public MetaProperty product() { + return product; + } + + /** + * The meta-property for the {@code premium} property. + * @return the meta-property, not null + */ + public MetaProperty premium() { + return premium; + } + + //----------------------------------------------------------------------- + @Override + protected Object propertyGet(Bean bean, String propertyName, boolean quiet) { + switch (propertyName.hashCode()) { + case 3237038: // info + return ((OvernightInArrearsCapFloorTrade) bean).getInfo(); + case -309474065: // product + return ((OvernightInArrearsCapFloorTrade) bean).getProduct(); + case -318452137: // premium + return ((OvernightInArrearsCapFloorTrade) bean).premium; + } + return super.propertyGet(bean, propertyName, quiet); + } + + @Override + protected void propertySet(Bean bean, String propertyName, Object newValue, boolean quiet) { + metaProperty(propertyName); + if (quiet) { + return; + } + throw new UnsupportedOperationException("Property cannot be written: " + propertyName); + } + + } + + //----------------------------------------------------------------------- + /** + * The bean-builder for {@code OvernightInArrearsCapFloorTrade}. + */ + public static final class Builder extends DirectFieldsBeanBuilder { + + private TradeInfo info; + private OvernightInArrearsCapFloor product; + private AdjustablePayment premium; + + /** + * Restricted constructor. + */ + private Builder() { + applyDefaults(this); + } + + /** + * Restricted copy constructor. + * @param beanToCopy the bean to copy from, not null + */ + private Builder(OvernightInArrearsCapFloorTrade beanToCopy) { + this.info = beanToCopy.getInfo(); + this.product = beanToCopy.getProduct(); + this.premium = beanToCopy.premium; + } + + //----------------------------------------------------------------------- + @Override + public Object get(String propertyName) { + switch (propertyName.hashCode()) { + case 3237038: // info + return info; + case -309474065: // product + return product; + case -318452137: // premium + return premium; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + } + + @Override + public Builder set(String propertyName, Object newValue) { + switch (propertyName.hashCode()) { + case 3237038: // info + this.info = (TradeInfo) newValue; + break; + case -309474065: // product + this.product = (OvernightInArrearsCapFloor) newValue; + break; + case -318452137: // premium + this.premium = (AdjustablePayment) newValue; + break; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + return this; + } + + @Override + public Builder set(MetaProperty property, Object value) { + super.set(property, value); + return this; + } + + @Override + public OvernightInArrearsCapFloorTrade build() { + return new OvernightInArrearsCapFloorTrade( + info, + product, + premium); + } + + //----------------------------------------------------------------------- + /** + * Sets the additional trade information, defaulted to an empty instance. + *

    + * This allows additional information to be attached to the trade. + * @param info the new value, not null + * @return this, for chaining, not null + */ + public Builder info(TradeInfo info) { + JodaBeanUtils.notNull(info, "info"); + this.info = info; + return this; + } + + /** + * Sets the cap/floor product that was agreed when the trade occurred. + *

    + * The product captures the contracted financial details of the trade. + * @param product the new value, not null + * @return this, for chaining, not null + */ + public Builder product(OvernightInArrearsCapFloor product) { + JodaBeanUtils.notNull(product, "product"); + this.product = product; + return this; + } + + /** + * Sets the optional premium of the product. + *

    + * For most cap/floor products, a premium is paid upfront. This typically occurs instead + * of periodic payments based on fixed or rate index rates over the lifetime of the product. + *

    + * The premium sign must be compatible with the product Pay/Receive flag. + * @param premium the new value + * @return this, for chaining, not null + */ + public Builder premium(AdjustablePayment premium) { + this.premium = premium; + return this; + } + + //----------------------------------------------------------------------- + @Override + public String toString() { + StringBuilder buf = new StringBuilder(128); + buf.append("OvernightInArrearsCapFloorTrade.Builder{"); + buf.append("info").append('=').append(JodaBeanUtils.toString(info)).append(',').append(' '); + buf.append("product").append('=').append(JodaBeanUtils.toString(product)).append(',').append(' '); + buf.append("premium").append('=').append(JodaBeanUtils.toString(premium)); + buf.append('}'); + return buf.toString(); + } + + } + + //-------------------------- AUTOGENERATED END -------------------------- +} diff --git a/modules/product/src/main/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapletFloorletPeriod.java b/modules/product/src/main/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapletFloorletPeriod.java index 66ed183438..2d33087b80 100644 --- a/modules/product/src/main/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapletFloorletPeriod.java +++ b/modules/product/src/main/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapletFloorletPeriod.java @@ -35,7 +35,7 @@ import com.opengamma.strata.product.rate.OvernightCompoundedRateComputation; /** - * A period over which an caplet/floorlet on overnight composition in-arrears is paid. + * A period over which a caplet/floorlet on overnight composition in-arrears is paid. *

    * The payoff depend on the level of the compounded rate over the period. The option is * of Asian type with the averaging mechanism given by the composition. diff --git a/modules/product/src/main/java/com/opengamma/strata/product/capfloor/ResolvedOvernightInArrearsCapFloor.java b/modules/product/src/main/java/com/opengamma/strata/product/capfloor/ResolvedOvernightInArrearsCapFloor.java new file mode 100644 index 0000000000..314cebe2c8 --- /dev/null +++ b/modules/product/src/main/java/com/opengamma/strata/product/capfloor/ResolvedOvernightInArrearsCapFloor.java @@ -0,0 +1,420 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.product.capfloor; + +import java.io.Serializable; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Optional; + +import org.joda.beans.Bean; +import org.joda.beans.BeanBuilder; +import org.joda.beans.ImmutableBean; +import org.joda.beans.JodaBeanUtils; +import org.joda.beans.MetaBean; +import org.joda.beans.MetaProperty; +import org.joda.beans.gen.BeanDefinition; +import org.joda.beans.gen.ImmutableConstructor; +import org.joda.beans.gen.PropertyDefinition; +import org.joda.beans.impl.direct.DirectMetaBean; +import org.joda.beans.impl.direct.DirectMetaProperty; +import org.joda.beans.impl.direct.DirectMetaPropertyMap; +import org.joda.beans.impl.direct.DirectPrivateBeanBuilder; + +import com.google.common.collect.ImmutableSet; +import com.opengamma.strata.basics.ReferenceData; +import com.opengamma.strata.basics.currency.Currency; +import com.opengamma.strata.basics.index.Index; +import com.opengamma.strata.collect.ArgChecker; +import com.opengamma.strata.product.ResolvedProduct; +import com.opengamma.strata.product.swap.ResolvedSwapLeg; + +/** + * An overnight rate in arrears cap/floor, resolved for pricing. + *

    + * This is the resolved form of {@link OvernightInArrearsCapFloor} and is an input to the pricers. + * Applications will typically create a {@code ResolvedOvernightInArrearsCapFloor} + * from a {@code OvernightInArrearsCapFloor} using {@link OvernightInArrearsCapFloor#resolve(ReferenceData)}. + *

    + * A {@code ResolvedOvernightInArrearsCapFloor} is bound to data that changes over time, such as holiday calendars. + * If the data changes, such as the addition of a new holiday, the resolved form will not be updated. + * Care must be taken when placing the resolved form in a cache or persistence layer. + */ +@BeanDefinition(builderScope = "private") +public final class ResolvedOvernightInArrearsCapFloor + implements ResolvedProduct, ImmutableBean, Serializable { + + /** + * The overnight rate in arrears cap/floor leg of the product. + *

    + * This is associated with periodic payments based on overnight index rate. + * The payments are overnight rate in arrears caplets or floorlets. + */ + @PropertyDefinition(validate = "notNull") + private final ResolvedOvernightInArrearsCapFloorLeg capFloorLeg; + /** + * The optional pay leg of the product. + *

    + * These periodic payments are not made for typical cap/floor products. Instead the premium is paid upfront. + */ + @PropertyDefinition(get = "optional") + private final ResolvedSwapLeg payLeg; + /** + * The set of currencies. + */ + private final transient ImmutableSet currencies; // not a property, derived and cached from input data + /** + * The set of indices. + */ + private final transient ImmutableSet indices; // not a property, derived and cached from input data + + //------------------------------------------------------------------------- + /** + * Obtains an instance from a cap/floor leg with no pay leg. + *

    + * The pay leg is absent in the resulting cap/floor. + * + * @param capFloorLeg the cap/floor leg + * @return the cap/floor + */ + public static ResolvedOvernightInArrearsCapFloor of(ResolvedOvernightInArrearsCapFloorLeg capFloorLeg) { + ArgChecker.notNull(capFloorLeg, "capFloorLeg"); + return new ResolvedOvernightInArrearsCapFloor(capFloorLeg, null); + } + + /** + * Obtains an instance from a cap/floor leg and a pay leg. + * + * @param capFloorLeg the cap/floor leg + * @param payLeg the pay leg + * @return the cap/floor + */ + public static ResolvedOvernightInArrearsCapFloor of( + ResolvedOvernightInArrearsCapFloorLeg capFloorLeg, + ResolvedSwapLeg payLeg) { + + ArgChecker.notNull(capFloorLeg, "capFloorLeg"); + ArgChecker.notNull(payLeg, "payLeg"); + return new ResolvedOvernightInArrearsCapFloor(capFloorLeg, payLeg); + } + + //------------------------------------------------------------------------- + @ImmutableConstructor + private ResolvedOvernightInArrearsCapFloor( + ResolvedOvernightInArrearsCapFloorLeg capFloorLeg, + ResolvedSwapLeg payLeg) { + + JodaBeanUtils.notNull(capFloorLeg, "capFloorLeg"); + if (payLeg != null) { + ArgChecker.isFalse( + payLeg.getPayReceive().equals(capFloorLeg.getPayReceive()), + "Legs must have different Pay/Receive flag, but both were {}", payLeg.getPayReceive()); + } + this.capFloorLeg = capFloorLeg; + this.payLeg = payLeg; + this.currencies = buildCurrencies(capFloorLeg, payLeg); + this.indices = buildIndices(capFloorLeg, payLeg); + } + + // collect the set of currencies + private static ImmutableSet buildCurrencies( + ResolvedOvernightInArrearsCapFloorLeg capFloorLeg, + ResolvedSwapLeg payLeg) { + + ImmutableSet.Builder builder = ImmutableSet.builder(); + builder.add(capFloorLeg.getCurrency()); + if (payLeg != null) { + builder.add(payLeg.getCurrency()); + } + return builder.build(); + } + + // collect the set of indices + private static ImmutableSet buildIndices( + ResolvedOvernightInArrearsCapFloorLeg capFloorLeg, + ResolvedSwapLeg payLeg) { + + ImmutableSet.Builder builder = ImmutableSet.builder(); + builder.add(capFloorLeg.getIndex()); + if (payLeg != null) { + payLeg.collectIndices(builder); + } + return builder.build(); + } + + // ensure standard constructor is invoked + private Object readResolve() { + return new ResolvedOvernightInArrearsCapFloor(capFloorLeg, payLeg); + } + + //------------------------------------------------------------------------- + /** + * Returns the set of payment currencies referred to by the cap/floor. + *

    + * This returns the complete set of payment currencies for the cap/floor. + * This will typically return one currency, but could return two. + * + * @return the set of payment currencies referred to by this swap + */ + public ImmutableSet allPaymentCurrencies() { + return currencies; + } + + /** + * Returns the set of indices referred to by the cap/floor. + *

    + * A cap/floor will typically refer to one index, such as 'GBP-SONIA'. + * Calling this method will return the complete list of indices. + * + * @return the set of indices referred to by this cap/floor + */ + public ImmutableSet allIndices() { + return indices; + } + + //------------------------- AUTOGENERATED START ------------------------- + /** + * The meta-bean for {@code ResolvedOvernightInArrearsCapFloor}. + * @return the meta-bean, not null + */ + public static ResolvedOvernightInArrearsCapFloor.Meta meta() { + return ResolvedOvernightInArrearsCapFloor.Meta.INSTANCE; + } + + static { + MetaBean.register(ResolvedOvernightInArrearsCapFloor.Meta.INSTANCE); + } + + /** + * The serialization version id. + */ + private static final long serialVersionUID = 1L; + + @Override + public ResolvedOvernightInArrearsCapFloor.Meta metaBean() { + return ResolvedOvernightInArrearsCapFloor.Meta.INSTANCE; + } + + //----------------------------------------------------------------------- + /** + * Gets the overnight rate in arrears cap/floor leg of the product. + *

    + * This is associated with periodic payments based on overnight index rate. + * The payments are overnight rate in arrears caplets or floorlets. + * @return the value of the property, not null + */ + public ResolvedOvernightInArrearsCapFloorLeg getCapFloorLeg() { + return capFloorLeg; + } + + //----------------------------------------------------------------------- + /** + * Gets the optional pay leg of the product. + *

    + * These periodic payments are not made for typical cap/floor products. Instead the premium is paid upfront. + * @return the optional value of the property, not null + */ + public Optional getPayLeg() { + return Optional.ofNullable(payLeg); + } + + //----------------------------------------------------------------------- + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && obj.getClass() == this.getClass()) { + ResolvedOvernightInArrearsCapFloor other = (ResolvedOvernightInArrearsCapFloor) obj; + return JodaBeanUtils.equal(capFloorLeg, other.capFloorLeg) && + JodaBeanUtils.equal(payLeg, other.payLeg); + } + return false; + } + + @Override + public int hashCode() { + int hash = getClass().hashCode(); + hash = hash * 31 + JodaBeanUtils.hashCode(capFloorLeg); + hash = hash * 31 + JodaBeanUtils.hashCode(payLeg); + return hash; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(96); + buf.append("ResolvedOvernightInArrearsCapFloor{"); + buf.append("capFloorLeg").append('=').append(JodaBeanUtils.toString(capFloorLeg)).append(',').append(' '); + buf.append("payLeg").append('=').append(JodaBeanUtils.toString(payLeg)); + buf.append('}'); + return buf.toString(); + } + + //----------------------------------------------------------------------- + /** + * The meta-bean for {@code ResolvedOvernightInArrearsCapFloor}. + */ + public static final class Meta extends DirectMetaBean { + /** + * The singleton instance of the meta-bean. + */ + static final Meta INSTANCE = new Meta(); + + /** + * The meta-property for the {@code capFloorLeg} property. + */ + private final MetaProperty capFloorLeg = DirectMetaProperty.ofImmutable( + this, "capFloorLeg", ResolvedOvernightInArrearsCapFloor.class, ResolvedOvernightInArrearsCapFloorLeg.class); + /** + * The meta-property for the {@code payLeg} property. + */ + private final MetaProperty payLeg = DirectMetaProperty.ofImmutable( + this, "payLeg", ResolvedOvernightInArrearsCapFloor.class, ResolvedSwapLeg.class); + /** + * The meta-properties. + */ + private final Map> metaPropertyMap$ = new DirectMetaPropertyMap( + this, null, + "capFloorLeg", + "payLeg"); + + /** + * Restricted constructor. + */ + private Meta() { + } + + @Override + protected MetaProperty metaPropertyGet(String propertyName) { + switch (propertyName.hashCode()) { + case 2124672084: // capFloorLeg + return capFloorLeg; + case -995239866: // payLeg + return payLeg; + } + return super.metaPropertyGet(propertyName); + } + + @Override + public BeanBuilder builder() { + return new ResolvedOvernightInArrearsCapFloor.Builder(); + } + + @Override + public Class beanType() { + return ResolvedOvernightInArrearsCapFloor.class; + } + + @Override + public Map> metaPropertyMap() { + return metaPropertyMap$; + } + + //----------------------------------------------------------------------- + /** + * The meta-property for the {@code capFloorLeg} property. + * @return the meta-property, not null + */ + public MetaProperty capFloorLeg() { + return capFloorLeg; + } + + /** + * The meta-property for the {@code payLeg} property. + * @return the meta-property, not null + */ + public MetaProperty payLeg() { + return payLeg; + } + + //----------------------------------------------------------------------- + @Override + protected Object propertyGet(Bean bean, String propertyName, boolean quiet) { + switch (propertyName.hashCode()) { + case 2124672084: // capFloorLeg + return ((ResolvedOvernightInArrearsCapFloor) bean).getCapFloorLeg(); + case -995239866: // payLeg + return ((ResolvedOvernightInArrearsCapFloor) bean).payLeg; + } + return super.propertyGet(bean, propertyName, quiet); + } + + @Override + protected void propertySet(Bean bean, String propertyName, Object newValue, boolean quiet) { + metaProperty(propertyName); + if (quiet) { + return; + } + throw new UnsupportedOperationException("Property cannot be written: " + propertyName); + } + + } + + //----------------------------------------------------------------------- + /** + * The bean-builder for {@code ResolvedOvernightInArrearsCapFloor}. + */ + private static final class Builder extends DirectPrivateBeanBuilder { + + private ResolvedOvernightInArrearsCapFloorLeg capFloorLeg; + private ResolvedSwapLeg payLeg; + + /** + * Restricted constructor. + */ + private Builder() { + } + + //----------------------------------------------------------------------- + @Override + public Object get(String propertyName) { + switch (propertyName.hashCode()) { + case 2124672084: // capFloorLeg + return capFloorLeg; + case -995239866: // payLeg + return payLeg; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + } + + @Override + public Builder set(String propertyName, Object newValue) { + switch (propertyName.hashCode()) { + case 2124672084: // capFloorLeg + this.capFloorLeg = (ResolvedOvernightInArrearsCapFloorLeg) newValue; + break; + case -995239866: // payLeg + this.payLeg = (ResolvedSwapLeg) newValue; + break; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + return this; + } + + @Override + public ResolvedOvernightInArrearsCapFloor build() { + return new ResolvedOvernightInArrearsCapFloor( + capFloorLeg, + payLeg); + } + + //----------------------------------------------------------------------- + @Override + public String toString() { + StringBuilder buf = new StringBuilder(96); + buf.append("ResolvedOvernightInArrearsCapFloor.Builder{"); + buf.append("capFloorLeg").append('=').append(JodaBeanUtils.toString(capFloorLeg)).append(',').append(' '); + buf.append("payLeg").append('=').append(JodaBeanUtils.toString(payLeg)); + buf.append('}'); + return buf.toString(); + } + + } + + //-------------------------- AUTOGENERATED END -------------------------- +} diff --git a/modules/product/src/main/java/com/opengamma/strata/product/capfloor/ResolvedOvernightInArrearsCapFloorLeg.java b/modules/product/src/main/java/com/opengamma/strata/product/capfloor/ResolvedOvernightInArrearsCapFloorLeg.java new file mode 100644 index 0000000000..fe94ad2f8f --- /dev/null +++ b/modules/product/src/main/java/com/opengamma/strata/product/capfloor/ResolvedOvernightInArrearsCapFloorLeg.java @@ -0,0 +1,468 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.product.capfloor; + +import java.io.Serializable; +import java.time.LocalDate; +import java.util.List; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; +import java.util.stream.Collectors; + +import org.joda.beans.Bean; +import org.joda.beans.ImmutableBean; +import org.joda.beans.JodaBeanUtils; +import org.joda.beans.MetaBean; +import org.joda.beans.MetaProperty; +import org.joda.beans.gen.BeanDefinition; +import org.joda.beans.gen.ImmutableConstructor; +import org.joda.beans.gen.PropertyDefinition; +import org.joda.beans.impl.direct.DirectFieldsBeanBuilder; +import org.joda.beans.impl.direct.DirectMetaBean; +import org.joda.beans.impl.direct.DirectMetaProperty; +import org.joda.beans.impl.direct.DirectMetaPropertyMap; + +import com.google.common.collect.ImmutableList; +import com.opengamma.strata.basics.ReferenceData; +import com.opengamma.strata.basics.currency.Currency; +import com.opengamma.strata.basics.index.OvernightIndex; +import com.opengamma.strata.collect.ArgChecker; +import com.opengamma.strata.product.common.PayReceive; + +/** + * A cap/floor leg of an overnight rate in arrears cap/floor product, resolved for pricing. + *

    + * This is the resolved form of {@link OvernightInArrearsCapFloorLeg} and is an input to the pricers. + * Applications will typically create a {@code ResolvedOvernightInArrearsCapFloorLeg} + * from a {@code OvernightInArrearsCapFloorLeg} using {@link OvernightInArrearsCapFloorLeg#resolve(ReferenceData)}. + *

    + * This defines a single leg for an overnight rate in arrears cap/floor product and is formed from a number of periods. + * Each period may be a caplet or floorlet. + * The cap/floor instruments are defined as a set of call/put options on successive compounded overnight index rates. + *

    + * A {@code ResolvedOvernightInArrearsCapFloorLeg} is bound to data that changes over time, such as holiday calendars. + * If the data changes, such as the addition of a new holiday, the resolved form will not be updated. + * Care must be taken when placing the resolved form in a cache or persistence layer. + */ +@BeanDefinition +public final class ResolvedOvernightInArrearsCapFloorLeg + implements ImmutableBean, Serializable { + + /** + * Whether the leg is pay or receive. + *

    + * A value of 'Pay' implies that the resulting amount is paid to the counterparty. + * A value of 'Receive' implies that the resulting amount is received from the counterparty. + *

    + * The value of this flag should match the signs of the payment period notionals. + */ + @PropertyDefinition(validate = "notNull") + private final PayReceive payReceive; + /** + * The periodic payments based on the successive observed values of compounded overnight index rates. + *

    + * Each payment period represents part of the life-time of the leg. + * In most cases, the periods do not overlap. However, since each payment period + * is essentially independent the data model allows overlapping periods. + */ + @PropertyDefinition(validate = "notEmpty") + private final ImmutableList capletFloorletPeriods; + + //------------------------------------------------------------------------- + @ImmutableConstructor + private ResolvedOvernightInArrearsCapFloorLeg( + PayReceive payReceive, + List capletFloorletPeriods) { + + this.payReceive = ArgChecker.notNull(payReceive, "payReceive"); + this.capletFloorletPeriods = ImmutableList.copyOf(capletFloorletPeriods); + Set currencies = + this.capletFloorletPeriods.stream().map(OvernightInArrearsCapletFloorletPeriod::getCurrency).collect(Collectors.toSet()); + ArgChecker.isTrue(currencies.size() == 1, "Leg must have a single currency, found: " + currencies); + Set indices = + this.capletFloorletPeriods.stream().map(OvernightInArrearsCapletFloorletPeriod::getIndex).collect(Collectors.toSet()); + ArgChecker.isTrue(indices.size() == 1, "Leg must have a single overnight index: " + indices); + } + + //------------------------------------------------------------------------- + /** + * Gets the accrual start date of the leg. + *

    + * This is the first accrual date in the leg, often known as the effective date. + * This date has typically been adjusted to be a valid business day. + * + * @return the start date of the leg + */ + public LocalDate getStartDate() { + return capletFloorletPeriods.get(0).getStartDate(); + } + + /** + * Gets the accrual end date of the leg. + *

    + * This is the last accrual date in the leg, often known as the termination date. + * This date has typically been adjusted to be a valid business day. + * + * @return the end date of the leg + */ + public LocalDate getEndDate() { + return capletFloorletPeriods.get(capletFloorletPeriods.size() - 1).getEndDate(); + } + + /** + * Gets the final caplet/floorlet period. + * + * @return the final period + */ + public OvernightInArrearsCapletFloorletPeriod getFinalPeriod() { + return capletFloorletPeriods.get(capletFloorletPeriods.size() - 1); + } + + /** + * Gets the currency of the leg. + *

    + * All periods in the leg will have this currency. + * + * @return the currency + */ + public Currency getCurrency() { + return capletFloorletPeriods.get(0).getCurrency(); + } + + /** + * Gets the overnight index of the leg. + *

    + * All periods in the leg will have this index. + * + * @return the index + */ + public OvernightIndex getIndex() { + return capletFloorletPeriods.get(0).getIndex(); + } + + //------------------------- AUTOGENERATED START ------------------------- + /** + * The meta-bean for {@code ResolvedOvernightInArrearsCapFloorLeg}. + * @return the meta-bean, not null + */ + public static ResolvedOvernightInArrearsCapFloorLeg.Meta meta() { + return ResolvedOvernightInArrearsCapFloorLeg.Meta.INSTANCE; + } + + static { + MetaBean.register(ResolvedOvernightInArrearsCapFloorLeg.Meta.INSTANCE); + } + + /** + * The serialization version id. + */ + private static final long serialVersionUID = 1L; + + /** + * Returns a builder used to create an instance of the bean. + * @return the builder, not null + */ + public static ResolvedOvernightInArrearsCapFloorLeg.Builder builder() { + return new ResolvedOvernightInArrearsCapFloorLeg.Builder(); + } + + @Override + public ResolvedOvernightInArrearsCapFloorLeg.Meta metaBean() { + return ResolvedOvernightInArrearsCapFloorLeg.Meta.INSTANCE; + } + + //----------------------------------------------------------------------- + /** + * Gets whether the leg is pay or receive. + *

    + * A value of 'Pay' implies that the resulting amount is paid to the counterparty. + * A value of 'Receive' implies that the resulting amount is received from the counterparty. + *

    + * The value of this flag should match the signs of the payment period notionals. + * @return the value of the property, not null + */ + public PayReceive getPayReceive() { + return payReceive; + } + + //----------------------------------------------------------------------- + /** + * Gets the periodic payments based on the successive observed values of compounded overnight index rates. + *

    + * Each payment period represents part of the life-time of the leg. + * In most cases, the periods do not overlap. However, since each payment period + * is essentially independent the data model allows overlapping periods. + * @return the value of the property, not empty + */ + public ImmutableList getCapletFloorletPeriods() { + return capletFloorletPeriods; + } + + //----------------------------------------------------------------------- + /** + * Returns a builder that allows this bean to be mutated. + * @return the mutable builder, not null + */ + public Builder toBuilder() { + return new Builder(this); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && obj.getClass() == this.getClass()) { + ResolvedOvernightInArrearsCapFloorLeg other = (ResolvedOvernightInArrearsCapFloorLeg) obj; + return JodaBeanUtils.equal(payReceive, other.payReceive) && + JodaBeanUtils.equal(capletFloorletPeriods, other.capletFloorletPeriods); + } + return false; + } + + @Override + public int hashCode() { + int hash = getClass().hashCode(); + hash = hash * 31 + JodaBeanUtils.hashCode(payReceive); + hash = hash * 31 + JodaBeanUtils.hashCode(capletFloorletPeriods); + return hash; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(96); + buf.append("ResolvedOvernightInArrearsCapFloorLeg{"); + buf.append("payReceive").append('=').append(JodaBeanUtils.toString(payReceive)).append(',').append(' '); + buf.append("capletFloorletPeriods").append('=').append(JodaBeanUtils.toString(capletFloorletPeriods)); + buf.append('}'); + return buf.toString(); + } + + //----------------------------------------------------------------------- + /** + * The meta-bean for {@code ResolvedOvernightInArrearsCapFloorLeg}. + */ + public static final class Meta extends DirectMetaBean { + /** + * The singleton instance of the meta-bean. + */ + static final Meta INSTANCE = new Meta(); + + /** + * The meta-property for the {@code payReceive} property. + */ + private final MetaProperty payReceive = DirectMetaProperty.ofImmutable( + this, "payReceive", ResolvedOvernightInArrearsCapFloorLeg.class, PayReceive.class); + /** + * The meta-property for the {@code capletFloorletPeriods} property. + */ + @SuppressWarnings({"unchecked", "rawtypes" }) + private final MetaProperty> capletFloorletPeriods = DirectMetaProperty.ofImmutable( + this, "capletFloorletPeriods", ResolvedOvernightInArrearsCapFloorLeg.class, (Class) ImmutableList.class); + /** + * The meta-properties. + */ + private final Map> metaPropertyMap$ = new DirectMetaPropertyMap( + this, null, + "payReceive", + "capletFloorletPeriods"); + + /** + * Restricted constructor. + */ + private Meta() { + } + + @Override + protected MetaProperty metaPropertyGet(String propertyName) { + switch (propertyName.hashCode()) { + case -885469925: // payReceive + return payReceive; + case 1504863482: // capletFloorletPeriods + return capletFloorletPeriods; + } + return super.metaPropertyGet(propertyName); + } + + @Override + public ResolvedOvernightInArrearsCapFloorLeg.Builder builder() { + return new ResolvedOvernightInArrearsCapFloorLeg.Builder(); + } + + @Override + public Class beanType() { + return ResolvedOvernightInArrearsCapFloorLeg.class; + } + + @Override + public Map> metaPropertyMap() { + return metaPropertyMap$; + } + + //----------------------------------------------------------------------- + /** + * The meta-property for the {@code payReceive} property. + * @return the meta-property, not null + */ + public MetaProperty payReceive() { + return payReceive; + } + + /** + * The meta-property for the {@code capletFloorletPeriods} property. + * @return the meta-property, not null + */ + public MetaProperty> capletFloorletPeriods() { + return capletFloorletPeriods; + } + + //----------------------------------------------------------------------- + @Override + protected Object propertyGet(Bean bean, String propertyName, boolean quiet) { + switch (propertyName.hashCode()) { + case -885469925: // payReceive + return ((ResolvedOvernightInArrearsCapFloorLeg) bean).getPayReceive(); + case 1504863482: // capletFloorletPeriods + return ((ResolvedOvernightInArrearsCapFloorLeg) bean).getCapletFloorletPeriods(); + } + return super.propertyGet(bean, propertyName, quiet); + } + + @Override + protected void propertySet(Bean bean, String propertyName, Object newValue, boolean quiet) { + metaProperty(propertyName); + if (quiet) { + return; + } + throw new UnsupportedOperationException("Property cannot be written: " + propertyName); + } + + } + + //----------------------------------------------------------------------- + /** + * The bean-builder for {@code ResolvedOvernightInArrearsCapFloorLeg}. + */ + public static final class Builder extends DirectFieldsBeanBuilder { + + private PayReceive payReceive; + private List capletFloorletPeriods = ImmutableList.of(); + + /** + * Restricted constructor. + */ + private Builder() { + } + + /** + * Restricted copy constructor. + * @param beanToCopy the bean to copy from, not null + */ + private Builder(ResolvedOvernightInArrearsCapFloorLeg beanToCopy) { + this.payReceive = beanToCopy.getPayReceive(); + this.capletFloorletPeriods = beanToCopy.getCapletFloorletPeriods(); + } + + //----------------------------------------------------------------------- + @Override + public Object get(String propertyName) { + switch (propertyName.hashCode()) { + case -885469925: // payReceive + return payReceive; + case 1504863482: // capletFloorletPeriods + return capletFloorletPeriods; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + } + + @SuppressWarnings("unchecked") + @Override + public Builder set(String propertyName, Object newValue) { + switch (propertyName.hashCode()) { + case -885469925: // payReceive + this.payReceive = (PayReceive) newValue; + break; + case 1504863482: // capletFloorletPeriods + this.capletFloorletPeriods = (List) newValue; + break; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + return this; + } + + @Override + public Builder set(MetaProperty property, Object value) { + super.set(property, value); + return this; + } + + @Override + public ResolvedOvernightInArrearsCapFloorLeg build() { + return new ResolvedOvernightInArrearsCapFloorLeg( + payReceive, + capletFloorletPeriods); + } + + //----------------------------------------------------------------------- + /** + * Sets whether the leg is pay or receive. + *

    + * A value of 'Pay' implies that the resulting amount is paid to the counterparty. + * A value of 'Receive' implies that the resulting amount is received from the counterparty. + *

    + * The value of this flag should match the signs of the payment period notionals. + * @param payReceive the new value, not null + * @return this, for chaining, not null + */ + public Builder payReceive(PayReceive payReceive) { + JodaBeanUtils.notNull(payReceive, "payReceive"); + this.payReceive = payReceive; + return this; + } + + /** + * Sets the periodic payments based on the successive observed values of compounded overnight index rates. + *

    + * Each payment period represents part of the life-time of the leg. + * In most cases, the periods do not overlap. However, since each payment period + * is essentially independent the data model allows overlapping periods. + * @param capletFloorletPeriods the new value, not empty + * @return this, for chaining, not null + */ + public Builder capletFloorletPeriods(List capletFloorletPeriods) { + JodaBeanUtils.notEmpty(capletFloorletPeriods, "capletFloorletPeriods"); + this.capletFloorletPeriods = capletFloorletPeriods; + return this; + } + + /** + * Sets the {@code capletFloorletPeriods} property in the builder + * from an array of objects. + * @param capletFloorletPeriods the new value, not empty + * @return this, for chaining, not null + */ + public Builder capletFloorletPeriods(OvernightInArrearsCapletFloorletPeriod... capletFloorletPeriods) { + return capletFloorletPeriods(ImmutableList.copyOf(capletFloorletPeriods)); + } + + //----------------------------------------------------------------------- + @Override + public String toString() { + StringBuilder buf = new StringBuilder(96); + buf.append("ResolvedOvernightInArrearsCapFloorLeg.Builder{"); + buf.append("payReceive").append('=').append(JodaBeanUtils.toString(payReceive)).append(',').append(' '); + buf.append("capletFloorletPeriods").append('=').append(JodaBeanUtils.toString(capletFloorletPeriods)); + buf.append('}'); + return buf.toString(); + } + + } + + //-------------------------- AUTOGENERATED END -------------------------- +} diff --git a/modules/product/src/main/java/com/opengamma/strata/product/capfloor/ResolvedOvernightInArrearsCapFloorTrade.java b/modules/product/src/main/java/com/opengamma/strata/product/capfloor/ResolvedOvernightInArrearsCapFloorTrade.java new file mode 100644 index 0000000000..25c27db7e7 --- /dev/null +++ b/modules/product/src/main/java/com/opengamma/strata/product/capfloor/ResolvedOvernightInArrearsCapFloorTrade.java @@ -0,0 +1,449 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.product.capfloor; + +import java.io.Serializable; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Optional; + +import org.joda.beans.Bean; +import org.joda.beans.ImmutableBean; +import org.joda.beans.JodaBeanUtils; +import org.joda.beans.MetaBean; +import org.joda.beans.MetaProperty; +import org.joda.beans.gen.BeanDefinition; +import org.joda.beans.gen.ImmutableDefaults; +import org.joda.beans.gen.PropertyDefinition; +import org.joda.beans.impl.direct.DirectFieldsBeanBuilder; +import org.joda.beans.impl.direct.DirectMetaBean; +import org.joda.beans.impl.direct.DirectMetaProperty; +import org.joda.beans.impl.direct.DirectMetaPropertyMap; + +import com.opengamma.strata.basics.ReferenceData; +import com.opengamma.strata.basics.currency.Payment; +import com.opengamma.strata.product.ResolvedTrade; +import com.opengamma.strata.product.TradeInfo; + +/** + * A trade in an overnight rate in arrears cap/floor, resolved for pricing. + *

    + * This is the resolved form of {@link OvernightInArrearsCapFloorTrade} and is the primary input to the pricers. + * Applications will typically create a {@code ResolvedOvernightInArrearsCapFloorTrade} from + * a {@code OvernightInArrearsCapFloorTrade} using {@link OvernightInArrearsCapFloorTrade#resolve(ReferenceData)}. + *

    + * A {@code OvernightInArrearsCapFloorTrade} is bound to data that changes over time, such as holiday calendars. + * If the data changes, such as the addition of a new holiday, the resolved form will not be updated. + * Care must be taken when placing the resolved form in a cache or persistence layer. + */ +@BeanDefinition +public final class ResolvedOvernightInArrearsCapFloorTrade + implements ResolvedTrade, ImmutableBean, Serializable { + + /** + * The additional trade information, defaulted to an empty instance. + *

    + * This allows additional information to be attached to the trade. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final TradeInfo info; + /** + * The resolved overnight in arrears cap/floor product. + *

    + * The product captures the contracted financial details of the trade. + */ + @PropertyDefinition(validate = "notNull", overrideGet = true) + private final ResolvedOvernightInArrearsCapFloor product; + /** + * The optional premium of the product. + *

    + * For most overnight rate in arrears cap/floor products, a premium is paid upfront. This typically occurs instead + * of periodic payments based on fixed or rate index rates over the lifetime of the product. + *

    + * The premium sign must be compatible with the product Pay/Receive flag. + */ + @PropertyDefinition(get = "optional") + private final Payment premium; + + //------------------------------------------------------------------------- + @ImmutableDefaults + private static void applyDefaults(Builder builder) { + builder.info = TradeInfo.empty(); + } + + //------------------------- AUTOGENERATED START ------------------------- + /** + * The meta-bean for {@code ResolvedOvernightInArrearsCapFloorTrade}. + * @return the meta-bean, not null + */ + public static ResolvedOvernightInArrearsCapFloorTrade.Meta meta() { + return ResolvedOvernightInArrearsCapFloorTrade.Meta.INSTANCE; + } + + static { + MetaBean.register(ResolvedOvernightInArrearsCapFloorTrade.Meta.INSTANCE); + } + + /** + * The serialization version id. + */ + private static final long serialVersionUID = 1L; + + /** + * Returns a builder used to create an instance of the bean. + * @return the builder, not null + */ + public static ResolvedOvernightInArrearsCapFloorTrade.Builder builder() { + return new ResolvedOvernightInArrearsCapFloorTrade.Builder(); + } + + private ResolvedOvernightInArrearsCapFloorTrade( + TradeInfo info, + ResolvedOvernightInArrearsCapFloor product, + Payment premium) { + JodaBeanUtils.notNull(info, "info"); + JodaBeanUtils.notNull(product, "product"); + this.info = info; + this.product = product; + this.premium = premium; + } + + @Override + public ResolvedOvernightInArrearsCapFloorTrade.Meta metaBean() { + return ResolvedOvernightInArrearsCapFloorTrade.Meta.INSTANCE; + } + + //----------------------------------------------------------------------- + /** + * Gets the additional trade information, defaulted to an empty instance. + *

    + * This allows additional information to be attached to the trade. + * @return the value of the property, not null + */ + @Override + public TradeInfo getInfo() { + return info; + } + + //----------------------------------------------------------------------- + /** + * Gets the resolved overnight in arrears cap/floor product. + *

    + * The product captures the contracted financial details of the trade. + * @return the value of the property, not null + */ + @Override + public ResolvedOvernightInArrearsCapFloor getProduct() { + return product; + } + + //----------------------------------------------------------------------- + /** + * Gets the optional premium of the product. + *

    + * For most overnight rate in arrears cap/floor products, a premium is paid upfront. This typically occurs instead + * of periodic payments based on fixed or rate index rates over the lifetime of the product. + *

    + * The premium sign must be compatible with the product Pay/Receive flag. + * @return the optional value of the property, not null + */ + public Optional getPremium() { + return Optional.ofNullable(premium); + } + + //----------------------------------------------------------------------- + /** + * Returns a builder that allows this bean to be mutated. + * @return the mutable builder, not null + */ + public Builder toBuilder() { + return new Builder(this); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && obj.getClass() == this.getClass()) { + ResolvedOvernightInArrearsCapFloorTrade other = (ResolvedOvernightInArrearsCapFloorTrade) obj; + return JodaBeanUtils.equal(info, other.info) && + JodaBeanUtils.equal(product, other.product) && + JodaBeanUtils.equal(premium, other.premium); + } + return false; + } + + @Override + public int hashCode() { + int hash = getClass().hashCode(); + hash = hash * 31 + JodaBeanUtils.hashCode(info); + hash = hash * 31 + JodaBeanUtils.hashCode(product); + hash = hash * 31 + JodaBeanUtils.hashCode(premium); + return hash; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(128); + buf.append("ResolvedOvernightInArrearsCapFloorTrade{"); + buf.append("info").append('=').append(JodaBeanUtils.toString(info)).append(',').append(' '); + buf.append("product").append('=').append(JodaBeanUtils.toString(product)).append(',').append(' '); + buf.append("premium").append('=').append(JodaBeanUtils.toString(premium)); + buf.append('}'); + return buf.toString(); + } + + //----------------------------------------------------------------------- + /** + * The meta-bean for {@code ResolvedOvernightInArrearsCapFloorTrade}. + */ + public static final class Meta extends DirectMetaBean { + /** + * The singleton instance of the meta-bean. + */ + static final Meta INSTANCE = new Meta(); + + /** + * The meta-property for the {@code info} property. + */ + private final MetaProperty info = DirectMetaProperty.ofImmutable( + this, "info", ResolvedOvernightInArrearsCapFloorTrade.class, TradeInfo.class); + /** + * The meta-property for the {@code product} property. + */ + private final MetaProperty product = DirectMetaProperty.ofImmutable( + this, "product", ResolvedOvernightInArrearsCapFloorTrade.class, ResolvedOvernightInArrearsCapFloor.class); + /** + * The meta-property for the {@code premium} property. + */ + private final MetaProperty premium = DirectMetaProperty.ofImmutable( + this, "premium", ResolvedOvernightInArrearsCapFloorTrade.class, Payment.class); + /** + * The meta-properties. + */ + private final Map> metaPropertyMap$ = new DirectMetaPropertyMap( + this, null, + "info", + "product", + "premium"); + + /** + * Restricted constructor. + */ + private Meta() { + } + + @Override + protected MetaProperty metaPropertyGet(String propertyName) { + switch (propertyName.hashCode()) { + case 3237038: // info + return info; + case -309474065: // product + return product; + case -318452137: // premium + return premium; + } + return super.metaPropertyGet(propertyName); + } + + @Override + public ResolvedOvernightInArrearsCapFloorTrade.Builder builder() { + return new ResolvedOvernightInArrearsCapFloorTrade.Builder(); + } + + @Override + public Class beanType() { + return ResolvedOvernightInArrearsCapFloorTrade.class; + } + + @Override + public Map> metaPropertyMap() { + return metaPropertyMap$; + } + + //----------------------------------------------------------------------- + /** + * The meta-property for the {@code info} property. + * @return the meta-property, not null + */ + public MetaProperty info() { + return info; + } + + /** + * The meta-property for the {@code product} property. + * @return the meta-property, not null + */ + public MetaProperty product() { + return product; + } + + /** + * The meta-property for the {@code premium} property. + * @return the meta-property, not null + */ + public MetaProperty premium() { + return premium; + } + + //----------------------------------------------------------------------- + @Override + protected Object propertyGet(Bean bean, String propertyName, boolean quiet) { + switch (propertyName.hashCode()) { + case 3237038: // info + return ((ResolvedOvernightInArrearsCapFloorTrade) bean).getInfo(); + case -309474065: // product + return ((ResolvedOvernightInArrearsCapFloorTrade) bean).getProduct(); + case -318452137: // premium + return ((ResolvedOvernightInArrearsCapFloorTrade) bean).premium; + } + return super.propertyGet(bean, propertyName, quiet); + } + + @Override + protected void propertySet(Bean bean, String propertyName, Object newValue, boolean quiet) { + metaProperty(propertyName); + if (quiet) { + return; + } + throw new UnsupportedOperationException("Property cannot be written: " + propertyName); + } + + } + + //----------------------------------------------------------------------- + /** + * The bean-builder for {@code ResolvedOvernightInArrearsCapFloorTrade}. + */ + public static final class Builder extends DirectFieldsBeanBuilder { + + private TradeInfo info; + private ResolvedOvernightInArrearsCapFloor product; + private Payment premium; + + /** + * Restricted constructor. + */ + private Builder() { + applyDefaults(this); + } + + /** + * Restricted copy constructor. + * @param beanToCopy the bean to copy from, not null + */ + private Builder(ResolvedOvernightInArrearsCapFloorTrade beanToCopy) { + this.info = beanToCopy.getInfo(); + this.product = beanToCopy.getProduct(); + this.premium = beanToCopy.premium; + } + + //----------------------------------------------------------------------- + @Override + public Object get(String propertyName) { + switch (propertyName.hashCode()) { + case 3237038: // info + return info; + case -309474065: // product + return product; + case -318452137: // premium + return premium; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + } + + @Override + public Builder set(String propertyName, Object newValue) { + switch (propertyName.hashCode()) { + case 3237038: // info + this.info = (TradeInfo) newValue; + break; + case -309474065: // product + this.product = (ResolvedOvernightInArrearsCapFloor) newValue; + break; + case -318452137: // premium + this.premium = (Payment) newValue; + break; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + return this; + } + + @Override + public Builder set(MetaProperty property, Object value) { + super.set(property, value); + return this; + } + + @Override + public ResolvedOvernightInArrearsCapFloorTrade build() { + return new ResolvedOvernightInArrearsCapFloorTrade( + info, + product, + premium); + } + + //----------------------------------------------------------------------- + /** + * Sets the additional trade information, defaulted to an empty instance. + *

    + * This allows additional information to be attached to the trade. + * @param info the new value, not null + * @return this, for chaining, not null + */ + public Builder info(TradeInfo info) { + JodaBeanUtils.notNull(info, "info"); + this.info = info; + return this; + } + + /** + * Sets the resolved overnight in arrears cap/floor product. + *

    + * The product captures the contracted financial details of the trade. + * @param product the new value, not null + * @return this, for chaining, not null + */ + public Builder product(ResolvedOvernightInArrearsCapFloor product) { + JodaBeanUtils.notNull(product, "product"); + this.product = product; + return this; + } + + /** + * Sets the optional premium of the product. + *

    + * For most overnight rate in arrears cap/floor products, a premium is paid upfront. This typically occurs instead + * of periodic payments based on fixed or rate index rates over the lifetime of the product. + *

    + * The premium sign must be compatible with the product Pay/Receive flag. + * @param premium the new value + * @return this, for chaining, not null + */ + public Builder premium(Payment premium) { + this.premium = premium; + return this; + } + + //----------------------------------------------------------------------- + @Override + public String toString() { + StringBuilder buf = new StringBuilder(128); + buf.append("ResolvedOvernightInArrearsCapFloorTrade.Builder{"); + buf.append("info").append('=').append(JodaBeanUtils.toString(info)).append(',').append(' '); + buf.append("product").append('=').append(JodaBeanUtils.toString(product)).append(',').append(' '); + buf.append("premium").append('=').append(JodaBeanUtils.toString(premium)); + buf.append('}'); + return buf.toString(); + } + + } + + //-------------------------- AUTOGENERATED END -------------------------- +} diff --git a/modules/product/src/test/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapFloorLegTest.java b/modules/product/src/test/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapFloorLegTest.java new file mode 100644 index 0000000000..84f39867f6 --- /dev/null +++ b/modules/product/src/test/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapFloorLegTest.java @@ -0,0 +1,305 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.product.capfloor; + +import static com.opengamma.strata.basics.currency.Currency.EUR; +import static com.opengamma.strata.basics.currency.Currency.GBP; +import static com.opengamma.strata.basics.date.HolidayCalendarIds.EUTA; +import static com.opengamma.strata.basics.index.OvernightIndices.EUR_EONIA; +import static com.opengamma.strata.basics.index.OvernightIndices.EUR_ESTR; +import static com.opengamma.strata.collect.TestHelper.assertSerialization; +import static com.opengamma.strata.collect.TestHelper.coverBeanEquals; +import static com.opengamma.strata.collect.TestHelper.coverImmutableBean; +import static com.opengamma.strata.product.common.PayReceive.PAY; +import static com.opengamma.strata.product.common.PayReceive.RECEIVE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +import java.time.LocalDate; +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import com.opengamma.strata.basics.ReferenceData; +import com.opengamma.strata.basics.date.AdjustableDate; +import com.opengamma.strata.basics.date.BusinessDayAdjustment; +import com.opengamma.strata.basics.date.BusinessDayConventions; +import com.opengamma.strata.basics.date.DaysAdjustment; +import com.opengamma.strata.basics.index.OvernightIndices; +import com.opengamma.strata.basics.schedule.Frequency; +import com.opengamma.strata.basics.schedule.PeriodicSchedule; +import com.opengamma.strata.basics.schedule.StubConvention; +import com.opengamma.strata.basics.value.ValueAdjustment; +import com.opengamma.strata.basics.value.ValueSchedule; +import com.opengamma.strata.basics.value.ValueStep; +import com.opengamma.strata.product.rate.OvernightCompoundedRateComputation; +import com.opengamma.strata.product.swap.OvernightAccrualMethod; +import com.opengamma.strata.product.swap.OvernightRateCalculation; + +/** + * Test {@link OvernightInArrearsCapFloorLeg}. + */ +public class OvernightInArrearsCapFloorLegTest { + + private static final ReferenceData REF_DATA = ReferenceData.standard(); + private static final LocalDate START = LocalDate.of(2011, 3, 17); + private static final LocalDate END = LocalDate.of(2012, 3, 17); + private static final OvernightRateCalculation RATE_CALCULATION = OvernightRateCalculation.of(EUR_ESTR); + private static final Frequency FREQUENCY = Frequency.P3M; + private static final BusinessDayAdjustment BUSS_ADJ = + BusinessDayAdjustment.of(BusinessDayConventions.FOLLOWING, EUTA); + private static final PeriodicSchedule SCHEDULE = PeriodicSchedule.builder() + .startDate(START) + .endDate(END) + .frequency(FREQUENCY) + .businessDayAdjustment(BUSS_ADJ) + .stubConvention(StubConvention.NONE) + .build(); + private static final DaysAdjustment PAYMENT_OFFSET = DaysAdjustment.ofBusinessDays(2, EUTA); + + private static final double[] NOTIONALS = new double[] {1.0e6, 1.2e6, 0.8e6, 1.0e6}; + private static final double[] STRIKES = new double[] {0.03, 0.0275, 0.02, 0.0345}; + private static final ValueSchedule CAP = ValueSchedule.of(0.0325); + private static final List FLOOR_STEPS = new ArrayList(); + private static final List NOTIONAL_STEPS = new ArrayList(); + static { + FLOOR_STEPS.add(ValueStep.of(1, ValueAdjustment.ofReplace(STRIKES[1]))); + FLOOR_STEPS.add(ValueStep.of(2, ValueAdjustment.ofReplace(STRIKES[2]))); + FLOOR_STEPS.add(ValueStep.of(3, ValueAdjustment.ofReplace(STRIKES[3]))); + NOTIONAL_STEPS.add(ValueStep.of(1, ValueAdjustment.ofReplace(NOTIONALS[1]))); + NOTIONAL_STEPS.add(ValueStep.of(2, ValueAdjustment.ofReplace(NOTIONALS[2]))); + NOTIONAL_STEPS.add(ValueStep.of(3, ValueAdjustment.ofReplace(NOTIONALS[3]))); + } + private static final ValueSchedule FLOOR = ValueSchedule.of(STRIKES[0], FLOOR_STEPS); + private static final ValueSchedule NOTIONAL = ValueSchedule.of(NOTIONALS[0], NOTIONAL_STEPS); + + @Test + public void test_builder_full() { + OvernightInArrearsCapFloorLeg test = OvernightInArrearsCapFloorLeg.builder() + .calculation(RATE_CALCULATION) + .capSchedule(CAP) + .currency(GBP) + .notional(NOTIONAL) + .paymentDateOffset(PAYMENT_OFFSET) + .paymentSchedule(SCHEDULE) + .payReceive(PAY) + .build(); + assertThat(test.getCalculation()).isEqualTo(RATE_CALCULATION); + assertThat(test.getCapSchedule().get()).isEqualTo(CAP); + assertThat(test.getFloorSchedule()).isNotPresent(); + assertThat(test.getCurrency()).isEqualTo(GBP); + assertThat(test.getNotional()).isEqualTo(NOTIONAL); + assertThat(test.getPaymentDateOffset()).isEqualTo(PAYMENT_OFFSET); + assertThat(test.getPaymentSchedule()).isEqualTo(SCHEDULE); + assertThat(test.getPayReceive()).isEqualTo(PAY); + assertThat(test.getStartDate()).isEqualTo(AdjustableDate.of(START, BUSS_ADJ)); + assertThat(test.getEndDate()).isEqualTo(AdjustableDate.of(END, BUSS_ADJ)); + assertThat(test.getIndex()).isEqualTo(EUR_ESTR); + } + + @Test + public void test_builder_min() { + OvernightInArrearsCapFloorLeg test = OvernightInArrearsCapFloorLeg.builder() + .calculation(RATE_CALCULATION) + .floorSchedule(FLOOR) + .notional(NOTIONAL) + .paymentSchedule(SCHEDULE) + .payReceive(RECEIVE) + .build(); + assertThat(test.getCalculation()).isEqualTo(RATE_CALCULATION); + assertThat(test.getCapSchedule()).isNotPresent(); + assertThat(test.getFloorSchedule().get()).isEqualTo(FLOOR); + assertThat(test.getCurrency()).isEqualTo(EUR); + assertThat(test.getNotional()).isEqualTo(NOTIONAL); + assertThat(test.getPaymentDateOffset()).isEqualTo(DaysAdjustment.NONE); + assertThat(test.getPaymentSchedule()).isEqualTo(SCHEDULE); + assertThat(test.getPayReceive()).isEqualTo(RECEIVE); + assertThat(test.getStartDate()).isEqualTo(AdjustableDate.of(START, BUSS_ADJ)); + assertThat(test.getEndDate()).isEqualTo(AdjustableDate.of(END, BUSS_ADJ)); + } + + @Test + public void test_builder_fail() { + // cap and floor present + assertThatIllegalArgumentException() + .isThrownBy(() -> OvernightInArrearsCapFloorLeg.builder() + .calculation(RATE_CALCULATION) + .capSchedule(CAP) + .floorSchedule(FLOOR) + .notional(NOTIONAL) + .paymentSchedule(SCHEDULE) + .payReceive(RECEIVE) + .build()); + // cap and floor missing + assertThatIllegalArgumentException() + .isThrownBy(() -> OvernightInArrearsCapFloorLeg.builder() + .calculation(RATE_CALCULATION) + .notional(NOTIONAL) + .paymentSchedule(PeriodicSchedule.builder() + .startDate(START) + .endDate(END) + .frequency(FREQUENCY) + .businessDayAdjustment(BUSS_ADJ) + .build()) + .payReceive(RECEIVE) + .build()); + // stub type + assertThatIllegalArgumentException() + .isThrownBy(() -> OvernightInArrearsCapFloorLeg.builder() + .calculation(RATE_CALCULATION) + .capSchedule(CAP) + .currency(GBP) + .notional(NOTIONAL) + .paymentDateOffset(PAYMENT_OFFSET) + .paymentSchedule(PeriodicSchedule.builder() + .startDate(START) + .endDate(END) + .frequency(FREQUENCY) + .businessDayAdjustment(BUSS_ADJ) + .stubConvention(StubConvention.SHORT_FINAL) + .build()) + .payReceive(PAY) + .build()); + // accrual method not compounded + assertThatIllegalArgumentException() + .isThrownBy(() -> OvernightInArrearsCapFloorLeg.builder() + .calculation(OvernightRateCalculation.builder() + .index(EUR_ESTR) + .accrualMethod(OvernightAccrualMethod.AVERAGED_DAILY) + .build()) + .floorSchedule(FLOOR) + .notional(NOTIONAL) + .paymentSchedule(SCHEDULE) + .payReceive(RECEIVE) + .build()); + } + + @Test + public void test_resolve_cap() { + OvernightRateCalculation rateCalc = OvernightRateCalculation.of(EUR_EONIA); + OvernightInArrearsCapFloorLeg base = OvernightInArrearsCapFloorLeg.builder() + .calculation(rateCalc) + .capSchedule(CAP) + .notional(NOTIONAL) + .paymentDateOffset(PAYMENT_OFFSET) + .paymentSchedule(SCHEDULE) + .payReceive(RECEIVE) + .build(); + LocalDate[] unadjustedDates = new LocalDate[]{ + START, START.plusMonths(3), + START.plusMonths(6), + START.plusMonths(9), + START.plusMonths(12)}; + OvernightInArrearsCapletFloorletPeriod[] periods = new OvernightInArrearsCapletFloorletPeriod[4]; + for (int i = 0; i < 4; ++i) { + LocalDate start = BUSS_ADJ.adjust(unadjustedDates[i], REF_DATA); + LocalDate end = BUSS_ADJ.adjust(unadjustedDates[i + 1], REF_DATA); + double yearFraction = rateCalc.getDayCount().relativeYearFraction(start, end); + periods[i] = OvernightInArrearsCapletFloorletPeriod.builder() + .caplet(CAP.getInitialValue()) + .currency(EUR) + .startDate(start) + .endDate(end) + .unadjustedStartDate(unadjustedDates[i]) + .unadjustedEndDate(unadjustedDates[i + 1]) + .paymentDate(PAYMENT_OFFSET.adjust(end, REF_DATA)) + .notional(NOTIONALS[i]) + .overnightRate(OvernightCompoundedRateComputation.of(EUR_EONIA, start, end, REF_DATA)) + .yearFraction(yearFraction) + .build(); + } + ResolvedOvernightInArrearsCapFloorLeg expected = ResolvedOvernightInArrearsCapFloorLeg.builder() + .capletFloorletPeriods(periods) + .payReceive(RECEIVE) + .build(); + ResolvedOvernightInArrearsCapFloorLeg computed = base.resolve(REF_DATA); + assertThat(computed).isEqualTo(expected); + } + + @Test + public void test_resolve_floor() { + OvernightInArrearsCapFloorLeg base = OvernightInArrearsCapFloorLeg.builder() + .calculation(RATE_CALCULATION) + .floorSchedule(FLOOR) + .currency(EUR) + .notional(NOTIONAL) + .paymentDateOffset(PAYMENT_OFFSET) + .paymentSchedule(SCHEDULE) + .payReceive(PAY) + .build(); + LocalDate[] unadjustedDates = new LocalDate[] { + START, + START.plusMonths(3), + START.plusMonths(6), + START.plusMonths(9), + START.plusMonths(12)}; + OvernightInArrearsCapletFloorletPeriod[] periods = new OvernightInArrearsCapletFloorletPeriod[4]; + for (int i = 0; i < 4; ++i) { + LocalDate start = BUSS_ADJ.adjust(unadjustedDates[i], REF_DATA); + LocalDate end = BUSS_ADJ.adjust(unadjustedDates[i + 1], REF_DATA); + double yearFraction = RATE_CALCULATION.getDayCount().relativeYearFraction(start, end); + periods[i] = OvernightInArrearsCapletFloorletPeriod.builder() + .floorlet(STRIKES[i]) + .currency(EUR) + .startDate(start) + .endDate(end) + .unadjustedStartDate(unadjustedDates[i]) + .unadjustedEndDate(unadjustedDates[i + 1]) + .paymentDate(PAYMENT_OFFSET.adjust(end, REF_DATA)) + .notional(-NOTIONALS[i]) + .overnightRate(OvernightCompoundedRateComputation.of(EUR_ESTR, start, end, REF_DATA)) + .yearFraction(yearFraction) + .build(); + } + ResolvedOvernightInArrearsCapFloorLeg expected = ResolvedOvernightInArrearsCapFloorLeg.builder() + .capletFloorletPeriods(periods) + .payReceive(PAY) + .build(); + ResolvedOvernightInArrearsCapFloorLeg computed = base.resolve(REF_DATA); + assertThat(computed).isEqualTo(expected); + } + + //------------------------------------------------------------------------- + @Test + public void coverage() { + OvernightInArrearsCapFloorLeg test1 = OvernightInArrearsCapFloorLeg.builder() + .calculation(RATE_CALCULATION) + .floorSchedule(FLOOR) + .notional(NOTIONAL) + .paymentSchedule(SCHEDULE) + .payReceive(RECEIVE) + .build(); + coverImmutableBean(test1); + OvernightInArrearsCapFloorLeg test2 = OvernightInArrearsCapFloorLeg.builder() + .calculation(OvernightRateCalculation.of(OvernightIndices.GBP_SONIA)) + .capSchedule(CAP) + .notional(ValueSchedule.of(1000)) + .paymentDateOffset(PAYMENT_OFFSET) + .paymentSchedule(PeriodicSchedule.builder() + .startDate(START) + .endDate(END) + .frequency(Frequency.P6M) + .businessDayAdjustment(BUSS_ADJ) + .build()) + .payReceive(PAY) + .build(); + coverBeanEquals(test1, test2); + } + + @Test + public void test_serialization() { + OvernightInArrearsCapFloorLeg test = OvernightInArrearsCapFloorLeg.builder() + .calculation(RATE_CALCULATION) + .floorSchedule(FLOOR) + .notional(NOTIONAL) + .paymentSchedule(SCHEDULE) + .payReceive(RECEIVE) + .build(); + assertSerialization(test); + } + +} diff --git a/modules/product/src/test/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapFloorTest.java b/modules/product/src/test/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapFloorTest.java new file mode 100644 index 0000000000..4742548481 --- /dev/null +++ b/modules/product/src/test/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapFloorTest.java @@ -0,0 +1,167 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.product.capfloor; + +import static com.opengamma.strata.basics.currency.Currency.EUR; +import static com.opengamma.strata.basics.currency.Currency.GBP; +import static com.opengamma.strata.basics.date.DayCounts.ACT_360; +import static com.opengamma.strata.basics.date.HolidayCalendarIds.EUTA; +import static com.opengamma.strata.basics.index.OvernightIndices.EUR_ESTR; +import static com.opengamma.strata.basics.index.OvernightIndices.GBP_SONIA; +import static com.opengamma.strata.collect.TestHelper.assertSerialization; +import static com.opengamma.strata.collect.TestHelper.coverBeanEquals; +import static com.opengamma.strata.collect.TestHelper.coverImmutableBean; +import static com.opengamma.strata.product.common.PayReceive.PAY; +import static com.opengamma.strata.product.common.PayReceive.RECEIVE; +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.LocalDate; + +import org.junit.jupiter.api.Test; + +import com.opengamma.strata.basics.ReferenceData; +import com.opengamma.strata.basics.date.BusinessDayAdjustment; +import com.opengamma.strata.basics.date.BusinessDayConventions; +import com.opengamma.strata.basics.date.DaysAdjustment; +import com.opengamma.strata.basics.schedule.Frequency; +import com.opengamma.strata.basics.schedule.PeriodicSchedule; +import com.opengamma.strata.basics.value.ValueSchedule; +import com.opengamma.strata.product.swap.FixedRateCalculation; +import com.opengamma.strata.product.swap.NotionalSchedule; +import com.opengamma.strata.product.swap.OvernightRateCalculation; +import com.opengamma.strata.product.swap.PaymentSchedule; +import com.opengamma.strata.product.swap.RateCalculationSwapLeg; +import com.opengamma.strata.product.swap.SwapLeg; + +/** + * Test {@link OvernightInArrearsCapFloor}. + */ +public class OvernightInArrearsCapFloorTest { + + private static final ReferenceData REF_DATA = ReferenceData.standard(); + private static final LocalDate START = LocalDate.of(2011, 3, 17); + private static final LocalDate END = LocalDate.of(2016, 3, 17); + private static final OvernightRateCalculation RATE_CALCULATION = OvernightRateCalculation.of(EUR_ESTR); + private static final Frequency FREQUENCY = Frequency.P3M; + private static final BusinessDayAdjustment BUSS_ADJ = + BusinessDayAdjustment.of(BusinessDayConventions.FOLLOWING, EUTA); + private static final PeriodicSchedule SCHEDULE = PeriodicSchedule.builder() + .startDate(START) + .endDate(END) + .frequency(FREQUENCY) + .businessDayAdjustment(BUSS_ADJ) + .build(); + private static final DaysAdjustment PAYMENT_OFFSET = DaysAdjustment.ofBusinessDays(2, EUTA); + private static final ValueSchedule CAP = ValueSchedule.of(0.0325); + private static final ValueSchedule NOTIONAL = ValueSchedule.of(1.0e6); + private static final OvernightInArrearsCapFloorLeg CAPFLOOR_LEG = OvernightInArrearsCapFloorLeg.builder() + .calculation(RATE_CALCULATION) + .capSchedule(CAP) + .notional(NOTIONAL) + .paymentDateOffset(PAYMENT_OFFSET) + .paymentSchedule(SCHEDULE) + .payReceive(RECEIVE) + .build(); + private static final SwapLeg PAY_LEG = RateCalculationSwapLeg.builder() + .payReceive(PAY) + .accrualSchedule(SCHEDULE) + .calculation( + FixedRateCalculation.of(0.001, ACT_360)) + .paymentSchedule( + PaymentSchedule.builder() + .paymentFrequency(FREQUENCY) + .paymentDateOffset(DaysAdjustment.NONE) + .build()) + .notionalSchedule( + NotionalSchedule.of(EUR, NOTIONAL)) + .build(); + private static final SwapLeg PAY_LEG_XCCY = RateCalculationSwapLeg.builder() + .payReceive(PAY) + .accrualSchedule(SCHEDULE) + .calculation( + OvernightRateCalculation.of(GBP_SONIA)) + .paymentSchedule( + PaymentSchedule.builder() + .paymentFrequency(FREQUENCY) + .paymentDateOffset(DaysAdjustment.NONE) + .build()) + .notionalSchedule( + NotionalSchedule.of(GBP, NOTIONAL)) + .build(); + + @Test + public void test_of_oneLeg() { + OvernightInArrearsCapFloor test = OvernightInArrearsCapFloor.of(CAPFLOOR_LEG); + assertThat(test.getCapFloorLeg()).isEqualTo(CAPFLOOR_LEG); + assertThat(test.getPayLeg()).isNotPresent(); + assertThat(test.isCrossCurrency()).isFalse(); + assertThat(test.allPaymentCurrencies()).containsOnly(EUR); + assertThat(test.allCurrencies()).containsOnly(EUR); + assertThat(test.allIndices()).containsOnly(EUR_ESTR); + } + + @Test + public void test_of_twoLegs() { + OvernightInArrearsCapFloor test = OvernightInArrearsCapFloor.of(CAPFLOOR_LEG, PAY_LEG); + assertThat(test.getCapFloorLeg()).isEqualTo(CAPFLOOR_LEG); + assertThat(test.getPayLeg().get()).isEqualTo(PAY_LEG); + assertThat(test.isCrossCurrency()).isFalse(); + assertThat(test.allPaymentCurrencies()).containsOnly(EUR); + assertThat(test.allCurrencies()).containsOnly(EUR); + assertThat(test.allIndices()).containsOnly(EUR_ESTR); + } + + @Test + public void test_of_twoLegs_xccy() { + OvernightInArrearsCapFloor test = OvernightInArrearsCapFloor.of(CAPFLOOR_LEG, PAY_LEG_XCCY); + assertThat(test.getCapFloorLeg()).isEqualTo(CAPFLOOR_LEG); + assertThat(test.getPayLeg().get()).isEqualTo(PAY_LEG_XCCY); + assertThat(test.isCrossCurrency()).isTrue(); + assertThat(test.allPaymentCurrencies()).containsOnly(GBP, EUR); + assertThat(test.allCurrencies()).containsOnly(GBP, EUR); + assertThat(test.allIndices()).containsOnly(GBP_SONIA, EUR_ESTR); + } + + @Test + public void test_resolve_oneLeg() { + OvernightInArrearsCapFloor base = OvernightInArrearsCapFloor.of(CAPFLOOR_LEG); + ResolvedOvernightInArrearsCapFloor test = base.resolve(REF_DATA); + assertThat(test.getCapFloorLeg()).isEqualTo(CAPFLOOR_LEG.resolve(REF_DATA)); + assertThat(test.getPayLeg()).isNotPresent(); + } + + @Test + public void test_resolve_twoLegs() { + OvernightInArrearsCapFloor base = OvernightInArrearsCapFloor.of(CAPFLOOR_LEG, PAY_LEG); + ResolvedOvernightInArrearsCapFloor test = base.resolve(REF_DATA); + assertThat(test.getCapFloorLeg()).isEqualTo(CAPFLOOR_LEG.resolve(REF_DATA)); + assertThat(test.getPayLeg().get()).isEqualTo(PAY_LEG.resolve(REF_DATA)); + } + + //------------------------------------------------------------------------- + @Test + public void coverage() { + OvernightInArrearsCapFloor test1 = OvernightInArrearsCapFloor.of(CAPFLOOR_LEG); + coverImmutableBean(test1); + OvernightInArrearsCapFloorLeg capFloor = OvernightInArrearsCapFloorLeg.builder() + .calculation(RATE_CALCULATION) + .floorSchedule(CAP) + .notional(NOTIONAL) + .paymentDateOffset(PAYMENT_OFFSET) + .paymentSchedule(SCHEDULE) + .payReceive(RECEIVE) + .build(); + OvernightInArrearsCapFloor test2 = OvernightInArrearsCapFloor.of(capFloor, PAY_LEG); + coverBeanEquals(test1, test2); + } + + @Test + public void test_serialization() { + OvernightInArrearsCapFloor test = OvernightInArrearsCapFloor.of(CAPFLOOR_LEG); + assertSerialization(test); + } + +} diff --git a/modules/product/src/test/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapFloorTradeTest.java b/modules/product/src/test/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapFloorTradeTest.java new file mode 100644 index 0000000000..50154a3081 --- /dev/null +++ b/modules/product/src/test/java/com/opengamma/strata/product/capfloor/OvernightInArrearsCapFloorTradeTest.java @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.product.capfloor; + +import static com.opengamma.strata.basics.currency.Currency.EUR; +import static com.opengamma.strata.basics.date.HolidayCalendarIds.EUTA; +import static com.opengamma.strata.basics.index.OvernightIndices.EUR_ESTR; +import static com.opengamma.strata.collect.TestHelper.assertSerialization; +import static com.opengamma.strata.collect.TestHelper.coverBeanEquals; +import static com.opengamma.strata.collect.TestHelper.coverImmutableBean; +import static com.opengamma.strata.product.common.PayReceive.PAY; +import static com.opengamma.strata.product.common.PayReceive.RECEIVE; +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.LocalDate; + +import org.junit.jupiter.api.Test; + +import com.opengamma.strata.basics.ReferenceData; +import com.opengamma.strata.basics.currency.AdjustablePayment; +import com.opengamma.strata.basics.currency.Currency; +import com.opengamma.strata.basics.currency.CurrencyAmount; +import com.opengamma.strata.basics.date.BusinessDayAdjustment; +import com.opengamma.strata.basics.date.BusinessDayConventions; +import com.opengamma.strata.basics.date.DaysAdjustment; +import com.opengamma.strata.basics.schedule.Frequency; +import com.opengamma.strata.basics.schedule.PeriodicSchedule; +import com.opengamma.strata.basics.value.ValueSchedule; +import com.opengamma.strata.product.PortfolioItemSummary; +import com.opengamma.strata.product.PortfolioItemType; +import com.opengamma.strata.product.ProductType; +import com.opengamma.strata.product.TradeInfo; +import com.opengamma.strata.product.swap.OvernightRateCalculation; + +/** + * Test {@link OvernightInArrearsCapFloorTrade}. + */ +public class OvernightInArrearsCapFloorTradeTest { + + private static final ReferenceData REF_DATA = ReferenceData.standard(); + private static final LocalDate START = LocalDate.of(2011, 3, 17); + private static final LocalDate END = LocalDate.of(2016, 3, 17); + private static final OvernightRateCalculation RATE_CALCULATION = OvernightRateCalculation.of(EUR_ESTR); + private static final Frequency FREQUENCY = Frequency.P3M; + private static final BusinessDayAdjustment BUSS_ADJ = + BusinessDayAdjustment.of(BusinessDayConventions.FOLLOWING, EUTA); + private static final PeriodicSchedule SCHEDULE = PeriodicSchedule.builder() + .startDate(START) + .endDate(END) + .frequency(FREQUENCY) + .businessDayAdjustment(BUSS_ADJ) + .build(); + private static final DaysAdjustment PAYMENT_OFFSET = DaysAdjustment.ofBusinessDays(2, EUTA); + private static final ValueSchedule CAP = ValueSchedule.of(0.0325); + private static final double NOTIONAL_VALUE = 1.0e6; + private static final ValueSchedule NOTIONAL = ValueSchedule.of(NOTIONAL_VALUE); + private static final OvernightInArrearsCapFloorLeg CAP_LEG = OvernightInArrearsCapFloorLeg.builder() + .calculation(RATE_CALCULATION) + .capSchedule(CAP) + .notional(NOTIONAL) + .paymentDateOffset(PAYMENT_OFFSET) + .paymentSchedule(SCHEDULE) + .payReceive(RECEIVE) + .build(); + private static final OvernightInArrearsCapFloorLeg FLOOR_LEG = OvernightInArrearsCapFloorLeg.builder() + .calculation(RATE_CALCULATION) + .floorSchedule(CAP) + .notional(NOTIONAL) + .paymentDateOffset(PAYMENT_OFFSET) + .paymentSchedule(SCHEDULE) + .payReceive(RECEIVE) + .build(); + private static final OvernightInArrearsCapFloor PRODUCT = OvernightInArrearsCapFloor.of(CAP_LEG); + private static final OvernightInArrearsCapFloor PRODUCT_FLOOR = OvernightInArrearsCapFloor.of(FLOOR_LEG); + private static final AdjustablePayment PREMIUM = + AdjustablePayment.of(CurrencyAmount.of(EUR, NOTIONAL_VALUE), LocalDate.of(2011, 3, 18)); + private static final TradeInfo TRADE_INFO = TradeInfo.builder() + .tradeDate(LocalDate.of(2011, 3, 15)) + .build(); + + //------------------------------------------------------------------------- + @Test + public void test_builder_full() { + OvernightInArrearsCapFloorTrade test = sut(); + assertThat(test.getPremium().get()).isEqualTo(PREMIUM); + assertThat(test.getProduct()).isEqualTo(PRODUCT); + assertThat(test.getInfo()).isEqualTo(TRADE_INFO); + assertThat(test.withInfo(TRADE_INFO).getInfo()).isEqualTo(TRADE_INFO); + } + + @Test + public void test_builder_min() { + OvernightInArrearsCapFloorTrade test = OvernightInArrearsCapFloorTrade.builder() + .product(PRODUCT) + .build(); + assertThat(test.getPremium()).isNotPresent(); + assertThat(test.getProduct()).isEqualTo(PRODUCT); + assertThat(test.getInfo()).isEqualTo(TradeInfo.empty()); + } + + //------------------------------------------------------------------------- + @Test + public void test_summarize() { + OvernightInArrearsCapFloorTrade trade = sut(); + PortfolioItemSummary expected = PortfolioItemSummary.builder() + .id(TRADE_INFO.getId().orElse(null)) + .portfolioItemType(PortfolioItemType.TRADE) + .productType(ProductType.OVERNIGHT_IN_ARREARS_CAP_FLOOR) + .currencies(Currency.EUR) + .description("5Y EUR 1mm Rec Compounded EUR-ESTR Cap 3.25% / Pay Premium : 17Mar11-17Mar16") + .build(); + assertThat(trade.summarize()).isEqualTo(expected); + } + + @Test + public void test_summarize_floor() { + OvernightInArrearsCapFloorTrade trade = OvernightInArrearsCapFloorTrade.builder() + .info(TRADE_INFO) + .product(PRODUCT_FLOOR) + .build(); + PortfolioItemSummary expected = PortfolioItemSummary.builder() + .id(TRADE_INFO.getId().orElse(null)) + .portfolioItemType(PortfolioItemType.TRADE) + .productType(ProductType.OVERNIGHT_IN_ARREARS_CAP_FLOOR) + .currencies(Currency.EUR) + .description("5Y EUR 1mm Rec Compounded EUR-ESTR Floor 3.25% : 17Mar11-17Mar16") + .build(); + assertThat(trade.summarize()).isEqualTo(expected); + } + + //------------------------------------------------------------------------- + @Test + public void test_resolve() { + OvernightInArrearsCapFloorTrade test = sut(); + ResolvedOvernightInArrearsCapFloorTrade expected = ResolvedOvernightInArrearsCapFloorTrade.builder() + .info(TRADE_INFO) + .product(PRODUCT.resolve(REF_DATA)) + .premium(PREMIUM.resolve(REF_DATA)) + .build(); + assertThat(test.resolve(REF_DATA)).isEqualTo(expected); + } + + @Test + public void test_resolve_noPremium() { + OvernightInArrearsCapFloorTrade test = OvernightInArrearsCapFloorTrade.builder() + .info(TRADE_INFO) + .product(PRODUCT) + .build(); + ResolvedOvernightInArrearsCapFloorTrade expected = ResolvedOvernightInArrearsCapFloorTrade.builder() + .info(TRADE_INFO) + .product(PRODUCT.resolve(REF_DATA)) + .build(); + assertThat(test.resolve(REF_DATA)).isEqualTo(expected); + } + + //------------------------------------------------------------------------- + @Test + public void coverage() { + OvernightInArrearsCapFloorTrade test1 = sut(); + coverImmutableBean(test1); + OvernightInArrearsCapFloor product = OvernightInArrearsCapFloor.of( + OvernightInArrearsCapFloorLeg.builder() + .calculation(RATE_CALCULATION) + .floorSchedule(CAP) + .notional(NOTIONAL) + .paymentDateOffset(PAYMENT_OFFSET) + .paymentSchedule(SCHEDULE) + .payReceive(PAY) + .build()); + OvernightInArrearsCapFloorTrade test2 = OvernightInArrearsCapFloorTrade.builder() + .product(product) + .build(); + coverBeanEquals(test1, test2); + } + + @Test + public void test_serialization() { + OvernightInArrearsCapFloorTrade test = sut(); + assertSerialization(test); + } + + //------------------------------------------------------------------------- + OvernightInArrearsCapFloorTrade sut() { + return OvernightInArrearsCapFloorTrade.builder() + .info(TRADE_INFO) + .product(PRODUCT) + .premium(PREMIUM) + .build(); + } + +} diff --git a/modules/product/src/test/java/com/opengamma/strata/product/capfloor/ResolvedOvernightInArrearsCapFloorLegTest.java b/modules/product/src/test/java/com/opengamma/strata/product/capfloor/ResolvedOvernightInArrearsCapFloorLegTest.java new file mode 100644 index 0000000000..85bf954d3e --- /dev/null +++ b/modules/product/src/test/java/com/opengamma/strata/product/capfloor/ResolvedOvernightInArrearsCapFloorLegTest.java @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.product.capfloor; + +import static com.opengamma.strata.basics.currency.Currency.EUR; +import static com.opengamma.strata.basics.currency.Currency.GBP; +import static com.opengamma.strata.basics.index.OvernightIndices.EUR_ESTR; +import static com.opengamma.strata.basics.index.OvernightIndices.GBP_SONIA; +import static com.opengamma.strata.collect.TestHelper.assertSerialization; +import static com.opengamma.strata.collect.TestHelper.coverBeanEquals; +import static com.opengamma.strata.collect.TestHelper.coverImmutableBean; +import static com.opengamma.strata.product.common.PayReceive.PAY; +import static com.opengamma.strata.product.common.PayReceive.RECEIVE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +import java.time.LocalDate; + +import org.junit.jupiter.api.Test; + +import com.opengamma.strata.basics.ReferenceData; +import com.opengamma.strata.product.rate.OvernightCompoundedRateComputation; + +/** + * Test {@link ResolvedOvernightInArrearsCapFloorLeg}. + */ +public class ResolvedOvernightInArrearsCapFloorLegTest { + + private static final ReferenceData REF_DATA = ReferenceData.standard(); + private static final double STRIKE = 0.0125; + private static final double NOTIONAL = 1.0e6; + private static final OvernightInArrearsCapletFloorletPeriod PERIOD_1 = OvernightInArrearsCapletFloorletPeriod.builder() + .caplet(STRIKE) + .notional(NOTIONAL) + .currency(EUR) + .startDate(LocalDate.of(2011, 3, 17)) + .endDate(LocalDate.of(2011, 6, 17)) + .unadjustedStartDate(LocalDate.of(2011, 3, 17)) + .unadjustedEndDate(LocalDate.of(2011, 6, 17)) + .paymentDate(LocalDate.of(2011, 6, 21)) + .overnightRate(OvernightCompoundedRateComputation.of( + EUR_ESTR, + LocalDate.of(2011, 3, 17), + LocalDate.of(2011, 6, 17), + REF_DATA)) + .yearFraction(0.2556) + .build(); + private static final OvernightInArrearsCapletFloorletPeriod PERIOD_2 = OvernightInArrearsCapletFloorletPeriod.builder() + .caplet(STRIKE) + .notional(NOTIONAL) + .currency(EUR) + .startDate(LocalDate.of(2011, 6, 17)) + .endDate(LocalDate.of(2011, 9, 19)) + .unadjustedStartDate(LocalDate.of(2011, 6, 17)) + .unadjustedEndDate(LocalDate.of(2011, 9, 17)) + .paymentDate(LocalDate.of(2011, 9, 21)) + .overnightRate(OvernightCompoundedRateComputation.of( + EUR_ESTR, + LocalDate.of(2011, 6, 17), + LocalDate.of(2011, 9, 17), + REF_DATA)) + .yearFraction(0.2611) + .build(); + private static final OvernightInArrearsCapletFloorletPeriod PERIOD_3 = OvernightInArrearsCapletFloorletPeriod.builder() + .caplet(STRIKE) + .notional(NOTIONAL) + .currency(EUR) + .startDate(LocalDate.of(2011, 9, 19)) + .endDate(LocalDate.of(2011, 12, 19)) + .unadjustedStartDate(LocalDate.of(2011, 9, 17)) + .unadjustedEndDate(LocalDate.of(2011, 12, 17)) + .paymentDate(LocalDate.of(2011, 12, 21)) + .overnightRate(OvernightCompoundedRateComputation.of( + EUR_ESTR, + LocalDate.of(2011, 9, 17), + LocalDate.of(2011, 12, 17), + REF_DATA)) + .yearFraction(0.2528) + .build(); + private static final OvernightInArrearsCapletFloorletPeriod PERIOD_4 = OvernightInArrearsCapletFloorletPeriod.builder() + .caplet(STRIKE) + .notional(NOTIONAL) + .currency(EUR) + .startDate(LocalDate.of(2011, 12, 19)) + .endDate(LocalDate.of(2012, 3, 19)) + .unadjustedStartDate(LocalDate.of(2011, 12, 17)) + .unadjustedEndDate(LocalDate.of(2012, 3, 17)) + .paymentDate(LocalDate.of(2012, 3, 21)) + .overnightRate(OvernightCompoundedRateComputation.of( + EUR_ESTR, + LocalDate.of(2011, 12, 17), + LocalDate.of(2012, 3, 17), + REF_DATA)) + .yearFraction(0.2528) + .build(); + + @Test + public void test_builder() { + ResolvedOvernightInArrearsCapFloorLeg test = ResolvedOvernightInArrearsCapFloorLeg.builder() + .capletFloorletPeriods(PERIOD_1, PERIOD_2, PERIOD_3, PERIOD_4) + .payReceive(RECEIVE) + .build(); + assertThat(test.getCapletFloorletPeriods()).containsExactly(PERIOD_1, PERIOD_2, PERIOD_3, PERIOD_4); + assertThat(test.getPayReceive()).isEqualTo(RECEIVE); + assertThat(test.getStartDate()).isEqualTo(PERIOD_1.getStartDate()); + assertThat(test.getEndDate()).isEqualTo(PERIOD_4.getEndDate()); + assertThat(test.getFinalPeriod()).isEqualTo(PERIOD_4); + assertThat(test.getCurrency()).isEqualTo(EUR); + assertThat(test.getIndex()).isEqualTo(EUR_ESTR); + } + + @Test + public void test_builder_fail() { + // two currencies + OvernightInArrearsCapletFloorletPeriod periodGbp = OvernightInArrearsCapletFloorletPeriod.builder() + .caplet(STRIKE) + .notional(NOTIONAL) + .currency(GBP) + .startDate(LocalDate.of(2011, 6, 17)) + .endDate(LocalDate.of(2011, 9, 19)) + .unadjustedStartDate(LocalDate.of(2011, 6, 17)) + .unadjustedEndDate(LocalDate.of(2011, 9, 17)) + .paymentDate(LocalDate.of(2011, 9, 21)) + .overnightRate(OvernightCompoundedRateComputation.of( + EUR_ESTR, + LocalDate.of(2011, 6, 17), + LocalDate.of(2011, 9, 17), + REF_DATA)) + .yearFraction(0.2611) + .build(); + assertThatIllegalArgumentException() + .isThrownBy(() -> ResolvedOvernightInArrearsCapFloorLeg.builder() + .capletFloorletPeriods(PERIOD_1, periodGbp) + .payReceive(RECEIVE) + .build()); + // two indices + OvernightInArrearsCapletFloorletPeriod period = OvernightInArrearsCapletFloorletPeriod.builder() + .caplet(STRIKE) + .notional(NOTIONAL) + .currency(EUR) + .startDate(LocalDate.of(2011, 6, 17)) + .endDate(LocalDate.of(2011, 9, 19)) + .unadjustedStartDate(LocalDate.of(2011, 6, 17)) + .unadjustedEndDate(LocalDate.of(2011, 9, 17)) + .paymentDate(LocalDate.of(2011, 9, 21)).overnightRate(OvernightCompoundedRateComputation.of( + GBP_SONIA, + LocalDate.of(2011, 6, 17), + LocalDate.of(2011, 9, 17), + REF_DATA)) + .yearFraction(0.2611) + .build(); + assertThatIllegalArgumentException() + .isThrownBy(() -> ResolvedOvernightInArrearsCapFloorLeg.builder() + .capletFloorletPeriods(PERIOD_1, period) + .payReceive(RECEIVE) + .build()); + } + + //------------------------------------------------------------------------- + @Test + public void coverage() { + ResolvedOvernightInArrearsCapFloorLeg test1 = ResolvedOvernightInArrearsCapFloorLeg.builder() + .capletFloorletPeriods(PERIOD_1, PERIOD_2, PERIOD_3, PERIOD_4) + .payReceive(RECEIVE) + .build(); + coverImmutableBean(test1); + ResolvedOvernightInArrearsCapFloorLeg test2 = ResolvedOvernightInArrearsCapFloorLeg.builder() + .capletFloorletPeriods(PERIOD_2, PERIOD_3) + .payReceive(PAY) + .build(); + coverBeanEquals(test1, test2); + } + + @Test + public void test_serialization() { + ResolvedOvernightInArrearsCapFloorLeg test = ResolvedOvernightInArrearsCapFloorLeg.builder() + .capletFloorletPeriods(PERIOD_1, PERIOD_2, PERIOD_3, PERIOD_4) + .payReceive(RECEIVE) + .build(); + assertSerialization(test); + } + +} diff --git a/modules/product/src/test/java/com/opengamma/strata/product/capfloor/ResolvedOvernightInArrearsCapFloorTest.java b/modules/product/src/test/java/com/opengamma/strata/product/capfloor/ResolvedOvernightInArrearsCapFloorTest.java new file mode 100644 index 0000000000..07c38ac87f --- /dev/null +++ b/modules/product/src/test/java/com/opengamma/strata/product/capfloor/ResolvedOvernightInArrearsCapFloorTest.java @@ -0,0 +1,176 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.product.capfloor; + +import static com.opengamma.strata.basics.currency.Currency.EUR; +import static com.opengamma.strata.basics.date.DayCounts.ACT_365F; +import static com.opengamma.strata.basics.index.OvernightIndices.EUR_ESTR; +import static com.opengamma.strata.collect.TestHelper.assertSerialization; +import static com.opengamma.strata.collect.TestHelper.coverBeanEquals; +import static com.opengamma.strata.collect.TestHelper.coverImmutableBean; +import static com.opengamma.strata.product.common.PayReceive.PAY; +import static com.opengamma.strata.product.common.PayReceive.RECEIVE; +import static com.opengamma.strata.product.swap.SwapLegType.FIXED; +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.LocalDate; + +import org.junit.jupiter.api.Test; + +import com.opengamma.strata.basics.ReferenceData; +import com.opengamma.strata.product.rate.FixedRateComputation; +import com.opengamma.strata.product.rate.OvernightCompoundedRateComputation; +import com.opengamma.strata.product.swap.RateAccrualPeriod; +import com.opengamma.strata.product.swap.RatePaymentPeriod; +import com.opengamma.strata.product.swap.ResolvedSwapLeg; + +/** + * Test {@link ResolvedOvernightInArrearsCapFloor}. + */ +public class ResolvedOvernightInArrearsCapFloorTest { + + private static final ReferenceData REF_DATA = ReferenceData.standard(); + private static final double STRIKE = 0.0125; + private static final double NOTIONAL = 1.0e6; + private static final OvernightInArrearsCapletFloorletPeriod PERIOD_1 = OvernightInArrearsCapletFloorletPeriod.builder() + .caplet(STRIKE) + .notional(NOTIONAL) + .currency(EUR) + .startDate(LocalDate.of(2011, 3, 17)) + .endDate(LocalDate.of(2011, 6, 17)) + .unadjustedStartDate(LocalDate.of(2011, 3, 17)) + .unadjustedEndDate(LocalDate.of(2011, 6, 17)) + .paymentDate(LocalDate.of(2011, 6, 21)) + .overnightRate(OvernightCompoundedRateComputation.of( + EUR_ESTR, + LocalDate.of(2011, 3, 17), + LocalDate.of(2011, 6, 17), + REF_DATA)) + .yearFraction(0.2556) + .build(); + private static final OvernightInArrearsCapletFloorletPeriod PERIOD_2 = OvernightInArrearsCapletFloorletPeriod.builder() + .caplet(STRIKE) + .notional(NOTIONAL) + .currency(EUR) + .startDate(LocalDate.of(2011, 6, 17)) + .endDate(LocalDate.of(2011, 9, 19)) + .unadjustedStartDate(LocalDate.of(2011, 6, 17)) + .unadjustedEndDate(LocalDate.of(2011, 9, 17)) + .paymentDate(LocalDate.of(2011, 9, 21)) + .overnightRate(OvernightCompoundedRateComputation.of( + EUR_ESTR, + LocalDate.of(2011, 6, 17), + LocalDate.of(2011, 9, 17), + REF_DATA)) + .yearFraction(0.2611) + .build(); + private static final OvernightInArrearsCapletFloorletPeriod PERIOD_3 = OvernightInArrearsCapletFloorletPeriod.builder() + .caplet(STRIKE) + .notional(NOTIONAL) + .currency(EUR) + .startDate(LocalDate.of(2011, 9, 19)) + .endDate(LocalDate.of(2011, 12, 19)) + .unadjustedStartDate(LocalDate.of(2011, 9, 17)) + .unadjustedEndDate(LocalDate.of(2011, 12, 17)) + .paymentDate(LocalDate.of(2011, 12, 21)) + .overnightRate(OvernightCompoundedRateComputation.of( + EUR_ESTR, + LocalDate.of(2011, 9, 17), + LocalDate.of(2011, 12, 17), + REF_DATA)) + .yearFraction(0.2528) + .build(); + private static final OvernightInArrearsCapletFloorletPeriod PERIOD_4 = OvernightInArrearsCapletFloorletPeriod.builder() + .caplet(STRIKE) + .notional(NOTIONAL) + .currency(EUR) + .startDate(LocalDate.of(2011, 12, 19)) + .endDate(LocalDate.of(2012, 3, 19)) + .unadjustedStartDate(LocalDate.of(2011, 12, 17)) + .unadjustedEndDate(LocalDate.of(2012, 3, 17)) + .paymentDate(LocalDate.of(2012, 3, 21)) + .overnightRate(OvernightCompoundedRateComputation.of( + EUR_ESTR, + LocalDate.of(2011, 12, 17), + LocalDate.of(2012, 3, 17), + REF_DATA)) + .yearFraction(0.2528) + .build(); + static final ResolvedOvernightInArrearsCapFloorLeg CAPFLOOR_LEG = ResolvedOvernightInArrearsCapFloorLeg.builder() + .capletFloorletPeriods(PERIOD_1, PERIOD_2, PERIOD_3, PERIOD_4) + .payReceive(RECEIVE) + .build(); + + private static final double RATE = 0.015; + private static final RatePaymentPeriod PAY_PERIOD_1 = RatePaymentPeriod.builder() + .paymentDate(LocalDate.of(2011, 9, 21)) + .accrualPeriods(RateAccrualPeriod.builder() + .startDate(LocalDate.of(2011, 3, 17)) + .endDate(LocalDate.of(2011, 9, 19)) + .yearFraction(0.517) + .rateComputation(FixedRateComputation.of(RATE)) + .build()) + .dayCount(ACT_365F) + .currency(EUR) + .notional(-NOTIONAL) + .build(); + private static final RatePaymentPeriod PAY_PERIOD_2 = RatePaymentPeriod.builder() + .paymentDate(LocalDate.of(2012, 3, 21)) + .accrualPeriods(RateAccrualPeriod.builder() + .startDate(LocalDate.of(2011, 9, 19)) + .endDate(LocalDate.of(2012, 3, 19)) + .yearFraction(0.505) + .rateComputation(FixedRateComputation.of(RATE)) + .build()) + .dayCount(ACT_365F) + .currency(EUR) + .notional(-NOTIONAL) + .build(); + static final ResolvedSwapLeg PAY_LEG = ResolvedSwapLeg.builder() + .paymentPeriods(PAY_PERIOD_1, PAY_PERIOD_2) + .type(FIXED) + .payReceive(PAY) + .build(); + + //------------------------------------------------------------------------- + @Test + public void test_of_oneLeg() { + ResolvedOvernightInArrearsCapFloor test = ResolvedOvernightInArrearsCapFloor.of(CAPFLOOR_LEG); + assertThat(test.getCapFloorLeg()).isEqualTo(CAPFLOOR_LEG); + assertThat(test.getPayLeg()).isNotPresent(); + assertThat(test.allPaymentCurrencies()).containsOnly(EUR); + assertThat(test.allIndices()).containsOnly(EUR_ESTR); + } + + @Test + public void test_of_twoLegs() { + ResolvedOvernightInArrearsCapFloor test = ResolvedOvernightInArrearsCapFloor.of(CAPFLOOR_LEG, PAY_LEG); + assertThat(test.getCapFloorLeg()).isEqualTo(CAPFLOOR_LEG); + assertThat(test.getPayLeg().get()).isEqualTo(PAY_LEG); + assertThat(test.allPaymentCurrencies()).containsOnly(EUR); + assertThat(test.allIndices()).containsOnly(EUR_ESTR); + } + + //------------------------------------------------------------------------- + @Test + public void coverage() { + ResolvedOvernightInArrearsCapFloor test1 = ResolvedOvernightInArrearsCapFloor.of(CAPFLOOR_LEG, PAY_LEG); + coverImmutableBean(test1); + ResolvedOvernightInArrearsCapFloorLeg capFloor = ResolvedOvernightInArrearsCapFloorLeg.builder() + .capletFloorletPeriods(PERIOD_1) + .payReceive(PAY) + .build(); + ResolvedOvernightInArrearsCapFloor test2 = ResolvedOvernightInArrearsCapFloor.of(capFloor); + coverBeanEquals(test1, test2); + } + + @Test + public void test_serialization() { + ResolvedOvernightInArrearsCapFloor test = ResolvedOvernightInArrearsCapFloor.of(CAPFLOOR_LEG); + assertSerialization(test); + } + +} diff --git a/modules/product/src/test/java/com/opengamma/strata/product/capfloor/ResolvedOvernightInArrearsCapFloorTradeTest.java b/modules/product/src/test/java/com/opengamma/strata/product/capfloor/ResolvedOvernightInArrearsCapFloorTradeTest.java new file mode 100644 index 0000000000..f51940a15b --- /dev/null +++ b/modules/product/src/test/java/com/opengamma/strata/product/capfloor/ResolvedOvernightInArrearsCapFloorTradeTest.java @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.product.capfloor; + +import static com.opengamma.strata.basics.currency.Currency.EUR; +import static com.opengamma.strata.collect.TestHelper.assertSerialization; +import static com.opengamma.strata.collect.TestHelper.coverBeanEquals; +import static com.opengamma.strata.collect.TestHelper.coverImmutableBean; +import static com.opengamma.strata.collect.TestHelper.date; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Optional; + +import org.junit.jupiter.api.Test; + +import com.opengamma.strata.basics.currency.CurrencyAmount; +import com.opengamma.strata.basics.currency.Payment; +import com.opengamma.strata.product.TradeInfo; + +/** + * Test {@link ResolvedOvernightInArrearsCapFloorTrade}. + */ +public class ResolvedOvernightInArrearsCapFloorTradeTest { + + private static final TradeInfo TRADE_INFO = TradeInfo.of(date(2016, 6, 30)); + private static final ResolvedOvernightInArrearsCapFloor PRODUCT = ResolvedOvernightInArrearsCapFloor.of( + ResolvedOvernightInArrearsCapFloorTest.CAPFLOOR_LEG, + ResolvedOvernightInArrearsCapFloorTest.PAY_LEG); + private static final Payment PREMIUM = Payment.of(CurrencyAmount.of(EUR, -0.001 * 1.0e6), date(2016, 7, 2)); + + //------------------------------------------------------------------------- + @Test + public void test_builder() { + ResolvedOvernightInArrearsCapFloorTrade test = ResolvedOvernightInArrearsCapFloorTrade.builder() + .product(PRODUCT) + .build(); + assertThat(test.getInfo()).isEqualTo(TradeInfo.empty()); + assertThat(test.getProduct()).isEqualTo(PRODUCT); + assertThat(test.getPremium()).isEqualTo(Optional.empty()); + } + + @Test + public void test_builder_full() { + ResolvedOvernightInArrearsCapFloorTrade test = ResolvedOvernightInArrearsCapFloorTrade.builder() + .info(TRADE_INFO) + .product(PRODUCT) + .premium(PREMIUM) + .build(); + assertThat(test.getInfo()).isEqualTo(TRADE_INFO); + assertThat(test.getProduct()).isEqualTo(PRODUCT); + assertThat(test.getPremium()).isEqualTo(Optional.of(PREMIUM)); + } + + //------------------------------------------------------------------------- + @Test + public void coverage() { + ResolvedOvernightInArrearsCapFloorTrade test = ResolvedOvernightInArrearsCapFloorTrade.builder() + .info(TRADE_INFO) + .product(PRODUCT) + .premium(PREMIUM) + .build(); + coverImmutableBean(test); + ResolvedOvernightInArrearsCapFloorTrade test2 = ResolvedOvernightInArrearsCapFloorTrade.builder() + .product(PRODUCT) + .build(); + coverBeanEquals(test, test2); + } + + @Test + public void test_serialization() { + ResolvedOvernightInArrearsCapFloorTrade test = ResolvedOvernightInArrearsCapFloorTrade.builder() + .product(PRODUCT) + .build(); + assertSerialization(test); + } + +} From 748caa95841d86c84400486f55bf0297d01403d9 Mon Sep 17 00:00:00 2001 From: Andras Vig <93195277+Andras1022@users.noreply.github.com> Date: Wed, 16 Oct 2024 15:44:02 +0200 Subject: [PATCH 107/116] Adding Inauguration Day to MXMC (#2678) * PROD-42681: Adding Inauguration Day to MXMC * PROD-42681: Adding Inauguration Day to MXMC --- .../basics/date/GlobalHolidayCalendars.java | 7 ++++++- .../date/GlobalHolidayCalendarsTest.java | 2 ++ .../basics/date/GlobalHolidayCalendars.bin | Bin 0 -> 178050 bytes 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 src/main/resources/com/opengamma/strata/basics/date/GlobalHolidayCalendars.bin diff --git a/modules/basics/src/main/java/com/opengamma/strata/basics/date/GlobalHolidayCalendars.java b/modules/basics/src/main/java/com/opengamma/strata/basics/date/GlobalHolidayCalendars.java index 2ddc39b5a5..e3394ab0f9 100644 --- a/modules/basics/src/main/java/com/opengamma/strata/basics/date/GlobalHolidayCalendars.java +++ b/modules/basics/src/main/java/com/opengamma/strata/basics/date/GlobalHolidayCalendars.java @@ -1169,6 +1169,7 @@ private static void addHungarianSaturdays(List holidays, Set holidays = new ArrayList<>(2000); for (int year = 1950; year <= 2099; year++) { @@ -1186,6 +1187,10 @@ static ImmutableHolidayCalendar generateMexicoCity() { holidays.add(date(year, 5, 1)); // independence holidays.add(date(year, 9, 16)); + // inaguration day - occurring once in every 6 years (2024, 2030, etc). + if (year >= 2024 && (year + 4) % 6 == 0) { + holidays.add(date(year, 10, 1)); + } // dead holidays.add(date(year, 11, 2)); // revolution @@ -1196,7 +1201,7 @@ static ImmutableHolidayCalendar generateMexicoCity() { holidays.add(date(year, 12, 25)); } removeSatSun(holidays); - return ImmutableHolidayCalendar.of(HolidayCalendarId.of("MXMC"), holidays, SATURDAY, SUNDAY); + return ImmutableHolidayCalendar.of(HolidayCalendarIds.MXMC, holidays, SATURDAY, SUNDAY); } // generate BRBD diff --git a/modules/basics/src/test/java/com/opengamma/strata/basics/date/GlobalHolidayCalendarsTest.java b/modules/basics/src/test/java/com/opengamma/strata/basics/date/GlobalHolidayCalendarsTest.java index 29d36327ec..53c854a798 100644 --- a/modules/basics/src/test/java/com/opengamma/strata/basics/date/GlobalHolidayCalendarsTest.java +++ b/modules/basics/src/test/java/com/opengamma/strata/basics/date/GlobalHolidayCalendarsTest.java @@ -944,6 +944,8 @@ public static Object[][] data_mxmc() { md(5, 1), md(9, 16), md(11, 2), md(11, 16), md(12, 12), md(12, 25))}, {2016, mds(2016, md(1, 1), md(2, 1), md(3, 21), md(3, 24), md(3, 25), md(5, 1), md(9, 16), md(11, 2), md(11, 21), md(12, 12), md(12, 25))}, + {2024, mds(2024, md(1, 1), md(2, 5), md(3, 18), md(3, 28), md(3, 29), + md(5, 1), md(9, 16), md(10, 1), md(11, 2), md(11, 18), md(12, 12), md(12, 25))}, }; } diff --git a/src/main/resources/com/opengamma/strata/basics/date/GlobalHolidayCalendars.bin b/src/main/resources/com/opengamma/strata/basics/date/GlobalHolidayCalendars.bin new file mode 100644 index 0000000000000000000000000000000000000000..5599a791a5c8ee428b52049b0ad8b59064fbcd2c GIT binary patch literal 178050 zcmeIbO^jpNl_r+sN+4R8nxugMraRp9BVfr2*bowGaUdjX9tfAR)!AsN#YR^PGin4d z5=v6c0JX>}7GM%4dLzKOFfg&}GN#nzvetHOIsq>%1l-|KP8E$VFQzuOve}s&t(+0u zBr(14_nrIm-Xrx`|kPfcfNDZJ?}mK{{0`lbL;5V?FZlbZtvC) z55@<-aXOuJUtccfBm6WbY5MjYFW`?J{v9snXD$4}V^X}|#P5B)e+TcUc;OhY4;L3x zcMM*>Xy9`^hGTpe|6&YzzlYyDi}NX8$LCV}`ehr(;w7BBJ9=n8cYu$d;wN1$&J%pV z9fL6j9gJtk=svV#zlP8C`Psox=8a>{cnro!F~+=wKRCui{Ejh3U&7~x^4Y=gfjN&H zgE7YZ9FM^m(|cx&ZWEtN@cS|6Ju~)TY#zGN-Ui;0bDlffQisV5V*oQV#*fVyV!J)( zqtu+o9aDyju7`dv4ByF*f3Ji1+23Y3kPUg7fQ_*h@Ze>;}f`U*JTT6UMIO z1CKd=iCfNh0Y@51MwLQ4QKPm zyo+Nv_NhIO^Opobm~*b#oA-sKf)AYc7{du?^8VuR$@@zKh;rVTlKASHzl>fi^2e0n zbA&NcbIyUrUh0FK6MV>HGO+XR1AD%2_2E(4oVTnEFtL1i`5M;4tcmc!Ysdo}!+G=kZ5(6$C5O-G1&&GGF=hBPF@~Je z@S)b;j1SWWF!36aUu(|E`pYUGt{tC4*ggbqIH$_q*nA*9{K1-xwfLNJE%$^E#Ak$` z#yA;)Gh9lEFJ=Cc;C&thd*kw9`83d9mQNeGmNnLe!WApoCoqSjA<)WJGv z?LCFL={56VRX^{5*cyDAzz^^thL4k>i5E{fzp{9d=Yv)sdVzc}_(*=^;{9Z_3qH)%`FXBhtHtLK*bLzVEm-;>B%Vg%gV#?}uLbC57$2~_ zQTV|4Le7wD(AZjkA$RBlA@RcaOB_Bpf6?M|1nz{`>+93tdQIwg6(4f-yQ*HJK4|R? z)d%tcRFinF;e*E~V*MVX51tPJ`8mv0*RxIF1NzJUo+e&wqYt5cI0YTF_3WY3PY_6} zpE3E6;iIo-L+p*s2cMtA5RJbi;Ew2L?D{=;e?ym_AHi2*^MRabN6gRr@PUx}JwzWo zAIAFpT=ZnBuiv-QhsgDN0%B|Qr0Mii8866%*nAK@QQ&jy_V4}iAH7-9D||LZde7Q3 z84VX7Nquj|T|Ce4b*HJRHHM3eKcEiqn9=fMiMNKA%PZFl;QKwiExp2%<$K4-ckwxl zozg#S-Tj8^67Um}5TUzFV&M@nLtcka(Bvbq|J%@0erGx}(q8E94k< zulvb(gx@(vA(wdKjyXZ^>IG}iR%?UmilZc^B%m+?{#xtodt8t$Hb>whmXr8TIuLs9X^Nitk(Dm#!j(6((0Dm zo6n{D7f)1tfVq-Ozy{#sdWD<$;PGLv@G?F%1V>;TnN{v!O^6F%f?jbWeu zGP*n^{cH78uMZrLx%6*#N7T>OXsOUoB_A^V9KAR_`@m{!xt=t^o$d62xpbfUV6U|( z*N0F(gy3^H&w7O#dqedhln>NT{$O3lqsuE5J|Xso>O&|W^10=EbICVmI{l2y2jotz zyW%fnoxd!f_V5A3yy>QVgPKVlKf?PX{NBK#^~K)Ht15eU!3WN(gI?j?5%qIin{Qy= z_=GNAkPogm1m4{x4t4p4;4@A}mJgNjG{XnIvn$ch%6zN^U+Dq+4(0`^RmBVOmuuz& zZ6xl_Uy{UKS2TN8g-;Wog9*ruP+KYNg{i^%5XuLGk1jty1a~q%w6@{Htj=EmC3DAU z`MI(8di7zI53Mv^YV&h`7Ij7XwxV7mHsnM*AYR1e1LKS9o%P1u6XTcF`KQ=B_WJOJ z^Fi?8wXe#0HpE`153%?_{RGu)t+hY(JLhC@y?C-Io{|H6-{aH8-tSHQZZXUDD|~*X z)Q3<$P)l0)X$RD^Mn84&!snlZc=bD|#=RaeY=LmUEh`m0) zdNk=mo1^UKgw|_)#0NQf^%}WjbWLBs--o$eGtK^<=R-h#J_IK)ugLYget$2N z527c^{f$F#$Jncj7qR(}>8HM)4Y4;iAAEd)A@ED+XLUX6^;3F9M_y`u$$7pXd!~_V>sK{X3i}tokfc)xiMC&Jk4 zy}~PhU!mQ{7C-!uC*>IHwZ@h76EPg#b@j^plN7&m9!;D(!SBb|i|EXri9LKBFKx8f z$AWXoEuS|&aJ@oTpUJ#G{|YCwTs&{!KmOV=y+YtKxr?dNwo-iV zXvdgxP>kX6ImG)iUh4KD`sfv6k?}f@wV(6$()T%b!{pNB1NJtn`M`0GO>X&V>#pk+ z*5G4m4cLFz-B-wYcV(_97W4Ro*z04#z~+|M%!hm~@!tIG&mD$#-fRAn02{NGk~^vF zwQIuO@wM~8`;_Fj%NrT!vZ-xEHpzWGziD{j&Xxy+Vb4D*2GXK$!Jgz|y$g+FcNmM522#K*A6G ziFq}{G{A;rAyTzNs1zayr1<7fj!r<&R&kk`wGztzIHx1e@PPCD}2meVL3icaD&DjPj&Y0f)55C z+50Wa&%M7K&a+ zmx=TWH`Qwed=g+oo7?5_V$I&(BupO+J~}=yzPR4mcYLo&|I z2tKA)2t8S=XV>&I#9pTlvG_oIKsAYJ!_D=3!CzY7PN==1e1K+8I43y|8aO!R%C)|D zAEM3oJw9Ex_q$fV7yP9O{Y)@kd_G7ofbnIueqZB*qMj}2r^G7&WUeJxtKSRu`gjUN zaVt}iW{)C)a*H67ZkPld1(;M1czi-V4;*;X1QC`m$^n~1@Jt6UeJnfY4 z=e!ahe15LP=V(z|zZdNF`DgilPC*~G;X_S+zJ^b1J^)Ioy-W6UHsfP@0h{Xg0zTx< zPWTXzpTpdIuTYnN?hzkOArEQw{>Hj~LQoz&VP0PyFQ^YO`H=ZbX+8U7qkbyw_4*Kr z4?e!Y5cp+nJ?r(eynbJ^H&h=&_>keFuislM2D3SS&d*LsDUdSTtcLgL+euMp2^ z!YS8k4cf?gtk)W5e-Hk|yxR57_c}rp-RLocLa0VV}z0 zSNONY%;4i|4Y!xYeVC2-xLTuC-YfL@9AXTtr98vL)EW!dE8J-BhFrRq55&#)0=m9e zSdEXbHQarL%Tjzo?Der=kiQP?`uLE~C2(J1zE`->U&tNdLx8<8`QY*KvBT_#gX_qn zvb}ChTm0n++~MosDX+uyoEcW=Lu@{{*a51&2fwWKmp*);JJ=6C_*%@@8t%SAbKQW< z72vPyr(PdqEnRL2*LQ2#!CK1N5DxqfUS|5KUcpuxL)CDu~)cJA42(%;p1x!cdc697mE4` zhcRne=oOaQYu3{BhOUPXj#JKG5)j**$M*_1;?o3=3nGMBcKyyd8C*B_ z3NdZrgU6@q_I_{b_YU~y@@*eaCvo<3s3k4@*!v2}8F#I3b^e)M`~8LP=MW!IO zAfDKJZm<3Rg7CEvq$7cfW1DydNk>Fq{hGg{hZKxt&f-ichB8d_{Ht#czhz( z@AqLY*G#j&=lKwjpASvE%H3Be*Q!-W%jA^vjB`#FveF8@qGY;zuM{qA~&)%(5VLTo;0 z@ws*T+u#2aK7;g=+y6K0m->J{(E&fq8v4C=?l<^e6`l`;qn1|(_|Kdx+ZS^<=EvBu zx90nBJkRPFDfq^D9AO?DuK~dNqD7{L7~=I7KIlHT@jCom|3b#Vco>88Uc8QfF@}6U znqLcRzdPm_hr08uJtGu*YqURqOdDgn^Q?V88hn%XbTIEt_VROlpWMs#QnG%Ho0A*E z)&kl0OOBI3e8vgwZ&?i8yxn;U&x{2?cHSy`Pl20UhmYPv+hXG8P1}jt20lE^A7jQ? z=hV7y`q~iax%$%AN^&2lIj7EEa)CdX_ZY(!>SfLwm4)Ub^6dsB%AN5_{AA;DgssUMr%EFLs@R_|P2;{aOOo zdi}%)?0H=8dm|qTduvMlB)>x9h2?P+J~)5T;&TLFA=esa541L3_`QNhk}K5e!!~?4 zz{+$mFTkqu7xC?ge8A9lFQq=7dVILI7NnnX^uhBXAV0^vP3@fNP^Erio#fg%jlH|z zgZMf2Qs9@W{L|R0*N2#V$ncpq0IMoL53x5kAJ+HQOw6^M+L(WeeqwJ;Yj3DNY=;l_ z)-oL`jW0*=mDqeBC)yF~HPO#V`r!F6*5~JR6XMQm`vF8EymH33%`x@-Uct9f#ABYdR z)W8`u_#`k=_z++(@FtI=@Zq)jnZ@VjMt@1b&2Iod=PySyUu*EY|1h%^eK;Ez^~<@L`7D5J+Hi ziH-iU2_H2dU~ip16!-w_bN-^o2b^h4lFfQj@Rzf30(`(P#<{qBSYAqwQ|T`Se3q9D z=uBrJdmg!bBj+!`hx!Tsn>XNj_4=?IK8O}v8Vx&!4};%cKR5YHe~yDjo8!eMKG@u> zB;UyEgY}mHK4ktfNow^I{sOsP_JBRtsa8Mp`Vff^-d~cD3ZJIa&*^4+-^%OfmiiFN z2hkJ6l*IUDd3>?@8JiD)QsQC_AKn>Sd_+%>pKIfbu{VxBcs?MKK7gC0SZ~a)B%bE| zrJIVLzzD2gE!*tsHTF^;3Ve7&YWiF~lFP3)@j;8v!sIx|3VcHBjm-zq&ot*RHTZ~ra-9O~ z4dsKx7tBe+hYTN^pV#;c^>a6Tm|sYIQSialv!b6h{*vXNar7aS4_SV0>otYHY{iF> zt>0_(A(RiS*FZI?Gqw5&J(m3(NXxvTuvhdGIaLfkWcj%cALgGS_WJw^`#J9-XKK~x z!!~><)b9#^5q*fr2Mn#|gU83!?=|>j`Wc%KHb2+cQX`U(2W{@%XuLG;A!Z>aTC z7cbWKbKvyw=hFNtlnCn5G``VfZ?f)91j)w4DDtkv%ddqeeMJA7>YUgIxP zzem&u@*#G9ZuB!U9|H1o(GyqCD)e(JKDhe5MjtYN(ec6O8%Qc2OzZ2ltbVuqy*2jk zf)C;^3Vhfr{N4{X_6kRD&0##^LQxwx^a>d}aOe-1OW*@Icdiygl5w)BSBNhTv!8?O zZQh$I_6k`uyI$BFbK-sv6soLOXlo732_MVVp0-!GT*w%?USY{z&3dm83fBn@$tO?Ek2WcFJO{pv9g2@EB5AcY4u*N8lOThpwLU*jE~*x9@;p! zkq-rX3wyZ=KID5t3ViZ=oAb^7QrauT`qlEG*bCdJ4+TDq3%$b4{_=|Wh`8W^&ylGYx%iCPeSYs)rU|%gyOT7e=6*~(ND#-D2R(vzbo|QMnBEo zC31=4{^zE8?V97ujef4~hv)aZHq>ho;>(SGmh=m5^3TQbjec&v7XZ1u?04PdpIhT| z>-P74@O!^|(<@|s_yAjAYrTLC_Z4!V>=?)X0Qn6+2kkEHjc(HmbGc<=&oj*RJ_@z@ z7QNJ)Ug7Fq&8zi}Z+e9*xzkOra1OV<=@rf)kPxe0VXyn9SIF1_eOFwUsOx>K?bQHv z)Y6sri6CA{oRi!M>qNfVm{VVSBIa>j?HIVmr)IAkVDst!-v6 z0=AdN(@nL;HRH3k*S!aP2*szcSMvq)VQp^{|d_w=QZm?C?B@*mwnpEtcic@Cj{j@FHSesO#Vy*BCZvwpHy_|~^K_6pOt=2PzXuIz2feT5%! zpAj(|&mg^2JcD%knY(YOmAr4S>n?i+>4LfR`|p`^;~AtMxcg#e*mHFEkF`e%?5pYHqq`-9FV-M6!OZ@_1XXS7Z{K3T6YE$NLG z?PV{Fm~h_r&6=$60hm2rQ<~#ouzjMD6&o56$ z9J_;lae^0)vDU*`UK@oE*)ulJRD8&u+3W8kD|@D#_{+rk3-`JmA2#1NXZV0MTf&F4 z`wDS;@w?@G*l=Ir=4X%s>Y!(k0y6qbhR?M68KhjBfk3}2#+Sk~dqeEauItw6gX6<*;~|wAK4g0}iOOGcdo?A`AbkZs z6ncea<?{p?DqdC9#K3t@KiJ`ic97e6J9hOT9kiuT$OhjN<>yeDAi?2YVlxnh*I} z1A7Y8uw(cFdxuy)z5tISi^_2pXc^A%br1+ z>8I-z0(-8L)?V=!_lyqM4oqe}v(^~t)%f82rInOjtCo*1t^9r28|{6IYja}b#g6!3 z@F{x+X%QdlXGA_oz5ytO$2Iwe@)@K#J+b~`?2V%jo)3tm53rQ!S}&l;hfF`qoxHe`D_nQ_@T6WJ3VcA_Q|B-5&S5AHYS5?F_BKoOb7J)Y_F#Uw zYj2A7QXdL@Sl_!_^OqJT)5g3do@((~ls$uVT|YzYjm-zq&ot*RHTbk3n!<+wdqepk z@db0z@FBye?3r>!e_{T)8$OghV{n}huAb$d3VB!MFIoN>M;}7@!2DDE1@*huU$)}I zXc&bL)K5??tJh#em7e(gGgu$u@FC03b@;5+?=|-N{L0m9HTtj(A0ANmT|TCWFQN|- z`GBF-eDL_V`n?99Oh04uq3juh#dw<2PgAee-kuSy_r75;e*dVQ3**sTZ50+Pxl=niu@{6AGX71Y3g@P{uxmp$cNbZ zxzW$adOKD<%Ehcj^Ml75!+mk%raEfX|2d z%NfUDe0gJ}viD;bPYe3+!_MNlXb8thALsn#vBYG=(}KU0;{)JMr)&8}Ek0`f%-Or< zFNlA{wf#}fUp^wp%r`dZC-T1@-tByx<3lMv$T!}1`Nk?f=|J=o<25i|e?B$#qO%K{ zU{2Ied8Unx7t`MoK4829Ob^ExK3w3#o)7Xd%ZCeveqPY_OXeO(zl0Cf_{>av5qvHM zAI#h3SKtHe9aww+mqivY9uu>4Gar!ebByji`htz8!iVu{{%P>|Go@_gWm(q7=SYOlmoTzT?k&fDjoviO)c^NmVA=l*mr@{QLFKL2|IZh^W6|8iY{&u11N*eL#jFKk-lLr1ti>YS4glGne1 zm#`|}!$;r)#j*a4f^Tu$@>e=gE8*C{&+)tslX>e>}YM| zgSFT3A!l!IqrWgOq<&g|fsMfI#lac$bECh!G3w;~C6CX=3O=GIA6k6!`6u)f_|X3v zvQAb%oxRNs`T%=N{Uyoy3&w*l82t>z=WLUnl;e}jKXdxI+1}WExI=t2`f2f5$v<=Y zP;T!jsIjgO*TaWUe46l=5PO|Itm|imzXb9j1fN6bNv<9-`PDV*Lnt4%!6(FC(a!*V z2<5|8`nguWpHcgY@sx7N{0i|RmtTG1{v!IB)$h6dswAEU>ccjC2*u|{Kbddb=%>#& z0^-Y!e!6<(i^(@6|Gd#pQ?HffpONvo(a#(GY|ojX*m_N=pSNzm`Te)-_Z9vG_i4Po zMD2;6JCihJjmsRUhku8QIVxw_w@g#K-^B0l&Zpx$IG8Vd6^G&&*2ivd^P+*zVGLAq z%f)x``@6W0jAL-Tdy8{ZSL1E-xzQ!(k3;2iyl)OE@YMmvJ;e`BA^Si$riEj;S2O6~ zd>C$ajQ1bn_x}IjDJnb5M4smYIJ4sVnr#gGd2abIQ(=+p~=L6^c)kiu$ zczouMxb`Z1LhOyr2jVjr3O;sStMN%-r0^lY-k5yw_>5kt{N)JTNn!Io@!`Pui}<<5 zUxde4G~#;Q`Vh(o>ZkY%y7!<_t)7rOp?nZsd!f^ZP(Eb(IeMYh&+YVK+5l84eF)`4 z2tJ2SKf5}6WAlOf$)9f^UTN_Ou{Sm!h!5v|XPgA;XJkGspQ_?%hR^b;Mo*65<6{_+Ux~jc^NR3RPK3mZP<;sD1NHMqGH+`FK`#GWYT5LW5O7bB}eopR~co9b*JRg+%IX=E9>)9rJ1tvt@ z-wWk~=!tTF;}E$9mRG&syNmkW=%>D(4Y4;iAAJ6aKp=iuQ_p(+#O*4e(HFj-li{PU z-(%{-F6uS2PWt-Y_=|qOi|eZ0&++kPs;g(|D_iM9r2QPPpCGo$YwG()qMv)TpJV1- zzrS(o_P74{TiN#&c3*#L_U;;IUDlrLm-QLj$QP{BV>9l@&$#!)_p#RJY*Zaj(HrWU zULcP#Iv``-mS)Ga&PoDAWj49 z#k`~O0kQHC!5}{G8GNLsDZ}TtU}TWJvH9@G_SWBdX=|}(Q!IyYJ>B3hM~g@18Kir} zhX>#z{AGIA_)E2(fIIudhu;9!#QS)9X8fglA~6RqZPb$%HVNr}dVP>sUzJ4$I%k|gqMSU=PcMz4YnYh>iIji_kU%waqrM`YI z+8e45jcc#h*74aVJ_OhAz(;($bU$a^UQnQ-elO}nC?D$gH&*pi@=tZV*aaU#@Tsrg zi}pevYW8!A{u0cGE$X!pd&Buqx1UqQCp13~uixwT_g4JnQQUg1xeTk{cfkkfiMpOW z1U}GD)+0mFq2=m+Z!um(uiu0BH}lc2p?VxuiqQh`@OHG57Fzj zMri#Ww!as@et&45L8{&Fg}vhEds4su=SDv(_Ir!*bQgTk;&bcv{Wt&6KZ7*8uMiNY z{R?a&LkN1fmR0l>7p^$3`S!z`28j3jae*bJ($v2nD4g17-4pQOO2j1!5z`QV0}QZ zP^k~0dKE?ahTrl%Vf}A#@cV-<)6J19B~aLLau_gT$9h?8y#r9{hp1ROVwwKXvhf`e1W2 zb-p3^DEW~23wnhLe1Ne$!?}ZbY3&t%iNpu5pCERSezG^Juy+@HF!<>5^TRoEZ(z@L z(AXQQ599-&WNsanf6fB+Gd3Rr@^j-ax_XV+gvN_deF)(Le&!`y*@Q>PE1e4v()6Cw3%s6O+@&e9-6TFqipQ|WMPo*tW(8kB{q}!FGpz89pKQX0ad+A0$=+4A>@n z-F5gR0D_qK+Dc(B@Q%iZ3?G|IfE$=zslOcI{dCXxP>3DVdVc}GfarekVYSvEH>&)F z?}zdM<7K@<*bWLR^i#)&oPL^G1KhwIEAg%To9n8KFCq4Z>O&|We63+~OL7DJ9suKw@g>3g^a0pwYK>TYaJeOMRr!mp zHNXu_uTnoTp6?an*h+hM!3WV3*DHip0DIto9p(tom^&t`;?tl*%ntG!07tzm2u2-nA*Z7N0AIOLP9D`y`VfffyVU3pOr>L;kCuixP>V((0uZ^Pc0 zeDMCF#E1GBVz2OF6i}~i!H2MVt!18Tp|m&CPn|wUJcWZb;KRH&zAm16d~C0f+<@Kz zh0Xh2nSRF6hl~%({2Y8RdSZKp@CDdVUcbBi^FkLdw$X=BK1h6Vy+XteU|+hwk?H4t z@FBxTSu{^ix~E!`_&D$neqCYm$FP)Q4TvYm#4S>-Ru?@O+pg zf%>Vh-?!pJ?0OAJrKVoX>UYyCtcw@B;DhL=0w44W|MZXk_|^{(#s|N_&t!XdDfeU( z8!Nxdc!FnKG7ieVGoM9*_oY|Jz<7+;am@Fu?cBndA53Il7ysh>3h@Ts&-Dr~xTp4> z{Ty;%v)}nXKG%RgJmiUry}}C|Gic8x7F_i3?(bku_!|1f@u$8CmGugtNj#>5V=&G+ zhx;cOn>MtcV+>4&?`M0P17jPG!Fm2IY{S#@mJ8wK74j?m&M}&JA4AaI6hqY7%eoxn zE!!6|@1HhsPK*s@HJH7N`SJZ9b27zVA&*hv^8oWo&Ae;zIh@A=~S21?s0fUsz?Y_&IWX@UB)LLiv#C zC$A&%I#jABO>k#BeUR^|Rp~=0A42dsgq9591He*cZ>TO5=;yPY_6B?=JWt^PWjuROt!k4NGx!2F}{_w%9>$zG_LhOyr2kIxNMt@Q13H>(IUgIx% zK7hwyb8x*jwCAaeFHOXs1UAFou=+hfAFQ800#qu0xex4Nt|~vLenR)BEdZpk*Xt(` z1+KOF5Xy%v|9qsb-|f85!6lVGkPqDfdW91ow@dRY?=Sd(79V2YP}Z{vxPy5w+k3(X zpPwu7IRbY=?DhH8Bb`2M!w2pYb}%o%s`8iEd;pZ{{Tz>v`TnWee2m<&JdUCdo)7-} z3ajI3<}dF1$g1=6CVT}ZEROex58~(M`wDCIh}(z9is|=%@Lh1LFY1n$J<13A%-n4e>vpt$b)3ajl6 z)d$aqu|7W+J(-RZ_@zoex8j5OzQS642<3yrCjqgAchE=hyL5k}iT91Y4OPBPF2v@8 znRk6Xd+YY^e&>Gn4AOkBu=(~=>1oXv+pvz(({gwedW8T$?ju`VoCBv{^B72ii?{N} z>v#iWe2V{Uto+5a+kDBK{cCP)_y_Y%`P|pdAXf(%i@&DJ#V-OC1uW&NOUg6KuQRfoJZ2Z2$JU(w?92Pz; zd;qpp;&TYQW_>5lk8;`mv&NJm=am`ZLX6Bmt z%Msph;`M#v!)w6j9_KxH*#~E8{YCh-Cw$0ijRQE?jC%5v*kcJc`U}@1ln=6&FZ%NX ztZ3VQr?eeI)*6_t>!*?r)Xxrn;KwgcL4U^?!5Buk^Q8El^Ju~@8W*k)(*rE;tbuPf za$|GeL!6tKFFJkh6@#Tm3VdBsmcbgrp zexlOQ#0zpEHXj6^g}$B*vDfKCEItq$P;Kw(ch0GI#=7U?oO)+`ZoMAy_}tX*)$vrR z521Wud||u_sb}q4s^W#uKO@#_pqjd#rGARNzu1rcoKSp@psykJk`MI1@On+ZpA%ZI zN$wbt4xB6WdFLuEPEk3ty|Ni&C_5EA_UGcuck6C+;-p2kT*O9f5(O2weoJm>t-0j^- zZuxhe#R1~kaB=bfa4mUmTy~Bzx}*R85&!s)FPg1C;~2SK;l-4%ADcGBw1u1a+H>>@ z|Ec-hLmA{hzBs_g`D==v7A{&~uW*7X&3li!I4kyh@WwITAN2n}?it%&;Tc}=`%q`J z!R*8MT4T(~^e{71YdrdY5j&O-%y|lXS&hk`p9~WeDL^~`|N-Z&VxC2EAR=i*Te!$CK4Ycmskou>=oAf zOM*ofJ_Oj?15d%hD17kvV1a-=&jY_K_m?BQKQi|24Ilix2cjpn{(^Pd8$L*_@psgd z7UxYpxujo~`3v56y+Sn~#Lvxrh1Aa$mbYF%m3+wb6Y~bF&=Z}0;#gy^Rv)GhKA%H&h=&`QYOVl(TR0jad)t2X06Y z*kbJSjZ8ly^TFI#NPijY`~^KuIH&MVqn|j|*lX_3E3Y<{P4) z0s8PR^9|_MDOR*jA42(%;WO^y{>9pSjPuCWX~F!HI#g+|_)8={IDbKIYx6O=f6@0+ zSM#yv(&e8zd$-YtP(B!Zbou$=9N$m36(16nK9CQ|-))hfpG#e#%Fm6xavi4EhkxY6fM2p{CWLY+Psd=}^0dhJKd$1txRVn7`}N5Dt&&+-27LGW4dzCv9+8)C21 zhgO;f)@wRG&|lL3ZJYXCZ*M3c7++wnz0T|cxR%!=9-r=D_y8_~kJaX%vGu|5Vg5*4 zzu$NB4yxbxgAZAJk^2f&_4_t_!1B854$rQW57f^zpq@>@MXBEd;zdk8`21Xn5A`#| zUY}n*3a!`le86?bM)#HVnyKI8@nL{Xxd!Hh^B^J_9U20+7XDbRM?5~}zQU0DJ&Hbf zKH$C~+R(wgb^gL$p-w+#e{YZYAbMi%v#Z_TIGnrsT^BE?4>9?W>F2be-QNhYH#Q%9 z{s}|+l7Cj$vtB>Zp4QqMst?=Yqsz~!pRxH6J3lw|dmMf6d>HHVbJ3IOIMLScTk*l% zSLo}t+Wt{My~ch@0%8mA%sxSBz1D=D7<=Wu!rFL2eTdBmGw)(Oy9u9LxBu{;|Ka_@ zGe|E`Lo!x2jqk6-$|>T><>Fb=eV=&nKC)T&w`||b_5yisgjgGI@yB3!`8_<*b7>j?iBB)%LT8u=31LxAx_aj_l_qzMrA!P zW3X2^HonktxuqP#Ii;8}#z38X_7^-)4`ZO#I2+F7{2g;lzSgk$$ZY-zH}Cm=6TLM) zqx{&+TY8^-o#Qp|A22D{i?zONr8wtPw-;fLG4nRIy7YO8g7;rka&!v`A+6nr2)=d!MPeCFp|*Q^&%flr9NvH3uJ_%K|% z_UpMN=#cl91pXp?2(ULMA2NJi_Iu!O2Yy5%lGB^~pw?gD<5oZCYJCv>#5WLV^dXcF)X$F5&zFWX_4>)aeYieMA8GX=ln){JP(MTL zjm-zfmjlKZ#2qa@A@;`RgWx0a<&G-8WcnGI56c&U{<3_b)lZ}n^9FhgeQ=3d%g@30 z&0Yj`cQwBX(1&gKAo1me=zf5H>f#0UVeod&wq>&Z+Dbe~H8g zpMS!TApM-`?A-+)3_iO2ocbA?53%#}o$vvbhK3KBzv${U>Ss;7_>}qST0Ih=4^mC$%7u1Jq=EG)u7W#TN#9prtk@z6``CIyWHp@Rt?S0<3j{3c6;$jDJ zv8o=)@EQGmso&S|38`nPpP}`;@fV#wgz|y$CA6Nc(Ferj-RePbHzpr4e+j7HBkIF0>b1V)+xq%FL?1jK0`haw z6J_sQC3zf<}yUuU6Q{Jugw zv*Ki>7iQ`Ro_o_XNWWux2xl0__CCx$70<(yavrEP?05U(p7dX`Ka$_e%IX!A&#qTE zM}9zi)8XGd+q}1r_np01YyS+=lb7s;+4~C37^YW}8ogX#`b&o)hwH#L4w}d35Vpf~WaG`{Pw+jD_}oPc2leqfk9D7O_QLn&8Kezf zD*abaHt%in7&8WY$JsM0uGssq_YL6~jA44IIA#qWK9ln=O|R6=h4YrVV(dIVA@(8` zOk_OVI39x!#7FK)r)|&A{@h{c=6wnqfU(CXf$hXwp4plYX%?ON4EZb2Y_36m-m-_;)C}WJi}!8p7aVYiM^Y* z%oTq)f8lzB@O&|W7+((X)5ads=*5)^pAdUv^MUw~ zj}1hQ_nu3>F(YS&hEsmO+{Kp!2h#^&FP}-PvUe*!@EN3c#b3sppW`u3U5KX{K6r*n za#y9FVlNi0FZNzuRoS}>K8S622I*b7Hp$*sXfS5~d9!{h;|29Wo;iu}PCsqkO)(zV zuMa;WmJU~^521X>@WC@VMNbs@C$R5eUMM?M`IY!fBtE$OGl3zel8?=vRpHYFe#GsV z&umfHyNy1C^1R&kwQgvH3tw97oL0cfp5{{2b=OM|JgDf`dcjMNB?WKjoR6 zm=~^DI5B=%UauX&Z^d3^ydW21^TBACzMc)S*XctnJ`fv}f)dk)dsM%3PT&J{`r--o z&iLF-{Z9QH!Uy(+4~#D+AJfvvF1UC&ZK#ok{`C;PCU6N(S@GsIr% z1N|?&Ueog-G(Ydd2k;2Vz1Yw3_(ZJV--Nj-II7v-^Lz-%&pXtU==FO%K8T(u_csom ze)1Wliv8YQ)bB<=_4RCsy|MY=>osLP>-95s{jTIghL65}583Yx)rVcwYoec#^uhBX zAU~J*qO51>E1~g1{AKUzcin#PF8H9u2fe~See?UKSNLE$xrepBKx#0*Gf7j!sg>^! zI?H+=Z_lSchcA4VB9MI*@oZ>f&Lz*yF&g*}&#ja{zKeg~UCjSot2_FDPZe88`ZubO8R z@E9FFb9rV3*WR6{6rT`#WAlOd3;+i3aedHAd=mHzar;Jqy~H~fA3Q$UcimR{%MsRn z-}u0L(t*#EywmuL@ED6mTsyeVlAk-B8XtO9eF)_P^^@oSs(FS0&ZtPk?t-zt3woRPe=Sj^?N)%h@L3-Hx3bBu)L^8bn#*r^}EqeeLWju zuh)l2eDL`v0s;LJpi)3TPdtNkw6xb~n9r5&_lD}jcKE34_p_M#z<7$E zsQEe9DUHpCaiZcwrk}cc7M%KgD?aG=bGED3Ky30Zg+7w^))&_DbFZJuc(DsUh`%WC zVXyF?ecRqwcoxp??gjMSJf*l;G^iBIebFwjm?LUT!Q!{ zuGR>!m$4Uno3*{;ZTR5vQN#}V%Mo$_=%K2%+7%zPvBTjbIzEV_521X>Vx>I4n)y}f zUUyMH^?Z;RrpToW`l;lD-|JTN&YXU3rw{eHrPGH{K7`=o^;2nYY(9kK5)Pjbdqedh zln=xQ;X>6bEb3=uJ}7dhqQBJF8csjOUM!sGP(^K3&`(8f>EbDdR@EAg4-#J#y~2Wi z2IzyfH{|k-5I$u3Szl{-{RBXWr&H?CamBS*&R+4CNPO`Ag2cd_r@YoE=;u^tFHBX} zp4;+)^TuA*IrH3h#kFcS|7^wP1E5s(3Z1`%=I6%V`d*>chZg-DeZHskvra|t!`36E zy`j}!VZmP}X{yl^V59C8?t%}9FD-5F%<8AQSLpOJHXlSk6}>{ICn5HR^a{7(1NAda z#b3HZXd-+;nSb*83ibM_)d%uH`~`Cg@|W(QwpZx%b2og@=jYm9fYVQ|Q-Vd)#0#Ha zDfJl&^_sd@===p#Q`fWLj=9$Ny#Cs6XRpzRID81j=P008 z==2lI8+AV?v|bZ^h{y*Ft?CsP@KNUH@D+8h(8Y@oeeitH=jZBPq0`TOg(AMdt>v##}@4WFPI8pIooBDk#KIrTB?dr7zTnGKrie6zsKb7%f7km(ZQQ*T~ z;kSO*KZ7*rzCv&=tXCL#Um>I>s8_x29_l~#VLr^XOd=gh{1lY^ii@nYI zUZM4ut?<#r4&Z}WsqYo;h!5)6Vew(CguB=8MeKkNS*%p_3JdzF=L2Iws>r1a`l;kY zrl0lKC1M_Ot;KfwpvWz)K7{fi1Rt-TnqHyRPf$%)d*=N`lS^3rL_VSG4Ox6b?DhH? zi4Q@!WkEk9^Ffh275zm~Ygqk6c%0wS)K)v=93=)S=_5UST2stnUqN!w0XQiK5oX>*rKwFHF_<3iJ7A03WC)nqC0$fqv?H zgZ?=RiI z-}O82(cV{R_PW!wes5|Ad|-TmuIqY*1^ukQwuJG*^I@Q_*Yv$Yiw~%#-rswAS(Ke?Y1%m;mb zuJ0AXUz*qtgu6%G-wWk~PklWbVz1YSNPO`1I}Fk0 zpC(@D?TyKY3?FsvU(5&H;b#zVpxmDOdVTbe28@<}eSrV? zt6c+r-_{4C&$DN2;utx%{l3C~58t=FAzN!)VNd8JdxiQv#7Th61tRgUWjea8y`SZ@q2gl*kHDx?W31J z#$<4cziQw={)(~B@B;9e+^xgs0ftL4FZ+FDlPY`;=kEIs9Jl*b_I5Kq$g@GohfUwF zRNw;*IX;uz65mi{&V!dW^1V$8Ccui!!`Bpn4wu$rym}l1Y@*tP&>e0d(IU;2#<-G;A;Kl>HyQ+3Ljhq zY0mSk%3nrDu*;s4&x+j(J~Ygl*zel{XFe03+N39f59W2r zZuhsIjBPy4`HS%3jg{~N|d9#fWYBp8F^wXy8@mG++0 z*^6U}d{~e(X-*&BaQTMlgRyN!+mLTO5sfwTcKxMI_{jB?z-PYU`;{_$j&N?wd)~m{ znD@VdyI0z~3qFW#GqLUJ_=$_T<@gx9C0?lb;GVPolj($f5YAi|A2NL8dlum@qsLso z%KQ@tVV&IfWm9**C_ec7Gr^28?>ExNmH6cHPo2Gi`tVoul>k2c^#QOp{v!87n*1DV zEMpL3ko`E*lYf6WpH2e!kkunfeaQGQNwLP{gN>(o{k-(`h{xwb^7Fru{2X&E=I35N z1s`LtN*}U%#Psm$^uhC?g@Oa;fxjR>hYcnElHoIvdJXznU9Tlr502MH?gr_pix<)P z!2JAe!F##*4ze<=Syg;FIl}ue0pD+{ix)aREMJKahU*ucx2b0_$CCIW{t{xZ&#xl! zf%sr(_$YM0U*<0vKIBfQz2GsTtxg}vhdzEdC!A-{!5=tfS-z3^i>cq?FR0(~fiiz- zf;$`!_EzXaX74uoVDQQ1=QVtIVDQQ6cg)d_A-1pT=aA#=2_HN@rk;hKpnk{t)$3;% zA8frg=x{&h8u{S!PjC(MrheM}jgR2N>-l+tbMy7~g+5-y6F%tbwVZyc z>a{HY+#^1mP7z=7`x_elRK|;y`u*DZkm;wYp3U-4rM+GsBJsiNCx|Wjc~b2!UOy4S z;97O{yVx754#WGvH1|3pX=&b>gQH`SjMf_!t3`I_Z_Z# zfA1CQwR(JR-G1xaZ~e)}USZmQhF(DGe4q7?&z;C0$*{K?qf!5FMvFb|29Fi~oa;o{k+E&NesulN0Pd>1x* zVP~SL0?@I+OmO`QCWB$KwU+D99;@)Vk8x7qjd}lN9X^M1*DFky*t@H>m$86jHzc=w zqT&M$Ies+h0yjNAybkTL4xbQveJmKn;e+H7L(la;uk#ns#qQPU?IksUhS$Y@rXl4y~`!&rm*u;N$gE?klXfH&h=&`M~(X zpSC>v?@EPFh`piu5XuK%YmAeTTx$Vwq23MQ&*Zwy6`XPTMgs2eb=Vu154_ImE_#J( zf8lkBcUAfc6Xp#pTA$ZiU~{v|-d*s4=kMS?GTEz9jhZ8sUF>rFWujQW^AC&m;K9TzT{16zg@ZqA$ z-fj4h2tG{lB|op^1F_-x+vh$%uf<2!DUv=oKD1JwpX>0Mq^@48^cP~YPkdl};eB>k z0_y(BJ#d}B8;ngY2JZTL?FjGVZS)F#yr{I7`bnFQWr#R@z`UU+zMif1mk@hn^MUxJ zso+B`_$BhsN`Gl#aYF62YpK!)mv3-RJP-J=;o6&w4<4WHz}4@S{?Y_@64)G{558Wj z%Q^f;EZ}=_kQ6= zL+ev*5FBu?=?U*ki=_{te2`j${$lP)uho+lv?7!bfT4R2xg|bZs}G@k$n;a5L0YRP z)X(koL7rKm(uYt!gy7@#Q);V8t-Z1NK>chmzDRDVi!UMe#^wX@88N<$6H{xb^)oUb zm|F(nJwa~>R8r*|qMxJxOBFAu4-aR| zuOu&2`3vxQuH{39&o~(>@-eLGvImfCym+C`KR>@-J}|>1ADn*v7YXqBWKxTd*UzcW z-dE(q|Ek7EnV%od(JS1{hYztdmQz{29jXuHL+t!q^z)kaVU-Ud`MKx`sH4#n&}37kn`Jm^_nHrJo`8I(>-62jY`{ZU5@` zd#TfcYCd>;x;OQErG6^)A(Rh{FQN5ps6NE5*V120{cfL=qpaW0_hUcD=jQ`6@0VO>CtjUzF#jC&CjbBd literal 0 HcmV?d00001 From 05790a0745f5e13593cf7dee252241bb0d827edb Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Wed, 16 Oct 2024 14:45:06 +0000 Subject: [PATCH 108/116] [maven-release-plugin] prepare release v2.12.42 --- examples/pom.xml | 6 +++++- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 59152ac8ad..d2d703540c 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.42-SNAPSHOT + 2.12.42 jar Strata-Examples Example code to demonstrate use of Strata @@ -272,4 +272,8 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> + + + v2.12.42 + diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index c46914670c..641d76cc6a 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.42-SNAPSHOT + 2.12.42 .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 32a5769e52..247f69371c 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.42-SNAPSHOT + 2.12.42 .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 3bb57365d7..3a77bd924a 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.42-SNAPSHOT + 2.12.42 .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index bcb8272ab2..c33c7e669d 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.42-SNAPSHOT + 2.12.42 .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 9f26593859..d17c16deea 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.42-SNAPSHOT + 2.12.42 .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index ef3910df18..0a4912f546 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.42-SNAPSHOT + 2.12.42 .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index a98acd197f..e3fb97ce4f 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.42-SNAPSHOT + 2.12.42 .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 069169a041..93f575933f 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.42-SNAPSHOT + 2.12.42 .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index f71ddad74f..bebe1fc86b 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.42-SNAPSHOT + 2.12.42 pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.42 diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index f9e746e558..f6c289be58 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.42-SNAPSHOT + 2.12.42 .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 43d4967edd..be44821292 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.42-SNAPSHOT + 2.12.42 .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 5f9129e618..aad926ec02 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.42-SNAPSHOT + 2.12.42 .. strata-report diff --git a/pom.xml b/pom.xml index 924db250d2..ce6ef3f2d1 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.42-SNAPSHOT + 2.12.42 pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.42 From 540c343e09407ed26891fe91e7fd840d0cf88a16 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Wed, 16 Oct 2024 14:45:08 +0000 Subject: [PATCH 109/116] [maven-release-plugin] prepare for next development iteration --- examples/pom.xml | 6 +----- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index d2d703540c..8f504e9229 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.42 + 2.12.43-SNAPSHOT jar Strata-Examples Example code to demonstrate use of Strata @@ -272,8 +272,4 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> - - - v2.12.42 - diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index 641d76cc6a..da026b9501 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.42 + 2.12.43-SNAPSHOT .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 247f69371c..af02a59f04 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.42 + 2.12.43-SNAPSHOT .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 3a77bd924a..fee1aab278 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.42 + 2.12.43-SNAPSHOT .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index c33c7e669d..493539c4e7 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.42 + 2.12.43-SNAPSHOT .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index d17c16deea..60b62bbfb8 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.42 + 2.12.43-SNAPSHOT .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 0a4912f546..a2fc6b5103 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.42 + 2.12.43-SNAPSHOT .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index e3fb97ce4f..50d0d221a7 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.42 + 2.12.43-SNAPSHOT .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 93f575933f..32348ee22b 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.42 + 2.12.43-SNAPSHOT .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index bebe1fc86b..5a2cd0de67 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.42 + 2.12.43-SNAPSHOT pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.42 + HEAD diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index f6c289be58..9402f178cc 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.42 + 2.12.43-SNAPSHOT .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index be44821292..3598b4c230 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.42 + 2.12.43-SNAPSHOT .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index aad926ec02..dd1356d3ee 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.42 + 2.12.43-SNAPSHOT .. strata-report diff --git a/pom.xml b/pom.xml index ce6ef3f2d1..6ced91402f 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.42 + 2.12.43-SNAPSHOT pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.42 + HEAD From 4dce556ebc4c4e4d7c25c2d316d197a6f5890da5 Mon Sep 17 00:00:00 2001 From: Alexis Skitini Date: Wed, 16 Oct 2024 22:05:23 +0300 Subject: [PATCH 110/116] Overnight CapFloor CSV plugin (#2679) * Overnight CapFloor CSV plugin * copyright * variable names --------- Co-authored-by: Alexis Skitini --- .../csv/IborCapFloorTradeCsvPlugin.java | 4 +- ...rnightInArrearsCapFloorTradeCsvPlugin.java | 330 ++++++++++++++++++ .../loader/csv/TradeCsvInfoResolver.java | 36 +- .../config/base/TradeCsvParserPlugin.ini | 1 + .../config/base/TradeCsvWriterPlugin.ini | 1 + .../strata/loader/csv/TradeCsvLoaderTest.java | 63 +++- .../opengamma/strata/loader/csv/trades.csv | 3 + 7 files changed, 432 insertions(+), 6 deletions(-) create mode 100644 modules/loader/src/main/java/com/opengamma/strata/loader/csv/OvernightInArrearsCapFloorTradeCsvPlugin.java diff --git a/modules/loader/src/main/java/com/opengamma/strata/loader/csv/IborCapFloorTradeCsvPlugin.java b/modules/loader/src/main/java/com/opengamma/strata/loader/csv/IborCapFloorTradeCsvPlugin.java index 4f6094dc71..e69bbc6fbb 100644 --- a/modules/loader/src/main/java/com/opengamma/strata/loader/csv/IborCapFloorTradeCsvPlugin.java +++ b/modules/loader/src/main/java/com/opengamma/strata/loader/csv/IborCapFloorTradeCsvPlugin.java @@ -68,7 +68,7 @@ import com.opengamma.strata.product.swap.IborRateCalculation; /** - * Handles the CSV file format for CapFloor trades. + * Handles the CSV file format for IBOR cap/floor trades. */ public class IborCapFloorTradeCsvPlugin implements TradeCsvParserPlugin, TradeCsvWriterPlugin { @@ -122,7 +122,7 @@ public Optional parseTrade( TradeCsvInfoResolver resolver) { if (requiredJavaType.isAssignableFrom(IborCapFloorTrade.class)) { - return Optional.of(resolver.parseCapFloorTrade(baseRow, info)); + return Optional.of(resolver.parseIborCapFloorTrade(baseRow, info)); } return Optional.empty(); } diff --git a/modules/loader/src/main/java/com/opengamma/strata/loader/csv/OvernightInArrearsCapFloorTradeCsvPlugin.java b/modules/loader/src/main/java/com/opengamma/strata/loader/csv/OvernightInArrearsCapFloorTradeCsvPlugin.java new file mode 100644 index 0000000000..513d0f1174 --- /dev/null +++ b/modules/loader/src/main/java/com/opengamma/strata/loader/csv/OvernightInArrearsCapFloorTradeCsvPlugin.java @@ -0,0 +1,330 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.loader.csv; + +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.CAP_FLOOR_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.CURRENCY_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.DATE_ADJ_CAL_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.DATE_ADJ_CNV_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.DIRECTION_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.END_DATE_CAL_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.END_DATE_CNV_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.END_DATE_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.FIRST_REGULAR_START_DATE_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.INDEX_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.LAST_REGULAR_END_DATE_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.NOTIONAL_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.OVERRIDE_START_DATE_CAL_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.OVERRIDE_START_DATE_CNV_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.OVERRIDE_START_DATE_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.PAYMENT_FREQUENCY_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.PREMIUM_AMOUNT_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.PREMIUM_CURRENCY_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.PREMIUM_DATE_CAL_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.PREMIUM_DATE_CNV_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.PREMIUM_DATE_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.PREMIUM_DIRECTION_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.ROLL_CONVENTION_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.START_DATE_CAL_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.START_DATE_CNV_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.START_DATE_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.STRIKE_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.STUB_CONVENTION_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderColumns.TRADE_TYPE_FIELD; +import static com.opengamma.strata.loader.csv.CsvLoaderUtils.formattedPercentage; + +import java.time.LocalDate; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import com.google.common.collect.ImmutableSet; +import com.opengamma.strata.basics.currency.AdjustablePayment; +import com.opengamma.strata.basics.currency.Currency; +import com.opengamma.strata.basics.currency.CurrencyAmount; +import com.opengamma.strata.basics.date.AdjustableDate; +import com.opengamma.strata.basics.date.BusinessDayAdjustment; +import com.opengamma.strata.basics.date.BusinessDayConventions; +import com.opengamma.strata.basics.index.Index; +import com.opengamma.strata.basics.index.OvernightIndex; +import com.opengamma.strata.basics.schedule.Frequency; +import com.opengamma.strata.basics.schedule.PeriodicSchedule; +import com.opengamma.strata.basics.schedule.StubConvention; +import com.opengamma.strata.basics.value.ValueSchedule; +import com.opengamma.strata.collect.io.CsvOutput; +import com.opengamma.strata.collect.io.CsvRow; +import com.opengamma.strata.collect.result.ParseFailureException; +import com.opengamma.strata.loader.LoaderUtils; +import com.opengamma.strata.product.Trade; +import com.opengamma.strata.product.TradeInfo; +import com.opengamma.strata.product.capfloor.OvernightInArrearsCapFloor; +import com.opengamma.strata.product.capfloor.OvernightInArrearsCapFloorLeg; +import com.opengamma.strata.product.capfloor.OvernightInArrearsCapFloorTrade; +import com.opengamma.strata.product.common.CapFloor; +import com.opengamma.strata.product.common.PayReceive; +import com.opengamma.strata.product.swap.OvernightRateCalculation; + +/** + * Handles the CSV file format for Overnight in arrears cap/floor trades. + */ +public class OvernightInArrearsCapFloorTradeCsvPlugin + implements TradeCsvParserPlugin, TradeCsvWriterPlugin { + + /** + * The singleton instance of the plugin. + */ + public static final OvernightInArrearsCapFloorTradeCsvPlugin INSTANCE = + new OvernightInArrearsCapFloorTradeCsvPlugin(); + + private static final ImmutableSet HEADERS = ImmutableSet.of( + CAP_FLOOR_FIELD, + START_DATE_FIELD, + END_DATE_FIELD, + PAYMENT_FREQUENCY_FIELD, + DIRECTION_FIELD, + CURRENCY_FIELD, + STRIKE_FIELD, + NOTIONAL_FIELD, + INDEX_FIELD, + PREMIUM_AMOUNT_FIELD, + PREMIUM_CURRENCY_FIELD, + PREMIUM_DIRECTION_FIELD, + PREMIUM_DATE_FIELD, + PREMIUM_DATE_CNV_FIELD, + PREMIUM_DATE_CAL_FIELD, + DATE_ADJ_CNV_FIELD, + DATE_ADJ_CAL_FIELD, + START_DATE_CNV_FIELD, + START_DATE_CAL_FIELD, + END_DATE_CNV_FIELD, + END_DATE_CAL_FIELD, + STUB_CONVENTION_FIELD, + ROLL_CONVENTION_FIELD, + FIRST_REGULAR_START_DATE_FIELD, + LAST_REGULAR_END_DATE_FIELD, + OVERRIDE_START_DATE_FIELD, + OVERRIDE_START_DATE_CNV_FIELD, + OVERRIDE_START_DATE_CAL_FIELD); + + //------------------------------------------------------------------------- + @Override + public Set tradeTypeNames() { + return ImmutableSet.of("OVERNIGHTCAPFLOOR", "OVERNIGHT CAPFLOOR"); + } + + @Override + public Optional parseTrade( + Class requiredJavaType, + CsvRow baseRow, + List additionalRows, + TradeInfo info, + TradeCsvInfoResolver resolver) { + + if (requiredJavaType.isAssignableFrom(OvernightInArrearsCapFloorTrade.class)) { + return Optional.of(resolver.parseOvernightCapFloorTrade(baseRow, info)); + } + return Optional.empty(); + } + + @Override + public String getName() { + return OvernightInArrearsCapFloorTrade.class.getSimpleName(); + } + + @Override + public Set> supportedTradeTypes() { + return ImmutableSet.of(OvernightInArrearsCapFloorTrade.class); + } + + //------------------------------------------------------------------------- + /** + * Parses from the CSV row. + * + * @param row the CSV row + * @param info the trade info + * @param resolver the resolver used to parse additional information + * @return the parsed trade + */ + static OvernightInArrearsCapFloorTrade parseCapFloor(CsvRow row, TradeInfo info, TradeCsvInfoResolver resolver) { + OvernightInArrearsCapFloorTrade overnightCapFloorTrade = parseRow(row, info); + return resolver.completeTrade(row, overnightCapFloorTrade); + } + + //------------------------------------------------------------------------- + // parses the row to a trade + private static OvernightInArrearsCapFloorTrade parseRow(CsvRow row, TradeInfo info) { + OvernightInArrearsCapFloor overnightInArrearsCapFloor = parseOvernightInArrearsCapFloor(row); + Optional paymentOpt = parsePremium(row); + return paymentOpt.map(adjustablePayment -> + OvernightInArrearsCapFloorTrade.builder() + .info(info) + .product(overnightInArrearsCapFloor) + .premium(adjustablePayment) + .build()) + .orElseGet(() -> OvernightInArrearsCapFloorTrade.builder() + .info(info) + .product(overnightInArrearsCapFloor) + .build()); + } + + // parse an OvernightInArrearsCapFloor + private static OvernightInArrearsCapFloor parseOvernightInArrearsCapFloor(CsvRow row) { + PayReceive payReceive = row.getValue(DIRECTION_FIELD, LoaderUtils::parsePayReceive); + Currency currency = row.getValue(CURRENCY_FIELD, LoaderUtils::parseCurrency); + ValueSchedule strike = ValueSchedule.of(row.getValue(STRIKE_FIELD, LoaderUtils::parseDoublePercent)); + double notional = row.getValue(NOTIONAL_FIELD, LoaderUtils::parseDouble); + OvernightIndex overnightIndex = parseOvernightIndex(row); + PeriodicSchedule paymentSchedule = parseSchedule(row, currency); + OvernightInArrearsCapFloorLeg.Builder capFloorLegBuilder = OvernightInArrearsCapFloorLeg.builder() + .payReceive(payReceive) + .paymentSchedule(paymentSchedule) + .currency(currency) + .notional(ValueSchedule.of(notional)) + .calculation(OvernightRateCalculation.of(overnightIndex)); + CapFloor capFloorType = LoaderUtils.parseCapFloor(row.getValue(CAP_FLOOR_FIELD)); + if (capFloorType.isCap()) { + capFloorLegBuilder.capSchedule(strike); + } else { + capFloorLegBuilder.floorSchedule(strike); + } + OvernightInArrearsCapFloorLeg capFloorLeg = capFloorLegBuilder.build(); + return OvernightInArrearsCapFloor.of(capFloorLeg); + } + + // parse the overnight index + private static OvernightIndex parseOvernightIndex(CsvRow row) { + Index index = row.getValue(INDEX_FIELD, LoaderUtils::findIndex); + if (index instanceof OvernightIndex) { + return (OvernightIndex) index; + } else { + throw new ParseFailureException("Index '{value}' is not an overnight index", index.getName()); + } + } + + // parse the periodic schedule for CapFloor + private static PeriodicSchedule parseSchedule(CsvRow row, Currency currency) { + PeriodicSchedule.Builder builder = PeriodicSchedule.builder(); + // basics + builder.startDate(row.getValue(START_DATE_FIELD, LoaderUtils::parseDate)); + builder.endDate(row.getValue(END_DATE_FIELD, LoaderUtils::parseDate)); + builder.frequency(Frequency.parse(row.getValue(PAYMENT_FREQUENCY_FIELD))); + // stub period is not allowed for CapFloor trade + builder.stubConvention(StubConvention.NONE); + // adjustments + BusinessDayAdjustment dateAdj = + CsvLoaderUtils.parseBusinessDayAdjustment(row, DATE_ADJ_CNV_FIELD, DATE_ADJ_CAL_FIELD) + .orElse(BusinessDayAdjustment.NONE); + builder.businessDayAdjustment(dateAdj); + CsvLoaderUtils.parseBusinessDayAdjustment(row, START_DATE_CNV_FIELD, START_DATE_CAL_FIELD) + .ifPresent(builder::startDateBusinessDayAdjustment); + CsvLoaderUtils.parseBusinessDayAdjustment(row, END_DATE_CNV_FIELD, END_DATE_CAL_FIELD) + .ifPresent(builder::endDateBusinessDayAdjustment); + // optionals + row.findValue(ROLL_CONVENTION_FIELD) + .map(LoaderUtils::parseRollConvention) + .ifPresent(builder::rollConvention); + row.findValue(FIRST_REGULAR_START_DATE_FIELD) + .map(LoaderUtils::parseDate) + .ifPresent(builder::firstRegularStartDate); + row.findValue(LAST_REGULAR_END_DATE_FIELD) + .map(LoaderUtils::parseDate) + .ifPresent(builder::lastRegularEndDate); + Optional overrideDateOpt = row.findValue(OVERRIDE_START_DATE_FIELD) + .map(ignored -> CsvLoaderUtils.parseAdjustableDate( + row, + OVERRIDE_START_DATE_FIELD, + OVERRIDE_START_DATE_CNV_FIELD, + OVERRIDE_START_DATE_CAL_FIELD, + BusinessDayConventions.MODIFIED_FOLLOWING, + currency)); + overrideDateOpt.ifPresent(builder::overrideStartDate); + return builder.build(); + } + + // parse the upfront premium amount + private static Optional parsePremium(CsvRow row) { + Optional premiumAmountOpt = row.findValue(PREMIUM_AMOUNT_FIELD) + .map(LoaderUtils::parseDouble); + if (premiumAmountOpt.isPresent()) { + Currency premiumCurrency = row.getValue(PREMIUM_CURRENCY_FIELD, LoaderUtils::parseCurrency); + PayReceive premiumDirection = row.getValue(PREMIUM_DIRECTION_FIELD, LoaderUtils::parsePayReceive); + LocalDate premiumDate = row.getValue(PREMIUM_DATE_FIELD, LoaderUtils::parseDate); + CurrencyAmount premiumAmount = CurrencyAmount.of(premiumCurrency, premiumAmountOpt.get()); + AdjustablePayment payment = premiumDirection.isPay() ? + AdjustablePayment.ofPay(premiumAmount, premiumDate) : + AdjustablePayment.ofReceive(premiumAmount, premiumDate); + return Optional.of(payment); + } + return Optional.empty(); + } + + //------------------------------------------------------------------------- + @Override + public Set headers(List trades) { + return HEADERS; + } + + @Override + public void writeCsv(CsvOutput.CsvRowOutputWithHeaders csv, OvernightInArrearsCapFloorTrade trade) { + OvernightInArrearsCapFloorLeg capFloorLeg = trade.getProduct().getCapFloorLeg(); + csv.writeCell(TRADE_TYPE_FIELD, "OvernightCapFloor"); + String capFloorType; + double strike; + if (capFloorLeg.getCapSchedule().isPresent()) { + capFloorType = "Cap"; + strike = capFloorLeg.getCapSchedule().get().getInitialValue(); + } else if (capFloorLeg.getFloorSchedule().isPresent()) { + capFloorType = "Floor"; + strike = capFloorLeg.getFloorSchedule().get().getInitialValue(); + } else { + throw new UnsupportedOperationException("Unknown CapFloor type, trade is missing cap or floor schedule"); + } + csv.writeCell(CAP_FLOOR_FIELD, capFloorType); + writePeriodicSchedule(csv, capFloorLeg.getPaymentSchedule()); + csv.writeCell(DIRECTION_FIELD, capFloorLeg.getPayReceive()); + csv.writeCell(CURRENCY_FIELD, capFloorLeg.getCurrency()); + csv.writeCell(STRIKE_FIELD, formattedPercentage(strike)); + csv.writeCell(NOTIONAL_FIELD, capFloorLeg.getNotional().getInitialValue()); + csv.writeCell(INDEX_FIELD, capFloorLeg.getCalculation().getIndex()); + trade.getPremium().ifPresent(premium -> CsvWriterUtils.writePremiumFields(csv, premium)); + csv.writeNewLine(); + } + + private void writePeriodicSchedule(CsvOutput.CsvRowOutputWithHeaders csv, PeriodicSchedule paymentSchedule) { + csv.writeCell(START_DATE_FIELD, paymentSchedule.getStartDate()); + csv.writeCell(END_DATE_FIELD, paymentSchedule.getEndDate()); + csv.writeCell(PAYMENT_FREQUENCY_FIELD, paymentSchedule.getFrequency()); + csv.writeCell(DATE_ADJ_CNV_FIELD, paymentSchedule.getBusinessDayAdjustment().getConvention()); + csv.writeCell(DATE_ADJ_CAL_FIELD, paymentSchedule.getBusinessDayAdjustment().getCalendar()); + paymentSchedule.getStartDateBusinessDayAdjustment().ifPresent(startDateAdjustment -> { + csv.writeCell(START_DATE_CNV_FIELD, startDateAdjustment.getConvention()); + csv.writeCell(START_DATE_CAL_FIELD, startDateAdjustment.getCalendar()); + }); + paymentSchedule.getEndDateBusinessDayAdjustment().ifPresent(endDateAdjustment -> { + csv.writeCell(END_DATE_CNV_FIELD, endDateAdjustment.getConvention()); + csv.writeCell(END_DATE_CAL_FIELD, endDateAdjustment.getCalendar()); + }); + paymentSchedule.getStubConvention().ifPresent( + stubConvention -> csv.writeCell(STUB_CONVENTION_FIELD, stubConvention)); + paymentSchedule.getRollConvention().ifPresent( + rollConvention -> csv.writeCell(ROLL_CONVENTION_FIELD, rollConvention)); + paymentSchedule.getFirstRegularStartDate().ifPresent( + firstRegDate -> csv.writeCell(FIRST_REGULAR_START_DATE_FIELD, firstRegDate)); + paymentSchedule.getLastRegularEndDate().ifPresent( + lastRegDate -> csv.writeCell(LAST_REGULAR_END_DATE_FIELD, lastRegDate)); + paymentSchedule.getOverrideStartDate().ifPresent(overrideStartDate -> { + csv.writeCell(OVERRIDE_START_DATE_FIELD, overrideStartDate.getUnadjusted()); + csv.writeCell(OVERRIDE_START_DATE_CNV_FIELD, overrideStartDate.getAdjustment().getConvention()); + csv.writeCell(OVERRIDE_START_DATE_CAL_FIELD, overrideStartDate.getAdjustment().getCalendar()); + }); + } + + //------------------------------------------------------------------------- + // Restricted constructor. + private OvernightInArrearsCapFloorTradeCsvPlugin() { + } + +} diff --git a/modules/loader/src/main/java/com/opengamma/strata/loader/csv/TradeCsvInfoResolver.java b/modules/loader/src/main/java/com/opengamma/strata/loader/csv/TradeCsvInfoResolver.java index 00501f8e64..d72840b211 100644 --- a/modules/loader/src/main/java/com/opengamma/strata/loader/csv/TradeCsvInfoResolver.java +++ b/modules/loader/src/main/java/com/opengamma/strata/loader/csv/TradeCsvInfoResolver.java @@ -21,6 +21,7 @@ import com.opengamma.strata.product.TradeInfo; import com.opengamma.strata.product.TradeInfoBuilder; import com.opengamma.strata.product.capfloor.IborCapFloorTrade; +import com.opengamma.strata.product.capfloor.OvernightInArrearsCapFloorTrade; import com.opengamma.strata.product.common.CcpId; import com.opengamma.strata.product.credit.CdsIndexTrade; import com.opengamma.strata.product.credit.CdsTrade; @@ -338,6 +339,23 @@ public default IborCapFloorTrade completeTrade(CsvRow row, IborCapFloorTrade tra return completeTradeCommon(row, trade); } + /** + * Completes the CapFloor trade, potentially parsing additional columns. + *

    + * This is called after the trade has been parsed and after + * {@link #parseTradeInfo(CsvRow, TradeInfoBuilder)}. + *

    + * By default this calls {@link #completeTradeCommon(CsvRow, Trade)}. + * + * @param row the CSV row to parse + * @param trade the parsed trade + * @return the updated trade + */ + public default OvernightInArrearsCapFloorTrade completeTrade(CsvRow row, OvernightInArrearsCapFloorTrade trade) { + //do nothing + return completeTradeCommon(row, trade); + } + //------------------------------------------------------------------------- /** * Parses a FRA trade from CSV. @@ -486,17 +504,29 @@ public default CdsIndexTrade parseCdsIndexTrade(CsvRow row, TradeInfo info) { } /** - * Parses a CapFloor trade from CSV. + * Parses an IBOR CapFloor trade from CSV. * * @param row the CSV row to parse * @param info the trade info - * @return the CapFloor trade + * @return the IBOR CapFloor trade * @throws RuntimeException if the row contains invalid data */ - public default IborCapFloorTrade parseCapFloorTrade(CsvRow row, TradeInfo info) { + public default IborCapFloorTrade parseIborCapFloorTrade(CsvRow row, TradeInfo info) { return IborCapFloorTradeCsvPlugin.parseCapFloor(row, info, this); } + /** + * Parses an overnight CapFloor trade from CSV. + * + * @param row the CSV row to parse + * @param info the trade info + * @return the overnight CapFloor trade + * @throws RuntimeException if the row contains invalid data + */ + public default OvernightInArrearsCapFloorTrade parseOvernightCapFloorTrade(CsvRow row, TradeInfo info) { + return OvernightInArrearsCapFloorTradeCsvPlugin.parseCapFloor(row, info, this); + } + //------------------------------------------------------------------------- /** * Parses any kind of trade from CSV before standard matching. diff --git a/modules/loader/src/main/resources/META-INF/com/opengamma/strata/config/base/TradeCsvParserPlugin.ini b/modules/loader/src/main/resources/META-INF/com/opengamma/strata/config/base/TradeCsvParserPlugin.ini index 57c69cc204..3c9a0fea98 100644 --- a/modules/loader/src/main/resources/META-INF/com/opengamma/strata/config/base/TradeCsvParserPlugin.ini +++ b/modules/loader/src/main/resources/META-INF/com/opengamma/strata/config/base/TradeCsvParserPlugin.ini @@ -17,6 +17,7 @@ com.opengamma.strata.loader.csv.FxSingleTradeCsvPlugin = constants com.opengamma.strata.loader.csv.FxSwapTradeCsvPlugin = constants com.opengamma.strata.loader.csv.FxVanillaOptionTradeCsvPlugin = constants com.opengamma.strata.loader.csv.IborCapFloorTradeCsvPlugin = constants +com.opengamma.strata.loader.csv.OvernightInArrearsCapFloorTradeCsvPlugin = constants com.opengamma.strata.loader.csv.SecurityTradeCsvPlugin = constants com.opengamma.strata.loader.csv.SwapTradeCsvPlugin = constants com.opengamma.strata.loader.csv.SwaptionTradeCsvPlugin = constants diff --git a/modules/loader/src/main/resources/META-INF/com/opengamma/strata/config/base/TradeCsvWriterPlugin.ini b/modules/loader/src/main/resources/META-INF/com/opengamma/strata/config/base/TradeCsvWriterPlugin.ini index e14bc33b53..8a840721c0 100644 --- a/modules/loader/src/main/resources/META-INF/com/opengamma/strata/config/base/TradeCsvWriterPlugin.ini +++ b/modules/loader/src/main/resources/META-INF/com/opengamma/strata/config/base/TradeCsvWriterPlugin.ini @@ -21,6 +21,7 @@ com.opengamma.strata.loader.csv.CdsTradeCsvPlugin = constants com.opengamma.strata.loader.csv.CdsIndexTradeCsvPlugin = constants com.opengamma.strata.loader.csv.SecurityTradeCsvPlugin = constants com.opengamma.strata.loader.csv.IborCapFloorTradeCsvPlugin = constants +com.opengamma.strata.loader.csv.OvernightInArrearsCapFloorTradeCsvPlugin = constants com.opengamma.strata.loader.csv.GenericSecurityTradeCsvPlugin = constants # The set of alternate names diff --git a/modules/loader/src/test/java/com/opengamma/strata/loader/csv/TradeCsvLoaderTest.java b/modules/loader/src/test/java/com/opengamma/strata/loader/csv/TradeCsvLoaderTest.java index 0ae3077bde..fed06aad02 100644 --- a/modules/loader/src/test/java/com/opengamma/strata/loader/csv/TradeCsvLoaderTest.java +++ b/modules/loader/src/test/java/com/opengamma/strata/loader/csv/TradeCsvLoaderTest.java @@ -96,6 +96,9 @@ import com.opengamma.strata.product.capfloor.IborCapFloor; import com.opengamma.strata.product.capfloor.IborCapFloorLeg; import com.opengamma.strata.product.capfloor.IborCapFloorTrade; +import com.opengamma.strata.product.capfloor.OvernightInArrearsCapFloor; +import com.opengamma.strata.product.capfloor.OvernightInArrearsCapFloorLeg; +import com.opengamma.strata.product.capfloor.OvernightInArrearsCapFloorTrade; import com.opengamma.strata.product.common.CcpIds; import com.opengamma.strata.product.common.LongShort; import com.opengamma.strata.product.credit.Cds; @@ -2097,7 +2100,7 @@ public void test_load_filtered() { ImmutableList.of(FILE.getCharSource()), ImmutableList.of(FraTrade.class, TermDepositTrade.class)); assertThat(trades.getValue()).hasSize(6); - assertThat(trades.getFailures()).hasSize(24); + assertThat(trades.getFailures()).hasSize(26); assertThat(trades.getFailures().get(0).getMessage()).isEqualTo( "Trade type not allowed " + SwapTrade.class.getName() + ", only these types are supported: FraTrade, TermDepositTrade"); } @@ -2322,6 +2325,64 @@ public void test_load_CapFloor() { checkRoundtrip(IborCapFloorTrade.class, filtered, expected0, expected1); } + @Test + public void test_load_OvernightCapFloor() { + TradeCsvLoader test = TradeCsvLoader.standard(); + ValueWithFailures> trades = test.load(FILE); + + List filtered = trades.getValue().stream() + .flatMap(filtering(OvernightInArrearsCapFloorTrade.class)) + .collect(toImmutableList()); + assertThat(filtered).hasSize(2); + + OvernightInArrearsCapFloorTrade expected0 = OvernightInArrearsCapFloorTrade.builder() + .info(TradeInfo.builder() + .id(StandardId.of("OG", "123456")) + .tradeDate(date(2017, 6, 1)) + .build()) + .product(OvernightInArrearsCapFloor.of(OvernightInArrearsCapFloorLeg.builder() + .payReceive(RECEIVE) + .paymentSchedule(PeriodicSchedule.of( + date(2020, 3, 10), + date(2025, 3, 10), + Frequency.P3M, + BusinessDayAdjustment.NONE, + StubConvention.NONE, + false)) + .currency(USD) + .notional(ValueSchedule.of(10_000_000)) + .calculation(OvernightRateCalculation.of(OvernightIndices.USD_SOFR)) + .capSchedule(ValueSchedule.of(0.021)) + .build())) + .build(); + assertBeanEquals(expected0, filtered.get(0)); + + OvernightInArrearsCapFloorTrade expected1 = OvernightInArrearsCapFloorTrade.builder() + .info(TradeInfo.builder() + .id(StandardId.of("OG", "123457")) + .tradeDate(date(2017, 6, 1)) + .build()) + .product(OvernightInArrearsCapFloor.of(OvernightInArrearsCapFloorLeg.builder() + .payReceive(PAY) + .paymentSchedule(PeriodicSchedule.of( + date(2020, 3, 10), + date(2030, 3, 10), + Frequency.P6M, + BusinessDayAdjustment.NONE, + StubConvention.NONE, + false)) + .currency(EUR) + .notional(ValueSchedule.of(15_000_000)) + .calculation(OvernightRateCalculation.of(OvernightIndices.EUR_ESTR)) + .floorSchedule(ValueSchedule.of(0.005)) + .build())) + .premium(AdjustablePayment.ofReceive(CurrencyAmount.of(EUR, 5000), date(2020, 3, 10))) + .build(); + assertBeanEquals(expected1, filtered.get(1)); + + checkRoundtrip(OvernightInArrearsCapFloorTrade.class, filtered, expected0, expected1); + } + //------------------------------------------------------------------------- @Test public void test_load_invalidNoHeader() { diff --git a/modules/loader/src/test/resources/com/opengamma/strata/loader/csv/trades.csv b/modules/loader/src/test/resources/com/opengamma/strata/loader/csv/trades.csv index 8bb1368405..5348549445 100644 --- a/modules/loader/src/test/resources/com/opengamma/strata/loader/csv/trades.csv +++ b/modules/loader/src/test/resources/com/opengamma/strata/loader/csv/trades.csv @@ -45,3 +45,6 @@ CDS Index,OG,123455,01/06/2017,,,,,Buy,,,,,5,,,GBP,1000000,01/06/2017,01/06/2022 ,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, CapFloor,OG,123452,01/06/2017,,,,,,,,USD-LIBOR-3M,,,,,USD,10000000,10/03/2020,10/03/2025,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cap,Receive,2.1,3M,,,, CapFloor,OG,123453,01/06/2017,,,,,,,,EUR-EURIBOR-6M,,,,,EUR,15000000,10/03/2020,10/03/2030,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Receive,EUR,5000,10/03/2020,,,,,,,,,,,,,,Floor,Pay,0.5,6M,,,, +,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,, +OvernightCapFloor,OG,123456,01/06/2017,,,,,,,,USD-SOFR,,,,,USD,10000000,10/03/2020,10/03/2025,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Cap,Receive,2.1,3M,,,, +OvernightCapFloor,OG,123457,01/06/2017,,,,,,,,EUR-ESTR,,,,,EUR,15000000,10/03/2020,10/03/2030,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,Receive,EUR,5000,10/03/2020,,,,,,,,,,,,,,Floor,Pay,0.5,6M,,,, From b8a13c7dd24f105855da462936d8f22380c8e6c0 Mon Sep 17 00:00:00 2001 From: Yuki Iwashita Date: Wed, 16 Oct 2024 21:10:21 +0100 Subject: [PATCH 111/116] Overnight rate in arrears cap floor pricers (#2680) * overnight cap product * tests * javadoc * line * clean * white spaces * pricers * failing test for accrual * pricers * test * spaces * addressed review comments * error message --- ...tInArrearsCapletFloorletPeriodAmounts.java | 327 +++++++++++++++++ ...rsCapletFloorletPeriodCurrencyAmounts.java | 328 +++++++++++++++++ ...brOvernightInArrearsCapFloorLegPricer.java | 222 ++++++++++++ ...ernightInArrearsCapFloorProductPricer.java | 257 ++++++++++++++ ...OvernightInArrearsCapFloorTradePricer.java | 248 +++++++++++++ ...htInArrearsCapletFloorletPeriodPricer.java | 66 +++- ...rrearsCapletFloorletPeriodAmountsTest.java | 110 ++++++ ...pletFloorletPeriodCurrencyAmountsTest.java | 111 ++++++ ...ernightInArrearsCapFloorLegPricerTest.java | 335 ++++++++++++++++++ ...ghtInArrearsCapFloorProductPricerTest.java | 150 ++++++++ ...abrOvernightInArrearsCapFloorTestData.java | 169 +++++++++ ...nightInArrearsCapFloorTradePricerTest.java | 186 ++++++++++ ...ArrearsCapletFloorletPeriodPricerTest.java | 100 +++++- 13 files changed, 2598 insertions(+), 11 deletions(-) create mode 100644 modules/pricer/src/main/java/com/opengamma/strata/pricer/capfloor/OvernightInArrearsCapletFloorletPeriodAmounts.java create mode 100644 modules/pricer/src/main/java/com/opengamma/strata/pricer/capfloor/OvernightInArrearsCapletFloorletPeriodCurrencyAmounts.java create mode 100644 modules/pricer/src/main/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorLegPricer.java create mode 100644 modules/pricer/src/main/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorProductPricer.java create mode 100644 modules/pricer/src/main/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorTradePricer.java create mode 100644 modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/OvernightInArrearsCapletFloorletPeriodAmountsTest.java create mode 100644 modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/OvernightInArrearsCapletFloorletPeriodCurrencyAmountsTest.java create mode 100644 modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorLegPricerTest.java create mode 100644 modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorProductPricerTest.java create mode 100644 modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorTestData.java create mode 100644 modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorTradePricerTest.java diff --git a/modules/pricer/src/main/java/com/opengamma/strata/pricer/capfloor/OvernightInArrearsCapletFloorletPeriodAmounts.java b/modules/pricer/src/main/java/com/opengamma/strata/pricer/capfloor/OvernightInArrearsCapletFloorletPeriodAmounts.java new file mode 100644 index 0000000000..86bc1a6723 --- /dev/null +++ b/modules/pricer/src/main/java/com/opengamma/strata/pricer/capfloor/OvernightInArrearsCapletFloorletPeriodAmounts.java @@ -0,0 +1,327 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.pricer.capfloor; + +import java.io.Serializable; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Optional; + +import org.joda.beans.Bean; +import org.joda.beans.ImmutableBean; +import org.joda.beans.JodaBeanUtils; +import org.joda.beans.MetaBean; +import org.joda.beans.MetaProperty; +import org.joda.beans.gen.BeanDefinition; +import org.joda.beans.gen.PropertyDefinition; +import org.joda.beans.impl.direct.DirectFieldsBeanBuilder; +import org.joda.beans.impl.direct.DirectMetaBean; +import org.joda.beans.impl.direct.DirectMetaProperty; +import org.joda.beans.impl.direct.DirectMetaPropertyMap; + +import com.google.common.collect.ImmutableMap; +import com.opengamma.strata.product.capfloor.OvernightInArrearsCapletFloorletPeriod; + +/** + * A map of double values keyed by overnight rate in arrears caplet/floorlet periods. + *

    + * The double values should represent the same metric. + */ +@BeanDefinition +public final class OvernightInArrearsCapletFloorletPeriodAmounts + implements ImmutableBean, Serializable { + + /** + * The map of overnight rate in arrears caplet/floorlet periods to the double amount. + */ + @PropertyDefinition(validate = "notNull") + private final ImmutableMap amounts; + + //------------------------------------------------------------------------- + /** + * Obtains an instance of double amounts. + * + * @param doubleMap the map of doubles + * @return the instance + */ + public static OvernightInArrearsCapletFloorletPeriodAmounts of( + Map doubleMap) { + + return new OvernightInArrearsCapletFloorletPeriodAmounts(doubleMap); + } + + /** + * Gets a double amount for the provided overnight rate in arrears caplet/floorlet. + * + * @param period the caplet/floorlet + * @return the double amount, empty if missing + */ + public Optional findAmount(OvernightInArrearsCapletFloorletPeriod period) { + return Optional.ofNullable(amounts.get(period)); + } + + /** + * Gets a double amount for the provided overnight rate in arrears caplet/floorlet. + * + * @param period the caplet/floorlet + * @return the double amount + * @throws IllegalArgumentException if the period is missing + */ + public double getAmount(OvernightInArrearsCapletFloorletPeriod period) { + return findAmount(period).orElseThrow( + () -> new IllegalArgumentException("Could not find double amount for " + period)); + } + + //------------------------- AUTOGENERATED START ------------------------- + /** + * The meta-bean for {@code OvernightInArrearsCapletFloorletPeriodAmounts}. + * @return the meta-bean, not null + */ + public static OvernightInArrearsCapletFloorletPeriodAmounts.Meta meta() { + return OvernightInArrearsCapletFloorletPeriodAmounts.Meta.INSTANCE; + } + + static { + MetaBean.register(OvernightInArrearsCapletFloorletPeriodAmounts.Meta.INSTANCE); + } + + /** + * The serialization version id. + */ + private static final long serialVersionUID = 1L; + + /** + * Returns a builder used to create an instance of the bean. + * @return the builder, not null + */ + public static OvernightInArrearsCapletFloorletPeriodAmounts.Builder builder() { + return new OvernightInArrearsCapletFloorletPeriodAmounts.Builder(); + } + + private OvernightInArrearsCapletFloorletPeriodAmounts( + Map amounts) { + JodaBeanUtils.notNull(amounts, "amounts"); + this.amounts = ImmutableMap.copyOf(amounts); + } + + @Override + public OvernightInArrearsCapletFloorletPeriodAmounts.Meta metaBean() { + return OvernightInArrearsCapletFloorletPeriodAmounts.Meta.INSTANCE; + } + + //----------------------------------------------------------------------- + /** + * Gets the map of overnight rate in arrears caplet/floorlet periods to the double amount. + * @return the value of the property, not null + */ + public ImmutableMap getAmounts() { + return amounts; + } + + //----------------------------------------------------------------------- + /** + * Returns a builder that allows this bean to be mutated. + * @return the mutable builder, not null + */ + public Builder toBuilder() { + return new Builder(this); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && obj.getClass() == this.getClass()) { + OvernightInArrearsCapletFloorletPeriodAmounts other = (OvernightInArrearsCapletFloorletPeriodAmounts) obj; + return JodaBeanUtils.equal(amounts, other.amounts); + } + return false; + } + + @Override + public int hashCode() { + int hash = getClass().hashCode(); + hash = hash * 31 + JodaBeanUtils.hashCode(amounts); + return hash; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(64); + buf.append("OvernightInArrearsCapletFloorletPeriodAmounts{"); + buf.append("amounts").append('=').append(JodaBeanUtils.toString(amounts)); + buf.append('}'); + return buf.toString(); + } + + //----------------------------------------------------------------------- + /** + * The meta-bean for {@code OvernightInArrearsCapletFloorletPeriodAmounts}. + */ + public static final class Meta extends DirectMetaBean { + /** + * The singleton instance of the meta-bean. + */ + static final Meta INSTANCE = new Meta(); + + /** + * The meta-property for the {@code amounts} property. + */ + @SuppressWarnings({"unchecked", "rawtypes" }) + private final MetaProperty> amounts = DirectMetaProperty.ofImmutable( + this, "amounts", OvernightInArrearsCapletFloorletPeriodAmounts.class, (Class) ImmutableMap.class); + /** + * The meta-properties. + */ + private final Map> metaPropertyMap$ = new DirectMetaPropertyMap( + this, null, + "amounts"); + + /** + * Restricted constructor. + */ + private Meta() { + } + + @Override + protected MetaProperty metaPropertyGet(String propertyName) { + switch (propertyName.hashCode()) { + case -879772901: // amounts + return amounts; + } + return super.metaPropertyGet(propertyName); + } + + @Override + public OvernightInArrearsCapletFloorletPeriodAmounts.Builder builder() { + return new OvernightInArrearsCapletFloorletPeriodAmounts.Builder(); + } + + @Override + public Class beanType() { + return OvernightInArrearsCapletFloorletPeriodAmounts.class; + } + + @Override + public Map> metaPropertyMap() { + return metaPropertyMap$; + } + + //----------------------------------------------------------------------- + /** + * The meta-property for the {@code amounts} property. + * @return the meta-property, not null + */ + public MetaProperty> amounts() { + return amounts; + } + + //----------------------------------------------------------------------- + @Override + protected Object propertyGet(Bean bean, String propertyName, boolean quiet) { + switch (propertyName.hashCode()) { + case -879772901: // amounts + return ((OvernightInArrearsCapletFloorletPeriodAmounts) bean).getAmounts(); + } + return super.propertyGet(bean, propertyName, quiet); + } + + @Override + protected void propertySet(Bean bean, String propertyName, Object newValue, boolean quiet) { + metaProperty(propertyName); + if (quiet) { + return; + } + throw new UnsupportedOperationException("Property cannot be written: " + propertyName); + } + + } + + //----------------------------------------------------------------------- + /** + * The bean-builder for {@code OvernightInArrearsCapletFloorletPeriodAmounts}. + */ + public static final class Builder extends DirectFieldsBeanBuilder { + + private Map amounts = ImmutableMap.of(); + + /** + * Restricted constructor. + */ + private Builder() { + } + + /** + * Restricted copy constructor. + * @param beanToCopy the bean to copy from, not null + */ + private Builder(OvernightInArrearsCapletFloorletPeriodAmounts beanToCopy) { + this.amounts = beanToCopy.getAmounts(); + } + + //----------------------------------------------------------------------- + @Override + public Object get(String propertyName) { + switch (propertyName.hashCode()) { + case -879772901: // amounts + return amounts; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + } + + @SuppressWarnings("unchecked") + @Override + public Builder set(String propertyName, Object newValue) { + switch (propertyName.hashCode()) { + case -879772901: // amounts + this.amounts = (Map) newValue; + break; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + return this; + } + + @Override + public Builder set(MetaProperty property, Object value) { + super.set(property, value); + return this; + } + + @Override + public OvernightInArrearsCapletFloorletPeriodAmounts build() { + return new OvernightInArrearsCapletFloorletPeriodAmounts( + amounts); + } + + //----------------------------------------------------------------------- + /** + * Sets the map of overnight rate in arrears caplet/floorlet periods to the double amount. + * @param amounts the new value, not null + * @return this, for chaining, not null + */ + public Builder amounts(Map amounts) { + JodaBeanUtils.notNull(amounts, "amounts"); + this.amounts = amounts; + return this; + } + + //----------------------------------------------------------------------- + @Override + public String toString() { + StringBuilder buf = new StringBuilder(64); + buf.append("OvernightInArrearsCapletFloorletPeriodAmounts.Builder{"); + buf.append("amounts").append('=').append(JodaBeanUtils.toString(amounts)); + buf.append('}'); + return buf.toString(); + } + + } + + //-------------------------- AUTOGENERATED END -------------------------- +} diff --git a/modules/pricer/src/main/java/com/opengamma/strata/pricer/capfloor/OvernightInArrearsCapletFloorletPeriodCurrencyAmounts.java b/modules/pricer/src/main/java/com/opengamma/strata/pricer/capfloor/OvernightInArrearsCapletFloorletPeriodCurrencyAmounts.java new file mode 100644 index 0000000000..c7ea8d6df0 --- /dev/null +++ b/modules/pricer/src/main/java/com/opengamma/strata/pricer/capfloor/OvernightInArrearsCapletFloorletPeriodCurrencyAmounts.java @@ -0,0 +1,328 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.pricer.capfloor; + +import java.io.Serializable; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Optional; + +import org.joda.beans.Bean; +import org.joda.beans.ImmutableBean; +import org.joda.beans.JodaBeanUtils; +import org.joda.beans.MetaBean; +import org.joda.beans.MetaProperty; +import org.joda.beans.gen.BeanDefinition; +import org.joda.beans.gen.PropertyDefinition; +import org.joda.beans.impl.direct.DirectFieldsBeanBuilder; +import org.joda.beans.impl.direct.DirectMetaBean; +import org.joda.beans.impl.direct.DirectMetaProperty; +import org.joda.beans.impl.direct.DirectMetaPropertyMap; + +import com.google.common.collect.ImmutableMap; +import com.opengamma.strata.basics.currency.CurrencyAmount; +import com.opengamma.strata.product.capfloor.OvernightInArrearsCapletFloorletPeriod; + +/** + * A map of currency amounts keyed by overnight in arrears caplet/floorlet periods. + *

    + * The currency amounts should represent the same metric. + */ +@BeanDefinition +public final class OvernightInArrearsCapletFloorletPeriodCurrencyAmounts + implements ImmutableBean, Serializable { + + /** + * The map of overnight rate in arrears caplet/floorlet periods to the currency amount. + */ + @PropertyDefinition(validate = "notNull") + private final ImmutableMap amounts; + + //------------------------------------------------------------------------- + /** + * Obtains an instance of currency amounts. + * + * @param currencyAmountMap the map of currency amounts + * @return the instance + */ + public static OvernightInArrearsCapletFloorletPeriodCurrencyAmounts of( + Map currencyAmountMap) { + + return new OvernightInArrearsCapletFloorletPeriodCurrencyAmounts(currencyAmountMap); + } + + /** + * Gets a currency amount for the provided overnight rate in arrears caplet/floorlet. + * + * @param period the caplet/floorlet + * @return the currency amount, empty if missing + */ + public Optional findAmount(OvernightInArrearsCapletFloorletPeriod period) { + return Optional.ofNullable(amounts.get(period)); + } + + /** + * Gets a currency amount for the provided overnight rate in arrears caplet/floorlet. + * + * @param period the caplet/floorlet + * @return the currency amount + * @throws IllegalArgumentException if the period is missing + */ + public CurrencyAmount getAmount(OvernightInArrearsCapletFloorletPeriod period) { + return findAmount(period).orElseThrow( + () -> new IllegalArgumentException("Could not find currency amount for " + period)); + } + + //------------------------- AUTOGENERATED START ------------------------- + /** + * The meta-bean for {@code OvernightInArrearsCapletFloorletPeriodCurrencyAmounts}. + * @return the meta-bean, not null + */ + public static OvernightInArrearsCapletFloorletPeriodCurrencyAmounts.Meta meta() { + return OvernightInArrearsCapletFloorletPeriodCurrencyAmounts.Meta.INSTANCE; + } + + static { + MetaBean.register(OvernightInArrearsCapletFloorletPeriodCurrencyAmounts.Meta.INSTANCE); + } + + /** + * The serialization version id. + */ + private static final long serialVersionUID = 1L; + + /** + * Returns a builder used to create an instance of the bean. + * @return the builder, not null + */ + public static OvernightInArrearsCapletFloorletPeriodCurrencyAmounts.Builder builder() { + return new OvernightInArrearsCapletFloorletPeriodCurrencyAmounts.Builder(); + } + + private OvernightInArrearsCapletFloorletPeriodCurrencyAmounts( + Map amounts) { + JodaBeanUtils.notNull(amounts, "amounts"); + this.amounts = ImmutableMap.copyOf(amounts); + } + + @Override + public OvernightInArrearsCapletFloorletPeriodCurrencyAmounts.Meta metaBean() { + return OvernightInArrearsCapletFloorletPeriodCurrencyAmounts.Meta.INSTANCE; + } + + //----------------------------------------------------------------------- + /** + * Gets the map of overnight rate in arrears caplet/floorlet periods to the currency amount. + * @return the value of the property, not null + */ + public ImmutableMap getAmounts() { + return amounts; + } + + //----------------------------------------------------------------------- + /** + * Returns a builder that allows this bean to be mutated. + * @return the mutable builder, not null + */ + public Builder toBuilder() { + return new Builder(this); + } + + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + if (obj != null && obj.getClass() == this.getClass()) { + OvernightInArrearsCapletFloorletPeriodCurrencyAmounts other = (OvernightInArrearsCapletFloorletPeriodCurrencyAmounts) obj; + return JodaBeanUtils.equal(amounts, other.amounts); + } + return false; + } + + @Override + public int hashCode() { + int hash = getClass().hashCode(); + hash = hash * 31 + JodaBeanUtils.hashCode(amounts); + return hash; + } + + @Override + public String toString() { + StringBuilder buf = new StringBuilder(64); + buf.append("OvernightInArrearsCapletFloorletPeriodCurrencyAmounts{"); + buf.append("amounts").append('=').append(JodaBeanUtils.toString(amounts)); + buf.append('}'); + return buf.toString(); + } + + //----------------------------------------------------------------------- + /** + * The meta-bean for {@code OvernightInArrearsCapletFloorletPeriodCurrencyAmounts}. + */ + public static final class Meta extends DirectMetaBean { + /** + * The singleton instance of the meta-bean. + */ + static final Meta INSTANCE = new Meta(); + + /** + * The meta-property for the {@code amounts} property. + */ + @SuppressWarnings({"unchecked", "rawtypes" }) + private final MetaProperty> amounts = DirectMetaProperty.ofImmutable( + this, "amounts", OvernightInArrearsCapletFloorletPeriodCurrencyAmounts.class, (Class) ImmutableMap.class); + /** + * The meta-properties. + */ + private final Map> metaPropertyMap$ = new DirectMetaPropertyMap( + this, null, + "amounts"); + + /** + * Restricted constructor. + */ + private Meta() { + } + + @Override + protected MetaProperty metaPropertyGet(String propertyName) { + switch (propertyName.hashCode()) { + case -879772901: // amounts + return amounts; + } + return super.metaPropertyGet(propertyName); + } + + @Override + public OvernightInArrearsCapletFloorletPeriodCurrencyAmounts.Builder builder() { + return new OvernightInArrearsCapletFloorletPeriodCurrencyAmounts.Builder(); + } + + @Override + public Class beanType() { + return OvernightInArrearsCapletFloorletPeriodCurrencyAmounts.class; + } + + @Override + public Map> metaPropertyMap() { + return metaPropertyMap$; + } + + //----------------------------------------------------------------------- + /** + * The meta-property for the {@code amounts} property. + * @return the meta-property, not null + */ + public MetaProperty> amounts() { + return amounts; + } + + //----------------------------------------------------------------------- + @Override + protected Object propertyGet(Bean bean, String propertyName, boolean quiet) { + switch (propertyName.hashCode()) { + case -879772901: // amounts + return ((OvernightInArrearsCapletFloorletPeriodCurrencyAmounts) bean).getAmounts(); + } + return super.propertyGet(bean, propertyName, quiet); + } + + @Override + protected void propertySet(Bean bean, String propertyName, Object newValue, boolean quiet) { + metaProperty(propertyName); + if (quiet) { + return; + } + throw new UnsupportedOperationException("Property cannot be written: " + propertyName); + } + + } + + //----------------------------------------------------------------------- + /** + * The bean-builder for {@code OvernightInArrearsCapletFloorletPeriodCurrencyAmounts}. + */ + public static final class Builder extends DirectFieldsBeanBuilder { + + private Map amounts = ImmutableMap.of(); + + /** + * Restricted constructor. + */ + private Builder() { + } + + /** + * Restricted copy constructor. + * @param beanToCopy the bean to copy from, not null + */ + private Builder(OvernightInArrearsCapletFloorletPeriodCurrencyAmounts beanToCopy) { + this.amounts = beanToCopy.getAmounts(); + } + + //----------------------------------------------------------------------- + @Override + public Object get(String propertyName) { + switch (propertyName.hashCode()) { + case -879772901: // amounts + return amounts; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + } + + @SuppressWarnings("unchecked") + @Override + public Builder set(String propertyName, Object newValue) { + switch (propertyName.hashCode()) { + case -879772901: // amounts + this.amounts = (Map) newValue; + break; + default: + throw new NoSuchElementException("Unknown property: " + propertyName); + } + return this; + } + + @Override + public Builder set(MetaProperty property, Object value) { + super.set(property, value); + return this; + } + + @Override + public OvernightInArrearsCapletFloorletPeriodCurrencyAmounts build() { + return new OvernightInArrearsCapletFloorletPeriodCurrencyAmounts( + amounts); + } + + //----------------------------------------------------------------------- + /** + * Sets the map of overnight rate in arrears caplet/floorlet periods to the currency amount. + * @param amounts the new value, not null + * @return this, for chaining, not null + */ + public Builder amounts(Map amounts) { + JodaBeanUtils.notNull(amounts, "amounts"); + this.amounts = amounts; + return this; + } + + //----------------------------------------------------------------------- + @Override + public String toString() { + StringBuilder buf = new StringBuilder(64); + buf.append("OvernightInArrearsCapletFloorletPeriodCurrencyAmounts.Builder{"); + buf.append("amounts").append('=').append(JodaBeanUtils.toString(amounts)); + buf.append('}'); + return buf.toString(); + } + + } + + //-------------------------- AUTOGENERATED END -------------------------- +} diff --git a/modules/pricer/src/main/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorLegPricer.java b/modules/pricer/src/main/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorLegPricer.java new file mode 100644 index 0000000000..9feb394b4d --- /dev/null +++ b/modules/pricer/src/main/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorLegPricer.java @@ -0,0 +1,222 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.pricer.capfloor; + +import java.time.ZoneOffset; +import java.util.Map; + +import com.google.common.collect.ImmutableMap; +import com.opengamma.strata.basics.currency.CurrencyAmount; +import com.opengamma.strata.collect.ArgChecker; +import com.opengamma.strata.collect.MapStream; +import com.opengamma.strata.market.sensitivity.PointSensitivityBuilder; +import com.opengamma.strata.pricer.rate.RatesProvider; +import com.opengamma.strata.product.capfloor.OvernightInArrearsCapletFloorletPeriod; +import com.opengamma.strata.product.capfloor.ResolvedOvernightInArrearsCapFloorLeg; + +/** + * Pricer for overnight rate in arrears cap/floor legs in SABR model. + */ +public class SabrOvernightInArrearsCapFloorLegPricer { + + /** + * Default implementation. + */ + public static final SabrOvernightInArrearsCapFloorLegPricer DEFAULT = + new SabrOvernightInArrearsCapFloorLegPricer(SabrOvernightInArrearsCapletFloorletPeriodPricer.DEFAULT); + + /** + * The period pricer. + */ + private final SabrOvernightInArrearsCapletFloorletPeriodPricer periodPricer; + + /** + * Creates an instance. + * + * @param periodPricer the pricer for {@link OvernightInArrearsCapletFloorletPeriod}. + */ + public SabrOvernightInArrearsCapFloorLegPricer(SabrOvernightInArrearsCapletFloorletPeriodPricer periodPricer) { + this.periodPricer = ArgChecker.notNull(periodPricer, "periodPricer"); + } + + //------------------------------------------------------------------------- + /** + * Obtains the underlying period pricer. + * + * @return the period pricer + */ + public SabrOvernightInArrearsCapletFloorletPeriodPricer getPeriodPricer() { + return periodPricer; + } + + //------------------------------------------------------------------------- + /** + * Calculates the present value of the overnight rate in arrears cap/floor leg. + *

    + * The present value of the leg is the value on the valuation date. + * The result is returned using the payment currency of the leg. + * + * @param capFloorLeg the cap/floor leg + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @return the present value + */ + public CurrencyAmount presentValue( + ResolvedOvernightInArrearsCapFloorLeg capFloorLeg, + RatesProvider ratesProvider, + SabrParametersIborCapletFloorletVolatilities volatilities) { + + validate(ratesProvider, volatilities); + return capFloorLeg.getCapletFloorletPeriods().stream() + .map(period -> periodPricer.presentValue(period, ratesProvider, volatilities)) + .reduce(CurrencyAmount::plus) + .orElse(CurrencyAmount.zero(capFloorLeg.getCurrency())); + } + + //------------------------------------------------------------------------- + /** + * Calculates the present value for each caplet/floorlet of the overnight rate in arrears cap/floor leg. + *

    + * The present value of each caplet/floorlet is the value on the valuation date. + * The result is returned using the payment currency of the leg. + * + * @param capFloorLeg the cap/floor leg + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @return the present values + */ + public OvernightInArrearsCapletFloorletPeriodCurrencyAmounts presentValueCapletFloorletPeriods( + ResolvedOvernightInArrearsCapFloorLeg capFloorLeg, + RatesProvider ratesProvider, + SabrParametersIborCapletFloorletVolatilities volatilities) { + + validate(ratesProvider, volatilities); + Map periodPresentValues = + MapStream.of(capFloorLeg.getCapletFloorletPeriods()) + .mapValues(period -> periodPricer.presentValue(period, ratesProvider, volatilities)) + .toMap(); + return OvernightInArrearsCapletFloorletPeriodCurrencyAmounts.of(periodPresentValues); + } + + //------------------------------------------------------------------------- + /** + * Calculates the current cash of the overnight in arrears cap/floor leg. + * + * @param capFloorLeg the cap/floor leg + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @return the current cash + */ + public CurrencyAmount currentCash( + ResolvedOvernightInArrearsCapFloorLeg capFloorLeg, + RatesProvider ratesProvider, + SabrParametersIborCapletFloorletVolatilities volatilities) { + + validate(ratesProvider, volatilities); + return capFloorLeg.getCapletFloorletPeriods().stream() + .filter(period -> period.getPaymentDate().equals(ratesProvider.getValuationDate())) + .map(period -> periodPricer.presentValue(period, ratesProvider, volatilities)) + .reduce(CurrencyAmount::plus) + .orElse(CurrencyAmount.zero(capFloorLeg.getCurrency())); + } + + //------------------------------------------------------------------------- + /** + * Calculates the forward rates for each caplet/floorlet of the overnight rate in arrears cap/floor leg. + * + * @param capFloorLeg the cap/floor leg + * @param ratesProvider the rates provider + * @return the forward rates + */ + public OvernightInArrearsCapletFloorletPeriodAmounts forwardRates( + ResolvedOvernightInArrearsCapFloorLeg capFloorLeg, + RatesProvider ratesProvider) { + + Map forwardRates = + MapStream.of(capFloorLeg.getCapletFloorletPeriods()) + .filterKeys(period -> !ratesProvider.getValuationDate().isAfter(period.getOvernightRate().getEndDate())) + .mapValues(period -> periodPricer.forwardRate(period, ratesProvider)) + .toMap(); + return OvernightInArrearsCapletFloorletPeriodAmounts.of(forwardRates); + } + + //------------------------------------------------------------------------- + /** + * Calculates the implied volatilities for each caplet/floorlet of the overnight rate in arrears cap/floor leg. + * + * @param capFloorLeg the cap/floor leg + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @return the implied volatilities + */ + public OvernightInArrearsCapletFloorletPeriodAmounts impliedVolatilities( + ResolvedOvernightInArrearsCapFloorLeg capFloorLeg, + RatesProvider ratesProvider, + SabrParametersIborCapletFloorletVolatilities volatilities) { + + validate(ratesProvider, volatilities); + ImmutableMap impliedVolatilities = + MapStream.of(capFloorLeg.getCapletFloorletPeriods()) + .filterKeys(period -> volatilities.relativeTime( + period.getOvernightRate().getEndDate().atStartOfDay(ZoneOffset.UTC)) >= 0) + .mapValues(period -> periodPricer.impliedVolatility(period, ratesProvider, volatilities)) + .toMap(); + return OvernightInArrearsCapletFloorletPeriodAmounts.of(impliedVolatilities); + } + + /** + * Calculates the present value sensitivity of the overnight in arrears cap/floor leg to the rate curves. + *

    + * The present value sensitivity is computed in a "sticky model parameter" style, i.e. the sensitivity to the + * curve nodes with the SABR model parameters unchanged. This sensitivity does not include a potential + * re-calibration of the model parameters to the raw market data. + * + * @param capFloorLeg the cap/floor leg + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @return the point sensitivity to the rate curves + */ + public PointSensitivityBuilder presentValueSensitivityRatesStickyModel( + ResolvedOvernightInArrearsCapFloorLeg capFloorLeg, + RatesProvider ratesProvider, + SabrParametersIborCapletFloorletVolatilities volatilities) { + + validate(ratesProvider, volatilities); + return capFloorLeg.getCapletFloorletPeriods().stream() + .map(period -> periodPricer.presentValueSensitivityRatesStickyModel(period, ratesProvider, volatilities)) + .reduce(PointSensitivityBuilder::combinedWith) + .orElse(PointSensitivityBuilder.none()); + } + + /** + * Calculates the present value sensitivity to the SABR model parameters of the overnight in arrears cap/floor. + *

    + * The sensitivity of the present value to the SABR model parameters, alpha, beta, rho and nu. + * + * @param capFloorLeg the cap/floor leg + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @return the point sensitivity to the SABR model parameters + */ + public PointSensitivityBuilder presentValueSensitivityModelParamsSabr( + ResolvedOvernightInArrearsCapFloorLeg capFloorLeg, + RatesProvider ratesProvider, + SabrParametersIborCapletFloorletVolatilities volatilities) { + + validate(ratesProvider, volatilities); + return capFloorLeg.getCapletFloorletPeriods().stream() + .map(period -> periodPricer.presentValueSensitivityModelParamsSabr(period, ratesProvider, volatilities)) + .reduce(PointSensitivityBuilder::combinedWith) + .orElse(PointSensitivityBuilder.none()); + } + + //------------------------------------------------------------------------- + private void validate(RatesProvider ratesProvider, IborCapletFloorletVolatilities volatilities) { + ArgChecker.isTrue(volatilities.getValuationDate().equals(ratesProvider.getValuationDate()), + "volatility and rate data must be for the same date"); + } + +} diff --git a/modules/pricer/src/main/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorProductPricer.java b/modules/pricer/src/main/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorProductPricer.java new file mode 100644 index 0000000000..b271c26ba7 --- /dev/null +++ b/modules/pricer/src/main/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorProductPricer.java @@ -0,0 +1,257 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.pricer.capfloor; + +import com.opengamma.strata.basics.currency.CurrencyAmount; +import com.opengamma.strata.basics.currency.MultiCurrencyAmount; +import com.opengamma.strata.collect.ArgChecker; +import com.opengamma.strata.market.sensitivity.PointSensitivityBuilder; +import com.opengamma.strata.pricer.rate.RatesProvider; +import com.opengamma.strata.pricer.swap.DiscountingSwapLegPricer; +import com.opengamma.strata.product.capfloor.OvernightInArrearsCapFloorLeg; +import com.opengamma.strata.product.capfloor.ResolvedOvernightInArrearsCapFloor; +import com.opengamma.strata.product.swap.SwapLeg; + +/** + * Pricer for overnight rate in arrears cap/floor products in SABR model. + */ +public class SabrOvernightInArrearsCapFloorProductPricer { + + /** + * Default implementation. + */ + public static final SabrOvernightInArrearsCapFloorProductPricer DEFAULT = + new SabrOvernightInArrearsCapFloorProductPricer( + SabrOvernightInArrearsCapFloorLegPricer.DEFAULT, + DiscountingSwapLegPricer.DEFAULT); + /** + * The pricer for {@link OvernightInArrearsCapFloorLeg} + */ + private final SabrOvernightInArrearsCapFloorLegPricer capFloorLegPricer; + /** + * The pricer for {@link SwapLeg}. + */ + private final DiscountingSwapLegPricer payLegPricer; + + /** + * Creates an instance. + * + * @param capFloorLegPricer the pricer for {@link OvernightInArrearsCapFloorLeg} + * @param payLegPricer the pricer for {@link SwapLeg} + */ + public SabrOvernightInArrearsCapFloorProductPricer( + SabrOvernightInArrearsCapFloorLegPricer capFloorLegPricer, + DiscountingSwapLegPricer payLegPricer) { + + this.capFloorLegPricer = ArgChecker.notNull(capFloorLegPricer, "capFloorLegPricer"); + this.payLegPricer = ArgChecker.notNull(payLegPricer, "payLegPricer"); + } + + //------------------------------------------------------------------------- + /** + * Gets the cap/floor leg pricer. + * + * @return the cap/floor leg pricer + */ + public SabrOvernightInArrearsCapFloorLegPricer getCapFloorLegPricer() { + return capFloorLegPricer; + } + + /** + * Gets the pay leg pricer. + * + * @return the pay leg pricer + */ + public DiscountingSwapLegPricer getPayLegPricer() { + return payLegPricer; + } + + //------------------------------------------------------------------------- + /** + * Calculates the present value of the overnight rate in arrears cap/floor product. + *

    + * The present value of the product is the value on the valuation date. + *

    + * The cap/floor leg and pay leg are typically in the same currency, + * thus the present value is expressed as a single currency amount in most cases. + * + * @param capFloor the cap/floor product + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @return the present value + */ + public MultiCurrencyAmount presentValue( + ResolvedOvernightInArrearsCapFloor capFloor, + RatesProvider ratesProvider, + SabrParametersIborCapletFloorletVolatilities volatilities) { + + CurrencyAmount pvCapFloorLeg = capFloorLegPricer.presentValue( + capFloor.getCapFloorLeg(), + ratesProvider, + volatilities); + if (!capFloor.getPayLeg().isPresent()) { + return MultiCurrencyAmount.of(pvCapFloorLeg); + } + CurrencyAmount pvPayLeg = payLegPricer.presentValue(capFloor.getPayLeg().get(), ratesProvider); + return MultiCurrencyAmount.of(pvCapFloorLeg).plus(pvPayLeg); + } + + //------------------------------------------------------------------------- + /** + * Calculates the present value for each caplet/floorlet of the overnight rate in arrears cap/floor product. + *

    + * The present value of each caplet/floorlet is the value on the valuation date. + * The result is returned using the payment currency of the leg. + *

    + * The present value will not be calculated for the pay leg if the product has one. + * + * @param capFloor the cap/floor product + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @return the present values + */ + public OvernightInArrearsCapletFloorletPeriodCurrencyAmounts presentValueCapletFloorletPeriods( + ResolvedOvernightInArrearsCapFloor capFloor, + RatesProvider ratesProvider, + SabrParametersIborCapletFloorletVolatilities volatilities) { + + return capFloorLegPricer.presentValueCapletFloorletPeriods(capFloor.getCapFloorLeg(), ratesProvider, volatilities); + } + + //------------------------------------------------------------------------- + /** + * Calculates the present value rates sensitivity of the overnight rate in arrears cap/floor product. + *

    + * The present value sensitivity is computed in a "sticky model parameter" style, i.e., the sensitivity to the + * curve nodes with the SABR model parameters unchanged. + * This sensitivity does not include a potential re-calibration of the model parameters to the raw market data. + * + * @param capFloor the cap/floor product + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @return the present value sensitivity + */ + public PointSensitivityBuilder presentValueSensitivityRatesStickyModel( + ResolvedOvernightInArrearsCapFloor capFloor, + RatesProvider ratesProvider, + SabrParametersIborCapletFloorletVolatilities volatilities) { + + PointSensitivityBuilder pvSensiCapFloorLeg = capFloorLegPricer.presentValueSensitivityRatesStickyModel( + capFloor.getCapFloorLeg(), + ratesProvider, + volatilities); + if (!capFloor.getPayLeg().isPresent()) { + return pvSensiCapFloorLeg; + } + PointSensitivityBuilder pvSensiPayLeg = payLegPricer.presentValueSensitivity(capFloor.getPayLeg().get(), ratesProvider); + return pvSensiCapFloorLeg.combinedWith(pvSensiPayLeg); + } + + //------------------------------------------------------------------------- + /** + * Calculates the currency exposure of the overnight rate in arrears cap/floor product. + * + * @param capFloor the cap/floor product + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @return the currency exposure + */ + public MultiCurrencyAmount currencyExposure( + ResolvedOvernightInArrearsCapFloor capFloor, + RatesProvider ratesProvider, + SabrParametersIborCapletFloorletVolatilities volatilities) { + + CurrencyAmount ceCapFloorLeg = capFloorLegPricer.presentValue( + capFloor.getCapFloorLeg(), + ratesProvider, + volatilities); + if (!capFloor.getPayLeg().isPresent()) { + return MultiCurrencyAmount.of(ceCapFloorLeg); + } + MultiCurrencyAmount cePayLeg = payLegPricer.currencyExposure(capFloor.getPayLeg().get(), ratesProvider); + return cePayLeg.plus(ceCapFloorLeg); + } + + //------------------------------------------------------------------------- + /** + * Calculates the current cash of the overnight rate in arrears cap/floor product. + * + * @param capFloor the cap/floor product + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @return the current cash + */ + public MultiCurrencyAmount currentCash( + ResolvedOvernightInArrearsCapFloor capFloor, + RatesProvider ratesProvider, + SabrParametersIborCapletFloorletVolatilities volatilities) { + + CurrencyAmount ccCapFloorLeg = capFloorLegPricer.currentCash( + capFloor.getCapFloorLeg(), + ratesProvider, + volatilities); + if (!capFloor.getPayLeg().isPresent()) { + return MultiCurrencyAmount.of(ccCapFloorLeg); + } + CurrencyAmount ccPayLeg = payLegPricer.currentCash(capFloor.getPayLeg().get(), ratesProvider); + return MultiCurrencyAmount.of(ccPayLeg).plus(ccCapFloorLeg); + } + + //------------------------------------------------------------------------- + /** + * Calculates the present value volatility sensitivity of the overnight rata in arrears cap/floor product. + *

    + * The sensitivity of the present value to the SABR model parameters, alpha, beta, rho and nu. + * + * @param capFloor the cap/floor product + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @return the present value sensitivity + */ + public PointSensitivityBuilder presentValueSensitivityModelParamsSabr( + ResolvedOvernightInArrearsCapFloor capFloor, + RatesProvider ratesProvider, + SabrParametersIborCapletFloorletVolatilities volatilities) { + + return capFloorLegPricer.presentValueSensitivityModelParamsSabr( + capFloor.getCapFloorLeg(), + ratesProvider, + volatilities); + } + + //------------------------------------------------------------------------- + /** + * Calculates the forward rates for each caplet/floorlet of the overnight rate in arrears cap/floor. + * + * @param capFloor the cap/floor + * @param ratesProvider the rates provider + * @return the forward rates + */ + public OvernightInArrearsCapletFloorletPeriodAmounts forwardRates( + ResolvedOvernightInArrearsCapFloor capFloor, + RatesProvider ratesProvider) { + + return capFloorLegPricer.forwardRates(capFloor.getCapFloorLeg(), ratesProvider); + } + + //------------------------------------------------------------------------- + /** + * Calculates the implied volatilities for each caplet/floorlet of the overnight rate in arrears cap/floor. + * + * @param capFloor the cap/floor + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @return the implied volatilities + */ + public OvernightInArrearsCapletFloorletPeriodAmounts impliedVolatilities( + ResolvedOvernightInArrearsCapFloor capFloor, + RatesProvider ratesProvider, + SabrParametersIborCapletFloorletVolatilities volatilities) { + + return capFloorLegPricer.impliedVolatilities(capFloor.getCapFloorLeg(), ratesProvider, volatilities); + } + +} diff --git a/modules/pricer/src/main/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorTradePricer.java b/modules/pricer/src/main/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorTradePricer.java new file mode 100644 index 0000000000..130bdbf996 --- /dev/null +++ b/modules/pricer/src/main/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorTradePricer.java @@ -0,0 +1,248 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.pricer.capfloor; + +import com.opengamma.strata.basics.currency.CurrencyAmount; +import com.opengamma.strata.basics.currency.MultiCurrencyAmount; +import com.opengamma.strata.basics.currency.Payment; +import com.opengamma.strata.collect.ArgChecker; +import com.opengamma.strata.market.sensitivity.PointSensitivities; +import com.opengamma.strata.market.sensitivity.PointSensitivityBuilder; +import com.opengamma.strata.pricer.DiscountingPaymentPricer; +import com.opengamma.strata.pricer.rate.RatesProvider; +import com.opengamma.strata.product.capfloor.ResolvedOvernightInArrearsCapFloor; +import com.opengamma.strata.product.capfloor.ResolvedOvernightInArrearsCapFloorTrade; + +/** + * Pricer for overnight rate in arrears cap/floor trades in SABR model. + */ +public class SabrOvernightInArrearsCapFloorTradePricer { + + /** + * Default implementation. + */ + public static final SabrOvernightInArrearsCapFloorTradePricer DEFAULT = + new SabrOvernightInArrearsCapFloorTradePricer( + SabrOvernightInArrearsCapFloorProductPricer.DEFAULT, + DiscountingPaymentPricer.DEFAULT); + /** + * The pricer for {@link ResolvedOvernightInArrearsCapFloor}. + */ + private final SabrOvernightInArrearsCapFloorProductPricer productPricer; + /** + * Pricer for {@link Payment}. + */ + private final DiscountingPaymentPricer paymentPricer; + + /** + * Creates an instance. + * + * @param productPricer the pricer for {@link ResolvedOvernightInArrearsCapFloor} + * @param paymentPricer the pricer for {@link Payment} + */ + public SabrOvernightInArrearsCapFloorTradePricer( + SabrOvernightInArrearsCapFloorProductPricer productPricer, + DiscountingPaymentPricer paymentPricer) { + + this.productPricer = ArgChecker.notNull(productPricer, "productPricer"); + this.paymentPricer = ArgChecker.notNull(paymentPricer, "paymentPricer"); + } + + //------------------------------------------------------------------------- + /** + * Gets the product pricer. + * + * @return the product pricer + */ + public SabrOvernightInArrearsCapFloorProductPricer getProductPricer() { + return productPricer; + } + + /** + * Gets the payment pricer. + * + * @return the payment pricer + */ + public DiscountingPaymentPricer getPaymentPricer() { + return paymentPricer; + } + + //------------------------------------------------------------------------- + /** + * Calculates the present value of the overnight rate in arrears cap/floor trade. + *

    + * The present value of the trade is the value on the valuation date. + *

    + * The cap/floor leg and pay leg are typically in the same currency, + * thus the present value is expressed as a single currency amount in most cases. + * + * @param trade the cap/floor trade + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @return the present value + */ + public MultiCurrencyAmount presentValue( + ResolvedOvernightInArrearsCapFloorTrade trade, + RatesProvider ratesProvider, + SabrParametersIborCapletFloorletVolatilities volatilities) { + + MultiCurrencyAmount pvProduct = productPricer.presentValue(trade.getProduct(), ratesProvider, volatilities); + if (!trade.getPremium().isPresent()) { + return pvProduct; + } + CurrencyAmount pvPremium = paymentPricer.presentValue(trade.getPremium().get(), ratesProvider); + return pvProduct.plus(pvPremium); + } + + //------------------------------------------------------------------------- + /** + * Calculates the present value for each caplet/floorlet of the overnight rate in arrears cap/floor trade. + *

    + * The present value of each caplet/floorlet is the value on the valuation date. + * The result is returned using the payment currency of the leg. + *

    + * The present value will not be calculated for the trade premium or for the pay leg + * if the cap/floor product has one. + * + * @param trade the cap/floor leg + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @return the present values + */ + public OvernightInArrearsCapletFloorletPeriodCurrencyAmounts presentValueCapletFloorletPeriods( + ResolvedOvernightInArrearsCapFloorTrade trade, + RatesProvider ratesProvider, + SabrParametersIborCapletFloorletVolatilities volatilities) { + + return productPricer.presentValueCapletFloorletPeriods(trade.getProduct(), ratesProvider, volatilities); + } + + //------------------------------------------------------------------------- + /** + * Calculates the present value rates sensitivity of the overnight rate in arrears cap/floor trade. + *

    + * The present value sensitivity is computed in a "sticky model parameter" style, i.e. the sensitivity to the + * curve nodes with the SABR model parameters unchanged. This sensitivity does not include a potential + * re-calibration of the model parameters to the raw market data. + * + * @param trade the cap/floor trade + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @return the present value sensitivity + */ + public PointSensitivities presentValueSensitivityRatesStickyModel( + ResolvedOvernightInArrearsCapFloorTrade trade, + RatesProvider ratesProvider, + SabrParametersIborCapletFloorletVolatilities volatilities) { + + PointSensitivityBuilder pvSensiProduct = + productPricer.presentValueSensitivityRatesStickyModel(trade.getProduct(), ratesProvider, volatilities); + if (!trade.getPremium().isPresent()) { + return pvSensiProduct.build(); + } + PointSensitivityBuilder pvSensiPremium = + getPaymentPricer().presentValueSensitivity(trade.getPremium().get(), ratesProvider); + return pvSensiProduct.combinedWith(pvSensiPremium).build(); + } + + /** + * Calculates the present value volatility sensitivity of the overnight rate in arrears cap/floor trade. + *

    + * The sensitivity of the present value to the SABR model parameters, alpha, beta, rho and nu. + * + * @param trade the cap/floor trade + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @return the present value sensitivity + */ + public PointSensitivityBuilder presentValueSensitivityModelParamsSabr( + ResolvedOvernightInArrearsCapFloorTrade trade, + RatesProvider ratesProvider, + SabrParametersIborCapletFloorletVolatilities volatilities) { + + return productPricer.presentValueSensitivityModelParamsSabr(trade.getProduct(), ratesProvider, volatilities); + } + + //------------------------------------------------------------------------- + /** + * Calculates the currency exposure of the overnight rate in arrears cap/floor trade. + * + * @param trade the cap/floor trade + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @return the currency exposure + */ + public MultiCurrencyAmount currencyExposure( + ResolvedOvernightInArrearsCapFloorTrade trade, + RatesProvider ratesProvider, + SabrParametersIborCapletFloorletVolatilities volatilities) { + + MultiCurrencyAmount ceProduct = productPricer.currencyExposure(trade.getProduct(), ratesProvider, volatilities); + if (!trade.getPremium().isPresent()) { + return ceProduct; + } + CurrencyAmount pvPremium = paymentPricer.presentValue(trade.getPremium().get(), ratesProvider); + return ceProduct.plus(pvPremium); + } + + //------------------------------------------------------------------------- + /** + * Calculates the current cash of the overnight rate in arrears cap/floor trade. + * + * @param trade the cap/floor trade + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @return the current cash + */ + public MultiCurrencyAmount currentCash( + ResolvedOvernightInArrearsCapFloorTrade trade, + RatesProvider ratesProvider, + SabrParametersIborCapletFloorletVolatilities volatilities) { + + MultiCurrencyAmount ccProduct = productPricer.currentCash(trade.getProduct(), ratesProvider, volatilities); + if (!trade.getPremium().isPresent()) { + return ccProduct; + } + Payment premium = trade.getPremium().get(); + if (premium.getDate().equals(ratesProvider.getValuationDate())) { + ccProduct = ccProduct.plus(premium.getCurrency(), premium.getAmount()); + } + return ccProduct; + } + + //------------------------------------------------------------------------- + /** + * Calculates the forward rates for each caplet/floorlet of the overnight rate in arrears cap/floor trade. + * + * @param trade the cap/floor trade + * @param ratesProvider the rates provider + * @return the forward rates + */ + public OvernightInArrearsCapletFloorletPeriodAmounts forwardRates( + ResolvedOvernightInArrearsCapFloorTrade trade, + RatesProvider ratesProvider) { + + return productPricer.forwardRates(trade.getProduct(), ratesProvider); + } + + //------------------------------------------------------------------------- + /** + * Calculates the implied volatilities for each caplet/floorlet of the overnight rate in arrears cap/floor trade. + * + * @param trade the cap/floor trade + * @param ratesProvider the rates provider + * @param volatilities the volatilities + * @return the implied volatilities + */ + public OvernightInArrearsCapletFloorletPeriodAmounts impliedVolatilities( + ResolvedOvernightInArrearsCapFloorTrade trade, + RatesProvider ratesProvider, + SabrParametersIborCapletFloorletVolatilities volatilities) { + + return productPricer.impliedVolatilities(trade.getProduct(), ratesProvider, volatilities); + } + +} diff --git a/modules/pricer/src/main/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapletFloorletPeriodPricer.java b/modules/pricer/src/main/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapletFloorletPeriodPricer.java index 9741c53092..156eb4f005 100644 --- a/modules/pricer/src/main/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapletFloorletPeriodPricer.java +++ b/modules/pricer/src/main/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapletFloorletPeriodPricer.java @@ -17,6 +17,7 @@ import com.opengamma.strata.basics.currency.Currency; import com.opengamma.strata.basics.currency.CurrencyAmount; import com.opengamma.strata.basics.value.ValueDerivatives; +import com.opengamma.strata.collect.ArgChecker; import com.opengamma.strata.collect.array.DoubleArray; import com.opengamma.strata.market.sensitivity.PointSensitivityBuilder; import com.opengamma.strata.pricer.ZeroRateSensitivity; @@ -74,9 +75,9 @@ private SabrOvernightInArrearsCapletFloorletPeriodPricer(SabrInArrearsVolatility /** * Computes the present value in the SABR model with effective parameters. * - * @param period the caplet/floorlet period - * @param ratesProvider the rates provider - * @param sabrVolatilities the SABR volatilities + * @param period the caplet/floorlet period + * @param ratesProvider the rates provider + * @param sabrVolatilities the SABR volatilities * @return the present value */ public CurrencyAmount presentValue( @@ -120,9 +121,9 @@ public CurrencyAmount presentValue( /** * Computes the present value sensitivity to the rate with "sticky SABR model parameters". * - * @param period the caplet/floorlet period - * @param ratesProvider the rates provider - * @param sabrVolatilities the SABR volatilities + * @param period the caplet/floorlet period + * @param ratesProvider the rates provider + * @param sabrVolatilities the SABR volatilities * @return the present value rate sensitivity */ public PointSensitivityBuilder presentValueSensitivityRatesStickyModel( @@ -182,9 +183,9 @@ public PointSensitivityBuilder presentValueSensitivityRatesStickyModel( /** * Computes the present value sensitivity to the SABR model parameters. * - * @param period the caplet/floorlet period - * @param ratesProvider the rates provider - * @param sabrVolatilities the SABR volatilities + * @param period the caplet/floorlet period + * @param ratesProvider the rates provider + * @param sabrVolatilities the SABR volatilities * @return the present value model parameters sensitivity */ public PointSensitivityBuilder presentValueSensitivityModelParamsSabr( @@ -239,4 +240,51 @@ public PointSensitivityBuilder presentValueSensitivityModelParamsSabr( IborCapletFloorletSabrSensitivity.of(name, startTime, NU, currency, paramHat.get(3))); } + //------------------------------------------------------------------------- + /** + * Computes the implied volatility of the caplet/floorlet. + * + * @param period the caplet/floorlet period + * @param ratesProvider the rates provider + * @param sabrVolatilities the SABR volatilities + * @return the implied volatility + */ + public double impliedVolatility( + OvernightInArrearsCapletFloorletPeriod period, + RatesProvider ratesProvider, + SabrParametersIborCapletFloorletVolatilities sabrVolatilities) { + + OvernightCompoundedRateComputation onComputation = period.getOvernightRate(); + LocalDate startDate = onComputation.getStartDate(); + LocalDate endDate = onComputation.getEndDate(); + double startTime = sabrVolatilities.relativeTime(startDate.atStartOfDay(ZoneOffset.UTC)); // ON rates don't have an exact fixing time + double endTime = sabrVolatilities.relativeTime(endDate.atStartOfDay(ZoneOffset.UTC)); + ArgChecker.isTrue(endTime >= 0d, "Option must be before expiry to compute an implied volatility"); + double strike = period.getStrike(); + double forward = ON_FUNCT.rate(onComputation, onComputation.getStartDate(), onComputation.getEndDate(), ratesProvider); + double alpha = sabrVolatilities.alpha(startTime); // parameters at start of composition period, for coherence with term rate caplets + double beta = sabrVolatilities.beta(startTime); + double rho = sabrVolatilities.rho(startTime); + double nu = sabrVolatilities.nu(startTime); + double shift = sabrVolatilities.shift(startTime); + SabrFormulaData sabr = SabrFormulaData.of(alpha, beta, rho, nu); + SabrFormulaData sabrAdjusted = sabrInArrearsFunction.effectiveSabr(sabr, startTime, endTime); + return sabrVolatilities.getParameters().getSabrVolatilityFormula() + .volatility(forward + shift, strike + shift, endTime, + sabrAdjusted.getAlpha(), sabrAdjusted.getBeta(), sabrAdjusted.getRho(), sabrAdjusted.getNu()); + } + + //------------------------------------------------------------------------- + /** + * Computes the forward rate for the caplet/floorlet. + * + * @param period the caplet/floorlet period + * @param ratesProvider the rates provider + * @return the forward rate + */ + public double forwardRate(OvernightInArrearsCapletFloorletPeriod period, RatesProvider ratesProvider) { + OvernightCompoundedRateComputation onComputation = period.getOvernightRate(); + return ON_FUNCT.rate(onComputation, onComputation.getStartDate(), onComputation.getEndDate(), ratesProvider); + } + } diff --git a/modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/OvernightInArrearsCapletFloorletPeriodAmountsTest.java b/modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/OvernightInArrearsCapletFloorletPeriodAmountsTest.java new file mode 100644 index 0000000000..31f8962f27 --- /dev/null +++ b/modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/OvernightInArrearsCapletFloorletPeriodAmountsTest.java @@ -0,0 +1,110 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.pricer.capfloor; + +import static com.opengamma.strata.basics.index.OvernightIndices.EUR_ESTR; +import static com.opengamma.strata.collect.TestHelper.assertSerialization; +import static com.opengamma.strata.collect.TestHelper.coverImmutableBean; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +import java.time.LocalDate; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import com.google.common.collect.ImmutableMap; +import com.opengamma.strata.basics.ReferenceData; +import com.opengamma.strata.product.capfloor.OvernightInArrearsCapletFloorletPeriod; +import com.opengamma.strata.product.rate.OvernightCompoundedRateComputation; + +/** + * Test {@link OvernightInArrearsCapletFloorletPeriodAmounts}. + */ +public class OvernightInArrearsCapletFloorletPeriodAmountsTest { + + private static final ReferenceData REF_DATA = ReferenceData.standard(); + private static final LocalDate START = LocalDate.of(2011, 1, 5); + private static final LocalDate END = LocalDate.of(2011, 7, 5); + private static final double NOTIONAL = 1_000_000; + private static final double STRIKE = 0.01; + private static final OvernightCompoundedRateComputation RATE_COMP = OvernightCompoundedRateComputation.of( + EUR_ESTR, + START, + END, + REF_DATA); + private static final OvernightInArrearsCapletFloorletPeriod CAPLET_LONG = + OvernightInArrearsCapletFloorletPeriod.builder() + .caplet(STRIKE) + .startDate(START) + .endDate(END) + .yearFraction(0.5) + .notional(NOTIONAL) + .overnightRate(RATE_COMP) + .build(); + private static final OvernightInArrearsCapletFloorletPeriod CAPLET_SHORT = + OvernightInArrearsCapletFloorletPeriod.builder() + .caplet(STRIKE) + .startDate(START) + .endDate(END) + .yearFraction(0.5) + .notional(NOTIONAL * -1) + .overnightRate(RATE_COMP) + .build(); + private static final Map CAPLET_DOUBLE_MAP = ImmutableMap.of( + CAPLET_LONG, + 1d); + + @Test + void test_of() { + OvernightInArrearsCapletFloorletPeriodAmounts test = + OvernightInArrearsCapletFloorletPeriodAmounts.of(CAPLET_DOUBLE_MAP); + assertThat(test.getAmounts()).isEqualTo(CAPLET_DOUBLE_MAP); + } + + @Test + void test_findAmount() { + OvernightInArrearsCapletFloorletPeriodAmounts test = + OvernightInArrearsCapletFloorletPeriodAmounts.of(CAPLET_DOUBLE_MAP); + assertThat(test.findAmount(CAPLET_LONG)).contains(1d); + } + + @Test + void test_findAmountEmpty() { + OvernightInArrearsCapletFloorletPeriodAmounts test = + OvernightInArrearsCapletFloorletPeriodAmounts.of(CAPLET_DOUBLE_MAP); + assertThat(test.findAmount(CAPLET_SHORT)).isEmpty(); + } + + @Test + void test_getAmount() { + OvernightInArrearsCapletFloorletPeriodAmounts test = + OvernightInArrearsCapletFloorletPeriodAmounts.of(CAPLET_DOUBLE_MAP); + assertThat(test.getAmount(CAPLET_LONG)).isEqualTo(1d); + } + + @Test + void test_getAmountThrows() { + OvernightInArrearsCapletFloorletPeriodAmounts test = + OvernightInArrearsCapletFloorletPeriodAmounts.of(CAPLET_DOUBLE_MAP); + assertThatIllegalArgumentException().isThrownBy(() -> test.getAmount(CAPLET_SHORT)) + .withMessage("Could not find double amount for " + CAPLET_SHORT); + } + + @Test + void coverage() { + OvernightInArrearsCapletFloorletPeriodAmounts test = + OvernightInArrearsCapletFloorletPeriodAmounts.of(CAPLET_DOUBLE_MAP); + coverImmutableBean(test); + } + + @Test + public void test_serialization() { + OvernightInArrearsCapletFloorletPeriodAmounts test = + OvernightInArrearsCapletFloorletPeriodAmounts.of(CAPLET_DOUBLE_MAP); + assertSerialization(test); + } +} diff --git a/modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/OvernightInArrearsCapletFloorletPeriodCurrencyAmountsTest.java b/modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/OvernightInArrearsCapletFloorletPeriodCurrencyAmountsTest.java new file mode 100644 index 0000000000..8ff5d3e480 --- /dev/null +++ b/modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/OvernightInArrearsCapletFloorletPeriodCurrencyAmountsTest.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.pricer.capfloor; + +import static com.opengamma.strata.basics.index.OvernightIndices.EUR_ESTR; +import static com.opengamma.strata.collect.TestHelper.assertSerialization; +import static com.opengamma.strata.collect.TestHelper.coverImmutableBean; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; + +import java.time.LocalDate; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import com.google.common.collect.ImmutableMap; +import com.opengamma.strata.basics.ReferenceData; +import com.opengamma.strata.basics.currency.Currency; +import com.opengamma.strata.basics.currency.CurrencyAmount; +import com.opengamma.strata.product.capfloor.OvernightInArrearsCapletFloorletPeriod; +import com.opengamma.strata.product.rate.OvernightCompoundedRateComputation; + +/** + * Test {@link OvernightInArrearsCapletFloorletPeriodCurrencyAmounts}. + */ +public class OvernightInArrearsCapletFloorletPeriodCurrencyAmountsTest { + + private static final ReferenceData REF_DATA = ReferenceData.standard(); + private static final LocalDate START = LocalDate.of(2011, 1, 5); + private static final LocalDate END = LocalDate.of(2011, 7, 5); + private static final double NOTIONAL = 1_000_000; + private static final double STRIKE = 0.01; + private static final OvernightCompoundedRateComputation RATE_COMP = OvernightCompoundedRateComputation.of( + EUR_ESTR, + START, + END, + REF_DATA); + private static final OvernightInArrearsCapletFloorletPeriod CAPLET_LONG = OvernightInArrearsCapletFloorletPeriod.builder() + .caplet(STRIKE) + .startDate(START) + .endDate(END) + .yearFraction(0.5) + .notional(NOTIONAL) + .overnightRate(RATE_COMP) + .build(); + private static final OvernightInArrearsCapletFloorletPeriod CAPLET_SHORT = OvernightInArrearsCapletFloorletPeriod.builder() + .caplet(STRIKE) + .startDate(START) + .endDate(END) + .yearFraction(0.5) + .notional(NOTIONAL * -1) + .overnightRate(RATE_COMP) + .build(); + private static final CurrencyAmount CURRENCY_AMOUNT = CurrencyAmount.of(Currency.USD, 1d); + private static final Map CAPLET_CURRENCY_AMOUNT_MAP = ImmutableMap.of( + CAPLET_LONG, CURRENCY_AMOUNT); + + @Test + void test_of() { + OvernightInArrearsCapletFloorletPeriodCurrencyAmounts test = + OvernightInArrearsCapletFloorletPeriodCurrencyAmounts.of(CAPLET_CURRENCY_AMOUNT_MAP); + assertThat(test.getAmounts()).isEqualTo(CAPLET_CURRENCY_AMOUNT_MAP); + } + + @Test + void test_findAmount() { + OvernightInArrearsCapletFloorletPeriodCurrencyAmounts test = + OvernightInArrearsCapletFloorletPeriodCurrencyAmounts.of(CAPLET_CURRENCY_AMOUNT_MAP); + assertThat(test.findAmount(CAPLET_LONG)).contains(CURRENCY_AMOUNT); + } + + @Test + void test_findAmountEmpty() { + OvernightInArrearsCapletFloorletPeriodCurrencyAmounts test = + OvernightInArrearsCapletFloorletPeriodCurrencyAmounts.of(CAPLET_CURRENCY_AMOUNT_MAP); + assertThat(test.findAmount(CAPLET_SHORT)).isEmpty(); + } + + @Test + void test_getAmount() { + OvernightInArrearsCapletFloorletPeriodCurrencyAmounts test = + OvernightInArrearsCapletFloorletPeriodCurrencyAmounts.of(CAPLET_CURRENCY_AMOUNT_MAP); + assertThat(test.getAmount(CAPLET_LONG)).isEqualTo(CURRENCY_AMOUNT); + } + + @Test + void test_getAmountThrows() { + OvernightInArrearsCapletFloorletPeriodCurrencyAmounts test = + OvernightInArrearsCapletFloorletPeriodCurrencyAmounts.of(CAPLET_CURRENCY_AMOUNT_MAP); + assertThatIllegalArgumentException().isThrownBy(() -> test.getAmount(CAPLET_SHORT)) + .withMessage("Could not find currency amount for " + CAPLET_SHORT); + } + + @Test + void coverage() { + OvernightInArrearsCapletFloorletPeriodCurrencyAmounts test = + OvernightInArrearsCapletFloorletPeriodCurrencyAmounts.of(CAPLET_CURRENCY_AMOUNT_MAP); + coverImmutableBean(test); + } + + @Test + public void test_serialization() { + OvernightInArrearsCapletFloorletPeriodCurrencyAmounts test = + OvernightInArrearsCapletFloorletPeriodCurrencyAmounts.of(CAPLET_CURRENCY_AMOUNT_MAP); + assertSerialization(test); + } + +} diff --git a/modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorLegPricerTest.java b/modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorLegPricerTest.java new file mode 100644 index 0000000000..7fb3f46f5d --- /dev/null +++ b/modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorLegPricerTest.java @@ -0,0 +1,335 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.pricer.capfloor; + +import static com.opengamma.strata.basics.currency.Currency.EUR; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.CAP_LEG; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.FLOOR_LEG; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.NOTIONAL_VALUE; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.RATES; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.RATES_AFTER; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.RATES_PAY; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.VOLS; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.VOLS_AFTER; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.VOLS_PAY; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.data.Offset.offset; + +import java.time.ZoneOffset; +import java.util.Map; + +import org.junit.jupiter.api.Test; + +import com.opengamma.strata.basics.currency.CurrencyAmount; +import com.opengamma.strata.collect.MapStream; +import com.opengamma.strata.market.param.CurrencyParameterSensitivities; +import com.opengamma.strata.market.sensitivity.PointSensitivityBuilder; +import com.opengamma.strata.product.capfloor.OvernightInArrearsCapletFloorletPeriod; + +/** + * Test {@link SabrOvernightInArrearsCapFloorLegPricer}. + */ +public class SabrOvernightInArrearsCapFloorLegPricerTest { + + private static final SabrOvernightInArrearsCapFloorLegPricer PRICER = SabrOvernightInArrearsCapFloorLegPricer.DEFAULT; + private static final SabrOvernightInArrearsCapletFloorletPeriodPricer PRICER_PERIOD = PRICER.getPeriodPricer(); + private static final double TOL = 1.0e-13; + + @Test + public void test_presentValue() { + CurrencyAmount capComputed = PRICER.presentValue(CAP_LEG, RATES, VOLS); + CurrencyAmount floorComputed = PRICER.presentValue(FLOOR_LEG, RATES, VOLS); + double capExpected = 0d; + double floorExpected = 0d; + int nPeriods = CAP_LEG.getCapletFloorletPeriods().size(); + for (int i = 0; i < nPeriods; ++i) { + capExpected += PRICER_PERIOD.presentValue(CAP_LEG.getCapletFloorletPeriods().get(i), RATES, VOLS).getAmount(); + floorExpected += PRICER_PERIOD.presentValue(FLOOR_LEG.getCapletFloorletPeriods().get(i), RATES, VOLS).getAmount(); + } + assertThat(capComputed.getCurrency()).isEqualTo(EUR); + assertThat(capComputed.getAmount()).isEqualTo(capExpected); + assertThat(floorComputed.getCurrency()).isEqualTo(EUR); + assertThat(floorComputed.getAmount()).isEqualTo(floorExpected); + } + + @Test + public void test_presentValue_after() { + CurrencyAmount capComputed = PRICER.presentValue(CAP_LEG, RATES_AFTER, VOLS_AFTER); + CurrencyAmount floorComputed = PRICER.presentValue(FLOOR_LEG, RATES_AFTER, VOLS_AFTER); + double capExpected = 0d; + double floorExpected = 0d; + int nPeriods = CAP_LEG.getCapletFloorletPeriods().size(); + for (int i = 1; i < nPeriods; ++i) { + capExpected += PRICER_PERIOD.presentValue( + CAP_LEG.getCapletFloorletPeriods().get(i), + RATES_AFTER, + VOLS_AFTER).getAmount(); + floorExpected += PRICER_PERIOD.presentValue( + FLOOR_LEG.getCapletFloorletPeriods().get(i), + RATES_AFTER, + VOLS_AFTER).getAmount(); + } + assertThat(capComputed.getCurrency()).isEqualTo(EUR); + assertThat(capComputed.getAmount()).isCloseTo(capExpected, offset(TOL * NOTIONAL_VALUE)); + assertThat(floorComputed.getCurrency()).isEqualTo(EUR); + assertThat(floorComputed.getAmount()).isCloseTo(floorExpected, offset(TOL * NOTIONAL_VALUE)); + } + + //------------------------------------------------------------------------- + @Test + public void test_presentValueCapletFloorletPeriods() { + CurrencyAmount capComputed = PRICER.presentValue(CAP_LEG, RATES, VOLS); + CurrencyAmount floorComputed = PRICER.presentValue(FLOOR_LEG, RATES, VOLS); + Map capletsComputed = + PRICER.presentValueCapletFloorletPeriods(CAP_LEG, RATES, VOLS).getAmounts(); + Map floorletsComputed = + PRICER.presentValueCapletFloorletPeriods(FLOOR_LEG, RATES, VOLS).getAmounts(); + + Map capletsExpected = + MapStream.of(CAP_LEG.getCapletFloorletPeriods()) + .mapValues(caplet -> PRICER_PERIOD.presentValue(caplet, RATES, VOLS)) + .toMap(); + CurrencyAmount capletsTotalExpected = capletsExpected.values().stream().reduce(CurrencyAmount::plus).get(); + Map floorletsExpected = + MapStream.of(FLOOR_LEG.getCapletFloorletPeriods()) + .mapValues(floorlet -> PRICER_PERIOD.presentValue(floorlet, RATES, VOLS)) + .toMap(); + CurrencyAmount floorletsTotalExpected = floorletsExpected.values().stream().reduce(CurrencyAmount::plus).get(); + + assertThat(capletsComputed).isEqualTo(capletsExpected); + assertThat(capComputed).isEqualTo(capletsTotalExpected); + assertThat(floorletsComputed).isEqualTo(floorletsExpected); + assertThat(floorComputed).isEqualTo(floorletsTotalExpected); + } + + @Test + public void test_presentValueCapletFloorletPeriods_after() { + CurrencyAmount capComputed = PRICER.presentValue(CAP_LEG, RATES_AFTER, VOLS_AFTER); + CurrencyAmount floorComputed = PRICER.presentValue(FLOOR_LEG, RATES_AFTER, VOLS_AFTER); + Map capletsComputed = + PRICER.presentValueCapletFloorletPeriods(CAP_LEG, RATES_AFTER, VOLS_AFTER).getAmounts(); + Map floorletsComputed = + PRICER.presentValueCapletFloorletPeriods(FLOOR_LEG, RATES_AFTER, VOLS_AFTER).getAmounts(); + + Map capletsExpected = + MapStream.of(CAP_LEG.getCapletFloorletPeriods()) + .mapValues(caplet -> PRICER_PERIOD.presentValue(caplet, RATES_AFTER, VOLS_AFTER)) + .toMap(); + CurrencyAmount capletsTotalExpected = capletsExpected.values().stream().reduce(CurrencyAmount::plus).get(); + Map floorletsExpected = + MapStream.of(FLOOR_LEG.getCapletFloorletPeriods()) + .mapValues(floorlet -> PRICER_PERIOD.presentValue(floorlet, RATES_AFTER, VOLS_AFTER)) + .toMap(); + CurrencyAmount floorletsTotalExpected = floorletsExpected.values().stream().reduce(CurrencyAmount::plus).get(); + + assertThat(capletsComputed).isEqualTo(capletsExpected); + assertThat(capComputed).isEqualTo(capletsTotalExpected); + assertThat(floorletsComputed).isEqualTo(floorletsExpected); + assertThat(floorComputed).isEqualTo(floorletsTotalExpected); + } + + //------------------------------------------------------------------------- + @Test + public void test_presentValueSensitivityRatesStickyModel() { + PointSensitivityBuilder capComputed = PRICER.presentValueSensitivityRatesStickyModel(CAP_LEG, RATES, VOLS); + PointSensitivityBuilder floorComputed = PRICER.presentValueSensitivityRatesStickyModel(FLOOR_LEG, RATES, VOLS); + PointSensitivityBuilder capExpected = PointSensitivityBuilder.none(); + PointSensitivityBuilder floorExpected = PointSensitivityBuilder.none(); + int nPeriods = CAP_LEG.getCapletFloorletPeriods().size(); + for (int i = 0; i < nPeriods; ++i) { + capExpected = capExpected.combinedWith( + PRICER_PERIOD.presentValueSensitivityRatesStickyModel( + CAP_LEG.getCapletFloorletPeriods().get(i), + RATES, + VOLS)); + floorExpected = floorExpected.combinedWith( + PRICER_PERIOD.presentValueSensitivityRatesStickyModel( + FLOOR_LEG.getCapletFloorletPeriods().get(i), + RATES, + VOLS)); + } + CurrencyParameterSensitivities capSensiComputed = RATES_AFTER.parameterSensitivity(capComputed.build()); + CurrencyParameterSensitivities floorSensiComputed = RATES_AFTER.parameterSensitivity(floorComputed.build()); + CurrencyParameterSensitivities capSensiExpected = RATES_AFTER.parameterSensitivity(capExpected.build()); + CurrencyParameterSensitivities floorSensiExpected = RATES_AFTER.parameterSensitivity(floorExpected.build()); + assertThat(capSensiComputed.equalWithTolerance(capSensiExpected, NOTIONAL_VALUE * TOL)).isTrue(); + assertThat(floorSensiComputed.equalWithTolerance(floorSensiExpected, NOTIONAL_VALUE * TOL)).isTrue(); + } + + @Test + public void test_presentValueSensitivityRatesStickyModel_after() { + PointSensitivityBuilder capComputed = PRICER.presentValueSensitivityRatesStickyModel( + CAP_LEG, + RATES_AFTER, + VOLS_AFTER); + PointSensitivityBuilder floorComputed = PRICER.presentValueSensitivityRatesStickyModel( + FLOOR_LEG, + RATES_AFTER, + VOLS_AFTER); + PointSensitivityBuilder capExpected = PointSensitivityBuilder.none(); + PointSensitivityBuilder floorExpected = PointSensitivityBuilder.none(); + int nPeriods = CAP_LEG.getCapletFloorletPeriods().size(); + for (int i = 1; i < nPeriods; ++i) { + capExpected = capExpected.combinedWith( + PRICER_PERIOD.presentValueSensitivityRatesStickyModel( + CAP_LEG.getCapletFloorletPeriods().get(i), + RATES_AFTER, + VOLS_AFTER)); + floorExpected = floorExpected.combinedWith( + PRICER_PERIOD.presentValueSensitivityRatesStickyModel( + FLOOR_LEG.getCapletFloorletPeriods().get(i), + RATES_AFTER, + VOLS_AFTER)); + } + CurrencyParameterSensitivities capSensiComputed = RATES_AFTER.parameterSensitivity(capComputed.build()); + CurrencyParameterSensitivities floorSensiComputed = RATES_AFTER.parameterSensitivity(floorComputed.build()); + CurrencyParameterSensitivities capSensiExpected = RATES_AFTER.parameterSensitivity(capExpected.build()); + CurrencyParameterSensitivities floorSensiExpected = RATES_AFTER.parameterSensitivity(floorExpected.build()); + assertThat(capSensiComputed.equalWithTolerance(capSensiExpected, NOTIONAL_VALUE * TOL)).isTrue(); + assertThat(floorSensiComputed.equalWithTolerance(floorSensiExpected, NOTIONAL_VALUE * TOL)).isTrue(); + } + + //------------------------------------------------------------------------- + @Test + public void test_presentValueSensitivityModelParamsSabr() { + PointSensitivityBuilder capComputed = PRICER.presentValueSensitivityModelParamsSabr(CAP_LEG, RATES, VOLS); + PointSensitivityBuilder floorComputed = PRICER.presentValueSensitivityModelParamsSabr(FLOOR_LEG, RATES, VOLS); + CurrencyParameterSensitivities capExpected = CurrencyParameterSensitivities.empty(); + CurrencyParameterSensitivities floorExpected = CurrencyParameterSensitivities.empty(); + int nPeriods = CAP_LEG.getCapletFloorletPeriods().size(); + for (int i = 0; i < nPeriods; ++i) { + capExpected = capExpected.combinedWith(VOLS.parameterSensitivity(PRICER_PERIOD + .presentValueSensitivityModelParamsSabr(CAP_LEG.getCapletFloorletPeriods().get(i), RATES, VOLS).build())); + floorExpected = floorExpected.combinedWith(VOLS.parameterSensitivity(PRICER_PERIOD + .presentValueSensitivityModelParamsSabr(FLOOR_LEG.getCapletFloorletPeriods().get(i), RATES, VOLS).build())); + } + CurrencyParameterSensitivities capSensiComputed = VOLS.parameterSensitivity(capComputed.build()); + CurrencyParameterSensitivities floorSensiComputed = VOLS.parameterSensitivity(floorComputed.build()); + assertThat(capSensiComputed.equalWithTolerance(capExpected, TOL * NOTIONAL_VALUE)).isTrue(); + assertThat(floorSensiComputed.equalWithTolerance(floorExpected, TOL * NOTIONAL_VALUE)).isTrue(); + } + + @Test + public void test_presentValueSensitivityModelParamsSabr_after() { + PointSensitivityBuilder capComputed = PRICER.presentValueSensitivityModelParamsSabr( + CAP_LEG, + RATES_AFTER, + VOLS_AFTER); + PointSensitivityBuilder floorComputed = PRICER.presentValueSensitivityModelParamsSabr( + FLOOR_LEG, + RATES_AFTER, + VOLS_AFTER); + CurrencyParameterSensitivities capExpected = CurrencyParameterSensitivities.empty(); + CurrencyParameterSensitivities floorExpected = CurrencyParameterSensitivities.empty(); + int nPeriods = CAP_LEG.getCapletFloorletPeriods().size(); + for (int i = 1; i < nPeriods; ++i) { + capExpected = capExpected.combinedWith( + VOLS_AFTER.parameterSensitivity(PRICER_PERIOD.presentValueSensitivityModelParamsSabr( + CAP_LEG.getCapletFloorletPeriods().get(i), + RATES_AFTER, + VOLS_AFTER).build())); + floorExpected = floorExpected.combinedWith( + VOLS_AFTER.parameterSensitivity(PRICER_PERIOD.presentValueSensitivityModelParamsSabr( + FLOOR_LEG.getCapletFloorletPeriods().get(i), + RATES_AFTER, + VOLS_AFTER).build())); + } + CurrencyParameterSensitivities capSensiComputed = VOLS_AFTER.parameterSensitivity(capComputed.build()); + CurrencyParameterSensitivities floorSensiComputed = VOLS_AFTER.parameterSensitivity(floorComputed.build()); + assertThat(capSensiComputed.equalWithTolerance(capExpected, TOL * NOTIONAL_VALUE)).isTrue(); + assertThat(floorSensiComputed.equalWithTolerance(floorExpected, TOL * NOTIONAL_VALUE)).isTrue(); + } + + //------------------------------------------------------------------------- + @Test + public void test_currentCash() { + CurrencyAmount capComputed = PRICER.currentCash(CAP_LEG, RATES, VOLS); + CurrencyAmount floorComputed = PRICER.currentCash(FLOOR_LEG, RATES, VOLS); + assertThat(capComputed.getCurrency()).isEqualTo(EUR); + assertThat(capComputed.getAmount()).isEqualTo(0d); + assertThat(floorComputed.getCurrency()).isEqualTo(EUR); + assertThat(floorComputed.getAmount()).isEqualTo(0d); + } + + @Test + public void test_currentCash_pay() { + CurrencyAmount capComputed = PRICER.currentCash(CAP_LEG, RATES_PAY, VOLS_PAY); + CurrencyAmount floorComputed = PRICER.currentCash(FLOOR_LEG, RATES_PAY, VOLS_PAY); + double capExpected = 0d; + OvernightInArrearsCapletFloorletPeriod period = FLOOR_LEG.getCapletFloorletPeriods().get(1); + double floorExpected = PRICER_PERIOD.presentValue(period, RATES_PAY, VOLS_PAY).getAmount(); + assertThat(capComputed.getCurrency()).isEqualTo(EUR); + assertThat(capComputed.getAmount()).isEqualTo(capExpected); + assertThat(floorComputed.getCurrency()).isEqualTo(EUR); + assertThat(floorComputed.getAmount()).isCloseTo(floorExpected, offset(TOL * NOTIONAL_VALUE)); + } + + //------------------------------------------------------------------------- + @Test + public void test_impliedVolatility() { + Map computed = + PRICER.impliedVolatilities(CAP_LEG, RATES, VOLS).getAmounts(); + Map expected = MapStream.of(CAP_LEG.getCapletFloorletPeriods()) + .mapValues(caplet -> PRICER_PERIOD.impliedVolatility(caplet, RATES, VOLS)) + .toMap(); + assertThat(computed).isEqualTo(expected); + computed.forEach((caplet, vol) -> assertThat(vol).isCloseTo(expected.get(caplet), offset(TOL))); + } + + @Test + public void test_impliedVolatility_onFix() { + Map computed = + PRICER.impliedVolatilities(CAP_LEG, RATES_PAY, VOLS_PAY).getAmounts(); + Map expected = MapStream.of(CAP_LEG.getCapletFloorletPeriods()) + .filterKeys(caplet -> VOLS_PAY.relativeTime(caplet.getEndDate().atStartOfDay(ZoneOffset.UTC)) >= 0) + .mapValues(caplet -> PRICER_PERIOD.impliedVolatility(caplet, RATES_PAY, VOLS_PAY)) + .toMap(); + assertThat(computed).isEqualTo(expected); + } + + @Test + public void test_impliedVolatility_afterFix() { + Map computed = + PRICER.impliedVolatilities(CAP_LEG, RATES_AFTER, VOLS_AFTER).getAmounts(); + Map expected = MapStream.of(CAP_LEG.getCapletFloorletPeriods()) + .filterKeys(caplet -> VOLS_AFTER.relativeTime(caplet.getEndDate().atStartOfDay(ZoneOffset.UTC)) >= 0) + .mapValues(caplet -> PRICER_PERIOD.impliedVolatility(caplet, RATES_AFTER, VOLS_AFTER)) + .toMap(); + assertThat(computed).isEqualTo(expected); + } + + //------------------------------------------------------------------------- + @Test + public void test_forwardRate() { + Map computed = PRICER.forwardRates(CAP_LEG, RATES).getAmounts(); + Map expected = MapStream.of(CAP_LEG.getCapletFloorletPeriods()) + .mapValues(caplet -> PRICER_PERIOD.forwardRate(caplet, RATES)) + .toMap(); + assertThat(computed).isEqualTo(expected); + } + + @Test + public void test_forwardRate_onFix() { + Map computed = PRICER.forwardRates(CAP_LEG, RATES_PAY).getAmounts(); + Map expected = MapStream.of(CAP_LEG.getCapletFloorletPeriods()) + .filterKeys(caplet -> !RATES_PAY.getValuationDate().isAfter(caplet.getEndDate())) + .mapValues(caplet -> PRICER_PERIOD.forwardRate(caplet, RATES_PAY)) + .toMap(); + assertThat(computed).isEqualTo(expected); + } + + @Test + public void test_forwardRate_afterFix() { + Map computed = + PRICER.forwardRates(CAP_LEG, RATES_AFTER).getAmounts(); + Map expected = MapStream.of(CAP_LEG.getCapletFloorletPeriods()) + .filterKeys(caplet -> !RATES_AFTER.getValuationDate().isAfter(caplet.getEndDate())) + .mapValues(caplet -> PRICER_PERIOD.forwardRate(caplet, RATES_AFTER)) + .toMap(); + assertThat(computed).isEqualTo(expected); + } + +} diff --git a/modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorProductPricerTest.java b/modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorProductPricerTest.java new file mode 100644 index 0000000000..d9e43c2715 --- /dev/null +++ b/modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorProductPricerTest.java @@ -0,0 +1,150 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.pricer.capfloor; + +import static com.opengamma.strata.basics.currency.Currency.EUR; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.CAP_LEG; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.CAP_ONE_LEG; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.CAP_TWO_LEGS; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.NOTIONAL_VALUE; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.PAY_LEG; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.RATES; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.RATES_PAY; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.VOLS; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.VOLS_PAY; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.data.Offset.offset; + +import org.junit.jupiter.api.Test; + +import com.opengamma.strata.basics.currency.CurrencyAmount; +import com.opengamma.strata.basics.currency.MultiCurrencyAmount; +import com.opengamma.strata.market.sensitivity.PointSensitivityBuilder; +import com.opengamma.strata.pricer.swap.DiscountingSwapLegPricer; + +/** + * Test {@link SabrOvernightInArrearsCapFloorProductPricer} + */ +public class SabrOvernightInArrearsCapFloorProductPricerTest { + + private static final SabrOvernightInArrearsCapFloorProductPricer PRICER = + SabrOvernightInArrearsCapFloorProductPricer.DEFAULT; + private static final SabrOvernightInArrearsCapFloorLegPricer PRICER_CAP_LEG = PRICER.getCapFloorLegPricer(); + private static final DiscountingSwapLegPricer PRICER_PAY_LEG = PRICER.getPayLegPricer(); + private static final double TOL = 1.0e-13; + + @Test + public void test_presentValue() { + MultiCurrencyAmount computed1 = PRICER.presentValue(CAP_ONE_LEG, RATES, VOLS); + MultiCurrencyAmount computed2 = PRICER.presentValue(CAP_TWO_LEGS, RATES, VOLS); + CurrencyAmount cap = PRICER_CAP_LEG.presentValue(CAP_LEG, RATES, VOLS); + CurrencyAmount pay = PRICER_PAY_LEG.presentValue(PAY_LEG, RATES); + assertThat(computed1).isEqualTo(MultiCurrencyAmount.of(cap)); + assertThat(computed2).isEqualTo(MultiCurrencyAmount.of(cap.plus(pay))); + } + + @Test + public void test_presentValueCapletFloorletPeriods() { + OvernightInArrearsCapletFloorletPeriodCurrencyAmounts computed1 = + PRICER.presentValueCapletFloorletPeriods(CAP_ONE_LEG, RATES, VOLS); + OvernightInArrearsCapletFloorletPeriodCurrencyAmounts computed2 = + PRICER.presentValueCapletFloorletPeriods(CAP_TWO_LEGS, RATES, VOLS); + OvernightInArrearsCapletFloorletPeriodCurrencyAmounts expected = + PRICER_CAP_LEG.presentValueCapletFloorletPeriods(CAP_LEG, RATES, VOLS); + assertThat(computed1).isEqualTo(expected); + assertThat(computed2).isEqualTo(expected); // calc ignores pay leg pv + } + + @Test + public void test_presentValueSensitivityRatesStickyModel() { + PointSensitivityBuilder computed1 = PRICER.presentValueSensitivityRatesStickyModel(CAP_ONE_LEG, RATES, VOLS); + PointSensitivityBuilder computed2 = PRICER.presentValueSensitivityRatesStickyModel(CAP_TWO_LEGS, RATES, VOLS); + PointSensitivityBuilder cap = PRICER_CAP_LEG.presentValueSensitivityRatesStickyModel(CAP_LEG, RATES, VOLS); + PointSensitivityBuilder pay = PRICER_PAY_LEG.presentValueSensitivity(PAY_LEG, RATES); + assertThat(computed1).isEqualTo(cap); + assertThat(computed2).isEqualTo(cap.combinedWith(pay)); + } + + @Test + public void test_presentValueSensitivityModelParamsSabr() { + PointSensitivityBuilder computed1 = PRICER.presentValueSensitivityModelParamsSabr(CAP_ONE_LEG, RATES, VOLS); + PointSensitivityBuilder computed2 = PRICER.presentValueSensitivityModelParamsSabr(CAP_TWO_LEGS, RATES, VOLS); + PointSensitivityBuilder cap = PRICER_CAP_LEG.presentValueSensitivityModelParamsSabr(CAP_LEG, RATES, VOLS); + assertThat(computed1).isEqualTo(cap); + assertThat(computed2).isEqualTo(cap); + } + + @Test + public void test_currencyExposure() { + MultiCurrencyAmount computed1 = PRICER.currencyExposure(CAP_ONE_LEG, RATES, VOLS); + MultiCurrencyAmount computed2 = PRICER.currencyExposure(CAP_TWO_LEGS, RATES, VOLS); + MultiCurrencyAmount pv1 = PRICER.presentValue(CAP_ONE_LEG, RATES, VOLS); + MultiCurrencyAmount pv2 = PRICER.presentValue(CAP_TWO_LEGS, RATES, VOLS); + PointSensitivityBuilder point1 = PRICER.presentValueSensitivityRatesStickyModel(CAP_ONE_LEG, RATES, VOLS); + PointSensitivityBuilder point2 = PRICER.presentValueSensitivityRatesStickyModel(CAP_TWO_LEGS, RATES, VOLS); + MultiCurrencyAmount expected1 = RATES.currencyExposure(point1.build()).plus(pv1); + MultiCurrencyAmount expected2 = RATES.currencyExposure(point2.build()).plus(pv2); + assertThat(computed1.getAmount(EUR).getAmount()) + .isCloseTo(expected1.getAmount(EUR).getAmount(), offset(NOTIONAL_VALUE * TOL)); + assertThat(computed2.getAmount(EUR).getAmount()) + .isCloseTo(expected2.getAmount(EUR).getAmount(), offset(NOTIONAL_VALUE * TOL)); + } + + @Test + public void test_currentCash() { + MultiCurrencyAmount cc1 = PRICER.currentCash(CAP_ONE_LEG, RATES, VOLS); + MultiCurrencyAmount cc2 = PRICER.currentCash(CAP_TWO_LEGS, RATES, VOLS); + assertThat(cc1).isEqualTo(MultiCurrencyAmount.of(CurrencyAmount.zero(EUR))); + assertThat(cc2).isEqualTo(MultiCurrencyAmount.of(CurrencyAmount.zero(EUR))); + } + + @Test + public void test_currentCash_onPay() { + MultiCurrencyAmount cc1 = PRICER.currentCash(CAP_ONE_LEG, RATES_PAY, VOLS_PAY); + MultiCurrencyAmount cc2 = PRICER.currentCash(CAP_TWO_LEGS, RATES_PAY, VOLS_PAY); + CurrencyAmount ccCap = PRICER_CAP_LEG.currentCash(CAP_LEG, RATES_PAY, VOLS_PAY); + CurrencyAmount ccPay = PRICER_PAY_LEG.currentCash(PAY_LEG, RATES_PAY); + assertThat(cc1).isEqualTo(MultiCurrencyAmount.of(ccCap)); + assertThat(cc2).isEqualTo(MultiCurrencyAmount.of(ccCap).plus(ccPay)); + } + + //------------------------------------------------------------------------- + @Test + public void test_impliedVolatility() { + OvernightInArrearsCapletFloorletPeriodAmounts computed = PRICER.impliedVolatilities(CAP_ONE_LEG, RATES, VOLS); + OvernightInArrearsCapletFloorletPeriodAmounts expected = PRICER_CAP_LEG.impliedVolatilities(CAP_LEG, RATES, VOLS); + assertThat(computed).isEqualTo(expected); + } + + @Test + public void test_impliedVolatility_onFix() { + OvernightInArrearsCapletFloorletPeriodAmounts computed = PRICER.impliedVolatilities( + CAP_ONE_LEG, + RATES_PAY, + VOLS_PAY); + OvernightInArrearsCapletFloorletPeriodAmounts expected = PRICER_CAP_LEG.impliedVolatilities( + CAP_LEG, + RATES_PAY, + VOLS_PAY); + assertThat(computed).isEqualTo(expected); + } + + //------------------------------------------------------------------------- + @Test + public void test_forwardRate() { + OvernightInArrearsCapletFloorletPeriodAmounts computed = PRICER.forwardRates(CAP_ONE_LEG, RATES); + OvernightInArrearsCapletFloorletPeriodAmounts expected = PRICER_CAP_LEG.forwardRates(CAP_LEG, RATES); + assertThat(computed).isEqualTo(expected); + } + + @Test + public void test_forwardRate_onFix() { + OvernightInArrearsCapletFloorletPeriodAmounts computed = PRICER.forwardRates(CAP_ONE_LEG, RATES_PAY); + OvernightInArrearsCapletFloorletPeriodAmounts expected = PRICER_CAP_LEG.forwardRates(CAP_LEG, RATES_PAY); + assertThat(computed).isEqualTo(expected); + } + +} diff --git a/modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorTestData.java b/modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorTestData.java new file mode 100644 index 0000000000..71924f58d4 --- /dev/null +++ b/modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorTestData.java @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.pricer.capfloor; + +import static com.opengamma.strata.basics.currency.Currency.EUR; +import static com.opengamma.strata.basics.date.HolidayCalendarIds.EUTA; +import static com.opengamma.strata.basics.index.OvernightIndices.EUR_ESTR; +import static com.opengamma.strata.collect.TestHelper.dateUtc; +import static com.opengamma.strata.product.common.PayReceive.PAY; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; + +import com.opengamma.strata.basics.ReferenceData; +import com.opengamma.strata.basics.currency.Payment; +import com.opengamma.strata.basics.date.BusinessDayAdjustment; +import com.opengamma.strata.basics.date.BusinessDayConventions; +import com.opengamma.strata.basics.date.DayCounts; +import com.opengamma.strata.basics.date.DaysAdjustment; +import com.opengamma.strata.basics.date.HolidayCalendar; +import com.opengamma.strata.basics.date.PeriodAdditionConventions; +import com.opengamma.strata.basics.date.Tenor; +import com.opengamma.strata.basics.date.TenorAdjustment; +import com.opengamma.strata.basics.index.IborIndex; +import com.opengamma.strata.basics.index.ImmutableIborIndex; +import com.opengamma.strata.basics.schedule.Frequency; +import com.opengamma.strata.basics.schedule.PeriodicSchedule; +import com.opengamma.strata.basics.schedule.RollConventions; +import com.opengamma.strata.basics.schedule.StubConvention; +import com.opengamma.strata.basics.value.ValueSchedule; +import com.opengamma.strata.collect.timeseries.LocalDateDoubleTimeSeries; +import com.opengamma.strata.collect.timeseries.LocalDateDoubleTimeSeriesBuilder; +import com.opengamma.strata.pricer.rate.ImmutableRatesProvider; +import com.opengamma.strata.product.TradeInfo; +import com.opengamma.strata.product.capfloor.OvernightInArrearsCapFloorLeg; +import com.opengamma.strata.product.capfloor.ResolvedOvernightInArrearsCapFloor; +import com.opengamma.strata.product.capfloor.ResolvedOvernightInArrearsCapFloorLeg; +import com.opengamma.strata.product.capfloor.ResolvedOvernightInArrearsCapFloorTrade; +import com.opengamma.strata.product.common.PayReceive; +import com.opengamma.strata.product.swap.OvernightRateCalculation; +import com.opengamma.strata.product.swap.ResolvedSwapLeg; + +/** + * Data for testing overnight rate in arrears cap/floor. + */ +public class SabrOvernightInArrearsCapFloorTestData { + + private static final ZonedDateTime VALUATION = dateUtc(2021, 12, 20); + private static final ZonedDateTime VALUATION_AFTER = dateUtc(2023, 8, 18); + private static final ZonedDateTime VALUATION_PAY = dateUtc(2024, 6, 24); + // reference data + private static final ReferenceData REF_DATA = ReferenceData.standard(); + private static final IborIndex EUR_ESTRTERM_3M = ImmutableIborIndex.builder() + .name("EUR-ESTRTERM-3M") + .currency(EUR) + .dayCount(DayCounts.ACT_360) + .fixingCalendar(EUTA) + .fixingTime(LocalTime.of(11, 0)) + .fixingZone(ZoneId.of("Europe/Brussels")) + .fixingDateOffset(DaysAdjustment.ofBusinessDays(-2, EUTA)) + .effectiveDateOffset(DaysAdjustment.ofBusinessDays(2, EUTA)) + .maturityDateOffset(TenorAdjustment.of( + Tenor.TENOR_3M, + PeriodAdditionConventions.LAST_BUSINESS_DAY, + BusinessDayAdjustment.of(BusinessDayConventions.MODIFIED_FOLLOWING, EUTA))) + .build(); + // cap leg and floor leg + private static final HolidayCalendar EUTA_IMPL = REF_DATA.getValue(EUTA); + private static final LocalDate START_DATE = LocalDate.of(2022, 6, 22); + private static final LocalDate END_DATE = LocalDate.of(2027, 6, 22); + static final double NOTIONAL_VALUE = 1_000_000.0d; + private static final ValueSchedule NOTIONAL = ValueSchedule.of(NOTIONAL_VALUE); + private static final double STRIKE = 0.0155; + private static final ValueSchedule STRIKE_SCHEDULE = ValueSchedule.of(STRIKE); + private static final PeriodicSchedule PAY_SCHEDULE = PeriodicSchedule.of( + START_DATE, + END_DATE, + Frequency.P12M, + BusinessDayAdjustment.of(BusinessDayConventions.MODIFIED_FOLLOWING, EUTA), + StubConvention.NONE, + RollConventions.NONE); + static final ResolvedOvernightInArrearsCapFloorLeg CAP_LEG = OvernightInArrearsCapFloorLeg.builder() + .capSchedule(STRIKE_SCHEDULE) + .calculation(OvernightRateCalculation.of(EUR_ESTR)) + .currency(EUR) + .notional(NOTIONAL) + .paymentSchedule(PAY_SCHEDULE) + .payReceive(PayReceive.RECEIVE) + .build().resolve(REF_DATA); + static final ResolvedOvernightInArrearsCapFloorLeg FLOOR_LEG = OvernightInArrearsCapFloorLeg.builder() + .floorSchedule(STRIKE_SCHEDULE) + .calculation(OvernightRateCalculation.of(EUR_ESTR)) + .currency(EUR) + .notional(NOTIONAL) + .paymentSchedule(PAY_SCHEDULE) + .payReceive(PayReceive.PAY) + .build().resolve(REF_DATA); + // caps + static final ResolvedSwapLeg PAY_LEG = IborCapFloorDataSet.createFixedPayLeg( + EUR_ESTRTERM_3M, + START_DATE, + END_DATE, + 0.0015, + NOTIONAL_VALUE, + PAY); + static final ResolvedOvernightInArrearsCapFloor CAP_TWO_LEGS = + ResolvedOvernightInArrearsCapFloor.of(CAP_LEG, PAY_LEG); + static final ResolvedOvernightInArrearsCapFloor CAP_ONE_LEG = ResolvedOvernightInArrearsCapFloor.of(CAP_LEG); + // cap trades + private static final TradeInfo TRADE_INFO = TradeInfo.builder().tradeDate(VALUATION.toLocalDate()).build(); + static final Payment PREMIUM = Payment.of(EUR, -NOTIONAL_VALUE * 0.19, VALUATION.toLocalDate()); + static final ResolvedOvernightInArrearsCapFloorTrade TRADE = ResolvedOvernightInArrearsCapFloorTrade.builder() + .product(CAP_ONE_LEG) + .build(); + static final ResolvedOvernightInArrearsCapFloorTrade TRADE_PAYLEG = ResolvedOvernightInArrearsCapFloorTrade.builder() + .product(CAP_TWO_LEGS) + .info(TRADE_INFO) + .build(); + static final ResolvedOvernightInArrearsCapFloorTrade TRADE_PREMIUM = ResolvedOvernightInArrearsCapFloorTrade.builder() + .product(CAP_ONE_LEG) + .premium(PREMIUM) + .info(TradeInfo.empty()) + .build(); + // valuation date before start date + static final ImmutableRatesProvider RATES = IborCapletFloorletSabrRateVolatilityDataSet.getRatesProvider( + VALUATION.toLocalDate(), + EUR_ESTRTERM_3M, + LocalDateDoubleTimeSeries.empty()); + static final SabrParametersIborCapletFloorletVolatilities VOLS = IborCapletFloorletSabrRateVolatilityDataSet + .getVolatilities(VALUATION, EUR_ESTRTERM_3M); + // valuation datas after start data + private static final LocalDateDoubleTimeSeries TS_ESTR_AFTER_END; + static { + LocalDateDoubleTimeSeriesBuilder builder = LocalDateDoubleTimeSeries.builder(); + LocalDate currentDate = START_DATE; + while (currentDate.isBefore(VALUATION_PAY.toLocalDate())) { + builder.put(currentDate, 0.0150); + currentDate = EUTA_IMPL.next(currentDate); + } + TS_ESTR_AFTER_END = builder.build(); + } + static final ImmutableRatesProvider RATES_AFTER = + IborCapletFloorletSabrRateVolatilityDataSet.getRatesProvider( + VALUATION_AFTER.toLocalDate(), + EUR_ESTRTERM_3M, + LocalDateDoubleTimeSeries.empty()).toBuilder() + .timeSeries(EUR_ESTR, TS_ESTR_AFTER_END) + .build(); + static final SabrParametersIborCapletFloorletVolatilities VOLS_AFTER = + IborCapletFloorletSabrRateVolatilityDataSet.getVolatilities(VALUATION_AFTER, EUR_ESTRTERM_3M); + static final ImmutableRatesProvider RATES_PAY = + IborCapletFloorletSabrRateVolatilityDataSet.getRatesProvider( + VALUATION_PAY.toLocalDate(), + EUR_ESTRTERM_3M, + LocalDateDoubleTimeSeries.empty()).toBuilder() + .timeSeries(EUR_ESTR, TS_ESTR_AFTER_END) + .build(); + static final SabrParametersIborCapletFloorletVolatilities VOLS_PAY = + IborCapletFloorletSabrRateVolatilityDataSet.getVolatilities(VALUATION_PAY, EUR_ESTRTERM_3M); + + private SabrOvernightInArrearsCapFloorTestData() { + } + +} diff --git a/modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorTradePricerTest.java b/modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorTradePricerTest.java new file mode 100644 index 0000000000..2ddc9d2929 --- /dev/null +++ b/modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapFloorTradePricerTest.java @@ -0,0 +1,186 @@ +/* + * Copyright (C) 2024 - present by OpenGamma Inc. and the OpenGamma group of companies + * + * Please see distribution for license. + */ +package com.opengamma.strata.pricer.capfloor; + +import static com.opengamma.strata.basics.currency.Currency.EUR; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.CAP_ONE_LEG; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.CAP_TWO_LEGS; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.NOTIONAL_VALUE; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.PREMIUM; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.RATES; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.RATES_PAY; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.TRADE; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.TRADE_PAYLEG; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.TRADE_PREMIUM; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.VOLS; +import static com.opengamma.strata.pricer.capfloor.SabrOvernightInArrearsCapFloorTestData.VOLS_PAY; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.data.Offset.offset; + +import org.junit.jupiter.api.Test; + +import com.opengamma.strata.basics.currency.CurrencyAmount; +import com.opengamma.strata.basics.currency.MultiCurrencyAmount; +import com.opengamma.strata.market.sensitivity.PointSensitivities; +import com.opengamma.strata.pricer.DiscountingPaymentPricer; + +/** + * Test {@link SabrOvernightInArrearsCapFloorTradePricer}. + */ +public class SabrOvernightInArrearsCapFloorTradePricerTest { + + private static final SabrOvernightInArrearsCapFloorTradePricer PRICER = + SabrOvernightInArrearsCapFloorTradePricer.DEFAULT; + private static final SabrOvernightInArrearsCapFloorProductPricer PRICER_PRODUCT = PRICER.getProductPricer(); + private static final DiscountingPaymentPricer PRICER_PREMIUM = PRICER.getPaymentPricer(); + private static final double TOL = 1.0e-13; + + @Test + public void test_presentValue() { + MultiCurrencyAmount computedWithPayLeg = PRICER.presentValue(TRADE_PAYLEG, RATES, VOLS); + MultiCurrencyAmount computedWithPremium = PRICER.presentValue(TRADE_PREMIUM, RATES, VOLS); + MultiCurrencyAmount pvOneLeg = PRICER_PRODUCT.presentValue(CAP_ONE_LEG, RATES, VOLS); + MultiCurrencyAmount pvTwoLegs = PRICER_PRODUCT.presentValue(CAP_TWO_LEGS, RATES, VOLS); + CurrencyAmount pvPrem = PRICER_PREMIUM.presentValue(PREMIUM, RATES); + assertThat(computedWithPayLeg).isEqualTo(pvTwoLegs); + assertThat(computedWithPremium).isEqualTo(pvOneLeg.plus(pvPrem)); + } + + @Test + public void test_presentValueCapletFloorletPeriods() { + OvernightInArrearsCapletFloorletPeriodCurrencyAmounts computed = PRICER.presentValueCapletFloorletPeriods( + TRADE, + RATES, + VOLS); + OvernightInArrearsCapletFloorletPeriodCurrencyAmounts computedWithPayLeg = PRICER.presentValueCapletFloorletPeriods( + TRADE_PAYLEG, + RATES, + VOLS); + OvernightInArrearsCapletFloorletPeriodCurrencyAmounts computedWithPremium = PRICER.presentValueCapletFloorletPeriods( + TRADE_PREMIUM, + RATES, + VOLS); + OvernightInArrearsCapletFloorletPeriodCurrencyAmounts expected = PRICER_PRODUCT.presentValueCapletFloorletPeriods( + CAP_ONE_LEG, + RATES, + VOLS); + assertThat(computed).isEqualTo(expected); + assertThat(computedWithPayLeg).isEqualTo(expected); // calc ignores pay leg pv + assertThat(computedWithPremium).isEqualTo(expected); // calc ignores premium pv + } + + @Test + public void test_presentValueSensitivityRatesStickyModel() { + PointSensitivities computedWithPayLeg = PRICER.presentValueSensitivityRatesStickyModel(TRADE_PAYLEG, RATES, VOLS); + PointSensitivities computedWithPremium = PRICER.presentValueSensitivityRatesStickyModel(TRADE_PREMIUM, RATES, VOLS); + PointSensitivities pvOneLeg = PRICER_PRODUCT.presentValueSensitivityRatesStickyModel( + CAP_ONE_LEG, + RATES, + VOLS).build(); + PointSensitivities pvTwoLegs = PRICER_PRODUCT.presentValueSensitivityRatesStickyModel( + CAP_TWO_LEGS, + RATES, + VOLS).build(); + PointSensitivities pvPrem = PRICER_PREMIUM.presentValueSensitivity(PREMIUM, RATES).build(); + assertThat(computedWithPayLeg).isEqualTo(pvTwoLegs); + assertThat(computedWithPremium).isEqualTo(pvOneLeg.combinedWith(pvPrem)); + } + + @Test + public void test_presentValueSensitivityModelParamsSabr() { + PointSensitivities computedWithPayLeg = PRICER.presentValueSensitivityModelParamsSabr( + TRADE_PAYLEG, + RATES, + VOLS).build(); + PointSensitivities computedWithPremium = PRICER.presentValueSensitivityModelParamsSabr( + TRADE_PREMIUM, + RATES, + VOLS).build(); + PointSensitivities pvOneLeg = PRICER_PRODUCT.presentValueSensitivityModelParamsSabr( + CAP_ONE_LEG, + RATES, + VOLS).build(); + PointSensitivities pvTwoLegs = PRICER_PRODUCT.presentValueSensitivityModelParamsSabr( + CAP_TWO_LEGS, + RATES, + VOLS).build(); + assertThat(computedWithPayLeg).isEqualTo(pvTwoLegs); + assertThat(computedWithPremium).isEqualTo(pvOneLeg); + } + + @Test + public void test_currencyExposure() { + MultiCurrencyAmount computedWithPayLeg = PRICER.currencyExposure(TRADE_PAYLEG, RATES, VOLS); + MultiCurrencyAmount computedWithPremium = PRICER.currencyExposure(TRADE_PREMIUM, RATES, VOLS); + MultiCurrencyAmount pvWithPayLeg = PRICER.presentValue(TRADE_PAYLEG, RATES, VOLS); + MultiCurrencyAmount pvWithPremium = PRICER.presentValue(TRADE_PREMIUM, RATES, VOLS); + PointSensitivities pointWithPayLeg = PRICER.presentValueSensitivityRatesStickyModel(TRADE_PAYLEG, RATES, VOLS); + PointSensitivities pointWithPremium = PRICER.presentValueSensitivityRatesStickyModel(TRADE_PREMIUM, RATES, VOLS); + MultiCurrencyAmount expectedWithPayLeg = RATES.currencyExposure(pointWithPayLeg).plus(pvWithPayLeg); + MultiCurrencyAmount expectedWithPremium = RATES.currencyExposure(pointWithPremium).plus(pvWithPremium); + assertThat(computedWithPayLeg.getAmount(EUR).getAmount()).isCloseTo( + expectedWithPayLeg.getAmount(EUR).getAmount(), + offset(NOTIONAL_VALUE * TOL)); + assertThat(computedWithPremium.getAmount(EUR).getAmount()).isCloseTo( + expectedWithPremium.getAmount(EUR).getAmount(), + offset(NOTIONAL_VALUE * TOL)); + } + + @Test + public void test_currentCash() { + MultiCurrencyAmount computedWithPayLeg = PRICER.currentCash(TRADE_PAYLEG, RATES, VOLS); + MultiCurrencyAmount computedWithPremium = PRICER.currentCash(TRADE_PREMIUM, RATES, VOLS); + assertThat(computedWithPayLeg).isEqualTo(MultiCurrencyAmount.of(CurrencyAmount.zero(EUR))); + assertThat(computedWithPremium).isEqualTo(MultiCurrencyAmount.of(PREMIUM.getValue())); + } + + @Test + public void test_currentCash_onPay() { + MultiCurrencyAmount computedWithPayLeg = PRICER.currentCash(TRADE_PAYLEG, RATES_PAY, VOLS_PAY); + MultiCurrencyAmount computedWithPremium = PRICER.currentCash(TRADE_PREMIUM, RATES_PAY, VOLS_PAY); + MultiCurrencyAmount expectedWithPayLeg = PRICER_PRODUCT.currentCash(CAP_TWO_LEGS, RATES_PAY, VOLS_PAY); + MultiCurrencyAmount expectedWithPremium = PRICER_PRODUCT.currentCash(CAP_ONE_LEG, RATES_PAY, VOLS_PAY); + assertThat(computedWithPayLeg).isEqualTo(expectedWithPayLeg); + assertThat(computedWithPremium).isEqualTo(expectedWithPremium); + } + + @Test + public void test_forwardRates() { + OvernightInArrearsCapletFloorletPeriodAmounts computedWithPayLeg = PRICER.forwardRates(TRADE_PAYLEG, RATES_PAY); + OvernightInArrearsCapletFloorletPeriodAmounts computedWithPremium = PRICER.forwardRates(TRADE_PREMIUM, RATES_PAY); + OvernightInArrearsCapletFloorletPeriodAmounts expectedWithPayLeg = PRICER_PRODUCT.forwardRates( + CAP_TWO_LEGS, + RATES_PAY); + OvernightInArrearsCapletFloorletPeriodAmounts expectedWithPremium = PRICER_PRODUCT.forwardRates( + CAP_ONE_LEG, + RATES_PAY); + assertThat(computedWithPayLeg).isEqualTo(expectedWithPayLeg); + assertThat(computedWithPremium).isEqualTo(expectedWithPremium); + } + + @Test + public void test_impliedVolatilities() { + OvernightInArrearsCapletFloorletPeriodAmounts computedWithPayLeg = PRICER.impliedVolatilities( + TRADE_PAYLEG, + RATES_PAY, + VOLS_PAY); + OvernightInArrearsCapletFloorletPeriodAmounts computedWithPremium = PRICER.impliedVolatilities( + TRADE_PREMIUM, + RATES_PAY, + VOLS_PAY); + OvernightInArrearsCapletFloorletPeriodAmounts expectedWithPayLeg = PRICER_PRODUCT.impliedVolatilities( + CAP_TWO_LEGS, + RATES_PAY, + VOLS_PAY); + OvernightInArrearsCapletFloorletPeriodAmounts expectedWithPremium = PRICER_PRODUCT.impliedVolatilities( + CAP_ONE_LEG, + RATES_PAY, + VOLS_PAY); + assertThat(computedWithPayLeg).isEqualTo(expectedWithPayLeg); + assertThat(computedWithPremium).isEqualTo(expectedWithPremium); + } + +} diff --git a/modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapletFloorletPeriodPricerTest.java b/modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapletFloorletPeriodPricerTest.java index ff700c9735..04603fdb77 100644 --- a/modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapletFloorletPeriodPricerTest.java +++ b/modules/pricer/src/test/java/com/opengamma/strata/pricer/capfloor/SabrOvernightInArrearsCapletFloorletPeriodPricerTest.java @@ -9,11 +9,14 @@ import static com.opengamma.strata.basics.date.HolidayCalendarIds.EUTA; import static com.opengamma.strata.basics.index.OvernightIndices.EUR_ESTR; import static com.opengamma.strata.collect.TestHelper.dateUtc; +import static com.opengamma.strata.pricer.capfloor.IborCapletFloorletSabrRateVolatilityDataSet.CONST_SHIFT; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; import java.time.LocalDate; import java.time.LocalTime; import java.time.ZoneId; +import java.time.ZoneOffset; import java.time.ZonedDateTime; import org.assertj.core.data.Offset; @@ -427,7 +430,6 @@ public void presentValue_afterpay_formula() { assertThat(computedCaplet.getAmount()).isCloseTo(0.0d, TOLERANCE_PV); assertThat(computedFloorlet.getCurrency()).isEqualTo(EUR); assertThat(computedFloorlet.getAmount()).isCloseTo(0.0d, TOLERANCE_PV); - } //------------------------------------------------------------------------- @@ -586,7 +588,6 @@ public void presentValue_afterend_param_sensitivity() { .presentValueSensitivityModelParamsSabr(FLOORLET_SHORT, RATES_AFTER_END, VOLS_AFTER_END).build(); assertThat(ptsCapletLongComputed).isEqualTo(PointSensitivities.empty()); assertThat(ptsFloorletShortComputed).isEqualTo(PointSensitivities.empty()); - } @Test @@ -597,7 +598,102 @@ public void presentValue_afterpay_param_sensitivity() { .presentValueSensitivityModelParamsSabr(FLOORLET_SHORT, RATES_AFTER_PAY, VOLS_AFTER_PAY).build(); assertThat(ptsCapletLongComputed).isEqualTo(PointSensitivities.empty()); assertThat(ptsFloorletShortComputed).isEqualTo(PointSensitivities.empty()); + } + + //------------------------------------------------------------------------- + + @Test + public void forwardRate_impliedVolatility_beforestart() { + double forwardRateCapletComputed = PRICER_ON_INARREARS_Q1.forwardRate(CAPLET_LONG, RATES); + double impliedVolCapletComputed = PRICER_ON_INARREARS_Q1.impliedVolatility(CAPLET_LONG, RATES, VOLS); + double forwardRateFloorletComputed = PRICER_ON_INARREARS_Q1.forwardRate(FLOORLET_LONG, RATES); + double impliedVolFloorletComputed = PRICER_ON_INARREARS_Q1.impliedVolatility(FLOORLET_LONG, RATES, VOLS); + OvernightIndexObservation onObs = OvernightIndexObservation.of(EUR_ESTR, START_DATE, REF_DATA); + double forwardExpected = RATES.overnightIndexRates(EUR_ESTR).periodRate(onObs, END_DATE); + assertThat(forwardRateCapletComputed).isCloseTo(forwardExpected, TOLERANCE_SMALL_IV); + assertThat(forwardRateFloorletComputed).isCloseTo(forwardExpected, TOLERANCE_SMALL_IV); + double num = NOTIONAL * ACCRUAL_FACTOR * RATES.discountFactor(EUR, PAYMENT_DATE); + double timeToExpiry = VOLS.relativeTime(END_DATE.atStartOfDay(ZoneOffset.UTC)); + CurrencyAmount inArrearsPv = PRICER_ON_INARREARS_Q1.presentValue(CAPLET_LONG, RATES, VOLS); + double impliedVolExpected = BlackFormulaRepository.impliedVolatility( + inArrearsPv.getAmount() / num, + forwardExpected + CONST_SHIFT, + STRIKE + CONST_SHIFT, + timeToExpiry, + true); + assertThat(impliedVolCapletComputed).isCloseTo(impliedVolExpected, TOLERANCE_SMALL_IV); + assertThat(impliedVolFloorletComputed).isCloseTo(impliedVolExpected, TOLERANCE_SMALL_IV); + } + + @Test + public void forwardRate_impliedVolatility_afterstart() { + double strike = 0.0115; // near-ATM + OvernightInArrearsCapletFloorletPeriod capletLong = + OvernightInArrearsCapletFloorletPeriod.builder() + .caplet(strike) + .startDate(START_DATE) + .endDate(END_DATE) + .paymentDate(PAYMENT_DATE) + .yearFraction(ACCRUAL_FACTOR) + .notional(NOTIONAL) + .overnightRate(RATE_COMP) + .build(); + OvernightInArrearsCapletFloorletPeriod floorletLong = + OvernightInArrearsCapletFloorletPeriod.builder() + .floorlet(strike) + .startDate(START_DATE) + .endDate(END_DATE) + .paymentDate(PAYMENT_DATE) + .yearFraction(ACCRUAL_FACTOR) + .notional(NOTIONAL) + .overnightRate(RATE_COMP) + .build(); + double forwardRateCapletComputed = PRICER_ON_INARREARS_Q1.forwardRate(capletLong, RATES_AFTER_START); + double impliedVolCapletComputed = PRICER_ON_INARREARS_Q1.impliedVolatility( + capletLong, + RATES_AFTER_START, + VOLS_AFTER_START); + double forwardRateFloorletComputed = PRICER_ON_INARREARS_Q1.forwardRate(floorletLong, RATES_AFTER_START); + double impliedVolFloorletComputed = PRICER_ON_INARREARS_Q1.impliedVolatility( + floorletLong, + RATES_AFTER_START, + VOLS_AFTER_START); + double forwardExpected = ForwardOvernightCompoundedRateComputationFn.DEFAULT.rate( + capletLong.getOvernightRate(), + START_DATE, + END_DATE, + RATES_AFTER_START); + assertThat(forwardRateCapletComputed).isCloseTo(forwardExpected, TOLERANCE_SMALL_IV); + assertThat(forwardRateFloorletComputed).isCloseTo(forwardExpected, TOLERANCE_SMALL_IV); + double num = NOTIONAL * ACCRUAL_FACTOR * RATES_AFTER_START.discountFactor(EUR, PAYMENT_DATE); + double timeToExpiry = VOLS_AFTER_START.relativeTime(END_DATE.atStartOfDay(ZoneOffset.UTC)); + CurrencyAmount inArrearsPv = PRICER_ON_INARREARS_Q1.presentValue(capletLong, RATES_AFTER_START, VOLS_AFTER_START); + double impliedVolExpected = BlackFormulaRepository.impliedVolatility( + inArrearsPv.getAmount() / num, + forwardExpected + CONST_SHIFT, + strike + CONST_SHIFT, + timeToExpiry, + true); + assertThat(impliedVolCapletComputed).isCloseTo(impliedVolExpected, TOLERANCE_SMALL_IV); + assertThat(impliedVolFloorletComputed).isCloseTo(impliedVolExpected, TOLERANCE_SMALL_IV); + } + @Test + public void forwardRate_impliedVolatility_afterend() { + double forwardRateCapletComputed = PRICER_ON_INARREARS_Q1.forwardRate(CAPLET_LONG, RATES_AFTER_END); + double forwardRateFloorletComputed = PRICER_ON_INARREARS_Q1.forwardRate(FLOORLET_LONG, RATES_AFTER_END); + double forwardExpected = ForwardOvernightCompoundedRateComputationFn.DEFAULT.rate( + CAPLET_LONG.getOvernightRate(), + START_DATE, + END_DATE, + RATES_AFTER_END); + assertThat(forwardRateCapletComputed).isCloseTo(forwardExpected, TOLERANCE_SMALL_IV); + assertThat(forwardRateFloorletComputed).isCloseTo(forwardExpected, TOLERANCE_SMALL_IV); + // impliedVolatility fails after expiry + assertThatIllegalArgumentException() + .isThrownBy(() -> PRICER_ON_INARREARS_Q1.impliedVolatility(CAPLET_LONG, RATES_AFTER_END, VOLS_AFTER_END)); + assertThatIllegalArgumentException() + .isThrownBy(() -> PRICER_ON_INARREARS_Q1.impliedVolatility(FLOORLET_LONG, RATES_AFTER_END, VOLS_AFTER_END)); } } From c132356d4086a867674344930eff8de44d49cf16 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Thu, 17 Oct 2024 14:39:58 +0000 Subject: [PATCH 112/116] [maven-release-plugin] prepare release v2.12.43 --- examples/pom.xml | 6 +++++- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index 8f504e9229..c4c542006e 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.43-SNAPSHOT + 2.12.43 jar Strata-Examples Example code to demonstrate use of Strata @@ -272,4 +272,8 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> + + + v2.12.43 + diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index da026b9501..5a1ecc949e 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.43-SNAPSHOT + 2.12.43 .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index af02a59f04..497a8ef49e 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.43-SNAPSHOT + 2.12.43 .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index fee1aab278..35ce20a409 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.43-SNAPSHOT + 2.12.43 .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 493539c4e7..384f1354cf 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.43-SNAPSHOT + 2.12.43 .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 60b62bbfb8..31686c8b52 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.43-SNAPSHOT + 2.12.43 .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index a2fc6b5103..b1fac8ad42 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.43-SNAPSHOT + 2.12.43 .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 50d0d221a7..a741fc8eec 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.43-SNAPSHOT + 2.12.43 .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 32348ee22b..8b73d37ac8 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.43-SNAPSHOT + 2.12.43 .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 5a2cd0de67..5c3679df30 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.43-SNAPSHOT + 2.12.43 pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.43 diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 9402f178cc..e4b9202891 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.43-SNAPSHOT + 2.12.43 .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 3598b4c230..f692cd3d7c 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.43-SNAPSHOT + 2.12.43 .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index dd1356d3ee..0e274533db 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.43-SNAPSHOT + 2.12.43 .. strata-report diff --git a/pom.xml b/pom.xml index 6ced91402f..fae8c87393 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.43-SNAPSHOT + 2.12.43 pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.43 From d92d4ecf6c49f13ac4e0af0af98ea24784a9aff5 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Thu, 17 Oct 2024 14:40:00 +0000 Subject: [PATCH 113/116] [maven-release-plugin] prepare for next development iteration --- examples/pom.xml | 6 +----- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index c4c542006e..b968607eb1 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.43 + 2.12.44-SNAPSHOT jar Strata-Examples Example code to demonstrate use of Strata @@ -272,8 +272,4 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> - - - v2.12.43 - diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index 5a1ecc949e..0e84c7ab2a 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.43 + 2.12.44-SNAPSHOT .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 497a8ef49e..2d73016809 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.43 + 2.12.44-SNAPSHOT .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 35ce20a409..66951bea44 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.43 + 2.12.44-SNAPSHOT .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 384f1354cf..8365ff3e38 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.43 + 2.12.44-SNAPSHOT .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 31686c8b52..e0aab3eb48 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.43 + 2.12.44-SNAPSHOT .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index b1fac8ad42..31055089ac 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.43 + 2.12.44-SNAPSHOT .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index a741fc8eec..608c0b2bdd 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.43 + 2.12.44-SNAPSHOT .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 8b73d37ac8..d4721fa8e6 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.43 + 2.12.44-SNAPSHOT .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 5c3679df30..b93dddd2d5 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.43 + 2.12.44-SNAPSHOT pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.43 + HEAD diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index e4b9202891..1a71a31ad0 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.43 + 2.12.44-SNAPSHOT .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index f692cd3d7c..3b4e1150cd 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.43 + 2.12.44-SNAPSHOT .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 0e274533db..d1b2cd2a47 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.43 + 2.12.44-SNAPSHOT .. strata-report diff --git a/pom.xml b/pom.xml index fae8c87393..836e807683 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.43 + 2.12.44-SNAPSHOT pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.43 + HEAD From 0604bec3cdb57f4b76cc1ccf67beb3f27230c4a0 Mon Sep 17 00:00:00 2001 From: Andras Vig <93195277+Andras1022@users.noreply.github.com> Date: Mon, 28 Oct 2024 13:08:56 +0100 Subject: [PATCH 114/116] Adding Inauguration Day to MXMC (#2682) * Adding Inauguration Day to MXMC * Adding Inauguration Day to MXMC * Adding Inauguration Day to MXMC --- .../basics/date/GlobalHolidayCalendars.bin | Bin 178050 -> 178050 bytes .../basics/date/GlobalHolidayCalendars.bin | Bin 178050 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/main/resources/com/opengamma/strata/basics/date/GlobalHolidayCalendars.bin diff --git a/modules/basics/src/main/resources/com/opengamma/strata/basics/date/GlobalHolidayCalendars.bin b/modules/basics/src/main/resources/com/opengamma/strata/basics/date/GlobalHolidayCalendars.bin index 8dc6a3d4dab3cdb83346bbe619939cb7b8105fdb..5599a791a5c8ee428b52049b0ad8b59064fbcd2c 100644 GIT binary patch delta 83 zcmZpA&(-vvt6>YH=@Z6t+s&RZ$}n_1FP%mnP`}ub1W40X?@;+5xlym-g8KT(=_Z0h0xn_2B_`w=D7jR>hgp BE)oC$ diff --git a/src/main/resources/com/opengamma/strata/basics/date/GlobalHolidayCalendars.bin b/src/main/resources/com/opengamma/strata/basics/date/GlobalHolidayCalendars.bin deleted file mode 100644 index 5599a791a5c8ee428b52049b0ad8b59064fbcd2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 178050 zcmeIbO^jpNl_r+sN+4R8nxugMraRp9BVfr2*bowGaUdjX9tfAR)!AsN#YR^PGin4d z5=v6c0JX>}7GM%4dLzKOFfg&}GN#nzvetHOIsq>%1l-|KP8E$VFQzuOve}s&t(+0u zBr(14_nrIm-Xrx`|kPfcfNDZJ?}mK{{0`lbL;5V?FZlbZtvC) z55@<-aXOuJUtccfBm6WbY5MjYFW`?J{v9snXD$4}V^X}|#P5B)e+TcUc;OhY4;L3x zcMM*>Xy9`^hGTpe|6&YzzlYyDi}NX8$LCV}`ehr(;w7BBJ9=n8cYu$d;wN1$&J%pV z9fL6j9gJtk=svV#zlP8C`Psox=8a>{cnro!F~+=wKRCui{Ejh3U&7~x^4Y=gfjN&H zgE7YZ9FM^m(|cx&ZWEtN@cS|6Ju~)TY#zGN-Ui;0bDlffQisV5V*oQV#*fVyV!J)( zqtu+o9aDyju7`dv4ByF*f3Ji1+23Y3kPUg7fQ_*h@Ze>;}f`U*JTT6UMIO z1CKd=iCfNh0Y@51MwLQ4QKPm zyo+Nv_NhIO^Opobm~*b#oA-sKf)AYc7{du?^8VuR$@@zKh;rVTlKASHzl>fi^2e0n zbA&NcbIyUrUh0FK6MV>HGO+XR1AD%2_2E(4oVTnEFtL1i`5M;4tcmc!Ysdo}!+G=kZ5(6$C5O-G1&&GGF=hBPF@~Je z@S)b;j1SWWF!36aUu(|E`pYUGt{tC4*ggbqIH$_q*nA*9{K1-xwfLNJE%$^E#Ak$` z#yA;)Gh9lEFJ=Cc;C&thd*kw9`83d9mQNeGmNnLe!WApoCoqSjA<)WJGv z?LCFL={56VRX^{5*cyDAzz^^thL4k>i5E{fzp{9d=Yv)sdVzc}_(*=^;{9Z_3qH)%`FXBhtHtLK*bLzVEm-;>B%Vg%gV#?}uLbC57$2~_ zQTV|4Le7wD(AZjkA$RBlA@RcaOB_Bpf6?M|1nz{`>+93tdQIwg6(4f-yQ*HJK4|R? z)d%tcRFinF;e*E~V*MVX51tPJ`8mv0*RxIF1NzJUo+e&wqYt5cI0YTF_3WY3PY_6} zpE3E6;iIo-L+p*s2cMtA5RJbi;Ew2L?D{=;e?ym_AHi2*^MRabN6gRr@PUx}JwzWo zAIAFpT=ZnBuiv-QhsgDN0%B|Qr0Mii8866%*nAK@QQ&jy_V4}iAH7-9D||LZde7Q3 z84VX7Nquj|T|Ce4b*HJRHHM3eKcEiqn9=fMiMNKA%PZFl;QKwiExp2%<$K4-ckwxl zozg#S-Tj8^67Um}5TUzFV&M@nLtcka(Bvbq|J%@0erGx}(q8E94k< zulvb(gx@(vA(wdKjyXZ^>IG}iR%?UmilZc^B%m+?{#xtodt8t$Hb>whmXr8TIuLs9X^Nitk(Dm#!j(6((0Dm zo6n{D7f)1tfVq-Ozy{#sdWD<$;PGLv@G?F%1V>;TnN{v!O^6F%f?jbWeu zGP*n^{cH78uMZrLx%6*#N7T>OXsOUoB_A^V9KAR_`@m{!xt=t^o$d62xpbfUV6U|( z*N0F(gy3^H&w7O#dqedhln>NT{$O3lqsuE5J|Xso>O&|W^10=EbICVmI{l2y2jotz zyW%fnoxd!f_V5A3yy>QVgPKVlKf?PX{NBK#^~K)Ht15eU!3WN(gI?j?5%qIin{Qy= z_=GNAkPogm1m4{x4t4p4;4@A}mJgNjG{XnIvn$ch%6zN^U+Dq+4(0`^RmBVOmuuz& zZ6xl_Uy{UKS2TN8g-;Wog9*ruP+KYNg{i^%5XuLGk1jty1a~q%w6@{Htj=EmC3DAU z`MI(8di7zI53Mv^YV&h`7Ij7XwxV7mHsnM*AYR1e1LKS9o%P1u6XTcF`KQ=B_WJOJ z^Fi?8wXe#0HpE`153%?_{RGu)t+hY(JLhC@y?C-Io{|H6-{aH8-tSHQZZXUDD|~*X z)Q3<$P)l0)X$RD^Mn84&!snlZc=bD|#=RaeY=LmUEh`m0) zdNk=mo1^UKgw|_)#0NQf^%}WjbWLBs--o$eGtK^<=R-h#J_IK)ugLYget$2N z527c^{f$F#$Jncj7qR(}>8HM)4Y4;iAAEd)A@ED+XLUX6^;3F9M_y`u$$7pXd!~_V>sK{X3i}tokfc)xiMC&Jk4 zy}~PhU!mQ{7C-!uC*>IHwZ@h76EPg#b@j^plN7&m9!;D(!SBb|i|EXri9LKBFKx8f z$AWXoEuS|&aJ@oTpUJ#G{|YCwTs&{!KmOV=y+YtKxr?dNwo-iV zXvdgxP>kX6ImG)iUh4KD`sfv6k?}f@wV(6$()T%b!{pNB1NJtn`M`0GO>X&V>#pk+ z*5G4m4cLFz-B-wYcV(_97W4Ro*z04#z~+|M%!hm~@!tIG&mD$#-fRAn02{NGk~^vF zwQIuO@wM~8`;_Fj%NrT!vZ-xEHpzWGziD{j&Xxy+Vb4D*2GXK$!Jgz|y$g+FcNmM522#K*A6G ziFq}{G{A;rAyTzNs1zayr1<7fj!r<&R&kk`wGztzIHx1e@PPCD}2meVL3icaD&DjPj&Y0f)55C z+50Wa&%M7K&a+ zmx=TWH`Qwed=g+oo7?5_V$I&(BupO+J~}=yzPR4mcYLo&|I z2tKA)2t8S=XV>&I#9pTlvG_oIKsAYJ!_D=3!CzY7PN==1e1K+8I43y|8aO!R%C)|D zAEM3oJw9Ex_q$fV7yP9O{Y)@kd_G7ofbnIueqZB*qMj}2r^G7&WUeJxtKSRu`gjUN zaVt}iW{)C)a*H67ZkPld1(;M1czi-V4;*;X1QC`m$^n~1@Jt6UeJnfY4 z=e!ahe15LP=V(z|zZdNF`DgilPC*~G;X_S+zJ^b1J^)Ioy-W6UHsfP@0h{Xg0zTx< zPWTXzpTpdIuTYnN?hzkOArEQw{>Hj~LQoz&VP0PyFQ^YO`H=ZbX+8U7qkbyw_4*Kr z4?e!Y5cp+nJ?r(eynbJ^H&h=&_>keFuislM2D3SS&d*LsDUdSTtcLgL+euMp2^ z!YS8k4cf?gtk)W5e-Hk|yxR57_c}rp-RLocLa0VV}z0 zSNONY%;4i|4Y!xYeVC2-xLTuC-YfL@9AXTtr98vL)EW!dE8J-BhFrRq55&#)0=m9e zSdEXbHQarL%Tjzo?Der=kiQP?`uLE~C2(J1zE`->U&tNdLx8<8`QY*KvBT_#gX_qn zvb}ChTm0n++~MosDX+uyoEcW=Lu@{{*a51&2fwWKmp*);JJ=6C_*%@@8t%SAbKQW< z72vPyr(PdqEnRL2*LQ2#!CK1N5DxqfUS|5KUcpuxL)CDu~)cJA42(%;p1x!cdc697mE4` zhcRne=oOaQYu3{BhOUPXj#JKG5)j**$M*_1;?o3=3nGMBcKyyd8C*B_ z3NdZrgU6@q_I_{b_YU~y@@*eaCvo<3s3k4@*!v2}8F#I3b^e)M`~8LP=MW!IO zAfDKJZm<3Rg7CEvq$7cfW1DydNk>Fq{hGg{hZKxt&f-ichB8d_{Ht#czhz( z@AqLY*G#j&=lKwjpASvE%H3Be*Q!-W%jA^vjB`#FveF8@qGY;zuM{qA~&)%(5VLTo;0 z@ws*T+u#2aK7;g=+y6K0m->J{(E&fq8v4C=?l<^e6`l`;qn1|(_|Kdx+ZS^<=EvBu zx90nBJkRPFDfq^D9AO?DuK~dNqD7{L7~=I7KIlHT@jCom|3b#Vco>88Uc8QfF@}6U znqLcRzdPm_hr08uJtGu*YqURqOdDgn^Q?V88hn%XbTIEt_VROlpWMs#QnG%Ho0A*E z)&kl0OOBI3e8vgwZ&?i8yxn;U&x{2?cHSy`Pl20UhmYPv+hXG8P1}jt20lE^A7jQ? z=hV7y`q~iax%$%AN^&2lIj7EEa)CdX_ZY(!>SfLwm4)Ub^6dsB%AN5_{AA;DgssUMr%EFLs@R_|P2;{aOOo zdi}%)?0H=8dm|qTduvMlB)>x9h2?P+J~)5T;&TLFA=esa541L3_`QNhk}K5e!!~?4 zz{+$mFTkqu7xC?ge8A9lFQq=7dVILI7NnnX^uhBXAV0^vP3@fNP^Erio#fg%jlH|z zgZMf2Qs9@W{L|R0*N2#V$ncpq0IMoL53x5kAJ+HQOw6^M+L(WeeqwJ;Yj3DNY=;l_ z)-oL`jW0*=mDqeBC)yF~HPO#V`r!F6*5~JR6XMQm`vF8EymH33%`x@-Uct9f#ABYdR z)W8`u_#`k=_z++(@FtI=@Zq)jnZ@VjMt@1b&2Iod=PySyUu*EY|1h%^eK;Ez^~<@L`7D5J+Hi ziH-iU2_H2dU~ip16!-w_bN-^o2b^h4lFfQj@Rzf30(`(P#<{qBSYAqwQ|T`Se3q9D z=uBrJdmg!bBj+!`hx!Tsn>XNj_4=?IK8O}v8Vx&!4};%cKR5YHe~yDjo8!eMKG@u> zB;UyEgY}mHK4ktfNow^I{sOsP_JBRtsa8Mp`Vff^-d~cD3ZJIa&*^4+-^%OfmiiFN z2hkJ6l*IUDd3>?@8JiD)QsQC_AKn>Sd_+%>pKIfbu{VxBcs?MKK7gC0SZ~a)B%bE| zrJIVLzzD2gE!*tsHTF^;3Ve7&YWiF~lFP3)@j;8v!sIx|3VcHBjm-zq&ot*RHTZ~ra-9O~ z4dsKx7tBe+hYTN^pV#;c^>a6Tm|sYIQSialv!b6h{*vXNar7aS4_SV0>otYHY{iF> zt>0_(A(RiS*FZI?Gqw5&J(m3(NXxvTuvhdGIaLfkWcj%cALgGS_WJw^`#J9-XKK~x z!!~><)b9#^5q*fr2Mn#|gU83!?=|>j`Wc%KHb2+cQX`U(2W{@%XuLG;A!Z>aTC z7cbWKbKvyw=hFNtlnCn5G``VfZ?f)91j)w4DDtkv%ddqeeMJA7>YUgIxP zzem&u@*#G9ZuB!U9|H1o(GyqCD)e(JKDhe5MjtYN(ec6O8%Qc2OzZ2ltbVuqy*2jk zf)C;^3Vhfr{N4{X_6kRD&0##^LQxwx^a>d}aOe-1OW*@Icdiygl5w)BSBNhTv!8?O zZQh$I_6k`uyI$BFbK-sv6soLOXlo732_MVVp0-!GT*w%?USY{z&3dm83fBn@$tO?Ek2WcFJO{pv9g2@EB5AcY4u*N8lOThpwLU*jE~*x9@;p! zkq-rX3wyZ=KID5t3ViZ=oAb^7QrauT`qlEG*bCdJ4+TDq3%$b4{_=|Wh`8W^&ylGYx%iCPeSYs)rU|%gyOT7e=6*~(ND#-D2R(vzbo|QMnBEo zC31=4{^zE8?V97ujef4~hv)aZHq>ho;>(SGmh=m5^3TQbjec&v7XZ1u?04PdpIhT| z>-P74@O!^|(<@|s_yAjAYrTLC_Z4!V>=?)X0Qn6+2kkEHjc(HmbGc<=&oj*RJ_@z@ z7QNJ)Ug7Fq&8zi}Z+e9*xzkOra1OV<=@rf)kPxe0VXyn9SIF1_eOFwUsOx>K?bQHv z)Y6sri6CA{oRi!M>qNfVm{VVSBIa>j?HIVmr)IAkVDst!-v6 z0=AdN(@nL;HRH3k*S!aP2*szcSMvq)VQp^{|d_w=QZm?C?B@*mwnpEtcic@Cj{j@FHSesO#Vy*BCZvwpHy_|~^K_6pOt=2PzXuIz2feT5%! zpAj(|&mg^2JcD%knY(YOmAr4S>n?i+>4LfR`|p`^;~AtMxcg#e*mHFEkF`e%?5pYHqq`-9FV-M6!OZ@_1XXS7Z{K3T6YE$NLG z?PV{Fm~h_r&6=$60hm2rQ<~#ouzjMD6&o56$ z9J_;lae^0)vDU*`UK@oE*)ulJRD8&u+3W8kD|@D#_{+rk3-`JmA2#1NXZV0MTf&F4 z`wDS;@w?@G*l=Ir=4X%s>Y!(k0y6qbhR?M68KhjBfk3}2#+Sk~dqeEauItw6gX6<*;~|wAK4g0}iOOGcdo?A`AbkZs z6ncea<?{p?DqdC9#K3t@KiJ`ic97e6J9hOT9kiuT$OhjN<>yeDAi?2YVlxnh*I} z1A7Y8uw(cFdxuy)z5tISi^_2pXc^A%br1+ z>8I-z0(-8L)?V=!_lyqM4oqe}v(^~t)%f82rInOjtCo*1t^9r28|{6IYja}b#g6!3 z@F{x+X%QdlXGA_oz5ytO$2Iwe@)@K#J+b~`?2V%jo)3tm53rQ!S}&l;hfF`qoxHe`D_nQ_@T6WJ3VcA_Q|B-5&S5AHYS5?F_BKoOb7J)Y_F#Uw zYj2A7QXdL@Sl_!_^OqJT)5g3do@((~ls$uVT|YzYjm-zq&ot*RHTbk3n!<+wdqepk z@db0z@FBye?3r>!e_{T)8$OghV{n}huAb$d3VB!MFIoN>M;}7@!2DDE1@*huU$)}I zXc&bL)K5??tJh#em7e(gGgu$u@FC03b@;5+?=|-N{L0m9HTtj(A0ANmT|TCWFQN|- z`GBF-eDL_V`n?99Oh04uq3juh#dw<2PgAee-kuSy_r75;e*dVQ3**sTZ50+Pxl=niu@{6AGX71Y3g@P{uxmp$cNbZ zxzW$adOKD<%Ehcj^Ml75!+mk%raEfX|2d z%NfUDe0gJ}viD;bPYe3+!_MNlXb8thALsn#vBYG=(}KU0;{)JMr)&8}Ek0`f%-Or< zFNlA{wf#}fUp^wp%r`dZC-T1@-tByx<3lMv$T!}1`Nk?f=|J=o<25i|e?B$#qO%K{ zU{2Ied8Unx7t`MoK4829Ob^ExK3w3#o)7Xd%ZCeveqPY_OXeO(zl0Cf_{>av5qvHM zAI#h3SKtHe9aww+mqivY9uu>4Gar!ebByji`htz8!iVu{{%P>|Go@_gWm(q7=SYOlmoTzT?k&fDjoviO)c^NmVA=l*mr@{QLFKL2|IZh^W6|8iY{&u11N*eL#jFKk-lLr1ti>YS4glGne1 zm#`|}!$;r)#j*a4f^Tu$@>e=gE8*C{&+)tslX>e>}YM| zgSFT3A!l!IqrWgOq<&g|fsMfI#lac$bECh!G3w;~C6CX=3O=GIA6k6!`6u)f_|X3v zvQAb%oxRNs`T%=N{Uyoy3&w*l82t>z=WLUnl;e}jKXdxI+1}WExI=t2`f2f5$v<=Y zP;T!jsIjgO*TaWUe46l=5PO|Itm|imzXb9j1fN6bNv<9-`PDV*Lnt4%!6(FC(a!*V z2<5|8`nguWpHcgY@sx7N{0i|RmtTG1{v!IB)$h6dswAEU>ccjC2*u|{Kbddb=%>#& z0^-Y!e!6<(i^(@6|Gd#pQ?HffpONvo(a#(GY|ojX*m_N=pSNzm`Te)-_Z9vG_i4Po zMD2;6JCihJjmsRUhku8QIVxw_w@g#K-^B0l&Zpx$IG8Vd6^G&&*2ivd^P+*zVGLAq z%f)x``@6W0jAL-Tdy8{ZSL1E-xzQ!(k3;2iyl)OE@YMmvJ;e`BA^Si$riEj;S2O6~ zd>C$ajQ1bn_x}IjDJnb5M4smYIJ4sVnr#gGd2abIQ(=+p~=L6^c)kiu$ zczouMxb`Z1LhOyr2jVjr3O;sStMN%-r0^lY-k5yw_>5kt{N)JTNn!Io@!`Pui}<<5 zUxde4G~#;Q`Vh(o>ZkY%y7!<_t)7rOp?nZsd!f^ZP(Eb(IeMYh&+YVK+5l84eF)`4 z2tJ2SKf5}6WAlOf$)9f^UTN_Ou{Sm!h!5v|XPgA;XJkGspQ_?%hR^b;Mo*65<6{_+Ux~jc^NR3RPK3mZP<;sD1NHMqGH+`FK`#GWYT5LW5O7bB}eopR~co9b*JRg+%IX=E9>)9rJ1tvt@ z-wWk~=!tTF;}E$9mRG&syNmkW=%>D(4Y4;iAAJ6aKp=iuQ_p(+#O*4e(HFj-li{PU z-(%{-F6uS2PWt-Y_=|qOi|eZ0&++kPs;g(|D_iM9r2QPPpCGo$YwG()qMv)TpJV1- zzrS(o_P74{TiN#&c3*#L_U;;IUDlrLm-QLj$QP{BV>9l@&$#!)_p#RJY*Zaj(HrWU zULcP#Iv``-mS)Ga&PoDAWj49 z#k`~O0kQHC!5}{G8GNLsDZ}TtU}TWJvH9@G_SWBdX=|}(Q!IyYJ>B3hM~g@18Kir} zhX>#z{AGIA_)E2(fIIudhu;9!#QS)9X8fglA~6RqZPb$%HVNr}dVP>sUzJ4$I%k|gqMSU=PcMz4YnYh>iIji_kU%waqrM`YI z+8e45jcc#h*74aVJ_OhAz(;($bU$a^UQnQ-elO}nC?D$gH&*pi@=tZV*aaU#@Tsrg zi}pevYW8!A{u0cGE$X!pd&Buqx1UqQCp13~uixwT_g4JnQQUg1xeTk{cfkkfiMpOW z1U}GD)+0mFq2=m+Z!um(uiu0BH}lc2p?VxuiqQh`@OHG57Fzj zMri#Ww!as@et&45L8{&Fg}vhEds4su=SDv(_Ir!*bQgTk;&bcv{Wt&6KZ7*8uMiNY z{R?a&LkN1fmR0l>7p^$3`S!z`28j3jae*bJ($v2nD4g17-4pQOO2j1!5z`QV0}QZ zP^k~0dKE?ahTrl%Vf}A#@cV-<)6J19B~aLLau_gT$9h?8y#r9{hp1ROVwwKXvhf`e1W2 zb-p3^DEW~23wnhLe1Ne$!?}ZbY3&t%iNpu5pCERSezG^Juy+@HF!<>5^TRoEZ(z@L z(AXQQ599-&WNsanf6fB+Gd3Rr@^j-ax_XV+gvN_deF)(Le&!`y*@Q>PE1e4v()6Cw3%s6O+@&e9-6TFqipQ|WMPo*tW(8kB{q}!FGpz89pKQX0ad+A0$=+4A>@n z-F5gR0D_qK+Dc(B@Q%iZ3?G|IfE$=zslOcI{dCXxP>3DVdVc}GfarekVYSvEH>&)F z?}zdM<7K@<*bWLR^i#)&oPL^G1KhwIEAg%To9n8KFCq4Z>O&|We63+~OL7DJ9suKw@g>3g^a0pwYK>TYaJeOMRr!mp zHNXu_uTnoTp6?an*h+hM!3WV3*DHip0DIto9p(tom^&t`;?tl*%ntG!07tzm2u2-nA*Z7N0AIOLP9D`y`VfffyVU3pOr>L;kCuixP>V((0uZ^Pc0 zeDMCF#E1GBVz2OF6i}~i!H2MVt!18Tp|m&CPn|wUJcWZb;KRH&zAm16d~C0f+<@Kz zh0Xh2nSRF6hl~%({2Y8RdSZKp@CDdVUcbBi^FkLdw$X=BK1h6Vy+XteU|+hwk?H4t z@FBxTSu{^ix~E!`_&D$neqCYm$FP)Q4TvYm#4S>-Ru?@O+pg zf%>Vh-?!pJ?0OAJrKVoX>UYyCtcw@B;DhL=0w44W|MZXk_|^{(#s|N_&t!XdDfeU( z8!Nxdc!FnKG7ieVGoM9*_oY|Jz<7+;am@Fu?cBndA53Il7ysh>3h@Ts&-Dr~xTp4> z{Ty;%v)}nXKG%RgJmiUry}}C|Gic8x7F_i3?(bku_!|1f@u$8CmGugtNj#>5V=&G+ zhx;cOn>MtcV+>4&?`M0P17jPG!Fm2IY{S#@mJ8wK74j?m&M}&JA4AaI6hqY7%eoxn zE!!6|@1HhsPK*s@HJH7N`SJZ9b27zVA&*hv^8oWo&Ae;zIh@A=~S21?s0fUsz?Y_&IWX@UB)LLiv#C zC$A&%I#jABO>k#BeUR^|Rp~=0A42dsgq9591He*cZ>TO5=;yPY_6B?=JWt^PWjuROt!k4NGx!2F}{_w%9>$zG_LhOyr2kIxNMt@Q13H>(IUgIx% zK7hwyb8x*jwCAaeFHOXs1UAFou=+hfAFQ800#qu0xex4Nt|~vLenR)BEdZpk*Xt(` z1+KOF5Xy%v|9qsb-|f85!6lVGkPqDfdW91ow@dRY?=Sd(79V2YP}Z{vxPy5w+k3(X zpPwu7IRbY=?DhH8Bb`2M!w2pYb}%o%s`8iEd;pZ{{Tz>v`TnWee2m<&JdUCdo)7-} z3ajI3<}dF1$g1=6CVT}ZEROex58~(M`wDCIh}(z9is|=%@Lh1LFY1n$J<13A%-n4e>vpt$b)3ajl6 z)d$aqu|7W+J(-RZ_@zoex8j5OzQS642<3yrCjqgAchE=hyL5k}iT91Y4OPBPF2v@8 znRk6Xd+YY^e&>Gn4AOkBu=(~=>1oXv+pvz(({gwedW8T$?ju`VoCBv{^B72ii?{N} z>v#iWe2V{Uto+5a+kDBK{cCP)_y_Y%`P|pdAXf(%i@&DJ#V-OC1uW&NOUg6KuQRfoJZ2Z2$JU(w?92Pz; zd;qpp;&TYQW_>5lk8;`mv&NJm=am`ZLX6Bmt z%Msph;`M#v!)w6j9_KxH*#~E8{YCh-Cw$0ijRQE?jC%5v*kcJc`U}@1ln=6&FZ%NX ztZ3VQr?eeI)*6_t>!*?r)Xxrn;KwgcL4U^?!5Buk^Q8El^Ju~@8W*k)(*rE;tbuPf za$|GeL!6tKFFJkh6@#Tm3VdBsmcbgrp zexlOQ#0zpEHXj6^g}$B*vDfKCEItq$P;Kw(ch0GI#=7U?oO)+`ZoMAy_}tX*)$vrR z521Wud||u_sb}q4s^W#uKO@#_pqjd#rGARNzu1rcoKSp@psykJk`MI1@On+ZpA%ZI zN$wbt4xB6WdFLuEPEk3ty|Ni&C_5EA_UGcuck6C+;-p2kT*O9f5(O2weoJm>t-0j^- zZuxhe#R1~kaB=bfa4mUmTy~Bzx}*R85&!s)FPg1C;~2SK;l-4%ADcGBw1u1a+H>>@ z|Ec-hLmA{hzBs_g`D==v7A{&~uW*7X&3li!I4kyh@WwITAN2n}?it%&;Tc}=`%q`J z!R*8MT4T(~^e{71YdrdY5j&O-%y|lXS&hk`p9~WeDL^~`|N-Z&VxC2EAR=i*Te!$CK4Ycmskou>=oAf zOM*ofJ_Oj?15d%hD17kvV1a-=&jY_K_m?BQKQi|24Ilix2cjpn{(^Pd8$L*_@psgd z7UxYpxujo~`3v56y+Sn~#Lvxrh1Aa$mbYF%m3+wb6Y~bF&=Z}0;#gy^Rv)GhKA%H&h=&`QYOVl(TR0jad)t2X06Y z*kbJSjZ8ly^TFI#NPijY`~^KuIH&MVqn|j|*lX_3E3Y<{P4) z0s8PR^9|_MDOR*jA42(%;WO^y{>9pSjPuCWX~F!HI#g+|_)8={IDbKIYx6O=f6@0+ zSM#yv(&e8zd$-YtP(B!Zbou$=9N$m36(16nK9CQ|-))hfpG#e#%Fm6xavi4EhkxY6fM2p{CWLY+Psd=}^0dhJKd$1txRVn7`}N5Dt&&+-27LGW4dzCv9+8)C21 zhgO;f)@wRG&|lL3ZJYXCZ*M3c7++wnz0T|cxR%!=9-r=D_y8_~kJaX%vGu|5Vg5*4 zzu$NB4yxbxgAZAJk^2f&_4_t_!1B854$rQW57f^zpq@>@MXBEd;zdk8`21Xn5A`#| zUY}n*3a!`le86?bM)#HVnyKI8@nL{Xxd!Hh^B^J_9U20+7XDbRM?5~}zQU0DJ&Hbf zKH$C~+R(wgb^gL$p-w+#e{YZYAbMi%v#Z_TIGnrsT^BE?4>9?W>F2be-QNhYH#Q%9 z{s}|+l7Cj$vtB>Zp4QqMst?=Yqsz~!pRxH6J3lw|dmMf6d>HHVbJ3IOIMLScTk*l% zSLo}t+Wt{My~ch@0%8mA%sxSBz1D=D7<=Wu!rFL2eTdBmGw)(Oy9u9LxBu{;|Ka_@ zGe|E`Lo!x2jqk6-$|>T><>Fb=eV=&nKC)T&w`||b_5yisgjgGI@yB3!`8_<*b7>j?iBB)%LT8u=31LxAx_aj_l_qzMrA!P zW3X2^HonktxuqP#Ii;8}#z38X_7^-)4`ZO#I2+F7{2g;lzSgk$$ZY-zH}Cm=6TLM) zqx{&+TY8^-o#Qp|A22D{i?zONr8wtPw-;fLG4nRIy7YO8g7;rka&!v`A+6nr2)=d!MPeCFp|*Q^&%flr9NvH3uJ_%K|% z_UpMN=#cl91pXp?2(ULMA2NJi_Iu!O2Yy5%lGB^~pw?gD<5oZCYJCv>#5WLV^dXcF)X$F5&zFWX_4>)aeYieMA8GX=ln){JP(MTL zjm-zfmjlKZ#2qa@A@;`RgWx0a<&G-8WcnGI56c&U{<3_b)lZ}n^9FhgeQ=3d%g@30 z&0Yj`cQwBX(1&gKAo1me=zf5H>f#0UVeod&wq>&Z+Dbe~H8g zpMS!TApM-`?A-+)3_iO2ocbA?53%#}o$vvbhK3KBzv${U>Ss;7_>}qST0Ih=4^mC$%7u1Jq=EG)u7W#TN#9prtk@z6``CIyWHp@Rt?S0<3j{3c6;$jDJ zv8o=)@EQGmso&S|38`nPpP}`;@fV#wgz|y$CA6Nc(Ferj-RePbHzpr4e+j7HBkIF0>b1V)+xq%FL?1jK0`haw z6J_sQC3zf<}yUuU6Q{Jugw zv*Ki>7iQ`Ro_o_XNWWux2xl0__CCx$70<(yavrEP?05U(p7dX`Ka$_e%IX!A&#qTE zM}9zi)8XGd+q}1r_np01YyS+=lb7s;+4~C37^YW}8ogX#`b&o)hwH#L4w}d35Vpf~WaG`{Pw+jD_}oPc2leqfk9D7O_QLn&8Kezf zD*abaHt%in7&8WY$JsM0uGssq_YL6~jA44IIA#qWK9ln=O|R6=h4YrVV(dIVA@(8` zOk_OVI39x!#7FK)r)|&A{@h{c=6wnqfU(CXf$hXwp4plYX%?ON4EZb2Y_36m-m-_;)C}WJi}!8p7aVYiM^Y* z%oTq)f8lzB@O&|W7+((X)5ads=*5)^pAdUv^MUw~ zj}1hQ_nu3>F(YS&hEsmO+{Kp!2h#^&FP}-PvUe*!@EN3c#b3sppW`u3U5KX{K6r*n za#y9FVlNi0FZNzuRoS}>K8S622I*b7Hp$*sXfS5~d9!{h;|29Wo;iu}PCsqkO)(zV zuMa;WmJU~^521X>@WC@VMNbs@C$R5eUMM?M`IY!fBtE$OGl3zel8?=vRpHYFe#GsV z&umfHyNy1C^1R&kwQgvH3tw97oL0cfp5{{2b=OM|JgDf`dcjMNB?WKjoR6 zm=~^DI5B=%UauX&Z^d3^ydW21^TBACzMc)S*XctnJ`fv}f)dk)dsM%3PT&J{`r--o z&iLF-{Z9QH!Uy(+4~#D+AJfvvF1UC&ZK#ok{`C;PCU6N(S@GsIr% z1N|?&Ueog-G(Ydd2k;2Vz1Yw3_(ZJV--Nj-II7v-^Lz-%&pXtU==FO%K8T(u_csom ze)1Wliv8YQ)bB<=_4RCsy|MY=>osLP>-95s{jTIghL65}583Yx)rVcwYoec#^uhBX zAU~J*qO51>E1~g1{AKUzcin#PF8H9u2fe~See?UKSNLE$xrepBKx#0*Gf7j!sg>^! zI?H+=Z_lSchcA4VB9MI*@oZ>f&Lz*yF&g*}&#ja{zKeg~UCjSot2_FDPZe88`ZubO8R z@E9FFb9rV3*WR6{6rT`#WAlOd3;+i3aedHAd=mHzar;Jqy~H~fA3Q$UcimR{%MsRn z-}u0L(t*#EywmuL@ED6mTsyeVlAk-B8XtO9eF)_P^^@oSs(FS0&ZtPk?t-zt3woRPe=Sj^?N)%h@L3-Hx3bBu)L^8bn#*r^}EqeeLWju zuh)l2eDL`v0s;LJpi)3TPdtNkw6xb~n9r5&_lD}jcKE34_p_M#z<7$E zsQEe9DUHpCaiZcwrk}cc7M%KgD?aG=bGED3Ky30Zg+7w^))&_DbFZJuc(DsUh`%WC zVXyF?ecRqwcoxp??gjMSJf*l;G^iBIebFwjm?LUT!Q!{ zuGR>!m$4Uno3*{;ZTR5vQN#}V%Mo$_=%K2%+7%zPvBTjbIzEV_521X>Vx>I4n)y}f zUUyMH^?Z;RrpToW`l;lD-|JTN&YXU3rw{eHrPGH{K7`=o^;2nYY(9kK5)Pjbdqedh zln=xQ;X>6bEb3=uJ}7dhqQBJF8csjOUM!sGP(^K3&`(8f>EbDdR@EAg4-#J#y~2Wi z2IzyfH{|k-5I$u3Szl{-{RBXWr&H?CamBS*&R+4CNPO`Ag2cd_r@YoE=;u^tFHBX} zp4;+)^TuA*IrH3h#kFcS|7^wP1E5s(3Z1`%=I6%V`d*>chZg-DeZHskvra|t!`36E zy`j}!VZmP}X{yl^V59C8?t%}9FD-5F%<8AQSLpOJHXlSk6}>{ICn5HR^a{7(1NAda z#b3HZXd-+;nSb*83ibM_)d%uH`~`Cg@|W(QwpZx%b2og@=jYm9fYVQ|Q-Vd)#0#Ha zDfJl&^_sd@===p#Q`fWLj=9$Ny#Cs6XRpzRID81j=P008 z==2lI8+AV?v|bZ^h{y*Ft?CsP@KNUH@D+8h(8Y@oeeitH=jZBPq0`TOg(AMdt>v##}@4WFPI8pIooBDk#KIrTB?dr7zTnGKrie6zsKb7%f7km(ZQQ*T~ z;kSO*KZ7*rzCv&=tXCL#Um>I>s8_x29_l~#VLr^XOd=gh{1lY^ii@nYI zUZM4ut?<#r4&Z}WsqYo;h!5)6Vew(CguB=8MeKkNS*%p_3JdzF=L2Iws>r1a`l;kY zrl0lKC1M_Ot;KfwpvWz)K7{fi1Rt-TnqHyRPf$%)d*=N`lS^3rL_VSG4Ox6b?DhH? zi4Q@!WkEk9^Ffh275zm~Ygqk6c%0wS)K)v=93=)S=_5UST2stnUqN!w0XQiK5oX>*rKwFHF_<3iJ7A03WC)nqC0$fqv?H zgZ?=RiI z-}O82(cV{R_PW!wes5|Ad|-TmuIqY*1^ukQwuJG*^I@Q_*Yv$Yiw~%#-rswAS(Ke?Y1%m;mb zuJ0AXUz*qtgu6%G-wWk~PklWbVz1YSNPO`1I}Fk0 zpC(@D?TyKY3?FsvU(5&H;b#zVpxmDOdVTbe28@<}eSrV? zt6c+r-_{4C&$DN2;utx%{l3C~58t=FAzN!)VNd8JdxiQv#7Th61tRgUWjea8y`SZ@q2gl*kHDx?W31J z#$<4cziQw={)(~B@B;9e+^xgs0ftL4FZ+FDlPY`;=kEIs9Jl*b_I5Kq$g@GohfUwF zRNw;*IX;uz65mi{&V!dW^1V$8Ccui!!`Bpn4wu$rym}l1Y@*tP&>e0d(IU;2#<-G;A;Kl>HyQ+3Ljhq zY0mSk%3nrDu*;s4&x+j(J~Ygl*zel{XFe03+N39f59W2r zZuhsIjBPy4`HS%3jg{~N|d9#fWYBp8F^wXy8@mG++0 z*^6U}d{~e(X-*&BaQTMlgRyN!+mLTO5sfwTcKxMI_{jB?z-PYU`;{_$j&N?wd)~m{ znD@VdyI0z~3qFW#GqLUJ_=$_T<@gx9C0?lb;GVPolj($f5YAi|A2NL8dlum@qsLso z%KQ@tVV&IfWm9**C_ec7Gr^28?>ExNmH6cHPo2Gi`tVoul>k2c^#QOp{v!87n*1DV zEMpL3ko`E*lYf6WpH2e!kkunfeaQGQNwLP{gN>(o{k-(`h{xwb^7Fru{2X&E=I35N z1s`LtN*}U%#Psm$^uhC?g@Oa;fxjR>hYcnElHoIvdJXznU9Tlr502MH?gr_pix<)P z!2JAe!F##*4ze<=Syg;FIl}ue0pD+{ix)aREMJKahU*ucx2b0_$CCIW{t{xZ&#xl! zf%sr(_$YM0U*<0vKIBfQz2GsTtxg}vhdzEdC!A-{!5=tfS-z3^i>cq?FR0(~fiiz- zf;$`!_EzXaX74uoVDQQ1=QVtIVDQQ6cg)d_A-1pT=aA#=2_HN@rk;hKpnk{t)$3;% zA8frg=x{&h8u{S!PjC(MrheM}jgR2N>-l+tbMy7~g+5-y6F%tbwVZyc z>a{HY+#^1mP7z=7`x_elRK|;y`u*DZkm;wYp3U-4rM+GsBJsiNCx|Wjc~b2!UOy4S z;97O{yVx754#WGvH1|3pX=&b>gQH`SjMf_!t3`I_Z_Z# zfA1CQwR(JR-G1xaZ~e)}USZmQhF(DGe4q7?&z;C0$*{K?qf!5FMvFb|29Fi~oa;o{k+E&NesulN0Pd>1x* zVP~SL0?@I+OmO`QCWB$KwU+D99;@)Vk8x7qjd}lN9X^M1*DFky*t@H>m$86jHzc=w zqT&M$Ies+h0yjNAybkTL4xbQveJmKn;e+H7L(la;uk#ns#qQPU?IksUhS$Y@rXl4y~`!&rm*u;N$gE?klXfH&h=&`M~(X zpSC>v?@EPFh`piu5XuK%YmAeTTx$Vwq23MQ&*Zwy6`XPTMgs2eb=Vu154_ImE_#J( zf8lkBcUAfc6Xp#pTA$ZiU~{v|-d*s4=kMS?GTEz9jhZ8sUF>rFWujQW^AC&m;K9TzT{16zg@ZqA$ z-fj4h2tG{lB|op^1F_-x+vh$%uf<2!DUv=oKD1JwpX>0Mq^@48^cP~YPkdl};eB>k z0_y(BJ#d}B8;ngY2JZTL?FjGVZS)F#yr{I7`bnFQWr#R@z`UU+zMif1mk@hn^MUxJ zso+B`_$BhsN`Gl#aYF62YpK!)mv3-RJP-J=;o6&w4<4WHz}4@S{?Y_@64)G{558Wj z%Q^f;EZ}=_kQ6= zL+ev*5FBu?=?U*ki=_{te2`j${$lP)uho+lv?7!bfT4R2xg|bZs}G@k$n;a5L0YRP z)X(koL7rKm(uYt!gy7@#Q);V8t-Z1NK>chmzDRDVi!UMe#^wX@88N<$6H{xb^)oUb zm|F(nJwa~>R8r*|qMxJxOBFAu4-aR| zuOu&2`3vxQuH{39&o~(>@-eLGvImfCym+C`KR>@-J}|>1ADn*v7YXqBWKxTd*UzcW z-dE(q|Ek7EnV%od(JS1{hYztdmQz{29jXuHL+t!q^z)kaVU-Ud`MKx`sH4#n&}37kn`Jm^_nHrJo`8I(>-62jY`{ZU5@` zd#TfcYCd>;x;OQErG6^)A(Rh{FQN5ps6NE5*V120{cfL=qpaW0_hUcD=jQ`6@0VO>CtjUzF#jC&CjbBd From f0d9f2deb0c7ddfbfc4360dea4d687c5b41046a4 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Mon, 28 Oct 2024 16:09:07 +0000 Subject: [PATCH 115/116] [maven-release-plugin] prepare release v2.12.44 --- examples/pom.xml | 6 +++++- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 20 insertions(+), 16 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index b968607eb1..d73e14bf52 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.44-SNAPSHOT + 2.12.44 jar Strata-Examples Example code to demonstrate use of Strata @@ -272,4 +272,8 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> + + + v2.12.44 + diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index 0e84c7ab2a..f7daff8fd8 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.44-SNAPSHOT + 2.12.44 .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 2d73016809..78d102bc92 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.44-SNAPSHOT + 2.12.44 .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 66951bea44..65654da503 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.44-SNAPSHOT + 2.12.44 .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index 8365ff3e38..e53684e9bc 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.44-SNAPSHOT + 2.12.44 .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index e0aab3eb48..1f8cc9940f 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.44-SNAPSHOT + 2.12.44 .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 31055089ac..7573e4fb13 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.44-SNAPSHOT + 2.12.44 .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index 608c0b2bdd..aac4537fcf 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.44-SNAPSHOT + 2.12.44 .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index d4721fa8e6..443ac8045e 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.44-SNAPSHOT + 2.12.44 .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index b93dddd2d5..5dd94b3cb7 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.44-SNAPSHOT + 2.12.44 pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.44 diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 1a71a31ad0..52471bbda7 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.44-SNAPSHOT + 2.12.44 .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 3b4e1150cd..4fda21b11b 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.44-SNAPSHOT + 2.12.44 .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index d1b2cd2a47..86e23af80e 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.44-SNAPSHOT + 2.12.44 .. strata-report diff --git a/pom.xml b/pom.xml index 836e807683..78f49120a4 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.44-SNAPSHOT + 2.12.44 pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - HEAD + v2.12.44 From 9cc7256e88488e10e7211b07ee3b482cd9e05dd9 Mon Sep 17 00:00:00 2001 From: opengammacibot Date: Mon, 28 Oct 2024 16:09:09 +0000 Subject: [PATCH 116/116] [maven-release-plugin] prepare for next development iteration --- examples/pom.xml | 6 +----- modules/basics/pom.xml | 2 +- modules/calc/pom.xml | 2 +- modules/collect/pom.xml | 2 +- modules/data/pom.xml | 2 +- modules/loader/pom.xml | 2 +- modules/market/pom.xml | 2 +- modules/math/pom.xml | 2 +- modules/measure/pom.xml | 2 +- modules/pom.xml | 4 ++-- modules/pricer/pom.xml | 2 +- modules/product/pom.xml | 2 +- modules/report/pom.xml | 2 +- pom.xml | 4 ++-- 14 files changed, 16 insertions(+), 20 deletions(-) diff --git a/examples/pom.xml b/examples/pom.xml index d73e14bf52..bc2cb9f54b 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-examples - 2.12.44 + 2.12.45-SNAPSHOT jar Strata-Examples Example code to demonstrate use of Strata @@ -272,8 +272,4 @@ OpenGamma Strata Examples OpenGamma Strata Examples]]> - - - v2.12.44 - diff --git a/modules/basics/pom.xml b/modules/basics/pom.xml index f7daff8fd8..6943914c0b 100644 --- a/modules/basics/pom.xml +++ b/modules/basics/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.44 + 2.12.45-SNAPSHOT .. strata-basics diff --git a/modules/calc/pom.xml b/modules/calc/pom.xml index 78d102bc92..889f95b5dc 100644 --- a/modules/calc/pom.xml +++ b/modules/calc/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.44 + 2.12.45-SNAPSHOT .. strata-calc diff --git a/modules/collect/pom.xml b/modules/collect/pom.xml index 65654da503..404ae8ea25 100644 --- a/modules/collect/pom.xml +++ b/modules/collect/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.44 + 2.12.45-SNAPSHOT .. strata-collect diff --git a/modules/data/pom.xml b/modules/data/pom.xml index e53684e9bc..25ce33b9bb 100644 --- a/modules/data/pom.xml +++ b/modules/data/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.44 + 2.12.45-SNAPSHOT .. strata-data diff --git a/modules/loader/pom.xml b/modules/loader/pom.xml index 1f8cc9940f..e2b1ccca95 100644 --- a/modules/loader/pom.xml +++ b/modules/loader/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.44 + 2.12.45-SNAPSHOT .. strata-loader diff --git a/modules/market/pom.xml b/modules/market/pom.xml index 7573e4fb13..9be4f8726c 100644 --- a/modules/market/pom.xml +++ b/modules/market/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.44 + 2.12.45-SNAPSHOT .. strata-market diff --git a/modules/math/pom.xml b/modules/math/pom.xml index aac4537fcf..0b1f5a2fee 100644 --- a/modules/math/pom.xml +++ b/modules/math/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.44 + 2.12.45-SNAPSHOT .. strata-math diff --git a/modules/measure/pom.xml b/modules/measure/pom.xml index 443ac8045e..2a6b44e568 100644 --- a/modules/measure/pom.xml +++ b/modules/measure/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.44 + 2.12.45-SNAPSHOT .. strata-measure diff --git a/modules/pom.xml b/modules/pom.xml index 5dd94b3cb7..35776c8892 100644 --- a/modules/pom.xml +++ b/modules/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-parent - 2.12.44 + 2.12.45-SNAPSHOT pom Strata-Parent OpenGamma Strata Parent @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.44 + HEAD diff --git a/modules/pricer/pom.xml b/modules/pricer/pom.xml index 52471bbda7..957e9895cd 100644 --- a/modules/pricer/pom.xml +++ b/modules/pricer/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.44 + 2.12.45-SNAPSHOT .. strata-pricer diff --git a/modules/product/pom.xml b/modules/product/pom.xml index 4fda21b11b..660fce4cfe 100644 --- a/modules/product/pom.xml +++ b/modules/product/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.44 + 2.12.45-SNAPSHOT .. strata-product diff --git a/modules/report/pom.xml b/modules/report/pom.xml index 86e23af80e..5d5c5a7ab6 100644 --- a/modules/report/pom.xml +++ b/modules/report/pom.xml @@ -5,7 +5,7 @@ com.opengamma.strata strata-parent - 2.12.44 + 2.12.45-SNAPSHOT .. strata-report diff --git a/pom.xml b/pom.xml index 78f49120a4..1b6b05e7b2 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ com.opengamma.strata strata-root - 2.12.44 + 2.12.45-SNAPSHOT pom Strata-Root OpenGamma Strata root @@ -40,7 +40,7 @@ scm:git:https://github.com/OpenGamma/Strata.git scm:git:https://github.com/OpenGamma/Strata.git https://github.com/OpenGamma/Strata - v2.12.44 + HEAD