[{"data":1,"prerenderedAt":2856},["ShallowReactive",2],{"doc:\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Fipmt-ppmt-effect-and-nominal-equivalents-in-python":3,"surround:\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Fipmt-ppmt-effect-and-nominal-equivalents-in-python":2822,"ancestors:\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Fipmt-ppmt-effect-and-nominal-equivalents-in-python":2831,"children:\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Fipmt-ppmt-effect-and-nominal-equivalents-in-python":2836,"related:\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Fipmt-ppmt-effect-and-nominal-equivalents-in-python":2837},{"id":4,"title":5,"body":6,"dateModified":2791,"datePublished":2791,"description":2792,"extension":2793,"faq":2794,"keyword":2803,"kind":2804,"meta":2805,"navigation":291,"path":2813,"seo":2814,"slug":2816,"stem":2817,"topics":2818,"type":2820,"__hash__":2821},"docs\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Fipmt-ppmt-effect-and-nominal-equivalents-in-python\u002Findex.md","IPMT, PPMT, EFFECT and NOMINAL Equivalents in Python",{"type":7,"value":8,"toc":2779},"minimark",[9,58,63,91,112,116,123,411,427,431,438,849,861,1075,1209,1213,1221,1498,1518,1522,1538,1769,1779,1859,1863,1866,2633,2640,2644,2688,2692,2714,2718,2724,2730,2736,2742,2746,2775],[10,11,12,13,17,18,21,22,25,26,21,29,32,33,21,36,39,40,43,44,47,48,51,52,57],"p",{},"Loan models in Excel lean on a small family of functions: ",[14,15,16],"code",{},"PMT"," for the level payment, ",[14,19,20],{},"IPMT"," and ",[14,23,24],{},"PPMT"," to split a given payment into interest and principal, ",[14,27,28],{},"CUMIPMT",[14,30,31],{},"CUMPRINC"," to total those parts over a range of periods, and ",[14,34,35],{},"EFFECT",[14,37,38],{},"NOMINAL"," to convert between a quoted annual rate and the rate actually earned or paid after compounding. NumPy once shipped these as ",[14,41,42],{},"numpy.pmt"," and friends; they moved to the separate ",[14,45,46],{},"numpy-financial"," package, which is not always available or wanted in a production script. They are also short enough to write from first principles, which has the advantage of making Excel's conventions — negative signs for money paid out, the ",[14,49,50],{},"type"," argument for payments at the start of a period — explicit. This page implements each function, uses them for a loan schedule in pandas, and checks every value against the spreadsheet. It belongs to ",[53,54,56],"a",{"href":55},"\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002F","Excel Formula Equivalents in pandas",".",[59,60,62],"h2",{"id":61},"prerequisites","Prerequisites",[64,65,70],"pre",{"className":66,"code":67,"language":68,"meta":69,"style":69},"language-bash shiki shiki-themes github-light github-dark-high-contrast","pip install pandas openpyxl\n","bash","",[14,71,72],{"__ignoreMap":69},[73,74,77,81,85,88],"span",{"class":75,"line":76},"line",1,[73,78,80],{"class":79},"sMTad","pip",[73,82,84],{"class":83},"srMev"," install",[73,86,87],{"class":83}," pandas",[73,89,90],{"class":83}," openpyxl\n",[10,92,93,94,97,98,100,101,21,104,107,108,57],{},"The functions need only standard Python. The example is a 25,000 loan at 6.9% a year, repaid monthly over four years. LibreOffice (",[14,95,96],{},"soffice",") recalculates the same spreadsheet formulas for the comparison in Step 5. ",[14,99,16],{},", ",[14,102,103],{},"NPV",[14,105,106],{},"IRR"," are covered in more depth in ",[53,109,111],{"href":110},"\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Fpmt-npv-and-irr-in-python\u002F","PMT, NPV and IRR in Python",[59,113,115],{"id":114},"step-1-pmt-and-excels-sign-convention","Step 1 — PMT and Excel's sign convention",[10,117,118,119,122],{},"Everything else builds on the payment. Excel's functions treat money received as positive and money paid out as negative, so a loan received as ",[14,120,121],{},"pv=25000"," produces a negative payment:",[64,124,128],{"className":125,"code":126,"language":127,"meta":69,"style":69},"language-python shiki shiki-themes github-light github-dark-high-contrast","def pmt(rate, nper, pv, fv=0.0, when=0):\n    if rate == 0:\n        return -(pv + fv) \u002F nper\n    factor = (1 + rate) ** nper\n    return -(rate * (pv * factor + fv)) \u002F ((1 + rate * when) * (factor - 1))\n\nRATE, NPER, PV = 0.069 \u002F 12, 48, 25_000\nprint(\"monthly payment:\", round(pmt(RATE, NPER, PV), 2))\nprint(\"payment at start of month:\", round(pmt(RATE, NPER, PV, when=1), 2))\n","python",[14,129,130,162,180,204,229,286,293,331,369],{"__ignoreMap":69},[73,131,132,136,140,144,147,151,154,156,159],{"class":75,"line":76},[73,133,135],{"class":134},"s-kum","def",[73,137,139],{"class":138},"s_Opv"," pmt",[73,141,143],{"class":142},"skGVy","(rate, nper, pv, fv",[73,145,146],{"class":134},"=",[73,148,150],{"class":149},"sP0c6","0.0",[73,152,153],{"class":142},", when",[73,155,146],{"class":134},[73,157,158],{"class":149},"0",[73,160,161],{"class":142},"):\n",[73,163,165,168,171,174,177],{"class":75,"line":164},2,[73,166,167],{"class":134},"    if",[73,169,170],{"class":142}," rate ",[73,172,173],{"class":134},"==",[73,175,176],{"class":149}," 0",[73,178,179],{"class":142},":\n",[73,181,183,186,189,192,195,198,201],{"class":75,"line":182},3,[73,184,185],{"class":134},"        return",[73,187,188],{"class":134}," -",[73,190,191],{"class":142},"(pv ",[73,193,194],{"class":134},"+",[73,196,197],{"class":142}," fv) ",[73,199,200],{"class":134},"\u002F",[73,202,203],{"class":142}," nper\n",[73,205,207,210,212,215,218,221,224,227],{"class":75,"line":206},4,[73,208,209],{"class":142},"    factor ",[73,211,146],{"class":134},[73,213,214],{"class":142}," (",[73,216,217],{"class":149},"1",[73,219,220],{"class":134}," +",[73,222,223],{"class":142}," rate) ",[73,225,226],{"class":134},"**",[73,228,203],{"class":142},[73,230,232,235,237,240,243,246,248,251,253,256,258,261,263,265,267,269,272,274,277,280,283],{"class":75,"line":231},5,[73,233,234],{"class":134},"    return",[73,236,188],{"class":134},[73,238,239],{"class":142},"(rate ",[73,241,242],{"class":134},"*",[73,244,245],{"class":142}," (pv ",[73,247,242],{"class":134},[73,249,250],{"class":142}," factor ",[73,252,194],{"class":134},[73,254,255],{"class":142}," fv)) ",[73,257,200],{"class":134},[73,259,260],{"class":142}," ((",[73,262,217],{"class":149},[73,264,220],{"class":134},[73,266,170],{"class":142},[73,268,242],{"class":134},[73,270,271],{"class":142}," when) ",[73,273,242],{"class":134},[73,275,276],{"class":142}," (factor ",[73,278,279],{"class":134},"-",[73,281,282],{"class":149}," 1",[73,284,285],{"class":142},"))\n",[73,287,289],{"class":75,"line":288},6,[73,290,292],{"emptyLinePlaceholder":291},true,"\n",[73,294,296,299,301,304,306,309,312,315,318,321,323,326,328],{"class":75,"line":295},7,[73,297,298],{"class":149},"RATE",[73,300,100],{"class":142},[73,302,303],{"class":149},"NPER",[73,305,100],{"class":142},[73,307,308],{"class":149},"PV",[73,310,311],{"class":134}," =",[73,313,314],{"class":149}," 0.069",[73,316,317],{"class":134}," \u002F",[73,319,320],{"class":149}," 12",[73,322,100],{"class":142},[73,324,325],{"class":149},"48",[73,327,100],{"class":142},[73,329,330],{"class":149},"25_000\n",[73,332,334,337,340,343,345,348,351,353,355,357,359,361,364,367],{"class":75,"line":333},8,[73,335,336],{"class":149},"print",[73,338,339],{"class":142},"(",[73,341,342],{"class":83},"\"monthly payment:\"",[73,344,100],{"class":142},[73,346,347],{"class":149},"round",[73,349,350],{"class":142},"(pmt(",[73,352,298],{"class":149},[73,354,100],{"class":142},[73,356,303],{"class":149},[73,358,100],{"class":142},[73,360,308],{"class":149},[73,362,363],{"class":142},"), ",[73,365,366],{"class":149},"2",[73,368,285],{"class":142},[73,370,372,374,376,379,381,383,385,387,389,391,393,395,397,401,403,405,407,409],{"class":75,"line":371},9,[73,373,336],{"class":149},[73,375,339],{"class":142},[73,377,378],{"class":83},"\"payment at start of month:\"",[73,380,100],{"class":142},[73,382,347],{"class":149},[73,384,350],{"class":142},[73,386,298],{"class":149},[73,388,100],{"class":142},[73,390,303],{"class":149},[73,392,100],{"class":142},[73,394,308],{"class":149},[73,396,100],{"class":142},[73,398,400],{"class":399},"sa561","when",[73,402,146],{"class":134},[73,404,217],{"class":149},[73,406,363],{"class":142},[73,408,366],{"class":149},[73,410,285],{"class":142},[10,412,413,414,417,418,421,422,426],{},"The monthly rate is the annual rate divided by 12 and the number of periods is 48 months. The result, about −597.5, is negative because it is money the borrower pays out. ",[14,415,416],{},"when=1"," corresponds to Excel's ",[14,419,420],{},"type=1"," — payments at the ",[423,424,425],"em",{},"start"," of each period, as with leases and rent — which makes each payment slightly smaller because interest has less time to accrue. Keeping Excel's signs in the Python functions means figures can be compared directly with an existing workbook; flip the sign only when presenting the numbers.",[59,428,430],{"id":429},"step-2-ipmt-and-ppmt-split-a-payment","Step 2 — IPMT and PPMT: split a payment",[10,432,433,434,437],{},"The interest part of payment ",[14,435,436],{},"per"," is the rate times the balance outstanding at the start of that period; the principal part is the rest of the payment. Computing the balance with the future-value formula avoids looping:",[64,439,441],{"className":125,"code":440,"language":127,"meta":69,"style":69},"def fv(rate, nper, pmt_, pv, when=0):\n    if rate == 0:\n        return -(pv + pmt_ * nper)\n    factor = (1 + rate) ** nper\n    return -(pv * factor + pmt_ * (1 + rate * when) * (factor - 1) \u002F rate)\n\ndef ipmt(rate, per, nper, pv, fv_=0.0, when=0):\n    payment = pmt(rate, nper, pv, fv_, when)\n    if when == 1 and per == 1:\n        return 0.0\n    balance = fv(rate, per - 1, payment, pv, when)          # balance after per-1 payments (Excel signs)\n    interest = balance * rate\n    return interest \u002F (1 + rate) if when == 1 else interest\n\ndef ppmt(rate, per, nper, pv, fv_=0.0, when=0):\n    return pmt(rate, nper, pv, fv_, when) - ipmt(rate, per, nper, pv, fv_, when)\n\nfor per in (1, 2, 24, 48):\n    print(f\"payment {per:2}: interest {ipmt(RATE, per, NPER, PV):9.2f}  principal {ppmt(RATE, per, NPER, PV):9.2f}\")\n",[14,442,443,459,471,489,507,553,557,579,589,612,620,642,658,691,696,718,731,736,766],{"__ignoreMap":69},[73,444,445,447,450,453,455,457],{"class":75,"line":76},[73,446,135],{"class":134},[73,448,449],{"class":138}," fv",[73,451,452],{"class":142},"(rate, nper, pmt_, pv, when",[73,454,146],{"class":134},[73,456,158],{"class":149},[73,458,161],{"class":142},[73,460,461,463,465,467,469],{"class":75,"line":164},[73,462,167],{"class":134},[73,464,170],{"class":142},[73,466,173],{"class":134},[73,468,176],{"class":149},[73,470,179],{"class":142},[73,472,473,475,477,479,481,484,486],{"class":75,"line":182},[73,474,185],{"class":134},[73,476,188],{"class":134},[73,478,191],{"class":142},[73,480,194],{"class":134},[73,482,483],{"class":142}," pmt_ ",[73,485,242],{"class":134},[73,487,488],{"class":142}," nper)\n",[73,490,491,493,495,497,499,501,503,505],{"class":75,"line":206},[73,492,209],{"class":142},[73,494,146],{"class":134},[73,496,214],{"class":142},[73,498,217],{"class":149},[73,500,220],{"class":134},[73,502,223],{"class":142},[73,504,226],{"class":134},[73,506,203],{"class":142},[73,508,509,511,513,515,517,519,521,523,525,527,529,531,533,535,537,539,541,543,545,548,550],{"class":75,"line":231},[73,510,234],{"class":134},[73,512,188],{"class":134},[73,514,191],{"class":142},[73,516,242],{"class":134},[73,518,250],{"class":142},[73,520,194],{"class":134},[73,522,483],{"class":142},[73,524,242],{"class":134},[73,526,214],{"class":142},[73,528,217],{"class":149},[73,530,220],{"class":134},[73,532,170],{"class":142},[73,534,242],{"class":134},[73,536,271],{"class":142},[73,538,242],{"class":134},[73,540,276],{"class":142},[73,542,279],{"class":134},[73,544,282],{"class":149},[73,546,547],{"class":142},") ",[73,549,200],{"class":134},[73,551,552],{"class":142}," rate)\n",[73,554,555],{"class":75,"line":288},[73,556,292],{"emptyLinePlaceholder":291},[73,558,559,561,564,567,569,571,573,575,577],{"class":75,"line":295},[73,560,135],{"class":134},[73,562,563],{"class":138}," ipmt",[73,565,566],{"class":142},"(rate, per, nper, pv, fv_",[73,568,146],{"class":134},[73,570,150],{"class":149},[73,572,153],{"class":142},[73,574,146],{"class":134},[73,576,158],{"class":149},[73,578,161],{"class":142},[73,580,581,584,586],{"class":75,"line":333},[73,582,583],{"class":142},"    payment ",[73,585,146],{"class":134},[73,587,588],{"class":142}," pmt(rate, nper, pv, fv_, when)\n",[73,590,591,593,596,598,600,603,606,608,610],{"class":75,"line":371},[73,592,167],{"class":134},[73,594,595],{"class":142}," when ",[73,597,173],{"class":134},[73,599,282],{"class":149},[73,601,602],{"class":134}," and",[73,604,605],{"class":142}," per ",[73,607,173],{"class":134},[73,609,282],{"class":149},[73,611,179],{"class":142},[73,613,615,617],{"class":75,"line":614},10,[73,616,185],{"class":134},[73,618,619],{"class":149}," 0.0\n",[73,621,623,626,628,631,633,635,638],{"class":75,"line":622},11,[73,624,625],{"class":142},"    balance ",[73,627,146],{"class":134},[73,629,630],{"class":142}," fv(rate, per ",[73,632,279],{"class":134},[73,634,282],{"class":149},[73,636,637],{"class":142},", payment, pv, when)          ",[73,639,641],{"class":640},"s-wDw","# balance after per-1 payments (Excel signs)\n",[73,643,645,648,650,653,655],{"class":75,"line":644},12,[73,646,647],{"class":142},"    interest ",[73,649,146],{"class":134},[73,651,652],{"class":142}," balance ",[73,654,242],{"class":134},[73,656,657],{"class":142}," rate\n",[73,659,661,663,666,668,670,672,674,676,679,681,683,685,688],{"class":75,"line":660},13,[73,662,234],{"class":134},[73,664,665],{"class":142}," interest ",[73,667,200],{"class":134},[73,669,214],{"class":142},[73,671,217],{"class":149},[73,673,220],{"class":134},[73,675,223],{"class":142},[73,677,678],{"class":134},"if",[73,680,595],{"class":142},[73,682,173],{"class":134},[73,684,282],{"class":149},[73,686,687],{"class":134}," else",[73,689,690],{"class":142}," interest\n",[73,692,694],{"class":75,"line":693},14,[73,695,292],{"emptyLinePlaceholder":291},[73,697,699,701,704,706,708,710,712,714,716],{"class":75,"line":698},15,[73,700,135],{"class":134},[73,702,703],{"class":138}," ppmt",[73,705,566],{"class":142},[73,707,146],{"class":134},[73,709,150],{"class":149},[73,711,153],{"class":142},[73,713,146],{"class":134},[73,715,158],{"class":149},[73,717,161],{"class":142},[73,719,721,723,726,728],{"class":75,"line":720},16,[73,722,234],{"class":134},[73,724,725],{"class":142}," pmt(rate, nper, pv, fv_, when) ",[73,727,279],{"class":134},[73,729,730],{"class":142}," ipmt(rate, per, nper, pv, fv_, when)\n",[73,732,734],{"class":75,"line":733},17,[73,735,292],{"emptyLinePlaceholder":291},[73,737,739,742,744,747,749,751,753,755,757,760,762,764],{"class":75,"line":738},18,[73,740,741],{"class":134},"for",[73,743,605],{"class":142},[73,745,746],{"class":134},"in",[73,748,214],{"class":142},[73,750,217],{"class":149},[73,752,100],{"class":142},[73,754,366],{"class":149},[73,756,100],{"class":142},[73,758,759],{"class":149},"24",[73,761,100],{"class":142},[73,763,325],{"class":149},[73,765,161],{"class":142},[73,767,769,772,774,777,780,784,786,789,792,795,797,800,802,805,807,809,811,814,817,819,822,824,827,829,831,833,835,837,839,841,843,846],{"class":75,"line":768},19,[73,770,771],{"class":149},"    print",[73,773,339],{"class":142},[73,775,776],{"class":134},"f",[73,778,779],{"class":83},"\"payment ",[73,781,783],{"class":782},"sSjpA","{",[73,785,436],{"class":142},[73,787,788],{"class":134},":2",[73,790,791],{"class":782},"}",[73,793,794],{"class":83},": interest ",[73,796,783],{"class":782},[73,798,799],{"class":142},"ipmt(",[73,801,298],{"class":149},[73,803,804],{"class":142},", per, ",[73,806,303],{"class":149},[73,808,100],{"class":142},[73,810,308],{"class":149},[73,812,813],{"class":142},")",[73,815,816],{"class":134},":9.2f",[73,818,791],{"class":782},[73,820,821],{"class":83},"  principal ",[73,823,783],{"class":782},[73,825,826],{"class":142},"ppmt(",[73,828,298],{"class":149},[73,830,804],{"class":142},[73,832,303],{"class":149},[73,834,100],{"class":142},[73,836,308],{"class":149},[73,838,813],{"class":142},[73,840,816],{"class":134},[73,842,791],{"class":782},[73,844,845],{"class":83},"\"",[73,847,848],{"class":142},")\n",[10,850,851,852,855,856,858,859,57],{},"In month 1 about 144 of the 597 payment is interest and 454 repays principal; by month 48 almost the whole payment is principal. Both parts carry Excel's negative sign. ",[14,853,854],{},"fv"," gives the balance after any number of payments in one formula, so ",[14,857,20],{}," for period 30 does not need to walk through 29 earlier periods. With payments at the start of the period, the first payment contains no interest at all — nothing has been borrowed for any time yet — and later interest figures are discounted by one period, which is how Excel defines ",[14,860,420],{},[862,863,871,872,871,876,871,880,871,887,871,896,871,900,871,907,871,911,871,915,871,919,871,923,871,925,871,929,871,931,871,934,871,937,871,940,871,942,871,945,871,947,871,950,871,953,871,957,871,959,871,961,871,963,871,965,871,968,871,972,871,974,871,976,871,978,871,980,871,985,871,990,871,994,871,998,871,1003,871,1008,871,1012,871,1016,871,1019,871,1023,871,1025,871,1028,871,1031,871,1035,871,1037,871,1040,871,1046,871,1050,871,1056,871,1061,871,1069],"svg",{"viewBox":864,"role":865,"ariaLabelledBy":866,"xmlns":869,"style":870},"103 0 553 192","img",[867,868],"fin-split-t","fin-split-d","http:\u002F\u002Fwww.w3.org\u002F2000\u002Fsvg","width:100%;max-width:553px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif","\n  ",[873,874,875],"title",{"id":867},"Each payment splits into interest and principal",[877,878,879],"desc",{"id":868},"Every monthly payment of 597.50 is the same, but the split changes. In month 1, 143.75 is interest and 453.75 principal. In month 24, 79.79 is interest and 517.71 principal. In month 48 almost all of the payment is principal.",[881,882],"rect",{"x":883,"y":158,"width":884,"height":885,"fill":886},"103","553","192","#ffffff",[881,888],{"x":889,"y":890,"width":891,"height":892,"rx":158,"fill":893,"stroke":894,"style":895},"119.9","40.0","32.0","24.0","#e7ebef","var(--line,#cdd5e6)","stroke-width:1px",[881,897],{"x":898,"y":890,"width":899,"height":892,"rx":158,"fill":893,"stroke":894,"style":895},"151.9","58.8",[901,902,906],"text",{"x":903,"y":904,"style":905},"181.3","57.0","font-size:11px;font-weight:600;fill:var(--muted,#5b6780);text-anchor:middle","A",[881,908],{"x":909,"y":890,"width":910,"height":892,"rx":158,"fill":893,"stroke":894,"style":895},"210.7","71.7",[901,912,914],{"x":913,"y":904,"style":905},"246.6","B",[881,916],{"x":889,"y":917,"width":891,"height":918,"rx":158,"fill":893,"stroke":894,"style":895},"64.0","28.0",[901,920,217],{"x":921,"y":922,"style":905},"135.9","83.0",[881,924],{"x":898,"y":917,"width":899,"height":918,"rx":158,"fill":886,"stroke":894,"style":895},[901,926,928],{"x":903,"y":922,"style":927},"font-size:10.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","Month",[881,930],{"x":909,"y":917,"width":910,"height":918,"rx":158,"fill":886,"stroke":894,"style":895},[901,932,933],{"x":913,"y":922,"style":927},"Payment",[881,935],{"x":889,"y":936,"width":891,"height":918,"rx":158,"fill":893,"stroke":894,"style":895},"92.0",[901,938,366],{"x":921,"y":939,"style":905},"111.0",[881,941],{"x":898,"y":936,"width":899,"height":918,"rx":158,"fill":886,"stroke":894,"style":895},[901,943,217],{"x":903,"y":939,"style":944},"font-size:10.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle",[881,946],{"x":909,"y":936,"width":910,"height":918,"rx":158,"fill":886,"stroke":894,"style":895},[901,948,949],{"x":913,"y":939,"style":944},"−597.50",[881,951],{"x":889,"y":952,"width":891,"height":918,"rx":158,"fill":893,"stroke":894,"style":895},"120.0",[901,954,956],{"x":921,"y":955,"style":905},"139.0","3",[881,958],{"x":898,"y":952,"width":899,"height":918,"rx":158,"fill":886,"stroke":894,"style":895},[901,960,759],{"x":903,"y":955,"style":944},[881,962],{"x":909,"y":952,"width":910,"height":918,"rx":158,"fill":886,"stroke":894,"style":895},[901,964,949],{"x":913,"y":955,"style":944},[881,966],{"x":889,"y":967,"width":891,"height":918,"rx":158,"fill":893,"stroke":894,"style":895},"148.0",[901,969,971],{"x":921,"y":970,"style":905},"167.0","4",[881,973],{"x":898,"y":967,"width":899,"height":918,"rx":158,"fill":886,"stroke":894,"style":895},[901,975,325],{"x":903,"y":970,"style":944},[881,977],{"x":909,"y":967,"width":910,"height":918,"rx":158,"fill":886,"stroke":894,"style":895},[901,979,949],{"x":913,"y":970,"style":944},[881,981],{"x":982,"y":890,"width":983,"height":918,"rx":158,"fill":893,"stroke":894,"style":984},"501.9","66.9","stroke-width:1.5px",[901,986,989],{"x":987,"y":988,"style":927},"535.4","59.0","Interest",[881,991],{"x":992,"y":890,"width":993,"height":918,"rx":158,"fill":893,"stroke":894,"style":984},"568.8","71.3",[901,995,997],{"x":996,"y":988,"style":927},"604.4","Principal",[881,999],{"x":982,"y":1000,"width":983,"height":918,"rx":158,"fill":1001,"stroke":1002,"style":984},"68.0","#fdefd8","var(--gold,#b4740a)",[901,1004,1007],{"x":987,"y":1005,"style":1006},"87.0","font-size:10.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","−143.75",[881,1009],{"x":992,"y":1000,"width":993,"height":918,"rx":158,"fill":1010,"stroke":1011,"style":984},"#d9f4f1","var(--teal,#0f9488)",[901,1013,1015],{"x":996,"y":1005,"style":1014},"font-size:10.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","−453.75",[881,1017],{"x":982,"y":1018,"width":983,"height":918,"rx":158,"fill":1001,"stroke":1002,"style":984},"96.0",[901,1020,1022],{"x":987,"y":1021,"style":1006},"115.0","−79.79",[881,1024],{"x":992,"y":1018,"width":993,"height":918,"rx":158,"fill":1010,"stroke":1011,"style":984},[901,1026,1027],{"x":996,"y":1021,"style":1014},"−517.71",[881,1029],{"x":982,"y":1030,"width":983,"height":918,"rx":158,"fill":1001,"stroke":1002,"style":984},"124.0",[901,1032,1034],{"x":987,"y":1033,"style":1006},"143.0","−3.42",[881,1036],{"x":992,"y":1030,"width":993,"height":918,"rx":158,"fill":1010,"stroke":1011,"style":984},[901,1038,1039],{"x":996,"y":1033,"style":1014},"−594.08",[901,1041,1045],{"x":1042,"y":1043,"style":1044},"201.2","29.0","font-size:12.5px;font-weight:700;fill:var(--muted,#5b6780);text-anchor:middle","payment",[901,1047,1049],{"x":1048,"y":1043,"style":1044},"571.0","split",[75,1051],{"x1":1052,"y1":1018,"x2":1053,"y2":1018,"stroke":1054,"style":1055},"292.4","487.9","var(--brand,#5b5cf0)","stroke-width:2px",[1057,1058],"polygon",{"points":1059,"fill":1060},"491.9,96.0 482.9,101.0 482.9,91.0","#5b5cf0",[881,1062],{"x":1063,"y":1064,"width":1065,"height":1066,"rx":1067,"fill":886,"stroke":894,"style":1068},"320.4","63.0","143.6","22.0","11","stroke-width:1.2px",[901,1070,1074],{"x":1071,"y":1072,"style":1073},"392.2","78.0","font-size:11.5px;font-weight:400;fill:var(--brand-strong,#4338ca);text-anchor:middle;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace","IPMT + PPMT = PMT",[862,1076,871,1082,871,1085,871,1088,871,1092,871,1100,871,1111,871,1116,871,1121,871,1126,871,1129,871,1132,871,1139,871,1145,871,1149,871,1153,871,1157,871,1160,871,1163,871,1170,871,1175,871,1178,871,1181,871,1185,871,1188,871,1191,871,1198,871,1203,871,1206],{"viewBox":1077,"role":865,"ariaLabelledBy":1078,"xmlns":869,"style":1081},"4 0 752 142",[1079,1080],"fin-chain-t","fin-chain-d","width:100%;max-width:752px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[873,1083,1084],{"id":1079},"How the loan functions build on each other",[877,1086,1087],{"id":1080},"PMT gives the level payment. FV gives the balance after any number of payments. IPMT is the balance before a period times the rate, and PPMT is the payment minus IPMT. CUMIPMT and CUMPRINC sum IPMT and PPMT over a range of periods.",[881,1089],{"x":971,"y":158,"width":1090,"height":1091,"fill":886},"752","142",[881,1093],{"x":1094,"y":1095,"width":1096,"height":1097,"rx":1098,"fill":1099,"stroke":1054,"style":1055},"20.0","16.0","153.0","110.5","12","#f0f4ff",[1101,1102,1104],"g",{"transform":1103},"translate(84.5,37.8) scale(1.000)",[1105,1106],"path",{"d":1107,"fill":1108,"stroke":1109,"style":1110},"M5 9h14 M4 15h14 M10 4l-2 16 M16 4l-2 16","none","var(--brand-strong,#4338ca)","stroke-width:1.80px;stroke-linecap:round;stroke-linejoin:round",[901,1112,16],{"x":1113,"y":1114,"style":1115},"96.5","84.2","font-size:13.5px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:middle",[901,1117,1120],{"x":1113,"y":1118,"style":1119},"103.8","font-size:11.5px;font-weight:400;fill:var(--text,#172033);text-anchor:middle","level payment",[75,1122],{"x1":1123,"y1":1124,"x2":1125,"y2":1124,"stroke":1054,"style":1055},"178.0","71.2","200.0",[1057,1127],{"points":1128,"fill":1060},"204.0,71.2 195.0,76.2 195.0,66.2",[881,1130],{"x":1131,"y":1095,"width":1096,"height":1097,"rx":1098,"fill":893,"stroke":894,"style":1055},"209.0",[1101,1133,1135],{"transform":1134},"translate(273.5,29.0) scale(1.000)",[1105,1136],{"d":1137,"fill":1108,"stroke":1138,"style":1110},"M12 3l9 5-9 5-9-5z M3 13l9 5 9-5 M3 17l9 5 9-5","var(--text,#172033)",[901,1140,1144],{"x":1141,"y":1142,"style":1143},"285.5","75.5","font-size:13.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","FV",[901,1146,1148],{"x":1141,"y":1147,"style":1119},"95.0","balance after k",[901,1150,1152],{"x":1141,"y":1151,"style":1119},"112.5","payments",[75,1154],{"x1":1155,"y1":1124,"x2":1156,"y2":1124,"stroke":1054,"style":1055},"367.0","389.0",[1057,1158],{"points":1159,"fill":1060},"393.0,71.2 384.0,76.2 384.0,66.2",[881,1161],{"x":1162,"y":1095,"width":1096,"height":1097,"rx":1098,"fill":1010,"stroke":1011,"style":1055},"398.0",[1101,1164,1166],{"transform":1165},"translate(462.5,29.0) scale(1.000)",[1105,1167],{"d":1168,"fill":1108,"stroke":1169,"style":1110},"M4 12h6 M10 12l6-6h4 M10 12l6 6h4 M17 3l3 3-3 3 M17 15l3 3-3 3","var(--teal-ink,#0b6157)",[901,1171,1174],{"x":1172,"y":1142,"style":1173},"474.5","font-size:13.5px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:middle","IPMT \u002F PPMT",[901,1176,1177],{"x":1172,"y":1147,"style":1119},"balance × rate;",[901,1179,1180],{"x":1172,"y":1151,"style":1119},"remainder",[75,1182],{"x1":1183,"y1":1124,"x2":1184,"y2":1124,"stroke":1054,"style":1055},"556.0","578.0",[1057,1186],{"points":1187,"fill":1060},"582.0,71.2 573.0,76.2 573.0,66.2",[881,1189],{"x":1190,"y":1095,"width":1096,"height":1097,"rx":1098,"fill":1001,"stroke":1002,"style":1055},"587.0",[1101,1192,1194],{"transform":1193},"translate(651.5,29.0) scale(1.000)",[1105,1195],{"d":1196,"fill":1108,"stroke":1197,"style":1110},"M4 20h16 M7 17v-5 M12 17V7 M17 17v-8","var(--gold-ink,#7a4e06)",[901,1199,1202],{"x":1200,"y":1142,"style":1201},"663.5","font-size:13.5px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:middle","CUMIPMT \u002F",[901,1204,31],{"x":1200,"y":1205,"style":1201},"93.0",[901,1207,1208],{"x":1200,"y":1151,"style":1119},"sums over a range",[59,1210,1212],{"id":1211},"step-3-cumipmt-and-cumprinc-totals-over-a-range","Step 3 — CUMIPMT and CUMPRINC: totals over a range",[10,1214,1215,21,1218,1220],{},[14,1216,1217],{},"CUMIPMT(rate, nper, pv, start, end, type)",[14,1219,31],{}," total the interest and principal over a range of periods — typically a year of a loan, for a tax statement or a budget:",[64,1222,1224],{"className":125,"code":1223,"language":127,"meta":69,"style":69},"def cumipmt(rate, nper, pv, start, end, when=0):\n    return sum(ipmt(rate, p, nper, pv, when=when) for p in range(start, end + 1))\n\ndef cumprinc(rate, nper, pv, start, end, when=0):\n    return sum(ppmt(rate, p, nper, pv, when=when) for p in range(start, end + 1))\n\nfor year in range(1, 5):\n    s, e = 12 * (year - 1) + 1, 12 * year\n    print(f\"year {year}: interest {cumipmt(RATE, NPER, PV, s, e):9.2f}  principal {cumprinc(RATE, NPER, PV, s, e):10.2f}\")\nprint(\"principal over the whole loan:\", round(cumprinc(RATE, NPER, PV, 1, NPER), 2))\n",[14,1225,1226,1242,1278,1282,1297,1328,1332,1354,1388,1458],{"__ignoreMap":69},[73,1227,1228,1230,1233,1236,1238,1240],{"class":75,"line":76},[73,1229,135],{"class":134},[73,1231,1232],{"class":138}," cumipmt",[73,1234,1235],{"class":142},"(rate, nper, pv, start, end, when",[73,1237,146],{"class":134},[73,1239,158],{"class":149},[73,1241,161],{"class":142},[73,1243,1244,1246,1249,1252,1254,1256,1259,1261,1264,1266,1269,1272,1274,1276],{"class":75,"line":164},[73,1245,234],{"class":134},[73,1247,1248],{"class":149}," sum",[73,1250,1251],{"class":142},"(ipmt(rate, p, nper, pv, ",[73,1253,400],{"class":399},[73,1255,146],{"class":134},[73,1257,1258],{"class":142},"when) ",[73,1260,741],{"class":134},[73,1262,1263],{"class":142}," p ",[73,1265,746],{"class":134},[73,1267,1268],{"class":149}," range",[73,1270,1271],{"class":142},"(start, end ",[73,1273,194],{"class":134},[73,1275,282],{"class":149},[73,1277,285],{"class":142},[73,1279,1280],{"class":75,"line":182},[73,1281,292],{"emptyLinePlaceholder":291},[73,1283,1284,1286,1289,1291,1293,1295],{"class":75,"line":206},[73,1285,135],{"class":134},[73,1287,1288],{"class":138}," cumprinc",[73,1290,1235],{"class":142},[73,1292,146],{"class":134},[73,1294,158],{"class":149},[73,1296,161],{"class":142},[73,1298,1299,1301,1303,1306,1308,1310,1312,1314,1316,1318,1320,1322,1324,1326],{"class":75,"line":231},[73,1300,234],{"class":134},[73,1302,1248],{"class":149},[73,1304,1305],{"class":142},"(ppmt(rate, p, nper, pv, ",[73,1307,400],{"class":399},[73,1309,146],{"class":134},[73,1311,1258],{"class":142},[73,1313,741],{"class":134},[73,1315,1263],{"class":142},[73,1317,746],{"class":134},[73,1319,1268],{"class":149},[73,1321,1271],{"class":142},[73,1323,194],{"class":134},[73,1325,282],{"class":149},[73,1327,285],{"class":142},[73,1329,1330],{"class":75,"line":288},[73,1331,292],{"emptyLinePlaceholder":291},[73,1333,1334,1336,1339,1341,1343,1345,1347,1349,1352],{"class":75,"line":295},[73,1335,741],{"class":134},[73,1337,1338],{"class":142}," year ",[73,1340,746],{"class":134},[73,1342,1268],{"class":149},[73,1344,339],{"class":142},[73,1346,217],{"class":149},[73,1348,100],{"class":142},[73,1350,1351],{"class":149},"5",[73,1353,161],{"class":142},[73,1355,1356,1359,1361,1363,1366,1369,1371,1373,1375,1377,1379,1381,1383,1385],{"class":75,"line":333},[73,1357,1358],{"class":142},"    s, e ",[73,1360,146],{"class":134},[73,1362,320],{"class":149},[73,1364,1365],{"class":134}," *",[73,1367,1368],{"class":142}," (year ",[73,1370,279],{"class":134},[73,1372,282],{"class":149},[73,1374,547],{"class":142},[73,1376,194],{"class":134},[73,1378,282],{"class":149},[73,1380,100],{"class":142},[73,1382,1098],{"class":149},[73,1384,1365],{"class":134},[73,1386,1387],{"class":142}," year\n",[73,1389,1390,1392,1394,1396,1399,1401,1404,1406,1408,1410,1413,1415,1417,1419,1421,1423,1426,1428,1430,1432,1434,1437,1439,1441,1443,1445,1447,1449,1452,1454,1456],{"class":75,"line":371},[73,1391,771],{"class":149},[73,1393,339],{"class":142},[73,1395,776],{"class":134},[73,1397,1398],{"class":83},"\"year ",[73,1400,783],{"class":782},[73,1402,1403],{"class":142},"year",[73,1405,791],{"class":782},[73,1407,794],{"class":83},[73,1409,783],{"class":782},[73,1411,1412],{"class":142},"cumipmt(",[73,1414,298],{"class":149},[73,1416,100],{"class":142},[73,1418,303],{"class":149},[73,1420,100],{"class":142},[73,1422,308],{"class":149},[73,1424,1425],{"class":142},", s, e)",[73,1427,816],{"class":134},[73,1429,791],{"class":782},[73,1431,821],{"class":83},[73,1433,783],{"class":782},[73,1435,1436],{"class":142},"cumprinc(",[73,1438,298],{"class":149},[73,1440,100],{"class":142},[73,1442,303],{"class":149},[73,1444,100],{"class":142},[73,1446,308],{"class":149},[73,1448,1425],{"class":142},[73,1450,1451],{"class":134},":10.2f",[73,1453,791],{"class":782},[73,1455,845],{"class":83},[73,1457,848],{"class":142},[73,1459,1460,1462,1464,1467,1469,1471,1474,1476,1478,1480,1482,1484,1486,1488,1490,1492,1494,1496],{"class":75,"line":614},[73,1461,336],{"class":149},[73,1463,339],{"class":142},[73,1465,1466],{"class":83},"\"principal over the whole loan:\"",[73,1468,100],{"class":142},[73,1470,347],{"class":149},[73,1472,1473],{"class":142},"(cumprinc(",[73,1475,298],{"class":149},[73,1477,100],{"class":142},[73,1479,303],{"class":149},[73,1481,100],{"class":142},[73,1483,308],{"class":149},[73,1485,100],{"class":142},[73,1487,217],{"class":149},[73,1489,100],{"class":142},[73,1491,303],{"class":149},[73,1493,363],{"class":142},[73,1495,366],{"class":149},[73,1497,285],{"class":142},[10,1499,1500,1501,21,1503,1505,1506,21,1508,1510,1511,1514,1515,1517],{},"Interest falls from about 1,549 in year 1 to about 261 in year 4, while principal rises, and the principal over all 48 periods totals exactly −25,000 — the loan repaid in full. Unlike ",[14,1502,20],{},[14,1504,24],{},", Excel's ",[14,1507,28],{},[14,1509,31],{}," ",[423,1512,1513],{},"require"," the ",[14,1516,50],{}," argument and reject a zero or negative present value; the Python versions here are more forgiving, so add the same checks if the code must reject the same inputs.",[59,1519,1521],{"id":1520},"step-4-effect-and-nominal-compounding","Step 4 — EFFECT and NOMINAL: compounding",[10,1523,1524,1525,1528,1529,1532,1533,21,1535,1537],{},"A rate quoted as \"6.9% a year, compounded monthly\" is a ",[423,1526,1527],{},"nominal"," rate; the rate actually charged over a year, the ",[423,1530,1531],{},"effective"," rate, is higher because interest is charged on interest. ",[14,1534,35],{},[14,1536,38],{}," convert between the two:",[64,1539,1541],{"className":125,"code":1540,"language":127,"meta":69,"style":69},"def effect(nominal_rate, npery):\n    return (1 + nominal_rate \u002F npery) ** npery - 1\n\ndef nominal(effect_rate, npery):\n    return npery * ((1 + effect_rate) ** (1 \u002F npery) - 1)\n\nfor n, label in ((1, \"annually\"), (4, \"quarterly\"), (12, \"monthly\"), (365, \"daily\")):\n    print(f\"6.9% compounded {label:9} → effective {effect(0.069, n):.4%}\")\nprint(\"nominal monthly rate for 7.12% effective:\", f\"{nominal(0.0712, 12):.4%}\")\n",[14,1542,1543,1553,1581,1585,1595,1628,1632,1682,1726],{"__ignoreMap":69},[73,1544,1545,1547,1550],{"class":75,"line":76},[73,1546,135],{"class":134},[73,1548,1549],{"class":138}," effect",[73,1551,1552],{"class":142},"(nominal_rate, npery):\n",[73,1554,1555,1557,1559,1561,1563,1566,1568,1571,1573,1576,1578],{"class":75,"line":164},[73,1556,234],{"class":134},[73,1558,214],{"class":142},[73,1560,217],{"class":149},[73,1562,220],{"class":134},[73,1564,1565],{"class":142}," nominal_rate ",[73,1567,200],{"class":134},[73,1569,1570],{"class":142}," npery) ",[73,1572,226],{"class":134},[73,1574,1575],{"class":142}," npery ",[73,1577,279],{"class":134},[73,1579,1580],{"class":149}," 1\n",[73,1582,1583],{"class":75,"line":182},[73,1584,292],{"emptyLinePlaceholder":291},[73,1586,1587,1589,1592],{"class":75,"line":206},[73,1588,135],{"class":134},[73,1590,1591],{"class":138}," nominal",[73,1593,1594],{"class":142},"(effect_rate, npery):\n",[73,1596,1597,1599,1601,1603,1605,1607,1609,1612,1614,1616,1618,1620,1622,1624,1626],{"class":75,"line":231},[73,1598,234],{"class":134},[73,1600,1575],{"class":142},[73,1602,242],{"class":134},[73,1604,260],{"class":142},[73,1606,217],{"class":149},[73,1608,220],{"class":134},[73,1610,1611],{"class":142}," effect_rate) ",[73,1613,226],{"class":134},[73,1615,214],{"class":142},[73,1617,217],{"class":149},[73,1619,317],{"class":134},[73,1621,1570],{"class":142},[73,1623,279],{"class":134},[73,1625,282],{"class":149},[73,1627,848],{"class":142},[73,1629,1630],{"class":75,"line":288},[73,1631,292],{"emptyLinePlaceholder":291},[73,1633,1634,1636,1639,1641,1643,1645,1647,1650,1653,1655,1657,1660,1662,1664,1666,1669,1671,1674,1676,1679],{"class":75,"line":295},[73,1635,741],{"class":134},[73,1637,1638],{"class":142}," n, label ",[73,1640,746],{"class":134},[73,1642,260],{"class":142},[73,1644,217],{"class":149},[73,1646,100],{"class":142},[73,1648,1649],{"class":83},"\"annually\"",[73,1651,1652],{"class":142},"), (",[73,1654,971],{"class":149},[73,1656,100],{"class":142},[73,1658,1659],{"class":83},"\"quarterly\"",[73,1661,1652],{"class":142},[73,1663,1098],{"class":149},[73,1665,100],{"class":142},[73,1667,1668],{"class":83},"\"monthly\"",[73,1670,1652],{"class":142},[73,1672,1673],{"class":149},"365",[73,1675,100],{"class":142},[73,1677,1678],{"class":83},"\"daily\"",[73,1680,1681],{"class":142},")):\n",[73,1683,1684,1686,1688,1690,1693,1695,1698,1701,1703,1706,1708,1711,1714,1717,1720,1722,1724],{"class":75,"line":333},[73,1685,771],{"class":149},[73,1687,339],{"class":142},[73,1689,776],{"class":134},[73,1691,1692],{"class":83},"\"6.9% compounded ",[73,1694,783],{"class":782},[73,1696,1697],{"class":142},"label",[73,1699,1700],{"class":134},":9",[73,1702,791],{"class":782},[73,1704,1705],{"class":83}," → effective ",[73,1707,783],{"class":782},[73,1709,1710],{"class":142},"effect(",[73,1712,1713],{"class":149},"0.069",[73,1715,1716],{"class":142},", n)",[73,1718,1719],{"class":134},":.4%",[73,1721,791],{"class":782},[73,1723,845],{"class":83},[73,1725,848],{"class":142},[73,1727,1728,1730,1732,1735,1738,1741,1743,1745,1747,1749,1752,1755,1757,1759,1761,1763,1765,1767],{"class":75,"line":371},[73,1729,336],{"class":149},[73,1731,339],{"class":142},[73,1733,1734],{"class":83},"\"nominal monthly rate for 7.12",[73,1736,1737],{"class":782},"% e",[73,1739,1740],{"class":83},"ffective:\"",[73,1742,100],{"class":142},[73,1744,776],{"class":134},[73,1746,845],{"class":83},[73,1748,783],{"class":782},[73,1750,1751],{"class":142},"nominal(",[73,1753,1754],{"class":149},"0.0712",[73,1756,100],{"class":142},[73,1758,1098],{"class":149},[73,1760,813],{"class":142},[73,1762,1719],{"class":134},[73,1764,791],{"class":782},[73,1766,845],{"class":83},[73,1768,848],{"class":142},[10,1770,1771,1772,1774,1775,1778],{},"Monthly compounding turns a nominal 6.9% into an effective rate of about 7.12%; daily compounding gives slightly more. ",[14,1773,38],{}," reverses the conversion, which is what you need when a contract states an effective (or \"annual percentage\") rate and the model works in monthly periods. Excel truncates the ",[14,1776,1777],{},"npery"," argument to an integer; pass whole numbers to stay comparable.",[862,1780,871,1786,871,1789,871,1792,871,1796,871,1800,871,1806,871,1810,871,1815,871,1818,871,1822,871,1825,871,1830,871,1832,871,1836,871,1839,871,1844,871,1847,871,1851,871,1854],{"viewBox":1781,"role":865,"ariaLabelledBy":1782,"xmlns":869,"style":1785},"4 0 740 180",[1783,1784],"fin-effect-t","fin-effect-d","width:100%;max-width:740px;height:auto;display:block;margin:1.5rem auto;font-family:Inter,ui-sans-serif,system-ui,sans-serif",[873,1787,1788],{"id":1783},"The same 6.9% nominal rate, compounded differently",[877,1790,1791],{"id":1784},"A nominal annual rate of 6.9 percent gives an effective annual rate of 6.90 percent when compounded once a year, about 7.08 percent quarterly, about 7.12 percent monthly and about 7.14 percent daily.",[881,1793],{"x":971,"y":158,"width":1794,"height":1795,"fill":886},"740","180",[881,1797],{"x":1094,"y":1095,"width":1798,"height":918,"rx":1799,"fill":893,"stroke":894,"style":895},"86.8","7",[901,1801,1805],{"x":1802,"y":1803,"style":1804},"63.4","34.5","font-size:12.5px;font-weight:700;fill:var(--text,#172033);text-anchor:middle","annually",[881,1807],{"x":1808,"y":1095,"width":1809,"height":918,"rx":1799,"fill":893,"stroke":894,"style":984},"116.8","546.3",[901,1811,1814],{"x":1812,"y":1803,"style":1813},"671.1","font-size:12px;font-weight:700;fill:var(--text,#172033);text-anchor:start","6.90%",[881,1816],{"x":1094,"y":1817,"width":1798,"height":918,"rx":1799,"fill":893,"stroke":894,"style":895},"56.0",[901,1819,1821],{"x":1802,"y":1820,"style":1804},"74.5","quarterly",[881,1823],{"x":1808,"y":1817,"width":1824,"height":918,"rx":1799,"fill":1099,"stroke":1054,"style":984},"560.6",[901,1826,1829],{"x":1827,"y":1820,"style":1828},"685.4","font-size:12px;font-weight:700;fill:var(--brand-strong,#4338ca);text-anchor:start","7.08%",[881,1831],{"x":1094,"y":1018,"width":1798,"height":918,"rx":1799,"fill":893,"stroke":894,"style":895},[901,1833,1835],{"x":1802,"y":1834,"style":1804},"114.5","monthly",[881,1837],{"x":1808,"y":1018,"width":1838,"height":918,"rx":1799,"fill":1010,"stroke":1011,"style":984},"563.7",[901,1840,1843],{"x":1841,"y":1834,"style":1842},"688.6","font-size:12px;font-weight:700;fill:var(--teal-ink,#0b6157);text-anchor:start","7.12%",[881,1845],{"x":1094,"y":1846,"width":1798,"height":918,"rx":1799,"fill":893,"stroke":894,"style":895},"136.0",[901,1848,1850],{"x":1802,"y":1849,"style":1804},"154.5","daily",[881,1852],{"x":1808,"y":1846,"width":1853,"height":918,"rx":1799,"fill":1001,"stroke":1002,"style":984},"565.3",[901,1855,1858],{"x":1856,"y":1849,"style":1857},"690.1","font-size:12px;font-weight:700;fill:var(--gold-ink,#7a4e06);text-anchor:start","7.14%",[59,1860,1862],{"id":1861},"step-5-a-pandas-schedule-checked-against-the-spreadsheet","Step 5 — A pandas schedule, checked against the spreadsheet",[10,1864,1865],{},"Build the split as a DataFrame for every period, then write the equivalent formulas into a workbook, recalculate and compare:",[64,1867,1869],{"className":125,"code":1868,"language":127,"meta":69,"style":69},"import subprocess\nimport pandas as pd\nfrom openpyxl import Workbook, load_workbook\n\nperiods = range(1, NPER + 1)\nsched = pd.DataFrame({\"Period\": list(periods),\n                      \"Interest\": [ipmt(RATE, p, NPER, PV) for p in periods],\n                      \"Principal\": [ppmt(RATE, p, NPER, PV) for p in periods]})\nsched[\"Balance\"] = PV + sched[\"Principal\"].cumsum()\nprint(sched.round(2).iloc[[0, 1, 23, 47]].to_string(index=False))\n\nwb = Workbook()\nws = wb.active\nfor i, p in enumerate(periods, start=1):\n    ws.append([f\"=IPMT(0.069\u002F12,{p},48,25000)\", f\"=PPMT(0.069\u002F12,{p},48,25000)\", f\"=IPMT(0.069\u002F12,{p},48,25000,0,1)\"])\nws[\"E1\"], ws[\"E2\"] = \"=CUMIPMT(0.069\u002F12,48,25000,13,24,0)\", \"=CUMPRINC(0.069\u002F12,48,25000,13,24,0)\"\nws[\"E3\"], ws[\"E4\"] = \"=EFFECT(0.069,12)\", \"=NOMINAL(0.0712,12)\"\nwb.save(\"loan.xlsx\")\nsubprocess.run([\"soffice\", \"--headless\", \"--convert-to\", \"xlsx\", \"--outdir\", \"calc\", \"loan.xlsx\"], check=True, capture_output=True)\nc = load_workbook(\"calc\u002Floan.xlsx\", data_only=True).active\ndiffs = [abs(c.cell(p, 1).value - ipmt(RATE, p, NPER, PV)) for p in periods]\ndiffs += [abs(c.cell(p, 2).value - ppmt(RATE, p, NPER, PV)) for p in periods]\ndiffs += [abs(c.cell(p, 3).value - ipmt(RATE, p, NPER, PV, when=1)) for p in periods]\ndiffs += [abs(c[\"E1\"].value - cumipmt(RATE, NPER, PV, 13, 24)), abs(c[\"E2\"].value - cumprinc(RATE, NPER, PV, 13, 24)),\n          abs(c[\"E3\"].value - effect(0.069, 12)), abs(c[\"E4\"].value - nominal(0.0712, 12))]\nprint(f\"{len(diffs)} values compared, largest difference: {max(diffs):.2e}\")\n",[14,1870,1871,1879,1892,1905,1909,1932,1954,1984,2013,2040,2081,2085,2095,2105,2128,2180,2206,2230,2240,2299,2325,2374,2417,2466,2546,2593],{"__ignoreMap":69},[73,1872,1873,1876],{"class":75,"line":76},[73,1874,1875],{"class":134},"import",[73,1877,1878],{"class":142}," subprocess\n",[73,1880,1881,1883,1886,1889],{"class":75,"line":164},[73,1882,1875],{"class":134},[73,1884,1885],{"class":142}," pandas ",[73,1887,1888],{"class":134},"as",[73,1890,1891],{"class":142}," pd\n",[73,1893,1894,1897,1900,1902],{"class":75,"line":182},[73,1895,1896],{"class":134},"from",[73,1898,1899],{"class":142}," openpyxl ",[73,1901,1875],{"class":134},[73,1903,1904],{"class":142}," Workbook, load_workbook\n",[73,1906,1907],{"class":75,"line":206},[73,1908,292],{"emptyLinePlaceholder":291},[73,1910,1911,1914,1916,1918,1920,1922,1924,1926,1928,1930],{"class":75,"line":231},[73,1912,1913],{"class":142},"periods ",[73,1915,146],{"class":134},[73,1917,1268],{"class":149},[73,1919,339],{"class":142},[73,1921,217],{"class":149},[73,1923,100],{"class":142},[73,1925,303],{"class":149},[73,1927,220],{"class":134},[73,1929,282],{"class":149},[73,1931,848],{"class":142},[73,1933,1934,1937,1939,1942,1945,1948,1951],{"class":75,"line":288},[73,1935,1936],{"class":142},"sched ",[73,1938,146],{"class":134},[73,1940,1941],{"class":142}," pd.DataFrame({",[73,1943,1944],{"class":83},"\"Period\"",[73,1946,1947],{"class":142},": ",[73,1949,1950],{"class":149},"list",[73,1952,1953],{"class":142},"(periods),\n",[73,1955,1956,1959,1962,1964,1967,1969,1971,1973,1975,1977,1979,1981],{"class":75,"line":295},[73,1957,1958],{"class":83},"                      \"Interest\"",[73,1960,1961],{"class":142},": [ipmt(",[73,1963,298],{"class":149},[73,1965,1966],{"class":142},", p, ",[73,1968,303],{"class":149},[73,1970,100],{"class":142},[73,1972,308],{"class":149},[73,1974,547],{"class":142},[73,1976,741],{"class":134},[73,1978,1263],{"class":142},[73,1980,746],{"class":134},[73,1982,1983],{"class":142}," periods],\n",[73,1985,1986,1989,1992,1994,1996,1998,2000,2002,2004,2006,2008,2010],{"class":75,"line":333},[73,1987,1988],{"class":83},"                      \"Principal\"",[73,1990,1991],{"class":142},": [ppmt(",[73,1993,298],{"class":149},[73,1995,1966],{"class":142},[73,1997,303],{"class":149},[73,1999,100],{"class":142},[73,2001,308],{"class":149},[73,2003,547],{"class":142},[73,2005,741],{"class":134},[73,2007,1263],{"class":142},[73,2009,746],{"class":134},[73,2011,2012],{"class":142}," periods]})\n",[73,2014,2015,2018,2021,2024,2026,2029,2031,2034,2037],{"class":75,"line":371},[73,2016,2017],{"class":142},"sched[",[73,2019,2020],{"class":83},"\"Balance\"",[73,2022,2023],{"class":142},"] ",[73,2025,146],{"class":134},[73,2027,2028],{"class":149}," PV",[73,2030,220],{"class":134},[73,2032,2033],{"class":142}," sched[",[73,2035,2036],{"class":83},"\"Principal\"",[73,2038,2039],{"class":142},"].cumsum()\n",[73,2041,2042,2044,2047,2049,2052,2054,2056,2058,2060,2063,2065,2068,2071,2074,2076,2079],{"class":75,"line":614},[73,2043,336],{"class":149},[73,2045,2046],{"class":142},"(sched.round(",[73,2048,366],{"class":149},[73,2050,2051],{"class":142},").iloc[[",[73,2053,158],{"class":149},[73,2055,100],{"class":142},[73,2057,217],{"class":149},[73,2059,100],{"class":142},[73,2061,2062],{"class":149},"23",[73,2064,100],{"class":142},[73,2066,2067],{"class":149},"47",[73,2069,2070],{"class":142},"]].to_string(",[73,2072,2073],{"class":399},"index",[73,2075,146],{"class":134},[73,2077,2078],{"class":149},"False",[73,2080,285],{"class":142},[73,2082,2083],{"class":75,"line":622},[73,2084,292],{"emptyLinePlaceholder":291},[73,2086,2087,2090,2092],{"class":75,"line":644},[73,2088,2089],{"class":142},"wb ",[73,2091,146],{"class":134},[73,2093,2094],{"class":142}," Workbook()\n",[73,2096,2097,2100,2102],{"class":75,"line":660},[73,2098,2099],{"class":142},"ws ",[73,2101,146],{"class":134},[73,2103,2104],{"class":142}," wb.active\n",[73,2106,2107,2109,2112,2114,2117,2120,2122,2124,2126],{"class":75,"line":693},[73,2108,741],{"class":134},[73,2110,2111],{"class":142}," i, p ",[73,2113,746],{"class":134},[73,2115,2116],{"class":149}," enumerate",[73,2118,2119],{"class":142},"(periods, ",[73,2121,425],{"class":399},[73,2123,146],{"class":134},[73,2125,217],{"class":149},[73,2127,161],{"class":142},[73,2129,2130,2133,2135,2138,2140,2142,2144,2147,2149,2151,2154,2156,2158,2160,2162,2164,2166,2168,2170,2172,2174,2177],{"class":75,"line":698},[73,2131,2132],{"class":142},"    ws.append([",[73,2134,776],{"class":134},[73,2136,2137],{"class":83},"\"=IPMT(0.069\u002F12,",[73,2139,783],{"class":782},[73,2141,10],{"class":142},[73,2143,791],{"class":782},[73,2145,2146],{"class":83},",48,25000)\"",[73,2148,100],{"class":142},[73,2150,776],{"class":134},[73,2152,2153],{"class":83},"\"=PPMT(0.069\u002F12,",[73,2155,783],{"class":782},[73,2157,10],{"class":142},[73,2159,791],{"class":782},[73,2161,2146],{"class":83},[73,2163,100],{"class":142},[73,2165,776],{"class":134},[73,2167,2137],{"class":83},[73,2169,783],{"class":782},[73,2171,10],{"class":142},[73,2173,791],{"class":782},[73,2175,2176],{"class":83},",48,25000,0,1)\"",[73,2178,2179],{"class":142},"])\n",[73,2181,2182,2185,2188,2191,2194,2196,2198,2201,2203],{"class":75,"line":720},[73,2183,2184],{"class":142},"ws[",[73,2186,2187],{"class":83},"\"E1\"",[73,2189,2190],{"class":142},"], ws[",[73,2192,2193],{"class":83},"\"E2\"",[73,2195,2023],{"class":142},[73,2197,146],{"class":134},[73,2199,2200],{"class":83}," \"=CUMIPMT(0.069\u002F12,48,25000,13,24,0)\"",[73,2202,100],{"class":142},[73,2204,2205],{"class":83},"\"=CUMPRINC(0.069\u002F12,48,25000,13,24,0)\"\n",[73,2207,2208,2210,2213,2215,2218,2220,2222,2225,2227],{"class":75,"line":733},[73,2209,2184],{"class":142},[73,2211,2212],{"class":83},"\"E3\"",[73,2214,2190],{"class":142},[73,2216,2217],{"class":83},"\"E4\"",[73,2219,2023],{"class":142},[73,2221,146],{"class":134},[73,2223,2224],{"class":83}," \"=EFFECT(0.069,12)\"",[73,2226,100],{"class":142},[73,2228,2229],{"class":83},"\"=NOMINAL(0.0712,12)\"\n",[73,2231,2232,2235,2238],{"class":75,"line":738},[73,2233,2234],{"class":142},"wb.save(",[73,2236,2237],{"class":83},"\"loan.xlsx\"",[73,2239,848],{"class":142},[73,2241,2242,2245,2248,2250,2253,2255,2258,2260,2263,2265,2268,2270,2273,2275,2277,2280,2283,2285,2288,2290,2293,2295,2297],{"class":75,"line":768},[73,2243,2244],{"class":142},"subprocess.run([",[73,2246,2247],{"class":83},"\"soffice\"",[73,2249,100],{"class":142},[73,2251,2252],{"class":83},"\"--headless\"",[73,2254,100],{"class":142},[73,2256,2257],{"class":83},"\"--convert-to\"",[73,2259,100],{"class":142},[73,2261,2262],{"class":83},"\"xlsx\"",[73,2264,100],{"class":142},[73,2266,2267],{"class":83},"\"--outdir\"",[73,2269,100],{"class":142},[73,2271,2272],{"class":83},"\"calc\"",[73,2274,100],{"class":142},[73,2276,2237],{"class":83},[73,2278,2279],{"class":142},"], ",[73,2281,2282],{"class":399},"check",[73,2284,146],{"class":134},[73,2286,2287],{"class":149},"True",[73,2289,100],{"class":142},[73,2291,2292],{"class":399},"capture_output",[73,2294,146],{"class":134},[73,2296,2287],{"class":149},[73,2298,848],{"class":142},[73,2300,2302,2305,2307,2310,2313,2315,2318,2320,2322],{"class":75,"line":2301},20,[73,2303,2304],{"class":142},"c ",[73,2306,146],{"class":134},[73,2308,2309],{"class":142}," load_workbook(",[73,2311,2312],{"class":83},"\"calc\u002Floan.xlsx\"",[73,2314,100],{"class":142},[73,2316,2317],{"class":399},"data_only",[73,2319,146],{"class":134},[73,2321,2287],{"class":149},[73,2323,2324],{"class":142},").active\n",[73,2326,2328,2331,2333,2336,2339,2342,2344,2347,2349,2352,2354,2356,2358,2360,2362,2365,2367,2369,2371],{"class":75,"line":2327},21,[73,2329,2330],{"class":142},"diffs ",[73,2332,146],{"class":134},[73,2334,2335],{"class":142}," [",[73,2337,2338],{"class":149},"abs",[73,2340,2341],{"class":142},"(c.cell(p, ",[73,2343,217],{"class":149},[73,2345,2346],{"class":142},").value ",[73,2348,279],{"class":134},[73,2350,2351],{"class":142}," ipmt(",[73,2353,298],{"class":149},[73,2355,1966],{"class":142},[73,2357,303],{"class":149},[73,2359,100],{"class":142},[73,2361,308],{"class":149},[73,2363,2364],{"class":142},")) ",[73,2366,741],{"class":134},[73,2368,1263],{"class":142},[73,2370,746],{"class":134},[73,2372,2373],{"class":142}," periods]\n",[73,2375,2377,2379,2382,2384,2386,2388,2390,2392,2394,2397,2399,2401,2403,2405,2407,2409,2411,2413,2415],{"class":75,"line":2376},22,[73,2378,2330],{"class":142},[73,2380,2381],{"class":134},"+=",[73,2383,2335],{"class":142},[73,2385,2338],{"class":149},[73,2387,2341],{"class":142},[73,2389,366],{"class":149},[73,2391,2346],{"class":142},[73,2393,279],{"class":134},[73,2395,2396],{"class":142}," ppmt(",[73,2398,298],{"class":149},[73,2400,1966],{"class":142},[73,2402,303],{"class":149},[73,2404,100],{"class":142},[73,2406,308],{"class":149},[73,2408,2364],{"class":142},[73,2410,741],{"class":134},[73,2412,1263],{"class":142},[73,2414,746],{"class":134},[73,2416,2373],{"class":142},[73,2418,2420,2422,2424,2426,2428,2430,2432,2434,2436,2438,2440,2442,2444,2446,2448,2450,2452,2454,2456,2458,2460,2462,2464],{"class":75,"line":2419},23,[73,2421,2330],{"class":142},[73,2423,2381],{"class":134},[73,2425,2335],{"class":142},[73,2427,2338],{"class":149},[73,2429,2341],{"class":142},[73,2431,956],{"class":149},[73,2433,2346],{"class":142},[73,2435,279],{"class":134},[73,2437,2351],{"class":142},[73,2439,298],{"class":149},[73,2441,1966],{"class":142},[73,2443,303],{"class":149},[73,2445,100],{"class":142},[73,2447,308],{"class":149},[73,2449,100],{"class":142},[73,2451,400],{"class":399},[73,2453,146],{"class":134},[73,2455,217],{"class":149},[73,2457,2364],{"class":142},[73,2459,741],{"class":134},[73,2461,1263],{"class":142},[73,2463,746],{"class":134},[73,2465,2373],{"class":142},[73,2467,2469,2471,2473,2475,2477,2480,2482,2485,2487,2490,2492,2494,2496,2498,2500,2502,2505,2507,2509,2512,2514,2516,2518,2520,2522,2525,2527,2529,2531,2533,2535,2537,2539,2541,2543],{"class":75,"line":2468},24,[73,2470,2330],{"class":142},[73,2472,2381],{"class":134},[73,2474,2335],{"class":142},[73,2476,2338],{"class":149},[73,2478,2479],{"class":142},"(c[",[73,2481,2187],{"class":83},[73,2483,2484],{"class":142},"].value ",[73,2486,279],{"class":134},[73,2488,2489],{"class":142}," cumipmt(",[73,2491,298],{"class":149},[73,2493,100],{"class":142},[73,2495,303],{"class":149},[73,2497,100],{"class":142},[73,2499,308],{"class":149},[73,2501,100],{"class":142},[73,2503,2504],{"class":149},"13",[73,2506,100],{"class":142},[73,2508,759],{"class":149},[73,2510,2511],{"class":142},")), ",[73,2513,2338],{"class":149},[73,2515,2479],{"class":142},[73,2517,2193],{"class":83},[73,2519,2484],{"class":142},[73,2521,279],{"class":134},[73,2523,2524],{"class":142}," cumprinc(",[73,2526,298],{"class":149},[73,2528,100],{"class":142},[73,2530,303],{"class":149},[73,2532,100],{"class":142},[73,2534,308],{"class":149},[73,2536,100],{"class":142},[73,2538,2504],{"class":149},[73,2540,100],{"class":142},[73,2542,759],{"class":149},[73,2544,2545],{"class":142},")),\n",[73,2547,2549,2552,2554,2556,2558,2560,2563,2565,2567,2569,2571,2573,2575,2577,2579,2581,2584,2586,2588,2590],{"class":75,"line":2548},25,[73,2550,2551],{"class":149},"          abs",[73,2553,2479],{"class":142},[73,2555,2212],{"class":83},[73,2557,2484],{"class":142},[73,2559,279],{"class":134},[73,2561,2562],{"class":142}," effect(",[73,2564,1713],{"class":149},[73,2566,100],{"class":142},[73,2568,1098],{"class":149},[73,2570,2511],{"class":142},[73,2572,2338],{"class":149},[73,2574,2479],{"class":142},[73,2576,2217],{"class":83},[73,2578,2484],{"class":142},[73,2580,279],{"class":134},[73,2582,2583],{"class":142}," nominal(",[73,2585,1754],{"class":149},[73,2587,100],{"class":142},[73,2589,1098],{"class":149},[73,2591,2592],{"class":142},"))]\n",[73,2594,2596,2598,2600,2602,2604,2606,2609,2612,2614,2617,2619,2622,2624,2627,2629,2631],{"class":75,"line":2595},26,[73,2597,336],{"class":149},[73,2599,339],{"class":142},[73,2601,776],{"class":134},[73,2603,845],{"class":83},[73,2605,783],{"class":782},[73,2607,2608],{"class":149},"len",[73,2610,2611],{"class":142},"(diffs)",[73,2613,791],{"class":782},[73,2615,2616],{"class":83}," values compared, largest difference: ",[73,2618,783],{"class":782},[73,2620,2621],{"class":149},"max",[73,2623,2611],{"class":142},[73,2625,2626],{"class":134},":.2e",[73,2628,791],{"class":782},[73,2630,845],{"class":83},[73,2632,848],{"class":142},[10,2634,2635,2636,57],{},"The schedule shows the balance falling from 25,000 to zero — the running total of principal repayments added to the original loan. The comparison covers interest and principal for all 48 periods, interest with payments at the start of the period, the cumulative functions for year 2, and both rate conversions: every value agrees with the spreadsheet to within floating-point precision. The same functions drive a full amortisation report in ",[53,2637,2639],{"href":2638},"\u002Fautomating-reporting-workflows\u002Fbuilding-finance-and-operations-reports\u002Fbuild-a-loan-amortization-schedule-in-excel\u002F","Build a Loan Amortization Schedule in Excel with Python",[59,2641,2643],{"id":2642},"common-pitfalls","Common pitfalls",[2645,2646,2647,2655,2661,2670,2676],"ul",{},[2648,2649,2650,2654],"li",{},[2651,2652,2653],"strong",{},"Annual rates with monthly periods."," Divide the rate by 12 and multiply the term by 12.",[2648,2656,2657,2660],{},[2651,2658,2659],{},"Ignoring the sign convention."," Payments out are negative; keep Excel's signs until presentation.",[2648,2662,2663,2666,2667,2669],{},[2651,2664,2665],{},"Payments at the start of the period."," Pass ",[14,2668,416],{},"; the first payment has no interest.",[2648,2671,2672,2675],{},[2651,2673,2674],{},"Nominal and effective rates mixed up."," Convert with EFFECT and NOMINAL before using a rate.",[2648,2677,2678,2684,2685,2687],{},[2651,2679,2680,2681,2683],{},"Assuming ",[14,2682,42],{}," exists."," It moved to ",[14,2686,46],{},"; or use the formulas above.",[59,2689,2691],{"id":2690},"conclusion","Conclusion",[10,2693,2694,2695,100,2697,100,2699,100,2701,21,2703,2705,2706,21,2708,2710,2711,2713],{},"Excel's loan functions follow from two formulas — the level payment and the balance after a number of payments — and Python implementations of ",[14,2696,16],{},[14,2698,20],{},[14,2700,24],{},[14,2702,28],{},[14,2704,31],{}," take a few lines each, as do ",[14,2707,35],{},[14,2709,38],{}," for compounding. Keep Excel's sign convention and ",[14,2712,50],{}," argument so results can be compared with existing workbooks, convert annual rates to the payment period, build schedules with pandas, and check the functions against the spreadsheet's own results on every period.",[59,2715,2717],{"id":2716},"frequently-asked-questions","Frequently asked questions",[10,2719,2720,2723],{},[2651,2721,2722],{},"What is the Python equivalent of Excel's IPMT and PPMT?","\nCompute the payment with the PMT formula, the balance before the period with the future-value formula, and the interest as that balance times the rate; the principal is the payment minus the interest. numpy-financial also provides ipmt and ppmt.",[10,2725,2726,2729],{},[2651,2727,2728],{},"Why are my IPMT results negative?","\nExcel's convention treats money paid out as negative. A loan entered as a positive present value gives negative payments, interest and principal.",[10,2731,2732,2735],{},[2651,2733,2734],{},"How do I convert a nominal rate to an effective rate in Python?","\nUse (1 + nominal \u002F n) ** n - 1, where n is the number of compounding periods per year. This is Excel's EFFECT function.",[10,2737,2738,2741],{},[2651,2739,2740],{},"What does the type argument change?","\nType 1 means payments at the start of each period. Payments are slightly smaller, and the first payment contains no interest.",[59,2743,2745],{"id":2744},"related","Related",[2645,2747,2748,2754,2761,2768],{},[2648,2749,2750,2751,2753],{},"Up one level: ",[53,2752,56],{"href":55}," — spreadsheet functions in Python.",[2648,2755,2756,2760],{},[53,2757,2759],{"href":2758},"\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Ffv-pv-rate-and-nper-equivalents-in-python\u002F","FV, PV, RATE and NPER Equivalents in Python"," — the rest of the time-value family.",[2648,2762,2763,2767],{},[53,2764,2766],{"href":2765},"\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Fsln-db-and-ddb-depreciation-functions-in-python\u002F","SLN, DB and DDB Depreciation Functions in Python"," — the depreciation functions.",[2648,2769,2770,2774],{},[53,2771,2773],{"href":2772},"\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Fxirr-and-xnpv-equivalents-in-python\u002F","XIRR and XNPV Equivalents in Python"," — irregular cash flows.",[2776,2777,2778],"style",{},"html pre.shiki code .sMTad, html code.shiki .sMTad{--shiki-default:#6F42C1;--shiki-dark:#FFB757}html pre.shiki code .srMev, html code.shiki .srMev{--shiki-default:#032F62;--shiki-dark:#ADDCFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s-kum, html code.shiki .s-kum{--shiki-default:#D73A49;--shiki-dark:#FF9492}html pre.shiki code .s_Opv, html code.shiki .s_Opv{--shiki-default:#6F42C1;--shiki-dark:#DBB7FF}html pre.shiki code .skGVy, html code.shiki .skGVy{--shiki-default:#24292E;--shiki-dark:#F0F3F6}html pre.shiki code .sP0c6, html code.shiki .sP0c6{--shiki-default:#005CC5;--shiki-dark:#91CBFF}html pre.shiki code .sa561, html code.shiki .sa561{--shiki-default:#E36209;--shiki-dark:#FFB757}html pre.shiki code .s-wDw, html code.shiki .s-wDw{--shiki-default:#6A737D;--shiki-dark:#BDC4CC}html pre.shiki code .sSjpA, html code.shiki .sSjpA{--shiki-default:#005CC5;--shiki-dark:#FF9492}",{"title":69,"searchDepth":164,"depth":164,"links":2780},[2781,2782,2783,2784,2785,2786,2787,2788,2789,2790],{"id":61,"depth":164,"text":62},{"id":114,"depth":164,"text":115},{"id":429,"depth":164,"text":430},{"id":1211,"depth":164,"text":1212},{"id":1520,"depth":164,"text":1521},{"id":1861,"depth":164,"text":1862},{"id":2642,"depth":164,"text":2643},{"id":2690,"depth":164,"text":2691},{"id":2716,"depth":164,"text":2717},{"id":2744,"depth":164,"text":2745},"2026-10-02","Split loan payments into interest and principal and convert between nominal and effective rates in Python, matching Excel: PMT, IPMT, PPMT and CUMIPMT\u002FCUMPRINC from first principles, Excel's sign convention, payments at the start or end of the period, EFFECT and NOMINAL for compounding frequencies, a vectorised schedule in pandas, and a check against the spreadsheet functions.","md",[2795,2797,2799,2801],{"q":2722,"a":2796},"Compute the payment with the PMT formula, the balance before the period with the future-value formula, and the interest as that balance times the rate; the principal is the payment minus the interest. numpy-financial also provides ipmt and ppmt.",{"q":2728,"a":2798},"Excel's convention treats money paid out as negative. A loan entered as a positive present value gives negative payments, interest and principal.",{"q":2734,"a":2800},"Use (1 + nominal \u002F n) ** n - 1, where n is the number of compounding periods per year. This is Excel's EFFECT function.",{"q":2740,"a":2802},"Type 1 means payments at the start of each period. Payments are slightly smaller, and the first payment contains no interest.","ipmt ppmt effect and nominal equivalents in python",null,{"breadcrumb":2806},[2807,2809,2812],{"name":2808,"item":200},"Home",{"name":2810,"item":2811},"Advanced Data Transformation and Cleaning for Excel Automation","\u002Fadvanced-data-transformation-and-cleaning\u002F",{"name":56,"item":55},"\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Fipmt-ppmt-effect-and-nominal-equivalents-in-python",{"title":5,"description":2815},"Implement Excel IPMT, PPMT, CUMIPMT, CUMPRINC, EFFECT and NOMINAL in Python: sign convention, type 0\u002F1 payments, a pandas amortisation split and a period-by-period comparison with spreadsheet results.","ipmt-ppmt-effect-and-nominal-equivalents-in-python","advanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Fipmt-ppmt-effect-and-nominal-equivalents-in-python\u002Findex",[2819],"formula-equivalents","how-to","OQmo8FVlFZtl3EmT0fVk3Bq4IyC09PDe7E87I0u-a0U",[2823,2827],{"title":2824,"path":2825,"stem":2826,"children":-1},"INDIRECT and OFFSET Equivalents in pandas","\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Findirect-and-offset-equivalents-in-pandas","advanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Findirect-and-offset-equivalents-in-pandas\u002Findex",{"title":2828,"path":2829,"stem":2830,"children":-1},"Match Excel Rounding in pandas","\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Fmatch-excel-rounding-in-pandas","advanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas\u002Fmatch-excel-rounding-in-pandas\u002Findex",[2832,2834],{"path":2833,"title":56},"\u002Fadvanced-data-transformation-and-cleaning\u002Fexcel-formula-equivalents-in-pandas",{"path":2835,"title":2810},"\u002Fadvanced-data-transformation-and-cleaning",[],[2838,2841,2844,2847,2850,2853],{"path":2839,"title":2840,"kind":2820},"\u002Fadvanced-data-transformation-and-cleaning\u002Fmerging-and-joining-excel-dataframes\u002Fvlookup-equivalent-in-pandas-for-excel-files","The VLOOKUP Equivalent in pandas for Excel Files",{"path":2842,"title":2843,"kind":2820},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fextract-numbers-and-codes-from-text-with-pandas","Extract Numbers and Codes from Text with pandas",{"path":2845,"title":2846,"kind":2820},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcleaning-excel-data-with-pandas\u002Fsplit-full-names-into-first-and-last-names-with-pandas","Split Full Names into First and Last Names with pandas",{"path":2848,"title":2849,"kind":2820},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fbin-values-into-ranges-with-pandas-cut","Bin Values into Ranges Like Excel FREQUENCY with pd.cut",{"path":2851,"title":2852,"kind":2820},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fcalculate-percent-of-total-per-group-in-pandas","Calculate Percent of Total per Group in pandas",{"path":2854,"title":2855,"kind":2820},"\u002Fadvanced-data-transformation-and-cleaning\u002Fcreating-pivot-tables-from-excel-data\u002Fcount-distinct-values-per-group-in-pandas","Count Distinct Values per Group in pandas",1790972088344]