diff --git a/modules/basics/src/main/java/com/opengamma/strata/basics/date/MarketTenor.java b/modules/basics/src/main/java/com/opengamma/strata/basics/date/MarketTenor.java
index 84eebeff84..500313e2e0 100644
--- a/modules/basics/src/main/java/com/opengamma/strata/basics/date/MarketTenor.java
+++ b/modules/basics/src/main/java/com/opengamma/strata/basics/date/MarketTenor.java
@@ -108,6 +108,48 @@ public static MarketTenor ofSpot(Tenor tenor) {
return new MarketTenor(tenor.toString(), tenor, MARKET_CONVENTION_LAG);
}
+ /**
+ * Obtains an instance from a number of days from spot.
+ *
+ * A tenor of 1D will return SN.
+ * A tenor of 7D will return SW.
+ *
+ * @param days the tenor in days
+ * @return the tenor
+ */
+ public static MarketTenor ofSpotDays(int days) {
+ if (days == 1) {
+ return MarketTenor.SN;
+ }
+ if (days == 7) {
+ return MarketTenor.SW;
+ }
+ Tenor tenor = Tenor.ofDays(days);
+ return new MarketTenor(tenor.toString(), tenor, MARKET_CONVENTION_LAG);
+ }
+
+ /**
+ * Obtains an instance from a number of months from spot.
+ *
+ * @param months the tenor in months
+ * @return the tenor
+ */
+ public static MarketTenor ofSpotMonths(int months) {
+ Tenor tenor = Tenor.ofMonths(months);
+ return new MarketTenor(tenor.toString(), tenor, MARKET_CONVENTION_LAG);
+ }
+
+ /**
+ * Obtains an instance from a number of years from spot.
+ *
+ * @param years the tenor in years
+ * @return the tenor
+ */
+ public static MarketTenor ofSpotYears(int years) {
+ Tenor tenor = Tenor.ofYears(years);
+ return new MarketTenor(tenor.toString(), tenor, MARKET_CONVENTION_LAG);
+ }
+
//-------------------------------------------------------------------------
/**
* Parses a formatted string representing the market tenor.
diff --git a/modules/basics/src/test/java/com/opengamma/strata/basics/date/MarketTenorTest.java b/modules/basics/src/test/java/com/opengamma/strata/basics/date/MarketTenorTest.java
index 812422ff89..5b8cd7d915 100644
--- a/modules/basics/src/test/java/com/opengamma/strata/basics/date/MarketTenorTest.java
+++ b/modules/basics/src/test/java/com/opengamma/strata/basics/date/MarketTenorTest.java
@@ -93,6 +93,29 @@ public void test_ofSpot_special() {
assertThat(MarketTenor.ofSpot(TENOR_1D)).isEqualTo(MarketTenor.SN);
}
+ @Test
+ public void test_ofSpotDays() {
+ assertThat(MarketTenor.ofSpotDays(1).getCode()).isEqualTo("SN");
+ assertThat(MarketTenor.ofSpotDays(7).getCode()).isEqualTo("SW");
+ assertThat(MarketTenor.ofSpotDays(3).getCode()).isEqualTo("3D");
+ assertThat(MarketTenor.ofSpotDays(20).getCode()).isEqualTo("20D");
+ assertThatIllegalArgumentException().isThrownBy(() -> MarketTenor.ofSpotDays(-1));
+ }
+
+ @Test
+ public void test_ofSpotMonths() {
+ assertThat(MarketTenor.ofSpotMonths(3).getCode()).isEqualTo("3M");
+ assertThat(MarketTenor.ofSpotMonths(20).getCode()).isEqualTo("20M");
+ assertThatIllegalArgumentException().isThrownBy(() -> MarketTenor.ofSpotDays(-1));
+ }
+
+ @Test
+ public void test_ofSpotYears() {
+ assertThat(MarketTenor.ofSpotYears(3).getCode()).isEqualTo("3Y");
+ assertThat(MarketTenor.ofSpotYears(20).getCode()).isEqualTo("20Y");
+ assertThatIllegalArgumentException().isThrownBy(() -> MarketTenor.ofSpotYears(-1));
+ }
+
//-------------------------------------------------------------------------
@Test
public void test_parse_String_roundTrip() {
diff --git a/modules/loader/src/main/java/com/opengamma/strata/loader/LoaderUtils.java b/modules/loader/src/main/java/com/opengamma/strata/loader/LoaderUtils.java
index 883fd3f850..60277514ab 100644
--- a/modules/loader/src/main/java/com/opengamma/strata/loader/LoaderUtils.java
+++ b/modules/loader/src/main/java/com/opengamma/strata/loader/LoaderUtils.java
@@ -5,6 +5,7 @@
*/
package com.opengamma.strata.loader;
+import static com.opengamma.strata.collect.Guavate.tryCatchToOptional;
import static java.time.temporal.ChronoField.HOUR_OF_DAY;
import static java.time.temporal.ChronoField.MINUTE_OF_HOUR;
import static java.time.temporal.ChronoField.NANO_OF_SECOND;
@@ -34,6 +35,7 @@
import com.opengamma.strata.basics.currency.Currency;
import com.opengamma.strata.basics.date.BusinessDayConvention;
import com.opengamma.strata.basics.date.DayCount;
+import com.opengamma.strata.basics.date.MarketTenor;
import com.opengamma.strata.basics.date.Tenor;
import com.opengamma.strata.basics.index.FxIndex;
import com.opengamma.strata.basics.index.IborIndex;
@@ -262,7 +264,7 @@ public static BigDecimal parseBigDecimal(String str) {
}
/**
- * Parses a decimal from the input string, converting it from a percentage to a decimal values.
+ * Parses a decimal from the input string, converting it from a percentage to a decimal value.
*
* If input value is bracketed, it will be parsed as a negative decimal percent.
* For e.g. '(12.3456789)' will be parsed as a big decimal -0.123456789.
@@ -281,6 +283,27 @@ public static BigDecimal parseBigDecimalPercent(String str) {
}
}
+ /**
+ * Parses a decimal from the input string, converting it from a basis point to a decimal value.
+ *
+ * If input value is bracketed, it will be parsed as a negative decimal percent.
+ * For e.g. '(12.3456789)' will be parsed as a big decimal -0.00123456789.
+ *
+ * @param str the string to parse
+ * @return the parsed value
+ * @throws NumberFormatException if the string cannot be parsed
+ */
+ public static BigDecimal parseBigDecimalBasisPoint(String str) {
+ try {
+ return parseBigDecimal(str).movePointLeft(4);
+ } catch (NumberFormatException ex) {
+ NumberFormatException nfex =
+ new NumberFormatException("Unable to parse BigDecimal basis point from '" + str + "'");
+ nfex.initCause(ex);
+ throw nfex;
+ }
+ }
+
private static String normalize(String value) {
String normalizedValue = value.trim();
normalizedValue = normalizeIfBracketed(normalizedValue);
@@ -479,6 +502,50 @@ public static Period parsePeriod(String str) {
}
}
+ /**
+ * Tries to parse a period from the input string.
+ *
+ * @param str the string to parse, may be null
+ * @return the parsed period, empty if unable to parse
+ */
+ public static Optional tryParsePeriod(String str) {
+ if (str != null && str.length() >= 2) {
+ return tryCatchToOptional(() -> parsePeriod(str));
+ }
+ return Optional.empty();
+ }
+
+ //-------------------------------------------------------------------------
+ /**
+ * Parses a market tenor from the input string.
+ *
+ * @param str the string to parse
+ * @return the parsed value
+ * @throws IllegalArgumentException if the string cannot be parsed
+ */
+ public static MarketTenor parseMarketTenor(String str) {
+ try {
+ return MarketTenor.parse(str);
+
+ } catch (RuntimeException ex) {
+ throw new IllegalArgumentException("Unknown tenor format: " + str);
+ }
+ }
+
+ /**
+ * Tries to parse a market tenor from the input string.
+ *
+ * @param str the string to parse, may be null
+ * @return the parsed market tenor, empty if unable to parse
+ */
+ public static Optional tryParseMarketTenor(String str) {
+ if (str != null && str.length() >= 2) {
+ return tryCatchToOptional(() -> MarketTenor.parse(str));
+ }
+ return Optional.empty();
+ }
+
+ //-------------------------------------------------------------------------
/**
* Parses a tenor from the input string.
*
@@ -506,16 +573,13 @@ public static Tenor parseTenor(String str) {
* @return the parsed tenor, empty if unable to parse
*/
public static Optional tryParseTenor(String str) {
- if (str != null && str.length() > 1) {
- try {
- return Optional.of(Tenor.parse(str));
- } catch (RuntimeException ex) {
- // ignore
- }
+ if (str != null && str.length() >= 2) {
+ return tryCatchToOptional(() -> Tenor.parse(str));
}
return Optional.empty();
}
+ //-------------------------------------------------------------------------
/**
* Parses a frequency from the input string.
*
@@ -532,6 +596,19 @@ public static Frequency parseFrequency(String str) {
}
}
+ /**
+ * Tries to parse a frequency from the input string.
+ *
+ * @param str the string to parse, may be null
+ * @return the parsed frequency, empty if unable to parse
+ */
+ public static Optional tryParseFrequency(String str) {
+ if (str != null && !str.isEmpty()) {
+ return tryCatchToOptional(() -> Frequency.parse(str));
+ }
+ return Optional.empty();
+ }
+
//-------------------------------------------------------------------------
/**
* Parses currency from the input string.
@@ -561,11 +638,7 @@ public static Currency parseCurrency(String str) {
*/
public static Optional tryParseCurrency(String str) {
if (str != null && str.length() == 3 && CURRENCY_MATCHER.matchesAllOf(str)) {
- try {
- return Optional.of(Currency.parse(str));
- } catch (RuntimeException ex) {
- // ignore
- }
+ return tryCatchToOptional(() -> Currency.parse(str));
}
return Optional.empty();
}
diff --git a/modules/loader/src/test/java/com/opengamma/strata/loader/LoaderUtilsTest.java b/modules/loader/src/test/java/com/opengamma/strata/loader/LoaderUtilsTest.java
index 903e420f0c..dace7b3572 100644
--- a/modules/loader/src/test/java/com/opengamma/strata/loader/LoaderUtilsTest.java
+++ b/modules/loader/src/test/java/com/opengamma/strata/loader/LoaderUtilsTest.java
@@ -23,6 +23,7 @@
import org.junit.jupiter.api.Test;
import com.opengamma.strata.basics.currency.Currency;
+import com.opengamma.strata.basics.date.MarketTenor;
import com.opengamma.strata.basics.date.Tenor;
import com.opengamma.strata.basics.index.FxIndices;
import com.opengamma.strata.basics.index.IborIndices;
@@ -189,6 +190,21 @@ public void test_parseBigDecimalPercent() {
.withMessage("Unable to parse BigDecimal percentage from 'Rubbish'");
}
+ @Test
+ public void test_parseBigDecimalBasisPoint() {
+ assertThat(LoaderUtils.parseBigDecimalBasisPoint("1.2")).isEqualTo(BigDecimal.valueOf(0.00012d));
+ assertThat(LoaderUtils.parseBigDecimalBasisPoint("(1.2)")).isEqualTo(BigDecimal.valueOf(-0.00012d));
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> LoaderUtils.parseBigDecimalBasisPoint("()"))
+ .withMessage("Unable to parse BigDecimal basis point from '()'");
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> LoaderUtils.parseBigDecimalBasisPoint("(1.2(3)"))
+ .withMessage("Unable to parse BigDecimal basis point from '(1.2(3)'");
+ assertThatIllegalArgumentException()
+ .isThrownBy(() -> LoaderUtils.parseBigDecimalBasisPoint("Rubbish"))
+ .withMessage("Unable to parse BigDecimal basis point from 'Rubbish'");
+ }
+
//-------------------------------------------------------------------------
@Test
public void test_parseDate_formatter() {
@@ -264,6 +280,39 @@ public void test_parsePeriod() {
assertThatIllegalArgumentException().isThrownBy(() -> LoaderUtils.parsePeriod("2"));
}
+ @Test
+ public void test_tryParsePeriod() {
+ assertThat(LoaderUtils.tryParsePeriod("P2D")).hasValue(Period.ofDays(2));
+ assertThat(LoaderUtils.tryParsePeriod("2D")).hasValue(Period.ofDays(2));
+ assertThat(LoaderUtils.tryParsePeriod("2X")).isEmpty();
+ assertThat(LoaderUtils.tryParsePeriod("2")).isEmpty();
+ assertThat(LoaderUtils.tryParsePeriod("")).isEmpty();
+ assertThat(LoaderUtils.tryParsePeriod(null)).isEmpty();
+ }
+
+ //-------------------------------------------------------------------------
+ @Test
+ public void test_parseMarketTenor() {
+ assertThat(LoaderUtils.parseMarketTenor("P2D")).isEqualTo(MarketTenor.ofSpotDays(2));
+ assertThat(LoaderUtils.parseMarketTenor("2D")).isEqualTo(MarketTenor.ofSpotDays(2));
+ assertThat(LoaderUtils.parseMarketTenor("ON")).isEqualTo(MarketTenor.ON);
+ assertThat(LoaderUtils.parseMarketTenor("TN")).isEqualTo(MarketTenor.TN);
+ assertThatIllegalArgumentException().isThrownBy(() -> LoaderUtils.parseMarketTenor("2"));
+ }
+
+ @Test
+ public void test_tryParseMarketTenor() {
+ assertThat(LoaderUtils.tryParseMarketTenor("P2D")).hasValue(MarketTenor.ofSpotDays(2));
+ assertThat(LoaderUtils.tryParseMarketTenor("2D")).hasValue(MarketTenor.ofSpotDays(2));
+ assertThat(LoaderUtils.tryParseMarketTenor("ON")).hasValue(MarketTenor.ON);
+ assertThat(LoaderUtils.tryParseMarketTenor("TN")).hasValue(MarketTenor.TN);
+ assertThat(LoaderUtils.tryParseMarketTenor("2X")).isEmpty();
+ assertThat(LoaderUtils.tryParseMarketTenor("2")).isEmpty();
+ assertThat(LoaderUtils.tryParseMarketTenor("")).isEmpty();
+ assertThat(LoaderUtils.tryParseMarketTenor(null)).isEmpty();
+ }
+
+ //-------------------------------------------------------------------------
@Test
public void test_parseTenor() {
assertThat(LoaderUtils.parseTenor("P2D")).isEqualTo(Tenor.ofDays(2));
@@ -281,6 +330,7 @@ public void test_tryParseTenor() {
assertThat(LoaderUtils.tryParseTenor(null)).isEmpty();
}
+ //-------------------------------------------------------------------------
@Test
public void test_parseFrequency() {
assertThat(LoaderUtils.parseFrequency("P2D")).isEqualTo(Frequency.ofDays(2));
@@ -292,6 +342,20 @@ public void test_parseFrequency() {
assertThatIllegalArgumentException().isThrownBy(() -> LoaderUtils.parseFrequency("2"));
}
+ @Test
+ public void test_tryParseFrequency() {
+ assertThat(LoaderUtils.tryParseFrequency("P2D")).hasValue(Frequency.ofDays(2));
+ assertThat(LoaderUtils.tryParseFrequency("2D")).hasValue(Frequency.ofDays(2));
+ assertThat(LoaderUtils.tryParseFrequency("TERM")).hasValue(Frequency.TERM);
+ assertThat(LoaderUtils.tryParseFrequency("T")).hasValue(Frequency.TERM);
+ assertThat(LoaderUtils.tryParseFrequency("0T")).hasValue(Frequency.TERM);
+ assertThat(LoaderUtils.tryParseFrequency("1T")).hasValue(Frequency.TERM);
+ assertThat(LoaderUtils.tryParseFrequency("2X")).isEmpty();
+ assertThat(LoaderUtils.tryParseFrequency("2")).isEmpty();
+ assertThat(LoaderUtils.tryParseFrequency("")).isEmpty();
+ assertThat(LoaderUtils.tryParseFrequency(null)).isEmpty();
+ }
+
//-------------------------------------------------------------------------
@Test
public void test_parseCurrency() {