/*
Copyright (C)
2008 Praneet Tiwari
2009 Ueli Hofstetter
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.onefactormodels;
import org.jquantlib.lang.exceptions.LibraryException;
import org.jquantlib.math.Ops;
import org.jquantlib.math.matrixutilities.Array;
import org.jquantlib.math.optimization.PositiveConstraint;
import org.jquantlib.math.solvers1D.Brent;
import org.jquantlib.methods.lattices.Lattice;
import org.jquantlib.methods.lattices.TrinomialTree;
import org.jquantlib.model.ConstantParameter;
import org.jquantlib.model.Parameter;
import org.jquantlib.model.TermStructureFittingParameter;
import org.jquantlib.processes.OrnsteinUhlenbeckProcess;
import org.jquantlib.quotes.Handle;
import org.jquantlib.termstructures.YieldTermStructure;
import org.jquantlib.time.TimeGrid;
/**
* Standard Black-Karasinski model class.
*
* This class implements the standard Black-Karasinski model defined by
* {@latex[ d\ln r_t = (\theta(t) - \alpha \ln r_t)dt + \sigma dW_t }
* where {@latex$ \alpha } and {@latex$ \sigma } are constants.
*
* @category shortrate
*
* @author Praneet Tiwari
*/
// TODO: code review :: please verify against QL/C++ code
// TODO: code review :: license, class comments, comments for access modifiers, comments for @Override
public class BlackKarasinski extends OneFactorModel implements TermStructureConsistentModel {
// need permanent solution for this one
//TODO:renaming....
private final TermStructureConsistentModelClass termstructureConsistentModel;
private static final String no_defined_process_for_bk = "no defined process for Black-Karasinski";
public BlackKarasinski(final Handle termStructure){
this(termStructure, 0.1,0.1);
}
public BlackKarasinski(final Handle termStructure, final double a, final double sigma){
super(2);
if (System.getProperty("EXPERIMENTAL") == null)
throw new UnsupportedOperationException("Work in progress");
termstructureConsistentModel = new TermStructureConsistentModelClass(termStructure);
this.a_ = arguments_.get(0);
this.sigma_ = arguments_.get(1);
//FIXME: bug?
this.a_ = new ConstantParameter(a, new PositiveConstraint());
this.sigma_ = new ConstantParameter(sigma, new PositiveConstraint());
// 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 /* @Real */a() {
return a_.get(0.0);
}
public double /* @Real */sigma() {
return sigma_.get(0.0);
}
private Parameter a_;
private Parameter sigma_;
private class Helper implements Ops.DoubleOp {
private final int /* @Size */size_;
private final double /* @Time */dt_;
private final double /* @Real */xMin_, dx_;
private final Array statePrices_;
private final double /* @Real */discountBondPrice_;
public Helper(
final int /* @Size */i,
final double /* @Real */xMin,
final double /* @Real */dx,
final double /* @Real */discountBondPrice,
final OneFactorModel.ShortRateTree tree) {
size_ = (tree.size(i));
dt_ = (tree.timeGrid().dt(i));
xMin_ = (xMin);
dx_ = (dx);
statePrices_ = (tree.statePrices(i));
discountBondPrice_ = (discountBondPrice);
}
public double /* @Real */op /* () */(final double /* @Real */theta) {
double /* @Real */value = discountBondPrice_;
double /* @Real */x = xMin_;
for (int /* @Size */j = 0; j < size_; j++) {
final double /* @Real */discount = Math.exp(-Math.exp(theta + x) * dt_);
value -= statePrices_.get(j)/* [j] */* discount;
x += dx_;
}
return value;
}
}
@Override
public ShortRateDynamics dynamics() {
throw new LibraryException(no_defined_process_for_bk); // QA:[RG]::verified
}
@Override
public Lattice tree(final TimeGrid grid) {
final TermStructureFittingParameter phi = new TermStructureFittingParameter(termstructureConsistentModel.termStructure());
final ShortRateDynamics numericDynamics = (new Dynamics(phi, a(), sigma()));
final TrinomialTree trinomial = new TrinomialTree(numericDynamics.process(), grid, true);
final ShortRateTree numericTree = null;//new ShortRateTree(trinomial, numericDynamics, grid);
final TermStructureFittingParameter.NumericalImpl impl = (TermStructureFittingParameter.NumericalImpl) (phi.implementation());
impl.reset();
double /* @Real */value = 1.0;
final double /* @Real */vMin = -50.0;
final double /* @Real */vMax = 50.0;
for (int /* @Size */i = 0; i < (grid.size() - 1); i++) {
final double /* @Real */discountBond = termstructureConsistentModel.termStructure().currentLink().discount(grid.at(i + 1));
final double /* @Real */xMin = trinomial.underlying(i, 0);
final double /* @Real */dx = trinomial.dx(i);
final Helper finder = new BlackKarasinski.Helper(i, xMin, dx, discountBond, numericTree);
final Brent s1d = new Brent();
s1d.setMaxEvaluations(1000);
value = s1d.solve(finder, 1e-7, value, vMin, vMax);
impl.set(grid.index(i) /* [i] */, value);
// vMin = value - 10.0;
// vMax = value + 10.0;
}
return numericTree;
}
/**
* Short-rate dynamics in the Black-Karasinski model
*
* ! The short-rate is here \f[ r_t = e^{\varphi(t) + x_t} \f] where \f$ \varphi(t) \f$ is the deterministic time-dependent
* parameter (which can not be determined analytically) used for term-structure fitting and \f$ x_t \f$ is the state variable
* following an Ornstein-Uhlenbeck process.
*/
private class Dynamics extends ShortRateDynamics {
public Dynamics(final Parameter fitting, final double /* @Real */alpha, final double /* @Real */sigma) {
super(new OrnsteinUhlenbeckProcess(alpha, sigma, /* default */0.0, /* default */0.0));
fitting_ = (fitting);
}
@Override
public double /* @Real */variable(final double /* @Time */t, final double /* @Rate */r) {
return Math.log(r) - fitting_.get(t);
}
@Override
public double /* @Real */shortRate(final double /* @Time */t, final double /* @Real */x) {
return Math.exp(x + fitting_.get(t));
}
private final Parameter fitting_;
}
@Override
public Handle termStructure() {
return termstructureConsistentModel.termStructure();
}
}
Ads help maintain this website.