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
- Quarterly payout:
P * r / 4each quarter. - Monthly payout uses the discounted rate
i = (1 + r/4)^(1/3) - 1per month. Reinvesting the payout monthly then yields exactly the same effective annual yield as quarterly compounding:(1 + i)^3 = 1 + r/4. Rs 1,20,000 at 7.2% pays120000 * 0.005964 = Rs 716a month, slightly below the naiver/12figure of Rs 720. - A broken last period pays the regular amount pro-rated by days; the principal comes back with the final payout.
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.