finance

package
v0.2.18 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 11, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package finance provides high-precision financial calculations (annuities, loans, NPV/IRR, rate conversions, amortization schedules) built on top of github.com/TimLai666/go-decimal.

All exported functions use the Excel/Google-Sheets sign convention: money received is positive, money paid out is negative. PMT, FV, and PV therefore typically come back with the opposite sign of one another.

Precision and rounding are configurable per call via the optional Options argument; when omitted, results are produced at scale=10 with HalfUp rounding (internal computation always uses extra guard digits).

Index

Constants

View Source
const DefaultScale int32 = 10

DefaultScale is the result scale used when Options.Scale == 0.

Variables

View Source
var Zero = decimal.NewFromInt64(internalCtx, 0)

Zero is a convenience zero-valued decimal at the package's internal precision. Pass it as fv (or pv) when a TVM call doesn't need that term.

Functions

func AccrInt

func AccrInt(issue, firstInterest, settlement time.Time, rate, par decimal.Decimal,
	freq int, basis DayCountBasis, calcMethod bool, opts ...Options) (decimal.Decimal, error)

AccrInt returns the accrued interest of a security that pays periodic interest. With calcMethod=true, accrual is computed from issue to settlement; with calcMethod=false, accrual starts at firstInterest (matching Excel's behavior for bonds purchased after the first coupon date but before maturity).

Excel equivalent: ACCRINT(issue, first_interest, settlement, rate, par, frequency, basis, calc_method)

func AnnualFromContinuous

func AnnualFromContinuous(continuous decimal.Decimal, opts ...Options) (decimal.Decimal, error)

AnnualFromContinuous converts a continuously compounded rate ρ into the equivalent effective annual rate, exp(ρ) - 1.

func ContinuousFromAnnual

func ContinuousFromAnnual(effective decimal.Decimal, opts ...Options) (decimal.Decimal, error)

ContinuousFromAnnual converts an effective annual rate r into the continuously compounded rate that yields the same growth, ln(1+r).

func CumIPMT

func CumIPMT(rate decimal.Decimal, nper int, pv decimal.Decimal, startPeriod, endPeriod int, timing PaymentTiming, opts ...Options) (decimal.Decimal, error)

CumIPMT returns the cumulative interest paid between periods startPeriod and endPeriod (inclusive, 1-indexed).

Excel equivalent: CUMIPMT(rate, nper, pv, start_period, end_period, type)

func CumPPMT

func CumPPMT(rate decimal.Decimal, nper int, pv decimal.Decimal, startPeriod, endPeriod int, timing PaymentTiming, opts ...Options) (decimal.Decimal, error)

CumPPMT returns the cumulative principal paid between periods startPeriod and endPeriod (inclusive, 1-indexed).

Excel equivalent: CUMPRINC(rate, nper, pv, start_period, end_period, type)

func DDB

func DDB(cost, salvage decimal.Decimal, life, per int, factor decimal.Decimal, opts ...Options) (decimal.Decimal, error)

DDB returns the depreciation in the per-th period under the double-declining-balance method (or any declining-balance method determined by factor). The rate is factor/life applied to the remaining book value, capped so the asset never depreciates below salvage.

factor=2 is the conventional double-declining choice (Excel's default). Pass finance.MustNew("1.5") for 150%-DB, etc.

Excel equivalent: DDB(cost, salvage, life, period, factor)

func Duration

func Duration(settlement, maturity time.Time, coupon, yld decimal.Decimal,
	freq int, basis DayCountBasis, opts ...Options) (decimal.Decimal, error)

Duration returns the Macaulay duration of a bond.

D = Σ t_k · PV(cf_k) / Σ PV(cf_k)

where t_k is the time to cashflow k in years from settlement.

Excel equivalent: DURATION(settlement, maturity, coupon, yld, frequency, basis)

func EffectiveRate

func EffectiveRate(nominal decimal.Decimal, periodsPerYear int, opts ...Options) (decimal.Decimal, error)

EffectiveRate converts a nominal annual rate compounded periodsPerYear times per year into the effective annual rate.

effective = (1 + nominal/m)^m - 1

Excel equivalent: EFFECT(nominal_rate, npery)

func FV

func FV(rate decimal.Decimal, nper int, pmt, pv decimal.Decimal, timing PaymentTiming, opts ...Options) (decimal.Decimal, error)

FV computes the future value of an annuity given the periodic rate, number of periods, periodic payment, present value, and payment timing.

Excel equivalent: FV(rate, nper, pmt, pv, type)

func FromFloat

func FromFloat(f float64) (decimal.Decimal, error)

FromFloat converts a float64 to a Decimal. Use sparingly: float inputs already carry binary rounding error before they reach the decimal layer.

func FromInt

func FromInt(n int) decimal.Decimal

FromInt converts an int to a Decimal at the package's internal precision.

func IPMT

func IPMT(rate decimal.Decimal, per, nper int, pv, fv decimal.Decimal, timing PaymentTiming, opts ...Options) (decimal.Decimal, error)

IPMT returns the interest portion of the per-th payment.

Excel equivalent: IPMT(rate, per, nper, pv, fv, type)

per is 1-indexed. With PaymentBegin (type=1), the first payment has IPMT=0 because no interest has accrued by t=0.

func IRR

func IRR(cashflows []decimal.Decimal, guess decimal.Decimal, opts ...Options) (decimal.Decimal, error)

IRR computes the internal rate of return for a cashflow stream starting at t=0. Uses Newton's method seeded at guess (0.1 if guess is the zero Decimal, matching Excel's default).

Returns an error if the iteration fails to converge — most often because the cashflow stream has no real-valued IRR or because the initial guess is far from any root. Pass a custom guess close to the expected rate to recover.

Excel equivalent: IRR(values, [guess])

func MDuration

func MDuration(settlement, maturity time.Time, coupon, yld decimal.Decimal,
	freq int, basis DayCountBasis, opts ...Options) (decimal.Decimal, error)

MDuration returns the modified duration of a bond:

MD = Duration / (1 + yld/freq)

Excel equivalent: MDURATION(settlement, maturity, coupon, yld, frequency, basis)

func MIRR

func MIRR(cashflows []decimal.Decimal, financeRate, reinvestRate decimal.Decimal, opts ...Options) (decimal.Decimal, error)

MIRR computes the modified internal rate of return.

Unlike IRR, MIRR distinguishes between the rate at which negative (financing) cashflows are discounted and the rate at which positive (reinvestment) cashflows are compounded:

MIRR = (FV(positive_cf @ reinvestRate) / -PV(negative_cf @ financeRate))^(1/n) - 1

where n is the number of periods spanned (len(cashflows) - 1). Positive cashflows are compounded forward to t=n at reinvestRate; negative cashflows are discounted back to t=0 at financeRate.

Excel equivalent: MIRR(values, finance_rate, reinvest_rate)

func MustNew

func MustNew(s string) decimal.Decimal

MustNew is like New but panics on parse error. Suitable for tests and constants.

func NPER

func NPER(rate, pmt, pv, fv decimal.Decimal, timing PaymentTiming, opts ...Options) (decimal.Decimal, error)

NPER computes the number of periods required to satisfy the TVM equation. May return a non-integer value (the last period is then a partial period); round up if you need a whole-period count.

Excel equivalent: NPER(rate, pmt, pv, fv, type)

func NPV

func NPV(rate decimal.Decimal, cashflows []decimal.Decimal, opts ...Options) (decimal.Decimal, error)

NPV returns the net present value of a stream of cashflows where cashflows[0] is the cashflow at t=0, cashflows[1] at t=1, and so on.

NPV = Σ cashflows[i] / (1+rate)^i

This convention (t=0 first) matches numpy_financial.npv and is the natural input for IRR. It differs from Excel's NPV, which assumes the first value is at t=1; see NPVExcel for that variant.

func NPVExcel

func NPVExcel(rate decimal.Decimal, cashflows []decimal.Decimal, opts ...Options) (decimal.Decimal, error)

NPVExcel matches Excel's NPV(rate, value1, value2, ...): the first cashflow is treated as occurring at t=1 (not t=0). Provided for users porting spreadsheets verbatim.

func New

func New(s string) (decimal.Decimal, error)

New parses s as a decimal at the package's internal precision (28 digits). Use this to build inputs for finance functions from human-readable strings.

rate := finance.MustNew("0.00375")
pv   := finance.MustNew("250000")

func NominalRate

func NominalRate(effective decimal.Decimal, periodsPerYear int, opts ...Options) (decimal.Decimal, error)

NominalRate converts an effective annual rate into the equivalent nominal annual rate that, when compounded periodsPerYear times per year, yields the same effective annual rate.

nominal = m * ((1 + effective)^(1/m) - 1)

Excel equivalent: NOMINAL(effect_rate, npery)

func PMT

func PMT(rate decimal.Decimal, nper int, pv, fv decimal.Decimal, timing PaymentTiming, opts ...Options) (decimal.Decimal, error)

PMT computes the periodic payment of an annuity given an interest rate per period, total number of periods, present value, future value, and payment timing. Result follows Excel's sign convention: PMT comes back with the opposite sign of (PV + FV).

rate := finance.MustNew("0.005")        // 0.5% / month
pv   := finance.MustNew("100000")       // borrow 100,000
pmt, _ := finance.PMT(rate, 360, pv, finance.Zero, finance.PaymentEnd)
// pmt ≈ -599.5505...   (you pay ~599.55 per month)

Excel equivalent: PMT(rate, nper, pv, fv, type)

func PPMT

func PPMT(rate decimal.Decimal, per, nper int, pv, fv decimal.Decimal, timing PaymentTiming, opts ...Options) (decimal.Decimal, error)

PPMT returns the principal portion of the per-th payment. By definition PMT = IPMT + PPMT for every period, so PPMT is computed as PMT - IPMT in the same units.

Excel equivalent: PPMT(rate, per, nper, pv, fv, type)

func PV

func PV(rate decimal.Decimal, nper int, pmt, fv decimal.Decimal, timing PaymentTiming, opts ...Options) (decimal.Decimal, error)

PV computes the present value of an annuity (or loan) given the periodic rate, number of periods, periodic payment, future value, and payment timing.

Excel equivalent: PV(rate, nper, pmt, fv, type)

func Price

func Price(settlement, maturity time.Time, rate, yld, redemption decimal.Decimal,
	freq int, basis DayCountBasis, opts ...Options) (decimal.Decimal, error)

Price returns the bond's price per $100 face value given its annual coupon rate, yield, redemption value, frequency, and day-count basis.

Excel equivalent: PRICE(settlement, maturity, rate, yld, redemption, frequency, basis)

func RATE

func RATE(nper int, pmt, pv, fv decimal.Decimal, timing PaymentTiming, guess decimal.Decimal, opts ...Options) (decimal.Decimal, error)

RATE solves for the periodic interest rate that satisfies the TVM equation, using Newton's method seeded at 10% (Excel's default guess). Returns an error if the iteration fails to converge.

Excel equivalent: RATE(nper, pmt, pv, fv, type, [guess])

Pass an initial guess via guess. When guess is omitted, 0.1 is used.

func SLN

func SLN(cost, salvage decimal.Decimal, life int, opts ...Options) (decimal.Decimal, error)

SLN returns the straight-line depreciation per period:

SLN = (cost - salvage) / life

Excel equivalent: SLN(cost, salvage, life)

func SYD

func SYD(cost, salvage decimal.Decimal, life, per int, opts ...Options) (decimal.Decimal, error)

SYD returns the depreciation in the per-th period under the sum-of-years-digits method:

SYD = (cost - salvage) · (life - per + 1) / (life · (life + 1) / 2)

Excel equivalent: SYD(cost, salvage, life, per)

func ScheduleTable

func ScheduleTable(rate decimal.Decimal, nper int, pv, fv decimal.Decimal, timing PaymentTiming, opts ...Options) (insyra.IDataTable, error)

ScheduleTable returns the amortization schedule as an insyra DataTable with columns: Period, Payment, Interest, Principal, Balance. Numeric columns are stored as decimal.Decimal values so the table preserves the precision of the source calculation; convert via .String() if you need a textual export.

func TBillEq

func TBillEq(settlement, maturity time.Time, discount decimal.Decimal, opts ...Options) (decimal.Decimal, error)

TBillEq returns the bond-equivalent yield of a Treasury bill.

TBILLEQ = 365 · discount / (360 - discount · DSM)

where DSM is the number of calendar days from settlement to maturity. Returns an error if maturity ≤ settlement or DSM > 365.

Excel equivalent: TBILLEQ(settlement, maturity, discount)

func TBillPrice

func TBillPrice(settlement, maturity time.Time, discount decimal.Decimal, opts ...Options) (decimal.Decimal, error)

TBillPrice returns the price per $100 face value of a Treasury bill at the given discount rate.

TBILLPRICE = 100 · (1 - discount · DSM / 360)

Excel equivalent: TBILLPRICE(settlement, maturity, discount)

func TBillYield

func TBillYield(settlement, maturity time.Time, pr decimal.Decimal, opts ...Options) (decimal.Decimal, error)

TBillYield returns the yield of a Treasury bill given its price per $100 face value.

TBILLYIELD = ((100 - pr) / pr) · (360 / DSM)

Excel equivalent: TBILLYIELD(settlement, maturity, pr)

func VDB

func VDB(cost, salvage decimal.Decimal, life int, startPeriod, endPeriod, factor decimal.Decimal, noSwitch bool, opts ...Options) (decimal.Decimal, error)

VDB returns the cumulative depreciation between startPeriod and endPeriod under the variable declining-balance method.

startPeriod and endPeriod are real numbers in [0, life]; partial periods are pro-rated linearly within whatever depreciation method applies in that period. With noSwitch=false (Excel's default), the method automatically switches to straight-line for the remaining life as soon as straight-line would yield more depreciation than declining balance — which is what most US tax schedules require.

Excel equivalent: VDB(cost, salvage, life, start_period, end_period, factor, no_switch)

func XIRR

func XIRR(values []decimal.Decimal, dates []time.Time, guess decimal.Decimal, opts ...Options) (decimal.Decimal, error)

XIRR returns the rate that drives XNPV to zero. Uses Newton's method seeded at guess (or 0.1 if guess is the zero Decimal).

Excel equivalent: XIRR(values, dates, [guess])

func XNPV

func XNPV(rate decimal.Decimal, values []decimal.Decimal, dates []time.Time, opts ...Options) (decimal.Decimal, error)

XNPV returns the net present value of a stream of cashflows that occur on arbitrary dates. dates[0] is treated as the reference (t=0) and every other cashflow is discounted by (dates[i] - dates[0]) / 365 years, matching Excel's convention.

XNPV = Σ values[i] / (1 + rate)^((dates[i] - dates[0]) / 365)

Excel equivalent: XNPV(rate, values, dates)

func Yield

func Yield(settlement, maturity time.Time, rate, pr, redemption decimal.Decimal,
	freq int, basis DayCountBasis, guess decimal.Decimal,
	opts ...Options) (decimal.Decimal, error)

Yield solves for the bond yield that reproduces the given price per $100 face. Uses Newton's method with a finite-difference derivative seeded at the provided guess (or 0.05 if guess is the zero Decimal).

Excel equivalent: YIELD(settlement, maturity, rate, pr, redemption, frequency, basis)

Types

type AmortizationRow

type AmortizationRow struct {
	Period    int             // 1-indexed period number
	Payment   decimal.Decimal // total payment in this period (constant)
	Interest  decimal.Decimal // interest portion of the payment
	Principal decimal.Decimal // principal portion of the payment
	Balance   decimal.Decimal // remaining balance after this payment
}

AmortizationRow is one row in an amortization schedule. Values are kept as decimal.Decimal so callers don't lose precision when reading back individual entries.

func AmortizationSchedule

func AmortizationSchedule(rate decimal.Decimal, nper int, pv, fv decimal.Decimal, timing PaymentTiming, opts ...Options) ([]AmortizationRow, error)

AmortizationSchedule returns the full per-period amortization schedule of a level-payment loan. Use ScheduleTable for an insyra.IDataTable representation suitable for printing or export.

type DayCountBasis

type DayCountBasis uint8

DayCountBasis selects how day counts and year lengths are computed in bond and ACCRINT-style functions. Values match Excel's "basis" parameter exactly.

const (
	// Basis30_360US is the US (NASD) 30/360 convention. Excel basis = 0.
	Basis30_360US DayCountBasis = 0
	// BasisActualActual uses calendar days for both numerator and a
	// year length derived from the years actually spanned by the
	// period (ISDA actual/actual). Excel basis = 1.
	BasisActualActual DayCountBasis = 1
	// BasisActual360 uses calendar days over a 360-day year — common
	// for money-market instruments. Excel basis = 2.
	BasisActual360 DayCountBasis = 2
	// BasisActual365 uses calendar days over a fixed 365-day year.
	// Excel basis = 3.
	BasisActual365 DayCountBasis = 3
	// Basis30_360EU is the European 30/360 convention. Excel basis = 4.
	Basis30_360EU DayCountBasis = 4
)

type Options

type Options struct {
	// Scale is the number of decimal places kept in the result.
	// When 0, DefaultScale (10) is used.
	Scale int32
	// Mode is the rounding mode applied to the result. When empty,
	// RoundHalfUp is used. Available values: RoundHalfUp, RoundHalfEven,
	// RoundHalfDown, RoundUp, RoundDown, RoundCeiling, RoundFloor,
	// Round05Up, RoundUnnecessary.
	Mode RoundingMode
}

Options controls precision and rounding of finance results. Zero-value Options selects the high-precision defaults: Scale=10 and RoundHalfUp. Scale and Mode resolve independently — leaving either at its zero value (0 / "") keeps that field's default while letting the other be customized.

type PaymentTiming

type PaymentTiming uint8

PaymentTiming indicates whether an annuity payment occurs at the end of each period (ordinary annuity, Excel's type=0) or at the beginning (annuity due, Excel's type=1).

const (
	// PaymentEnd places each payment at the end of its period.
	// Equivalent to Excel's type=0. This is the default.
	PaymentEnd PaymentTiming = 0
	// PaymentBegin places each payment at the start of its period.
	// Equivalent to Excel's type=1.
	PaymentBegin PaymentTiming = 1
)

type RoundingMode

type RoundingMode string

RoundingMode is a string-typed selector for the rounding strategy applied to finance results. A string enum is used (rather than the underlying decimal.RoundingMode uint8) so that the empty string is unambiguously "use default" — there is no zero-value collision with any real mode.

const (
	// RoundHalfUp is the everyday 四捨五入 rule: half values move away
	// from zero. 1.235 → 1.24, -1.235 → -1.24. This is the default.
	RoundHalfUp RoundingMode = "half-up"
	// RoundHalfEven is banker's rounding (IEEE 754 / Python decimal
	// default): half values pick the neighbor whose last digit is
	// even, eliminating HalfUp's systematic upward bias on long sums.
	// 1.225 → 1.22, 1.235 → 1.24.
	RoundHalfEven RoundingMode = "half-even"
	// RoundHalfDown is "round half toward zero": half values stay put
	// rather than stepping away. 1.235 → 1.23, -1.235 → -1.23.
	RoundHalfDown RoundingMode = "half-down"
	// RoundUp rounds away from zero on any non-zero residue.
	// 1.231 → 1.24, -1.231 → -1.24.
	RoundUp RoundingMode = "up"
	// RoundDown truncates toward zero (the absolute value never grows).
	// 1.235 → 1.23, -1.235 → -1.23.
	RoundDown RoundingMode = "down"
	// RoundCeiling rounds toward +∞ on any non-zero residue.
	// 1.231 → 1.24, -1.231 → -1.23.
	RoundCeiling RoundingMode = "ceiling"
	// RoundFloor rounds toward -∞ on any non-zero residue.
	// 1.231 → 1.23, -1.231 → -1.24.
	RoundFloor RoundingMode = "floor"
	// Round05Up implements Python's ROUND_05UP rule: after truncating
	// toward zero, if the kept last digit is 0 or 5 then any non-zero
	// residue causes a step away from zero; otherwise the residue is
	// dropped.
	Round05Up RoundingMode = "05up"
	// RoundUnnecessary asserts that no rounding will be required. If
	// an operation under this mode has to discard a non-zero residue,
	// it panics with decimal.ErrRoundingNecessary.
	RoundUnnecessary RoundingMode = "unnecessary"
)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL