Source code for cashflows.bond

"""
Bond Valuation
===============================================================================

This module computes the present value or the yield-to-maturity of of the
expected cashflow of a bond. Also,it is possible to make a sensibility analysis
for different values for the yield-to-maturity and one present value of
the bond.

"""

from cashflows.tvmm import tvmm

[docs]def bond(face_value=None, coupon_rate=None, coupon_value=None, num_coupons=None, value=None, ytm=None): """ Evaluation of bond investments. Args: face_value (float): the bond's value-at-maturity. coupon_rate (float): rate for calculate the coupon payment. coupon_value (float): periodic payment. num_coupons (int): number of couont payments before maturity. value (float, list): present value of the bond ytm (float, list): yield-to-maturity. Returns: None, a float value, or a list of float values: * `value`: when `ytm` is specified. * `ytm`: when `value` is specified. * `None`: when `ytm` and `value` are specified. Prints a sensibility table. When `coupon_rate` is defined, `coupon_value` is calculated automaticly. Examples: >>> bond(face_value=1000, coupon_value=56, num_coupons=10, ytm=5.6) # doctest: +ELLIPSIS 1000.0... >>> bond(face_value=1000, coupon_rate=5.6, num_coupons=10, value=1000) # doctest: +ELLIPSIS 5.6... Also, it is possible to make sensibility analysis for bond's data. In the following case, the present value of the bond is calculated for various values of the yield-to-maturity. >>> bond(face_value=1000, coupon_rate=5.6, num_coupons=10, ... ytm=[4.0, 5.0, 5.6, 6.0, 7.0]) # doctest: +ELLIPSIS [1129.77..., 1046.33..., 1000.0..., 970.55..., 901.66...] And for different values: >>> bond(face_value=1000, coupon_rate=5.6, num_coupons=10, ... value=[900, 1000, 1100]) # doctest: +ELLIPSIS [7.0..., 5.6..., 4.3...] When values for the yield-to-maturity and one value for present value of the bond are supplied, the function prints a report. >>> bond(face_value=1000, coupon_rate=5.6, num_coupons=10, ... ytm=[4.0, 5.0, 5.6, 6.0, 7.0], value=1000) # doctest: +ELLIPSIS +NORMALIZE_WHITESPACE Bond valuation analysis Reference price: 1000 Analysis: Yield Value Change (%) ($) (%) ------------------------ 4.00 1129.77 12.98 5.00 1046.33 4.63 5.60 1000.00 0.00 6.00 970.56 -2.94 7.00 901.67 -9.83 """ if coupon_rate is None and coupon_value is None: raise ValueError('coupon_rate or coupon_value must be specified') if coupon_rate is None: coupon_rate = coupon_value / face_value if coupon_value is None: coupon_value = coupon_rate * face_value / 100 if value is None: value = tvmm(pmt=coupon_value, fval=face_value, nper=num_coupons, nrate=ytm, due=0, pyr=1) if isinstance(value, list): value = [-x for x in value] else: value = -value return value if ytm is None: if isinstance(value, list): value = [-x for x in value] else: value = -value return tvmm(pmt=coupon_value, fval=face_value, pval=value, nper=num_coupons, pyr=1) # # value and ytm are not None # sensibility analysis # values = tvmm(pmt=coupon_value, fval=face_value, nper=num_coupons, nrate=ytm, due=0, pyr=1) if isinstance(values, list): values = [-x for x in values] else: values = -values txt = ['Bond valuation analysis'] txt += ['Reference price: ' + value.__str__()] txt += ['Analysis:'] txt += [' Yield Value Change'] txt += [' (%) ($) (%)'] txt += [' ------------------------'] if not isinstance(ytm, list): ytm = [ytm] values = [values] for iytm, ivalue in zip(ytm, values): fmt = ' {:6.2f} {:9.2f} {:6.2f}' txt += [fmt.format(iytm, ivalue, 100 * (ivalue-value)/value)] print('\n'.join(txt))
if __name__ == "__main__": import doctest doctest.testmod()