/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.riskfactor; import java.util.Map; import org.apache.commons.lang.Validate; import org.apache.commons.math.util.MathUtils; import com.opengamma.analytics.financial.greeks.MixedOrderUnderlying; import com.opengamma.analytics.financial.greeks.NthOrderUnderlying; import com.opengamma.analytics.financial.greeks.Underlying; import com.opengamma.analytics.financial.pnl.UnderlyingType; import com.opengamma.timeseries.DoubleTimeSeries; /** * */ public class TaylorExpansionMultiplierCalculator { public static double getMultiplier(final Underlying underlying) { Validate.notNull(underlying, "underlying"); if (underlying instanceof NthOrderUnderlying) { final NthOrderUnderlying nthOrder = (NthOrderUnderlying) underlying; final int n = nthOrder.getOrder(); if (n == 0) { return 1; } return 1. / MathUtils.factorial(n); } else if (underlying instanceof MixedOrderUnderlying) { final MixedOrderUnderlying mixedOrder = (MixedOrderUnderlying) underlying; double result = 1; for (final NthOrderUnderlying underlyingOrder : mixedOrder.getUnderlyingOrders()) { result *= getMultiplier(underlyingOrder); } return result; } throw new IllegalArgumentException("Order was neither NthOrderUnderlying nor MixedOrderUnderlying: have " + underlying.getClass()); } public static double getValue(final Map<UnderlyingType, Double> underlyingData, final Underlying underlying) { Validate.notNull(underlying, "underlying"); Validate.notNull(underlyingData, "underlying data"); Validate.notEmpty(underlyingData, "underlying data"); Validate.noNullElements(underlyingData.keySet(), "underlying data keys"); Validate.noNullElements(underlyingData.values(), "underlying data values"); if (underlying instanceof NthOrderUnderlying) { final NthOrderUnderlying nthOrder = (NthOrderUnderlying) underlying; final int n = nthOrder.getOrder(); if (n == 0) { return 1; } final UnderlyingType type = nthOrder.getUnderlying(); Validate.isTrue(underlyingData.containsKey(type)); final double value = Math.pow(underlyingData.get(type), n); return value * getMultiplier(underlying); } else if (underlying instanceof MixedOrderUnderlying) { final MixedOrderUnderlying mixedOrder = (MixedOrderUnderlying) underlying; Double result = null; double multiplier; for (final NthOrderUnderlying underlyingOrder : mixedOrder.getUnderlyingOrders()) { if (result == null) { result = getValue(underlyingData, underlyingOrder); } else { multiplier = getValue(underlyingData, underlyingOrder); result = result * multiplier; } } if (result != null) { return result; } } throw new IllegalArgumentException("Order was neither NthOrderUnderlying nor MixedOrderUnderlying: have " + underlying.getClass()); } public static DoubleTimeSeries<?> getTimeSeries(final Map<UnderlyingType, DoubleTimeSeries<?>> underlyingData, final Underlying underlying) { Validate.notNull(underlying, "underlying"); Validate.notNull(underlyingData, "underlying data"); Validate.notEmpty(underlyingData, "underlying data"); Validate.noNullElements(underlyingData.keySet(), "underlying data keys"); Validate.noNullElements(underlyingData.values(), "underlying data values"); if (underlying instanceof NthOrderUnderlying) { final NthOrderUnderlying nthOrder = (NthOrderUnderlying) underlying; final int n = nthOrder.getOrder(); if (n == 0) { throw new UnsupportedOperationException(); } final UnderlyingType type = nthOrder.getUnderlying(); Validate.isTrue(underlyingData.containsKey(type)); DoubleTimeSeries<?> ts = underlyingData.get(type); ts = ts.power(n); return ts.multiply(getMultiplier(underlying)); } else if (underlying instanceof MixedOrderUnderlying) { final MixedOrderUnderlying mixedOrder = (MixedOrderUnderlying) underlying; DoubleTimeSeries<?> result = null; DoubleTimeSeries<?> multiplier = null; int size = 0; for (final NthOrderUnderlying underlyingOrder : mixedOrder.getUnderlyingOrders()) { if (result == null) { result = getTimeSeries(underlyingData, underlyingOrder); size = result.size(); } else { multiplier = getTimeSeries(underlyingData, underlyingOrder); if (multiplier.size() != size) { throw new IllegalArgumentException("Time series in map were not the same length"); } result = result.multiply(multiplier); if (result.size() != size) { throw new IllegalArgumentException("Time series in map did not contain the same times"); } } } return result; } throw new IllegalArgumentException("Order was neither NthOrderUnderlying nor MixedOrderUnderlying: have " + underlying.getClass()); } }