18.5 Schedule generation algorithms
The schedule is the loan’s contract with cash-flow. Generating it correctly is core to LMS function. This page covers each product variant.
Bullet schedule (single repayment at maturity)
Section titled “Bullet schedule (single repayment at maturity)”Use case
Section titled “Use case”- Working-capital line drawdown (
30 – 180 days; pay-off at maturity). - Short-term bridge.
- Some invoice-backed products.
Inputs
Section titled “Inputs”- Principal.
- Tenure days.
- Rate.
- Disbursement date.
- Convention (
Actual / 365).
Algorithm
Section titled “Algorithm”schedule_lines = []
interest_at_maturity = principal × rate × tenure_days / 365total_due_at_maturity = principal + interest_at_maturity
schedule_lines.append({ due_date: disbursement_date + tenure_days, principal_due: principal, interest_due: interest_at_maturity, total_due: total_due_at_maturity})
# Optional: monthly interest line if collected monthly (rare for bullet)Worked example
Section titled “Worked example”₹15 lakh drawn on 2026-04-15, 90 days, 21%.
interest = 1500000 × 0.21 × 90 / 365 = ₹77,671.23maturity_date = 2026-07-14schedule_line: due 2026-07-14, principal 15,00,000, interest 77,671.23Variant: monthly interest, bullet principal
Section titled “Variant: monthly interest, bullet principal”Some bullet products collect interest monthly:
monthly_interest = principal × rate × days_in_month / 365month_1: due last day of month, interest onlymonth_2: due last day of month, interest only...final_month: due maturity_date, interest + principalEMI schedule (term loan, amortising)
Section titled “EMI schedule (term loan, amortising)”Inputs
Section titled “Inputs”- Principal.
- Tenure months.
- Annual rate.
- Disbursement date.
- EMI start date (typically first day of month or first day after a
cooling-off + setupperiod).
Algorithm
Section titled “Algorithm”monthly_rate = annual_rate / 12n = tenure_months
EMI = principal × monthly_rate × (1 + monthly_rate)^n / ((1 + monthly_rate)^n - 1)
remaining_principal = principalschedule = []for k in 1..n: interest_k = remaining_principal × monthly_rate principal_k = EMI - interest_k remaining_principal -= principal_k schedule.append({ due_date: emi_start_date + (k-1) months, principal_due: principal_k, interest_due: interest_k, total_due: EMI })Rounding
Section titled “Rounding”- EMI rounded to nearest rupee (or 50 paise depending on policy).
- Final EMI adjusted to absorb rounding (so total exactly = principal + total interest).
Worked example
Section titled “Worked example”₹10 lakh, 24 months, 21%, EMI starts 2026-05-01.
monthly_rate = 0.21/12 = 0.0175n = 24
EMI = 1000000 × 0.0175 × 1.0175^24 / (1.0175^24 - 1)
(1.0175)^24 = 1.51767 (approximately)
EMI = 1000000 × 0.0175 × 1.51767 / 0.51767 = 17500 × 2.93175 = ₹51,306 (approximately)First month:
- Opening:
₹10,00,000. - Interest:
₹10,00,000 × 0.0175 = ₹17,500. - Principal:
₹51,306 - ₹17,500 = ₹33,806. - Closing:
₹9,66,194.
Second month:
- Opening:
₹9,66,194. - Interest:
₹9,66,194 × 0.0175 = ₹16,908. - Principal:
₹51,306 - ₹16,908 = ₹34,398. - … and so on.
Structured / customised schedule
Section titled “Structured / customised schedule”For specialised products (e.g., seasonal businesses with crop-cycle repayments, project-based with milestone payments):
Inputs
Section titled “Inputs”- Principal.
- Rate.
- Borrower-specific schedule of repayment dates + amounts.
- Validation: total of scheduled repayments ≥ principal × (1 + total interest factor).
Algorithm
Section titled “Algorithm”The schedule is constructed manually per agreement. LMS just stores schedule lines and accrues interest daily on outstanding.
Worked example (step-up)
Section titled “Worked example (step-up)”₹50 lakh, 18 months, step-up: smaller EMIs in first 6 months, larger in next 12.
Months 1-6: EMI ₹2,00,000 (covers interest mostly; small principal reduction)Months 7-18: EMI ₹4,50,000 (faster principal repayment)
Schedule constructed to ensure total = principal + total accrued interest.Drawdown schedule (for revolving lines)
Section titled “Drawdown schedule (for revolving lines)”Use case
Section titled “Use case”WC lines where borrower draws multiple times within the line.
Per-draw schedule
Section titled “Per-draw schedule”Each draw has its own schedule, typically bullet (or EMI if structured).
Line-level outstanding
Section titled “Line-level outstanding”line_outstanding = sum of all active drawdowns' principal outstandingsLimit usage
Section titled “Limit usage”limit_used = line_outstandinglimit_available = line_limit - line_outstandingWorked example
Section titled “Worked example”Line: ₹40 lakh. Borrower:
- Day 1: draws
₹15 lakhfor60 days→bullet schedule line. - Day 10: draws
₹10 lakhfor90 days→bullet schedule line. - Day 30: repays
₹15 lakh(closes Draw 1). - Day 50: draws
₹5 lakhfor60 days.
Line outstanding on Day 50: ₹10L + ₹5L = ₹15 lakh. Available: ₹25 lakh.
Each draw has its own schedule line; LMS aggregates for borrower-facing view.
Holiday handling
Section titled “Holiday handling”When a due date falls on a Sunday / national holiday / state holiday:
Options (per board policy)
Section titled “Options (per board policy)”- Push to next working day (common).
- Stay on calendar date (borrower expected to pay on or before).
Most NBFCs push due dates to next working day for NACH presentation purposes; the underlying schedule line records the original calendar date plus the pushed presentation date.
Implication
Section titled “Implication”If pushed to next working day, an extra 1 – 2 days of interest accrues (typically very small; absorbed). Policy decides whether to recover or absorb.
Leap year handling
Section titled “Leap year handling”Actual / 365 convention treats leap years identically (extra Feb 29 day accrues but denominator stays 365). Schedules are not specially adjusted for leap years.
Month-end (EOM) handling
Section titled “Month-end (EOM) handling”For schedules with month-end due dates (e.g., last day of every month):
- February:
28or29depending on year. - Months with
31days: due on31st. - Months with
30days: due on30th.
The schedule generator handles this:
emi_due_date(k): base_date = emi_start_date + (k-1) months if emi_start_date is end-of-month: return last_day_of_month(base_date) else: return base_date (or move backward if doesn't exist)Prepayment recomputation
Section titled “Prepayment recomputation”When borrower part-prepays:
Option A: Reduce EMI, keep tenure
Section titled “Option A: Reduce EMI, keep tenure”Same n, lower principal → lower EMI.
new_EMI = recomputed using same formula with new principal and same n_remainingnew_schedule for remaining n_remaining monthsOption B: Reduce tenure, keep EMI
Section titled “Option B: Reduce tenure, keep EMI”Same EMI, lower principal → shorter tenure.
n_new = solve for k such that EMI × k closely matches new_principal × somethingnew_schedule for n_new monthsBorrower chooses at prepayment (per agreement / option). LMS generates new schedule.
Restructure schedule
Section titled “Restructure schedule”Restructure produces a new schedule with new terms (extended tenure, possibly reduced rate, possibly moratorium).
Old schedule
Section titled “Old schedule”Marked as voided post-restructure date. Retained for audit.
New schedule
Section titled “New schedule”Generated using restructure terms; replaces the active schedule going forward.
Worked example
Section titled “Worked example”Original: ₹10 lakh / 24 months / 21% → EMI ₹51,306.
After 12 months, restructured: tenure extended by 12 months (new total 24 months remaining), rate stays.
At restructure date: remaining_principal = ₹5,42,108 (after 12 months of EMIs) new_n = 24 (12 originally remaining + 12 extension) new_EMI = 5,42,108 × 0.0175 × 1.0175^24 / (1.0175^24 - 1) = ₹27,815 (approximately)Lower EMI reduces borrower’s monthly burden; total interest paid increases.
What the LMS must enforce
Section titled “What the LMS must enforce”- Schedule deterministic — given identical inputs, identical schedule.
- Holiday handling consistent with board policy.
- EMI rounded per convention; final EMI absorbs rounding.
- Per-draw schedules for revolving lines independent and aggregable.
- Restructure preserves history — old schedule retained.
- Prepayment recomputation correct.
- Worked-example unit tests in CI to verify computations.