Debt. Consider all your credit cards, student loans, mortgage, a car payment or two, and the financing on your smartphone. They all have different interest rates, calculated in various ways, with payments sometimes being applied non-equally across balances (like promotional, seasonal, balance transfer, and cash advance rates on credit cards all might be different, and a payment might or might not be applied to the balance with the highest interest rate first). How might one figure out how best to pay off these debts?

With a conservative Christian circle of friends and family, Dave Ramsay and Larry Burkett are quoted at me a lot, but, while their debt snowball calculator can be useful, I doubted it was necessarily the most efficient method. I haven’t yet created a function that matches theirs, but the main problem I see is that it doesn’t re-order the creditors or balances in any way.

Another piece of advice I’ve often heard quoted is the idea that one should pay off the highest interest rate first, then work your way down. The idea that this is the most financially sound (that it avoids the most interest) is not always valid, while it seems logically sound. In certain scenarios this does work, but it can be (quite) a bit more complex than that when dealing with several balances.

I’m going to use some completely realistic numbers for an example scenario. Realistic because they’re not too far off from a reality I faced in the not too distant past. Not actually *real* because the numbers have been slightly modified to protect the guilty parties.

Reference Number | Type | Initial Principal Balance | Interest Rate | Minimum Payment Percentage | Minimum Payment Amount |

1 | Credit Card | 881.48 | 21.99% | 3.00% | 35 |

2 | Credit Card | 1259.37 | 21.99% | 3.00% | 20 |

3 | Credit Card | 1063.54 | 21.99% | | 120 |

4 | Credit Card | 5458.28 | 18.20% | 2.25% | 25 |

5 | Credit Card | 9395.24 | 7.90% | 3.00% | 20 |

6 | Credit Card | 10537.45 | 16.99% | 2.42% | 20 |

7 | Car Loan | 9082.4 | 3.75% | | 183.04 |

8 | Miscellaneous Loan | 9380.77 | 4.25% | | 277.94 |

9 | Cell Phone | 770 | 0 | | 55 |

10 | Mortgage 1 | 96263.74 | 3.75% | | 463.12 |

11 | Mortgage 2 | 161391.63 | 3.75% | | 972.54 |

The minimum payment for this set of loans is $2803.66 (35.00+37.78+120.00+122.81+281.86+254.57+183.04+277.94+55.00+463.12+972.54).

Paying the minimum, it would take 27 years 9 months to pay off all these loans with $151456.03 interest.

Additional Payment | Payoff Time | Interest Paid |

0 | 27 years 9 months | 151456.03 |

100 | 23 years 6 months | 128311.29 |

250 | 17 years 10 months | 96941.52 |

What happens if we rearrange this so we do work on the highest interest rate first? How does that change the outcome?

Additional Payment | Payoff Time | Interest Paid |

0 | 27 years 9 months | 150395.76 |

100 | 25 years 11 months | 133170.63 |

250 | 23 years 1 month | 119501.26 |

Already it’s clear that paying the highest interest rate alone, even when throwing a constant amount above the minimum at one’s debts, isn’t always the best method.

The method I prefer is quite similar to the snowball method, but rather than keeping *all* payments equal to the *current* minimum until one is paid off (and subsequently applying that balance to the next, and the next), mine is adjusted so that the minimum balance is paid on all until one is paid off, keeping the *overall* paid balance the same.

Anyway, with my method, and the original sort order:

Additional Payment | Payoff Time | Interest Paid |

0 | 11 years 5 months | 77763.61 |

100 | 10 years 11 months | 74617.76 |

250 | 10 years 3 months | 67780.65 |

But which order to pay these in? Can a different order get me a better (lower) number on interest paid and/or time to pay?

While there may be a better way, I only know brute force, which means I have 11!=39 916 800 possibilities to try out, but even so, by my figuring and without paying a penny extra per month, simply by rearranging the order in which the cash is applied, I can get interest paid down to $77033.62 (after trying only about 23% of the possibilities, though that took about 22 hours). Yes, that includes the two mortgages! A savings of a mere 1% might not seem much over the course of 23 years, but savings can be quite a bit more, percentage-wise, for other amounts. Dropping the mortgages for the sake of argument (and ease and speed of calculation), let’s revisit that last table:

Additional Payment | Payoff Time | Interest Paid | Reordered Payoff Time | Reordered Interest | New Order |

0 | 3 years 6 months | 9627.47 | 3 years 6 months | 9085.05 | 3, 1, 9, 2, 6, 8, 4, 5, 7 |

100 | 3 years 3 months | 9423.47 | 3 years 2 months | 7849.85 | 3, 2, 9, 1, 4, 6, 8, 5, 7 |

250 | 2 years 10 months | 7183.47 | 2 years 10 months | 6633.55 | 1, 2, 3, 4, 6, 5, 9, 8, 7 |

1000 | 1 year 11 months | 6635.47 | 1 year 10 months | 3834.80 | 1, 3, 2, 4, 9, 6, 5, 8, 7 |

By shuffling the order in which one pays off debts, one can save more than 16% at the $100 additional amount. Note also that the time doesn’t change much at all, despite the occasionally massive changes in interest owed. Work the system to your advantage. (Note also that the initial interest always ends in 47¢. This could be an amazing coincidence, but is probably a bug in my code. I believe it is insignificant in the grand scheme of things, however! I’ll revisit the calculations once I produce code that’s ready for the light of day.)

As far *as* that code goes, here are my goals:

- Make the DebtCollection class iterable
*Drastically* increase the speed of the shuffling/interest calculation code (10–20 minutes for 362 880 permutations; est. 100 hours for 39 916 800)
- Calculate maximum interest for shuffled objects
- Allow for a single Debt object with multiple balances at separate interest rates
- Correct for payments that do not occur monthly (e.g. biweekly)
- Use Decimal class to head off rounding issues
- Automagically calculate amortized payment if initial balance is provided
- Output payment schedule in nicer format (CSV, HTML, PDF, something) including dates

And my evaluation *of* those goals:

- Easy.
- I haven’t noticed any sort of pattern in the results yet, so this one’s more than a bit tricky.
- Just one line of code to add to #2.
- Another tricky one. I’d have to deal with the ability to specify the order in which balances are paid.
- Harder than I initially thought. Could multiply by an appropriate scalar, but that’d turn out incorrect answers.
- I can implement as I clean up the code.
- If initial balance is provided, easy as pie.
- Almost entirely cosmetic, unless I decide to add due dates for each of these, in which case I’d need an extra method for DebtCollection: next_due or something.