Skip to content

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)”
  • Working-capital line drawdown (30 – 180 days; pay-off at maturity).
  • Short-term bridge.
  • Some invoice-backed products.
  • Principal.
  • Tenure days.
  • Rate.
  • Disbursement date.
  • Convention (Actual / 365).
schedule_lines = []
interest_at_maturity = principal × rate × tenure_days / 365
total_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)

₹15 lakh drawn on 2026-04-15, 90 days, 21%.

interest = 1500000 × 0.21 × 90 / 365 = ₹77,671.23
maturity_date = 2026-07-14
schedule_line: due 2026-07-14, principal 15,00,000, interest 77,671.23

Variant: monthly interest, bullet principal

Section titled “Variant: monthly interest, bullet principal”

Some bullet products collect interest monthly:

monthly_interest = principal × rate × days_in_month / 365
month_1: due last day of month, interest only
month_2: due last day of month, interest only
...
final_month: due maturity_date, interest + principal
  • Principal.
  • Tenure months.
  • Annual rate.
  • Disbursement date.
  • EMI start date (typically first day of month or first day after a cooling-off + setup period).
monthly_rate = annual_rate / 12
n = tenure_months
EMI = principal × monthly_rate × (1 + monthly_rate)^n / ((1 + monthly_rate)^n - 1)
remaining_principal = principal
schedule = []
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
})
  • EMI rounded to nearest rupee (or 50 paise depending on policy).
  • Final EMI adjusted to absorb rounding (so total exactly = principal + total interest).

₹10 lakh, 24 months, 21%, EMI starts 2026-05-01.

monthly_rate = 0.21/12 = 0.0175
n = 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.

For specialised products (e.g., seasonal businesses with crop-cycle repayments, project-based with milestone payments):

  • Principal.
  • Rate.
  • Borrower-specific schedule of repayment dates + amounts.
  • Validation: total of scheduled repayments ≥ principal × (1 + total interest factor).

The schedule is constructed manually per agreement. LMS just stores schedule lines and accrues interest daily on outstanding.

₹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.

WC lines where borrower draws multiple times within the line.

Each draw has its own schedule, typically bullet (or EMI if structured).

line_outstanding = sum of all active drawdowns' principal outstandings
limit_used = line_outstanding
limit_available = line_limit - line_outstanding

Line: ₹40 lakh. Borrower:

  • Day 1: draws ₹15 lakh for 60 daysbullet schedule line.
  • Day 10: draws ₹10 lakh for 90 daysbullet schedule line.
  • Day 30: repays ₹15 lakh (closes Draw 1).
  • Day 50: draws ₹5 lakh for 60 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.

When a due date falls on a Sunday / national holiday / state holiday:

  • 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.

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.

Actual / 365 convention treats leap years identically (extra Feb 29 day accrues but denominator stays 365). Schedules are not specially adjusted for leap years.

For schedules with month-end due dates (e.g., last day of every month):

  • February: 28 or 29 depending on year.
  • Months with 31 days: due on 31st.
  • Months with 30 days: due on 30th.

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)

When borrower part-prepays:

Same n, lower principal → lower EMI.

new_EMI = recomputed using same formula with new principal and same n_remaining
new_schedule for remaining n_remaining months

Same EMI, lower principal → shorter tenure.

n_new = solve for k such that EMI × k closely matches new_principal × something
new_schedule for n_new months

Borrower chooses at prepayment (per agreement / option). LMS generates new schedule.

Restructure produces a new schedule with new terms (extended tenure, possibly reduced rate, possibly moratorium).

Marked as voided post-restructure date. Retained for audit.

Generated using restructure terms; replaces the active schedule going forward.

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.

  • 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.