Configuring measures using Spring Beans

This page describes the mechanism introduced in MR 3.1.0 that allows you to customize the measure configuration through Spring Beans.

It also provides an example of adding customization using the new 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

Annotation Condition Cube
SensitivitiesCopperContextBean BeanEnabledSensitivitiesCube Sensitivity Cube
SensitivitiesSummaryCopperContextBean BeanEnabledSensitivitiesSummaryCube Sensitivity Summary Cube
VarCopperContextBean BeanEnabledVaRCube VaR-ES Cube
VarSummaryCopperContextBean BeanEnabledVaRSummaryCube VaR-ES Summary Cube
PnLCopperContextBean BeanEnabledPnLCube PLCube
PnLSummaryCopperContextBean BeanEnabledPnLSummaryCube PL Summary Cube
MarketDataCopperContextBean BeanEnabledMarketDataCube Market Data Cube

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.

    @Bean
    @Qualifier(SP_QUALIFIER__VAR_MEASURES_RESOLVER)
    @Conditional(BeanEnabledVaRCube.class)
    public IMeasureResolver varResolver(ICopperContextScopeManager scopeManager, ConfigurableListableBeanFactory beanFactory) {
        return new MeasureResolver(scopeManager, beanFactory, VarCopperContextBean.class);
    }

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

Qualifier Condition Annotation
SP_QUALIFIER__SENSITIVITY_MEASURES_RESOLVER BeanEnabledSensitivitiesCube SensitivitiesCopperContextBean
SP_QUALIFIER__SENSITIVITY_SUMMARY_MEASURES_RESOLVER BeanEnabledSensitivitiesSummaryCube SensitivitiesSummaryCopperContextBean
SP_QUALIFIER__VAR_MEASURES_RESOLVER BeanEnabledVaRCube VarCopperContextBean
SP_QUALIFIER__VAR_SUMMARY_MEASURES_RESOLVER BeanEnabledVaRSummaryCube VarSummaryCopperContextBean
SP_QUALIFIER__PNL_MEASURES_RESOLVER BeanEnabledPnLCube PnLCopperContextBean
SP_QUALIFIER__PNL_SUMMARY_MEASURES_RESOLVER BeanEnabledPnLSummaryCube PnLSummaryCopperContextBean
SP_QUALIFIER__MARKET_DATA_MEASURES_RESOLVER BeanEnabledMarketDataCube MarketDataCopperContextBean

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:

Object Method Description
CopperCubePublisher copperCube CopperCubePublisher::accept Optional publisher responsible for setting up Copper-defined hierarchies.
IMeasureResolver measureResolver IMeasureResolver::measures IMeasureResolver object responsible for beans defined using the mechanism described on this page.
List<MeasurePublisher> additionalMeasures MeasurePublisher::accept Optional List of publishers for additional measures.

The optional objects are not available on the Summary cubes.

To replace the default copperCube and additionalMeasures publishers, the following qualifiers are available:

Qualifier Cube
SP_QUALIFIER__SENSITIVITY_COPPER_CUBE Sensitivity Cube
SP_QUALIFIER__ADDITIONAL_SENSITIVITY_MEASURES Sensitivity Cube
SP_QUALIFIER__VAR_COPPER_CUBE VaR-ES Cube
SP_QUALIFIER__ADDITIONAL_VAR_MEASURES VaR-ES Cube
SP_QUALIFIER__PNL_COPPER_CUBE PLCube
SP_QUALIFIER__ADDITIONAL_PNL_MEASURES PLCube
SP_QUALIFIER__MARKET_DATA_COPPER_CUBE Market Data Cube
SP_QUALIFIER__ADDITIONAL_MARKET_DATA_MEASURES Market Data Cube

The MeasurePublisher beans used by the cube configuration classes use the following qualifiers:

Qualifier Cube Condition
SP_QUALIFIER__SENSITIVITY_MEASURES Sensitivity Cube BeanEnabledSensitivitiesCube
SP_QUALIFIER__SENSITIVITY_SUMMARY_MEASURES Sensitivity Summary Cube BeanEnabledSensitivitiesSummaryCube
SP_QUALIFIER__VAR_MEASURES VaR-ES Cube BeanEnabledVaRCube
SP_QUALIFIER__VAR_SUMMARY_MEASURES VaR-ES Summary Cube BeanEnabledVaRSummaryCube
SP_QUALIFIER__PNL_MEASURES PLCube BeanEnabledPnLCube
SP_QUALIFIER__PNL_SUMMARY_MEASURES PL Summary Cube BeanEnabledPnLSummaryCube
SP_QUALIFIER__MARKET_DATA_MEASURES Market Data Cube BeanEnabledMarketDataCube
SP_QUALIFIER__COMMON_MEASURES Combined Cube BeanEnabledCommonCube

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:

Object Cube Description
MarketDataMeasureParameters Market Data Cube Measure parameters for the Market Data cube, containing cube levels, members and formatters.
MarketDataMeasureNames Market Data Cube Constants and naming methods for the Market Data cube.
PnLMeasureParameters PLCube, PL Summary Cube Measure parameters for the PL and PL Summary cubes, containing cube levels and formatters.
PnLMeasureNames PLCube, PL Summary Cube Constants and naming methods for the PL and PL Summary cubes.
SensiMeasureParameters Sensitivity Cube, Sensitivity Summary Cube Measure parameters for the Sensitivity and Sensitivity Summary cubes, containing cube levels, members, formatters, formula providers, the number of axes for a sensitivity, the maturity converter and the market data retrieval service together with custom parameters for the service.
SensiMeasureNames Sensitivity Cube, Sensitivity Summary Cube Constants and naming methods for the Sensitivity and Sensitivity Summary cubes.
DividendMeasureNames Sensitivity Cube, Sensitivity Summary Cube Constants and naming methods specific to the Dividend measures in the Sensitivity and Sensitivity Summary cubes.
VaRMeasureParameters VaR-ES Cube, VaR-ES Summary Cube Measure parameters for the VaR-ES and VaR-ES Summary cubes, containing cube levels, members and formatters, as well as configurable confidence levels and risk classes.
VaRMetricParametersAndNames VaR-ES Cube, VaR-ES Summary Cube Constants and naming methods for the VaR-ES and VaR-ES Summary cubes, together with the postprocessor object specific to each VaR metric (VaR, Harrel-Davis VaR, VaE, ES, ETG, Weighted VaR, Weighted VaE, Weighted ES, and Weighted ETG).

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:

Qualifier Type Description
SP_QUALIFIER__MARKET_DATA_MEASURE_PARAMETERS MarketDataMeasureParameters Measure parameters for the Market Data cube.
SP_QUALIFIER__PNL_MEASURE_PARAMETERS PnLMeasureParameters Measure parameters for the PL and PL Summary cubes.
SP_QUALIFIER__VAR_CUBE_MEASURE_PARAMETERS VaRMeasureParameters Measure parameters for the VaR-ES and VaR-ES Summary cubes.
SP_QUALIFIER__ES_PARAMETERS VaRMetricParametersAndNames The constants, naming methods, and postprocessor for the ES metric.
SP_QUALIFIER__ETG_PARAMETERS VaRMetricParametersAndNames The constants, naming methods, and postprocessor for the ETG metric.
SP_QUALIFIER__HD_PARAMETERS VaRMetricParametersAndNames The constants, naming methods, and postprocessor for the Harrel-Davis VaR metric.
SP_QUALIFIER__VAE_PARAMETERS VaRMetricParametersAndNames The constants, naming methods, and postprocessor for the VaE metric.
SP_QUALIFIER__VAR_PARAMETERS VaRMetricParametersAndNames The constants, naming methods, and postprocessor for the VaR metric.
SP_QUALIFIER__WES_PARAMETERS VaRMetricParametersAndNames The constants, naming methods, and postprocessor for the Weighted ES metric.
SP_QUALIFIER__WETG_PARAMETERS VaRMetricParametersAndNames The constants, naming methods, and postprocessor for the Weighted ETG metric.
SP_QUALIFIER__WVAE_PARAMETERS VaRMetricParametersAndNames The constants, naming methods, and postprocessor for the Weighted VaE metric.
SP_QUALIFIER__WVAR_PARAMETERS VaRMetricParametersAndNames The constants, naming methods, and postprocessor for the Weighted VaR metric.
SP_QUALIFIER__BASE_MEASURE_PARAMETERS SensiMeasureParameters Required measure parameters for the common and aggregated Sensitivity measure chains.
SP_QUALIFIER__DELTA_MEASURE_PARAMETERS SensiMeasureParameters Required measure parameters for the Delta measure chains.
SP_QUALIFIER__GAMMA_MEASURE_PARAMETERS SensiMeasureParameters Required measure parameters for the Gamma measure chains.
SP_QUALIFIER__VEGA_MEASURE_PARAMETERS SensiMeasureParameters Required measure parameters for the Vega measure chains.
SP_QUALIFIER__VANNA_MEASURE_PARAMETERS SensiMeasureParameters Required measure parameters for the Vanna measure chains.
SP_QUALIFIER__VOLGA_MEASURE_PARAMETERS SensiMeasureParameters Required measure parameters for the Volga measure chains.
SP_QUALIFIER__THETA_MEASURE_PARAMETERS SensiMeasureParameters Required measure parameters for the Theta measure chains.
SP_QUALIFIER__CROSS_GAMMA_MEASURE_PARAMETERS SensiMeasureParameters Required measure parameters for the Cross Gamma measure chains.
SP_QUALIFIER__CASH_MEASURE_PARAMETERS SensiMeasureParameters Required measure parameters for the Cash measure chains.
SP_QUALIFIER__CORRELATION_MEASURE_PARAMETERS SensiMeasureParameters Required measure parameters for the Correlation measure chains.
SP_QUALIFIER__DIVIDEND_MEASURE_PARAMETERS SensiMeasureParameters Required measure parameters for the Dividend measure chains.

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:

Cube Factory Abstract class Interface Description
Market Data Cube MarketDataFactory AMarketDataFactory IMarketDataMeasures All MeasureCreator objects used in creating measures for the Market Data cube.
PLCube, PL Summary Cube PnLFactory APnLFactory IPnLMeasures All MeasureCreator objects used in creating measures for the PL and PL Summary cubes.
Sensitivity Cube, Sensitivity Summary Cube SensiFactory ASensiFactory IBaseMeasures MeasureCreator objects for creating measures not split by sensitivity type.
IBucketedMeasures MeasureCreator objects for measures that can be bucketed on time pillars.
IDayToDayMeasures MeasureCreator objects for creating day-to-day difference measures.
ILadderExpansionMeasures MeasureCreator objects for creating ladder measures.
INamedDayToDayMeasures MeasureCreator objects for day-to-day measures.
INativeCurrencyMeasures MeasureCreator objects for creating sensitivity measures in the native currency.
ISensitivityMeasures MeasureCreator objects for creating the top-level, post-FX sensitivity measures.
ISplitMeasures MeasureCreator objects for creating corporate split measures.
Sensitivity Cube PnLExplainFactory APnLExplainFactory IAggregateMeasures MeasureCreator objects for creating aggregated top level measures (e.g. with a plus operation).
IBasePnLExplainMeasures MeasureCreator objects for creating measures not split by sensitivity type.
IBucketedMeasures See above.
IFilteredMeasures See above.
INamedDayToDayMeasures See above.
IPnLExplainMeasures MeasureCreator objects for creating PnL Explain measures, by sensitivity and aggregated.
ISensitivityMarketDataMeasures See above.
ISplitMeasures See above.
Sensitivity Cube TaylorFactory ATaylorFactory IAggregateMeasures See above.
IBucketedMeasures See above.
IContextualMeasures MeasureCreator objects for creating measures with the confidence level controlled through a context value.
IFilteredMeasures See above.
IFixedConfidenceMeasures MeasureCreator objects for creating measures per configurable confidence levels.
IIncrementalMeasures MeasureCreator objects for creating Incremental, LEstimator, Component VaR and Component VaR Delta measures.
INamedDayToDayMeasures See above.
IShiftMeasures MeasureCreator objects for creating market shift measures.
ISplitMeasures See above.
IStatisticalMeasures MeasureCreator for measures that perform statistical operations on vectors (e.g. min, max, mean).
ITaylorVaRMeasures MeasureCreator objects for creating Taylor VaR measures, by sensitivity and aggregated.
IVaRESMeasures MeasureCreator objects for creating measures not split by metric type.
VaR-ES Cube, VaR-ES Summary Cube VaRFactory AVaRFactory IContextualMeasures See above.
IContextualRiskClassMeasures MeasureCreator objects for creating measures with the confidence level controlled through a context value, split by configurable risk class.
IFixedConfidenceMeasures See above.
IIncrementalMeasures See above.
IRiskClassFixedConfidenceMeasures MeasureCreator objects for creating measures per configurable confidence level, split by configurable risk class.
IVaRESMeasures See above.

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:

    @SensitivitiesCopperContextBean
    @Qualifier(SENSI + PNL_EXPLAIN_NEXT_DATE)
    @MeasureGroup(PNL_EXPLAIN_NEXT_DATE)
    public CopperMeasure correlationPnlExplainNextDate(@Qualifier(SENSI + PNL_EXPLAIN_NATIVE_NEXT_DATE) CopperMeasure pnlExplainNativeNextDate) {
        return getFactory().pnlExplainNextDate().on(pnlExplainNativeNextDate);
    }

A measure operating on all measures part of the PNL_EXPLAIN_NEXT_DATE group:

    @SensitivitiesCopperContextBean
    @Qualifier(AGGREGATE_PNL_EXPLAIN_NATIVE_NEXT_DATE)
    public CopperMeasure pnlExplainNativeNextDate(@MeasureGroup(PNL_EXPLAIN_NATIVE_NEXT_DATE) CopperMeasure[] sensitivitiesPnlExplainNativeNextDate) {
        return getFactory().aggregateMeasures(SensiMeasureNames::getAggregatePnlExplainNativeNextDate).on(sensitivitiesPnlExplainNativeNextDate);
    }

A measure bean generating multiple measures based on project configuration:

    @VarCopperContextBean
    @Qualifier(METRIC + CONFIDENCE)
    public CopperMeasure[] esMetricConfidence(@Qualifier(VAR_FX_VECTOR) CopperMeasure varEsVarFxVector) {
        CopperMeasure[] returnArray = new CopperMeasure[getConfidenceLevels().size()];
        for (int i = 0; i < getConfidenceLevels().size(); i++) {
            returnArray[i] = getFactory().metricConfidence(getConfidenceLevels().get(i)).on(varEsVarFxVector);
        }
        return returnArray;
    }

The following packages contain [...]Chain classes implementing the relevant interfaces:

Package Factory
com.activeviam.mr.marketdata.measures.chains A single MarketDataFactory.
com.activeviam.mr.pnl.measures.chains.complete The common PnLFactory.
com.activeviam.mr.pnl.measures.chains.summary The common PnLFactory.
com.activeviam.mr.productcontrol.measures.chains The common PnLFactory.
com.activeviam.mr.sensi.measures.chains.complete A SensiFactory instance per sensitivity type, providing the correct Parameters and Names.
A PnLExplainFactory instance per sensitivity type, providing the correct Parameters and Names.
A TaylorFactory instance per sensitivity type, providing the correct Parameters and Names.
com.activeviam.mr.sensi.measures.chains.summary A SensiFactory instance per sensitivity type, providing the correct Parameters and Names.
com.activeviam.mr.var.measures.chains.complete A VaRFactory instance per metric type, providing the correct Parameters and Names.
com.activeviam.mr.var.measures.chains.summary A VaRFactory instance per metric type, providing the correct Parameters and Names.

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

@Configuration
public class CustomMeasuresConfig extends AVaRESChain {

    private static final int[] MULTIPLIERS = new int[]{2, 3, 5};

    @VarCopperContextBean
    @Qualifier(PNL_VECTOR_EXPAND)
    @Primary
    public CopperMeasure expandRename(@Qualifier(PNL_VECTOR_EXPAND) CopperMeasure pnlVectorExpand) {
        return pnlVectorExpand.as("PnLVectorExpandOld");
    }

    @VarCopperContextBean
    @Qualifier("MultiplePnLVectorExpand")
    @Primary
    public CopperMeasure[] multiply(@Qualifier(PNL_VECTOR_EXPAND) CopperMeasure pnlVectorExpand) {
        CopperMeasure[] returnArray = new CopperMeasure[MULTIPLIERS.length];
        for (int i = 0; i < MULTIPLIERS.length; i++) {
            returnArray[i] = pnlVectorExpand.multiply(Copper.constant(MULTIPLIERS[i])).as("PnLVectorExpand x " + MULTIPLIERS[i]);
        }
        return returnArray;
    }

    @VarCopperContextBean
    @Qualifier("Aggregate PnL Vector Expand")
    @Primary
    public CopperMeasure aggregatePnLVectorExpand(@Qualifier("MultiplePnLVectorExpand") CopperMeasure[] multipliedPnLVectorExpand) {
        return Arrays.stream(multipliedPnLVectorExpand).reduce(CopperMeasure::plus).get().as(PNL_VECTOR_EXPAND);
    }

    @VarCopperContextBean
    @Qualifier(PNL_VECTOR_EXPAND_NEIGHBOUR_VALUE)
    @Primary
    public CopperMeasure customVarEsPnlVectorExpandNeighbourValue(@Qualifier("Aggregate PnL Vector Expand") CopperMeasure varEsPnlVectorExpand) {
        return getFactory().pnlVectorExpandNeighbour().on(varEsPnlVectorExpand);
    }
}

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:
    @SensitivitiesCopperContextBean
    @Qualifier(SENSI + NATIVE_INTERMEDIATE)
    @Primary
    public CopperMeasure deltaSensiNativeIntermediate() {
        return null;
    }
  • Replacing the bean and returning the underlier:
    @SensitivitiesCopperContextBean
    @Qualifier(SENSI + NATIVE_VECTOR_EXPAND)
    public CopperMeasure deltaSkipVectorNativeExpand(@Qualifier(SENSI + NATIVE_SUM_TECHNICAL_FILTERED) CopperMeasure sumTechnicalFiltered) {
        return sumTechnicalFiltered;
    }

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