packages feed

hasquant-0.5.0.2: QuantLib/Index/InterestRate.chs

{-# LANGUAGE TemplateHaskell, StandaloneDeriving, PatternSynonyms #-}
-- suppress warnings about unused Extra_ constructors
{-# OPTIONS_GHC -Wno-unused-top-binds #-}
module QuantLib.Index.InterestRate
  (
    InterestRateIndex
  , BMAIndex
  , OvernightIborIndex
  , IborIndex
  , SwapIndex
  , OvernightIndexedSwapIndex
  , GenInterestRateIndex
  , GenIborIndex
  , GenSwapIndex

  , bmaIndex

  , fixingSchedule
  , forecastFixing
  , currency
  , dayCounter
  , fixingDays
  , tenor

  , asInterestRateIndex
  , asIborIndex
  , asSwapIndex

  , OvernightIborIndexType(..)
  , overnightIborIndex

  , LiborSwapIndexType(..)
  , liborSwapIndex

  , overnightIndexedSwapIndex
  , swapIndex
  , swapIndex'

  -- The bundled names are the fixed-tenor shortcut pattern synonyms defined below;
  -- @Euribor3M@ and @Euribor (3, Months)@ are the same value, usable interchangeably
  -- in expressions and in patterns.
  , IborConstructor(.., Bbsw1M, Bbsw2M, Bbsw3M, Bbsw4M, Bbsw5M, Bbsw6M
                      , BiborSW, Bibor1M, Bibor2M, Bibor3M, Bibor6M, Bibor9M, Bibor1Y
                      , Bkbm1M, Bkbm2M, Bkbm3M, Bkbm4M, Bkbm5M, Bkbm6M
                      , EuriborSW, Euribor2W, Euribor3W
                      , Euribor1M, Euribor2M, Euribor3M, Euribor4M, Euribor5M, Euribor6M
                      , Euribor7M, Euribor8M, Euribor9M, Euribor10M, Euribor11M, Euribor1Y
                      , Euribor365_SW, Euribor365_2W, Euribor365_3W
                      , Euribor365_1M, Euribor365_2M, Euribor365_3M, Euribor365_4M
                      , Euribor365_5M, Euribor365_6M, Euribor365_7M, Euribor365_8M
                      , Euribor365_9M, Euribor365_10M, Euribor365_11M, Euribor365_1Y
                      , EurLiborSW, EurLibor2W
                      , EurLibor1M, EurLibor2M, EurLibor3M, EurLibor4M, EurLibor5M, EurLibor6M
                      , EurLibor7M, EurLibor8M, EurLibor9M, EurLibor10M, EurLibor11M, EurLibor1Y)
  , iborIndex
  , overnightIndex
  , businessDayConvention
  , endOfMonth

  , underlyingSwap
  , underlyingOIS
  ) where
import QuantLib.Internal
import QuantLib.Internal.Syntax
{#import QuantLib.Time.Schedule#}(TimeUnit(..))
{#import QuantLib.Time.Calendar#}(BusinessDayConvention)
import QuantLib.Internal.Type
-- Plain (non-c2hs) import: QuantLib.CashFlow is later in exposed-modules than
-- this file, so a {#import#} here would need its .chi before it exists.
-- overnightIndexedSwapIndex below marshals RateAveragingType as a plain Int
-- via fromEnum instead, per CLAUDE.md's cross-module enum-import workaround.
import QuantLib.CashFlow (RateAveragingType)

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

#include "ql.h"

{#pointer *Currency foreign -> CCurrency nocode#}

{#pointer *QlInterestRateIndex as InterestRateIndex foreign -> CInterestRateIndex' nocode#}
{#pointer *QlBMAIndex as BMAIndex foreign -> CBMAIndex' nocode#}
{#pointer *QlOvernightIndex as OvernightIndex foreign -> COvernightIndex' nocode#}
{#pointer *QlIborIndex as IborIndex foreign -> CIborIndex' nocode#}
{#pointer *QlIndex as Index foreign -> CIndex' nocode#}
{#pointer *QlSwapIndex as SwapIndex foreign -> CSwapIndex' nocode#}
{#pointer *QlOvernightIndex as OvernightIborIndex foreign -> COvernightIndex' nocode#}
{#pointer *QlOvernightIndexedSwapIndex as OvernightIndexedSwapIndex foreign -> COvernightIndexedSwapIndex' nocode#}

{#pointer *QlVanillaSwap as VanillaSwap foreign -> CVanillaSwap' nocode#}
{#pointer *QlOvernightIndexedSwap as OvernightIndexedSwap foreign -> COvernightIndexedSwap' nocode#}

{#pointer *QlYieldTermStructure as YieldTermStructure foreign -> CYieldTermStructure' nocode#}

{#enum OvernightIborIndexType{} deriving (Show, Eq)#}
{#enum LiborSwapIndexType{} deriving (Show, Eq)#}
{#enum IborIndexType{} add prefix = "Ibor__" deriving (Show, Eq)#}
{#enum IborDailyTenorIndexType{} add prefix = "Ibor__" deriving (Show, Eq)#}
{#enum IborONIndexType{} add prefix = "Ibor__" deriving (Show, Eq)#}

-- the fully generic, non-enum-ordinal IborConstructor cases, merged into IborConstructor by
-- deriveIborConstructor below alongside the plain-tenor/daily-tenor/overnight cases generated
-- straight from IborIndexType/IborDailyTenorIndexType/IborONIndexType
data IborExtra =
      Extra__Ibor String -- ^familyName
      (Word, TimeUnit) -- ^tenor
      Word -- ^settlementDays
      Currency
      Calendar -- ^fixingCalendar
      BusinessDayConvention
      Bool -- ^endOfMonth
      DayCounter
    | Extra__Libor String (Word, TimeUnit) Word -- ^settlementDays
      Currency Calendar DayCounter
    | Extra__DailyTenorLibor String Word -- ^settlementDays
      Currency Calendar DayCounter
    | Extra__CustomIbor String -- ^familyName
      (Word, TimeUnit) -- ^tenor
      Word -- ^settlementDays
      Currency
      Calendar -- ^fixingCalendar
      Calendar -- ^valueCalendar
      Calendar -- ^maturityCalendar
      BusinessDayConvention
      Bool -- ^endOfMonth
      DayCounter

$(deriveIborConstructor IborConstructorSpec
    { iborTypeName = "IborConstructor"
    , iborOrdinalFn = "iborIndexOrdinal"
    , iborTenorFn = "iborIndexTenor"
    , iborTenorEnum = ''IborIndexType
    , iborDailyTenorEnum = ''IborDailyTenorIndexType
    , iborOvernightEnum = ''IborONIndexType
    , iborExtraType = ''IborExtra
    })

deriving instance Show IborConstructor
deriving instance Eq IborConstructor

-- Fixed-tenor shortcuts, mirroring upstream's thin @Euribor3M@-style subclasses (whose
-- constructors only delegate to the parameterized one). They are bidirectional pattern
-- synonyms, not constructors: each is *defined* as the parameterized case it stands for,
-- so there is a single list to keep right and no separate dispatch clause that can drift
-- out of step with it -- @Euribor365_SW@ used to expand, via such a clause, to
-- @Euribor (365, Weeks)@: wrong family and wrong tenor both.
pattern Bbsw1M, Bbsw2M, Bbsw3M, Bbsw4M, Bbsw5M, Bbsw6M :: IborConstructor
pattern Bbsw1M = Bbsw (1, Months)
pattern Bbsw2M = Bbsw (2, Months)
pattern Bbsw3M = Bbsw (3, Months)
pattern Bbsw4M = Bbsw (4, Months)
pattern Bbsw5M = Bbsw (5, Months)
pattern Bbsw6M = Bbsw (6, Months)

pattern BiborSW, Bibor1M, Bibor2M, Bibor3M, Bibor6M, Bibor9M, Bibor1Y :: IborConstructor
pattern BiborSW = Bibor (1, Weeks)
pattern Bibor1M = Bibor (1, Months)
pattern Bibor2M = Bibor (2, Months)
pattern Bibor3M = Bibor (3, Months)
pattern Bibor6M = Bibor (6, Months)
pattern Bibor9M = Bibor (9, Months)
pattern Bibor1Y = Bibor (1, Years)

pattern Bkbm1M, Bkbm2M, Bkbm3M, Bkbm4M, Bkbm5M, Bkbm6M :: IborConstructor
pattern Bkbm1M = Bkbm (1, Months)
pattern Bkbm2M = Bkbm (2, Months)
pattern Bkbm3M = Bkbm (3, Months)
pattern Bkbm4M = Bkbm (4, Months)
pattern Bkbm5M = Bkbm (5, Months)
pattern Bkbm6M = Bkbm (6, Months)

pattern EuriborSW, Euribor2W, Euribor3W, Euribor1M, Euribor2M, Euribor3M, Euribor4M
  , Euribor5M, Euribor6M, Euribor7M, Euribor8M, Euribor9M, Euribor10M, Euribor11M
  , Euribor1Y :: IborConstructor
pattern EuriborSW = Euribor (1, Weeks)
pattern Euribor2W = Euribor (2, Weeks)
pattern Euribor3W = Euribor (3, Weeks)
pattern Euribor1M = Euribor (1, Months)
pattern Euribor2M = Euribor (2, Months)
pattern Euribor3M = Euribor (3, Months)
pattern Euribor4M = Euribor (4, Months)
pattern Euribor5M = Euribor (5, Months)
pattern Euribor6M = Euribor (6, Months)
pattern Euribor7M = Euribor (7, Months)
pattern Euribor8M = Euribor (8, Months)
pattern Euribor9M = Euribor (9, Months)
pattern Euribor10M = Euribor (10, Months)
pattern Euribor11M = Euribor (11, Months)
pattern Euribor1Y = Euribor (1, Years)

pattern Euribor365_SW, Euribor365_2W, Euribor365_3W, Euribor365_1M, Euribor365_2M
  , Euribor365_3M, Euribor365_4M, Euribor365_5M, Euribor365_6M, Euribor365_7M
  , Euribor365_8M, Euribor365_9M, Euribor365_10M, Euribor365_11M
  , Euribor365_1Y :: IborConstructor
pattern Euribor365_SW = Euribor365 (1, Weeks)
pattern Euribor365_2W = Euribor365 (2, Weeks)
pattern Euribor365_3W = Euribor365 (3, Weeks)
pattern Euribor365_1M = Euribor365 (1, Months)
pattern Euribor365_2M = Euribor365 (2, Months)
pattern Euribor365_3M = Euribor365 (3, Months)
pattern Euribor365_4M = Euribor365 (4, Months)
pattern Euribor365_5M = Euribor365 (5, Months)
pattern Euribor365_6M = Euribor365 (6, Months)
pattern Euribor365_7M = Euribor365 (7, Months)
pattern Euribor365_8M = Euribor365 (8, Months)
pattern Euribor365_9M = Euribor365 (9, Months)
pattern Euribor365_10M = Euribor365 (10, Months)
pattern Euribor365_11M = Euribor365 (11, Months)
pattern Euribor365_1Y = Euribor365 (1, Years)

pattern EurLiborSW, EurLibor2W, EurLibor1M, EurLibor2M, EurLibor3M, EurLibor4M
  , EurLibor5M, EurLibor6M, EurLibor7M, EurLibor8M, EurLibor9M, EurLibor10M
  , EurLibor11M, EurLibor1Y :: IborConstructor
pattern EurLiborSW = EurLibor (1, Weeks)
pattern EurLibor2W = EurLibor (2, Weeks)
pattern EurLibor1M = EurLibor (1, Months)
pattern EurLibor2M = EurLibor (2, Months)
pattern EurLibor3M = EurLibor (3, Months)
pattern EurLibor4M = EurLibor (4, Months)
pattern EurLibor5M = EurLibor (5, Months)
pattern EurLibor6M = EurLibor (6, Months)
pattern EurLibor7M = EurLibor (7, Months)
pattern EurLibor8M = EurLibor (8, Months)
pattern EurLibor9M = EurLibor (9, Months)
pattern EurLibor10M = EurLibor (10, Months)
pattern EurLibor11M = EurLibor (11, Months)
pattern EurLibor1Y = EurLibor (1, Years)

iborIndex :: IborConstructor -> Maybe (GenYieldTermStructure y) -> IO IborIndex
iborIndex (Ibor n p s cr ca bd b dc) ts = qlIborIndex n p s cr ca bd b dc ts
iborIndex (Libor n p s cr ca dc) ts = qlLibor n p s cr ca dc ts
iborIndex (DailyTenorLibor n c cr ca dc) ts = qlDailyTenorLibor n c cr ca dc ts
iborIndex (CustomIbor n p s cr fc vc mc bd b dc) ts = qlCustomIborIndex n p s cr fc vc mc bd b dc ts
iborIndex c ts = qlCreateIbor (iborIndexOrdinal c) (iborIndexTenor c) ts

-- |Creates the BMA (Bond Market Association) short-term tax-exempt index, optionally linked to a forwarding curve.
{#fun qlBMAIndex as bmaIndex{withMaybeYieldTermStructure*`Maybe (GenYieldTermStructure y)',preErrorCheck-`String'errorCheck*-}->`BMAIndex'peekBMAIndex*#}

-- |This method returns a schedule of fixing dates between start and end.
{#fun qlBMAIndexFixingSchedule as fixingSchedule{withBMAIndex*`BMAIndex',withDay*`Day',withDay*`Day',preErrorCheck-`String'errorCheck*-}->`Schedule'peekSchedule*#}

-- |It can be overridden to implement particular conventions.
{#fun qlInterestRateIndexForecastFixing as forecastFixing{withInterestRateIndex*`GenInterestRateIndex ridx',withDay*`Day',preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |Returns the index's underlying currency.
{#fun qlInterestRateIndexCurrency as currency{withInterestRateIndex*`GenInterestRateIndex ridx',preErrorCheck-`String'errorCheck*-}->`Currency'peekCurrency*#}

-- |Returns the day counter used by the index.
{#fun qlInterestRateIndexDayCounter as dayCounter{withInterestRateIndex*`GenInterestRateIndex ridx',preErrorCheck-`String'errorCheck*-}->`DayCounter'peekDayCounter*#}

-- |Returns the number of business days between a fixing date and the corresponding value date.
{#fun pure qlInterestRateIndexFixingDays as fixingDays{withInterestRateIndex*`GenInterestRateIndex ridx'}->`Word'fromIntegral#}

-- |Returns the index's tenor.
{#fun qlInterestRateIndexTenor as tenor{withInterestRateIndex*`GenInterestRateIndex ridx',preEnum-`TimeUnit'peekEnum*,preErrorCheck-`String'errorCheck*-}->`Word'fromIntegral#}

-- |Creates one of the built-in overnight indexes (e.g. Sofr, Estr, Sonia), optionally linked to a forwarding curve.
{#fun qlCreateONIndex as overnightIborIndex{`OvernightIborIndexType',withMaybeYieldTermStructure*`Maybe (GenYieldTermStructure y)',preErrorCheck-`String'errorCheck*-}->`OvernightIborIndex'peekOvernightIborIndex*#}

-- |Creates one of the built-in ISDA-fix swap-rate indexes for a given tenor, with separate forwarding and discounting curves.
{#fun qlCreateLiborSwapIndex as liborSwapIndex{`LiborSwapIndexType',fromEnumQuantity`(Int,TimeUnit)'&
  ,withMaybeYieldTermStructure*`Maybe (GenYieldTermStructure y1)' -- ^forwarding
  ,withMaybeYieldTermStructure*`Maybe (GenYieldTermStructure y2)' -- ^discounting
  ,preErrorCheck-`String'errorCheck*-}->`SwapIndex'peekSwapIndex*#}

-- | Construct an overnight-indexed swap index.
-- RateAveragingType (QuantLib.CashFlow) is later in exposed-modules than this file,
-- so averagingMethod is marshalled as a plain Int via fromEnum in the unexported
-- glue binding below instead of a {#import#}'d enum type, per CLAUDE.md's
-- cross-module workaround. The public signature stays fully typed.
overnightIndexedSwapIndex :: String -> (Int, TimeUnit) -> Word -> Currency
  -> OvernightIborIndex -> Bool -> RateAveragingType -> IO OvernightIndexedSwapIndex
overnightIndexedSwapIndex familyName tenr settlementDays ccy idx telescopicValueDates averagingMethod =
  overnightIndexedSwapIndex_ familyName tenr settlementDays ccy idx telescopicValueDates (fromEnum averagingMethod)

-- |Low-level glue for 'overnightIndexedSwapIndex': constructs the swap-rate index tracking an overnight-indexed swap, taking the rate-averaging method as a plain Int.
{#fun qlOvernightIndexedSwapIndex as overnightIndexedSwapIndex_{`String',fromEnumQuantity`(Int,TimeUnit)'&,fromIntegral`Word' -- ^settlementDays
  ,withCurrency*`Currency',withOvernightIborIndex*`OvernightIborIndex'
  ,`Bool' -- ^telescopicValueDates
  ,`Int' -- ^averagingMethod
  ,preErrorCheck-`String'errorCheck*-}->`OvernightIndexedSwapIndex'peekOvernightIndexedSwapIndex*#}

-- |Creates a swap-rate index whose forwarding and discounting both come from the underlying ibor index's curve.
{#fun qlSwapIndex as swapIndex{`String',fromEnumQuantity`(Int,TimeUnit)'&,fromIntegral`Word' -- ^settlementDays
  ,withCurrency*`Currency',withCalendar*`Calendar',fromEnumQuantity`(Int,TimeUnit)'& -- ^fixedLegTenor
  ,`BusinessDayConvention',withDayCounter*`DayCounter',withIborIndex*`GenIborIndex ibor',preErrorCheck-`String'errorCheck*-}->`SwapIndex'peekSwapIndex*#}

-- |Creates a swap-rate index with a discounting curve distinct from the forwarding curve of the underlying ibor index.
{#fun qlSwapIndex1 as swapIndex'{`String' -- ^familyName
  ,fromEnumQuantity`(Int,TimeUnit)'& -- ^tenor
  ,fromIntegral`Word' -- ^settlementDays
  ,withCurrency*`Currency',withCalendar*`Calendar',fromEnumQuantity`(Int,TimeUnit)'& -- ^fixedLegTenor
  ,`BusinessDayConvention' -- ^fixedLegConvention
  ,withDayCounter*`DayCounter' -- ^fixedLegDayCounter
  ,withIborIndex*`GenIborIndex ibor',withYieldTermStructure*`GenYieldTermStructure y',preErrorCheck-`String'errorCheck*-}->`SwapIndex'peekSwapIndex*#}

-- |Low-level glue for 'iborIndex': constructs a generic Inter-Bank-Offered-Rate index, optionally linked to a forwarding curve.
{#fun qlIborIndex{`String' -- ^familyName
  ,fromEnumQuantity`(Word,TimeUnit)'& -- ^tenor
  ,fromIntegral`Word' -- ^settlementDays
  ,withCurrency*`Currency',withCalendar*`Calendar',`BusinessDayConvention'
  ,`Bool' -- ^endOfMonth
  ,withDayCounter*`DayCounter',withMaybeYieldTermStructure*`Maybe (GenYieldTermStructure y)',preErrorCheck-`String'errorCheck*-}->`IborIndex'peekIborIndex*#}

-- |Low-level glue for 'iborIndex': constructs an ICE LIBOR index (all currencies but EUR/O/N/S/N), optionally linked to a forwarding curve.
{#fun qlLibor{`String' -- ^familyName
  ,fromEnumQuantity`(Word,TimeUnit)'&,fromIntegral`Word' -- settlementDays
  ,withCurrency*`Currency',withCalendar*`Calendar',withDayCounter*`DayCounter',withMaybeYieldTermStructure*`Maybe (GenYieldTermStructure y)',preErrorCheck-`String'errorCheck*-}->`IborIndex'peekIborIndex*#}

-- |Low-level glue for 'iborIndex': constructs a one-day (O/N-S/N) ICE LIBOR index, optionally linked to a forwarding curve.
{#fun qlDailyTenorLibor{`String' -- ^familyName
  ,fromIntegral`Word' -- ^settlementDays
  ,withCurrency*`Currency',withCalendar*`Calendar',withDayCounter*`DayCounter',withMaybeYieldTermStructure*`Maybe (GenYieldTermStructure y)',preErrorCheck-`String'errorCheck*-}->`IborIndex'peekIborIndex*#}

-- |Low-level glue for 'iborIndex': constructs a LIBOR-like index with independently specified fixing/value/maturity calendars.
{#fun qlCustomIborIndex{`String' -- ^familyName
  ,fromEnumQuantity`(Word,TimeUnit)'& -- ^tenor
  ,fromIntegral`Word' -- ^settlementDays
  ,withCurrency*`Currency',withCalendar*`Calendar' -- ^fixingCalendar
  ,withCalendar*`Calendar' -- ^valueCalendar
  ,withCalendar*`Calendar' -- ^maturityCalendar
  ,`BusinessDayConvention'
  ,`Bool' -- ^endOfMonth
  ,withDayCounter*`DayCounter',withMaybeYieldTermStructure*`Maybe (GenYieldTermStructure y)',preErrorCheck-`String'errorCheck*-}->`IborIndex'peekIborIndex*#}

-- |Low-level glue for 'iborIndex': constructs one of the built-in fixed-tenor/daily-tenor/overnight ibor indexes by ordinal, optionally linked to a forwarding curve.
{#fun qlCreateIbor{fromIntegral`Int',fromEnumQuantity`(Word,TimeUnit)'&,withMaybeYieldTermStructure*`Maybe (GenYieldTermStructure y)',preErrorCheck-`String'errorCheck*-}->`IborIndex'peekIborIndex*#}

-- |Creates a generic overnight index, optionally linked to a forwarding curve.
{#fun qlOvernightIndex as overnightIndex{`String',fromIntegral`Word' -- ^settlementDays
  ,withCurrency*`Currency',withCalendar*`Calendar',withDayCounter*`DayCounter',withMaybeYieldTermStructure*`Maybe (GenYieldTermStructure y)',preErrorCheck-`String'errorCheck*-}->`OvernightIborIndex'peekOvernightIborIndex*#}

-- |Returns the business day convention used to adjust the index's value/maturity dates.
{#fun pure qlIborIndexBusinessDayConvention as businessDayConvention{withIborIndex*`GenIborIndex ibor'}->`BusinessDayConvention'#}

-- |Returns whether the index's date calculations roll to the end of the month.
{#fun pure qlIborIndexEndOfMonth as endOfMonth{withIborIndex*`GenIborIndex ibor'}->`Bool'#}

-- |Returns the overnight-indexed swap underlying the index for a given fixing date. Relinking the index's term structure afterwards has no effect on the returned swap.
{#fun qlOvernightIndexedSwapIndexUnderlyingSwap as underlyingOIS {withOvernightIndexedSwapIndex*`OvernightIndexedSwapIndex',withDay*`Day',preErrorCheck-`String'errorCheck*-}->`OvernightIndexedSwap'peekOvernightIndexedSwap*#}

-- |Returns the vanilla swap underlying the index for a given fixing date. Relinking the index's term structure afterwards has no effect on the returned swap.
{#fun qlSwapIndexUnderlyingSwap as underlyingSwap{withSwapIndex*`GenSwapIndex sidx',withDay*`Day',preErrorCheck-`String'errorCheck*-}->`VanillaSwap'peekVanillaSwap*#}

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