Documentation
¶
Overview ¶
Package indianfinance implements zero-dependency finance formulas for India — loans, investments, GST, gratuity and income tax.
Every function here is extracted from the calculators running at https://emicalcs.com and is covered by the test suite in finance_test.go, which is a direct port of the JavaScript suite the same formulas ship with.
Statutory figures — tax slabs, gratuity ceilings, GST rates — change by notification. Where a function depends on one, the value is a documented OPTION with a default rather than a hidden constant, so you can update it yourself the day it moves without waiting for a release.
A note on types ¶
The JavaScript original takes months and years as numbers and rounds them. This port takes them as int where the underlying loop is integer-stepped, which removes the NaN and Infinity cases the JS version has to guard against at runtime. The tenure ceiling below is kept regardless.
MIT licensed.
Index ¶
- Constants
- func AnnualContributionMaturity(yearlyAmount, annualRatePct float64, years int) (float64, error)
- func CAGR(initial, final, years float64) float64
- func EMI(principal, annualRate float64, months int) float64
- func GSTInterest(cashTaxPaid float64, days int, annualRatePct float64) float64
- func Lumpsum(principal, annualRate, years float64) float64
- func SIPFutureValue(monthly, annualRate float64, months int) float64
- func TotalInterest(principal, annualRate float64, months int) float64
- type AmortRow
- type ErrTenure
- type GST
- type Gratuity
- type GratuityOptions
- type PrepaymentInput
- type PrepaymentResult
- type Slab
- type StepUpResult
- type Tax
- type TaxOptions
Constants ¶
const ( MaxMonths = 1200 MaxYears = MaxMonths / 12 )
Every schedule function below steps one period at a time, so the loop is bounded only by the tenure it is handed. Left unchecked, a bad tenure is an out-of-memory crash in the CALLER's process — not a slow answer — and there is no UI here to clamp the input first. 1200 months / 100 years is far beyond anything real (the longest home loan on offer runs 30-40 years), so the ceiling only ever fires on input that was never going to mean anything.
const DefaultGSTInterestRate = 18.0
DefaultGSTInterestRate is the notified annual rate under Section 50(1).
Variables ¶
This section is empty.
Functions ¶
func AnnualContributionMaturity ¶
AnnualContributionMaturity returns the maturity of an annual-contribution scheme such as PPF or SSY. It returns an *ErrTenure if years exceeds MaxYears.
func EMI ¶
EMI returns the reducing-balance monthly instalment. annualRate is a percentage, e.g. 8.5 for 8.5% p.a.
func GSTInterest ¶
GSTInterest returns interest on a late GST payment.
Under Rule 88B(1) interest runs on the tax actually paid in cash from the electronic cash ledger — NOT on the gross output liability. Getting this wrong overstates the interest, often by several times. Pass cashTaxPaid as the cash-ledger portion, not the gross bill.
Pass annualRatePct as DefaultGSTInterestRate unless the notified rate has moved.
func SIPFutureValue ¶
SIPFutureValue returns the future value of a monthly SIP, with the contribution made at the start of each month.
func TotalInterest ¶
TotalInterest returns the total interest paid over the full tenure.
Types ¶
type AmortRow ¶
type AmortRow struct {
Month int
Opening float64
Interest float64
Principal float64
Closing float64
}
AmortRow is one month of an amortisation schedule.
type ErrTenure ¶
ErrTenure is returned when a tenure exceeds the ceiling. Use errors.Is to match it; the wrapped message carries the offending value.
type Gratuity ¶
type Gratuity struct {
Eligible bool
Amount float64
FormulaValue float64
Ceiling float64
Capped bool
}
Gratuity is the computed entitlement.
func ComputeGratuity ¶
func ComputeGratuity(lastSalary, years float64, opts GratuityOptions) Gratuity
ComputeGratuity applies the Code on Social Security, 2020 (in force 21 Nov 2025). lastSalary is the last drawn monthly Basic + DA; years is completed years of service.
type GratuityOptions ¶
type GratuityOptions struct {
Ceiling float64 // 0 -> 20,00,000. Use 25,00,000 for Central Government civil employees.
MinYears float64 // 0 -> 5. Use 1 for fixed-term employees.
}
GratuityOptions carries the statutory figures that change by notification. The zero value means "use the defaults".
type PrepaymentInput ¶
type PrepaymentInput struct {
Principal float64
AnnualRate float64
Months int // original tenure
MonthlyExtra float64
LumpSum float64
LumpSumAtMonth int // 0 = before the first instalment
}
PrepaymentInput describes a prepayment scenario. The EMI is held fixed, so prepaying shortens the tenure rather than reducing the instalment.
type PrepaymentResult ¶
type PrepaymentResult struct {
InterestSaved float64
MonthsSaved int
NewMonths int
NewInterest float64
}
PrepaymentResult is what prepaying achieves.
func Prepayment ¶
func Prepayment(in PrepaymentInput) (PrepaymentResult, error)
Prepayment computes the effect of prepaying with the EMI held fixed. It returns an *ErrTenure if Months exceeds MaxMonths.
type Slab ¶
Slab is one income-tax bracket: everything up to Upto is taxed at Rate. The final slab must use math.Inf(1) as Upto.
func DefaultSlabs ¶
func DefaultSlabs() []Slab
DefaultSlabs are the new-regime slabs for FY 2026-27 (AY 2027-28), unchanged by Budget 2026.
type StepUpResult ¶
StepUpResult is the outcome of a step-up SIP.
func StepUpSIP ¶
func StepUpSIP(monthly, annualRate float64, years int, stepUpPct float64) (StepUpResult, error)
StepUpSIP models a SIP whose contribution rises by stepUpPct every 12 months.
Worth knowing: a step-up SIP does NOT beat a flat SIP of the same total outlay. It wins in headline terms only because more money goes in. Hold the money constant and the flat schedule wins, because its rupees compound for longer. See https://emicalcs.com/step-up-sip-calculator/
It returns an *ErrTenure if years exceeds MaxYears.
type Tax ¶
Tax is the computed liability.
func IncomeTaxNewRegime ¶
func IncomeTaxNewRegime(taxableIncome float64, opts TaxOptions) Tax
IncomeTaxNewRegime computes tax under Section 115BAC, including the Section 87A rebate with marginal relief — tax cannot exceed the income above the rebate threshold, otherwise earning one rupee more would cost more than one rupee.
type TaxOptions ¶
type TaxOptions struct {
Slabs []Slab // nil -> DefaultSlabs
RebateUpto float64 // 0 -> 12,00,000 (Section 87A)
Cess float64 // 0 -> 0.04
}
TaxOptions overrides the statutory defaults. The zero value means "use the FY 2026-27 defaults".