Post-processors on the Market Data API

The Market Data API provides several post-processors for the retrieval of market data:

  • a single market data corresponding to a key defining the market data
  • all the market data corresponding to a curve, surface, or cube

Market data post-processors

Interfaces for market data retrieval are defined in the packages com.activeviam.marketdata.api.retrievers.intf and com.activeviam.marketdata.api.retrievers.contextual.intf.

Post-processor Description
AMarketDataPostProcessor<C, V, T extends IContextualMarketDataRetriever<C, V>> Abstract class that handles:
- required levels
- default value for market data
- the MarketDataDateShift used for the retrieval of market data
ADefaultMarketDataPostProcessor<R extends IContextualMarketDataRetriever<List<Object>, Double>> Abstract class extending AMarketDataPostProcessor that handles coordinates of type List<Object> and market data of type Double. That class also offers the possibility to override the coordinates coming from the location in the buildCoordinates(ILocation location) method.
SingleMarketDataPostProcessor Handles the retrieval of a single piece of market data without any interpolation.
CurveMarketDataPostProcessor Handles the retrieval of curve market data with interpolation. Uses the maturity converter for the computation of the interpolation input data.
SurfaceMarketDataPostProcessor Handles the retrieval of surface market data with interpolation. Uses the maturity converter for the computation of the interpolation input data.
CubeMarketDataPostProcessor Handles the retrieval of cube market data with interpolation. Uses the maturity converter for the computation of the interpolation input data.

AMarketDataPostProcessor

This post-processor extends ABasicPostProcessor.

It uses the following generic types:

  • C: type of the coordinates used to retrieve market data (e.g. List<Object>).
  • V: type of the retrieved market data (e.g. Double).
  • T extends IContextualMarketDataRetriever<C, V>: type of the IContextualMarketDataRetriever used in the post-processor.

This post-processor has the following properties:

  • LEVELS_PROPERTY: a ILevelInfo[] representing the levels required for retrieving market data.
  • MARKET_DATA_DATE_SHIFT_PROPERTY: a MarketDataDateShift object.
  • DEFAULT_VALUE_PROPERTY: an object of type V that represents the default value to return.

The logic of the post-processor is as follows:

  1. Check if the point location for which the post-processor is invoked is at the required levels. If it is not, the default value is returned.
  2. If the point location is at the required levels, invoke the abstract method C buildCoordinates(ILocation location) for the point location to build the coordinates from the location.
  3. Invoke the abstract method T getMarketDataRetriever(ILocation location) for the point location to get the retriever that will be used.
  4. Invoke the retriever for the extracted coordinates and the MarketDataDateShift specified in the configuration of the post-processor.

ADefaultMarketDataPostProcessor

This post-processor extends AMarketDataPostProcessor<List<Object>, Double, R>. It handles the retrieval of market data with coordinates of type List<Object> and values Double.

This post-processor has one property on top of the properties from AMarketDataPostProcessor:

  • OVERRIDDEN_STORE_VALUES_PROPERTY: a List<Object> representing the overridden values used to build the coordinates from the point location. To use overridden values, a List<Object> of a length bigger than the number of required levels needs to be provided. The post-processor iterates over that list and for each null value found in that list, it takes the coordinate of the corresponding index in the required levels. Otherwise it takes the value specified in the overridden values list (see example below).

Optionally, the method List<Object> overrideCoordinates(List<Object> coordinates) can be implemented in a class extending that post-processor to further override the coordinates after the execution of that logic.

SingleMarketDataPostProcessor

This post-processor extends ADefaultMarketDataPostProcessor<IDefaultContextualMarketDataRetriever>.

This post-processor has one property on top of the properties from ADefaultMarketDataPostProcessor:

  • RETRIEVER_PROPERTY: the name of the IMarketDataRetrievalContainer<IDefaultMarketDataRetriever> object to use to retrieve market data.

This post-processor creates a SingleContextualMarketDataRetriever from the IMarketDataRetrievalContainer defined in the properties to retrieve market data.

CurveMarketDataPostProcessor

This post-processor extends ADefaultMarketDataPostProcessor<InterpolatingCurveContextualMarketDataRetriever>.

This post-processor has one property on top of the properties from ADefaultMarketDataPostProcessor:

  • INTERPOLATION_MODE_PROPERTY: specifies the InterpolationMode to use.

The post-processor uses the IMaturityConverter and the CurveMarketDataRetrieverFactory that are injected via the interfaces IMaturityConverterAware and ICurveMarketDataRetrieverFactoryAware respectively.

The maturity converter is used to convert the tenors into double values so that they can be used as inputs of the interpolator. The CurveMarketDataRetrieverFactory instantiates an InterpolatingCurveContextualMarketDataRetriever, used to handle curve market data retrieval and interpolation.

SurfaceMarketDataPostProcessor

This post-processor extends ADefaultMarketDataPostProcessor<InterpolatingSurfaceContextualMarketDataRetriever>.

This post-processor has one property on top of the properties from ADefaultMarketDataPostProcessor:

  • INTERPOLATION_MODE_PROPERTY: specifies the InterpolationMode to use.

The post-processor uses the IMaturityConverter and the SurfaceMarketDataRetrieverFactory that are injected via the interfaces IMaturityConverterAware and ISurfaceMarketDataRetrieverFactoryAware respectively.

The maturity converter is used to convert the tenors and moneyness into double values so that they can be used as inputs of the interpolator. The SurfaceMarketDataRetrieverFactory instantiates an InterpolatingSurfaceContextualMarketDataRetriever, used to handle surface market data retrieval and interpolation.

CubeMarketDataPostProcessor

This post-processor extends ADefaultMarketDataPostProcessor<InterpolatingCubeContextualMarketDataRetriever>.

This post-processor has one property on top of the properties from ADefaultMarketDataPostProcessor:

  • INTERPOLATION_MODE_PROPERTY: specifies the InterpolationMode to use.

The post-processor uses the IMaturityConverter and the CubeMarketDataRetrieverFactory that are injected via the interfaces IMaturityConverterAware and ICubeMarketDataRetrieverFactoryAware respectively.

The maturity converter is used to convert the tenors, moneyness and maturities into double values so that they can be used as inputs of the interpolator. The CubeMarketDataRetrieverFactory instantiates an InterpolatingCubeContextualMarketDataRetriever that is used to handle cube market data retrieval and interpolation.

Configuration

To instantiate market data post-processors, builders are provided in the SingleMarketDataPostProcessor, CurveMarketDataPostProcessor, SurfaceMarketDataPostProcessor and CubeMarketDataPostProcessor classes.

The builder of the SingleMarketDataPostProcessor has the following methods:

  • withRequiredLevels: list of LevelIdentifier objects to define the required levels.
  • withRetriever: the String corresponding to the name of the IMarketDataRetrievalContainer to use.

Optionally, the following methods can be used:

  • withMarketDataDateShift: specifies the MarketDataDateShift value to use (by default, the MarketDataDateShift.CURRENT_DAY value is used as market data shift).
  • withDefaultValue: specifies the value to return.
  • withOverriddenValues: specifies the overridden values to use when the coordinates are built (see below). By default, no overridden values are used.

Example

Here’s an example of creating a measure using the SingleMarketDataPostProcessor:

    LevelIdentifier asOfDateLevel = new LevelIdentifier("Dates", "Date", "AsOfDate");
    LevelIdentifier marketDataSetLevel = new LevelIdentifier("MarketData", "MarketDataSets", "MarketDataSet");
    LevelIdentifier riskFactorIdLevel = new LevelIdentifier("RiskFactorId", "RiskFactorId", "RiskFactorId");

    CopperMeasure instrumentMeasure = SingleMarketDataPostProcessor.measure()
        .withRetriever(SPOT_MARKET_DATA_STORE)
        .withRequiredLevels(asOfDateLevel, marketDataSetLevel, riskFactorIdLevel)
        .as("InstrumentMeasure");

To use overridden values, a List<Object> of a length bigger than the number of required levels needs to be provided. The post-processor iterates over that list and for each null value found in that list, it takes the coordinate of the corresponding index in the required levels. Otherwise it takes the value specified in the overridden values list. For instance, with the following configuration:

    LevelIdentifier asOfDateLevel = new LevelIdentifier("Dates", "Date", "AsOfDate");
    LevelIdentifier marketDataSetLevel = new LevelIdentifier("MarketData", "MarketDataSets", "MarketDataSet");

    CopperMeasure instrumentMeasureWithOverride = SingleMarketDataPostProcessor.measure()
                .withRetriever(SPOT_MARKET_DATA_STORE)
                .withRequiredLevels(asOfDateLevel, marketDataSetLevel)
                .withOverridenValues(Arrays.asList(null, null, "Instrument2"))
                .as("InstrumentMeasureWithOverride");

the post-processor retrieves data for coordinates equal to:

  • the as-of-date and the market data set that are extracted from the location at which the post-processor is invoked
  • the instrument id “Instrument2”

In addition to the methods present in the SingleMarketDataPostProcessor builder, the CurvePostProcessor, SurfacePostProcessor and CubePostProcessor builders also have a withInterpolationMode to specify which interpolation mode to use. Those three post-processors use the maturity retriever to convert tenors, moneyness, and maturities for the inputs of the interpolator.

Example - CurvePostProcessor builder

     LevelIdentifier asOfDateLevel = new LevelIdentifier("Dates", "Date", "AsOfDate");
     LevelIdentifier marketDataSetLevel = new LevelIdentifier("MarketData", "MarketDataSets", "MarketDataSet");
     LevelIdentifier curveIdLevel = new LevelIdentifier("CurveId", "CurveId", "CurveId");
     LevelIdentifier tenorsLevel = new LevelIdentifier("Tenor", "Tenor", "Tenor");

     CopperMeasure copperMeasure = CurveMarketDataPostProcessor.measure()
        .withInterpolationMode(InterpolationMode.LINEAR)
        .withRequiredLevels(asOfDateLevel, marketDataSetLevel, curveIdLevel, tenorsLevel)
        .as("CurveMeasure");

Example - SurfacePostProcessor builder

     LevelIdentifier asOfDateLevel = new LevelIdentifier("Dates", "Date", "AsOfDate");
     LevelIdentifier marketDataSetLevel = new LevelIdentifier("MarketData", "MarketDataSets", "MarketDataSet");
     LevelIdentifier surfaceIdLevel = new LevelIdentifier("SurfaceId", "SurfaceId", "SurfaceId");
     LevelIdentifier tenorsLevel = new LevelIdentifier("Tenor", "Tenor", "Tenor");
     LevelIdentifier moneynessesLevel = new LevelIdentifier("Moneyness", "Moneyness", "Moneyness");

    CopperMeasure copperMeasure = SurfaceMarketDataPostProcessor.measure()
        .withInterpolationMode(InterpolationMode.LINEAR)
        .withRequiredLevels(asOfDateLevel, marketDataSetLevel, surfaceIdLevel, tenorsLevel, moneynessesLevel)
        .as("SurfaceMeasure");

Example - CubePostProcessor builder


     LevelIdentifier asOfDateLevel = new LevelIdentifier("Dates", "Date", "AsOfDate");
     LevelIdentifier marketDataSetLevel = new LevelIdentifier("MarketData", "MarketDataSets", "MarketDataSet");
     LevelIdentifier cubeIdLevel = new LevelIdentifier("CubeId", "CubeId", "CubeId");
     LevelIdentifier tenorsLevel = new LevelIdentifier("Tenor", "Tenor", "Tenor");
     LevelIdentifier moneynessesLevel = new LevelIdentifier("Moneyness", "Moneyness", "Moneyness");
     LevelIdentifier maturitiesLevel = new LevelIdentifier("UnderlyingMaturity", "UnderlyingMaturity", "UnderlyingMaturity");

     CopperMeasure copperMeasure = CubeMarketDataPostProcessor.measure()
        .withInterpolationMode(InterpolationMode.LINEAR)
        .withRequiredLevels(asOfDateLevel, marketDataSetLevel, cubeIdLevel, tenorsLevel, moneynessesLevel, maturitiesLevel)
        .as("CubeMeasure");

MarketDataMeasureBuilderHelper

In Atoti Market Risk, the MarketDataMeasureBuilderHelper class can also be used to define measures using the market data post-processor: This class is useful to create measures for custom market data post-processors. Let’s assume that we have written a DividendsReportingPostProcessor that extends SingleMarketDataPostProcessor and that we have defined a MarketDataRetrievalContainer named DIVIDEND_REPORTING_MARKET_DATA_RETRIEVER.

We can then define the following measure:

     LevelIdentifier curveIdLevel = new LevelIdentifier("InstrumentId", "InstrumentId", "InstrumentId");
     LevelIdentifier tenorsLevel = new LevelIdentifier("ExecutionDate", "ExecutionDate", "ExecutionDate");

     CopperMeasure dividendMeasure = new MarketDataMeasureBuilderHelper(
        DividendsReportingPostProcessor.PLUGIN_KEY,
        DIVIDEND_REPORTING_MARKET_DATA_RETRIEVER)
        .startBuilding(List.of(curveIdLevel, tenorsLevel), MarketDataDateShift.CURRENT_DAY)
        .as("DividendMeasure");

The constructor of the MarketDataMeasureBuilderHelper class takes the following arguments:

  • the plugin key of the post-processor
  • the name of the IMarketDataRetrievalContainer to use

The startBuilding method takes the following arguments:

  • the list of LevelIdentifier objects used to define the requested levels of the post-processor
  • the MarketDataDateShift to use

note

Important note

The LevelIdentifier for the as of date level new LevelIdentifier(DATES_DIMENSION, DATE_HIERARCHY, AS_OF_DATE_LEVEL) and the LevelIdentifier for the market data set level new LevelIdentifier(MARKET_DATA_DIMENSION, MARKET_DATA_SETS_HIERARCHY, MARKET_DATA_SET_LEVEL) are automatically added to the list of required levels. If you need a different behavior, you can extend the MarketDataMeasureBuilderHelper class to implement your own logic.

Optionally, you can specify:

  • an underlying measure with the withUnderlyingMeasure method. If that method is not used, contributors.COUNT is the measure used by default.
  • the type of the post-processor with the withType method. If that method is not used, DOUBLE is the type used by default.
  • overridden values in the withOverriddenStoreValues method:
     LevelIdentifier curveIdLevel = new LevelIdentifier("CurveId", "CurveId", "CurveId");

     CopperMeasure dividendMeasure = new MarketDataMeasureBuilderHelper(
                DividendsReportingPostProcessor.PLUGIN_KEY,
                DIVIDEND_REPORTING_MARKET_DATA_RETRIEVER)
                .withUnderlyingMeasure(Copper.measure("SampleMeasure"))
                .withOverriddenStoreValues(Arrays.asList(null, null, null, LocalDate.of(2024, 2, 1)))
                .withType(ILiteralType.DOUBLE)
                .startBuilding(List.of(curveIdLevel), MarketDataDateShift.CURRENT_DAY)
                .as("DividendMeasure");