/*
Copyright (C) 2007 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.
*/
/*
Copyright (C) 2001, 2002, 2003 Sadruddin Rejeb
Copyright (C) 2006 Ferdinando Ametrano
Copyright (C) 2006 Fran�ois du Vignaud
Copyright (C) 2006, 2007 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.instruments;
import java.util.List;
import org.jquantlib.QL;
import org.jquantlib.Settings;
import org.jquantlib.cashflow.CashFlow;
import org.jquantlib.cashflow.CashFlows;
import org.jquantlib.cashflow.FloatingRateCoupon;
import org.jquantlib.cashflow.Leg;
import org.jquantlib.lang.exceptions.LibraryException;
import org.jquantlib.pricingengines.PricingEngine;
import org.jquantlib.quotes.Handle;
import org.jquantlib.termstructures.YieldTermStructure;
import org.jquantlib.time.Date;
/**
* Base class for cap-like instruments
*
* @category instruments
*
* @author Ueli Hofstetter
*/
public class CapFloor extends Instrument {
public enum Type { Cap, Floor, Collar };
private final Type type_;
private final Leg floatingLeg_;
private List*@Rate*/ Double> capRates_;
private List*@Rate*/ Double> floorRates_;
private final Handle termStructure_;
public CapFloor(
final CapFloor.Type type,
final Leg floatingLeg,
final List*@Rate*/ Double> capRates,
final List*@Rate*/ Double> floorRates,
final Handle termStructure,
final PricingEngine engine){
QL.validateExperimentalMode();
this.type_ = type;
this.floatingLeg_ = floatingLeg;
this.capRates_ = capRates;
this.floorRates_ = floorRates;
this.termStructure_ = termStructure;
setPricingEngine(engine);
if (type_ == Type.Cap || type_ == Type.Collar) {
QL.require(capRates_.size()>0 , "no cap rates given"); // TODO: message
// capRates_.reserve(floatingLeg_.size());
while (capRates_.size() < floatingLeg_.size()) {
// this looks kind of suspicious...
capRates_.add(capRates_.get(capRates_.size() - 1));
}
}
if (type_ == Type.Floor || type_ == Type.Collar) {
QL.require(floorRates_.size()>0 , "no floor rates given"); // TODO: message
// floorRates_.reserve(floatingLeg_.size());
while (floorRates_.size() < floatingLeg_.size()) {
floorRates_.add(floorRates_.get(floorRates_.size() - 1));
}
}
final Date evaluationDate = new Settings().evaluationDate();
for (final CashFlow cashFlow : floatingLeg_) {
cashFlow.addObserver(this);
}
// TODO: code review :: please verify against QL/C++ code
// seems like we should have this.evaluationDate
this.termStructure_.addObserver(this);
evaluationDate.addObserver(this);
}
public CapFloor(
final Type type,
final Leg floatingLeg,
final List*@Rate*/ Double> strikes,
final Handle termStructure,
final PricingEngine engine){
if (System.getProperty("EXPERIMENTAL") == null)
throw new UnsupportedOperationException("Work in progress");
this.type_ = type;
this.floatingLeg_ = floatingLeg;
this.termStructure_ = termStructure;
setPricingEngine(engine);
QL.require(strikes.size()>0 , "no strikes given"); // TODO: message
if (type_ == Type.Cap) {
capRates_ = strikes;
//capRates_.reserve(floatingLeg_.size());
while (capRates_.size() < floatingLeg_.size()) {
capRates_.add(capRates_.get(capRates_.size()-1));
}
} else if (type_ == Type.Floor) {
floorRates_ = strikes;
//floorRates_.reserve(floatingLeg_.size());
while (floorRates_.size() < floatingLeg_.size()) {
floorRates_.add(floorRates_.get(floorRates_.size()-1));
}
} else
throw new LibraryException("only Cap/Floor types allowed in this constructor"); // TODO: message
final Date evaluationDate = new Settings().evaluationDate();
for (final CashFlow cashFlow : floatingLeg_) {
cashFlow.addObserver(this);
}
// TODO: code review :: please verify against QL/C++ code
// Seems like we should have this.evaluationDate
this.termStructure_.addObserver(this);
evaluationDate.addObserver(this);
}
public /*@Rate*/double atmRate(){
return CashFlows.getInstance().atmRate(floatingLeg_, termStructure_);
}
@Override
public boolean isExpired(){
Date lastPaymentDate = Date.minDate();
for (int i=0; i(args);
// QL_REQUIRE(arguments != 0, "wrong argument type");
//
// Size n = floatingLeg_.size();
//
// arguments->startTimes.clear();
// arguments->startTimes.reserve(n);
//
// arguments->fixingDates.clear();
// arguments->fixingDates.reserve(n);
//
// arguments->fixingTimes.clear();
// arguments->fixingTimes.reserve(n);
//
// arguments->endTimes.clear();
// arguments->endTimes.reserve(n);
//
// arguments->accrualTimes.clear();
// arguments->accrualTimes.reserve(n);
//
// arguments->forwards.clear();
//
// arguments->discounts.clear();
//
// arguments->nominals.clear();
// arguments->nominals.reserve(n);
//
// arguments->gearings.clear();
// arguments->gearings.reserve(n);
//
// arguments->capRates.clear();
//
// arguments->floorRates.clear();
//
// arguments->type = type_;
//
// Date today = Settings::instance().evaluationDate();
// Date settlement = termStructure_->referenceDate();
// DayCounter counter = termStructure_->dayCounter();
//
// for (Size i=0; i coupon =
// boost::dynamic_pointer_cast(floatingLeg_[i]);
// QL_REQUIRE(coupon, "non-iborCoupon given");
// Date beginDate = coupon->accrualStartDate();
// Time time = counter.yearFraction(settlement, beginDate);
// arguments->startTimes.push_back(time);
// Date fixingDate = coupon->fixingDate();
// arguments->fixingDates.push_back(fixingDate);
// time = counter.yearFraction(today, fixingDate);
// arguments->fixingTimes.push_back(time);
// time = counter.yearFraction(settlement, coupon->date());
// arguments->endTimes.push_back(time);
// // this is passed explicitly for precision
// arguments->accrualTimes.push_back(coupon->accrualPeriod());
// // this is passed explicitly for precision
// if (arguments->endTimes.back() >= 0.0) { // but only if needed
// arguments->forwards.push_back(coupon->adjustedFixing());
// arguments->discounts.push_back(
// termStructure_->discount(coupon->date()));
// } else {
// arguments->forwards.push_back(Null());
// arguments->discounts.push_back(Null());
// }
// arguments->nominals.push_back(coupon->nominal());
// Spread spread = coupon->spread();
// Real gearing = coupon->gearing();
// QL_REQUIRE(gearing > 0.0, "positive gearing required");
// arguments->gearings.push_back(gearing);
// arguments->spreads.push_back(spread);
// if (type_ == Cap || type_ == Collar)
// arguments->capRates.push_back((capRates_[i]-spread)/gearing);
// if (type_ == Floor || type_ == Collar)
// arguments->floorRates.push_back(
// (floorRates_[i]-spread)/gearing);
// }
//}
//void CapFloor::arguments::validate() const {
// QL_REQUIRE(endTimes.size() == startTimes.size(),
// "number of start times (" << startTimes.size()
// << ") different from that of end times ("
// << endTimes.size() << ")");
// QL_REQUIRE(accrualTimes.size() == startTimes.size(),
// "number of start times (" << startTimes.size()
// << ") different from that of accrual times ("
// << accrualTimes.size() << ")");
// QL_REQUIRE(type == CapFloor::Floor ||
// capRates.size() == startTimes.size(),
// "number of start times (" << startTimes.size()
// << ") different from that of cap rates ("
// << capRates.size() << ")");
// QL_REQUIRE(type == CapFloor::Cap ||
// floorRates.size() == startTimes.size(),
// "number of start times (" << startTimes.size()
// << ") different from that of floor rates ("
// << floorRates.size() << ")");
// QL_REQUIRE(gearings.size() == startTimes.size(),
// "number of start times (" << startTimes.size()
// << ") different from that of gearings ("
// << floorRates.size() << ")");
// QL_REQUIRE(nominals.size() == startTimes.size(),
// "number of start times (" << startTimes.size()
// << ") different from that of nominals ("
// << nominals.size() << ")");
//}
//
//Volatility CapFloor::impliedVolatility(Real targetValue,
// Real accuracy,
// Size maxEvaluations,
// Volatility minVol,
// Volatility maxVol) const {
// calculate();
// QL_REQUIRE(!isExpired(), "instrument expired");
//
// Volatility guess = 0.10; // no way we can get a more accurate one
//
// ImpliedVolHelper f(*this, termStructure_, targetValue);
// Brent solver;
// //NewtonSafe solver;
// solver.setMaxEvaluations(maxEvaluations);
// return solver.solve(f, accuracy, guess, minVol, maxVol);
//}
//
//
//CapFloor::ImpliedVolHelper::ImpliedVolHelper(
// const CapFloor& cap,
// const Handle& termStructure,
// Real targetValue)
//: termStructure_(termStructure), targetValue_(targetValue) {
//
// vol_ = boost::shared_ptr(new SimpleQuote(0.0));
// Handle h(vol_);
// engine_ = boost::shared_ptr(new BlackCapFloorEngine(h));
// cap.setupArguments(engine_->getArguments());
//
// results_ =
// dynamic_cast(engine_->getResults());
//}
//
//Real CapFloor::ImpliedVolHelper::operator()(Volatility x) const {
// vol_->setValue(x);
// engine_->calculate();
// return results_->value-targetValue_;
//}
//
//Real CapFloor::ImpliedVolHelper::derivative(Volatility x) const {
// vol_->setValue(x);
// engine_->calculate();
// return 0.0;
// //return results_->vega;
//}
//
//std::ostream& operator<<(std::ostream& out, CapFloor::Type t) {
// switch (t) {
// case CapFloor::Cap:
// return out << "Cap";
// case CapFloor::Floor:
// return out << "Floor";
// case CapFloor::Collar:
// return out << "Collar";
// default:
// QL_FAIL("unknown CapFloor::Type (" << Integer(t) << ")");
// }
//}
@Override
protected void performCalculations() throws ArithmeticException {
// TODO Auto-generated method stub
}
@Override
protected void setupArguments(final PricingEngine.Arguments arguments) {
// TODO Auto-generated method stub
}
// */
// class CapFloor : public Instrument {
// public:
// enum Type { Cap, Floor, Collar };
// class arguments;
// class engine;
// CapFloor(Type type,
// const Leg& floatingLeg,
// const std::vector& capRates,
// const std::vector& floorRates,
// const Handle& termStructure,
// const boost::shared_ptr& engine);
// CapFloor(Type type,
// const Leg& floatingLeg,
// const std::vector& strikes,
// const Handle& termStructure,
// const boost::shared_ptr& engine);
// //! \name Instrument interface
// //@{
// bool isExpired() const;
// void setupArguments(PricingEngine::arguments*) const;
// //@}
// //! \name Inspectors
// //@{
// Type type() const { return type_; }
// const Leg& leg() const {
// return floatingLeg_;
// }
// const std::vector& capRates() const {
// return capRates_;
// }
// const std::vector& floorRates() const {
// return floorRates_;
// }
// const Leg& floatingLeg() const {
// return floatingLeg_;
// }
// Rate atmRate() const;
// Date startDate() const;
// Date maturityDate() const;
// Date lastFixingDate() const;
// //@}
// //! implied term volatility
// Volatility impliedVolatility(Real price,
// Real accuracy = 1.0e-4,
// Size maxEvaluations = 100,
// Volatility minVol = 1.0e-7,
// Volatility maxVol = 4.0) const;
// private:
// Type type_;
// Leg floatingLeg_;
// std::vector capRates_;
// std::vector floorRates_;
// Handle termStructure_;
// // helper class for implied USE_INDEXEDvolatility calculation
// class ImpliedVolHelper {
// public:
// ImpliedVolHelper(const CapFloor&,
// const Handle&,
// Real targetValue);
// Real operator()(Volatility x) const;
// Real derivative(Volatility x) const;
// private:
// boost::shared_ptr engine_;
// Handle termStructure_;
// Real targetValue_;
// boost::shared_ptr vol_;
// const Instrument::results* results_;
// };
// };
//
// //! Concrete cap class
// /*! \ingroup instruments */
// class Cap : public CapFloor {
// public:
// Cap(const Leg& floatingLeg,
// const std::vector& exerciseRates,
// const Handle& termStructure,
// const boost::shared_ptr& engine)
// : CapFloor(CapFloor::Cap, floatingLeg,
// exerciseRates, std::vector(),
// termStructure, engine) {}
// };
//
// //! Concrete floor class
// /*! \ingroup instruments */
// class Floor : public CapFloor {
// public:
// Floor(const Leg& floatingLeg,
// const std::vector& exerciseRates,
// const Handle& termStructure,
// const boost::shared_ptr& engine)
// : CapFloor(CapFloor::Floor, floatingLeg,
// std::vector(), exerciseRates,
// termStructure, engine) {}
// };
//
// //! Concrete collar class
// /*! \ingroup instruments */
// class Collar : public CapFloor {
// public:
// Collar(const Leg& floatingLeg,
// const std::vector& capRates,
// const std::vector& floorRates,
// const Handle& termStructure,
// const boost::shared_ptr& engine)
// : CapFloor(CapFloor::Collar, floatingLeg, capRates, floorRates,
// termStructure, engine) {}
// };
//
//
// //! %Arguments for cap/floor calculation
// class CapFloor::arguments : public virtual PricingEngine::arguments {
// public:
// arguments() : type(CapFloor::Type(-1)) {}
// CapFloor::Type type;
// std::vector
Ads help maintain this website.