/*
Copyright (C) 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
<jquant-devel@lists.sourceforge.net>. The license is also available online at
<http://www.jquantlib.org/index.php/LICENSE.TXT>.
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) 2000, 2001, 2002, 2003 RiskMap srl
Copyright (C) 2003, 2004 StatPro Italia srl
Copyright (C) 2003 Nicolas Di C�sar�
Copyright (C) 2006, 2007 Cristina Duminuco
Copyright (C) 2006 Ferdinando Ametrano
Copyright (C) 2007 Giorgio Facchinetti
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
<quantlib-dev@lists.sf.net>. The license is also available online at
<http://quantlib.org/license.shtml>.
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.cashflow;
import org.jquantlib.QL;
import org.jquantlib.Settings;
import org.jquantlib.daycounters.DayCounter;
import org.jquantlib.indexes.InterestRateIndex;
import org.jquantlib.quotes.Handle;
import org.jquantlib.termstructures.YieldTermStructure;
import org.jquantlib.time.BusinessDayConvention;
import org.jquantlib.time.Date;
import org.jquantlib.time.TimeUnit;
import org.jquantlib.util.Observer;
import org.jquantlib.util.TypedVisitor;
import org.jquantlib.util.Visitor;
/**
*
* @author Ueli Hofstetter
*/
// TODO: code review :: license, class comments, comments for access modifiers, comments for @Override
// TODO: code review :: Please review this class! :S
public class FloatingRateCoupon extends Coupon implements Observer {
private static final String null_gearing = "Null gearing: degenerate Floating Rate Coupon not admitted";
private static final String no_adequate_pricer_given = "no adequate pricer given";
private static final String pricer_not_set = "pricer not set";
//
// private final fields
//
private final DayCounter dayCounter;
private int fixingDays; // FIXME - JM:: should be final
private final double spread;
private final boolean isInArrears;
//
// private fields
//
/**
* convexity adjustment for the given index fixing
*/
// TODO: what's the need of it?
//XXX private double convexityAdjustmentImpl;
protected FloatingRateCouponPricer pricer;
//TODO: code review :: please verify comment below against QL/C++ code
//XXX (Rate fixing) const;
//
// protected fields
//
//TODO: code review :: please verify against QL/C++ code
protected final double gearing_;
//TODO: code review :: please verify against QL/C++ code
protected final InterestRateIndex index_;
//
// public constructors
//
public FloatingRateCoupon(
final Date paymentDate,
final double nominal,
final Date startDate,
final Date endDate,
final int fixingDays,
final InterestRateIndex index,
final double gearing,
final double spread,
final Date refPeriodStart,
final Date refPeriodEnd,
final DayCounter dayCounter,
final boolean isInArrears) {
super(nominal, paymentDate, startDate, endDate, refPeriodStart, refPeriodEnd);
if (System.getProperty("EXPERIMENTAL") == null) {
throw new UnsupportedOperationException("Work in progress");
}
// TODO: code review :: please verify against QL/C++ code
QL.require(gearing > 0 , null_gearing); // QA:[RG]::verified
this.index_ = index;
this.fixingDays = (fixingDays == 0 ? index.fixingDays() : fixingDays);
this.gearing_ = gearing;
this.spread = spread;
this.isInArrears = isInArrears;
if (dayCounter != null) {
this.dayCounter = dayCounter;
} else {
this.dayCounter = index_.dayCounter();
}
final Date evaluationDate = new Settings().evaluationDate();
// TODO: code review :: please verify against QL/C++ code
// seems like we should have this.evaluationDate
this.index_.addObserver(this);
evaluationDate.addObserver(this);
//XXX:registerWith
//registerWith(this.index_);
//registerWith(evaluationDate);
}
//
// public methods
//
// TODO: code review :: please verify against QL/C++ code
public void setPricer(final FloatingRateCouponPricer pricer){
QL.require(pricer != null , no_adequate_pricer_given);
if (this.pricer != null) {
this.pricer.deleteObserver(this);
}
//XXX:registerWith
//unregisterWith(this.pricer);
this.pricer = pricer;
this.pricer.addObserver(this);
//XXX:registerWith
//registerWith(this.pricer);
update();
}
@Override
public double amount(){
return rate() * accrualPeriod() * nominal();
}
public double price(final Handle<YieldTermStructure> discountingCurve){
return amount()*discountingCurve.currentLink().discount(date());
}
public InterestRateIndex index() {
return index_;
}
public int fixingDays() {
return fixingDays;
}
public Date fixingDate() {
// if isInArrears_ fix at the end of period
final Date refDate = isInArrears ? accrualEndDate : accrualStartDate;
// FIXME: "isInArrears" : not specified in original implementation
return index_.fixingCalendar().advance(refDate, -fixingDays, TimeUnit.Days, BusinessDayConvention.Preceding, isInArrears);
}
public double gearing() {
return gearing_;
}
public double spread() {
return spread;
}
public double indexFixing() {
return index_.fixing(fixingDate());
}
public double adjustedFixing(){
return (rate()-spread())/gearing();
}
// TODO: code review :: Please review this method! What's the need of it???
public double convexityAdjustmentImpl(final double f) {
return (gearing() == 0.0 ? 0.0 : adjustedFixing()-f);
}
public double convexityAdjustment() {
return convexityAdjustmentImpl(indexFixing());
}
public boolean isInArrears(){
return isInArrears;
}
// FIXME move up the stack to specifiy fixing array
// for now use this function will refactor jan 2010
public void setFixingDays(final int fixingDays) {
this.fixingDays = fixingDays;
}
//
// Overrides Coupon
//
@Override
public DayCounter dayCounter() {
return dayCounter;
}
@Override
public double rate() {
QL.require(this.pricer != null, pricer_not_set);
// TODO: code review :: please verify against QL/C++ code
this.pricer.initialize(this);
return this.pricer.swapletRate();
}
@Override
public double accruedAmount(final Date date) {
// TODO: code review :: please verify against QL/C++ code
throw new UnsupportedOperationException();
}
//
// implements Observer
//
@Override
public void update() {
notifyObservers();
}
//XXX:registerWith
// @Override
// public void registerWith(final Observable o) {
// o.addObserver(this);
// }
//
// @Override
// public void unregisterWith(final Observable o) {
// o.deleteObserver(this);
// }
//
// implements TypedVisitable
//
@Override
public void accept(final TypedVisitor<Object> v) {
final Visitor<Object> v1 = (v!=null) ? v.getVisitor(this.getClass()) : null;
if (v1 != null) {
v1.visit(this);
} else {
super.accept(v) ;
}
}
}