/*
Copyright (C) 2008 Richard Gomes
This source code is release under the BSD License.
This file is part of JQuantLib, a free-software/open-source library
for financial quantitative analysts and developers - http://jquantlib.org/
JQuantLib is free software: you can redistribute it and/or modify it
under the terms of the JQuantLib license. You should have received a
copy of the license along with this program; if not, please email
. The license is also available online at
.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the license for more details.
JQuantLib is based on QuantLib. http://quantlib.org/
When applicable, the original copyright notice follows this notice.
*/
/*
Copyright (C) 2002, 2003, 2004 Ferdinando Ametrano
Copyright (C) 2003 StatPro Italia srl
This file is part of QuantLib, a free-software/open-source library
for financial quantitative analysts and developers - http://quantlib.org/
QuantLib is free software: you can redistribute it and/or modify it
under the terms of the QuantLib license. You should have received a
copy of the license along with this program; if not, please email
. The license is also available online at
.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the license for more details.
*/
package org.jquantlib.termstructures.volatilities;
import org.jquantlib.QL;
import org.jquantlib.daycounters.DayCounter;
import org.jquantlib.math.interpolations.Interpolation;
import org.jquantlib.math.interpolations.factories.Linear;
import org.jquantlib.math.matrixutilities.Array;
import org.jquantlib.termstructures.BlackVarianceTermStructure;
import org.jquantlib.termstructures.TermStructure;
import org.jquantlib.time.Date;
import org.jquantlib.util.PolymorphicVisitor;
import org.jquantlib.util.Visitor;
/**
* Black volatility curve modelled as variance curve
*
* This class calculates time-dependent Black volatilities using as input a
* vector of (ATM) Black volatilities observed in the market.
*
* The calculation is performed interpolating on the variance curve. Linear
* interpolation is used as default; this can be changed by the
* setInterpolation() method.
*
* For strike dependence, see BlackVarianceSurface.
*
* @author Richard Gomes
*/
// TODO check time extrapolation
public class BlackVarianceCurve extends BlackVarianceTermStructure {
//
// private fields
//
private final DayCounter dayCounter;
private final Date maxDate;
private final Date[] dates;
private final /*@Time*/ Array times;
private final /*@Variance*/ Array variances;
private Interpolation varianceCurve;
private final Interpolation.Interpolator factory;
//
// public constructors
//
public BlackVarianceCurve(
final Date referenceDate,
final Date[] dates,
final /*@Volatility*/ double[] blackVolCurve,
final DayCounter dayCounter) {
this(referenceDate, dates, blackVolCurve, dayCounter, true);
}
public BlackVarianceCurve(
final Date referenceDate,
final Date[] dates,
final /*@Volatility*/ double[] blackVolCurve,
final DayCounter dayCounter,
final boolean forceMonotoneVariance) {
super(referenceDate);
QL.require(dates.length==blackVolCurve.length , "mismatch between date vector and black vol vector"); // TODO: message
// cannot have dates[0]==referenceDate, since the
// value of the volatility at dates[0] would be lost
// (variance at referenceDate must be zero)
QL.require(dates[0].gt(referenceDate) , "cannot have dates[0] <= referenceDate"); // TODO: message
this.dayCounter = dayCounter;
this.dates = dates.clone();
this.maxDate = dates[dates.length-1];
variances = /*@Variance*/ new Array(this.dates.length+1);
times = /*@Time*/ new Array(this.dates.length+1);
variances.set(0, 0.0);
times.set(0, 0.0);
for (int j=1; j<=blackVolCurve.length; j++) {
times.set(j, timeFromReference(this.dates[j-1]));
QL.require(times.get(j)>times.get(j-1) , "times must be sorted unique"); // TODO: message
final double value = times.get(j) * blackVolCurve[j-1]*blackVolCurve[j-1];
variances.set(j, value);
QL.require(variances.get(j)>=variances.get(j-1) || !forceMonotoneVariance , "variance must be non-decreasing"); // TODO: message
}
// default: linear interpolation
factory = new Linear();
}
//
// public methods
//
public void setInterpolation() {
this.setInterpolation(factory);
}
public final void setInterpolation(final Interpolation.Interpolator factory) {
varianceCurve = factory.interpolate(times, variances);
varianceCurve.enableExtrapolation();
varianceCurve.update();
notifyObservers();
}
//
// Overrides TermStructure
//
@Override
public final DayCounter dayCounter() {
return dayCounter;
}
@Override
public final Date maxDate() {
return maxDate;
}
//
// Overrides BlackVolTermStrucure
//
@Override
public final /*@Real*/ double minStrike() {
return Double.NEGATIVE_INFINITY;
}
@Override
public final /*@Real*/ double maxStrike() {
return Double.POSITIVE_INFINITY;
}
@Override
// TODO :: compare against C++ sources
protected final /*@Variance*/ double blackVarianceImpl(final /*@Time*/ double t, final /*@Real*/ double maturity) {
if (t <= times.last()) {
return varianceCurve.op(t);
} else {
// extrapolate with flat vol
/*@Time*/ final double lastTime = times.last(); // TODO: probably an error here
return varianceCurve.op(lastTime) * t / lastTime;
}
}
//
// implements PolymorphicVisitable
//
@Override
public void accept(final PolymorphicVisitor pv) {
final Visitor v = (pv!=null) ? pv.visitor(this.getClass()) : null;
if (v != null) {
v.visit(this);
} else {
super.accept(pv);
}
}
}
Ads help maintain this website.