/**
* Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.greeks;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.apache.commons.lang.ObjectUtils;
import com.opengamma.analytics.financial.pnl.UnderlyingType;
import com.opengamma.analytics.math.interpolation.Interpolator1D;
import com.opengamma.analytics.math.interpolation.data.Interpolator1DDataBundle;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.tuple.Pair;
import com.opengamma.util.tuple.Pairs;
/**
*
*/
//TODO GRID_PV and GRID_IMPLIED_VOL don't belong in here
public class PDEResultCollection implements Iterable<Pair<Greek, double[]>> {
/** The present value for each strike value on the space grid at expiry */
public static final Greek GRID_PRICE = new Greek(new NthOrderUnderlying(0, UnderlyingType.FORWARD), "Local Volatility PV") {
@Override
public <T> T accept(final GreekVisitor<T> visitor) {
throw new UnsupportedOperationException();
}
};
/** The Black present value for each strike value on the space grid at expiry */
public static final Greek GRID_BLACK_PRICE = new Greek(new NthOrderUnderlying(0, UnderlyingType.FORWARD), "Black PV") {
@Override
public <T> T accept(final GreekVisitor<T> visitor) {
throw new UnsupportedOperationException();
}
};
/** The Black implied volatility for each strike value of the space grid at expiry */
public static final Greek GRID_IMPLIED_VOL = new Greek(new NthOrderUnderlying(0, UnderlyingType.IMPLIED_VOLATILITY), "Black Implied Volatility") {
@Override
public <T> T accept(final GreekVisitor<T> visitor) {
throw new UnsupportedOperationException();
}
};
/** The Black delta for each strike value on the space grid at expiry */
public static final Greek GRID_BLACK_DELTA = new Greek(new NthOrderUnderlying(1, UnderlyingType.FORWARD), "Forward Black delta") {
@Override
public <T> T accept(final GreekVisitor<T> visitor) {
throw new UnsupportedOperationException();
}
};
/** The Black dual delta for each strike value on the space grid at expiry */
public static final Greek GRID_BLACK_DUAL_DELTA = new Greek(new NthOrderUnderlying(1, UnderlyingType.STRIKE), "Dual Black delta") {
@Override
public <T> T accept(final GreekVisitor<T> visitor) {
throw new UnsupportedOperationException();
}
};
/** The Black gamma for each strike value on the space grid at expiry */
public static final Greek GRID_BLACK_GAMMA = new Greek(new NthOrderUnderlying(2, UnderlyingType.FORWARD), "Forward Black gamma") {
@Override
public <T> T accept(final GreekVisitor<T> visitor) {
throw new UnsupportedOperationException();
}
};
/** The Black dual gamma for each strike value on the space grid at expiry */
public static final Greek GRID_BLACK_DUAL_GAMMA = new Greek(new NthOrderUnderlying(2, UnderlyingType.STRIKE), "Dual Black gamma") {
@Override
public <T> T accept(final GreekVisitor<T> visitor) {
throw new UnsupportedOperationException();
}
};
/** The Black vega for each strike value on the space grid at expiry */
public static final Greek GRID_BLACK_VEGA = new Greek(new NthOrderUnderlying(1, UnderlyingType.IMPLIED_VOLATILITY), "Forward Black vega") {
@Override
public <T> T accept(final GreekVisitor<T> visitor) {
throw new UnsupportedOperationException();
}
};
/** The Black driftless vanna for each strike value on the space grid at expiry */
public static final Greek GRID_BLACK_VANNA = new Greek(new MixedOrderUnderlying(Arrays.asList(new NthOrderUnderlying(1, UnderlyingType.FORWARD),
new NthOrderUnderlying(1, UnderlyingType.IMPLIED_VOLATILITY))), "Forward Black vanna") {
@Override
public <T> T accept(final GreekVisitor<T> visitor) {
throw new UnsupportedOperationException();
}
};
/** The Black vomma for each strike value on the space grid at expiry */
public static final Greek GRID_BLACK_VOMMA = new Greek(new NthOrderUnderlying(2, UnderlyingType.IMPLIED_VOLATILITY), "Forward Black vomma") {
@Override
public <T> T accept(final GreekVisitor<T> visitor) {
throw new UnsupportedOperationException();
}
};
/** The delta for each strike value on the space grid at expiry */
public static final Greek GRID_DELTA = new Greek(new NthOrderUnderlying(1, UnderlyingType.FORWARD), "Forward delta") {
@Override
public <T> T accept(final GreekVisitor<T> visitor) {
throw new UnsupportedOperationException();
}
};
/** The dual delta for each strike value on the space grid at expiry */
public static final Greek GRID_DUAL_DELTA = new Greek(new NthOrderUnderlying(1, UnderlyingType.STRIKE), "Dual delta") {
@Override
public <T> T accept(final GreekVisitor<T> visitor) {
throw new UnsupportedOperationException();
}
};
/** The gamma for each strike value on the space grid at expiry */
public static final Greek GRID_GAMMA = new Greek(new NthOrderUnderlying(2, UnderlyingType.FORWARD), "Forward gamma") {
@Override
public <T> T accept(final GreekVisitor<T> visitor) {
throw new UnsupportedOperationException();
}
};
/** The dual gamma for each strike value on the space grid at expiry */
public static final Greek GRID_DUAL_GAMMA = new Greek(new NthOrderUnderlying(2, UnderlyingType.STRIKE), "Dual gamma") {
@Override
public <T> T accept(final GreekVisitor<T> visitor) {
throw new UnsupportedOperationException();
}
};
/** The vega for each strike value on the space grid at expiry */
public static final Greek GRID_VEGA = new Greek(new NthOrderUnderlying(1, UnderlyingType.IMPLIED_VOLATILITY), "Forward vega") {
@Override
public <T> T accept(final GreekVisitor<T> visitor) {
throw new UnsupportedOperationException();
}
};
/** The driftless vanna for each strike value on the space grid at expiry */
public static final Greek GRID_VANNA = new Greek(new MixedOrderUnderlying(Arrays.asList(new NthOrderUnderlying(1, UnderlyingType.FORWARD), new NthOrderUnderlying(1,
UnderlyingType.IMPLIED_VOLATILITY))), "Forward vanna") {
@Override
public <T> T accept(final GreekVisitor<T> visitor) {
throw new UnsupportedOperationException();
}
};
/** domestic and foreign prices*/
public static final Greek GRID_DOMESTIC_PV_QUOTE = new Greek(new NthOrderUnderlying(0, UnderlyingType.SPOT_PRICE), "Forex PV quote") {
@Override
public <T> T accept(final GreekVisitor<T> visitor) {
throw new UnsupportedOperationException();
}
};
/** The vomma for each strike value on the space grid at expiry */
public static final Greek GRID_VOMMA = new Greek(new NthOrderUnderlying(2, UnderlyingType.IMPLIED_VOLATILITY), "Forward vomma") {
@Override
public <T> T accept(final GreekVisitor<T> visitor) {
throw new UnsupportedOperationException();
}
};
private final Map<Greek, double[]> _gridDataMap = new TreeMap<>();
private final double[] _strikes;
private final int _n;
public PDEResultCollection(final double[] strikes) {
ArgumentChecker.notNull(strikes, "strikes");
_strikes = strikes;
_n = strikes.length;
}
public double[] getGridGreeks(final Greek greek) {
ArgumentChecker.notNull(greek, "greek");
return _gridDataMap.get(greek);
}
public Double getPointGreek(final Greek greek, final double strike, final Interpolator1D interpolator) {
ArgumentChecker.notNull(greek, "greek");
ArgumentChecker.notNull(interpolator, "interpolator");
if (!(_gridDataMap.containsKey(greek)) || _gridDataMap.get(greek) == null) {
return null;
}
final Interpolator1DDataBundle data = interpolator.getDataBundle(_strikes, _gridDataMap.get(greek));
return interpolator.interpolate(data, strike);
}
public void put(final Greek greek, final double[] result) {
ArgumentChecker.notNull(greek, "greek");
if (result != null) {
ArgumentChecker.isTrue(result.length == _n, "Result is the wrong length; have {}, need {}", result.length, _n);
}
_gridDataMap.put(greek, result);
}
public boolean isEmpty() {
return _gridDataMap.isEmpty();
}
public boolean contains(final Greek greek) {
return _gridDataMap.containsKey(greek);
}
public int size() {
return _gridDataMap.size();
}
public Set<Greek> keySet() {
return Collections.unmodifiableSet(_gridDataMap.keySet());
}
public Collection<double[]> values() {
return Collections.unmodifiableCollection(_gridDataMap.values());
}
public double[] getStrikes() {
return _strikes;
}
//TODO toPointGreekCollection(double strike, Interpolator1D interpolator)
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
for (final Map.Entry<Greek, double[]> entry : _gridDataMap.entrySet()) {
result = prime * result + entry.getKey().hashCode();
if (entry.getValue() != null) {
result = prime * result + Arrays.hashCode(entry.getValue());
}
}
result = prime * result + Arrays.hashCode(_strikes);
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof PDEResultCollection)) {
return false;
}
final PDEResultCollection other = (PDEResultCollection) obj;
if (!ObjectUtils.equals(_strikes, other._strikes)) {
return false;
}
if (size() != other.size()) {
return false;
}
for (final Map.Entry<Greek, double[]> entry : _gridDataMap.entrySet()) {
if (!other._gridDataMap.containsKey(entry.getKey())) {
return false;
}
if (!Arrays.equals(entry.getValue(), _gridDataMap.get(entry.getKey()))) {
return false;
}
}
return true;
}
@Override
public Iterator<Pair<Greek, double[]>> iterator() {
return new BackingMapGreekIterator(_gridDataMap.entrySet().iterator());
}
private static class BackingMapGreekIterator implements Iterator<Pair<Greek, double[]>> {
private final Iterator<Map.Entry<Greek, double[]>> _backingIterator;
public BackingMapGreekIterator(final Iterator<Map.Entry<Greek, double[]>> backingIterator) {
_backingIterator = backingIterator;
}
@Override
public boolean hasNext() {
return _backingIterator.hasNext();
}
@Override
public Pair<Greek, double[]> next() {
final Map.Entry<Greek, double[]> nextEntry = _backingIterator.next();
return Pairs.<Greek, double[]>of(nextEntry.getKey(), nextEntry.getValue());
}
@Override
public void remove() {
throw new UnsupportedOperationException("Cannot remove from this iterator");
}
}
}