Formulas and conventions

All rates are annual percentages, day counts are actual/365, amounts are rupees. The maths lives in fdladder/instruments.py.

Cumulative fixed deposits

Indian banks compound quarterly but pay simple interest for periods that are not whole quarters.

tenor < 182 days:  M = P * (1 + r * d / 365)
otherwise:         q = floor(4 * d / 365)            whole quarters
                   b = d - q * 365 / 4               broken-period days
                   M = P * (1 + r/4)^q * (1 + r * b / 365)

Worked example, Rs 1,00,000 at 7.25% for 400 days: q = 4, b = 35, so M = 100000 * 1.018125^4 * (1 + 0.0725 * 35 / 365) = 1,08,196.50. The effective annual yield is (M / P)^(365 / d) - 1 = 7.45%.

The value is continuous at each quarter boundary (at b = 91.25 the broken factor equals 1 + r/4) and at the 182-day switch the compounded value is only marginally above simple interest, so the conventions never produce a jump that would distort optimization.

Banks differ in the exact day rule (some use 90 or 91 days per quarter). fdladder uses 365/4 so the result is independent of the calendar quarter in which the deposit starts. Expect differences of a few rupees against a specific bank's calculator.

Non-cumulative deposits

Premature withdrawal

A cumulative FD closed after e days is re-priced at max(r - penalty, 0) for the elapsed period, using the same compounding rule. Other instruments return principal less penalty * e / 365 plus accrued interest not yet paid out (T-bills: simple interest at the reduced rate). Penalties are taken from the rate card (penalty_pct).

T-bills

price             = face * (1 - discount * d / 365)
investment yield  = (face - price) / price * 365 / d
discount -> yield = D / (1 - D * d / 365)

A 91-day bill at a 6.25% cut-off discount costs 98,441.78 per 1,00,000 and yields 6.3489%. The rate card stores the investment yield, and the instrument is modelled as a zero-coupon asset: value = 1 + y * d / 365.

G-secs, RBI floating rate bonds and tax-free bonds

Semi-annual coupons, 30/360 accrual (the Indian G-sec convention).

accrued = face * (c / 2) * days30/360(last coupon, settle) / 180
dirty   = sum_k CF_k / (1 + y/2)^(w + k),   w = days30/360(settle, next coupon) / 180
clean   = dirty - accrued

bond_ytm solves dirty(y) = clean + accrued with Newton's method (analytic derivative, starting at the coupon rate, tolerance 1e-10). Coupon dates are generated backwards from maturity in six-month steps, clamping to month end.

Inside the optimizer these instruments are modelled as bought at par with the card rate as the coupon: coupons of r/2 at six-monthly marks and the principal at the end.

Internal rate of return

xirr bisects sum_i A_i / (1 + x)^(d_i / 365) = 0 on [-99%, 1000%]. It is used for post-tax yields of single instruments and for the plan and strategy comparison IRRs.