def runLoans(self, economy): if self.wavgRemTerm <= 0.1: self.realizedLosses = 0 self.principalPayments = self.loanUPB self.loanUPB = 0 self.interestIncome = 0 return self.realizedLosses = self.loanUPB * (self.wavgCDR + economy) / 400 self.loanUPB = self.loanUPB - self.realizedLosses self.interestIncome = self.loanUPB * self.wavgCoupon / 400 self.principalPayments = -np.ppmt( self.wavgCoupon / 1200, 60 - self.wavgRemTerm, 60, self.loanUPB) - np.ppmt( self.wavgCoupon / 1200, 60 - self.wavgRemTerm - 1, 60, self.loanUPB) - np.ppmt(self.wavgCoupon / 1200, 60 - self.wavgRemTerm - 2, 60, self.loanUPB) self.principalPayments += self.loanUPB * self.wavgCPR / 400 if self.loanUPB >= 0.1: if len(self.loanYield) <= 3: self.loanYield.append( (self.interestIncome - self.realizedLosses) / self.loanUPB) else: self.loanYield.popleft() self.loanYield.append( (self.interestIncome - self.realizedLosses) / self.loanUPB) self.wavgRemTerm -= 3 self.loanUPB = self.loanUPB - self.principalPayments
def test_broadcast(self): assert_almost_equal(np.nper(0.075, -2000, 0, 100000.0, [0, 1]), [21.5449442, 20.76156441], 4) assert_almost_equal( np.ipmt(0.1 / 12, list(range(5)), 24, 2000), [ -17.29165168, -16.66666667, -16.03647345, -15.40102862, -14.76028842 ], 4, ) assert_almost_equal( np.ppmt(0.1 / 12, list(range(5)), 24, 2000), [ -74.998201, -75.62318601, -76.25337923, -76.88882405, -77.52956425 ], 4, ) assert_almost_equal( np.ppmt(0.1 / 12, list(range(5)), 24, 2000, 0, [0, 0, 1, "end", "begin"]), [ -74.998201, -75.62318601, -75.62318601, -76.88882405, -76.88882405 ], 4, )
def CPM_calc(startdate, duration, principal, interest, term): start = datetime.strptime(startdate, '%Y-%m-%d') if (term == "y"): amortization = pd.DataFrame( index=pd.date_range(start, periods=duration + 1, freq="Y").shift(n=start.day, freq="D")) amortization["payback"] = 0 amortization["interest"] = 0 amortization["principal"] = 0 amortization.principal.iloc[1:amortization.shape[0]] = -np.ppmt( params["interest"], amortization.principal.iloc[1:amortization.shape[0]], params["duration"], params["principal"]) amortization.interest.iloc[1:amortization.shape[0]] = -np.ipmt( params["interest"], amortization.interest.iloc[1:amortization.shape[0]], params["duration"], params["principal"]) amortization.payback.iloc[1:amortization.shape[0]] = -np.pmt( interest, duration, principal) amortization.payback = amortization.apply(money_trim, axis=1) if (term == "q"): amortization = pd.DataFrame( index=pd.date_range(start, periods=duration * 4 + 1, freq="q").shift(n=start.day, freq="D")) amortization["payback"] = 0 amortization["interest"] = 0 amortization["principal"] = 0 amortization.principal.iloc[1:amortization.shape[0]] = -np.ppmt( params["interest"] / 4, amortization.principal.iloc[1:amortization.shape[0]], params["duration"] * 4, params["principal"]) amortization.interest.iloc[1:amortization.shape[0]] = -np.ipmt( params["interest"] / 4, amortization.interest.iloc[1:amortization.shape[0]], params["duration"] * 4, params["principal"]) amortization.payback.iloc[1:amortization.shape[0]] = -np.pmt( interest / 4, duration * 4, principal) amortization.payback = amortization.apply(money_trim, axis=1) if (term == "m"): amortization = pd.DataFrame( index=pd.date_range(start, periods=duration * 12 + 1, freq="M").shift(n=start.day, freq="D")) amortization["payback"] = 0 amortization["interest"] = 0 amortization["principal"] = 0 amortization.principal.iloc[1:amortization.shape[0]] = -np.ppmt( params["interest"] / 12, amortization.principal.iloc[1:amortization.shape[0]], params["duration"] * 12, params["principal"]) amortization.interest.iloc[1:amortization.shape[0]] = -np.ipmt( params["interest"] / 12, amortization.interest.iloc[1:amortization.shape[0]], params["duration"] * 12, params["principal"]) amortization.payback.iloc[1:amortization.shape[0]] = -np.pmt( interest / 12, duration * 12, principal) amortization.payback = amortization.apply(money_trim, axis=1) amortization = amortization.apply(money_trim, axis=0) return amortization
def test_broadcast_decimal(self): # Use almost equal because precision is tested in the explicit tests, this test is to ensure # broadcast with Decimal is not broken. assert_almost_equal( np.ipmt( Decimal("0.1") / Decimal("12"), list(range(5)), Decimal("24"), Decimal("2000"), ), [ Decimal("-17.29165168"), Decimal("-16.66666667"), Decimal("-16.03647345"), Decimal("-15.40102862"), Decimal("-14.76028842"), ], 4, ) assert_almost_equal( np.ppmt( Decimal("0.1") / Decimal("12"), list(range(5)), Decimal("24"), Decimal("2000"), ), [ Decimal("-74.998201"), Decimal("-75.62318601"), Decimal("-76.25337923"), Decimal("-76.88882405"), Decimal("-77.52956425"), ], 4, ) assert_almost_equal( np.ppmt( Decimal("0.1") / Decimal("12"), list(range(5)), Decimal("24"), Decimal("2000"), Decimal("0"), [Decimal("0"), Decimal("0"), Decimal("1"), "end", "begin"], ), [ Decimal("-74.998201"), Decimal("-75.62318601"), Decimal("-75.62318601"), Decimal("-76.88882405"), Decimal("-76.88882405"), ], 4, )
def test_broadcast_decimal(self): # Use almost equal because precision is tested in the explicit tests, this test is to ensure # broadcast with Decimal is not broken. assert_almost_equal(np.ipmt(Decimal('0.1') / Decimal('12'), list(range(5)), Decimal('24'), Decimal('2000')), [Decimal('-17.29165168'), Decimal('-16.66666667'), Decimal('-16.03647345'), Decimal('-15.40102862'), Decimal('-14.76028842')], 4) assert_almost_equal(np.ppmt(Decimal('0.1') / Decimal('12'), list(range(5)), Decimal('24'), Decimal('2000')), [Decimal('-74.998201'), Decimal('-75.62318601'), Decimal('-76.25337923'), Decimal('-76.88882405'), Decimal('-77.52956425')], 4) assert_almost_equal(np.ppmt(Decimal('0.1') / Decimal('12'), list(range(5)), Decimal('24'), Decimal('2000'), Decimal('0'), [Decimal('0'), Decimal('0'), Decimal('1'), 'end', 'begin']), [Decimal('-74.998201'), Decimal('-75.62318601'), Decimal('-75.62318601'), Decimal('-76.88882405'), Decimal('-76.88882405')], 4)
def raise_error_because_not_equal(): assert_equal( round( np.ppmt( Decimal('0.23') / Decimal('12'), 1, 60, Decimal('10000000000')), 8), Decimal('-90238044.232277036'))
def approve_application(application_id): ''' approve application''' application = Application.query.get(application_id) application.status = 3 db.session.add(application) loan = Loan( application=application, principal=application.amount, outstanding=application.amount, terms=application.terms, loan_date=datetime.utcnow(), borrower=application.borrower, guarantor=application.guarantor) db.session.add(loan) monthly_payment = -np.pmt(rate=loan.terms.rate/100, nper=loan.terms.installments, pv=loan.principal) for month in range(loan.terms.installments): ipmt = np.ipmt(rate=loan.terms.rate/100, per=month+1, nper=loan.terms.installments, pv=loan.principal) ppmt = np.ppmt(rate=loan.terms.rate/100, per=month+1, nper=loan.terms.installments, pv=loan.principal) payment = Payment( loan=loan, payment=Decimal(monthly_payment), principal_pmt=-ppmt, interest_pmt=-ipmt, scheduled_date=loan.loan_date + timedelta(days=30*(month+1))) db.session.add(payment) db.session.commit() flash('Application has been appproved.') return redirect(url_for('admin.pending_applications'))
def mortgage(price: int, downpayment: int, rate: float, term_years: int, interest_only=False) -> pd.DataFrame: principal = price - downpayment rate = rate / 12 term = term_years * 12 periods = np.arange(term) + 1 if not interest_only: full_payments = np.pmt(rate, term, principal) * np.ones_like(periods) principal_payments = np.ppmt(rate, periods, term, principal) interest_payments = np.ipmt(rate, periods, term, principal) else: full_payments = (principal * rate) * -np.ones_like(periods) principal_payments = np.zeros_like(periods) interest_payments = full_payments debt_balance = (principal + principal_payments.cumsum()).round(2) return pd.DataFrame( data=np.array([ debt_balance, full_payments, principal_payments, interest_payments ]).T, columns= 'debt_balance, full_payments, principal_payments, interest_payments'. split(', '), index=pd.date_range(start=datetime.date.today(), periods=term, freq='M'))
def edit_periods(ProjectNumber, delete=False): conn = sqlite3.connect('database.db') conn.row_factory = sqlite3.Row cur = conn.cursor() cur.execute("select StartDate, TypeNumber from LOAN_PROJECT where ProjectNumber = {}".format(ProjectNumber)) project = dict(cur.fetchone()) start_date = datetime.datetime.strptime(project['StartDate'], "%Y-%m-%d") cur.execute("select * from LOAN_PROJECT_TYPE where TypeNumber = {}".format(project['TypeNumber'])) project_type = dict(cur.fetchone()) temp = project_type['TotalPrinciple'] rate = project_type['InterestRate']/12 for period in range(project_type['NumberOfPeriod']): if delete: edit_data('LOAN_PERIOD', [ProjectNumber, period]) else: due = start_date + relativedelta(months=period+1) principle = np.ceil(-np.ppmt(rate=rate, per=1, nper=20-period, pv=temp)) interest = np.ceil(temp * rate) temp -= principle edit_data('LOAN_PERIOD', [ProjectNumber, period+1, due.strftime("%Y-%m-%d"), int(principle), int(interest)], from_project=True) conn.commit() conn.close() return
def calc_PPMT(df, dts_r, first_due_period): first_due_month = pd.unique(df[first_due_period].ravel()) df_ppmt = pd.DataFrame() for f_d_m in first_due_month: f_d_m_this_n_z = df[(df[first_due_period] == f_d_m) & (df['Total_Fee_Rate'] > 0)] for ind_r, date_r in enumerate(dts_r): #f_d_m_this_n_z[date_r] = 0 f_d_m_this_n_z[date_r] = f_d_m_this_n_z[date_r].where( (f_d_m_this_n_z[first_due_period] > ind_r) | (f_d_m_this_n_z['Term_Remain'] < (ind_r - f_d_m + 1)), np.ppmt(f_d_m_this_n_z['Total_Fee_Rate'] / 12, (ind_r - f_d_m + 1), f_d_m_this_n_z['Term_Remain'], ((-1) * f_d_m_this_n_z['OutstandingPrincipal']))) f_d_m_this_z = df[(df[first_due_period] == f_d_m) & (df['Total_Fee_Rate'] == 0)] for ind_r, date_r in enumerate(dts_r): #f_d_m_this_z[date_r] = 0 f_d_m_this_z[date_r] = f_d_m_this_z[date_r].where( (f_d_m_this_z[first_due_period] > ind_r) | (f_d_m_this_z['Term_Remain'] < (ind_r - f_d_m + 1)), f_d_m_this_z['OutstandingPrincipal'] / f_d_m_this_z['Term_Remain']) df_ppmt = df_ppmt.append(f_d_m_this_n_z).append(f_d_m_this_z, ignore_index=True) return df_ppmt
def calculate_return_specs(self): """ Calculate the necessary attributes for the loan repayment process. Each element is represented by a list of floats and contains the relevant annual values. """ sum_xreolisio = 0 for year in range(1, self.loan_period + 1): self.interest_rate_instalment.append( -np.pmt(self.annual_interest, self.loan_period, self.repayment_amount, 0)) self.interest_rate.append( -np.ppmt(self.annual_interest, year, self.loan_period, self.repayment_amount)) self.interest.append(self.interest_rate_instalment[year] - self.interest_rate[year]) if year == 1: self.interest_subsidy.append(self.repayment_amount * self.subsidized_interest) else: sum_xreolisio = sum_xreolisio + self.interest_rate[year - 1] endiameso = self.repayment_amount - sum_xreolisio self.interest_subsidy.append(endiameso * self.subsidized_interest) self.interest_paid.append(self.interest[year] - self.interest_subsidy[year]) self.unpaid.append(self.unpaid[year - 1] - self.interest_rate[year])
def index(): form = CalcForm() if form.validate_on_submit(): print(form.data) interest = (0 if form.interestrate.data is None else (form.interestrate.data * .01)) years = 30 payments_year = 12 mortgage = int(0 if form.homeprice.data is None else (form.homeprice.data)) downpayment = form.downpayment.data or 0 taxes = form.taxes.data or 0 tax = (taxes / 12) pmt = -1 * np.pmt(interest / 12, years * payments_year, mortgage - downpayment) + tax ipmt = -1 * np.ipmt(interest / payments_year, 1, years * payments_year, mortgage - downpayment) ppmt = -1 * np.ppmt(interest / payments_year, 1, years * payments_year, mortgage - downpayment) prin_int = ipmt + ppmt return render_template('index.html', form=form, prin_int=prin_int, pmt=pmt, tax=tax)
def amortizing_loan(principal=None, rate=None, years=None, amort_years=None, payment_acct=None, principal_acct=None, interest_acct=None): periods = np.arange(amort_years) + 1 amort_schedule = np.ppmt(rate, periods, amort_years, principal) * -1 int_schedule = np.ipmt(rate, periods, amort_years, principal) * -1 @assert_accounts(payment_acct, principal_acct) async def amortizing_loan_principal_cfs(clock, balances): yield principal, principal_acct, payment_acct, 'Initial loan' await clock.tick(years=1, days=-1) for period in range(years - 1): amortization_payment = amort_schedule[period] yield amortization_payment, payment_acct, principal_acct, 'Amortization payment' await clock.tick(years=1) amortization_payment = amort_schedule[period + 1] yield amortization_payment, payment_acct, principal_acct, 'Amortization payment' await clock.tick(days=1) yield balances[ principal_acct] * -1, payment_acct, principal_acct, 'Paydown' @assert_accounts(payment_acct, interest_acct) async def amortizing_loan_interest_cfs(clock, balances): await clock.tick(years=1, days=-1) for period in range(years): interest_payment = int_schedule[period] yield interest_payment, payment_acct, interest_acct, 'Interest payment' await clock.tick(years=1) yield amortizing_loan_principal_cfs yield amortizing_loan_interest_cfs
def test_broadcast(self): assert_almost_equal(np.nper(0.075,-2000,0,100000.,[0,1]), [ 21.5449442 , 20.76156441], 4) assert_almost_equal(np.ipmt(0.1/12,list(range(5)), 24, 2000), [-17.29165168, -16.66666667, -16.03647345, -15.40102862, -14.76028842], 4) assert_almost_equal(np.ppmt(0.1/12,list(range(5)), 24, 2000), [-74.998201 , -75.62318601, -76.25337923, -76.88882405, -77.52956425], 4) assert_almost_equal(np.ppmt(0.1/12,list(range(5)), 24, 2000, 0, [0,0,1,'end','begin']), [-74.998201 , -75.62318601, -75.62318601, -76.88882405, -76.88882405], 4)
def populate_base_mortgage_table( monthly_breakdown_dict, mortgage_base_table, ): """ Function populates the empy columns in a base mortgage equation in order with Monthly Paymenet, Interestes Paid at period x, principal paid at period x and the ending balance (or pending balance) at that particular perdiod. :param monthly_breakdown_dict: the dictionary with all the mortgage informaiton :param mortgage_base_table: :return: """ # Populating table with Formulas mortgage_base_table["Monthly_Payment"] = monthly_breakdown_dict[ "Monthly_Payment"] mortgage_base_table["Interests_Paid"] = -1 * np.ipmt( monthly_breakdown_dict["Interest_Rate"] / monthly_breakdown_dict["Payments_a_year"], mortgage_base_table.index, monthly_breakdown_dict["Mortgage_lifespan"] * monthly_breakdown_dict["Payments_a_year"], monthly_breakdown_dict["Mortgage_value"]) mortgage_base_table["Principal_Paid"] = -1 * np.ppmt( monthly_breakdown_dict["Interest_Rate"] / monthly_breakdown_dict["Payments_a_year"], mortgage_base_table.index, monthly_breakdown_dict["Mortgage_lifespan"] * monthly_breakdown_dict["Payments_a_year"], monthly_breakdown_dict["Mortgage_value"]) return mortgage_base_table
def __init__(self, logistic_cost, loan_rate, annual_interest, subsidized_interest, loan_period, grace_period): self.logistic_cost = logistic_cost #with taxes self.loan_rate = loan_rate self.annual_interest = annual_interest self.subsidized_interest = subsidized_interest self.loan_period = loan_period self.grace_period = grace_period self.own_funds_rate = 1 - self.loan_rate self.own_fund = self.logistic_cost*self.own_funds_rate self.loan_fund = self.loan_rate*self.logistic_cost if self.loan_period == 0: self.calculate_loan_period() self.grace_period_tokos = self.annual_interest*self.grace_period*self.loan_fund self.repayment_amount = self.loan_fund + self.grace_period_tokos #tok/ki dosi ana etos danismou self.interest_rate_instalment = [] self.interest_rate_instalment.append(0) #xreolisio ana etos danismou self.interest_rate = [] self.interest_rate.append(0) #tokos self.interest = [] self.interest.append(0) #epidotisi tokou self.interest_subsidy = [] self.interest_subsidy.append(0) #tokos pliroteos self.interest_paid = [] self.interest_paid.append(0) #aneksoflito ipolipo self.unpaid = [] self.unpaid.append(self.repayment_amount) sum_xreolisio = 0 for year in range(1, self.loan_period+1): self.interest_rate_instalment.append(-np.pmt(self.annual_interest, self.loan_period, self.repayment_amount, 0)) self.interest_rate.append(-np.ppmt(self.annual_interest, year, self.loan_period, self.repayment_amount)) self.interest.append(self.interest_rate_instalment[year] - self.interest_rate[year]) if year == 1: self.interest_subsidy.append(self.repayment_amount*self.subsidized_interest) else: sum_xreolisio = sum_xreolisio + self.interest_rate[year-1] endiameso = self.repayment_amount - sum_xreolisio self.interest_subsidy.append(endiameso*self.subsidized_interest) self.interest_paid.append(self.interest[year] - self.interest_subsidy[year]) self.unpaid.append(self.unpaid[year-1] - self.interest_rate[year])
def test_ppmt_decimal(self): assert_equal( np.ppmt( Decimal("0.1") / Decimal("12"), Decimal("1"), Decimal("60"), Decimal("55000"), ), Decimal("-710.2541257864217612489830917"), )
def raise_error_because_not_equal(): assert_equal( round( np.ppmt( Decimal("0.23") / Decimal("12"), 1, 60, Decimal("10000000000")), 8, ), Decimal("-90238044.232277036"), )
def calc_int_n_pcp_payment(self, period, additional_payment=0): ipmt = np.ipmt(rate=self.rate/self.maturity, per=period, nper=self.payment_per_year*self.maturity, pv=self.principal) ppmt = np.ppmt(rate=self.rate/self.maturity, per=period, nper=self.payment_per_year*self.maturity, pv=self.principal) return round(ipmt, 2), round(ppmt, 2)
def average_capital_plus_interest(PV,mouth_rate,nper,Sum_interest=0): for i in range(1, nper + 1): PPMT = np.ppmt(mouth_rate, i, nper, PV) IPMT = np.ipmt(mouth_rate, i, nper, PV) EIR=mouth_rate*12 #有效年化利率 PMT = PPMT + IPMT Sum_interest+=IPMT yield i,round(-PPMT,1),round(-IPMT,1),round(-PMT,1) if i == nper: yield "总利息:"+str(round(-Sum_interest,1)),"实际利率:"+str("%.2f%%" % (EIR * 100))
def calculate(self): """Calculated annuitet values @percent_payments = dict with sum we need to pay at current period - for percent of loan @debt_payments = dict with sum we need to pay at current period - for body of loan @rest_payments = dict with sum, we still need to pay in next periods """ from numpy import ppmt, ipmt, arange periods = arange(self.mperiods) + 1 principal_repayments = ppmt(rate=self.rate, per=periods, nper=self.mperiods, pv=self.summa) interest_payments = ipmt(rate=self.rate, per=periods, nper=self.mperiods, pv=self.summa) date = self.start_date percent_payment = 0 # (self.summa * self.yrate / 12) debt_payment = 0 rest_payment = self.summa + abs(interest_payments.sum()) rest_payment_wo_percent = self.summa percent_payments = OrderedDict({date: percent_payment}) debt_payments = OrderedDict({date: debt_payment}) rest_payments = OrderedDict({date: rest_payment}) rest_payments_wo_percents = OrderedDict( {date: rest_payment_wo_percent}) for i in range(self.mperiods): date = lastDayNextMonth(date) percent_payment = interest_payments[i] debt_payment = principal_repayments[i] rest_payment -= abs(percent_payment) + abs(debt_payment) rest_payment_wo_percent -= abs(debt_payment) if rest_payment < 0.01: rest_payment = 0 if rest_payment_wo_percent < 0.01: rest_payment_wo_percent = 0 percent_payments[date] = percent_payment debt_payments[date] = debt_payment rest_payments[date] = rest_payment rest_payments_wo_percents[date] = rest_payment_wo_percent self.percent_payments = percent_payments self.debt_payments = debt_payments self.rest_payments = rest_payments self.rest_payments_wo_percents = rest_payments_wo_percents
def get_equity(n): k = 0 equity_accrued = [] for per in range(nper): if per != 0 and per % 12 == 0: nv = pv * (1.07)**(per / 12) equity_accrued += [nv * k / pv] p = -np.ppmt(rate, per, nper, pv) k += p return equity_accrued[n]
def test_ppmt_special_rate_decimal(self): # When rounded out to 8 decimal places like the float based test, this should not equal the same value # as the float, substituted for the decimal def raise_error_because_not_equal(): assert_equal( round(np.ppmt(Decimal('0.23') / Decimal('12'), 1, 60, Decimal('10000000000')), 8), Decimal('-90238044.232277036')) assert_raises(AssertionError, raise_error_because_not_equal) assert_equal(np.ppmt(Decimal('0.23') / Decimal('12'), 1, 60, Decimal('10000000000')), Decimal('-90238044.2322778884413969909'))
def _calculate_principal_schedule(self): if self.tenor == 0: self.principal_schedule = [] elif self.rate == 0: num_periods = len(self.loan_periods) self.principal_schedule = [self.principal / num_periods ] * num_periods else: self.principal_schedule = -np.ppmt( self.rate / 12, self.loan_periods, self.tenor * 12, self.principal)
def average_capital_plus_interest_by_actualInterest(PV,mouth_rate,nper): year_actual_Interest=mouth_rate*PV*nper FV=PV+year_actual_Interest PMT=FV/nper EIR=np.rate(nper,-PMT,PV,0)*12 actual_mouth_rate=EIR/12 for i in range(1, nper + 1): PPMT = np.ppmt(actual_mouth_rate, i, nper, PV) IPMT = np.ipmt(actual_mouth_rate, i, nper, PV) yield i,-PPMT,-IPMT,PMT if i == nper: yield year_actual_Interest,round(EIR,4)
def mort_pmt(df, purchase_date_eom): #Loops through each region ID purchase_date_eom = pd.to_datetime(purchase_date_eom) for i in region_list: df_region = df[df['RegionID'] == i].reset_index() df_region = df_region[df_region['date'] >= purchase_date_eom] #Skips region if data not available beginning on given purchase date if df_region['date'].iloc[0] != purchase_date_eom: continue else: #Calculate mortgage related components (period, principal, interest, remaining balance) #Dynamic scalar values purch_price = df_region[ 'Neighborhood_Zhvi_SingleFamilyResidence'].iloc[0] mort_rate = df_region['mort_rate'].iloc[ 0] #Consider adding some refinancing feature mort_amt = (purch_price * (1 - DOWN_PMT)) #Rolling columns for key mortgage components (period, interest, principal) df_region.loc[:, 'period'] = np.arange(1, len(df_region) + 1, 1) df_region.loc[:, 'prin_pmt'] = np.ppmt(mort_rate / 12, df_region['period'], YEARS * 12, mort_amt) df_region.loc[:, 'int_pmt'] = np.ipmt(mort_rate / 12, df_region['period'], YEARS * 12, mort_amt) df_region.loc[:, 'cum_prin'] = df_region['prin_pmt'].cumsum() #Ensures balance doesn't go above loan amt df_region.loc[:, 'cum_prin'] = df_region['cum_prin'].clip( lower=-mort_amt) df_region.loc[:, 'mort_balance'] = mort_amt + df_region['cum_prin'] #Calculate depreciation and after-sale taxes df_region.loc[:, 'cum_deprec'] = ( purch_price / (-27.5 * 12) ) * df_region['period'] #Depreciation limit set at 27.5 years #Ensures principal, interest payments go to zero when paid and depreciation doesn't exceed purchase price df_region.loc[:, 'cum_deprec'] = np.where( df_region['cum_deprec'] <= -purch_price, -purch_price, df_region['cum_deprec']) df_region.loc[:, 'prin_pmt'] = np.where( df_region['mort_balance'].shift(1) == 0, 0, df_region['prin_pmt']) df_region.loc[:, 'int_pmt'] = np.where( df_region['mort_balance'].shift(1) == 0, 0, df_region['int_pmt']) #Filters out relevant columns df_region.loc[:, 'book_value'] = purch_price + df_region['cum_deprec'] df_region = df_region[[ 'date', 'RegionID', 'period', 'prin_pmt', 'int_pmt', 'cum_prin', 'mort_balance', 'cum_deprec', 'book_value' ]] mort_df_list.append(df_region)
def add_oleary_amortization_info(self): """Calculate monthly principal and interest payment. Use those to calculate the accumulated principle at a given time""" self.oleary_df['oleary_principal_payment'] = np.ppmt( self.c.oleary_rate / 12, self.oleary_df.index, self.c.oleary_payment_years * 12, self.c.oleary_principal) self.oleary_df['oleary_interest_payment'] = np.ipmt( self.c.oleary_rate / 12, self.oleary_df.index, self.c.oleary_payment_years * 12, self.c.oleary_principal) self.oleary_df['oleary_cumulative_principal'] = self.oleary_df[ 'oleary_principal_payment'].abs().cumsum()
def add_castle_amortization_info(self): """Calculate monthly principal and interest payment for the new 'Castle' we are buying. Use those to calculate the accumulated principle at a given time""" self.main_df['castle_principal_payment'] = np.ppmt( self.c.castle_rate / 12, self.main_df.index, self.c.castle_payment_years * 12, self.c.castle_principal) self.main_df['castle_interest_payment'] = np.ipmt( self.c.castle_rate / 12, self.main_df.index, self.c.castle_payment_years * 12, self.c.castle_principal) self.main_df['castle_cumulative_principal'] = self.main_df[ 'castle_principal_payment'].abs().cumsum()
def xPPMT(rate=0, per=0, nper=0, pv=0, fv=0, type1=0): # 一直用等额本金 默认0 per = check_value(type(per))(per) if per == 0: return 0 rate = check_value(type(rate))(rate) nper = check_value(type(nper))(nper) pv = check_value(type(pv))(pv) fv = check_value(type(fv))(fv) try: a = numpy.ppmt(rate, per, nper, pv, fv) except: a = 0 return a
def get_p(n): fv = 0 running_pri_total = 0 principal = [] for per in range(nper): if per != 0 and per % 12 == 0: principal += [running_pri_total] running_pri_total = 0 p = -np.ppmt(rate, per, nper, pv) running_pri_total += p return principal(n)
def average_capital_plus_interest(PV,mouth_rate,nper,Sum_interest=0,returned_capital=0): for i in range(1, nper + 1): PPMT = -np.ppmt(mouth_rate, i, nper, PV) IPMT = -np.ipmt(mouth_rate, i, nper, PV) EIR=mouth_rate*12 #有效年化率 PMT = PPMT + IPMT Sum_interest+=IPMT returned_capital+= PPMT # 求出已还本金 left_capital=PV-returned_capital #求出剩余本金 actual_mouth_rate = IPMT / (left_capital+PPMT) #求出月利率 Sum_money=PV+Sum_interest yield '第'+str(i)+'期',round(PPMT,1),round(IPMT,1),round(PMT,1),round(left_capital,1),"%.2f%%" % (actual_mouth_rate * 100) if i == nper: yield "还款总额:"+str(round(Sum_money,1)),"总利息:"+str(round(Sum_interest,1)),"年利率:"+str("%.2f%%" % (EIR * 100))
def test_when(self): # begin assert_almost_equal(np.rate(10, 20, -3500, 10000, 1), np.rate(10, 20, -3500, 10000, "begin"), 4) # end assert_almost_equal(np.rate(10, 20, -3500, 10000), np.rate(10, 20, -3500, 10000, "end"), 4) assert_almost_equal(np.rate(10, 20, -3500, 10000, 0), np.rate(10, 20, -3500, 10000, "end"), 4) # begin assert_almost_equal(np.pv(0.07, 20, 12000, 0, 1), np.pv(0.07, 20, 12000, 0, "begin"), 2) # end assert_almost_equal(np.pv(0.07, 20, 12000, 0), np.pv(0.07, 20, 12000, 0, "end"), 2) assert_almost_equal(np.pv(0.07, 20, 12000, 0, 0), np.pv(0.07, 20, 12000, 0, "end"), 2) # begin assert_almost_equal(np.fv(0.075, 20, -2000, 0, 1), np.fv(0.075, 20, -2000, 0, "begin"), 4) # end assert_almost_equal(np.fv(0.075, 20, -2000, 0), np.fv(0.075, 20, -2000, 0, "end"), 4) assert_almost_equal(np.fv(0.075, 20, -2000, 0, 0), np.fv(0.075, 20, -2000, 0, "end"), 4) # begin assert_almost_equal(np.pmt(0.08 / 12, 5 * 12, 15000.0, 0, 1), np.pmt(0.08 / 12, 5 * 12, 15000.0, 0, "begin"), 4) # end assert_almost_equal(np.pmt(0.08 / 12, 5 * 12, 15000.0, 0), np.pmt(0.08 / 12, 5 * 12, 15000.0, 0, "end"), 4) assert_almost_equal(np.pmt(0.08 / 12, 5 * 12, 15000.0, 0, 0), np.pmt(0.08 / 12, 5 * 12, 15000.0, 0, "end"), 4) # begin assert_almost_equal(np.ppmt(0.1 / 12, 1, 60, 55000, 0, 1), np.ppmt(0.1 / 12, 1, 60, 55000, 0, "begin"), 4) # end assert_almost_equal(np.ppmt(0.1 / 12, 1, 60, 55000, 0), np.ppmt(0.1 / 12, 1, 60, 55000, 0, "end"), 4) assert_almost_equal(np.ppmt(0.1 / 12, 1, 60, 55000, 0, 0), np.ppmt(0.1 / 12, 1, 60, 55000, 0, "end"), 4) # begin assert_almost_equal(np.ipmt(0.1 / 12, 1, 24, 2000, 0, 1), np.ipmt(0.1 / 12, 1, 24, 2000, 0, "begin"), 4) # end assert_almost_equal(np.ipmt(0.1 / 12, 1, 24, 2000, 0), np.ipmt(0.1 / 12, 1, 24, 2000, 0, "end"), 4) assert_almost_equal(np.ipmt(0.1 / 12, 1, 24, 2000, 0, 0), np.ipmt(0.1 / 12, 1, 24, 2000, 0, "end"), 4) # begin assert_almost_equal(np.nper(0.075, -2000, 0, 100000.0, 1), np.nper(0.075, -2000, 0, 100000.0, "begin"), 4) # end assert_almost_equal(np.nper(0.075, -2000, 0, 100000.0), np.nper(0.075, -2000, 0, 100000.0, "end"), 4) assert_almost_equal(np.nper(0.075, -2000, 0, 100000.0, 0), np.nper(0.075, -2000, 0, 100000.0, "end"), 4)
def test_ppmt_special_rate(self): assert_equal(np.round(np.ppmt(0.23 / 12, 1, 60, 10000000000), 8), -90238044.232277036)
def test_ppmt_decimal(self): assert_equal(np.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('60'), Decimal('55000')), Decimal('-710.2541257864217612489830917'))
def test_ppmt(self): assert_equal(np.round(np.ppmt(0.1 / 12, 1, 60, 55000), 2), -710.25)
def test_decimal_with_when(self): """Test that decimals are still supported if the when argument is passed""" # begin assert_equal(np.rate(Decimal('10'), Decimal('20'), Decimal('-3500'), Decimal('10000'), Decimal('1')), np.rate(Decimal('10'), Decimal('20'), Decimal('-3500'), Decimal('10000'), 'begin')) # end assert_equal(np.rate(Decimal('10'), Decimal('20'), Decimal('-3500'), Decimal('10000')), np.rate(Decimal('10'), Decimal('20'), Decimal('-3500'), Decimal('10000'), 'end')) assert_equal(np.rate(Decimal('10'), Decimal('20'), Decimal('-3500'), Decimal('10000'), Decimal('0')), np.rate(Decimal('10'), Decimal('20'), Decimal('-3500'), Decimal('10000'), 'end')) # begin assert_equal(np.pv(Decimal('0.07'), Decimal('20'), Decimal('12000'), Decimal('0'), Decimal('1')), np.pv(Decimal('0.07'), Decimal('20'), Decimal('12000'), Decimal('0'), 'begin')) # end assert_equal(np.pv(Decimal('0.07'), Decimal('20'), Decimal('12000'), Decimal('0')), np.pv(Decimal('0.07'), Decimal('20'), Decimal('12000'), Decimal('0'), 'end')) assert_equal(np.pv(Decimal('0.07'), Decimal('20'), Decimal('12000'), Decimal('0'), Decimal('0')), np.pv(Decimal('0.07'), Decimal('20'), Decimal('12000'), Decimal('0'), 'end')) # begin assert_equal(np.fv(Decimal('0.075'), Decimal('20'), Decimal('-2000'), Decimal('0'), Decimal('1')), np.fv(Decimal('0.075'), Decimal('20'), Decimal('-2000'), Decimal('0'), 'begin')) # end assert_equal(np.fv(Decimal('0.075'), Decimal('20'), Decimal('-2000'), Decimal('0')), np.fv(Decimal('0.075'), Decimal('20'), Decimal('-2000'), Decimal('0'), 'end')) assert_equal(np.fv(Decimal('0.075'), Decimal('20'), Decimal('-2000'), Decimal('0'), Decimal('0')), np.fv(Decimal('0.075'), Decimal('20'), Decimal('-2000'), Decimal('0'), 'end')) # begin assert_equal(np.pmt(Decimal('0.08') / Decimal('12'), Decimal('5') * Decimal('12'), Decimal('15000.'), Decimal('0'), Decimal('1')), np.pmt(Decimal('0.08') / Decimal('12'), Decimal('5') * Decimal('12'), Decimal('15000.'), Decimal('0'), 'begin')) # end assert_equal(np.pmt(Decimal('0.08') / Decimal('12'), Decimal('5') * Decimal('12'), Decimal('15000.'), Decimal('0')), np.pmt(Decimal('0.08') / Decimal('12'), Decimal('5') * Decimal('12'), Decimal('15000.'), Decimal('0'), 'end')) assert_equal(np.pmt(Decimal('0.08') / Decimal('12'), Decimal('5') * Decimal('12'), Decimal('15000.'), Decimal('0'), Decimal('0')), np.pmt(Decimal('0.08') / Decimal('12'), Decimal('5') * Decimal('12'), Decimal('15000.'), Decimal('0'), 'end')) # begin assert_equal(np.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('60'), Decimal('55000'), Decimal('0'), Decimal('1')), np.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('60'), Decimal('55000'), Decimal('0'), 'begin')) # end assert_equal(np.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('60'), Decimal('55000'), Decimal('0')), np.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('60'), Decimal('55000'), Decimal('0'), 'end')) assert_equal(np.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('60'), Decimal('55000'), Decimal('0'), Decimal('0')), np.ppmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('60'), Decimal('55000'), Decimal('0'), 'end')) # begin assert_equal(np.ipmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('24'), Decimal('2000'), Decimal('0'), Decimal('1')).flat[0], np.ipmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('24'), Decimal('2000'), Decimal('0'), 'begin').flat[0]) # end assert_equal(np.ipmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('24'), Decimal('2000'), Decimal('0')).flat[0], np.ipmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('24'), Decimal('2000'), Decimal('0'), 'end').flat[0]) assert_equal(np.ipmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('24'), Decimal('2000'), Decimal('0'), Decimal('0')).flat[0], np.ipmt(Decimal('0.1') / Decimal('12'), Decimal('1'), Decimal('24'), Decimal('2000'), Decimal('0'), 'end').flat[0])
def test_when(self): # begin assert_equal(np.rate(10, 20, -3500, 10000, 1), np.rate(10, 20, -3500, 10000, 'begin')) # end assert_equal(np.rate(10, 20, -3500, 10000), np.rate(10, 20, -3500, 10000, 'end')) assert_equal(np.rate(10, 20, -3500, 10000, 0), np.rate(10, 20, -3500, 10000, 'end')) # begin assert_equal(np.pv(0.07, 20, 12000, 0, 1), np.pv(0.07, 20, 12000, 0, 'begin')) # end assert_equal(np.pv(0.07, 20, 12000, 0), np.pv(0.07, 20, 12000, 0, 'end')) assert_equal(np.pv(0.07, 20, 12000, 0, 0), np.pv(0.07, 20, 12000, 0, 'end')) # begin assert_equal(np.fv(0.075, 20, -2000, 0, 1), np.fv(0.075, 20, -2000, 0, 'begin')) # end assert_equal(np.fv(0.075, 20, -2000, 0), np.fv(0.075, 20, -2000, 0, 'end')) assert_equal(np.fv(0.075, 20, -2000, 0, 0), np.fv(0.075, 20, -2000, 0, 'end')) # begin assert_equal(np.pmt(0.08 / 12, 5 * 12, 15000., 0, 1), np.pmt(0.08 / 12, 5 * 12, 15000., 0, 'begin')) # end assert_equal(np.pmt(0.08 / 12, 5 * 12, 15000., 0), np.pmt(0.08 / 12, 5 * 12, 15000., 0, 'end')) assert_equal(np.pmt(0.08 / 12, 5 * 12, 15000., 0, 0), np.pmt(0.08 / 12, 5 * 12, 15000., 0, 'end')) # begin assert_equal(np.ppmt(0.1 / 12, 1, 60, 55000, 0, 1), np.ppmt(0.1 / 12, 1, 60, 55000, 0, 'begin')) # end assert_equal(np.ppmt(0.1 / 12, 1, 60, 55000, 0), np.ppmt(0.1 / 12, 1, 60, 55000, 0, 'end')) assert_equal(np.ppmt(0.1 / 12, 1, 60, 55000, 0, 0), np.ppmt(0.1 / 12, 1, 60, 55000, 0, 'end')) # begin assert_equal(np.ipmt(0.1 / 12, 1, 24, 2000, 0, 1), np.ipmt(0.1 / 12, 1, 24, 2000, 0, 'begin')) # end assert_equal(np.ipmt(0.1 / 12, 1, 24, 2000, 0), np.ipmt(0.1 / 12, 1, 24, 2000, 0, 'end')) assert_equal(np.ipmt(0.1 / 12, 1, 24, 2000, 0, 0), np.ipmt(0.1 / 12, 1, 24, 2000, 0, 'end')) # begin assert_equal(np.nper(0.075, -2000, 0, 100000., 1), np.nper(0.075, -2000, 0, 100000., 'begin')) # end assert_equal(np.nper(0.075, -2000, 0, 100000.), np.nper(0.075, -2000, 0, 100000., 'end')) assert_equal(np.nper(0.075, -2000, 0, 100000., 0), np.nper(0.075, -2000, 0, 100000., 'end'))
def raise_error_because_not_equal(): assert_equal( round(np.ppmt(Decimal('0.23') / Decimal('12'), 1, 60, Decimal('10000000000')), 8), Decimal('-90238044.232277036'))
'default': 'ls_default'} df = df.rename(columns=rename_dict) df = df.rename(columns=purpose_dict) # identify good loans and bad loans (might include the 31 to 120 day late category later) df.loc[df['ls_default'] == 1, 'bad_loan'] = 1 df.loc[df['ls_chargeoff'] == 1, 'bad_loan'] = 1 df.loc[df['bad_loan'] != 1, 'bad_loan'] = 0 df.loc[df['bad_loan'] != 1, 'good_loan'] = 1 df.loc[df['good_loan'] != 1, 'good_loan'] = 0 # add columns related to debt service and debt service coverage # calculate annual debt service payments for Lending Club loans df['annual_prin'] = sum([np.ppmt(df['int_rate'] / 12, i, df['term'], -df['loan_amnt'], 0) for i in range(1, 13)]) df['annual_prin'] = df['annual_prin'].round(2) df['annual_int'] = sum([np.ipmt(df['int_rate'] / 12, i, df['term'], -df['loan_amnt'], 0) for i in range(1, 13)]) df['annual_int'] = df['annual_int'].round(2) df['annual_debt_svc'] = df['annual_prin'] + df['annual_int'] df['annual_debt_svc'] = df['annual_debt_svc'].round(2) # total revolving debt NOT attributable to Lending Club loans df['other_rev_debt'] = df['total_bal_ex_mort'] - df['out_prncp'] df.loc[df['other_rev_debt'] < 0, 'other_rev_debt'] = 0 # total mortgage/installment debt (also not Lending Club) df['other_mort_debt'] = df['tot_cur_bal'] - df['other_rev_debt'] df.loc[df['other_mort_debt'] < 0, 'other_mort_debt'] = 0 # estimated annual debt service requirement on non-Lending-Club revolving debt (at Lending Club int_rate, 5yr amort)
def test_ppmt(self): np.round(np.ppmt(0.1/12,1,60,55000),2) == 710.25
def cashflows(self): """ Construct a dataframe with projections of balances and cashflows for a loan portfolio in an homogeneous loan pool, where the loans share the same origination period. :rtype: pandas dataframe """ loss_rates = self._credit_model.get('loss') nonperforming_rates = self._credit_model.get('nonperforming') provision_rates = self._credit_model.get('provision') prepayment_rates = self._prepayment_vector rates = self._rates_vector index_to_apply = list(range(self.origination_month(), self.origination_month() + self._nper + 1)) ans_df = pd.DataFrame(0., index = index_to_apply, columns = ('saldo_inicial', 'desembolsos', 'amortizacion', 'prepago', 'castigo', 'saldo_final', 'interes', 'improductiva', 'saldo_provision')) ans_df.loc[self.origination_month()] = [0, self._origination, 0, 0, 0, self._origination, 0, 0, self._origination * provision_rates[0]] rounding = 6 min_balance = 0.01 initial_balance = self._origination for payment in range(self._nper): index = payment + self.origination_month() loss = np.round(initial_balance * loss_rates[payment], rounding) prepayment = np.round(initial_balance * prepayment_rates[payment], rounding) nonperforming = np.round(initial_balance * nonperforming_rates[payment], rounding) provision = np.round((provision_rates[payment] * (initial_balance - nonperforming)) + nonperforming, rounding) ipmt = np.round((initial_balance - nonperforming) * rates[payment], rounding) contractual_ppmt = np.round(-(np.ppmt(rates[payment], payment + 1, self._nper, self._origination)), rounding) if contractual_ppmt > (initial_balance - prepayment - loss): ppmt = np.round(initial_balance - prepayment - loss, rounding) else: ppmt = contractual_ppmt ending_balance = np.round(initial_balance - ppmt - prepayment - loss, rounding) if ending_balance < min_balance: ending_balance = 0. origination = np.round(0., rounding) ans_df.loc[index + 1] = [initial_balance, origination, ppmt, prepayment, loss, ending_balance, ipmt, nonperforming, provision] initial_balance = ending_balance return ans_df