#coding:utf-8
import sys
from prettytable import PrettyTable
import math
'''
月利率 = 年利率/12
1.等额本息计算公式:每月还款金额 =〔贷款本金×月利率×(1+月利率)^还款月数〕÷〔(1+月利率)^还款月数 - 1〕
每月利息 = 每月还款金额 - (1 + 月利率 )^(还款期数-1) * (每月还款金额 - 月利率*贷款本金)
每月偿还本金 = ( 1 + 月利率)^(还款期数-1) * (每月还款金额 - 月利率*贷款本金)
2.等额本金计算公式:每月还款金额 =(贷款本金 / 还款月数)+(本金 — 已归还本金累计额)* 每月利率
每月偿还本金=贷款本金/还款月数
每月利息=(本金-累计已还本金)×月利率
'''
YEAR_LPR=0.0385 #年利率
MONTH_LPR=round(YEAR_LPR/12,12) #月利率
UNIT= 10000 #单位万元
'''
月供计算
periods:第n期还款
pay_month:总还款月数
total:单位(万元)
等额本息:pay_way=1
等额本金:pay_way=2
'''
#月供
def get_month_pay(total,periods=1,pay_month=360,pay_way=1):
result=0
if pay_way==1:
result = (total*UNIT*MONTH_LPR*((MONTH_LPR+1)**pay_month))/((MONTH_LPR+1)**pay_month-1)
elif pay_way==2:
result=(total*UNIT/pay_month)+(total*UNIT - (total*UNIT/pay_month)*(periods-1) )*MONTH_LPR
return round(result,6)
# 每月还款利息
def get_month_interest(total,periods=1,pay_month=360,pay_way=1):
result=0
if pay_way==1:
month_pay = round((total*UNIT*MONTH_LPR*((MONTH_LPR+1)**pay_month))/((MONTH_LPR+1)**pay_month-1),6) #每月还款金额
result = month_pay-((1 + MONTH_LPR)**(periods-1)) * (month_pay - MONTH_LPR * total * UNIT)
elif pay_way==2:
result = (total*UNIT - (total*UNIT/pay_month)*(periods-1) )*MONTH_LPR
return round(result,6)
#每月还款本金
def get_month_principal(total,periods=1,pay_month=360,pay_way=1):
result=0
if pay_way==1:
month_pay = round((total*UNIT*MONTH_LPR*((MONTH_LPR+1)**pay_month))/((MONTH_LPR+1)**pay_month-1),6) #每月还款金额
result = ((1 + MONTH_LPR)**(periods-1)) * (month_pay - MONTH_LPR * total* UNIT)
elif pay_way==2:
result = total*UNIT/pay_month
return round(result,6)
#获取剩余还款期数(还款周期,还款金额不变,缩短剩余期数)
#pay_month:月供
#total:上期本金
#total_new:新的还款本金
#periods:上期还款周期
def get_month_periods1(total_new,pay_month):
period = math.log10(pay_month/(pay_month-total_new*MONTH_LPR))/math.log10(1+MONTH_LPR)
# return math.ceil(period)
return int(period) #尽力缩短还款期数
def get_month_periods2(total,total_new,periods):
period = total_new/(total*UNIT) * periods
# return math.ceil(period)
return int(period)
'''
sum_total:还款本金
pay_month:总还款期数
pay_way:还款方式
等额本息:pay_way=1
等额本金:pay_way=2
before_pay_dict:提前还款参数,值:{key(第几期):value(提前还款金额)}
'''
def main(sum_total,pay_month,pay_way,before_pay_dict=dict()):
titiles = ["期数", "月还款", "还款本金","还款利息","总还款","总还款本金","剩余还款本金","总还款利息"]
tb = PrettyTable(titiles)
for i in titiles:tb._align[i] = 'l'
sum_month_pay1 = 0 #总还款金额
sum_month_pay2 = 0
sum_month_principal1= 0 #总还款本金
sum_month_principal2 = 0
sum_month_interest1 = 0 #总还款利息
sum_month_interest2 = 0
mod_principal1 = sum_total * UNIT #剩余本金
mod_principal2 = sum_total * UNIT
remaining_pay_month = pay_month ##提前还款后,剩余还款期数
total = sum_total
periods =0 #第n期
for i,_ in enumerate(range(1,pay_month+1),1):
periods += 1
month_pay1=get_month_pay(total,periods,remaining_pay_month,pay_way=1) #月供
month_pay2=get_month_pay(total,periods,remaining_pay_month,pay_way=2)
month_interest1 = get_month_interest(total,periods,remaining_pay_month,pay_way=1) #利息
month_interest2 = get_month_interest(total,periods,remaining_pay_month,pay_way=2)
month_principal1 = get_month_principal(total,periods,remaining_pay_month,pay_way=1) #本金
month_principal2 = get_month_principal(total,periods,remaining_pay_month,pay_way=2)
sum_month_pay1 += month_pay1 #总还款数
sum_month_pay2 += month_pay2
sum_month_principal1 += month_principal1 #总还款本金
sum_month_principal2 += month_principal2
sum_month_interest1 += month_interest1 #总还款利息
sum_month_interest2 += month_interest2
mod_principal1 = (sum_total*UNIT) -sum_month_principal1 #剩余本金
mod_principal2 = (sum_total*UNIT) -sum_month_principal2
#提前还款
if before_pay_dict.keys().__contains__(i):
pay_money = before_pay_dict[i] #提前还款金额
month_principal1 += pay_money
month_principal2 += pay_money
sum_month_pay1 += pay_money
sum_month_pay2 += pay_money
sum_month_principal1 += pay_money
sum_month_principal2 += pay_money
mod_principal1 -= pay_money
mod_principal2 -= pay_money
periods = 0
remaining_pay_month = pay_month - i
if pay_way==1 and mod_principal1>0: total = mod_principal1/10000
if pay_way==2 and mod_principal2>0: total = mod_principal2/10000
row1=['息-{}'.format(i),round(month_pay1,2),round(month_principal1,2),round(month_interest1,2),round(sum_month_pay1,2), round(sum_month_principal1,2),abs(round(mod_principal1,2)),round(sum_month_interest1,2)]
row2=['金-{}'.format(i),round(month_pay2,2),round(month_principal2,2),round(month_interest2,2),round(sum_month_pay2,2), round(sum_month_principal2,2),abs(round(mod_principal2,2)),round(sum_month_interest2,2)]
if pay_way==1 :tb.add_row(row1)
if pay_way==2 :tb.add_row(row2)
if before_pay_dict.keys().__contains__(i): tb.add_row(["---", "---", "---","---","---","---","---","---"])
print(tb)
#提前还贷,保持月供,缩短剩余期数方式
def mainv2(sum_total,pay_month,pay_way,before_pay_dict=dict()):
titiles = ["期数", "月还款", "还款本金","还款利息","总还款","总还款本金","剩余还款本金","总还款利息"]
tb = PrettyTable(titiles)
for i in titiles:tb._align[i] = 'l'
sum_month_pay1 = 0 #总还款金额
sum_month_pay2 = 0
sum_month_principal1= 0 #总还款本金
sum_month_principal2 = 0
sum_month_interest1 = 0 #总还款利息
sum_month_interest2 = 0
mod_principal1 = sum_total * UNIT #剩余本金
mod_principal2 = sum_total * UNIT
remaining_pay_month = pay_month #提前还款后,从新计算的还款周期
remaining_periods = pay_month #剩余还款期数
total = sum_total
periods =0 #第n期
for i,_ in enumerate(range(1,pay_month+1),1):
periods += 1
remaining_periods -= 1
month_pay1 = get_month_pay(total,periods,remaining_pay_month,pay_way=1) #月供
month_pay2 = get_month_pay(total,periods,remaining_pay_month,pay_way=2)
month_interest1 = get_month_interest(total,periods,remaining_pay_month,pay_way=1) #利息
month_interest2 = get_month_interest(total,periods,remaining_pay_month,pay_way=2)
month_principal1 = get_month_principal(total,periods,remaining_pay_month,pay_way=1) #本金
month_principal2 = get_month_principal(total,periods,remaining_pay_month,pay_way=2)
sum_month_pay1 += month_pay1 #总还款数
sum_month_pay2 += month_pay2
sum_month_principal1 += month_principal1 #总还款本金
sum_month_principal2 += month_principal2
sum_month_interest1 += month_interest1 #总还款利息
sum_month_interest2 += month_interest2
mod_principal1 = (sum_total*UNIT) - sum_month_principal1 #剩余本金
mod_principal2 = (sum_total*UNIT) - sum_month_principal2
#提前还款
if before_pay_dict.keys().__contains__(i):
pay_money = before_pay_dict[i] #提前还款金额
month_principal1 += pay_money
month_principal2 += pay_money
sum_month_pay1 += pay_money
sum_month_pay2 += pay_money
sum_month_principal1 += pay_money
sum_month_principal2 += pay_money
mod_principal1 -= pay_money
mod_principal2 -= pay_money
periods = 0
# remaining_pay_month = pay_month - i
if pay_way==1 and mod_principal1>0: total = mod_principal1/10000
if pay_way==2 and mod_principal2>0: total = mod_principal2/10000
if pay_way==1:remaining_pay_month = get_month_periods1(mod_principal1,month_pay1)
if pay_way==2:remaining_pay_month = get_month_periods2(sum_total,mod_principal2,pay_month)
# print('remaining_pay_month=',remaining_pay_month,mod_principal1,mod_principal2)
remaining_periods = remaining_pay_month
row1=['息-{}'.format(i),round(month_pay1,2),round(month_principal1,2),round(month_interest1,2),round(sum_month_pay1,2), round(sum_month_principal1,2),abs(round(mod_principal1,2)),round(sum_month_interest1,2)]
row2=['金-{}'.format(i),round(month_pay2,2),round(month_principal2,2),round(month_interest2,2),round(sum_month_pay2,2), round(sum_month_principal2,2),abs(round(mod_principal2,2)),round(sum_month_interest2,2)]
if pay_way==1 :tb.add_row(row1)
if pay_way==2 :tb.add_row(row2)
if before_pay_dict.keys().__contains__(i): tb.add_row(["---", "---", "---","---","---","---","---","---"])
if remaining_periods==0:break #已全部还完
if pay_way==1 and mod_principal1<=0:break
if pay_way==2 and mod_principal2<=0:break
print(tb)
if __name__ == "__main__":
pay_way = 1 #还款方式:1为等额本息,2为等额本金
before_pay_dict={
4:10000, #提前还款期数:提前还款金额
5:30000,
8:80000,
}
mainv2(50,15,pay_way,before_pay_dict) #提前还款,月供不变,还款期数减少
main(50,15,pay_way,before_pay_dict) #提前还款,月供减少,还款期数不变