# Adding a New Measure

In Strata, measures define the values that can be calculated for a trade or other calculation target.
For example, Strata provides a standard set of measures including present value and PV01 (see the
`Measures`

class).
When a user requests a calculation they specify the measures that should be calculated and the rules defining
how they should be calculated.

The set of measures calculated by Strata is extensible. Users can add new measures for the built-in asset classes and can also add support for the built-in measures for new asset classes.

## Calculation Functions

Measures are calculated by implementations of
`DerivedCalculationFunction`

or
`CalculationFunction`

.
`DerivedCalculationFunction`

is used when adding new measures for an asset class already exists in Strata.
`CalculationFunction`

is used when adding an asset class that does not already exist in Strata.

Adding a new measure to Strata requires three steps:

- Create a
`Measure`

instance to identify the measure and - Create a function to calculate the measure
- Provide pricing rules linking the
`Measure`

to the function

## Integrating the new function

The new function is normally integrated with the existing ones:

```
CalculationFunctions combined = StandardComponents.calculationFunctions().composedWith(myNewFunction);
```

The combined instance is then passed in via `CalculationRules`

.

## The DerivedCalculationFunction Interface

The interface `DerivedCalculationFunction`

is implemented to calculate one additional measures for an asset class.
It works by first calculating a base set of measures, then calculating the derived measure.
In most cases you should extend `AbstractDerivedCalculationFunction`

which only has one abstract method - `calculate()`

.

`DerivedCalculationFunction`

itself has five methods:

```
public interface DerivedCalculationFunction<T extends CalculationTarget, R> {
public abstract Class<T> targetType();
public abstract Measure measure();
public abstract Set<Measure> requiredMeasures();
public abstract FunctionRequirements requirements(T target, CalculationParameters parameters, ReferenceData refData);
public abstract R calculate(
T target,
Map<Measure, Object> requiredMeasures,
CalculationParameters parameters,
ScenarioMarketData marketData,
ReferenceData refData);
}
```

A typical implementation might be:

```
public MyCalculationFunction extends AbstractDerivedCalculationFunction<SwapTrade, CurrencyScenarioArray> {
private MyCalculationFunction() {
super(SwapTrade.class, MyMeasures.NEW_MEASURE, Measures.RESOLVED_TARGET);
}
@Override
public CurrencyScenarioArray calculate(
SwapTrade trade,
Map<Measure, Object> requiredMeasures,
CalculationParameters parameters,
ScenarioMarketData marketData,
ReferenceData refData) {
ResolvedSwapTrade resolvedTrade = (ResolvedSwapTrade) requiredMeasures.get(Measures.RESOLVED_TARGET);
return calculateNewMeasure(resolvedTrade, marketData, refData);
}
}
```

### Target type

The `targetType()`

method specifies the target type, such as `ResolvedSwap.class`

.
Each derived function implementation handles one type of target.

### Measure

The `measure()`

method specifies which measure is supported.
Each derived function implementation handles the calculation of one measure.

### Required measures

The `requiredMeasures()`

method specifies which measures the derived function depends on.
Normally this include the resolved target - `Measures.RESOLVED_TARGET`

.

### Requirements

The `requirements()`

method provides the ability to determine the market data needed
for the combination of the trade and measure. This can be used to validate that the
market data is available before pricing, or to drive the process of creating the market data.
More details can be found here.

### Calculate

The `calculate()`

method is where the main calculation is performed.
It receives the target and the map of measures that the calculation depends on.
See below for more information about how `calculate()`

should be implemented.

## The CalculationFunction Interface

The interface `CalculationFunction`

is implemented to calculate values for measures,
but only one can be registered for each asset class.
It contains four methods:

```
public interface CalculationFunction<T extends CalculationTarget> {
Class<T> targetType();
Set<Measure> supportedMeasures();
Currency naturalCurrency(T target, ReferenceData refData);
FunctionRequirements requirements(
T target, Set<Measure> measures, CalculationParameters parameters, ReferenceData refData);
Map<Measure, Result<?>> calculate(
T target,
Set<Measure> measures,
CalculationParameters parameters,
ScenarioMarketData marketData,
ReferenceData refData);
}
```

### Target type

The `targetType()`

method specifies the target type, such as `ResolvedSwap.class`

.
Each derived function implementation handles one type of target.

### Supported measures

The `supportedMeasures()`

method specifies which measures are supported.
Each function implementation will handle one or more measures.

### Natural currency

The `naturalCurrency()`

method provides the “natural” currency of the specified target.

For single-currency trades, the “natural” currency is the currency of the trade.

For cross-currency trades, the choice of “natural” currency is more arbitrary. It may be currency of the fixed leg, the currency of the first leg, the base currency in terms of the standard market ordering, or anything other choice that is consistent.

### Requirements

The `requirements()`

method provides the ability to determine the market data needed
for the combination of the trade and measures. This can be used to validate that the
market data is available before pricing, or to drive the process of creating the market data.
More details can be found here.

#### Function requirements

The `requirements`

method has a parameter for the calculation target and returns an instance of `FunctionRequirements`

.
The requirements specify the market data required by the function to calculate a value for the target.

Market data is identified by implementations of `MarketDataId`

.
The function creates a market data identifier for each piece of market data it requires and populates the
`FunctionRequirements`

. The requirements contain three types of values:

- Single values, for example a curve or a quoted price
- Time series of quoted values
- Output currencies

##### Single Market Data Values

Single market data values are individual items are market data used in the calculations, and they can be of any type.
A their simplest they might be a `double`

value representing a quoted price or rate.
They can also be complex values derived from underlying data, for example a curve.

Single market data values can be values that are directly observable in the market, for example rates or prices, or they can be derived from other underlying market data, for example calibrated curves or volatility surfaces.

##### Time Series

Time series contain multiple values of an item of observable market data over a ranges of dates. For example, a series of index rates used for historical fixings.

The values in a time series are always of type `double`

.

##### Output Currencies

The Strata calculation runner is able to automatically convert currency values into different currencies for the purposes of reporting. In order to perform this conversion the required FX rates must be available in the market data.

The calculation runner must know which currencies are included in the results in order to provide the correct FX rates. Therefore if the result of the function includes any currency value, the currencies should be included in the set of output currencies.

#### Example requirements Implementation

The code below shows an example of a `requirements`

method taken from the Strata class `FraCalculationFunction`

.
It demonstrates how to create a set of `FunctionRequirements`

for the data required to calculate the price of a FRA.

A FRA references one or two indices and one currency. In order to calculate the price of a FRA the following market data is required:

- A time series of historical rates for each of the indices
- A forward curve for predicting the future values of the rates for each of the indices
- A discount curve for the currency used for discounting future values

The requirements method must be implemented to return these items in the `FunctionRequirements`

.
In most case, the function will use an instance of `CalculationParameters`

.
The `requirements`

method will delegate most of the implementation to the parameters instance.

### Calculate

The `calculate()`

method calculates a value for each of the specified measures for the calculation target (normally a trade).
The method parameters are the calculation target, measures and an instance of `ScenarioMarketData`

containing
the market data required for the calculation.

To perform efficient calculations, the interface is designed to handle multiple measures and multiple scenarios efficiently.
In order to achieve this, the `calculate`

method is expected to calculate multiple values.
This may allow functions to avoid repeating common calculations when a value is calculated for the
same target across multiple scenarios and measures.

In simple cases, or when integrating with existing calculation libraries, the underlying calculations are
likely to produce one value at a time. In fact the default pricers included with Strata behave this way.
In this case it is the job of the `calculate`

method to unpack the scenario market data, call the underlying
calculations repeatedly and pack the results into a single return value.

#### Looking up Market Data

A function requests market data by calling the following methods on `ScenarioMarketData`

:

`getValue`

`getTimeSeries`

The single argument to these methods is the market data key identifying the market data required.
The return value of `getTimeSeries`

is a `LocalDateDoubleTimeSeries`

. The return value of `getValue`

is a `MarketDataBox`

which provides a market data value for each scenario. The market data value for
each scenario is provided by `MarketDataBox.getValue(int scenarioIndex)`

.

If the market data doesn’t contain a value for the key an exception will be thrown. The exception will be caught by the calculation runner and the results will contain an error explaining the calculation failed because the market data was not available.

#### Return Values

As explained above, the `calculate`

method performs calculations for all scenarios at once.
The calculated values can be divided into two categories:

- Aggregate values, for example the average, maximum or minimum value across all scenarios.
- Individual values, one for each scenario.

If the calculation produces an aggregate value there is are no restrictions on the return type of `calculate`

.

If the calculation produces a value for each scenario the calculate method should return an implementation of
`ScenarioResult`

. This allows the calculation engine to handle the results more intelligently in the
common case of running a single scenario.

If the calculated value contains currency amounts the return value should implement `CurrencyConvertible`

.
Convertible values can be automatically converted to the reporting currency.

### Function Design Guidelines

The Strata calculation engines performs calculations in parallel so it is possible a function will be executed concurrently on multiple threads with different targets. Therefore functions implementations must be thread safe.

It is strongly recommended that functions should be completely stateless, receiving everything required to perform the calculation via method arguments. This not only ensures they are thread safe but makes it immediately obvious they are safe.

If a function needs to store any configuration parameters as fields, the fields should be final and the configuration objects should be immutable.