> ## Documentation Index
> Fetch the complete documentation index at: https://docs.activeviam.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Implementing a configurable maturity converter

export const productName = "Atoti FRTB";

{productName} allows developers to implement their own maturity
converters based on the IMaturityConverter interface. This page will
walk you through the process of implementing a converter than can be
configured in a properties file.

## The IMaturityConverter interface and the MaturityConverterConfig class

Any implementation of a maturity converter implements the **IMaturityConverter interface**.
These implementations must be autowirable through Spring, as well as usable as an extended plugin.
The interface defines two methods:

* `toDate()` to convert a `String` tenor to a `LocalDate` object
* `toYearFraction()` to return the year fraction between
  a `LocalDate` as-of-date and a `String` maturity

The **MaturityConverterConfig class**
is used to expose (as a bean) the implementation of the interface that
is used throughout the project. The default implementation is **Actual360MaturityConverter**
,
based on the Actual/360 day count convention.

The example implementation below does not use the `leafCoordinates` or
`pivot` parameters defined in the interface, as currently all conversion
is handled in the ETL.

## Implementing a custom configurable converter

Although the default converter is hard-coded to the Actual/360
convention, you can easily implement a converter that uses the Spring
environment to define the day counts.

The static class constants must cover:

* Defaults for the week, month and year day counts
* Keys for the Spring environment properties
* A `Map<String, Integer>` to allow repeated retrieval of day values
  after initialisation

```
public ConfigurableMaturityConverter(Environment env) {
   DAY_VALUES.put(DAY_KEY, 1);
   DAY_VALUES.put(WEEK_KEY, Integer.parseInt(env.getProperty(WEEK_PROPERTY, WEEK_DEFAULT)));
   DAY_VALUES.put(MONTH_KEY, Integer.parseInt(env.getProperty(MONTH_PROPERTY, MONTH_DEFAULT)));
   DAY_VALUES.put(YEAR_KEY, Integer.parseInt(env.getProperty(YEAR_PROPERTY, YEAR_DEFAULT)));
}
```

Then add the week, month and year values to the `application.properties` file,
which is loaded by default into the Spring environment:

```
# The number of days in a week, for maturity conversion purposes.
maturity-conversion.days.week=7

# The number of days in a month, for maturity conversion purposes.
maturity-conversion.days.month=30

# The number of days in a year, for maturity conversion purposes.
maturity-conversion.days.year=365
```

To take advantage of the `LocalDate` API, the `toYearFraction()`
method converts the `String` maturity into a `LocalDate` using
the `toDate()` method, and retrieves the year count directly from the
`Map` initialised above:

```
@Override
public double toYearFraction(IActivePivot pivot, IDatastoreVersion datastoreVersion, LocalDate asOfDate, String maturity, List<Object> leafCoordinates) {
   LocalDate maturityDate = toDate(pivot, datastoreVersion, asOfDate, maturity, new LocalDateParser(), leafCoordinates);
   Double daysFromAsOfDate = (double)(maturityDate.toEpochDay() - asOfDate.toEpochDay());
   return daysFromAsOfDate / DAY_VALUES.get(YEAR_KEY);
}
```

The `toDate()` method has to handle both `String` representations of
dates, as well as tenors. One of the parameters of the method is a
LocalDateParser, which can be initialised to use any date format (with
the default being `yyyy-MM-dd`).

```
@Override
public LocalDate toDate(IActivePivot pivot, IDatastoreVersion datastoreVersion, LocalDate asOfDate, String tenorOrDate, LocalDateParser parser, List<Object> leafCoordinates) {
   LocalDate sensitivityDate;
   try {
      sensitivityDate = parser.parse(tenorOrDate);
   } catch (DateTimeParseException e) {
      // Not a date, mostly a tenor
      sensitivityDate = asOfDate.plusDays(daysInTenor(tenorOrDate));
   }
   return sensitivityDate;
}
```

In this example, the conversion of the tenor into a number of days is
handled in the static `daysInTenor` method. The example covers the
[Tomorrow Next](https://www.investopedia.com/terms/t/tomorrownext.asp)
tenor, and any combination of a number and one of D,W,M,Y in both
uppercase and lowercase. In the FRTB project, tenors expressed as
numbers without a period string are assumed to be fractions of a year.
Any special cases and error handling must be incorporated in this
conversion.

```
private static int daysInTenor(String tenor) {

   if(tenor.equalsIgnoreCase("TN")) {
      return 2;
   }

   double number = Double.parseDouble(tenor.replaceAll("[^0-9.]", ""));
   String tenorPeriod = String.valueOf(tenor.charAt(tenor.length() - 1));
   tenorPeriod = tenorPeriod.replaceAll("[0-9]", "");
   int days = 0;
   String tenorLowerCase = tenorPeriod.toLowerCase();
   if(!tenorLowerCase.isEmpty() && DAY_VALUES.containsKey(tenorLowerCase)) {
      days = (int) number * DAY_VALUES.get(tenorLowerCase);
   } else {
      //assume it's an frtb vertex expressed in years
      double vertex = Double.parseDouble(tenor);
      days = (int) (vertex * DAY_VALUES.get(YEAR_KEY));
   }
   return days;
}
```

To use the `ConfigurableMaturityConverter`, the
`MaturityConverterConfig` class must autowire the environment and
initialise the converter, exposing it as a bean:

```
@Configuration
public class MaturityConverterConfig implements IMaturityConverterConfig {

   @Autowired
   private Environment env;

   /**
    * Returns the maturity converter to be used in the project, as a Spring bean.
    * Default maturity converter is a {@link com.activeviam.frtb.core.dates.impl.Actual360MaturityConverter}.
    * This should be replaced by any custom maturity converter required by the project.
    * @return The required maturity converter.
    */
   @Bean
   public IMaturityConverter maturityConverter() {
      return new ConfigurableMaturityConverter(env);
   }

}
```
