sonntagsgesicht/shortrate

View on GitHub
shortrate/market_risk_factor.py

Summary

Maintainability
A
3 hrs
Test Coverage
# -*- coding: utf-8 -*-

# shortrate
# ---------
# risk factor model library python style.
#
# Author:   sonntagsgesicht, based on a fork of Deutsche Postbank [pbrisk]
# Version:  0.3, copyright Wednesday, 18 September 2019
# Website:  https://github.com/sonntagsgesicht/shortrate
# License:  Apache License 2.0 (see LICENSE file)


from scipy import integrate

from dcf import DateCurve, ZeroRateCurve, Price, FxRate

from .risk_factor_model import RiskFactorModel
from timewave import TimeDependentWienerProcess, TimeDependentGeometricBrownianMotion


class GaussRiskFactorModel(RiskFactorModel, TimeDependentWienerProcess):
    """ risk factor modeled as `timewave.TimeDependentWienerProcess` """
    @property
    def drift(self):
        return self._mu

    @property
    def volatility(self):
        return self._sigma

    def __init__(self, inner_factor, mu=0.0, sigma=0.0, time=.0027378507871321013, start=0.0):
        # super(GaussRiskFactorModel, self).__init__()
        RiskFactorModel.__init__(self, inner_factor=inner_factor, start=start)
        TimeDependentWienerProcess.__init__(self, mu=mu, sigma=sigma, time=time, start=start)

        # re-init RiskFactor properties due to funny calls of __init__ in __mro__
        self._inner_factor = inner_factor
        self._factor_value = self.start
        self._factor_date = self._initial_factor_date

    # TimeDependentWienerProcess methods

    def _integrate(self, f, s, e):
        result, _ = integrate.quad(f, s, e)
        return result


class GeometricBrownianMotionRiskFactorModel(GaussRiskFactorModel, TimeDependentGeometricBrownianMotion):
    """ risk factor modeled as `timewave.TimeDependentGeometricBrownianMotion` """
    pass


class GeometricBrownianMotionPriceFactorModel(Price, GeometricBrownianMotionRiskFactorModel):
    """ risk factor modeled as |GeometricBrownianMotionRiskFactorModel| """
    @property
    def value(self):
        return self._factor_value

    @property
    def origin(self):
        return self._factor_date

    def __init__(self, inner_factor, drift=0.0, volatility=0.0):
        Price.__init__(self, inner_factor.value, inner_factor.origin)
        GeometricBrownianMotionRiskFactorModel.__init__(self, inner_factor, drift, volatility, start=inner_factor.value)


class GeometricBrownianMotionPrice(GeometricBrownianMotionPriceFactorModel):
    def __init__(self, value=0.0, origin=None, day_count=None, drift=0.0, volatility=0.0):
        inner_factor = Price(value, origin)
        super(GeometricBrownianMotionPrice, self).__init__(inner_factor, drift, volatility)


class GeometricBrownianMotionFxRateFactorModel(FxRate, GeometricBrownianMotionRiskFactorModel):

    @property
    def value(self):
        return self._factor_value

    @property
    def origin(self):
        return self._factor_date

    def __init__(self, inner_factor, domestic_curve=None, foreign_curve=None, volatility=0.0):
        domestic_curve = ZeroRateCurve([inner_factor.origin], [0.]) if domestic_curve is None else domestic_curve
        foreign_curve = domestic_curve if foreign_curve is None else foreign_curve

        diff_curve = foreign_curve.cast(ZeroRateCurve) - domestic_curve.cast(ZeroRateCurve)
        domain = diff_curve.domain
        data = list(diff_curve.derivative(d) for d in domain)
        drift = DateCurve(domain, data, origin=inner_factor.origin, day_count=domestic_curve.day_count).to_curve()

        FxRate.__init__(self, inner_factor.value, inner_factor.origin)
        GeometricBrownianMotionRiskFactorModel.__init__(self, inner_factor, drift, volatility, start=inner_factor.value)


class GeometricBrownianMotionFxRate(GeometricBrownianMotionFxRateFactorModel):
    def __init__(self, value=1.0, origin=None, day_count=None, domestic_curve=None, foreign_curve=None, volatility=0.0):
        inner_factor = FxRate(value, origin)
        super(GeometricBrownianMotionFxRate, self).__init__(inner_factor, domestic_curve, foreign_curve, volatility)


class GaussFlatSpreadZeroRateCurveFactorModel(ZeroRateCurve, GaussRiskFactorModel):
    def __init__(self, inner_factor, drift=0.0, volatility=0.0):
        GaussRiskFactorModel.__init__(self, inner_factor, drift, volatility, start=0.0)
        ZeroRateCurve.__init__(self, inner_factor.domain, inner_factor(inner_factor.domain), inner_factor.interpolation,
                               inner_factor.origin, inner_factor.day_count, inner_factor.forward_tenor)

    def __call__(self, x):
        if isinstance(x, (tuple, list)):
            return [self(xx) for xx in x]
        return self._get_compounding_rate(self.origin, x)

    def _get_compounding_rate(self, start, stop):
        return self.inner_factor.get_zero_rate(start, stop) + self._factor_value


class GaussFlatSpreadZeroRateCurve(GaussFlatSpreadZeroRateCurveFactorModel):
    """ simple Brownian motion rate diffusion """

    def __init__(self, domain=None, data=None, interpolation=None,
                 origin=None, day_count=None, forward_tenor=None,
                 drift=0.0, volatility=0.0):
        inner_factor = ZeroRateCurve(domain, data, interpolation, origin, day_count, forward_tenor)
        super(GaussFlatSpreadZeroRateCurve, self).__init__(inner_factor, drift, volatility)