You've already forked lazarus-ccr
applications
bindings
components
Comba_Animation
aboutcomponent
acs
beepfp
callite
chelper
chemtext
cmdline
cmdlinecfg
colorpalette
cryptini
csvdocument
epiktimer
examplecomponent
extrasyn
fpexif
fpsound
fpspreadsheet
fractions
freetypepascal
geckoport
gradcontrols
grid_semaphor
industrialstuff
iosdesigner
iphonelazext
jujiboutils
jvcllaz
kcontrols
lazautoupdate
lazbarcodes
lazmapviewer
lclextensions
longtimer
manualdock
mbColorLib
mplayer
multithreadprocs
nvidia-widgets
onguard
orpheus
playsoundpackage
poweredby
powerpdf
rgbgraphics
richmemo
richview
rtfview
rx
scrolltext
smnetgradient
spktoolbar
svn
systools
examples
images
source
db
general
design
run
st2dbarc.pas
stastro.pas
stastrop.pas
stbarc.pas
stbarpn.pas
stbase.pas
stbcd.pas
stbits.pas
stccy.dat
stccycnv.dat
stcoll.pas
stconst.pas
stcrc.pas
stdate.pas
stdatest.pas
stdecmth.pas
stdict.pas
stdque.pas
steclpse.pas
stexpr.pas
stexpr.txt
stfin.pas
sthash.pas
stinistm.pas
stjup.pas
stjupsat.pas
stlarr.pas
stlist.pas
stmars.pas
stmath.pas
stmerc.pas
stmerge.pas
stmoney.pas
stneptun.pas
stnvbits.pas
stnvcoll.pas
stnvcont.pas
stnvdict.pas
stnvdq.pas
stnvlary.pas
stnvlist.pas
stnvlmat.pas
stnvscol.pas
stnvtree.pas
stpluto.pas
stpqueue.pas
stptrns.pas
strandom.pas
stregex.pas
stsaturn.pas
ststat.pas
ststrl.pas
ststrms.pas
ststrs.pas
sttext.pas
sttohtml.pas
sttree.pas
sttxtdat.pas
sturanus.pas
stutils.pas
stvarr.pas
stvenus.pas
include
windows_only
laz_systools.lpk
laz_systools.pas
laz_systools_all.lpg
laz_systools_design.lpk
laz_systools_design.pas
laz_systoolsdb.lpk
laz_systoolsdb.pas
laz_systoolsdb_design.lpk
laz_systoolsdb_design.pas
laz_systoolswin.lpk
laz_systoolswin.pas
laz_systoolswin_design.lpk
laz_systoolswin_design.pas
readme-orig.txt
readme.txt
readme404pre.txt
tdi
thtmlport
tparadoxdataset
tvplanit
xdev_toolkit
zlibar
zmsql
examples
image_sources
lclbindings
wst
1313 lines
43 KiB
ObjectPascal
1313 lines
43 KiB
ObjectPascal
![]() |
// Upgraded to Delphi 2009: Sebastian Zierer
|
||
|
|
||
|
(* ***** BEGIN LICENSE BLOCK *****
|
||
|
* Version: MPL 1.1
|
||
|
*
|
||
|
* The contents of this file are subject to the Mozilla Public License Version
|
||
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
||
|
* the License. You may obtain a copy of the License at
|
||
|
* http://www.mozilla.org/MPL/
|
||
|
*
|
||
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
||
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||
|
* for the specific language governing rights and limitations under the
|
||
|
* License.
|
||
|
*
|
||
|
* The Original Code is TurboPower SysTools
|
||
|
*
|
||
|
* The Initial Developer of the Original Code is
|
||
|
* TurboPower Software
|
||
|
*
|
||
|
* Portions created by the Initial Developer are Copyright (C) 1996-2002
|
||
|
* the Initial Developer. All Rights Reserved.
|
||
|
*
|
||
|
* Contributor(s):
|
||
|
*
|
||
|
* ***** END LICENSE BLOCK ***** *)
|
||
|
|
||
|
{*********************************************************}
|
||
|
{* SysTools: StFIN.pas 4.04 *}
|
||
|
{*********************************************************}
|
||
|
{* SysTools: Financial math functions modeled on *}
|
||
|
{* those in Excel *}
|
||
|
{*********************************************************}
|
||
|
|
||
|
{$IFDEF FPC}
|
||
|
{$mode DELPHI}
|
||
|
{$ENDIF}
|
||
|
|
||
|
//{$I StDefine.inc}
|
||
|
|
||
|
unit StFIN;
|
||
|
|
||
|
interface
|
||
|
|
||
|
uses
|
||
|
{$IFNDEF FPC}
|
||
|
Windows,
|
||
|
{$ENDIF}
|
||
|
{$IFDEF UseMathUnit}
|
||
|
Math,
|
||
|
{$ELSE}
|
||
|
StMath,
|
||
|
{$ENDIF}
|
||
|
SysUtils,
|
||
|
StBase,
|
||
|
StConst,
|
||
|
StDate;
|
||
|
|
||
|
type
|
||
|
TStPaymentTime = (ptEndOfPeriod, ptStartOfPeriod);
|
||
|
TStFrequency = (fqAnnual, fqSemiAnnual, fqQuarterly, fqMonthly);
|
||
|
TStBasis = (BasisNASD, {US (NASD) 30/360}
|
||
|
BasisActAct, {Actual/actual}
|
||
|
BasisAct360, {Actual/360}
|
||
|
BasisAct365, {Actual/365}
|
||
|
BasisEur30360); {European 30/360}
|
||
|
|
||
|
TStDateArray = array[0..(StMaxBlockSize div SizeOf(TStDate))-1] of TStDate;
|
||
|
|
||
|
|
||
|
const
|
||
|
StDelta : Extended = 0.00001; {delta for difference equations}
|
||
|
StEpsilon : Extended = 0.00001; {epsilon for difference equations}
|
||
|
StMaxIterations : Integer = 100; {max attempts for convergence}
|
||
|
|
||
|
|
||
|
function AccruedInterestMaturity(Issue, Maturity : TStDate;
|
||
|
Rate, Par : Extended;
|
||
|
Basis : TStBasis) : Extended;
|
||
|
{-Returns the accrued interest for a security that pays interest at maturity}
|
||
|
|
||
|
function AccruedInterestPeriodic(Issue, Settlement, Maturity : TStDate;
|
||
|
Rate, Par : Extended;
|
||
|
Frequency : TStFrequency;
|
||
|
Basis : TStBasis) : Extended;
|
||
|
{-Returns the accrued interest for a security that pays periodic interest}
|
||
|
|
||
|
function BondDuration(Settlement, Maturity : TStDate;
|
||
|
Rate, Yield : Extended;
|
||
|
Frequency : TStFrequency;
|
||
|
Basis : TStBasis) : Extended;
|
||
|
{-Returns the Macauley duration for an assumed par value of $100}
|
||
|
|
||
|
function BondPrice(Settlement, Maturity : TStDate;
|
||
|
Rate, Yield, Redemption : Extended;
|
||
|
Frequency : TStFrequency;
|
||
|
Basis : TStBasis) : Extended;
|
||
|
{-Returns the "clean" bond price per $100 face value of a security}
|
||
|
|
||
|
function CumulativeInterest(Rate : Extended;
|
||
|
NPeriods : Integer;
|
||
|
PV : Extended;
|
||
|
StartPeriod, EndPeriod : Integer;
|
||
|
Frequency : TStFrequency;
|
||
|
Timing : TStPaymentTime) : Extended;
|
||
|
{-Returns the cumulative interest paid on a loan in specified periods}
|
||
|
|
||
|
function CumulativePrincipal(Rate : Extended;
|
||
|
NPeriods : Integer;
|
||
|
PV : Extended;
|
||
|
StartPeriod, EndPeriod : Integer;
|
||
|
Frequency : TStFrequency;
|
||
|
Timing : TStPaymentTime) : Extended;
|
||
|
{-Returns the cumulative principal paid on a loan in specified periods}
|
||
|
|
||
|
function DayCount(Day1, Day2 : TStDate; Basis : TStBasis) : LongInt;
|
||
|
{-Returns the number of days from Day1 to Day2 according to day count basis}
|
||
|
|
||
|
function DecliningBalance(Cost, Salvage : Extended;
|
||
|
Life, Period, Month : Integer) : Extended;
|
||
|
{-Fixed rate declining balance depreciation}
|
||
|
|
||
|
function DiscountRate(Settlement, Maturity : TStDate;
|
||
|
Price, Redemption : Extended;
|
||
|
Basis : TStBasis) : Extended;
|
||
|
{-Returns the discount Rate for a security}
|
||
|
|
||
|
function DollarToDecimal(FracDollar : Extended;
|
||
|
Fraction : Integer) : Extended;
|
||
|
{-Converts a fractional dollar value to decimal dollar value}
|
||
|
|
||
|
function DollarToDecimalText(DecDollar : Extended) : string;
|
||
|
{-Converts a decimal dollar value into an English text string}
|
||
|
|
||
|
function DollarToFraction(DecDollar : Extended;
|
||
|
Fraction : Integer) : Extended;
|
||
|
{-Converts a decimal dollar value to fractional dollar value}
|
||
|
|
||
|
function DollarToFractionStr(FracDollar : Extended;
|
||
|
Fraction : Integer) : string;
|
||
|
{-Converts a fractional dollar value to number string}
|
||
|
|
||
|
function EffectiveInterestRate(NominalRate : Extended;
|
||
|
Frequency : TStFrequency) : Extended;
|
||
|
{-Converts nominal annual interest Rate to effective Rate}
|
||
|
|
||
|
function FutureValue(Rate : Extended;
|
||
|
NPeriods : Integer;
|
||
|
Pmt, PV : Extended;
|
||
|
Frequency : TStFrequency;
|
||
|
Timing: TStPaymentTime) : Extended;
|
||
|
{-Returns the future value of an annuity}
|
||
|
|
||
|
function FutureValueSchedule(Principal : Extended;
|
||
|
const Schedule : array of Double) : Extended;
|
||
|
|
||
|
function FutureValueSchedule16(Principal : Extended;
|
||
|
const Schedule; NRates : Integer) : Extended;
|
||
|
{-Returns the future value of investment with variable interest rates}
|
||
|
|
||
|
function InterestRate(NPeriods : Integer;
|
||
|
Pmt, PV, FV : Extended;
|
||
|
Frequency : TStFrequency;
|
||
|
Timing : TStPaymentTime;
|
||
|
Guess : Extended) : Extended;
|
||
|
{-Returns the interest Rate per period of an annuity}
|
||
|
|
||
|
function InternalRateOfReturn(const Values : array of Double;
|
||
|
Guess : Extended) : Extended;
|
||
|
|
||
|
function InternalRateOfReturn16(const Values; NValues : Integer;
|
||
|
Guess : Extended) : Extended;
|
||
|
{-Returns internal rate of return of a series of periodic cash flows}
|
||
|
|
||
|
function IsCardValid(const S : string) : Boolean;
|
||
|
{-Checks for valid credit card number (MasterCard, Visa, AMEX, Discover)}
|
||
|
|
||
|
function ModifiedDuration(Settlement, Maturity : TStDate;
|
||
|
Rate, Yield : Extended;
|
||
|
Frequency : TStFrequency;
|
||
|
Basis : TStBasis) : Extended;
|
||
|
{-Returns the modified duration for bond with an assumed par value of $100}
|
||
|
|
||
|
function ModifiedIRR(const Values : array of Double;
|
||
|
FinanceRate, ReinvestRate : Extended) : Extended;
|
||
|
|
||
|
function ModifiedIRR16(const Values; NValues : Integer;
|
||
|
FinanceRate, ReinvestRate : Extended) : Extended;
|
||
|
{-Returns the MIRR for a series of periodic cash flows}
|
||
|
|
||
|
function NetPresentValue(Rate : Extended;
|
||
|
const Values : array of Double) : Extended;
|
||
|
|
||
|
function NetPresentValue16(Rate : Extended;
|
||
|
const Values; NValues : Integer) : Extended;
|
||
|
{-Returns the net present value of a series of periodic cash flows}
|
||
|
|
||
|
function NominalInterestRate(EffectRate : Extended;
|
||
|
Frequency : TStFrequency) : Extended;
|
||
|
{-Converts effective annual interest Rate to nominal Rate}
|
||
|
|
||
|
function NonperiodicIRR(const Values : array of Double;
|
||
|
const Dates : array of TStDate;
|
||
|
Guess : Extended) : Extended;
|
||
|
|
||
|
function NonperiodicIRR16(const Values;
|
||
|
const Dates; NValues : Integer;
|
||
|
Guess : Extended) : Extended;
|
||
|
{-Returns the IRR for a series of irregular cash flows}
|
||
|
|
||
|
function NonperiodicNPV(Rate : Extended;
|
||
|
const Values : array of Double;
|
||
|
const Dates : array of TStDate) : Extended;
|
||
|
|
||
|
function NonperiodicNPV16(Rate : Extended;
|
||
|
const Values;
|
||
|
const Dates;
|
||
|
NValues : Integer) : Extended;
|
||
|
{-Returns the net present value for a series of irregular cash flows}
|
||
|
|
||
|
function Payment(Rate : Extended;
|
||
|
NPeriods : Integer;
|
||
|
PV, FV : Extended;
|
||
|
Frequency : TStFrequency;
|
||
|
Timing : TStPaymentTime) : Extended;
|
||
|
{-Returns the interest payment per period in an annuity}
|
||
|
|
||
|
function Periods(Rate : Extended;
|
||
|
Pmt, PV, FV : Extended;
|
||
|
Frequency : TStFrequency;
|
||
|
Timing: TStPaymentTime) : Integer;
|
||
|
{-Returns the number of periods for an annuity}
|
||
|
|
||
|
function PresentValue(Rate : Extended;
|
||
|
NPeriods : Integer;
|
||
|
Pmt, FV : Extended;
|
||
|
Frequency : TStFrequency;
|
||
|
Timing : TStPaymentTime) : Extended;
|
||
|
{-Returns present value of an annity}
|
||
|
|
||
|
function ReceivedAtMaturity(Settlement, Maturity : TStDate;
|
||
|
Investment, Discount : Extended;
|
||
|
Basis : TStBasis) : Extended;
|
||
|
{-Returns the amount received at Maturity for a fully invested security}
|
||
|
|
||
|
function RoundToDecimal(Value : Extended;
|
||
|
Places : Integer;
|
||
|
Bankers : Boolean) : Extended;
|
||
|
{-Rounds a real value to the specified number of decimal places}
|
||
|
|
||
|
function TBillEquivYield(Settlement, Maturity : TStDate;
|
||
|
Discount : Extended) : Extended;
|
||
|
{-Returns the bond-equivalent yield for a treasury bill}
|
||
|
|
||
|
function TBillPrice(Settlement, Maturity : TStDate;
|
||
|
Discount : Extended) : Extended;
|
||
|
{-Returns the price per $100 face value for a treasury bill}
|
||
|
|
||
|
function TBillYield(Settlement, Maturity : TStDate;
|
||
|
Price : Extended) : Extended;
|
||
|
{-Returns the yield for a treasury bill}
|
||
|
|
||
|
function VariableDecliningBalance(Cost, Salvage : Extended;
|
||
|
Life : Integer;
|
||
|
StartPeriod, EndPeriod, Factor : Extended;
|
||
|
NoSwitch : boolean) : Extended;
|
||
|
{-Variable rate declining balance depreciation}
|
||
|
|
||
|
function YieldDiscounted(Settlement, Maturity : TStDate;
|
||
|
Price, Redemption : Extended;
|
||
|
Basis : TStBasis) : Extended;
|
||
|
{-Returns the annual yield for a discounted security}
|
||
|
|
||
|
function YieldPeriodic(Settlement, Maturity : TStDate;
|
||
|
Rate, Price, Redemption : Extended;
|
||
|
Frequency : TStFrequency;
|
||
|
Basis : TStBasis) : Extended;
|
||
|
{-Returns the yield on a security that pays periodicinterest}
|
||
|
|
||
|
function YieldMaturity(Issue, Settlement, Maturity : TStDate;
|
||
|
Rate, Price : Extended;
|
||
|
Basis : TStBasis) : Extended;
|
||
|
{-Returns the annual yield of a security that pays interest at Maturity}
|
||
|
|
||
|
|
||
|
{========================================================================}
|
||
|
|
||
|
implementation
|
||
|
|
||
|
const
|
||
|
PaymentType : array[TStPaymentTime] of Integer = (0, 1);
|
||
|
{Used for converting Timing to integer 0 or 1}
|
||
|
|
||
|
CouponsPerYear : array[TStFrequency] of Integer = (1, 2, 4, 12);
|
||
|
{Used for converting Frequency to integer 1, 2, 4, or 12}
|
||
|
|
||
|
CouponPeriod : array[TStFrequency] of Integer = (12, 6, 3, 1);
|
||
|
{Used for converting Frequency to duration}
|
||
|
|
||
|
DefaultGuess : Extended = 0.1;
|
||
|
{Starting point for rate approximation routines}
|
||
|
|
||
|
var
|
||
|
RecipLn10 : Extended;
|
||
|
{Used for common log computation}
|
||
|
|
||
|
|
||
|
{================= Local routines used by this unit ==================}
|
||
|
|
||
|
procedure RaiseStFinError(Code : Longint);
|
||
|
begin
|
||
|
Raise EStFinError.CreateResTP(Code, 0);
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function Exp10(Exponent : Extended) : Extended;
|
||
|
{-Returns 10^Exponent}
|
||
|
begin
|
||
|
Result := Power(10.0, Exponent);
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function Log10(Value : Extended) : Extended;
|
||
|
{-Returns common log of Value}
|
||
|
begin
|
||
|
Result := Ln(Value) * RecipLn10;
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function DayCount(Day1, Day2 : TStDate; Basis : TStBasis) : LongInt;
|
||
|
{-The number of days from Day1 to Day2 according to day count basis}
|
||
|
var
|
||
|
BDT : TStBondDateType;
|
||
|
begin
|
||
|
case Basis of
|
||
|
BasisNASD : BDT := bdt30360PSA;
|
||
|
BasisEur30360 : BDT := bdt30E360;
|
||
|
else
|
||
|
BDT := bdtActual;
|
||
|
end;
|
||
|
Result := Longint(BondDateDiff(Day1, Day2, BDT));
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function LastCoupon(Settlement, Maturity : TStDate;
|
||
|
Frequency : TStFrequency) : TStDate;
|
||
|
{-The last coupon date prior to settlement}
|
||
|
var
|
||
|
Last : TStDate;
|
||
|
Months : Integer;
|
||
|
begin
|
||
|
Last := Maturity;
|
||
|
Months := 0;
|
||
|
while (Last >= Settlement) do begin
|
||
|
Months := Months + CouponPeriod[Frequency];
|
||
|
Last := IncDateTrunc(Maturity, -Months, 0);
|
||
|
end;
|
||
|
Result := Last;
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function NextCoupon(Settlement, Maturity : TStDate;
|
||
|
Frequency : TStFrequency) : TStDate;
|
||
|
{-The next coupon date after settlement}
|
||
|
var
|
||
|
Next : TStDate;
|
||
|
begin
|
||
|
Next := LastCoupon(Settlement, Maturity, Frequency);
|
||
|
Result := IncDateTrunc(Next, CouponPeriod[Frequency], 0);
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function CouponsToMaturity(Settlement, Maturity : TStDate;
|
||
|
Frequency : TStFrequency) : Integer;
|
||
|
{-The number of coupons remaining after settlement}
|
||
|
var
|
||
|
CouponDate : TStDate;
|
||
|
Months : Integer;
|
||
|
Coupons : Integer;
|
||
|
begin
|
||
|
CouponDate := Maturity;
|
||
|
Coupons := 0;
|
||
|
Months := 0;
|
||
|
while (CouponDate > Settlement) do begin
|
||
|
Months := Months + CouponPeriod[Frequency];
|
||
|
CouponDate := IncDateTrunc(Maturity, -Months, 0);
|
||
|
Coupons := Coupons + 1;
|
||
|
end;
|
||
|
Result := Coupons;
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function DayCountFraction(Day1, Day2, Settlement, Maturity : TStDate;
|
||
|
Frequency : TStFrequency;
|
||
|
Basis : TStBasis) : Extended;
|
||
|
{-The number of days from Day1 to Day2 divided by days/year
|
||
|
except for Act/Act which uses actual coupon period x frequency}
|
||
|
var
|
||
|
Last, Next : TStDate;
|
||
|
DPY : Integer;
|
||
|
begin
|
||
|
if (Basis = BasisActAct) then begin
|
||
|
Last := LastCoupon(Settlement, Maturity, Frequency);
|
||
|
Next := NextCoupon(Settlement, Maturity, Frequency);
|
||
|
DPY := DayCount(Last, Next, Basis) * CouponsPerYear[Frequency];
|
||
|
end else if (Basis = BasisAct365) then
|
||
|
DPY := 365
|
||
|
else
|
||
|
DPY := 360;
|
||
|
Result := DayCount(Day1, Day2, Basis) / DPY;
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function BondDirtyPrice(Settlement, Maturity : TStDate;
|
||
|
Rate, Yield, Redemption : Extended;
|
||
|
Frequency : TStFrequency;
|
||
|
Basis : TStBasis) : Extended;
|
||
|
{-Bond Price including interest accrued in current coupon period}
|
||
|
var
|
||
|
C, DCF, Yw : Extended;
|
||
|
Vn, Vdcf : Extended;
|
||
|
Next : TStDate;
|
||
|
N, W : Integer;
|
||
|
begin
|
||
|
W := CouponsPerYear[Frequency];
|
||
|
C := Redemption * (Rate / W);
|
||
|
Yw := Yield / W;
|
||
|
N := CouponsToMaturity(Settlement, Maturity, Frequency);
|
||
|
Next := NextCoupon(Settlement, Maturity, Frequency);
|
||
|
DCF := DayCountFraction(Settlement, Next, Settlement, Maturity,
|
||
|
Frequency, Basis);
|
||
|
Vdcf := Power(1.0 / (1.0 + Yw), DCF * W);
|
||
|
Vn := Power(1.0 / (1.0 + Yw), N - 1.0);
|
||
|
Result := Vdcf * (( C * (1.0 - Vn) / Yw) + Redemption * Vn + C);
|
||
|
end;
|
||
|
|
||
|
|
||
|
|
||
|
{====================== Public Routines ============================}
|
||
|
|
||
|
|
||
|
function AccruedInterestMaturity(Issue, Maturity : TStDate;
|
||
|
Rate, Par : Extended;
|
||
|
Basis : TStBasis) : Extended;
|
||
|
var
|
||
|
DCF : Extended;
|
||
|
begin
|
||
|
If (Rate <= 0.0) or (Par <= 0.0) or (Issue >= Maturity) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
DCF := DayCountFraction(Issue, Maturity, Issue, Maturity,
|
||
|
fqAnnual, Basis);
|
||
|
Result := Par * Rate * DCF;
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function AccruedInterestPeriodic(Issue, Settlement, Maturity : TStDate;
|
||
|
Rate, Par : Extended;
|
||
|
Frequency : TStFrequency;
|
||
|
Basis : TStBasis) : Extended;
|
||
|
var
|
||
|
Last : TStDate;
|
||
|
DCF : Extended;
|
||
|
begin
|
||
|
if (Rate <= 0.0) or (Par <= 0.0) or (Issue >= Settlement) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
Last := LastCoupon(Settlement, Maturity, Frequency);
|
||
|
if (Issue > Last) then
|
||
|
Last := Issue;
|
||
|
DCF := DayCountFraction(Last, Settlement, Settlement, Maturity,
|
||
|
Frequency, Basis);
|
||
|
Result := Par * Rate * DCF;
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function BondDuration(Settlement,Maturity : TStDate;
|
||
|
Rate, Yield : Extended;
|
||
|
Frequency : TStFrequency;
|
||
|
Basis : TStBasis) : Extended;
|
||
|
var
|
||
|
B, dB : Extended;
|
||
|
Yw : Extended;
|
||
|
begin
|
||
|
if (Rate < 0.0) or (Yield < 0.0) or (Settlement >= Maturity) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
Yw := Yield / CouponsPerYear[Frequency];
|
||
|
B := BondDirtyPrice(Settlement, Maturity, Rate, Yield, 100.0,
|
||
|
Frequency, Basis);
|
||
|
if (B <> 0.0) then begin
|
||
|
dB := BondDirtyPrice(Settlement, Maturity, Rate, Yield + StDelta, 100.0,
|
||
|
Frequency, Basis) - B;
|
||
|
Result := -((1.0 + Yw) / B) * (dB / StDelta);
|
||
|
end else
|
||
|
Result := 0;
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function BondPrice(Settlement, Maturity : TStDate;
|
||
|
Rate, Yield, Redemption : Extended;
|
||
|
Frequency : TStFrequency;
|
||
|
Basis : TStBasis) : Extended;
|
||
|
var
|
||
|
B, DCF : Extended;
|
||
|
Last : TStDate;
|
||
|
begin
|
||
|
if (Yield < 0.0) or (Rate < 0.0) or (Redemption <= 0) or
|
||
|
(Settlement >= Maturity) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
B := BondDirtyPrice(Settlement, Maturity, Rate, Yield, Redemption,
|
||
|
Frequency, Basis);
|
||
|
Last := LastCoupon(Settlement, Maturity, Frequency);
|
||
|
DCF := DayCountFraction(Last, Settlement, Settlement, Maturity,
|
||
|
Frequency, Basis);
|
||
|
Result := B - Redemption * Rate * DCF;
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function CumulativeInterest(Rate : Extended;
|
||
|
NPeriods : Integer;
|
||
|
PV : Extended;
|
||
|
StartPeriod, EndPeriod : Integer;
|
||
|
Frequency : TStFrequency;
|
||
|
Timing : TStPaymentTime) : Extended;
|
||
|
var
|
||
|
P, CP : Extended;
|
||
|
begin
|
||
|
if (Rate <=0.0) or (NPeriods <= 0) or (PV <= 0.0) or (StartPeriod < 1) or
|
||
|
(EndPeriod < 1) or (StartPeriod > EndPeriod) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
P := Payment(Rate, NPeriods, PV, 0.0, Frequency, Timing);
|
||
|
CP := CumulativePrincipal(Rate, NPeriods, PV, StartPeriod, EndPeriod,
|
||
|
Frequency, Timing);
|
||
|
Result := P * (EndPeriod - (StartPeriod - 1.0)) - CP;
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function CumulativePrincipal(Rate : Extended;
|
||
|
NPeriods : Integer;
|
||
|
PV : Extended;
|
||
|
StartPeriod, EndPeriod : Integer;
|
||
|
Frequency : TStFrequency;
|
||
|
Timing : TStPaymentTime) : Extended;
|
||
|
var
|
||
|
P : Extended;
|
||
|
begin
|
||
|
if (Rate <=0.0) or (NPeriods <= 0) or (PV <= 0.0) or (StartPeriod < 1) or
|
||
|
(EndPeriod < 1) or (StartPeriod > EndPeriod) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
P := Payment(Rate, NPeriods, PV, 0.0, Frequency, Timing);
|
||
|
Result := FutureValue(Rate, StartPeriod - 1, P, PV, Frequency, Timing) -
|
||
|
FutureValue(Rate, EndPeriod, P, PV, Frequency, Timing);
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function DecliningBalance(Cost, Salvage : Extended;
|
||
|
Life, Period, Month : Integer) : Extended;
|
||
|
var
|
||
|
Rate : Extended;
|
||
|
DPv : Extended;
|
||
|
TDPv : Extended;
|
||
|
I : Integer;
|
||
|
begin
|
||
|
if (Cost <= 0.0) or (Cost < Salvage) or (Period < 1) or (Life < 2) or
|
||
|
(Period > (Life + 1)) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
DPv := 0.0;
|
||
|
TDPv := 0.0;
|
||
|
if (Salvage = 0) then
|
||
|
Salvage := 0.001;
|
||
|
if (Month = 0) then
|
||
|
Month := 12;
|
||
|
Rate := RoundToDecimal(1.0 - Power(Salvage / Cost, 1.0 / Life), 3, false);
|
||
|
for I := 1 to Period do begin
|
||
|
if (I = 1) then
|
||
|
DPv := (Cost * Rate * Month) / 12.0 {1st Period}
|
||
|
else if (I = (Life + 1)) then
|
||
|
DPv := (Cost - TDPv) * Rate * (12.0 - Month) / 12.0 {Last Period}
|
||
|
else
|
||
|
DPv := (Cost - TDPv) * Rate; {All the rest}
|
||
|
TDpv := TDpv + Dpv
|
||
|
end;
|
||
|
Result := RoundToDecimal(Dpv, 3, False);
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function DiscountRate(Settlement, Maturity : TStDate;
|
||
|
Price, Redemption : Extended;
|
||
|
Basis : TStBasis) : Extended;
|
||
|
var
|
||
|
DCF : Extended;
|
||
|
begin
|
||
|
If (Price <= 0.0) or (Redemption <= 0.0) or (Settlement >= Maturity) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
DCF := DayCountFraction(Settlement, Maturity, Settlement, Maturity,
|
||
|
fqAnnual, Basis);
|
||
|
Result := (Redemption - Price) / (Redemption * DCF);
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function DollarToDecimal(FracDollar : Extended;
|
||
|
Fraction : Integer) : Extended;
|
||
|
var
|
||
|
I, F, N : Extended;
|
||
|
begin
|
||
|
if (Fraction < 1) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
I := Int(FracDollar); {Integral part}
|
||
|
N := Int(Log10(Fraction) + 1.0); {Number of decimal places}
|
||
|
F := Frac(FracDollar); {Fractional part}
|
||
|
Result := I + (F * Exp10(N) / Fraction);
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function DollarToDecimalText(DecDollar : Extended) : string;
|
||
|
var
|
||
|
A, P : Extended;
|
||
|
N, I : Integer;
|
||
|
Str : string;
|
||
|
T : Longint;
|
||
|
CentVal : Integer;
|
||
|
const
|
||
|
Orders : array[0..5] of string = ('', 'Thousand ', 'Million ',
|
||
|
'Billion ', 'Trillion ', 'Quadrillion ');
|
||
|
|
||
|
function Text100(Num: Longint) : string;
|
||
|
{formats an integer in the range 0 to 999}
|
||
|
var
|
||
|
I, J : Integer;
|
||
|
A, T : Longint;
|
||
|
S : string;
|
||
|
const
|
||
|
Tens : array[0..9] of string =
|
||
|
('', '', 'Twenty', 'Thirty', 'Forty', 'Fifty',
|
||
|
'Sixty', 'Seventy', 'Eighty', 'Ninety');
|
||
|
Ones : array[0..19] of string =
|
||
|
('', 'One', 'Two', 'Three', 'Four', 'Five',
|
||
|
'Six', 'Seven', 'Eight', 'Nine', 'Ten',
|
||
|
'Eleven', 'Twelve', 'Thirteen', 'Fourteen', 'Fifteen',
|
||
|
'Sixteen', 'Seventeen', 'Eighteen', 'Nineteen');
|
||
|
begin
|
||
|
S := '';
|
||
|
I := 0;
|
||
|
J := 0;
|
||
|
Result := S;
|
||
|
if (Num = 0) then
|
||
|
Exit;
|
||
|
A := Num;
|
||
|
T := A div 100;
|
||
|
if (T > 0) then begin
|
||
|
I := T; {I = Hundreds digit}
|
||
|
A := A - (T * 100);
|
||
|
end;
|
||
|
T := A div 10;
|
||
|
if (T > 1) then begin
|
||
|
J := T; {J = Tens digit}
|
||
|
A := A - (T * 10); {A = Ones digit}
|
||
|
end;
|
||
|
if (I > 0) then
|
||
|
S := Ones[I] + ' Hundred';
|
||
|
if (J > 0) then begin
|
||
|
if (I > 0) then
|
||
|
S := S + ' ' + Tens[J]
|
||
|
else
|
||
|
S := S + Tens[J];
|
||
|
end;
|
||
|
if (A > 0) then begin
|
||
|
if (J > 0) then
|
||
|
S := S + '-';
|
||
|
if (I > 0) and (J = 0) then
|
||
|
S := S + ' ' + Ones[A]
|
||
|
else
|
||
|
S := S + Ones[A];
|
||
|
end;
|
||
|
Result := S;
|
||
|
end;
|
||
|
|
||
|
begin
|
||
|
Str := '';
|
||
|
if (DecDollar < 0) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
if (DecDollar > 0) then begin
|
||
|
N := Trunc(Log10(DecDollar));
|
||
|
if (N > 17) then {DecDollar too large}
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
A := DecDollar;
|
||
|
for I := N downto 0 do begin
|
||
|
P := Int(Exp10(I * 3));
|
||
|
T := Trunc(A / P);
|
||
|
if (T > 0) then
|
||
|
Str := Str + {' ' +} Text100(T) + ' ' + Orders[I];
|
||
|
A := A - (T * P);
|
||
|
end;
|
||
|
end;
|
||
|
if (Str = '') then
|
||
|
Str := 'Zero ';
|
||
|
Str := Str + 'and ';
|
||
|
CentVal := Round(Frac(DecDollar) * 100);
|
||
|
if (CentVal < 10) then
|
||
|
Str := Str + '0';
|
||
|
Result := Str + IntToStr(CentVal) + '/100';
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function DollarToFraction(DecDollar : Extended;
|
||
|
Fraction : Integer) : Extended;
|
||
|
var
|
||
|
I, F, N : Extended;
|
||
|
begin
|
||
|
if (Fraction < 1) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
I := Int(DecDollar); {Integral part}
|
||
|
N := Int(Log10(Fraction) + 1.0); {Number of decimal places}
|
||
|
F := Frac(DecDollar); {Fractional part}
|
||
|
Result := I + (F * Fraction / Exp10(N));
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function DollarToFractionStr(FracDollar : Extended;
|
||
|
Fraction : Integer) : string;
|
||
|
var
|
||
|
I, F, N : Extended;
|
||
|
begin
|
||
|
Result := '';
|
||
|
if (Fraction < 1) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
I := Int(FracDollar); {Integral part}
|
||
|
N := Int(Log10(Fraction) + 1.0); {Number of decimal places}
|
||
|
F := Frac(FracDollar) * Exp10(N); {Fractional part}
|
||
|
Result := IntToStr(Trunc(I));
|
||
|
if (F > 0) then
|
||
|
Result := Result + ' ' + FloatToStrF(F, ffNumber, Trunc(N), 0) +
|
||
|
'/' + IntToStr(Fraction);
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function EffectiveInterestRate(NominalRate : Extended;
|
||
|
Frequency : TStFrequency) : Extended;
|
||
|
var
|
||
|
W : Integer;
|
||
|
begin
|
||
|
if (NominalRate <= 0.0) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
W := CouponsPerYear[Frequency];
|
||
|
Result := Power(1.0 + NominalRate / W, W) - 1.0;
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function FutureValue(Rate : Extended;
|
||
|
NPeriods : Integer;
|
||
|
Pmt, PV : Extended;
|
||
|
Frequency : TStFrequency;
|
||
|
Timing: TStPaymentTime) : Extended;
|
||
|
var
|
||
|
S, Rw : Extended;
|
||
|
PT : Integer;
|
||
|
|
||
|
begin
|
||
|
PT := PaymentType[Timing];
|
||
|
Rw := Rate / CouponsPerYear[Frequency];
|
||
|
S := Power(1.0 + Rw, NPeriods);
|
||
|
Result := -((PV * S) + Pmt * (S - 1.0) * (1.0 + Rw * PT) / Rw);
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function FutureValueSchedule(Principal : Extended;
|
||
|
const Schedule : array of Double) : Extended;
|
||
|
begin
|
||
|
Result := FutureValueSchedule16(Principal, Schedule,
|
||
|
High(Schedule) + 1);
|
||
|
end;
|
||
|
|
||
|
function FutureValueSchedule16(Principal : Extended;
|
||
|
const Schedule; NRates : Integer) : Extended;
|
||
|
var
|
||
|
I : Integer;
|
||
|
begin
|
||
|
Result := Principal;
|
||
|
for I := 0 to (NRates - 1) do
|
||
|
Result := Result * (1.0 + TDoubleArray(Schedule)[I]);
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function InterestRate(NPeriods : Integer;
|
||
|
Pmt, PV, FV : Extended;
|
||
|
Frequency : TStFrequency;
|
||
|
Timing : TStPaymentTime;
|
||
|
Guess : Extended) : Extended;
|
||
|
var
|
||
|
Rate : Extended;
|
||
|
NextRate : Extended;
|
||
|
T, dT : Extended;
|
||
|
Count : Integer;
|
||
|
begin
|
||
|
Count := 0;
|
||
|
NextRate := Guess;
|
||
|
if (Guess = 0.0) then
|
||
|
NextRate := DefaultGuess;
|
||
|
{Solve FV(rate) = FV for rate by Newton's method}
|
||
|
repeat
|
||
|
Rate := NextRate;
|
||
|
if (Rate <= - CouponsPerYear[Frequency]) then
|
||
|
Rate := -0.999 * CouponsPerYear[Frequency];
|
||
|
T := FutureValue(Rate, NPeriods, Pmt, PV, Frequency, Timing) - FV;
|
||
|
dT := FutureValue(Rate + StDelta, NPeriods, Pmt, PV, Frequency,
|
||
|
Timing) - FV - T;
|
||
|
if (dT = 0.0) then
|
||
|
Count := StMaxIterations
|
||
|
else
|
||
|
NextRate := Rate - StDelta * T / dT;
|
||
|
Inc(Count);
|
||
|
until (Abs(NextRate - Rate) < StEpsilon) or (Count > StMaxIterations);
|
||
|
if (Count > StMaxIterations) then
|
||
|
RaiseStFinError(stscFinNoConverge);
|
||
|
Result := NextRate;
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function InternalRateOfReturn(const Values : array of Double;
|
||
|
Guess : Extended) : Extended;
|
||
|
begin
|
||
|
Result := InternalRateOfReturn16(Values, High(Values) + 1, Guess);
|
||
|
end;
|
||
|
|
||
|
function InternalRateOfReturn16(const Values;
|
||
|
NValues : Integer;
|
||
|
Guess : Extended) : Extended;
|
||
|
var
|
||
|
Rate : Extended;
|
||
|
NextRate : Extended;
|
||
|
PV : Extended;
|
||
|
dPV : Extended;
|
||
|
Count : Integer;
|
||
|
begin
|
||
|
Count := 0;
|
||
|
NextRate := Guess;
|
||
|
if (Guess = 0.0) then
|
||
|
NextRate := DefaultGuess;
|
||
|
{Solve NPV(Rate) = 0 for rate by Newton's method}
|
||
|
repeat
|
||
|
Rate := NextRate;
|
||
|
if (Rate <= -1.0) then
|
||
|
Rate := -0.999;
|
||
|
PV := NetPresentValue16(Rate, Values, NValues);
|
||
|
dPV := NetPresentValue16(Rate + StDelta, Values, NValues) - PV;
|
||
|
if (dPV = 0.0) then
|
||
|
Count := StMaxIterations
|
||
|
else
|
||
|
NextRate := Rate - (StDelta * PV) / dPV;
|
||
|
Inc(Count);
|
||
|
until (Abs(NextRate - Rate) < StEpsilon) or (Count > StMaxIterations);
|
||
|
if (Count > StMaxIterations) then
|
||
|
RaiseStFinError(stscFinNoConverge);
|
||
|
Result := NextRate;
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function IsCardValid(const S : string) : Boolean;
|
||
|
const
|
||
|
Ord0 = Ord('0');
|
||
|
var
|
||
|
Temp : string;
|
||
|
I, J, K : Integer;
|
||
|
begin
|
||
|
Result := False;
|
||
|
Temp := '';
|
||
|
for I := 1 to Length(S) do
|
||
|
if (S[I] in ['0'..'9']) then
|
||
|
Temp := Temp + S[I];
|
||
|
if Temp = '' then
|
||
|
Exit;
|
||
|
K := 0;
|
||
|
I := 1;
|
||
|
if not Odd(Length(Temp)) then begin
|
||
|
J := Ord(Temp[I]) - Ord0;
|
||
|
J := J shl 1;
|
||
|
if J > 9 then
|
||
|
J := J - 9;
|
||
|
K := K + J;
|
||
|
Inc(I);
|
||
|
end;
|
||
|
while I <= Length(Temp) do begin
|
||
|
K := K + Ord(Temp[I]) - Ord0;
|
||
|
Inc(I);
|
||
|
if I > Length(Temp) then
|
||
|
Break;
|
||
|
J := Ord(Temp[I]) - Ord0;
|
||
|
J := J shl 1;
|
||
|
if J > 9 then
|
||
|
J := J - 9;
|
||
|
K := K + J;
|
||
|
Inc(I);
|
||
|
end;
|
||
|
Result := (K mod 10 = 0);
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function ModifiedDuration(Settlement, Maturity : TStDate;
|
||
|
Rate, Yield : Extended;
|
||
|
Frequency : TStFrequency;
|
||
|
Basis : TStBasis) : Extended;
|
||
|
begin
|
||
|
if (Rate < 0.0) or (Yield < 0.0) or (Settlement >= Maturity) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
Result := BondDuration(Settlement, Maturity, Rate, Yield,
|
||
|
Frequency, Basis)/ (1.0 + Yield / CouponsPerYear[Frequency]);
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function ModifiedIRR(const Values : array of Double;
|
||
|
FinanceRate, ReinvestRate : Extended) : Extended;
|
||
|
begin
|
||
|
Result := ModifiedIRR16(Values, High(Values) + 1, FinanceRate,
|
||
|
ReinvestRate);
|
||
|
end;
|
||
|
|
||
|
function ModifiedIRR16(const Values;
|
||
|
NValues : Integer;
|
||
|
FinanceRate, ReinvestRate : Extended) : Extended;
|
||
|
var
|
||
|
NPVPos : Extended;
|
||
|
NPVNeg : Extended;
|
||
|
Val : Extended;
|
||
|
Rn, Fn : Extended;
|
||
|
I : Integer;
|
||
|
begin
|
||
|
NPVPos := 0.0;
|
||
|
NPVNeg := 0.0;
|
||
|
for I := 0 to (NValues - 1) do begin
|
||
|
Val := TDoubleArray(Values)[I];
|
||
|
if (Val > 0.0) then
|
||
|
NPVPos := NPVPos + Val / Power(1.0 + ReinvestRate, I + 1.0)
|
||
|
else
|
||
|
NPVNeg := NPVNeg + Val / Power(1.0 + FinanceRate, I + 1.0);
|
||
|
end;
|
||
|
Rn := Power(1.0 + ReInvestRate, NValues);
|
||
|
Fn := 1.0 + FinanceRate;
|
||
|
Result := Power(-NPVPos * Rn / (NPVNeg * Fn), 1.0 / (NValues - 1.0)) - 1.0;
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function NetPresentValue(Rate : Extended;
|
||
|
const Values : array of Double) : Extended;
|
||
|
begin
|
||
|
Result := NetPresentValue16(Rate, Values, High(Values) + 1);
|
||
|
end;
|
||
|
|
||
|
function NetPresentValue16(Rate : Extended;
|
||
|
const Values;
|
||
|
NValues : Integer) : Extended;
|
||
|
var
|
||
|
I : Integer;
|
||
|
begin
|
||
|
Result := 0;
|
||
|
for I := 0 to (NValues - 1) do
|
||
|
Result := Result + TDoubleArray(Values)[I] / Power(1.0 + Rate, I + 1.0);
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function NominalInterestRate(EffectRate : Extended;
|
||
|
Frequency : TStFrequency) : Extended;
|
||
|
var
|
||
|
W : Extended;
|
||
|
begin
|
||
|
if (EffectRate <= 0.0) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
W := CouponsPerYear[Frequency];
|
||
|
Result := W * (Power(EffectRate + 1.0, 1.0 / W) - 1.0);
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function NonperiodicIRR(const Values : array of Double;
|
||
|
const Dates : array of TStDate;
|
||
|
Guess : Extended) : Extended;
|
||
|
begin
|
||
|
Result := NonPeriodicIRR16(Values, Dates, High(Values) + 1, Guess);
|
||
|
end;
|
||
|
|
||
|
function NonperiodicIRR16(const Values;
|
||
|
const Dates;
|
||
|
NValues : Integer;
|
||
|
Guess : Extended) : Extended;
|
||
|
var
|
||
|
Rate : Extended;
|
||
|
NextRate : Extended;
|
||
|
PV, dPV : Extended;
|
||
|
Count : Integer;
|
||
|
begin
|
||
|
Count := 0;
|
||
|
NextRate := Guess;
|
||
|
if (Guess = 0.0) then
|
||
|
NextRate := DefaultGuess;
|
||
|
{Solve XNPV(Rate) = 0 for rate by Newton's method}
|
||
|
repeat
|
||
|
Rate := NextRate;
|
||
|
if (Rate <= -1.0) then
|
||
|
Rate := -0.999;
|
||
|
PV := NonPeriodicNPV16(Rate, Values, Dates, NValues);
|
||
|
dPV := NonPeriodicNPV16(Rate + StDelta, Values, Dates, NValues) - PV;
|
||
|
if (dPV = 0.0) then
|
||
|
Count := StMaxIterations
|
||
|
else
|
||
|
NextRate := Rate - (StDelta * PV) / dPV;
|
||
|
Inc(Count);
|
||
|
until (Abs(NextRate - Rate) < StEpsilon) or (Count > StMaxIterations);
|
||
|
if (Count > StMaxIterations) then
|
||
|
RaiseStFinError(stscFinNoConverge);
|
||
|
Result := NextRate;
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function NonperiodicNPV(Rate : Extended;
|
||
|
const Values : array of Double;
|
||
|
const Dates : array of TStDate) : Extended;
|
||
|
begin
|
||
|
Result := NonperiodicNPV16(Rate, Values, Dates, High(Values) + 1);
|
||
|
end;
|
||
|
|
||
|
function NonperiodicNPV16(Rate : Extended;
|
||
|
const Values;
|
||
|
const Dates;
|
||
|
NValues : Integer) : Extended;
|
||
|
var
|
||
|
Day1 : TStDate;
|
||
|
Diff : Double;
|
||
|
I : Integer;
|
||
|
begin
|
||
|
Result := 0.0;
|
||
|
Day1 := TStDateArray(Dates)[0];
|
||
|
for I := 0 to (NValues - 1) do begin
|
||
|
Diff := TStDateArray(Dates)[I] - Day1;
|
||
|
if (Diff < 0) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
Result := Result + TDoubleArray(Values)[I] / Power(1.0 + Rate, Diff / 365.0);
|
||
|
end;
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function Payment(Rate : Extended;
|
||
|
NPeriods : Integer;
|
||
|
PV, FV : Extended;
|
||
|
Frequency : TStFrequency;
|
||
|
Timing : TStPaymentTime) : Extended;
|
||
|
var
|
||
|
PT, Rw, S : Extended;
|
||
|
begin
|
||
|
PT := PaymentType[Timing];
|
||
|
Rw := Rate / CouponsPerYear[Frequency];
|
||
|
S := Power(1.0 + Rw, NPeriods);
|
||
|
Result := Rw * (FV - PV * S) / ((S - 1.0) * (1.0 + Rw * PT));
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
function Periods(Rate : Extended;
|
||
|
Pmt, PV, FV : Extended;
|
||
|
Frequency : TStFrequency;
|
||
|
Timing: TStPaymentTime) : Integer;
|
||
|
var
|
||
|
S, Rw : Extended;
|
||
|
|
||
|
begin
|
||
|
Rw := Rate / CouponsPerYear[Frequency];
|
||
|
S := Pmt * (1.0 + Rw * PaymentType[Timing]);
|
||
|
Result := Round(Ln((Rw*FV + S) / (Rw*PV + S)) / Ln(1.0 + Rw));
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function PresentValue(Rate : Extended;
|
||
|
NPeriods : Integer;
|
||
|
Pmt, FV : Extended;
|
||
|
Frequency : TStFrequency;
|
||
|
Timing : TStPaymentTime) : Extended;
|
||
|
var
|
||
|
PT, Rw, S : Extended;
|
||
|
begin
|
||
|
PT := PaymentType[Timing];
|
||
|
Rw := Rate / CouponsPerYear[Frequency];
|
||
|
S := Power(1.0 + Rw, -NPeriods);
|
||
|
Result := (FV * S) + Pmt * (S - 1.0) * (1.0 + Rw * PT) / Rw;
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function ReceivedAtMaturity(Settlement, Maturity : TStDate;
|
||
|
Investment, Discount : Extended;
|
||
|
Basis : TStBasis) : Extended;
|
||
|
var
|
||
|
DCF : Extended;
|
||
|
begin
|
||
|
if (Investment <= 0.0) or (Discount <= 0.0) or (Settlement >= Maturity) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
DCF := DayCountFraction(Settlement, Maturity, Settlement, Maturity,
|
||
|
fqAnnual, Basis);
|
||
|
Result := Investment / (1.0 - Discount * DCF);
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
{revised}
|
||
|
function RoundToDecimal(Value : Extended;
|
||
|
Places : Integer;
|
||
|
Bankers : Boolean) : Extended;
|
||
|
var
|
||
|
Val, IV, N, F : Extended;
|
||
|
T : Integer;
|
||
|
begin
|
||
|
IV := 0;
|
||
|
N := Exp10(Places);
|
||
|
if (Places > 0) then
|
||
|
IV := Int(Value);
|
||
|
Val := (Value - IV) * N;
|
||
|
T := Trunc(Val);
|
||
|
F := (Val - T);
|
||
|
if Bankers then
|
||
|
Val := Round(Val) / N {Delphi's Round does Bankers}
|
||
|
else begin
|
||
|
if Abs(Round(10.0 * F)) >= 5 then begin
|
||
|
if (F > 0) then
|
||
|
Val := (T + 1.0) / N
|
||
|
else
|
||
|
Val := (T - 1.0) / N;
|
||
|
end else
|
||
|
Val := T / N;
|
||
|
end;
|
||
|
Result := Val + IV;
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function TBillEquivYield(Settlement, Maturity : TStDate;
|
||
|
Discount : Extended) : Extended;
|
||
|
var
|
||
|
DCF : Extended;
|
||
|
begin
|
||
|
if (Discount <= 0.0) or (Settlement > Maturity) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
DCF := DayCountFraction(Settlement, Maturity, Settlement, Maturity,
|
||
|
fqAnnual, BasisAct360);
|
||
|
if (DCF > 1.0) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
Result := (365.0 / 360.0) * Discount / (1.0 - Discount * DCF);
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function TBillPrice(Settlement, Maturity : TStDate;
|
||
|
Discount : Extended) : Extended;
|
||
|
var
|
||
|
DCF : Extended;
|
||
|
begin
|
||
|
if (Discount <= 0.0) or (Settlement > Maturity) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
DCF := DayCountFraction(Settlement, Maturity, Settlement, Maturity,
|
||
|
fqAnnual, BasisAct360);
|
||
|
if (DCF > 1.0) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
Result := 100.0 * ( 1.0 - Discount * DCF);
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function TBillYield(Settlement, Maturity : TStDate;
|
||
|
Price : Extended) : Extended;
|
||
|
var
|
||
|
DCF : Extended;
|
||
|
begin
|
||
|
if (Price <= 0.0) or (Settlement > Maturity) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
DCF := DayCountFraction(Settlement, Maturity, Settlement, Maturity,
|
||
|
fqAnnual, BasisAct360);
|
||
|
if (DCF > 1.0) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
Result := ((100.0 - Price) / Price) * (1.0 / DCF);
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function VariableDecliningBalance(Cost, Salvage : Extended;
|
||
|
Life : Integer;
|
||
|
StartPeriod, EndPeriod, Factor : Extended;
|
||
|
NoSwitch : Boolean) : Extended;
|
||
|
var
|
||
|
VDB : Extended;
|
||
|
SLD : Extended;
|
||
|
Rate : Extended;
|
||
|
begin
|
||
|
if (Cost <= 0.0) or (Cost < Salvage) or (Life < 2) or (EndPeriod > Life) or
|
||
|
(StartPeriod > EndPeriod) or (StartPeriod < 0) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
if (Factor = 0.0) then
|
||
|
Rate := 2.0 / Life
|
||
|
else
|
||
|
Rate := Factor / Life;
|
||
|
SLD := (Cost - Salvage) * (EndPeriod - StartPeriod) / Life;
|
||
|
VDB := Cost * (Power(1.0 - Rate, StartPeriod) - Power(1.0 - Rate, EndPeriod));
|
||
|
if (not NoSwitch) and (SLD > VDB) then
|
||
|
Result := SLD
|
||
|
else
|
||
|
Result := VDB;
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function YieldDiscounted(Settlement, Maturity : TStDate;
|
||
|
Price, Redemption : Extended;
|
||
|
Basis : TStBasis) : Extended;
|
||
|
var
|
||
|
DCF : Extended;
|
||
|
begin
|
||
|
if (Price <= 0.0) or (Redemption <= 0.0) or (Settlement >= Maturity) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
DCF := DayCountFraction(Settlement, Maturity, Settlement, Maturity,
|
||
|
fqAnnual, Basis);
|
||
|
Result := (Redemption - Price) / (Price * DCF);
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function YieldPeriodic(Settlement, Maturity : TStDate;
|
||
|
Rate, Price, Redemption : Extended;
|
||
|
Frequency : TStFrequency;
|
||
|
Basis : TStBasis) : Extended;
|
||
|
var
|
||
|
Yield : Extended;
|
||
|
NextYield : Extended;
|
||
|
P, dP : Extended;
|
||
|
Count : Integer;
|
||
|
begin
|
||
|
if (Price <= 0.0) or (Rate < 0.0) or (Redemption <= 0.0) or
|
||
|
(Settlement >= Maturity) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
Count := 0;
|
||
|
NextYield := Rate;
|
||
|
repeat {Solve B = BondPrice(yield) - Price = 0 by Newton's method}
|
||
|
if (NextYield > 0) then
|
||
|
Yield := NextYield
|
||
|
else
|
||
|
Yield := 0.001;
|
||
|
P := BondPrice(Settlement, Maturity, Rate, Yield, Redemption,
|
||
|
Frequency, Basis) - Price;
|
||
|
dP := BondPrice(Settlement, Maturity, Rate, Yield + StDelta,
|
||
|
Redemption, Frequency, Basis) - Price - P;
|
||
|
if (dP = 0.0) then
|
||
|
Count := StMaxIterations
|
||
|
else
|
||
|
NextYield := Yield - StDelta * P / dP;
|
||
|
Inc(Count);
|
||
|
until (Abs(NextYield - Yield) < StEpsilon) or (Count > StMaxIterations);
|
||
|
if (Count > StMaxIterations) then
|
||
|
RaiseStFinError(stscFinNoConverge);
|
||
|
Result := NextYield;
|
||
|
end;
|
||
|
|
||
|
{-------------------------------------------------------}
|
||
|
|
||
|
function YieldMaturity(Issue, Settlement, Maturity : TStDate;
|
||
|
Rate, Price : Extended;
|
||
|
Basis : TStBasis) : Extended;
|
||
|
var
|
||
|
DCFim, DCFsm, DCFis : Extended;
|
||
|
begin
|
||
|
if (Price <= 0.0) or (Rate < 0.0) or (Settlement < Issue) or
|
||
|
(Settlement >= Maturity) then
|
||
|
RaiseStFinError(stscFinBadArg);
|
||
|
DCFim := DayCountFraction(Issue, Maturity, Settlement, Maturity,
|
||
|
fqAnnual, Basis);
|
||
|
DCFsm := DayCountFraction(Settlement, Maturity, Settlement, Maturity,
|
||
|
fqAnnual, Basis);
|
||
|
DCFis := DayCountFraction(Issue, Settlement, Settlement, Maturity,
|
||
|
fqAnnual, Basis);
|
||
|
Result := 100.0 * (1.0 + Rate * DCFim);
|
||
|
Result := Result / (Price + 100.0 * Rate * DCFis);
|
||
|
Result := (Result - 1.0) / DCFsm;
|
||
|
end;
|
||
|
|
||
|
|
||
|
|
||
|
initialization
|
||
|
RecipLn10 := 1.0 / Ln(10.0);
|
||
|
end.
|
||
|
|