function Yield = bndyield(CleanPrice,CouponRate,Settle,Maturity,Period,Basis,Face)
% BNDYIELD 
% Yield = bndyield(CleanPrice,CouponRate,Settle,Maturity,Period,Basis,Face)
% Description: Returns yield to maturity for a fixed income security.
%
% Parameters:
% CleanPrice - current price without accrued interest
% CouponRate - decimal number (can be vector)
% Settle - settlement date (must be earlier than or equal to maturity)
% Maturity - maturity date
% Period (optional) - coupons per year of the bond; allowed values are
%     0, 1, 2 (default), 3, 4, 6 and 12
% Basis (optional) - day-count basis of the instrument; allowed values
%     are 0 for actual/actual (default), 1 for 30/360
% Face - face or par value of the bond (default = 100)
%
% Author: Mandy Partusch, apartusc@unlnotes.unl.edu
% Some code from bndprice.m by Byron Blunk
% Last updated by tshores 1/29/06
%
% This function is compatible with Matlab 7.0.1 and can be used with older
% versions after some minor changes.

% Local variables: 
% ii, t: index variables
% cf: vector of cash flows

if(nargin < 4)
	error('bndyield: Must have at least 4 arguments: CleanPrice, CouponRate, Settle, Maturity');
end
if(Settle > Maturity)
	error('bndyield: Settlement date must be earlier than or eaul to maturity date.');
end
% error handle that settle and maturity are dates


% set optional variables if not given
if (nargin < 5)
    Period = 2;
end

if (nargin < 6)
    Basis = 0;
end

if (nargin < 7)
    Face = 100;
end

% check that basis is valid
if (Basis ~= 0 && Basis ~= 1)
	error('bndyield: Basis must be 0 (actual/actual) or 1 (30/360).');
end

% Check that inputs are not vectors.
if ( ~isscalar(Settle) || ~isscalar(Maturity) || ~isscalar(Period) ...
	|| ~isscalar(Basis) || ~isscalar(Face))
    error('bndyield: input values must be scalars.')
end

%Make sure CouponRate is in column vector form
CouponRate = CouponRate(:);
%Given the period, calculate the value of each coupon payment
couponPayment = CouponRate * Face / Period;

%Find the next coupon date
settleVec = datevec(Settle);
maturityVec = datevec(Maturity);

% If the settle month is before the maturity month, coupon is on the maturity month 
couponDate = [settleVec(1) maturityVec(2) maturityVec(3)];
% month equals the maturity month but the settle day falls after the
% maturity day, then the coupon month is 12/Period months after the maturity
% month
if ((settleVec(2) > maturityVec(2)) || ((settleVec(2) == maturityVec(2)) && (settleVec(3) > maturityVec(3))))
    couponDate = addtodate(datenum(couponDate),12/Period,'month');
end

%Use Actual/Actual
if (Basis == 0)    
    % Find the number of days remaining in the current coupon
    couponDaysRemaining = daysact(Settle, datenum(couponDate));
    % Find the number of days elapsed in the current coupon
    couponDaysElapsed = daysact(addtodate(datenum(couponDate),-6,'month'), Settle);
    % Find the total number of days in the current coupon period
    totalCouponDays = daysact(addtodate(datenum(couponDate),-6,'month'),datenum(couponDate));    
    % Get the remaining days in the bond
    remainingDaysinBond = daysact(datenum(couponDate), Maturity);
% Use 30/360
else
    % Find the number of days remaining in the current coupon
    couponDaysRemaining = days360(Settle, datenum(couponDate));
    % Find the number of days elapsed in the current coupon
    couponDaysElapsed = days360(addtodate(datenum(couponDate),-6,'month'), Settle);
    % Find the total number of days in the current coupon period
    totalCouponDays = days360(addtodate(datenum(couponDate),-6,'month'),datenum(couponDate));
    % Get the remaining days in the bond
    remainingDaysinBond = days360(datenum(couponDate), Maturity);
end

% From the number of days, find the number of upcoming coupons
% Note this does not factor leap years into consideration
numCoupons = floor(remainingDaysinBond / 365) * Period + 1;

% set cash flows
cf = repmat(couponPayment, 1, numCoupons);
cf(:,numCoupons) = couponPayment + Face;

% build cash flow vector
cf = [CleanPrice * -1, Face.*CouponRate*ones(1, numCoupons-1), Face*(1 + CouponRate)];

Yield = irr(cf);