def olb_p(q: float, period: float, term: float, gr: Union[Accumulation, float, Rate], t: float, r: float = None, missed: list = None) -> float: """ Calculates the outstanding loan balance using the retrospective method. :param q: The payment amount. :type q: float :param period: The payment period. :type period: float :param term: The loan term, in years. :type term: float :param gr: A growth rate object. :type gr: Accumulation, float, or Rate. :param t: The valuation time, in years. :type t: float :param r: The final payment amount, if different from the others, defaults to None. :type r: float, optional :param missed: A list of missed payments, for example, 4th and 5th payments would be [4, 5]. :type missed: list :return: The outstanding loan balance. :rtype: float """ acc = Accumulation(gr=gr) if r is not None: ann = Annuity(period=period, term=term - t - period, gr=gr, amount=q) r_pv = r * acc.discount_func(term - t) olb = ann.pv() + r_pv else: ann = Annuity(period=min(period, term - t), term=term - t, gr=gr, amount=q) olb = ann.pv() if missed: for p in missed: olb += q * acc.val(t - p) return olb
def npv_solver( npval: float = None, payments: list = None, gr: Union[Accumulation, float, Rate] = None ): """ An experimental net present value solver. Finds a missing component given a stream of payments and net present \ value. For example, if the NPV is absent, but the rest of the payments are fully defined, this function \ returns the NPV. If the NPV is provided, but one aspect of a payment (such as a payment value), this function \ is planned to solve for that value. This function is still incomplete, please use with caution. :param npval: The net present value. :type npval: float :param payments: A list of payments. :type payments: list :param gr: A growth rate object. :type gr: Callable :return: Returns either the npv, a missing payment amount, a missing time of payment, or missing discount factor. :rtype: float """ args = [npval, payments, gr] if args.count(None) > 1: raise Exception("Only one argument can be missing.") if gr: gr = standardize_rate(gr) acc = Accumulation(gr=gr) # exclude missing payment payments_excl_missing = [x for x in payments if x.time is not None] missing_pmt = [x for x in payments if x.time is None].pop() payments_excl_missing_npv = npv(payments=payments_excl_missing, gr=gr) missing_pmt_pv = npval - payments_excl_missing_npv res = np.log(missing_pmt.amount / missing_pmt_pv) / np.log(acc.discount_func(1) ** -1) return res