/*
Copyright (C) 2008 Praneet Tiwari
Copyright (C) 2009 Ueli Hofstetter
Copyright (C) 2009 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.
*/
package org.jquantlib.model.shortrate.twofactormodels;
import static org.jquantlib.pricingengines.BlackFormula.blackFormula;
import java.util.ArrayList;
import java.util.List;
import org.jquantlib.instruments.Option;
import org.jquantlib.lang.annotation.QualityAssurance;
import org.jquantlib.lang.annotation.QualityAssurance.Quality;
import org.jquantlib.lang.annotation.QualityAssurance.Version;
import org.jquantlib.math.Constants;
import org.jquantlib.math.Ops;
import org.jquantlib.math.distributions.CumulativeNormalDistribution;
import org.jquantlib.math.matrixutilities.Array;
import org.jquantlib.math.solvers1D.Brent;
import org.jquantlib.model.AffineModel;
import org.jquantlib.model.Parameter;
import org.jquantlib.model.TermStructureFittingParameter;
import org.jquantlib.model.shortrate.onefactormodels.TermStructureConsistentModel;
import org.jquantlib.model.shortrate.onefactormodels.TermStructureConsistentModelClass;
import org.jquantlib.processes.OrnsteinUhlenbeckProcess;
import org.jquantlib.quotes.Handle;
import org.jquantlib.termstructures.Compounding;
import org.jquantlib.termstructures.YieldTermStructure;
import org.jquantlib.time.Frequency;
/**
* Two-additive-factor gaussian model class.
*
* This class implements a two-additive-factor model defined by {@latex$ dr_t = \varphi(t) + x_t + y_t }
* where {@latex$ x_t } and {@latex$ y_t } are defined by
* {@latex[ dx_t = -a x_t dt + \sigma dW^1_t, x_0 = 0 }
* {@latex[ dy_t = -b y_t dt + \sigma dW^2_t, y_0 = 0 } and {@latex$ dW^1_t dW^2_t = \rho dt }
*
* @note This class was not tested enough to guarantee its functionality.
*
* @category shortrate
*
* @author Praneet Tiwari
* @author Richard Gomes
*/
@QualityAssurance(quality=Quality.Q0_UNFINISHED, version=Version.V097, reviewers="Richard Gomes")
public class G2 extends TwoFactorModel implements AffineModel, TermStructureConsistentModel {
private static final String g2_model_needs_two_factors = "g2 model needs two factors to compute discount bond";
// need permanent solution for this one
private final TermStructureConsistentModelClass termStructureConsistentModelClass;
private final Parameter a_;
private final Parameter sigma_;
private final Parameter b_;
private final Parameter eta_;
private final Parameter rho_;
private Parameter phi_;
public G2(final Handle termStructure) {
this(termStructure, 0.1, 0.01, 0.1, 0.01, -0.75);
}
public G2(
final Handle termStructure,
final double /* @Real */ a) {
this(termStructure, a, 0.01, 0.1, 0.01, -0.75);
}
public G2(
final Handle termStructure,
final double /* @Real */ a,
final double /* @Real */ sigma) {
this(termStructure, a, sigma, 0.1, 0.01, -0.75);
}
public G2(
final Handle termStructure,
final double /* @Real */ a,
final double /* @Real */ sigma,
final double /* @Real */ b) {
this(termStructure, a, sigma, b, 0.01, -0.75);
}
public G2(
final Handle termStructure,
final double /* @Real */ a,
final double /* @Real */ sigma,
final double /* @Real */ b,
final double /* @Real */ eta) {
this(termStructure, a, sigma, b, eta, -0.75);
}
public G2(
final Handle termStructure,
final double /* @Real */ a,
final double /* @Real */ sigma,
final double /* @Real */ b,
final double /* @Real */ eta,
final double /* @Real */ rho) {
super(5);
//TODO: Code review :: incomplete code
if (true)
throw new UnsupportedOperationException("Work in progress");
termStructureConsistentModelClass = new TermStructureConsistentModelClass(termStructure);
a_ = (arguments_.get(0) /* [0] */);
sigma_ = (arguments_.get(1) /* [1] */);
b_ = (arguments_.get(2) /* []2] */);
eta_ = (arguments_.get(3) /* []3] */);
rho_ = (arguments_.get(4) /* []4] */);
generateArguments();
// TODO: code review :: please verify against QL/C++ code
// seems like we should have this.termStructure
termStructure.addObserver(this);
//XXX:registerWith
//registerWith(termStructure);
}
public double discountBond(final double t, final double T, final double x, final double y) {
return A(t, T) * Math.exp(-B(a(), (T - t)) * x - B(b(), (T - t)) * y);
}
@Override
public double /* @Real */discountBondOption(final Option.Type type, final double /* @Real */strike, final double /* @Time */maturity,
final double /* @Time */bondMaturity) {
final double /* @Real */v = sigmaP(maturity, bondMaturity);
final double /* @Real */f = termStructureConsistentModelClass.termStructure().currentLink().discount(bondMaturity);
final double /* @Real */k = termStructureConsistentModelClass.termStructure().currentLink().discount(maturity) * strike;
return blackFormula(type, k, f, v);
}
@Override
public TwoFactorModel.ShortRateDynamics dynamics() {
return (new Dynamics(phi_, a(), sigma(), b(), eta(), rho()));
}
public double swaption(final Object object, final double range, final int intervals) {
throw new UnsupportedOperationException("work in progress");
/*
* Real G2::swaption(const Swaption::arguments& arguments, Real range, Size intervals) const {
*
* Time start = arguments.floatingResetTimes[0]; Real w = (arguments.type==VanillaSwap::Payer ? 1 : -1 );
* SwaptionPricingFunction function(a(), sigma(), b(), eta(), rho(), w, start, arguments.fixedPayTimes, arguments.fixedRate,
* (*this));
*
* Real upper = function.mux() + range*function.sigmax(); Real lower = function.mux() - range*function.sigmax();
* SegmentIntegral integrator(intervals); return arguments.nominal*w*termStructure()->discount(start)* integrator(function,
* lower, upper); }
*/
}
@Override
public double discount(/* @Time */final double t) {
return termStructure().currentLink().discount(t);
}
@Override
public void generateArguments() {
phi_ = new FittingParameter(termStructureConsistentModelClass.termStructure(), a(), sigma(), b(), eta(), rho());
}
protected double /* @Real */A(final double /* @Time */t, final double /* @Time */T) {
return termStructureConsistentModelClass.termStructure().currentLink().discount(T)
/ termStructureConsistentModelClass.termStructure().currentLink().discount(t)
* Math.exp(0.5 * (V(T - t) - V(T) + V(t)));
}
protected double /* @Real */B(final double /* @Real */x, final double /* @Time */t) {
return (1.0 - Math.exp(-x * t)) / x;
}
private double /* @Real */V(final double /* @Time */t) {
final double /* @Real */expat = Math.exp(-a() * t);
final double /* @Real */expbt = Math.exp(-b() * t);
final double /* @Real */cx = sigma() / a();
final double /* @Real */cy = eta() / b();
final double /* @Real */valuex = cx * cx * (t + (2.0 * expat - 0.5 * expat * expat - 1.5) / a());
final double /* @Real */valuey = cy * cy * (t + (2.0 * expbt - 0.5 * expbt * expbt - 1.5) / b());
final double /* @Real */value = 2.0 * rho() * cx * cy
* (t + (expat - 1.0) / a() + (expbt - 1.0) / b() - (expat * expbt - 1.0) / (a() + b()));
return valuex + valuey + value;
}
private double /* @Real */a() {
return a_.get(0.0);
}
private double /* @Real */sigma() {
return sigma_.get(0.0);
}
private double /* @Real */b() {
return b_.get(0.0);
}
private double /* @Real */eta() {
return eta_.get(0.0);
}
private double /* @Real */rho() {
return rho_.get(0.0);
}
private double /* @Real */sigmaP(final double /* @Time */t, final double /* @Time */s) {
final double /* @Real */temp = 1.0 - Math.exp(-(a() + b()) * t);
final double /* @Real */temp1 = 1.0 - Math.exp(-a() * (s - t));
final double /* @Real */temp2 = 1.0 - Math.exp(-b() * (s - t));
final double /* @Real */a3 = a() * a() * a();
final double /* @Real */b3 = b() * b() * b();
final double /* @Real */sigma2 = sigma() * sigma();
final double /* @Real */eta2 = eta() * eta();
final double /* @Real */value = 0.5 * sigma2 * temp1 * temp1 * (1.0 - Math.exp(-2.0 * a() * t)) / a3 + 0.5 * eta2 * temp2 * temp2
* (1.0 - Math.exp(-2.0 * b() * t)) / b3 + 2.0 * rho() * sigma() * eta() / (a() * b() * (a() + b())) * temp1 * temp2
* temp;
return Math.sqrt(value);
}
@Override
public Handle termStructure() {
return termStructureConsistentModelClass.termStructure();
}
@Override
public double discountBond(final double now, final double maturity, final Array factors) {
throw new UnsupportedOperationException(
"not sure whether this is a quantlib error - looks like they forgot to overwrite a virtual method");
}
//
// private inner classes
//
private class Dynamics extends TwoFactorModel.ShortRateDynamics {
public Dynamics(final Parameter fitting, final double /* @Real */a, final double /* @Real */sigma, final double /* @Real */b,
final double /* @Real */eta, final double /* @Real */rho) {
super(new OrnsteinUhlenbeckProcess(a, sigma, 0.0, 0.0), new OrnsteinUhlenbeckProcess(b, eta, 0.0, 0.0), rho);
fitting_ = (fitting);
}
@Override
public double /* @Rate */shortRate(final double /* @Time */t, final double /* @Real */x, final double /* @Real */y) {
return fitting_.get(t) + x + y;
}
private final Parameter fitting_;
} // dynamics
//TODO: code review
private class SwaptionPricingFunction {
public SwaptionPricingFunction(final double /* @Real */a, final double /* @Real */sigma, final double /* @Real */b, final double /* @Real */eta,
final double /* @Real */rho, final double /* @Real */w, final double /* @Real */start,
final/* std::vector
Ads help maintain this website.