/** * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.model.option.pricing.analytic.formula; import org.apache.commons.lang.Validate; import com.opengamma.analytics.math.function.Function1D; import com.opengamma.analytics.math.statistics.distribution.NonCentralChiSquaredDistribution; /** * */ public class CEVPriceFunction implements OptionPriceFunction<CEVFunctionData> { private static final BlackPriceFunction BLACK_PRICE_FUNCTION = new BlackPriceFunction(); private static final NormalPriceFunction NORMAL_PRICE_FUNCTION = new NormalPriceFunction(); @Override public Function1D<CEVFunctionData, Double> getPriceFunction(final EuropeanVanillaOption option) { final double k = option.getStrike(); final double t = option.getTimeToExpiry(); final boolean isCall = option.isCall(); return new Function1D<CEVFunctionData, Double>() { @SuppressWarnings("synthetic-access") @Override public Double evaluate(final CEVFunctionData data) { Validate.notNull(data, "data"); final double forward = data.getForward(); final double numeraire = data.getNumeraire(); final double sigma = data.getVolatility(); final double beta = data.getBeta(); if (beta == 1.0) { final Function1D<BlackFunctionData, Double> blackFormula = BLACK_PRICE_FUNCTION.getPriceFunction(option); return blackFormula.evaluate(new BlackFunctionData(forward, numeraire, sigma)); } if (beta == 0.0) { final Function1D<NormalFunctionData, Double> normalFormula = NORMAL_PRICE_FUNCTION.getPriceFunction(option); return normalFormula.evaluate(new NormalFunctionData(forward, numeraire, sigma)); } final double b = 1.0 / (1 - beta); final double x = b * b / sigma / sigma / t; final double a = Math.pow(k, 2 * (1 - beta)) * x; final double c = Math.pow(forward, 2 * (1 - beta)) * x; if (beta < 1) { final NonCentralChiSquaredDistribution chiSq1 = new NonCentralChiSquaredDistribution(b + 2, c); final NonCentralChiSquaredDistribution chiSq2 = new NonCentralChiSquaredDistribution(b, a); if (isCall) { return numeraire * (forward * (1 - chiSq1.getCDF(a)) - k * chiSq2.getCDF(c)); } return numeraire * (k * (1 - chiSq2.getCDF(c)) - forward * chiSq1.getCDF(a)); } final NonCentralChiSquaredDistribution chiSq1 = new NonCentralChiSquaredDistribution(-b, a); final NonCentralChiSquaredDistribution chiSq2 = new NonCentralChiSquaredDistribution(2 - b, c); if (isCall) { return numeraire * (forward * (1 - chiSq1.getCDF(c)) - k * chiSq2.getCDF(a)); } return numeraire * (k * (1 - chiSq2.getCDF(a)) - forward * chiSq1.getCDF(c)); } }; } }