README

go-financial

This package is a go native port of the numpy-financial package with some additional helper
functions.

The functions in this package are a scalar version of their vectorised counterparts in
the numpy-financial library.

unit-tests status Go Report Card codecov GoDoc Release PRs Welcome

Currently, only some functions are ported,
which are as follows:

numpy-financial function go native function ported? info
fv Computes the future value
ipmt Computes interest payment for a loan
pmt Computes the fixed periodic payment(principal + interest) made against a loan amount
ppmt Computes principal payment for a loan
nper Computes the number of periodic payments
pv Computes the present value of a payment
rate Computes the rate of interest per period
irr Computes the internal rate of return
npv Computes the net present value of a series of cash flow
mirr Computes the modified internal rate of return

Index

While the numpy-financial package contains a set of elementary financial functions, this pkg also contains some helper functions on top of it. Their usage and description can be found below:

Detailed documentation is available at godoc.

Amortisation(Generate Table)

To generate the schedule for a loan of 20 lakhs over 15years at 12%p.a., you can do the following:

package main

import (
	"time"

	"github.com/shopspring/decimal"

	financial "github.com/razorpay/go-financial"
	"github.com/razorpay/go-financial/enums/frequency"
	"github.com/razorpay/go-financial/enums/interesttype"
	"github.com/razorpay/go-financial/enums/paymentperiod"
)

func main() {
	loc, err := time.LoadLocation("Asia/Kolkata")
	if err != nil {
		panic("location loading error")
	}
	currentDate := time.Date(2009, 11, 11, 4, 30, 0, 0, loc)
	config := financial.Config{

		// start date is inclusive
		StartDate: currentDate,

		// end date is inclusive.
		EndDate:   currentDate.AddDate(15, 0, 0).AddDate(0, 0, -1),
		Frequency: frequency.ANNUALLY,

		// AmountBorrowed is in paisa
		AmountBorrowed: decimal.NewFromInt(200000000),

		// InterestType can be flat or reducing
		InterestType: interesttype.REDUCING,

		// interest is in basis points
		Interest: decimal.NewFromInt(1200),

		// amount is paid at the end of the period
		PaymentPeriod: paymentperiod.ENDING,

		// all values will be rounded
		EnableRounding: true,

		// it will be rounded to nearest int
		RoundingPlaces: 0,

		// no error is tolerated
		RoundingErrorTolerance: decimal.Zero,
	}
	amortization, err := financial.NewAmortization(&config)
	if err != nil {
		panic(err)
	}

	rows, err := amortization.GenerateTable()
	if err != nil {
		panic(err)
	}
	// Generates json output of the data
	financial.PrintRows(rows)
	// Generates a html file with plots of the given data.
	financial.PlotRows(rows, "20lakh-loan-repayment-schedule")
} 
  
Generated plot

Fv

func Fv(rate float64, nper int64, pmt float64, pv float64, when paymentperiod.Type) float64  

Params:

 pv   : a present value 
rate  : an interest rate compounded once per period 
nper  : total number of periods 
pmt   : a (fixed) payment, paid either at the beginning (when =  1)
        or the end (when = 0) of each period 
when  : specification of whether payment is made at the beginning (when = 1)
        or the end (when = 0) of each period  

Fv computes future value at the end of some periods(nper).

Example(Fv)

If an investment has a 6% p.a. rate of return, compounded annually, and you are investing ₹ 10,000 at the end of each year with initial investment of ₹ 10,000, how much amount will you get at the end of 10 years ?

package main

import (
	"fmt"

	gofinancial "github.com/razorpay/go-financial"
	"github.com/razorpay/go-financial/enums/paymentperiod"
	"github.com/shopspring/decimal"
)

func main() {
	rate := decimal.NewFromFloat(0.06)
	nper := int64(10)
	payment := decimal.NewFromInt(-10000)
	pv := decimal.NewFromInt(-10000)
	when := paymentperiod.ENDING

	fv := gofinancial.Fv(rate, nper, payment, pv, when)
	fmt.Printf("fv:%v", fv.Round(0))
	// Output:
	// fv:149716
}

Run on go-playground

Pv

func Pv(rate float64, nper int64, pmt float64, fv float64, when paymentperiod.Type) float64 

Params:

 fv	: a future value
 rate	: an interest rate compounded once per period
 nper	: total number of periods
 pmt	: a (fixed) payment, paid either
	  at the beginning (when =  1) or the end (when = 0) of each period
 when	: specification of whether payment is made
	  at the beginning (when = 1) or the end
	  (when = 0) of each period

Pv computes present value some periods(nper) before the future value.

Example(Pv)

If an investment has a 6% p.a. rate of return, compounded annually, and you wish to possess ₹ 1,49,716 at the end of 10 peroids while providing ₹ 10,000 per period, how much should you put as your initial deposit ?

package main

import (
	"fmt"

	gofinancial "github.com/razorpay/go-financial"
	"github.com/razorpay/go-financial/enums/paymentperiod"
	"github.com/shopspring/decimal"
)

func main() {
	rate := decimal.NewFromFloat(0.06)
	nper := int64(10)
	payment := decimal.NewFromInt(-10000)
	fv := decimal.NewFromInt(149716)
	when := paymentperiod.ENDING

	pv := gofinancial.Pv(rate, nper, payment, fv, when)
	fmt.Printf("pv:%v", pv.Round(0))
	// Output:
	// pv:-10000	
}

Run on go-playground

Npv

func Npv(rate float64, values []float64) float64 

Params:

 rate	: a discount rate compounded once per period
 values	: the value of the cash flow for that time period. Values provided here must be an array of float64

Npv computes net present value based on the discount rate and the values of cash flow over the course of the cash flow period

Example(Npv)

Given a rate of 0.281 per period and initial deposit of 100 followed by withdrawls of 39, 59, 55, 20. What is the net present value of the cash flow ?

package main

import (
	"fmt"
	gofinancial "github.com/razorpay/go-financial"	
	"github.com/shopspring/decimal"
)

func main() {
	rate :=  decimal.NewFromFloat(0.281)
	values := []decimal.Decimal{decimal.NewFromInt(-100), decimal.NewFromInt(39), decimal.NewFromInt(59), decimal.NewFromInt(55), decimal.NewFromInt(20)}
	npv := gofinancial.Npv(rate, values)
	fmt.Printf("npv:%v", npv)
	// Output:
	// npv: -0.008478591638426
}

Run on go-playground

Pmt

func Pmt(rate float64, nper int64, pv float64, fv float64, when paymentperiod.Type) float64  

Params:

rate  : rate of interest compounded once per period 
nper  : total number of periods to be compounded for 
pv    : present value (e.g., an amount borrowed) 
fv    : future value (e.g., 0) 
when  : specification of whether payment is made at the
        beginning (when = 1) or the end (when = 0) of each period  

Pmt compute the fixed payment(principal + interest) against a loan amount ( fv = 0).
It can also be used to calculate the recurring payments needed to achieve a certain future value given an initial deposit, a fixed periodically compounded interest rate, and the total number of periods.

Example(Pmt-Loan)

If you have a loan of 1,00,000 to be paid after 2 years, with 18% p.a. compounded annually, how much total payment will you have to do each month? This example generates the total monthly payment(principal plus interest) needed for a loan of 1,00,000 over 2 years with 18% rate of interest compounded monthly

package main

import (
	"fmt"
	gofinancial "github.com/razorpay/go-financial"
	"github.com/razorpay/go-financial/enums/paymentperiod"
	"github.com/shopspring/decimal"
)

func main() {
	rate := decimal.NewFromFloat(0.18 / 12)
	nper := int64(12 * 2)
	pv := decimal.NewFromInt(100000)
	fv := decimal.NewFromInt(0)
	when := paymentperiod.ENDING
	pmt := gofinancial.Pmt(rate, nper, pv, fv, when)
	fmt.Printf("payment:%v", pmt.Round(0))
        // Output:
        // payment:-4992
}

Run on go-playground

Example(Pmt-Investment)

If an investment gives 6% rate of return compounded annually, how much amount should you invest each month to get 10,00,000 amount after 10 years?

package main

import (
	"fmt"
	gofinancial "github.com/razorpay/go-financial"
	"github.com/razorpay/go-financial/enums/paymentperiod"
	"github.com/shopspring/decimal"
)

func main() {
	rate := decimal.NewFromFloat(0.06)
	nper := int64(10)
	pv := decimal.NewFromInt(0)
	fv := decimal.NewFromInt(1000000)
	when := paymentperiod.BEGINNING
	pmt := gofinancial.Pmt(rate, nper, pv, fv, when)
	fmt.Printf("payment each year:%v", pmt.Round(0))
        // Output:
        // payment each year:-71574
}

Run on go-playground

IPmt

func IPmt(rate float64, per int64, nper int64, pv float64, fv float64, when paymentperiod.Type) float64  

IPmt computes interest payment for a loan under a given period.

Params:

rate  : rate of interest compounded once per period 
per   : period under consideration 
nper  : total number of periods to be compounded for 
pv    : present value (e.g., an amount borrowed) 
fv    : future value (e.g., 0) 
when  : specification of whether payment is made at the
        beginning (when = 1) or the end (when = 0) of each period  
Example(IPmt-Loan)

If you have a loan of 1,00,000 to be paid after 2 years, with 18% p.a. compounded annually, how much of the total payment done each month will be interest ?

package main

import (
	"fmt"
	gofinancial "github.com/razorpay/go-financial"
	"github.com/razorpay/go-financial/enums/paymentperiod"
	"github.com/shopspring/decimal"
)

func main() {
	rate := decimal.NewFromFloat(0.18 / 12)
	nper := int64(12 * 2)
	pv := decimal.NewFromInt(100000)
	fv := decimal.NewFromInt(0)
	when := paymentperiod.ENDING

	for i := int64(0); i < nper; i++ {
		ipmt := gofinancial.IPmt(rate, i+1, nper, pv, fv, when)
		fmt.Printf("period:%d interest:%v\n", i+1, ipmt.Round(0))
	}
	// Output:
	// period:1 interest:-1500
	// period:2 interest:-1448
	// period:3 interest:-1394
	// period:4 interest:-1340
	// period:5 interest:-1286
	// period:6 interest:-1230
	// period:7 interest:-1174
	// period:8 interest:-1116
	// period:9 interest:-1058
	// period:10 interest:-999
	// period:11 interest:-939
	// period:12 interest:-879
	// period:13 interest:-817
	// period:14 interest:-754
	// period:15 interest:-691
	// period:16 interest:-626
	// period:17 interest:-561
	// period:18 interest:-494
	// period:19 interest:-427
	// period:20 interest:-358
	// period:21 interest:-289
	// period:22 interest:-218
	// period:23 interest:-146
	// period:24 interest:-74
}

Run on go-playground

Example(IPmt-Investment)

If an investment gives 6% rate of return compounded annually, how much interest will you earn each year against your yearly payments(71574) to get 10,00,000 amount after 10 years

package main

import (
	"fmt"
	gofinancial "github.com/razorpay/go-financial"
	"github.com/razorpay/go-financial/enums/paymentperiod"
	"github.com/shopspring/decimal"
)

func main() {
	rate := decimal.NewFromFloat(0.06)
	nper := int64(10)
	pv := decimal.NewFromInt(0)
	fv := decimal.NewFromInt(1000000)
	when := paymentperiod.BEGINNING

	for i := int64(1); i < nper+1; i++ {
		ipmt := gofinancial.IPmt(rate, i+1, nper, pv, fv, when)
		fmt.Printf("period:%d interest earned:%v\n", i, ipmt.Round(0))
	}
	// Output:
	// period:1 interest earned:4294
	// period:2 interest earned:8846
	// period:3 interest earned:13672
	// period:4 interest earned:18786
	// period:5 interest earned:24208
	// period:6 interest earned:29955
	// period:7 interest earned:36047
	// period:8 interest earned:42504
	// period:9 interest earned:49348
	// period:10 interest earned:56604
}

Run on go-playground

PPmt

func PPmt(rate float64, per int64, nper int64, pv float64, fv float64, when paymentperiod.Type, round bool) float64  

PPmt computes principal payment for a loan under a given period.

Params:

rate  : rate of interest compounded once per period 
per   : period under consideration 
nper  : total number of periods to be compounded for 
pv    : present value (e.g., an amount borrowed) 
fv    : future value (e.g., 0) 
when  : specification of whether payment is made at 
        the beginning (when = 1) or the end (when = 0) of each period  
Example(PPmt-Loan)

If you have a loan of 1,00,000 to be paid after 2 years, with 18% p.a. compounded annually, how much total payment done each month will be principal ?

package main

import (
	"fmt"
	gofinancial "github.com/razorpay/go-financial"
	"github.com/razorpay/go-financial/enums/paymentperiod"
	"github.com/shopspring/decimal"
)

func main() {
	rate := decimal.NewFromFloat(0.18 / 12)
	nper := int64(12 * 2)
	pv := decimal.NewFromInt(100000)
	fv := decimal.NewFromInt(0)
	when := paymentperiod.ENDING

	for i := int64(0); i < nper; i++ {
		ppmt := gofinancial.PPmt(rate, i+1, nper, pv, fv, when)
		fmt.Printf("period:%d principal:%v\n", i+1, ppmt.Round(0))
	}
	// Output:
	// period:1 principal:-3492
	// period:2 principal:-3545
	// period:3 principal:-3598
	// period:4 principal:-3652
	// period:5 principal:-3707
	// period:6 principal:-3762
	// period:7 principal:-3819
	// period:8 principal:-3876
	// period:9 principal:-3934
	// period:10 principal:-3993
	// period:11 principal:-4053
	// period:12 principal:-4114
	// period:13 principal:-4176
	// period:14 principal:-4238
	// period:15 principal:-4302
	// period:16 principal:-4366
	// period:17 principal:-4432
	// period:18 principal:-4498
	// period:19 principal:-4566
	// period:20 principal:-4634
	// period:21 principal:-4704
	// period:22 principal:-4774
	// period:23 principal:-4846
	// period:24 principal:-4919
}

Run on go-playground

Nper

func Nper(rate float64, pmt float64, pv float64, fv float64, when paymentperiod.Type) float64 

Params:

rate   : an interest rate compounded once per period
pmt    : a (fixed) payment, paid either at the beginning (when =  1)
         or the end (when = 0) of each period
pv     : a present value
fv     : a future value
when   : specification of whether payment is made at the beginning (when = 1)
         or the end (when = 0) of each period  

Nper computes the number of periodic payments.

Example(Nper-Loan)

If a loan has a 6% annual interest, compounded monthly, and you only have $200/month to pay towards the loan, how long would it take to pay-off the loan of $5,000?

package main

import (
	"fmt"

	gofinancial "github.com/razorpay/go-financial"
	"github.com/razorpay/go-financial/enums/paymentperiod"
	"github.com/shopspring/decimal"
)


func main() {
	rate := decimal.NewFromFloat(0.06 / 12)
	fv := decimal.NewFromFloat(0)
	payment := decimal.NewFromFloat(-200)
	pv := decimal.NewFromFloat(5000)
	when := paymentperiod.ENDING

	nper,err := gofinancial.Nper(rate, payment, pv, fv, when)
	if err != nil{
		fmt.Printf("error:%v\n", err)
	}
	fmt.Printf("nper:%v",nper.Ceil())
	// Output:
	// nper:27
}

Run on go-playground

Documentation

Overview

This package is a go native port of the numpy-financial package with some additional helper functions.

The functions in this package are a scalar version of their vectorised counterparts in the numpy-financial(https://github.com/numpy/numpy-financial) library.

Currently, only some functions are ported, the remaining will be ported soon.

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrPayment          = errors.New("payment not matching interest plus principal")
	ErrUnevenEndDate    = errors.New("uneven end date")
	ErrInvalidFrequency = errors.New("invalid frequency")
	ErrNotEqual         = errors.New("input values are not equal")
	ErrOutOfBounds      = errors.New("error in representing data as it is out of bounds")
)

Functions

func DoPrincipalAdjustmentDueToRounding

func DoPrincipalAdjustmentDueToRounding(finalRow *Row, rows []Row, principal decimal.Decimal, round bool, places int32)

DoPrincipalAdjustmentDueToRounding takes care of errors in total principal to be collected and adjusts it against the the final principal and payment amount.

func Fv

Fv computes future value at the end of some periods(nper) by solving the following equation:

fv +
pv*(1+rate)**nper +
pmt*(1 + rate*when)/rate*((1 + rate)**nper - 1) == 0

Params:

 pv	: a present value
 rate	: an interest rate compounded once per period
 nper	: total number of periods
 pmt	: a (fixed) payment, paid either
	  at the beginning (when =  1) or the end (when = 0) of each period
 when	: specification of whether payment is made
	  at the beginning (when = 1) or the end
	  (when = 0) of each period

References:

[WRW] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
Open Document Format for Office Applications (OpenDocument)v1.2,
Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
Pre-Draft 12. Organization for the Advancement of Structured Information
Standards (OASIS). Billerica, MA, USA. [ODT Document].
Available:
http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formula
OpenDocument-formula-20090508.odt
Example

If an investment has a 6% p.a. rate of return, compounded annually, and you are investing ₹ 10,000 at the end of each year with initial investment of ₹ 10,000, how much amount will you get at the end of 10 years ?

package main

import (
	"fmt"

	gofinancial "github.com/razorpay/go-financial"
	"github.com/razorpay/go-financial/enums/paymentperiod"
	"github.com/shopspring/decimal"
)

func main() {
	rate := decimal.NewFromFloat(0.06)
	nper := int64(10)
	payment := decimal.NewFromInt(-10000)
	pv := decimal.NewFromInt(-10000)
	when := paymentperiod.ENDING

	fv := gofinancial.Fv(rate, nper, payment, pv, when)
	fmt.Printf("fv:%v", fv.Round(0))
}
Output:

fv:149716

func GetPeriodDifference

func GetPeriodDifference(from time.Time, to time.Time, freq frequency.Type) (int, error)

func IPmt

IPmt computes interest payment for a loan under a given period.

Params:

 rate	: rate of interest compounded once per period
 per	: period under consideration
 nper	: total number of periods to be compounded for
 pv	: present value (e.g., an amount borrowed)
 fv	: future value (e.g., 0)
 when	: specification of whether payment is made
	  at the beginning (when = 1) or the end
	  (when = 0) of each period

References:

[WRW] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
Open Document Format for Office Applications (OpenDocument)v1.2,
Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
Pre-Draft 12. Organization for the Advancement of Structured Information
Standards (OASIS). Billerica, MA, USA. [ODT Document].
Available:
http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formula
OpenDocument-formula-20090508.odt
Example (Investment)

If an investment gives 6% rate of return compounded annually, how much interest will you earn each year against your yearly payments(71574) to get 10,00,000 amount after 10 years

package main

import (
	"fmt"

	gofinancial "github.com/razorpay/go-financial"
	"github.com/razorpay/go-financial/enums/paymentperiod"
	"github.com/shopspring/decimal"
)

func main() {
	rate := decimal.NewFromFloat(0.06)
	nper := int64(10)
	pv := decimal.NewFromInt(0)
	fv := decimal.NewFromInt(1000000)
	when := paymentperiod.BEGINNING

	for i := int64(1); i < nper+1; i++ {
		ipmt := gofinancial.IPmt(rate, i+1, nper, pv, fv, when)
		fmt.Printf("period:%d interest earned:%v\n", i, ipmt.Round(0))
	}
}
Output:

period:1 interest earned:4294
period:2 interest earned:8846
period:3 interest earned:13672
period:4 interest earned:18786
period:5 interest earned:24208
period:6 interest earned:29955
period:7 interest earned:36047
period:8 interest earned:42504
period:9 interest earned:49348
period:10 interest earned:56604
Example (Loan)

If you have a loan of 1,00,000 to be paid after 2 years, with 18% p.a. compounded annually, how much of the total payment done each month will be interest ?

package main

import (
	"fmt"

	gofinancial "github.com/razorpay/go-financial"
	"github.com/razorpay/go-financial/enums/paymentperiod"
	"github.com/shopspring/decimal"
)

func main() {
	rate := decimal.NewFromFloat(0.18 / 12)
	nper := int64(12 * 2)
	pv := decimal.NewFromInt(100000)
	fv := decimal.NewFromInt(0)
	when := paymentperiod.ENDING

	for i := int64(0); i < nper; i++ {
		ipmt := gofinancial.IPmt(rate, i+1, nper, pv, fv, when)
		fmt.Printf("period:%d interest:%v\n", i+1, ipmt.Round(0))
	}
}
Output:

period:1 interest:-1500
period:2 interest:-1448
period:3 interest:-1394
period:4 interest:-1340
period:5 interest:-1286
period:6 interest:-1230
period:7 interest:-1174
period:8 interest:-1116
period:9 interest:-1058
period:10 interest:-999
period:11 interest:-939
period:12 interest:-879
period:13 interest:-817
period:14 interest:-754
period:15 interest:-691
period:16 interest:-626
period:17 interest:-561
period:18 interest:-494
period:19 interest:-427
period:20 interest:-358
period:21 interest:-289
period:22 interest:-218
period:23 interest:-146
period:24 interest:-74

func Nper

func Nper(rate decimal.Decimal, pmt decimal.Decimal, pv decimal.Decimal, fv decimal.Decimal, when paymentperiod.Type) (result decimal.Decimal, err error)

Nper computes the number of periodic payments by solving the equation:

fv +
pv*(1 + rate)**nper +
pmt*(1 + rate*when)/rate*((1 + rate)**nper - 1) = 0

Params:

 rate	: an interest rate compounded once per period
 pmt	: a (fixed) payment, paid either
	  at the beginning (when =  1) or the end (when = 0) of each period
 pv	: a present value
 when	: specification of whether payment is made
	  at the beginning (when = 1) or the end
	  (when = 0) of each period
 fv: a future value
 when	: specification of whether payment is made
	  at the beginning (when = 1) or the end
	  (when = 0) of each period
Example

If a loan has a 6% annual interest, compounded monthly, and you only have $200/month to pay towards the loan, how long would it take to pay-off the loan of $5,000?

package main

import (
	"fmt"

	gofinancial "github.com/razorpay/go-financial"
	"github.com/razorpay/go-financial/enums/paymentperiod"
	"github.com/shopspring/decimal"
)

func main() {
	rate := decimal.NewFromFloat(0.06 / 12)
	fv := decimal.Zero
	payment := decimal.NewFromInt(-200)
	pv := decimal.NewFromInt(5000)
	when := paymentperiod.ENDING

	nper, _ := gofinancial.Nper(rate, payment, pv, fv, when)
	fmt.Printf("nper:%v", nper.Ceil())
}
Output:

nper:27

func Npv

func Npv(rate decimal.Decimal, values []decimal.Decimal) decimal.Decimal

Npv computes the Net Present Value of a cash flow series

Params:

rate	: a discount rate applied once per period
values	: the value of the cash flow for that time period. Values provided here must be an array of float64

References:

L. J. Gitman, “Principles of Managerial Finance, Brief,” 3rd ed., Addison-Wesley, 2003, pg. 346.
Example

Given a discount rate of 8% per period and initial deposit of 40000 followed by withdrawls of 5000, 8000, 12000 and 30000. What is the net present value of the cash flow ?

package main

import (
	"fmt"

	gofinancial "github.com/razorpay/go-financial"
	"github.com/shopspring/decimal"
)

func main() {
	rate := decimal.NewFromFloat(0.08)
	values := []decimal.Decimal{decimal.NewFromInt(-40000), decimal.NewFromInt(5000), decimal.NewFromInt(8000), decimal.NewFromInt(12000), decimal.NewFromInt(30000)}
	npv := gofinancial.Npv(rate, values)
	fmt.Printf("npv:%v", npv.Round(0))
}
Output:

npv:3065

func PPmt

PPmt computes principal payment for a loan under a given period.

Params:

 rate	: rate of interest compounded once per period
 per	: period under consideration
 nper	: total number of periods to be compounded for
 pv	: present value (e.g., an amount borrowed)
 fv	: future value (e.g., 0)
 when	: specification of whether payment is made
	  at the beginning (when = 1) or the end
	  (when = 0) of each period

References:

[WRW] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
Open Document Format for Office Applications (OpenDocument)v1.2,
Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
Pre-Draft 12. Organization for the Advancement of Structured Information
Standards (OASIS). Billerica, MA, USA. [ODT Document].
Available:
http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formula
OpenDocument-formula-20090508.odt
Example (Loan)

If you have a loan of 1,00,000 to be paid after 2 years, with 18% p.a. compounded annually, how much total payment done each month will be principal ?

package main

import (
	"fmt"

	gofinancial "github.com/razorpay/go-financial"
	"github.com/razorpay/go-financial/enums/paymentperiod"
	"github.com/shopspring/decimal"
)

func main() {
	rate := decimal.NewFromFloat(0.18 / 12)
	nper := int64(12 * 2)
	pv := decimal.NewFromInt(100000)
	fv := decimal.NewFromInt(0)
	when := paymentperiod.ENDING

	for i := int64(0); i < nper; i++ {
		ppmt := gofinancial.PPmt(rate, i+1, nper, pv, fv, when)
		fmt.Printf("period:%d principal:%v\n", i+1, ppmt.Round(0))
	}
}
Output:

period:1 principal:-3492
period:2 principal:-3545
period:3 principal:-3598
period:4 principal:-3652
period:5 principal:-3707
period:6 principal:-3762
period:7 principal:-3819
period:8 principal:-3876
period:9 principal:-3934
period:10 principal:-3993
period:11 principal:-4053
period:12 principal:-4114
period:13 principal:-4176
period:14 principal:-4238
period:15 principal:-4302
period:16 principal:-4366
period:17 principal:-4432
period:18 principal:-4498
period:19 principal:-4566
period:20 principal:-4634
period:21 principal:-4704
period:22 principal:-4774
period:23 principal:-4846
period:24 principal:-4919

func PlotRows

func PlotRows(rows []Row, fileName string) (err error)

PlotRows uses the go-echarts package to generate an interactive plot from the Rows array.

func Pmt

Pmt compute the fixed payment(principal + interest) against a loan amount ( fv = 0).

It can also be used to calculate the recurring payments needed to achieve a certain future value given an initial deposit, a fixed periodically compounded interest rate, and the total number of periods.

It is obtained by solving the following equation:

fv + pv*(1 + rate)**nper + pmt*(1 + rate*when)/rate*((1 + rate)**nper - 1) == 0

Params:

 rate	: rate of interest compounded once per period
 nper	: total number of periods to be compounded for
 pv	: present value (e.g., an amount borrowed)
 fv	: future value (e.g., 0)
 when	: specification of whether payment is made
	  at the beginning (when = 1) or the end
	  (when = 0) of each period

References:

[WRW] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
Open Document Format for Office Applications (OpenDocument)v1.2,
Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
Pre-Draft 12. Organization for the Advancement of Structured Information
Standards (OASIS). Billerica, MA, USA. [ODT Document].
Available:
http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formula
OpenDocument-formula-20090508.odt
Example (Investment)

If an investment gives 6% rate of return compounded annually, how much amount should you invest each month to get 10,00,000 amount after 10 years?

package main

import (
	"fmt"

	gofinancial "github.com/razorpay/go-financial"
	"github.com/razorpay/go-financial/enums/paymentperiod"
	"github.com/shopspring/decimal"
)

func main() {
	rate := decimal.NewFromFloat(0.06)
	nper := int64(10)
	pv := decimal.NewFromInt(0)
	fv := decimal.NewFromInt(1000000)
	when := paymentperiod.BEGINNING
	pmt := gofinancial.Pmt(rate, nper, pv, fv, when)
	fmt.Printf("payment each year:%v", pmt.Round(0))
}
Output:

payment each year:-71574
Example (Loan)

If you have a loan of 1,00,000 to be paid after 2 years, with 18% p.a. compounded annually, how much total payment will you have to do each month? This example generates the total monthly payment(principal plus interest) needed for a loan of 1,00,000 over 2 years with 18% rate of interest compounded monthly

package main

import (
	"fmt"

	gofinancial "github.com/razorpay/go-financial"
	"github.com/razorpay/go-financial/enums/paymentperiod"
	"github.com/shopspring/decimal"
)

func main() {
	rate := decimal.NewFromFloat(0.18 / 12)
	nper := int64(12 * 2)
	pv := decimal.NewFromInt(100000)
	fv := decimal.NewFromInt(0)
	when := paymentperiod.ENDING
	pmt := gofinancial.Pmt(rate, nper, pv, fv, when)
	fmt.Printf("payment:%v", pmt.Round(0))
}
Output:

payment:-4992

func PrintRows

func PrintRows(rows []Row)

PrintRows outputs a formatted json for given rows as input.

func Pv

Pv computes present value by solving the following equation:

fv +
pv*(1+rate)**nper +
pmt*(1 + rate*when)/rate*((1 + rate)**nper - 1) == 0

Params:

 fv	: a future value
 rate	: an interest rate compounded once per period
 nper	: total number of periods
 pmt	: a (fixed) payment, paid either
	  at the beginning (when =  1) or the end (when = 0) of each period
 when	: specification of whether payment is made
	  at the beginning (when = 1) or the end
	  (when = 0) of each period

References:

[WRW] Wheeler, D. A., E. Rathke, and R. Weir (Eds.) (2009, May).
Open Document Format for Office Applications (OpenDocument)v1.2,
Part 2: Recalculated Formula (OpenFormula) Format - Annotated Version,
Pre-Draft 12. Organization for the Advancement of Structured Information
Standards (OASIS). Billerica, MA, USA. [ODT Document].
Available:
http://www.oasis-open.org/committees/documents.php?wg_abbrev=office-formula
OpenDocument-formula-20090508.odt
Example

If an investment has a 6% p.a. rate of return, compounded annually, and you wish to possess ₹ 1,49,716 at the end of 10 peroids while providing ₹ 10,000 per period, how much should you put as your initial deposit ?

package main

import (
	"fmt"

	gofinancial "github.com/razorpay/go-financial"
	"github.com/razorpay/go-financial/enums/paymentperiod"
	"github.com/shopspring/decimal"
)

func main() {
	rate := decimal.NewFromFloat(0.06)
	nper := int64(10)
	payment := decimal.NewFromInt(-10000)
	fv := decimal.NewFromInt(149716)
	when := paymentperiod.ENDING

	pv := gofinancial.Pv(rate, nper, payment, fv, when)
	fmt.Printf("pv:%v", pv.Round(0))
}
Output:

pv:-10000

Types

type Amortization

type Amortization struct {
	Config    *Config
	Financial Financial
}

Amortization struct holds the configuration and financial details.

func NewAmortization

func NewAmortization(c *Config) (*Amortization, error)

NewAmortization return a new amortisation object with config and financial fields initialised.

func (Amortization) GenerateTable

func (a Amortization) GenerateTable() ([]Row, error)

GenerateTable constructs the amortization table based on the configuration.

Example

This example generates amortization table for a loan of 20 lakhs over 15years at 12% per annum.

package main

import (
	"time"

	gofinancial "github.com/razorpay/go-financial"
	"github.com/razorpay/go-financial/enums/frequency"
	"github.com/razorpay/go-financial/enums/interesttype"
	"github.com/razorpay/go-financial/enums/paymentperiod"
	"github.com/shopspring/decimal"
)

func main() {
	loc, err := time.LoadLocation("Asia/Kolkata")
	if err != nil {
		panic("location loading error")
	}
	currentDate := time.Date(2009, 11, 11, 4, 30, 0, 0, loc)
	config := gofinancial.Config{

		// start date is inclusive
		StartDate: currentDate,

		// end date is inclusive.
		EndDate:   currentDate.AddDate(15, 0, 0).AddDate(0, 0, -1),
		Frequency: frequency.ANNUALLY,

		// AmountBorrowed is in paisa
		AmountBorrowed: decimal.NewFromInt(200000000),

		// InterestType can be flat or reducing
		InterestType: interesttype.REDUCING,

		// interest is in basis points
		Interest: decimal.NewFromInt(1200),

		// amount is paid at the end of the period
		PaymentPeriod: paymentperiod.ENDING,

		// all values will be rounded
		EnableRounding: true,

		// it will be rounded to nearest int
		RoundingPlaces: 0,

		// no error is tolerated
		RoundingErrorTolerance: decimal.Zero,
	}
	amortization, err := gofinancial.NewAmortization(&config)
	if err != nil {
		panic(err)
	}

	rows, err := amortization.GenerateTable()
	if err != nil {
		panic(err)
	}
	gofinancial.PrintRows(rows)
}
Output:

[
	{
		"Period": 1,
		"StartDate": "2009-11-11T04:30:00+05:30",
		"EndDate": "2010-11-10T23:59:59+05:30",
		"Payment": "-29364848",
		"Interest": "-24000000",
		"Principal": "-5364848"
	},
	{
		"Period": 2,
		"StartDate": "2010-11-11T00:00:00+05:30",
		"EndDate": "2011-11-10T23:59:59+05:30",
		"Payment": "-29364848",
		"Interest": "-23356218",
		"Principal": "-6008630"
	},
	{
		"Period": 3,
		"StartDate": "2011-11-11T00:00:00+05:30",
		"EndDate": "2012-11-10T23:59:59+05:30",
		"Payment": "-29364848",
		"Interest": "-22635183",
		"Principal": "-6729665"
	},
	{
		"Period": 4,
		"StartDate": "2012-11-11T00:00:00+05:30",
		"EndDate": "2013-11-10T23:59:59+05:30",
		"Payment": "-29364848",
		"Interest": "-21827623",
		"Principal": "-7537225"
	},
	{
		"Period": 5,
		"StartDate": "2013-11-11T00:00:00+05:30",
		"EndDate": "2014-11-10T23:59:59+05:30",
		"Payment": "-29364848",
		"Interest": "-20923156",
		"Principal": "-8441692"
	},
	{
		"Period": 6,
		"StartDate": "2014-11-11T00:00:00+05:30",
		"EndDate": "2015-11-10T23:59:59+05:30",
		"Payment": "-29364848",
		"Interest": "-19910153",
		"Principal": "-9454695"
	},
	{
		"Period": 7,
		"StartDate": "2015-11-11T00:00:00+05:30",
		"EndDate": "2016-11-10T23:59:59+05:30",
		"Payment": "-29364848",
		"Interest": "-18775589",
		"Principal": "-10589259"
	},
	{
		"Period": 8,
		"StartDate": "2016-11-11T00:00:00+05:30",
		"EndDate": "2017-11-10T23:59:59+05:30",
		"Payment": "-29364848",
		"Interest": "-17504878",
		"Principal": "-11859970"
	},
	{
		"Period": 9,
		"StartDate": "2017-11-11T00:00:00+05:30",
		"EndDate": "2018-11-10T23:59:59+05:30",
		"Payment": "-29364848",
		"Interest": "-16081682",
		"Principal": "-13283166"
	},
	{
		"Period": 10,
		"StartDate": "2018-11-11T00:00:00+05:30",
		"EndDate": "2019-11-10T23:59:59+05:30",
		"Payment": "-29364848",
		"Interest": "-14487702",
		"Principal": "-14877146"
	},
	{
		"Period": 11,
		"StartDate": "2019-11-11T00:00:00+05:30",
		"EndDate": "2020-11-10T23:59:59+05:30",
		"Payment": "-29364848",
		"Interest": "-12702445",
		"Principal": "-16662403"
	},
	{
		"Period": 12,
		"StartDate": "2020-11-11T00:00:00+05:30",
		"EndDate": "2021-11-10T23:59:59+05:30",
		"Payment": "-29364848",
		"Interest": "-10702956",
		"Principal": "-18661892"
	},
	{
		"Period": 13,
		"StartDate": "2021-11-11T00:00:00+05:30",
		"EndDate": "2022-11-10T23:59:59+05:30",
		"Payment": "-29364848",
		"Interest": "-8463529",
		"Principal": "-20901319"
	},
	{
		"Period": 14,
		"StartDate": "2022-11-11T00:00:00+05:30",
		"EndDate": "2023-11-10T23:59:59+05:30",
		"Payment": "-29364848",
		"Interest": "-5955371",
		"Principal": "-23409477"
	},
	{
		"Period": 15,
		"StartDate": "2023-11-11T00:00:00+05:30",
		"EndDate": "2024-11-10T23:59:59+05:30",
		"Payment": "-29364847",
		"Interest": "-3146234",
		"Principal": "-26218613"
	}
]

type Config

type Config struct {
	StartDate              time.Time          // Starting day of the amortization schedule(inclusive)
	EndDate                time.Time          // Ending day of the amortization schedule(inclusive)
	Frequency              frequency.Type     // Frequency enum with DAILY, WEEKLY, MONTHLY or ANNUALLY
	AmountBorrowed         decimal.Decimal    // Amount Borrowed
	InterestType           interesttype.Type  // InterestType enum with FLAT or REDUCING value.
	Interest               decimal.Decimal    // Interest in basis points
	PaymentPeriod          paymentperiod.Type // Payment period enum to know whether payment made at the BEGINNING or ENDING of a period
	EnableRounding         bool               // If enabled, the final values in amortization schedule are rounded
	RoundingPlaces         int32              // If specified, the final values in amortization schedule are rounded to these many places
	RoundingErrorTolerance decimal.Decimal    // Any difference in [payment-(principal+interest)] will be adjusted in interest component, upto the RoundingErrorTolerance value specified
	// contains filtered or unexported fields
}

Config is used to store details used in generation of amortization table.

type Financial

type Financial interface {
	GetPrincipal(config Config, period int64) decimal.Decimal
	GetInterest(config Config, period int64) decimal.Decimal
	GetPayment(config Config) decimal.Decimal
}

Financial interface defines the methods to be over ridden for different financial use cases.

type Flat

type Flat struct{}

Flat implements financial methods for facilitating a loan use case, following a flat rate of interest.

func (*Flat) GetInterest

func (f *Flat) GetInterest(config Config, period int64) decimal.Decimal

GetInterest returns interest amount contribution in a given period towards a loan, depending on config.

func (*Flat) GetPayment

func (f *Flat) GetPayment(config Config) decimal.Decimal

GetPayment returns the periodic payment to be done for a loan depending on config.

func (*Flat) GetPrincipal

func (f *Flat) GetPrincipal(config Config, _ int64) decimal.Decimal

GetPrincipal returns principal amount contribution in a given period towards a loan, depending on config.

type Reducing

type Reducing struct{}

Reducing implements financial methods for facilitating a loan use case, following a reducing rate of interest.

func (*Reducing) GetInterest

func (r *Reducing) GetInterest(config Config, period int64) decimal.Decimal

GetInterest returns interest amount contribution in a given period towards a loan, depending on config.

func (*Reducing) GetPayment

func (r *Reducing) GetPayment(config Config) decimal.Decimal

GetPayment returns the periodic payment to be done for a loan depending on config.

func (*Reducing) GetPrincipal

func (r *Reducing) GetPrincipal(config Config, period int64) decimal.Decimal

GetPrincipal returns principal amount contribution in a given period towards a loan, depending on config.

type Row

type Row struct {
	Period    int64
	StartDate time.Time
	EndDate   time.Time
	Payment   decimal.Decimal
	Interest  decimal.Decimal
	Principal decimal.Decimal
}

Row represents a single row in an amortization schedule.

Directories

Path Synopsis
enums