Package com.opengamma.financial.analytics.model.pnl

Source Code of com.opengamma.financial.analytics.model.pnl.FXOptionBlackVegaPnLFunction$Compiled

/**
* Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.financial.analytics.model.pnl;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import org.threeten.bp.Clock;
import org.threeten.bp.Instant;
import org.threeten.bp.LocalDate;
import org.threeten.bp.Period;
import org.threeten.bp.ZonedDateTime;

import com.google.common.collect.Iterables;
import com.opengamma.OpenGammaRuntimeException;
import com.opengamma.analytics.financial.schedule.HolidayDateRemovalFunction;
import com.opengamma.analytics.financial.schedule.Schedule;
import com.opengamma.analytics.financial.schedule.ScheduleCalculatorFactory;
import com.opengamma.analytics.financial.schedule.TimeSeriesSamplingFunction;
import com.opengamma.analytics.financial.schedule.TimeSeriesSamplingFunctionFactory;
import com.opengamma.analytics.financial.timeseries.util.TimeSeriesDifferenceOperator;
import com.opengamma.core.config.ConfigSource;
import com.opengamma.core.historicaltimeseries.HistoricalTimeSeries;
import com.opengamma.core.id.ExternalSchemes;
import com.opengamma.core.position.Position;
import com.opengamma.core.security.Security;
import com.opengamma.core.value.MarketDataRequirementNames;
import com.opengamma.engine.ComputationTarget;
import com.opengamma.engine.ComputationTargetSpecification;
import com.opengamma.engine.function.AbstractFunction;
import com.opengamma.engine.function.CompiledFunctionDefinition;
import com.opengamma.engine.function.FunctionCompilationContext;
import com.opengamma.engine.function.FunctionExecutionContext;
import com.opengamma.engine.function.FunctionInputs;
import com.opengamma.engine.target.ComputationTargetType;
import com.opengamma.engine.value.ComputedValue;
import com.opengamma.engine.value.ValueProperties;
import com.opengamma.engine.value.ValuePropertyNames;
import com.opengamma.engine.value.ValueRequirement;
import com.opengamma.engine.value.ValueRequirementNames;
import com.opengamma.engine.value.ValueSpecification;
import com.opengamma.financial.OpenGammaCompilationContext;
import com.opengamma.financial.OpenGammaExecutionContext;
import com.opengamma.financial.analytics.DoubleLabelledMatrix2D;
import com.opengamma.financial.analytics.model.CalculationPropertyNamesAndValues;
import com.opengamma.financial.analytics.model.InstrumentTypeProperties;
import com.opengamma.financial.analytics.model.InterpolatedDataProperties;
import com.opengamma.financial.analytics.model.forex.ConventionBasedFXRateFunction;
import com.opengamma.financial.analytics.model.forex.ForexVisitors;
import com.opengamma.financial.analytics.model.forex.option.black.FXOptionBlackFunction;
import com.opengamma.financial.analytics.timeseries.DateConstraint;
import com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesBundle;
import com.opengamma.financial.analytics.timeseries.HistoricalTimeSeriesFunctionUtils;
import com.opengamma.financial.analytics.volatility.surface.ConfigDBVolatilitySurfaceDefinitionSource;
import com.opengamma.financial.analytics.volatility.surface.ConfigDBVolatilitySurfaceSpecificationSource;
import com.opengamma.financial.analytics.volatility.surface.SurfaceInstrumentProvider;
import com.opengamma.financial.analytics.volatility.surface.VolatilitySurfaceDefinition;
import com.opengamma.financial.analytics.volatility.surface.VolatilitySurfaceSpecification;
import com.opengamma.financial.convention.calendar.Calendar;
import com.opengamma.financial.convention.calendar.MondayToFridayCalendar;
import com.opengamma.financial.currency.CurrencyPair;
import com.opengamma.financial.currency.CurrencyPairs;
import com.opengamma.financial.security.FinancialSecurity;
import com.opengamma.financial.security.option.FXOptionSecurity;
import com.opengamma.financial.security.option.NonDeliverableFXOptionSecurity;
import com.opengamma.id.ExternalId;
import com.opengamma.id.ExternalIdBundle;
import com.opengamma.timeseries.DoubleTimeSeries;
import com.opengamma.util.async.AsynchronousExecution;
import com.opengamma.util.money.Currency;
import com.opengamma.util.money.UnorderedCurrencyPair;

/**
*
*/
public class FXOptionBlackVegaPnLFunction extends AbstractFunction {

  private static final HolidayDateRemovalFunction HOLIDAY_REMOVER = HolidayDateRemovalFunction.getInstance();
  private static final Calendar WEEKEND_CALENDAR = new MondayToFridayCalendar("Weekend");
  private static final TimeSeriesDifferenceOperator DIFFERENCE = new TimeSeriesDifferenceOperator();

  @Override
  public CompiledFunctionDefinition compile(final FunctionCompilationContext context, final Instant atInstant) {
    final CurrencyPairs currencyPairs = OpenGammaCompilationContext.getCurrencyPairsSource(context).getCurrencyPairs(CurrencyPairs.DEFAULT_CURRENCY_PAIRS);
    return new Compiled(currencyPairs);
  }

  /**
   * The compiled form.
   */
  protected class Compiled extends AbstractInvokingCompiledFunction {

    private final CurrencyPairs _currencyPairs;

    public Compiled(final CurrencyPairs currencyPairs) {
      _currencyPairs = currencyPairs;
    }

    // CompiledFunctionDefinition

    @Override
    public ComputationTargetType getTargetType() {
      return ComputationTargetType.POSITION;
    }

    @Override
    public boolean canApplyTo(final FunctionCompilationContext context, final ComputationTarget target) {
      final Security security = target.getPosition().getSecurity();
      return security instanceof FXOptionSecurity || security instanceof NonDeliverableFXOptionSecurity;
    }

    @Override
    public Set<ValueSpecification> getResults(final FunctionCompilationContext context, final ComputationTarget target) {
      final FinancialSecurity security = (FinancialSecurity) target.getPosition().getSecurity();
      final Currency putCurrency = security.accept(ForexVisitors.getPutCurrencyVisitor());
      final Currency callCurrency = security.accept(ForexVisitors.getCallCurrencyVisitor());
      final CurrencyPair currencyPair = _currencyPairs.getCurrencyPair(putCurrency, callCurrency);
      final String currencyBase = currencyPair.getBase().getCode(); // The base currency
      final ValueProperties properties = createValueProperties()
          .with(ValuePropertyNames.CALCULATION_METHOD, CalculationPropertyNamesAndValues.BLACK_METHOD)
          .withAny(FXOptionBlackFunction.PUT_CURVE)
          .withAny(FXOptionBlackFunction.PUT_CURVE_CALC_CONFIG)
          .withAny(FXOptionBlackFunction.CALL_CURVE)
          .withAny(FXOptionBlackFunction.CALL_CURVE_CALC_CONFIG)
          .withAny(ValuePropertyNames.SURFACE)
          .withAny(InterpolatedDataProperties.X_INTERPOLATOR_NAME)
          .withAny(InterpolatedDataProperties.LEFT_X_EXTRAPOLATOR_NAME)
          .withAny(InterpolatedDataProperties.RIGHT_X_EXTRAPOLATOR_NAME)
          .with(ValuePropertyNames.CURRENCY, currencyBase)
          .withAny(ValuePropertyNames.SAMPLING_PERIOD)
          .withAny(ValuePropertyNames.SCHEDULE_CALCULATOR)
          .withAny(ValuePropertyNames.SAMPLING_FUNCTION)
          .with(ValuePropertyNames.PROPERTY_PNL_CONTRIBUTIONS, ValueRequirementNames.VEGA_QUOTE_MATRIX)
          .get();
      return Collections.singleton(new ValueSpecification(ValueRequirementNames.PNL_SERIES, target.toSpecification(), properties));
    }

    @Override
    public Set<ValueRequirement> getRequirements(final FunctionCompilationContext context, final ComputationTarget target, final ValueRequirement desiredValue) {
      final ValueProperties constraints = desiredValue.getConstraints();
      final Set<String> putCurveNames = constraints.getValues(FXOptionBlackFunction.PUT_CURVE);
      if (putCurveNames == null || putCurveNames.size() != 1) {
        return null;
      }
      final Set<String> putCurveCalculationConfigs = constraints.getValues(FXOptionBlackFunction.PUT_CURVE_CALC_CONFIG);
      if (putCurveCalculationConfigs == null || putCurveCalculationConfigs.size() != 1) {
        return null;
      }
      final Set<String> callCurveNames = constraints.getValues(FXOptionBlackFunction.CALL_CURVE);
      if (callCurveNames == null || callCurveNames.size() != 1) {
        return null;
      }
      final Set<String> callCurveCalculationConfigs = constraints.getValues(FXOptionBlackFunction.CALL_CURVE_CALC_CONFIG);
      if (callCurveCalculationConfigs == null || callCurveCalculationConfigs.size() != 1) {
        return null;
      }
      final Set<String> surfaceNames = constraints.getValues(ValuePropertyNames.SURFACE);
      if (surfaceNames == null || surfaceNames.size() != 1) {
        return null;
      }
      final Set<String> interpolatorNames = constraints.getValues(InterpolatedDataProperties.X_INTERPOLATOR_NAME);
      if (interpolatorNames == null || interpolatorNames.size() != 1) {
        return null;
      }
      final Set<String> leftExtrapolatorNames = constraints.getValues(InterpolatedDataProperties.LEFT_X_EXTRAPOLATOR_NAME);
      if (leftExtrapolatorNames == null || leftExtrapolatorNames.size() != 1) {
        return null;
      }
      final Set<String> rightExtrapolatorNames = constraints.getValues(InterpolatedDataProperties.RIGHT_X_EXTRAPOLATOR_NAME);
      if (rightExtrapolatorNames == null || rightExtrapolatorNames.size() != 1) {
        return null;
      }
      final Set<String> samplingPeriods = constraints.getValues(ValuePropertyNames.SAMPLING_PERIOD);
      if (samplingPeriods == null || samplingPeriods.size() != 1) {
        return null;
      }
      final FinancialSecurity security = (FinancialSecurity) target.getPosition().getSecurity();
      final Currency putCurrency = security.accept(ForexVisitors.getPutCurrencyVisitor());
      final Currency callCurrency = security.accept(ForexVisitors.getCallCurrencyVisitor());
      final UnorderedCurrencyPair currencies = UnorderedCurrencyPair.of(putCurrency, callCurrency);
      final String surfaceName = Iterables.getOnlyElement(surfaceNames);
      final String samplingPeriod = Iterables.getOnlyElement(samplingPeriods);
      final CurrencyPair currencyPair = _currencyPairs.getCurrencyPair(putCurrency, callCurrency);
      final String vegaResultCurrency = getResultCurrency(target, currencyPair);
      final String currencyBase = currencyPair.getBase().getCode(); // The base currency
      final ValueRequirement vegaMatrixRequirement = new ValueRequirement(ValueRequirementNames.VEGA_QUOTE_MATRIX, ComputationTargetSpecification.of(security),
          ValueProperties.builder()
              .with(ValuePropertyNames.CALCULATION_METHOD, CalculationPropertyNamesAndValues.BLACK_METHOD)
              .with(FXOptionBlackFunction.PUT_CURVE, Iterables.getOnlyElement(putCurveNames))
              .with(FXOptionBlackFunction.PUT_CURVE_CALC_CONFIG, Iterables.getOnlyElement(putCurveCalculationConfigs))
              .with(FXOptionBlackFunction.CALL_CURVE, Iterables.getOnlyElement(callCurveNames))
              .with(FXOptionBlackFunction.CALL_CURVE_CALC_CONFIG, Iterables.getOnlyElement(callCurveCalculationConfigs))
              .with(ValuePropertyNames.SURFACE, surfaceName)
              .with(InterpolatedDataProperties.X_INTERPOLATOR_NAME, Iterables.getOnlyElement(interpolatorNames))
              .with(InterpolatedDataProperties.LEFT_X_EXTRAPOLATOR_NAME, Iterables.getOnlyElement(leftExtrapolatorNames))
              .with(InterpolatedDataProperties.RIGHT_X_EXTRAPOLATOR_NAME, Iterables.getOnlyElement(rightExtrapolatorNames))
              .with(ValuePropertyNames.CURRENCY, vegaResultCurrency).get());
      final ValueRequirement surfaceHTSRequirement = getVolatilitySurfaceHTSRequirement(currencies, surfaceName, samplingPeriod);
      final Set<ValueRequirement> requirements = new HashSet<>();
      requirements.add(vegaMatrixRequirement);
      requirements.add(surfaceHTSRequirement);
      if (!currencyBase.equals(vegaResultCurrency)) {
        requirements.add(ConventionBasedFXRateFunction.getHistoricalTimeSeriesRequirement(putCurrency, callCurrency));
      }
      return requirements;
    }

    // FunctionInvoker

    @Override
    public Set<ComputedValue> execute(final FunctionExecutionContext executionContext, final FunctionInputs inputs, final ComputationTarget target,
        final Set<ValueRequirement> desiredValues) throws AsynchronousExecution {
      final Object vegaMatrixObject = inputs.getValue(ValueRequirementNames.VEGA_QUOTE_MATRIX);
      if (vegaMatrixObject == null) {
        throw new OpenGammaRuntimeException("Could not get vega matrix");
      }
      final Object volatilityHTSObject = inputs.getValue(ValueRequirementNames.VOLATILITY_SURFACE_HISTORICAL_TIME_SERIES);
      if (volatilityHTSObject == null) {
        throw new OpenGammaRuntimeException("Could not get historical time series for volatilities");
      }
      final DoubleLabelledMatrix2D vegaMatrix = (DoubleLabelledMatrix2D) vegaMatrixObject;
      final HistoricalTimeSeriesBundle timeSeriesBundle = (HistoricalTimeSeriesBundle) volatilityHTSObject;
      final Clock snapshotClock = executionContext.getValuationClock();
      final LocalDate now = ZonedDateTime.now(snapshotClock).toLocalDate();
      final ValueRequirement desiredValue = Iterables.getOnlyElement(desiredValues);
      final String surfaceName = desiredValue.getConstraint(ValuePropertyNames.SURFACE);
      final ConfigSource configSource = OpenGammaExecutionContext.getConfigSource(executionContext);
      final ConfigDBVolatilitySurfaceDefinitionSource definitionSource = new ConfigDBVolatilitySurfaceDefinitionSource(configSource);
      final ConfigDBVolatilitySurfaceSpecificationSource specificationSource = new ConfigDBVolatilitySurfaceSpecificationSource(configSource);
      final Position position = target.getPosition();
      final FinancialSecurity security = (FinancialSecurity) position.getSecurity();
      final Currency putCurrency = security.accept(ForexVisitors.getPutCurrencyVisitor());
      final Currency callCurrency = security.accept(ForexVisitors.getCallCurrencyVisitor());
      final UnorderedCurrencyPair currencyPair = UnorderedCurrencyPair.of(putCurrency, callCurrency);
      final VolatilitySurfaceDefinition<Object, Object> definition = getSurfaceDefinition(currencyPair, surfaceName, definitionSource);
      final VolatilitySurfaceSpecification specification = getSurfaceSpecification(currencyPair, surfaceName, specificationSource);
      final Period samplingPeriod = getSamplingPeriod(desiredValue.getConstraint(ValuePropertyNames.SAMPLING_PERIOD));
      final LocalDate startDate = now.minus(samplingPeriod);
      final String scheduleCalculatorName = desiredValue.getConstraint(ValuePropertyNames.SCHEDULE_CALCULATOR);
      final Schedule scheduleCalculator = getScheduleCalculator(scheduleCalculatorName);
      final String samplingFunctionName = desiredValue.getConstraint(ValuePropertyNames.SAMPLING_FUNCTION);
      final TimeSeriesSamplingFunction samplingFunction = getSamplingFunction(samplingFunctionName);
      final LocalDate[] schedule = HOLIDAY_REMOVER.getStrippedSchedule(scheduleCalculator.getSchedule(startDate, now, true, false), WEEKEND_CALENDAR);
      DoubleTimeSeries<?> vegaPnL = getPnLSeries(definition, specification, timeSeriesBundle, vegaMatrix, now, schedule, samplingFunction);
      vegaPnL = vegaPnL.multiply(position.getQuantity().doubleValue());
      final CurrencyPairs currencyPairs = OpenGammaExecutionContext.getCurrencyPairsSource(executionContext).getCurrencyPairs(CurrencyPairs.DEFAULT_CURRENCY_PAIRS);
      final CurrencyPair baseCounterPair = currencyPairs.getCurrencyPair(putCurrency, callCurrency);
      final String vegaResultCurrency = getResultCurrency(target, baseCounterPair);
      final String currencyBase = baseCounterPair.getBase().getCode();
      if (!currencyBase.equals(vegaResultCurrency)) {
        final Object spotFXObject = inputs.getValue(ValueRequirementNames.HISTORICAL_FX_TIME_SERIES);
        if (spotFXObject == null) {
          throw new OpenGammaRuntimeException("Could not get spot FX time series");
        }
        final DoubleTimeSeries<?> spotFX = ((HistoricalTimeSeries) spotFXObject).getTimeSeries();
        vegaPnL = vegaPnL.multiply(spotFX);
      }
      final ValueSpecification spec = new ValueSpecification(ValueRequirementNames.PNL_SERIES, target.toSpecification(), desiredValue.getConstraints());
      return Collections.singleton(new ComputedValue(spec, vegaPnL));
    }

  }

  private ValueRequirement getVolatilitySurfaceHTSRequirement(final UnorderedCurrencyPair currencies, final String surfaceName, final String samplingPeriod) {
    return HistoricalTimeSeriesFunctionUtils.createVolatilitySurfaceHTSRequirement(currencies, surfaceName, InstrumentTypeProperties.FOREX,
        MarketDataRequirementNames.MARKET_VALUE, null, DateConstraint.VALUATION_TIME.minus(samplingPeriod), true, DateConstraint.VALUATION_TIME, true);
  }

  private VolatilitySurfaceDefinition<Object, Object> getSurfaceDefinition(final UnorderedCurrencyPair currencyPair, final String definitionName,
      final ConfigDBVolatilitySurfaceDefinitionSource definitionSource) {
    final String fullDefinitionName = definitionName + "_" + currencyPair.getUniqueId().getValue();
    final VolatilitySurfaceDefinition<Object, Object> definition = (VolatilitySurfaceDefinition<Object, Object>) definitionSource.getDefinition(fullDefinitionName,
        InstrumentTypeProperties.FOREX);
    if (definition == null) {
      throw new OpenGammaRuntimeException("Could not get volatility surface definition named " + fullDefinitionName + " for instrument type " + InstrumentTypeProperties.FOREX);
    }
    return definition;
  }

  private VolatilitySurfaceSpecification getSurfaceSpecification(final UnorderedCurrencyPair currencyPair, final String specificationName,
      final ConfigDBVolatilitySurfaceSpecificationSource specificationSource) {
    final String fullSpecificationName = specificationName + "_" + currencyPair.getUniqueId().getValue();
    final VolatilitySurfaceSpecification specification = specificationSource.getSpecification(fullSpecificationName, InstrumentTypeProperties.FOREX);
    if (specification == null) {
      throw new OpenGammaRuntimeException("Could not get volatility surface specification named " + fullSpecificationName);
    }
    return specification;
  }

  private Period getSamplingPeriod(final String samplingPeriodName) {
    return Period.parse(samplingPeriodName);
  }

  private Schedule getScheduleCalculator(final String scheduleCalculatorName) {
    return ScheduleCalculatorFactory.getScheduleCalculator(scheduleCalculatorName);
  }

  private TimeSeriesSamplingFunction getSamplingFunction(final String samplingFunctionName) {
    return TimeSeriesSamplingFunctionFactory.getFunction(samplingFunctionName);
  }

  private DoubleTimeSeries<?> getPnLSeries(final VolatilitySurfaceDefinition<Object, Object> definition, final VolatilitySurfaceSpecification specification,
      final HistoricalTimeSeriesBundle timeSeriesBundle, final DoubleLabelledMatrix2D vegaMatrix, final LocalDate endDate, final LocalDate[] schedule,
      final TimeSeriesSamplingFunction samplingFunction) {
    final SurfaceInstrumentProvider<Object, Object> provider = (SurfaceInstrumentProvider<Object, Object>) specification.getSurfaceInstrumentProvider();
    final double[][] vegas = vegaMatrix.getValues();
    if (vegas.length != definition.getYs().length || vegas[0].length != definition.getXs().length) {
      throw new OpenGammaRuntimeException("Vega matrix not the same shape as that in definition");
    }
    DoubleTimeSeries<?> vegaPnL = null;
    int i = 0;
    for (final Object x : definition.getXs()) {
      int j = 0;
      for (final Object y : definition.getYs()) {
        ExternalId id = provider.getInstrument(x, y, endDate);
        if (id.getScheme().equals(ExternalSchemes.BLOOMBERG_TICKER_WEAK)) {
          id = ExternalSchemes.bloombergTickerSecurityId(id.getValue());
        }
        final ExternalIdBundle identifier = ExternalIdBundle.of(id);
        final HistoricalTimeSeries tsForTicker = timeSeriesBundle.get(MarketDataRequirementNames.MARKET_VALUE, identifier);
        if (tsForTicker == null) {
          throw new OpenGammaRuntimeException("Could not get identifier / vol series for " + id);
        }
        final DoubleTimeSeries<?> volHistory = DIFFERENCE.evaluate(samplingFunction.getSampledTimeSeries(tsForTicker.getTimeSeries(), schedule));
        final double vega = vegas[j][i] / 100;
        if (vegaPnL == null) {
          vegaPnL = volHistory.multiply(vega);
        } else {
          vegaPnL = vegaPnL.add(volHistory.multiply(vega));
        }
        j++;
      }
      i++;
    }
    return vegaPnL;
  }

  private String getResultCurrency(final ComputationTarget target, final CurrencyPair currencyPair) {
    final FinancialSecurity security = (FinancialSecurity) target.getPosition().getSecurity();
    final Currency putCurrency = security.accept(ForexVisitors.getPutCurrencyVisitor());
    final Currency callCurrency = security.accept(ForexVisitors.getCallCurrencyVisitor());
    Currency ccy;
    if (putCurrency.equals(currencyPair.getBase())) {
      ccy = callCurrency;
    } else {
      ccy = putCurrency;
    }
    return ccy.getCode();
  }
}
TOP

Related Classes of com.opengamma.financial.analytics.model.pnl.FXOptionBlackVegaPnLFunction$Compiled

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.