0
其实,网上已经有很多计算器了,比如新浪的计算器就算还能够过去,只是有两点
- 计算不够精确。其实这个不能够怪新浪的计算器。实际上每个银行在计算每年1月份利率调整的方法各不一样。比如这篇博客里面解释了工商银行的计算方式,而我按照他的计算方式去算结果总是会有一些偏差。
- 局限性。他只能够计算到3个利率变化的情况,一般5年以上的贷款利率变化很有可能超过3个。
我按照我自己的案例,写了以下脚本,去看农行是如何计算1月份的本息和的。结果发现,农行在计算一月份利息的时候是按照通用分段计息的方法,但是本金却是继续延续上一轮利率计算的本金。比如,12月份的剩余本金是10000块,那么1月份的本金是按照上一年的利率算,利息又是分段计算,然后加起来算出本息和。此后2月份就正常了。
反正每年1月份都是算的31天的利率,基本上1月份都要比平时还得多。
require 'date'
# 贷款总额
total_loan_money = 50 * 10000
# 贷款年限
total_loan_month = 20 * 12
# 初始利率
initial_interest_rate = 4.7
# 第一次还贷时间
initial_pay_dt = '2011-05-08'
# 利率调整时间表
interest_rate_changes = []
interest_rate_changes << [initial_pay_dt, initial_interest_rate]
interest_rate_changes << ['2012-01-01', 4.9]
interest_rate_changes << ['2013-01-01', 4.5]
interest_rate_changes << ['2015-01-01', 4.25]
interest_rate_changes << ['2016-01-01', 3.5]
p interest_rate_changes
def averageInterest(n, money, rate, ini_pay_dt)
list = []
money_to_pay_per_month = (money * rate * (1 + rate) ** n /((1 + rate) ** n - 1)).round(2)
n.times do |i|
remaining_load_money = (i==0) ? money : list[i-1][4]
interest_to_pay = (remaining_load_money * rate).round(2)
load_money_to_pay = (money_to_pay_per_month - interest_to_pay).round(2)
# [date, 本期利息,本期本金,本期本息,剩余本金]
list << [ini_pay_dt.strftime('%Y-%m-%d'), interest_to_pay, load_money_to_pay,
money_to_pay_per_month, (remaining_load_money - load_money_to_pay).round(2)]
ini_pay_dt = ini_pay_dt.next_month
end
list
end
def averageInterestAdjust(list, date, total_loan_month, rate1, rate2)
tmp_list = []
last_list = list[-2]
money = last_list[4]
rate1_per_day = rate1 / 30
rate2_per_day = rate2 / 30
ini_pay_dt = Date.parse(last_list[0])
rate1_days = date - ini_pay_dt
rate2_days = ini_pay_dt.next_month - date
# 本月利息
interest_to_pay = (money * (rate1_per_day * rate1_days +
rate2_per_day * rate2_days)).round(2)
# 本月应还金额
# 农业银行特色 应还本金还是按照上一年的利率计算的,但是利息是分段计算的
money_to_pay = (interest_to_pay + list[-1][2]).round(2)
tmp_list = [ini_pay_dt.strftime('%Y-%m-%d'), interest_to_pay,
(money_to_pay - interest_to_pay), money_to_pay,
money-(money_to_pay - interest_to_pay)]
list[-1][1] = tmp_list[1].round(2)
list[-1][2] = tmp_list[2].round(2)
list[-1][3] = tmp_list[3].round(2)
list[-1][4] = tmp_list[4].round(2)
list
end
list = []
i = 0
ini_pay_dt = Date.parse(initial_pay_dt)
interest_rate_changes.each do |t|
date = Date.parse(t[0])
if ini_pay_dt == date
i += 1
next
else
diff = (date.year - ini_pay_dt.year) * 12 + (date.month - ini_pay_dt.month)
end
list += averageInterest(total_loan_month, total_loan_money,
interest_rate_changes[i-1][1]/100.0/12.0, ini_pay_dt).slice(0, diff+1)
total_loan_month -= (diff)
# 每年1月1日利率调整,按日计息
list = averageInterestAdjust(list, date, total_loan_month,
interest_rate_changes[i-1][1]/100.0/12.0, interest_rate_changes[i][1]/100.0/12.0)
total_loan_month -= 1
ini_pay_dt = Date.parse(list[-1][0]).next_month
total_loan_money = list[-1][4]
i += 1
end
list += averageInterest(total_loan_month, total_loan_money,
interest_rate_changes[-1][1]/100.0/12.0, ini_pay_dt)
total_interest = 0
list.each do |t|
p t
total_interest += t[1]
end
puts total_interest
0
最近在玩ActiveRecord和Sql server,发现ActiveRecord居然支持preparedstatement了。但有些功能还是不能支持,比如NOT EXISTS和CROSS APPLY。
比如,下面这段SQL就没有办法转换成为ActiveRecord
只是有些接近的方法
生成的SQL实际上是
用到了LEFT JOIN,而不是EXISTS。不过,还好是prepared statement。
或者直接用SQL
实际上面生成的SQL就不是prepared过的了。这样就不好了,就不好的利用cache plan了。比起LEFT JOIN 引起的side effect,我更加倾向用LEFT JOIN方式,至少能够cache plan,不用每次compile。
比如,下面这段SQL就没有办法转换成为ActiveRecord
只是有些接近的方法
生成的SQL实际上是
用到了LEFT JOIN,而不是EXISTS。不过,还好是prepared statement。
或者直接用SQL
实际上面生成的SQL就不是prepared过的了。这样就不好了,就不好的利用cache plan了。比起LEFT JOIN 引起的side effect,我更加倾向用LEFT JOIN方式,至少能够cache plan,不用每次compile。