Source code for pymbs.payment_rules
"""
PyMBS is a Python library for use in modeling Mortgage-Backed Securities.
Copyright (C) 2019 Brian Farrell
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Contact: brian.farrell@me.com
"""
from copy import copy
import decimal
from pymbs.config import config
from pymbs.utils import _parse_expression, PNT
dec = decimal.Decimal
d0 = dec('0')
cleanup = dec('1E-2')
[docs]def calculate(bucket, exp):
model = config.cache['model'] # noqa
group_id = config.cache['group_id'] # noqa
prepay_scenario = config.cache['prepay_scenario'] # noqa
payment = config.cache['payment'] # noqa
expression = _parse_expression(exp)
b = eval(expression)
if 'buckets' in payment._fields:
if payment.buckets[bucket]:
payment.buckets[bucket] += b
else:
payment.buckets[bucket] = b
else:
this_bucket = f"{bucket[0]}"
buckets = {this_bucket: b}
payment = PNT(*list(payment), buckets)
config.cache['payment'] = payment
[docs]def pay_accrual(bucket, tranche):
pass
[docs]def pay_accrue(tranche_ids):
tranches = config.cache['tranches']
for tranche in tranches:
tranche.pay_accrue()
[docs]def pay_pro_rata(bucket, tranches):
ctx = decimal.getcontext()
ctx.prec = config.precision
ctx.Emax = config.emax
ctx.Emin = config.emin
decimal.setcontext(ctx)
model = config.cache['model'] # noqa
group_id = config.cache['group_id'] # noqa
prepay_scenario = config.cache['prepay_scenario'] # noqa
payment = config.cache['payment']
current_payment = ctx.create_decimal(payment.buckets[bucket[0]])
orig_current_payment = copy(current_payment)
target_tranches = []
for tranche_id in tranches:
t = model['groups'][group_id]['tranches'][tranche_id]
target_tranches.append(t)
upb_sum = d0
for tranche in target_tranches:
upb_sum += tranche.upb
if upb_sum > d0:
for tranche in target_tranches:
tranche.pro_rated_ratio = tranche.upb / upb_sum
if (current_payment > d0 and upb_sum > d0):
for tranche in target_tranches:
projected_payment = \
orig_current_payment * tranche.pro_rated_ratio
actual_payment = min(
projected_payment,
tranche.upb,
current_payment,
)
tranche.pay_principal(actual_payment)
current_payment -= actual_payment
if current_payment < cleanup:
current_payment = d0
payment.buckets[bucket[0]] = current_payment
[docs]def pay_sequential(bucket, tranches):
ctx = decimal.getcontext()
ctx.prec = config.precision
ctx.Emax = config.emax
ctx.Emin = config.emin
decimal.setcontext(ctx)
model = config.cache['model'] # noqa
group_id = config.cache['group_id'] # noqa
prepay_scenario = config.cache['prepay_scenario'] # noqa
payment = config.cache['payment']
current_payment = ctx.create_decimal(payment.buckets[bucket[0]])
target_tranches = []
for tranche_id in tranches:
t = model['groups'][group_id]['tranches'][tranche_id]
target_tranches.append(t)
for tranche in target_tranches:
if (current_payment > d0 and tranche.upb > d0):
actual_payment = min(
current_payment,
tranche.upb,
)
tranche.pay_principal(actual_payment)
current_payment -= actual_payment
if current_payment < cleanup:
current_payment = d0
payment.buckets[bucket[0]] = current_payment
[docs]def pay_concurrent(bucket, tranches, ratios):
pass
[docs]def pay_to_schedule(bucket, tranches, schedule):
pass