Example 5: Determine a payment using a stepped weighted profile
This example illustrates solving unknown payments on a proportional basis to accelerate capital repayment using a stepped profile.
Overview
This example demonstrates how to calculate a payment schedule where early and mid-term payments focus on reducing the principal faster. This method is often adopted in small business loans to align with asset depreciation rates, and leverages the SeriesPayment payment weighting feature. This feature allows for proportional distribution of an unknown payment across multiple series, rather than solving for a single value.
Code
This example solves for an unknown instalment amount for a $10,000 loan over twelve months, with the first 4 instalments 100% weighted, the next 4 by 60%, and the last 4 by 40%.
This is implemented by creating three separate SeriesPayment instances for each weighted instalment grouping and assigning the following values to the weighting attribute, as follows:
-
Instalments 1 - 4:
weighting = 1.0 # 100% of unknown -
Instalments 5 - 8:
weighting = 0.6 # 60% of unknown -
Instalments 9 - 12:
weighting = 0.4 # 40% of unknown
After the unknown values are solved we confirm the implicit interest rate (IRR) in the resulting profile equals the provided interest rate.
Notes:
-
Weighting calculations require two or more
SeriesPaymentrows. Applying a weight to a single payment series does not alter the result; the entire unknown value is assigned to that series. -
The solved for unknown is the fully weighted value, i.e. 100%. The provided schedule lists the weighted cash flows.
-
Dates are optional and default to the current system date. Here, a fixed
start_dateis provided solely to ensure reproducible doctest results.
import pandas as pd
from curo import (
Calculator, Mode,
SeriesAdvance, SeriesPayment,
US30U360
)
# Step 1: Create a [Calculator](api/calculator.md) instance
calculator = Calculator()
# Step 2: Define cash flow series
calculator.add(
SeriesAdvance(
label="Loan",
amount=10000.0,
)
)
calculator.add(
SeriesPayment(
number_of = 4,
label = "Instalment",
amount = None,
mode = Mode.ARREAR,
weighting = 1.0 # 100% of unknown
)
)
calculator.add(
SeriesPayment(
number_of = 4,
label = "Instalment",
amount = None,
mode = Mode.ARREAR,
weighting = 0.6 # 60% of unknown
)
)
calculator.add(
SeriesPayment(
number_of = 4,
label = "Instalment",
amount = None,
mode = Mode.ARREAR,
weighting = 0.4 # 40% of unknown
)
)
# Step 3: Solve for the unknown and validate rate
payment_normal_weight = calculator.solve_value(
convention = US30U360(),
interest_rate = 0.07,
start_date = pd.Timestamp("2026-01-05", tz="UTC")
)
lender_irr = calculator.solve_rate(
convention = US30U360()
)
amortisation_schedule = calculator.build_schedule(
profile = calculator.profile,
convention = US30U360(),
interest_rate = lender_irr
)
amortisation_schedule['post_date'] = amortisation_schedule['post_date'].dt.strftime('%Y-%m-%d')
# Step 4: Display results and schedule
print(f"Payment (normal weight): ${payment_normal_weight:.2f}") # Payment (normal weight): $1288.89
print(f"Lender IRR: {lender_irr:.2%}") # Lender IRR: 7.00%
print(amortisation_schedule)
# post_date label amount capital interest capital_balance
# 0 2026-01-05 Loan -10000.00 -10000.00 0.00 -10000.00
# 1 2026-02-05 Instalment 1288.89 1230.56 -58.33 -8769.44
# 2 2026-03-05 Instalment 1288.89 1237.73 -51.16 -7531.71
# 3 2026-04-05 Instalment 1288.89 1244.95 -43.94 -6286.76
# 4 2026-05-05 Instalment 1288.89 1252.22 -36.67 -5034.54
# 5 2026-06-05 Instalment 773.34 743.97 -29.37 -4290.57
# 6 2026-07-05 Instalment 773.34 748.31 -25.03 -3542.26
# 7 2026-08-05 Instalment 773.34 752.68 -20.66 -2789.58
# 8 2026-09-05 Instalment 773.34 757.07 -16.27 -2032.51
# 9 2026-10-05 Instalment 515.56 503.70 -11.86 -1528.81
# 10 2026-11-05 Instalment 515.56 506.64 -8.92 -1022.17
# 11 2026-12-05 Instalment 515.56 509.60 -5.96 -512.57
# 12 2027-01-05 Instalment 515.56 512.57 -2.99 -0.00
Cash Flow Diagram
The diagram below visualizes the cash flow dynamics of a $10,000 loan over 12 months, with the first 4 payments 100% weighted, the next 4 by 60%, and the last 4 by 40%, as implemented in the example code.
-
Advance: This is shown by a blue downward arrow at the start of the timeline, indicating the value is known.
-
Payments: The regular unknown payments are represented by red upward arrows. As the example uses three 4 monthly payment series with assigned weightings of 1.00, 0.60, and 0.40 respectively, we’ve adjusted the height of the upward arrows to reflect the reduction in payment values over time, and have also used a light grey background to emphasise the stepped profile.
Note: To keep the diagram readable, repeated identical payments are condensed, with a concertina (zig-zag) line indicating omitted periods.
