packages feed

hasquant-0.7.0.0: QuantLib/Credit.chs

-- |Portfolio-credit types, baskets, and loss models.
module QuantLib.Credit
  (
    -- * Types
    -- ** Issuers, pools and baskets
    DefaultProbKey
  , Issuer
  , Pool
  , Basket
  , TrancheBasket
  , DigitalBasket
    -- ** Loss models
  , DefaultLossModel
  , DigitalLossModel
    -- ** Configuration
  , Seniority(..)
  , RestructuringType(..)
  , LatentModelIntegrationType(..)

    -- * Constructors
  , northAmericaCorpDefaultKey
  , issuer
  , pool
  , basket
  , trancheBasketAsBasket
  , digitalBasket
  , digitalBasketAsBasket
  , gaussianLhpLossModel
  , constantLossModel

    -- * Inspectors
  , basketExpectedTrancheLoss
  , basketProbOverLoss
  , basketPercentile
  , basketExpectedShortfall
  , basketDefaultCorrelation
  , basketProbAtLeastNEvents
  , basketNotional
  , basketRemainingNotional
  , basketRecoveryRate
  ) where
import Data.List.NonEmpty(NonEmpty, toList)

import QuantLib.Internal
import QuantLib.Internal.Common
import QuantLib.Internal.Type

#include "qlTypesC2HS.h"
#include "qlEnumC2HS.h"
#include "qlEnumObjects.h"

#include "ql.h"

-- |Seniority of a bond; also used as the ISDA tier\/seniority for CDS conventional spreads.
{#enum Seniority{} deriving (Show, Eq, Read, Bounded)#}

-- |Restructuring clause of a default-probability key (ISDA @XR@\/@MR@\/@MM@\/@CR@).
{#enum RestructuringType{} deriving (Show, Eq, Read, Bounded)#}

-- |Numerical-integration scheme used by a 'QuantLib.Credit.LatentModel'-based copula loss
-- model (e.g. the gaussian\/student constant-loss dispatcher bound alongside 'NthToDefault').
{#enum LatentModelIntegrationType{} deriving (Show, Eq, Read, Bounded)#}

{#pointer *Currency foreign -> CCurrency nocode#}
{#pointer *QlQuote as Quote foreign -> CQuote' nocode#}
{#pointer *QlClaim as Claim foreign -> CQlClaim nocode#}
{#pointer *QlDefaultProbabilityTermStructure as DefaultProbabilityTermStructure foreign -> CDefaultProbabilityTermStructure' nocode#}
{#pointer *DefaultProbKey foreign -> CDefaultProbKey nocode#}
{#pointer *Issuer foreign -> CIssuer nocode#}
{#pointer *QlPool as Pool foreign -> CPool nocode#}
{#pointer *QlBasket as Basket foreign -> CBasket nocode#}
{#pointer *QlBasket as TrancheBasket foreign -> CBasket nocode#}
{#pointer *QlBasket as DigitalBasket foreign -> CBasket nocode#}
{#pointer *QlDefaultLossModel as DefaultLossModel foreign -> CDefaultLossModel nocode#}
{#pointer *QlDefaultLossModel as DigitalLossModel foreign -> CDefaultLossModel nocode#}

-- |ISDA standard default contractual key for corporate US debt. @restructuringType@ may be
-- 'NoRestructuring' to disable restructuring as a trigger.
{#fun qlNorthAmericaCorpDefaultKey as northAmericaCorpDefaultKey{withCurrency*`Currency' -- ^currency
  ,`Seniority' -- ^seniority
  ,fromEnumQuantity`(Int,TimeUnit)'& -- ^graceFailureToPay
  ,`Double' -- ^amountFailure
  ,`RestructuringType' -- ^restructuringType
  ,preErrorCheck-`String'errorCheck*-}->`DefaultProbKey'peekDefaultProbKey*#}

-- |An issuer's default-probability term structures, keyed by contract terms.
issuer :: NonEmpty (DefaultProbKey, DefaultProbabilityTermStructure) -> IO Issuer
issuer probs = qlIssuer keys curves
  where (keys, curves) = unzip (toList probs)
{#fun qlIssuer{withDefaultProbKeyArray*`[DefaultProbKey]'&
  ,withDefaultProbabilityTermStructureArrayRaw*`[DefaultProbabilityTermStructure]'
  ,preErrorCheck-`String'errorCheck*-}->`Issuer'peekIssuer*#}

-- |A named collection of issuers and their default-probability keys.
pool :: NonEmpty (String, Issuer, DefaultProbKey) -> IO Pool
pool entries = qlPool names issuers keys
  where (names, issuers, keys) = unzip3 (toList entries)
{#fun qlPool{withStringArray*`[String]'&
  ,withIssuerArrayRaw*`[Issuer]'
  ,withDefaultProbKeyArrayRaw*`[DefaultProbKey]'
  ,preErrorCheck-`String'errorCheck*-}->`Pool'peekPool*#}

-- |A tranched basket with a tranche-loss model; usable for CDO pricing.
basket :: Day -> NonEmpty (String, Double) -> Pool -> Double -> Double -> Claim -> DefaultLossModel -> IO TrancheBasket
basket refDate positions p attachmentRatio detachmentRatio cl lm =
  qlBasket refDate names notionals p attachmentRatio detachmentRatio cl lm
  where (names, notionals) = unzip (toList positions)
{#fun qlBasket{withDay*`Day' -- ^refDate
  ,withStringArray*`[String]'&
  ,withDoubleArrayRaw*`[Double]'
  ,withPool*`Pool'
  ,`Double' -- ^attachmentRatio
  ,`Double' -- ^detachmentRatio
  ,withClaim*`Claim'
  ,withDefaultLossModel*`DefaultLossModel'
  ,preErrorCheck-`String'errorCheck*-}->`TrancheBasket'peekTrancheBasket*#}

-- |Basket total notional at inception, before losses.
{#fun qlBasketNotional as basketNotional{withBasket*`Basket',preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |Live (undefaulted) notional remaining at date @d@. Loss-model-agnostic.
{#fun qlBasketRemainingNotional as basketRemainingNotional{withBasket*`Basket',withDay*`Day' -- ^d
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |Expected recovery rate of the @iName@-th pool name (0-based, in basket-construction order),
-- conditional on default by date @d@. Loss-model-agnostic.
{#fun qlBasketRecoveryRate as basketRecoveryRate{withBasket*`Basket',withDay*`Day' -- ^d
  ,fromIntegral`Word' -- ^iName
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |Expected tranche loss on date @d@; requires a tranche-loss model.
{#fun qlBasketExpectedTrancheLoss as basketExpectedTrancheLoss{withTrancheBasket*`TrancheBasket',withDay*`Day' -- ^d
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |Probability the tranche loses at least @lossFraction@ of the tranche notional by date @d@.
{#fun qlBasketProbOverLoss as basketProbOverLoss{withTrancheBasket*`TrancheBasket',withDay*`Day' -- ^d
  ,`Double' -- ^lossFraction
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |Tranche loss fraction at the given percentile of the loss distribution on date @d@ (VaR).
{#fun qlBasketPercentile as basketPercentile{withTrancheBasket*`TrancheBasket',withDay*`Day' -- ^d
  ,`Double' -- ^prob
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |Expected tranche loss given loss exceeds the given percentile on date @d@.
{#fun qlBasketExpectedShortfall as basketExpectedShortfall{withTrancheBasket*`TrancheBasket',withDay*`Day' -- ^d
  ,`Double' -- ^prob
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |Pearson default-probability correlation between pool names @iName@ and @jName@ (0-based) by
-- date @d@.
{#fun qlBasketDefaultCorrelation as basketDefaultCorrelation{withDigitalBasket*`DigitalBasket',withDay*`Day' -- ^d
  ,fromIntegral`Word' -- ^iName
  ,fromIntegral`Word' -- ^jName
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |Probability of at least @n@ defaults in the basket by date @d@.
{#fun qlBasketProbAtLeastNEvents as basketProbAtLeastNEvents{withDigitalBasket*`DigitalBasket'
  ,fromIntegral`Word' -- ^n
  ,withDay*`Day' -- ^d
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |A digital-loss basket for nth-to-default pricing.
digitalBasket :: Day -> NonEmpty (String, Double) -> Pool -> Double -> Double -> Claim -> DigitalLossModel -> IO DigitalBasket
digitalBasket refDate positions p attachmentRatio detachmentRatio cl lm =
  qlDigitalBasket refDate names notionals p attachmentRatio detachmentRatio cl lm
  where (names, notionals) = unzip (toList positions)
{#fun qlDigitalBasket{withDay*`Day' -- ^refDate
  ,withStringArray*`[String]'&
  ,withDoubleArrayRaw*`[Double]'
  ,withPool*`Pool'
  ,`Double' -- ^attachmentRatio
  ,`Double' -- ^detachmentRatio
  ,withClaim*`Claim'
  ,withDigitalLossModel*`DigitalLossModel'
  ,preErrorCheck-`String'errorCheck*-}->`DigitalBasket'peekDigitalBasket*#}

-- |One-factor Gaussian-copula LHP loss model. @recoveries@ follow basket-name order.
gaussianLhpLossModel :: GenQuote q -> NonEmpty Double -> IO DefaultLossModel
gaussianLhpLossModel correlQuote recoveries = qlGaussianLHPLossModel correlQuote (toList recoveries)
{#fun qlGaussianLHPLossModel{withQuote*`GenQuote q' -- ^correlQuote
  ,withDoubleArray*`[Double]'&
  ,preErrorCheck-`String'errorCheck*-}->`DefaultLossModel'peekDefaultLossModel*#}

-- |One-factor Gaussian- or Student-T-copula model for digital-loss baskets.
-- @[]@ selects Gaussian; @tOrders@ selects Student-T degrees of freedom.
constantLossModel :: GenQuote q -> NonEmpty Double -> LatentModelIntegrationType -> [Int] -> IO DigitalLossModel
constantLossModel correlQuote recoveries integralType tOrders =
  qlConstantLossModel correlQuote (toList recoveries) integralType tOrders
{#fun qlConstantLossModel{withQuote*`GenQuote q'
  ,withDoubleArray*`[Double]'&
  ,`LatentModelIntegrationType'
  ,withIntArray*`[Int]'&
  ,preErrorCheck-`String'errorCheck*-}->`DigitalLossModel'peekDigitalLossModel*#}

-- vim: set ff=unix ts=8 sts=2 sw=2 et: