Skip to main content
The Spring Bean mechanism introduced in version 3.1.0 allows measure configuration to be customized without modifying the core application. The example below demonstrates how to add a customization using this mechanism.

Concept

Measures in Atoti Market Risk are now configured as replaceable qualified Spring Beans, with the Atoti Server post-processing chain being composed through the use of qualified parameters in the bean creation methods.

Bean annotations

All measure beans in Atoti Market Risk have custom annotations, per cube. These annotations attach a Copper context to the bean and make instantiation conditional on the cube being enabled.

Available annotations

The Resolver objects

Each cube in Atoti Market Risk uses an implementation of the IMeasureResolver interface that defines the annotation to use for the measures intended for that cube.
The IMeasureResolver interface performs the following actions:
  • Collects all annotated beans.
  • Groups them by @Qualifier.
  • Selects the @Primary bean for each individual @Qualifier.
  • Publishes the beans on the Copper context, ordered by dependency relationship.

Available Resolvers

The MeasurePublisher beans

For each cube, a MeasurePublisher bean is created, which is responsible for calling the measure creation objects in the correct order. The possible measure creation objects are: The optional objects are not available on the Summary cubes. To replace the default copperCube and additionalMeasures publishers, the following qualifiers are available: The MeasurePublisher beans used by the cube configuration classes use the following qualifiers:

Parameter objects

The cube-specific measure chains rely on parameter objects that contain:
  • Configuration properties (usually cube levels, members, formatters)
  • Parameters required for creating measures (e.g. formula providers, the market data retrieval service, the number of axes for a sensitivity)
  • Constants for use in @Qualifier annotations
  • Methods for naming measures
The following object types are available: The [...]MeasureParameters and VaR-ES Cube metric-specific [...]Names objects are exposed as beans. For the other cubes, the [...]Names objects are created using the parameter beans. To replace the beans, the following qualifiers are available:

Factories

The logic for creating Copper-based measures is contained within collections of interfaces split by logical measure sub-chain (e.g. ILadderExpansionMeasures, IRiskClassFixedConfidenceMeasures). For each cube, an abstract factory class implements the specific interfaces and stores the Parameters and Names objects required. Concrete classes extend the abstract class and define common helper methods. The methods contained within the factory interfaces are mostly of the type MeasureCreator, an interface alias for Function<CopperMeasure[], CopperMeasure>. The function takes an array of underlying measures and returns a single resulting measure. The alias also defines two additional methods:
  • MeasureCreator#on(CopperMeasure... measures) - an alias for Function#apply(measures) that allows the usage of varargs
  • MeasureCreator#noUnderlying() - an alias for Function#apply(null)
The following factory classes are available:

Chains

Chain classes are configuration classes that leverage measure factories to define a measure chain as a collection of beans. A typical measure definition consists of:
  • The cube-specific bean annotation (see Bean annotations)
  • A @Qualifier annotation specific to the measure.
  • (OPTIONAL) A @MeasureGroup annotation marking the measure to be part of a group.
  • (OPTIONAL) A @Conditional annotation to enable/disable creating the measure depending on the project configuration.
  • The type of the bean (CopperMeasure and CopperMeasure[] are currently supported).
  • Underlying measures as qualified parameters of the method.
  • The logic for creating the measure, within the method body.

Examples

A measure defined as part of the PNL_EXPLAIN_NEXT_DATE group:
A measure operating on all measures part of the PNL_EXPLAIN_NEXT_DATE group:
A measure bean generating multiple measures based on project configuration:
The following packages contain [...]Chain classes implementing the relevant interfaces: Each package contains one or more [...]Chain classes, split by logical measure sub-chain. As multiple measures can make use of the same factory MeasureCreator method, a single factory interface can result in multiple [...]Chain classes. The Sensitivity and VaR-ES measures are further duplicated by sensitivity type and VaR metric, respectively. Each sensitivity type and VaR metric has a base abstract class that defines specific Parameters objects to be used in creating the relevant Factory. Summary cubes also have a (sometimes smaller) set of [...]Chain classes, with potentially missing measures.

Customization mechanism and examples

The internal configuration described in the Concept section enables the customization of measures through standalone bean definitions anywhere in the project configuration. To customize a measure chain, you can replace individually qualified measures by defining a bean with the same annotations, marked as @Primary. Making the configuration class extend one of the A[...]Chain abstract classes gives access to the factory, names and parameters objects specific to that chain, through getFactory(), getFactory().getNames() and getParameters(). While all internally defined measures make use of the factories, this is not a requirement.

Replacing the PnLVectorExpand measure

In this example we’re renaming the initial PnLVectorExpand measure to PnLVectorExpandOld, creating PnLVectorExpand x 2, PnLVectorExpand x 3 and PnLVectorExpand x 5 measures and summing them up to replace the initial PnLVectorExpand measure. Finally, to ensure our new bean is in the correct position in the chain, we replace the PNL_VECTOR_EXPAND_NEIGHBOUR_VALUE bean and use Aggregate PnL Vector Expand instead of PNL_VECTOR_EXPAND as the underlier.

Replacing a subchain

If the use-case requires replacing a longer part of a measure chain (e.g. skipping several intermediate steps), the intermediate beans also have to be explicitly replaced. Two options are available:
  • Replacing the bean and returning null:
  • Replacing the bean and returning the underlier:
If the intermediate measures are likely to be used as underliers in other parts of the chain, return the underlier to avoid NullPointerException issues.

Suggested Further Reading

Custom Measures Warning

Atoti Market Risk cubes and their summary variants (for example the VaR-ES Cube and the VaR-ES Summary Cube) are created as a horizontal distribution. This enables Atoti Market Risk to show a single measure (for example VaR) with some dates coming from the full cube and other date contributions from the summary cube. This is a useful feature, but it comes with a warning. Atoti Server expects that all cubes in a horizontal distribution have exactly identical measure chains. If they do not, this can lead to errors or incorrect results when queries are executed on a query cube with both cubes. The measure chains in Atoti Market Risk are not identical between main and summary cubes, but we have taken care to avoid these failure scenarios. We strongly recommend that, if you are using summary cubes, you add any new measures both to the main and summary cubes.
Measure chain differences between main and summary cubes may lead to runtime errors or incorrect query results.