packages feed

hasquant-0.5.0.2: QuantLib/TermStructure/Volatility.chs

{-# LANGUAGE TemplateHaskell #-}
module QuantLib.TermStructure.Volatility
  (
    BlackVarianceSurfaceExtrapolation(..)
  , ExtendedBlackVarianceSurfaceExtrapolation(..)
  , FixedLocalVolSurfaceExtrapolation(..)

  , BlackVarianceCurve
  , BlackVolatilitySurfaceDelta
  , SmileInterpolationMethod(..)
  , BlackVolTimeExtrapolationType(..)
  , BlackVolatilitySurfaceDeltaOpts(..)
  , defaultBlackVolatilitySurfaceDeltaOpts
  , BlackVolTermStructure
  , GenBlackVolTermStructure
  , RelinkableBlackVolTermStructure
  , CallableBondVolatilityStructure
  , CapFloorTermVolSurface
  , LocalVolTermStructure
  , OptionletVolatilityStructure
  , GenOptionletVolatilityStructure
  , RelinkableOptionletVolatilityStructure
  , SmileSection
  , SabrInterpolatedSmileSection
  , SwaptionVolatilityStructure
  , RelinkableSwaptionVolatilityStructure
  , VolatilityTermStructure
  , GenVolatilityTermStructure

  , asVolatilityTermStructure
  , asBlackVolTermStructure

  , localVolSurface
  , constantOptionletVolatility
  , constantOptionletVolatility'
  , optionletStripper1

  , impliedVolTermStructure
  , blackConstantVol'
  , blackConstantVol
  , relinkableBlackVolTermStructure
  , linkBlackVolTo
  , constantSwaptionVolatility'
  , constantSwaptionVolatility
  , blackVarianceForPeriod'
  , blackVarianceForPeriod
  , blackVarianceForTenor
  , blackVariance'
  , blackVariance
  , blackVarianceForPeriods
  , maxSwapLength
  , maxSwapTenor
  , smileSectionForPeriod'
  , smileSectionForPeriod
  , smileSectionForTenor
  , smileSection'
  , smileSection
  , smileSectionForPeriods
  , sabrSmileSection
  , sabrSmileSection'
  , noArbSabrSmileSection
  , noArbSabrSmileSection'
  , smileSectionVolatility
  , smileSectionVariance
  , SabrInterpolatedSmileSectionOpts(..)
  , defaultSabrInterpolatedSmileSectionOpts
  , sabrInterpolatedSmileSection
  , sabrInterpolatedSmileSectionAsSmileSection
  , sabrInterpolatedSmileSectionAlpha
  , sabrInterpolatedSmileSectionBeta
  , sabrInterpolatedSmileSectionNu
  , sabrInterpolatedSmileSectionRho
  , sabrInterpolatedSmileSectionRmsError
  , sabrInterpolatedSmileSectionMaxError
  , sabrInterpolatedSmileSectionEndCriteria
  , swapLength'
  , swapLength
  , volatilityForPeriod'
  , volatilityForPeriod
  , volatilityForTenor
  , volatilityForTenor'
  , volatility
  , volatilityForPeriods
  , callableBondConstantVolatility'
  , callableBondConstantVolatility
  , constantCapFloorTermVolatility'
  , constantCapFloorTermVolatility
  , spreadedSwaptionVolatility
  , relinkableSwaptionVolatilityStructure
  , linkSwaptionVolTo
  , relinkableOptionletVolatilityStructure
  , linkOptionletVolTo
  , localConstantVol'
  , localConstantVol
  , localVolCurve
  , capFloorTermVolCurve
  , capFloorTermVolCurve'
  , blackVarianceCurve
  , capFloorTermVolSurface
  , capFloorTermVolSurface'
  , blackVarianceSurface
  , piecewiseBlackVarianceSurface
  , blackVolatilitySurfaceDelta
  , blackVolatilitySurfaceDeltaFull
  , blackVolSmile
  , blackVolSmile'
  , swaptionVolatilityMatrix'
  , SabrSwaptionVolatilityCube
  , InterpolatedSwaptionVolatilityCube
  , sabrSwaptionVolatilityCube
  , interpolatedSwaptionVolatilityCube
  , sparseSabrParameters
  , denseSabrParameters
  , marketVolCube
  , volCubeAtmCalibrated
  , sabrSwaptionVolatilityCubeAtmStrike'
  , sabrSwaptionVolatilityCubeAtmStrike
  , interpolatedSwaptionVolatilityCubeAtmStrike'
  , interpolatedSwaptionVolatilityCubeAtmStrike
  , swaptionVolatilityMatrix
  , noExceptLocalVolSurface
  , fixedLocalVolSurface
  , spreadedOptionletVol
  , localVol
  , smileSectionAtmLevel
  , flatSmileSection
  , spreadedSmileSection
  , atmSmileSection
  ) where
import QuantLib.Internal
import Foreign.C.Types(CInt)
{#import QuantLib.Time.Calendar#}(BusinessDayConvention)
{#import QuantLib.InterestRate#}(VolatilityType)
{#import QuantLib.Math#}(EndCriteriaType)
{#import QuantLib.Quote#}(DeltaType(..), AtmType(..))
import QuantLib.Internal.Type
import QuantLib.Internal.Enum
import QuantLib.Internal.Syntax(deriveOptionsRecord)
import QuantLib.Time.Schedule(dayCounter, DayCounterConstructor(..))

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

{#pointer *DayCounter foreign -> CDayCounter nocode#}
{#pointer *QlQuote as Quote foreign -> CQuote' nocode#}
{#pointer *QlIborIndex as IborIndex foreign -> CIborIndex' nocode#}
{#pointer *QlSmileSection as SmileSection foreign -> CSmileSection nocode#}
{#pointer *QlSabrInterpolatedSmileSection as SabrInterpolatedSmileSection foreign -> CSabrInterpolatedSmileSection nocode#}

{#pointer *QlVolatilityTermStructure as VolatilityTermStructure foreign -> CVolatilityTermStructure' nocode#}
{#pointer *QlYieldTermStructure as YieldTermStructure foreign -> CYieldTermStructure' nocode#}
{#pointer *QlTermStructure as TermStructure foreign -> CTermStructure' nocode#}
{#pointer *QlOptionletVolatilityStructure as OptionletVolatilityStructure foreign -> COptionletVolatilityStructure' nocode#}
{#pointer *QlRelinkableOptionletVolatilityStructure as RelinkableOptionletVolatilityStructure foreign -> CRelinkableOptionletVolatilityStructure' nocode#}
{#pointer *QlLocalVolTermStructure as LocalVolTermStructure foreign -> CLocalVolTermStructure' nocode#}
{#pointer *QlBlackVarianceCurve as BlackVarianceCurve foreign -> CBlackVarianceCurve' nocode#}
{#pointer *QlBlackVolatilitySurfaceDelta as BlackVolatilitySurfaceDelta foreign -> CBlackVolatilitySurfaceDelta' nocode#}
{#pointer *QlBlackVolTermStructure as BlackVolTermStructure foreign -> CBlackVolTermStructure' nocode#}
{#pointer *QlRelinkableBlackVolTermStructure as RelinkableBlackVolTermStructure foreign -> CRelinkableBlackVolTermStructure' nocode#}
{#pointer *QlCallableBondVolatilityStructure as CallableBondVolatilityStructure foreign -> CCallableBondVolatilityStructure' nocode#}
{#pointer *QlCapFloorTermVolSurface as CapFloorTermVolSurface foreign -> CCapFloorTermVolSurface' nocode#}
{#pointer *QlSwaptionVolatilityStructure as SwaptionVolatilityStructure foreign -> CSwaptionVolatilityStructure' nocode#}
{#pointer *QlRelinkableSwaptionVolatilityStructure as RelinkableSwaptionVolatilityStructure foreign -> CRelinkableSwaptionVolatilityStructure' nocode#}
{#pointer *QlSabrSwaptionVolatilityCube as SabrSwaptionVolatilityCube foreign -> CSabrSwaptionVolatilityCube' nocode#}
{#pointer *QlInterpolatedSwaptionVolatilityCube as InterpolatedSwaptionVolatilityCube foreign -> CInterpolatedSwaptionVolatilityCube' nocode#}
{#pointer *QlSwapIndex as SwapIndex foreign -> CSwapIndex' nocode#}

{#enum BlackVarianceSurfaceExtrapolation{} deriving(Show, Eq)#}
{#enum ExtendedBlackVarianceSurfaceExtrapolation{} deriving(Show, Eq)#}

-- |'BlackVolatilitySurfaceDelta::SmileInterpolationMethod', local to that class -- not shared
-- with any other binding, so declared here rather than in 'QuantLib.Internal.Enum'.
{#enum SmileInterpolationMethod{} deriving(Show, Eq)#}

-- |'BlackVolTimeExtrapolation::Type', consumed only by 'blackVolatilitySurfaceDelta' today --
-- same local-declaration treatment as 'SmileInterpolationMethod'. Named
-- @BlackVolTimeExtrapolationType@ (rather than reusing the bare @Type@ c2hs would otherwise
-- emit) to avoid a top-level name clash.
{#enum BlackVolTimeExtrapolationType{} deriving(Show, Eq)#}

-- |'FixedLocalVolSurface::Extrapolation', local to that class -- not shared with any other
-- binding, same local-declaration treatment as 'SmileInterpolationMethod'.
{#enum FixedLocalVolSurfaceExtrapolation{} deriving(Show, Eq)#}

-- SabrInterpolatedSmileSectionOpts bundles every trailing param
-- sabrInterpolatedSmileSection_ hardcodes, pre-populated with upstream's own defaults,
-- overridden through record-update syntax -- see OISRateHelperOpts (QuantLib.TermStructure.Yield)
-- for the worked example this follows. dayCounter is Maybe here (unlike the raw binding's
-- plain DayCounter) since a real DayCounter is only obtainable in IO (`dayCounter
-- Actual365FixedStandard`) and can't live in a pure default record value;
-- sabrInterpolatedSmileSection substitutes a fresh Actual365Fixed for Nothing, same as
-- OISRateHelperOpts does for its Calendar fields. This splice must stay textually before
-- every {#fun#}-generated binding in this file -- see the comment above OISRateHelperOpts
-- for why (c2hs always appends its raw foreign-import stubs at the physical end of the
-- generated module regardless of where a {#fun#} hook appears in the source).
$(deriveOptionsRecord "SabrInterpolatedSmileSectionOpts" []
  [ ("sabrIsAlphaFixed", [t|Bool|], [|False|])
  , ("sabrIsBetaFixed", [t|Bool|], [|False|])
  , ("sabrIsNuFixed", [t|Bool|], [|False|])
  , ("sabrIsRhoFixed", [t|Bool|], [|False|])
  , ("sabrVegaWeighted", [t|Bool|], [|True|])
  , ("sabrDayCounter", [t|Maybe DayCounter|], [|Nothing|])
  , ("sabrShift", [t|Double|], [|0.0|])
  ])

-- BlackVolatilitySurfaceDeltaOpts bundles every trailing defaulted param of
-- 'BlackVolatilitySurfaceDelta''s one constructor (deltaType through longTermAtmDeltaType),
-- pre-populated with upstream's own defaults via defaultBlackVolatilitySurfaceDeltaOpts,
-- overridden through record-update syntax at the call site -- see OISRateHelperOpts
-- (QuantLib.TermStructure.Yield) for the worked example this follows. Same
-- splice-placement constraint as SabrInterpolatedSmileSectionOpts above.
$(deriveOptionsRecord "BlackVolatilitySurfaceDeltaOpts" []
  [ ("bvsdDeltaType", [t|DeltaType|], [|Spot|])
  , ("bvsdAtmType", [t|AtmType|], [|AtmDeltaNeutral|])
  , ("bvsdAtmDeltaType", [t|Maybe DeltaType|], [|Nothing|])
  , ("bvsdInterpolationMethod", [t|SmileInterpolationMethod|], [|SmileLinear|])
  , ("bvsdFlatStrikeExtrapolation", [t|Bool|], [|False|])
  , ("bvsdTimeExtrapolationType", [t|BlackVolTimeExtrapolationType|], [|FlatVolatility|])
  , ("bvsdSwitchTenor", [t|(Int, TimeUnit)|], [|(0, Days)|])
  , ("bvsdLongTermDeltaType", [t|DeltaType|], [|Fwd|])
  , ("bvsdLongTermAtmType", [t|AtmType|], [|AtmDeltaNeutral|])
  , ("bvsdLongTermAtmDeltaType", [t|Maybe DeltaType|], [|Nothing|])
  ])

-- |A local vol surface derived from a Black vol surface via Dupire's formula (Gatheral's
-- implementation).
{#fun qlLocalVolSurface as localVolSurface{withBlackVolTermStructure*`GenBlackVolTermStructure bv'
  ,withYieldTermStructure*`GenYieldTermStructure y1' -- ^riskFreeTS
  ,withYieldTermStructure*`GenYieldTermStructure y2' -- ^dividendTS
  ,withQuote*`GenQuote q' -- ^underlying
  ,preErrorCheck-`String'errorCheck*-}->`LocalVolTermStructure'peekLocalVolTermStructure*#}

-- |as 'localVolSurface', but a local vol calculation that would otherwise throw returns
-- @illegalLocalVolOverwrite@ instead
{#fun qlNoExceptLocalVolSurface as noExceptLocalVolSurface{withBlackVolTermStructure*`GenBlackVolTermStructure bv'
  ,withYieldTermStructure*`GenYieldTermStructure y1' -- ^riskFreeTS
  ,withYieldTermStructure*`GenYieldTermStructure y2' -- ^dividendTS
  ,withQuote*`GenQuote q' -- ^underlying
  ,`Double' -- ^illegalLocalVolOverwrite
  ,preErrorCheck-`String'errorCheck*-}->`LocalVolTermStructure'peekLocalVolTermStructure*#}

-- |a local vol surface fed directly from a matrix of local vols (rather than derived from a
-- Black vol surface, as 'localVolSurface' is) -- one flat strike grid shared across all dates,
-- same shape as 'blackVarianceSurface'.
fixedLocalVolSurface :: Day -> [Day] -- ^dates
  -> [Double] -- ^strikes
  -> Matrix Double -- ^localVolMatrix
  -> DayCounter
  -> FixedLocalVolSurfaceExtrapolation -- ^lowerExtrapolation
  -> FixedLocalVolSurfaceExtrapolation -- ^upperExtrapolation
  -> IO LocalVolTermStructure
fixedLocalVolSurface d ds s (Matrix mr mc md) = qlFixedLocalVolSurface d ds s mr mc md
{#fun qlFixedLocalVolSurface{withDay*`Day',withDayArray*`[Day]'&,withDoubleArray*`[Double]'&,fromIntegral`Word',fromIntegral`Word',withDoubleArrayRaw*`[Double]',withDayCounter*`DayCounter',`FixedLocalVolSurfaceExtrapolation',`FixedLocalVolSurfaceExtrapolation',preErrorCheck-`String'errorCheck*-}->`LocalVolTermStructure'peekLocalVolTermStructure*#}

-- |the local vol at a given date and underlying level, for any 'LocalVolTermStructure' (however
-- it was constructed) -- the only way to observe what a local vol surface actually computes.
{#fun qlLocalVolTermStructureLocalVol as localVol{withLocalVolTermStructure*`LocalVolTermStructure'
  ,withDay*`Day'
  ,`Double' -- ^underlyingLevel
  ,`Bool' -- ^extrapolate
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |Constant caplet volatility, no time-strike dependence
-- floating reference date, floating market data
{#fun qlConstantOptionletVol1 as constantOptionletVolatility'{fromIntegral`Word',withCalendar*`Calendar',`BusinessDayConvention',withQuote*`GenQuote q',withDayCounter*`DayCounter'
  ,`VolatilityType' -- ^type
  ,`Double' -- ^displacement
  ,preErrorCheck-`String'errorCheck*-}->`OptionletVolatilityStructure'peekOptionletVolatilityStructure*#}

-- |fixed reference date, floating market data
{#fun qlConstantOptionletVolatility as constantOptionletVolatility{withDay*`Day',withCalendar*`Calendar',`BusinessDayConvention',withQuote*`GenQuote q',withDayCounter*`DayCounter'
  ,`VolatilityType' -- ^type
  ,`Double' -- ^displacement
  ,preErrorCheck-`String'errorCheck*-}->`OptionletVolatilityStructure'peekOptionletVolatilityStructure*#}

-- |'Nothing' emits 'TimeUnit''s -1 sentinel (same convention as 'fromMaybeEnum'), since 'TimeUnit'
-- itself starts at 0 and can't self-sentinel -- used for 'optionletStripper1''s optionletFrequency.
fromMaybeEnumQuantity :: Maybe (Word, TimeUnit) -> (CInt, CInt)
fromMaybeEnumQuantity = maybe (0, -1) fromEnumQuantity

-- |Strips a 'CapFloorTermVolSurface' (quoted cap\/floor term vols) into caplet\/floorlet vols via
-- 'OptionletStripper1', immediately wrapping the result behind 'StrippedOptionletAdapter' in one
-- step -- 'OptionletStripper1' itself is never exposed as a Haskell type, since none of its own
-- getters (capFloorPrices\/capletVols\/etc.) are needed beyond feeding the adapter, per the "bind
-- few inspectors" rule.
{#fun qlOptionletStripper1 as optionletStripper1{withGenVolatilityTermStructure*`CapFloorTermVolSurface'
  ,withIborIndex*`GenIborIndex ibor'
  ,fromMaybeDouble`Maybe Double' -- ^switchStrikes
  ,`Double' -- ^accuracy
  ,fromIntegral`Word' -- ^maxIter
  ,withMaybeYieldTermStructure*`Maybe (GenYieldTermStructure y)' -- ^discount
  ,`VolatilityType' -- ^type
  ,`Double' -- ^displacement
  ,`Bool' -- ^dontThrow
  ,fromMaybeEnumQuantity`Maybe (Word, TimeUnit)'& -- ^optionletFrequency
  ,preErrorCheck-`String'errorCheck*-}->`OptionletVolatilityStructure'peekOptionletVolatilityStructure*#}

-- |An optionlet vol surface behind a relinkable handle. The result /is/ an
-- 'OptionletVolatilityStructure': pass it anywhere one is expected and everything built on it
-- keeps tracking whatever the handle currently points at, so a later 'linkOptionletVolTo'
-- reprices already-constructed instruments without rebuilding them. Mirrors
-- 'relinkableSwaptionVolatilityStructure'.
{#fun qlRelinkableOptionletVolatilityStructure as relinkableOptionletVolatilityStructure{withMaybeOptionletVolatilityStructure*`Maybe (GenOptionletVolatilityStructure ov)'
  ,preErrorCheck-`String'errorCheck*-}->`RelinkableOptionletVolatilityStructure'peekRelinkableOptionletVolatilityStructure*#}

-- |Point a relinkable optionlet vol handle at a different surface. Everything already built on
-- the handle reprices against the new surface, with no engine rebuilt. Named distinctly from
-- 'QuantLib.TermStructure.Yield.linkTo'\/'linkBlackVolTo'\/'linkSwaptionVolTo' for the same
-- reason as those: all four relinkable vol types live in this one module.
{#fun qlRelinkableOptionletVolatilityStructureLinkTo as linkOptionletVolTo{withRelinkableOptionletVolatilityStructure*`RelinkableOptionletVolatilityStructure'
  ,withOptionletVolatilityStructure*`GenOptionletVolatilityStructure ov',preErrorCheck-`String'errorCheck*-}->`()'#}

-- |A constant Black volatility, no time-strike dependence -- floating reference date, floating
-- market data
{#fun qlBlackConstantVol1 as blackConstantVol'{fromIntegral`Word',withCalendar*`Calendar',withQuote*`GenQuote q',withDayCounter*`DayCounter',preErrorCheck-`String'errorCheck*-}->`BlackVolTermStructure'peekBlackVolTermStructure*#}

-- |as 'blackConstantVol\'', but a fixed reference date
{#fun qlBlackConstantVol as blackConstantVol{withDay*`Day',withCalendar*`Calendar',withQuote*`GenQuote q',withDayCounter*`DayCounter',preErrorCheck-`String'errorCheck*-}->`BlackVolTermStructure'peekBlackVolTermStructure*#}

-- |A Black vol surface behind a relinkable handle. The result /is/ a 'BlackVolTermStructure':
-- pass it anywhere one is expected and everything built on it keeps tracking whatever the
-- handle currently points at, so a later 'linkBlackVolTo' reprices already-constructed
-- instruments without rebuilding them. Mirrors
-- 'QuantLib.TermStructure.Yield.relinkableYieldTermStructure'.
{#fun qlRelinkableBlackVolTermStructure as relinkableBlackVolTermStructure{withMaybeBlackVolTermStructure*`Maybe (GenBlackVolTermStructure bv)'
  ,preErrorCheck-`String'errorCheck*-}->`RelinkableBlackVolTermStructure'peekRelinkableBlackVolTermStructure*#}

-- |Point a relinkable Black vol handle at a different surface. Everything already built on the
-- handle reprices against the new surface, with no engine rebuilt. Mirrors
-- 'QuantLib.TermStructure.Yield.linkTo' -- see its haddock for why this mutator is justified.
{#fun qlRelinkableBlackVolTermStructureLinkTo as linkBlackVolTo{withRelinkableBlackVolTermStructure*`RelinkableBlackVolTermStructure'
  ,withBlackVolTermStructure*`GenBlackVolTermStructure bv',preErrorCheck-`String'errorCheck*-}->`()'#}

-- |fixed reference date, floating market data
{#fun qlConstantSwaptionVolatility1 as constantSwaptionVolatility'{withDay*`Day',withCalendar*`Calendar',`BusinessDayConvention',withQuote*`GenQuote q',withDayCounter*`DayCounter'
  ,`VolatilityType' -- ^type
  ,`Double' -- ^shift
  ,preErrorCheck-`String'errorCheck*-}->`SwaptionVolatilityStructure'peekSwaptionVolatilityStructure*#}

-- |floating reference date, floating market data
{#fun qlConstantSwaptionVolatility as constantSwaptionVolatility{fromIntegral`Word',withCalendar*`Calendar',`BusinessDayConvention',withQuote*`GenQuote q',withDayCounter*`DayCounter'
  ,`VolatilityType' -- ^type
  ,`Double' -- ^shift
  ,preErrorCheck-`String'errorCheck*-}->`SwaptionVolatilityStructure'peekSwaptionVolatilityStructure*#}

-- |returns the Black variance for a given option date and swap tenor
{#fun qlSwaptionVolatilityStructureBlackVariance1 as blackVarianceForPeriod'{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv'
  ,withDay*`Day' -- ^optionDate
  ,fromEnumQuantity`(Word,TimeUnit)'& -- ^swapTenor
  ,`Double' -- ^strike
  ,`Bool' -- ^extrapolate
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |returns the Black variance for a given option time and swap tenor
{#fun qlSwaptionVolatilityStructureBlackVariance2 as blackVarianceForPeriod{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv'
  ,`Double' -- optionTime
  ,fromEnumQuantity`(Word,TimeUnit)'& -- swapTenor
  ,`Double' -- ^strike
  ,`Bool' -- ^extrapolate
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |returns the Black variance for a given option tenor and swap length
{#fun qlSwaptionVolatilityStructureBlackVariance3 as blackVarianceForTenor{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv'
  ,fromEnumQuantity`(Word,TimeUnit)'& -- ^optionTenor
  ,`Double' -- ^swapLength
  ,`Double' -- ^strike
  ,`Bool' -- ^extrapolate
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |returns the Black variance for a given option date and swap length
{#fun qlSwaptionVolatilityStructureBlackVariance4 as blackVariance'{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv'
  ,withDay*`Day' -- ^optionDate
  ,`Double' -- ^swapLength
  ,`Double' -- ^strike
  ,`Bool' -- ^extrapolate
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |returns the Black variance for a given option time and swap length
{#fun qlSwaptionVolatilityStructureBlackVariance5 as blackVariance{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv'
  ,`Double' -- ^optionTime
  ,`Double' -- ^swapLength
  ,`Double' -- ^strike
  ,`Bool' -- ^extrapolate
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |returns the Black variance for a given option tenor and swap tenor
{#fun qlSwaptionVolatilityStructureBlackVariance as blackVarianceForPeriods{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv'
  ,fromEnumQuantity`(Word,TimeUnit)'& -- ^optionTenor
  ,fromEnumQuantity`(Word,TimeUnit)'& -- ^swapTenor
  ,`Double' -- ^strike
  ,`Bool' -- ^extrapolate
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |the largest swapLength for which the term structure can return vols
{#fun qlSwaptionVolatilityStructureMaxSwapLength as maxSwapLength{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv',preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |the largest length for which the term structure can return vols
{#fun qlSwaptionVolatilityStructureMaxSwapTenor as maxSwapTenor{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv',preEnum-`TimeUnit'peekEnum*,preErrorCheck-`String'errorCheck*-}->`Int'#}

-- |returns the smile for a given option date and swap tenor
{#fun qlSwaptionVolatilityStructureSmileSection1 as smileSectionForPeriod'{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv'
  ,withDay*`Day' -- ^optionDate
  ,fromEnumQuantity`(Word,TimeUnit)'& -- ^swapTenor
  ,`Bool' -- ^extrapolate
  ,preErrorCheck-`String'errorCheck*-}->`SmileSection'peekSmileSection*#}

-- |returns the smile for a given option time and swap tenor
{#fun qlSwaptionVolatilityStructureSmileSection2 as smileSectionForPeriod{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv'
  ,`Double' -- ^optionTime
  ,fromEnumQuantity`(Word,TimeUnit)'& -- ^swapTenor
  ,`Bool' -- ^extrapolate
  ,preErrorCheck-`String'errorCheck*-}->`SmileSection'peekSmileSection*#}

-- |returns the smile for a given option tenor and swap length
{#fun qlSwaptionVolatilityStructureSmileSection3 as smileSectionForTenor{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv'
  ,fromEnumQuantity`(Word,TimeUnit)'& -- ^optionTenor
  ,`Double' -- ^swapLength
  ,`Bool' -- ^extrapolate
  ,preErrorCheck-`String'errorCheck*-}->`SmileSection'peekSmileSection*#}

-- |returns the smile for a given option date and swap length
{#fun qlSwaptionVolatilityStructureSmileSection4 as smileSection'{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv'
  ,withDay*`Day' -- ^optionDate
  ,`Double' -- ^swapLength
  ,`Bool' -- ^extr
  ,preErrorCheck-`String'errorCheck*-}->`SmileSection'peekSmileSection*#}

-- |returns the smile for a given option time and swap length
{#fun qlSwaptionVolatilityStructureSmileSection5 as smileSection{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv'
  ,`Double' -- ^optionTime
  ,`Double' -- ^swapLength
  ,`Bool' -- ^extr
  ,preErrorCheck-`String'errorCheck*-}->`SmileSection'peekSmileSection*#}

-- |returns the smile for a given option tenor and swap tenor
{#fun qlSwaptionVolatilityStructureSmileSection as smileSectionForPeriods{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv'
  ,fromEnumQuantity`(Word,TimeUnit)'& -- ^optionTenor
  ,fromEnumQuantity`(Word,TimeUnit)'& -- ^swapTenor
  ,`Bool' -- ^extr
  ,preErrorCheck-`String'errorCheck*-}->`SmileSection'peekSmileSection*#}

-- |a smile section built directly from SABR parameters (Hagan et al. 2002), rather than
-- interpolated from a 'SwaptionVolatilityStructure'
{#fun qlSabrSmileSection as sabrSmileSection{`Double' -- ^timeToExpiry
  ,`Double' -- ^forward
  ,`Double' -- ^alpha
  ,`Double' -- ^beta
  ,`Double' -- ^nu
  ,`Double' -- ^rho
  ,`Double' -- ^shift
  ,`VolatilityType' -- ^volatilityType
  ,preErrorCheck-`String'errorCheck*-}->`SmileSection'peekSmileSection*#}

-- |as 'sabrSmileSection', but the time to expiry is derived from a date, reference date and day
-- counter rather than given directly
{#fun qlSabrSmileSection1 as sabrSmileSection'{withDay*`Day' -- ^optionDate
  ,`Double' -- ^forward
  ,`Double' -- ^alpha
  ,`Double' -- ^beta
  ,`Double' -- ^nu
  ,`Double' -- ^rho
  ,withMaybeDay*`Maybe Day' -- ^referenceDate
  ,withDayCounter*`DayCounter'
  ,`Double' -- ^shift
  ,`VolatilityType' -- ^volatilityType
  ,preErrorCheck-`String'errorCheck*-}->`SmileSection'peekSmileSection*#}

-- |an arbitrage-free SABR smile section (Doust's approach via 'NoArbSabrSmileSection'), built
-- directly from SABR parameters like 'sabrSmileSection' but guaranteeing a proper terminal density
{#fun qlNoArbSabrSmileSection as noArbSabrSmileSection{`Double' -- ^timeToExpiry
  ,`Double' -- ^forward
  ,`Double' -- ^alpha
  ,`Double' -- ^beta
  ,`Double' -- ^nu
  ,`Double' -- ^rho
  ,`Double' -- ^shift
  ,`VolatilityType' -- ^volatilityType
  ,preErrorCheck-`String'errorCheck*-}->`SmileSection'peekSmileSection*#}

-- |as 'noArbSabrSmileSection', but the time to expiry is derived from a date and day counter
-- rather than given directly
{#fun qlNoArbSabrSmileSection1 as noArbSabrSmileSection'{withDay*`Day' -- ^optionDate
  ,`Double' -- ^forward
  ,`Double' -- ^alpha
  ,`Double' -- ^beta
  ,`Double' -- ^nu
  ,`Double' -- ^rho
  ,withDayCounter*`DayCounter'
  ,`Double' -- ^shift
  ,`VolatilityType' -- ^volatilityType
  ,preErrorCheck-`String'errorCheck*-}->`SmileSection'peekSmileSection*#}

-- |the volatility for the given strike, for any 'SmileSection' (however it was constructed)
{#fun qlSmileSectionVolatility as smileSectionVolatility{withSmileSection*`SmileSection'
  ,`Double' -- ^strike
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |the Black variance for the given strike, for any 'SmileSection' (however it was constructed)
{#fun qlSmileSectionVariance as smileSectionVariance{withSmileSection*`SmileSection'
  ,`Double' -- ^strike
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |the ATM level baked into the 'SmileSection' at construction (or later re-anchored via
-- 'atmSmileSection'), for any 'SmileSection' (however it was constructed)
{#fun qlSmileSectionAtmLevel as smileSectionAtmLevel{withSmileSection*`SmileSection'
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |a flat-volatility smile section: 'volatility' returns @vol@ for every strike.
-- 'Nothing'\/'Nothing' reproduce upstream's own defaults for @referenceDate@\/@atmLevel@.
{#fun qlFlatSmileSection as flatSmileSection{withDay*`Day'
  ,`Double' -- ^vol
  ,withDayCounter*`DayCounter'
  ,withMaybeDay*`Maybe Day' -- ^referenceDate
  ,fromMaybeDouble`Maybe Double' -- ^atmLevel
  ,`VolatilityType' -- ^type
  ,`Double' -- ^shift
  ,preErrorCheck-`String'errorCheck*-}->`SmileSection'peekSmileSection*#}

-- |a 'SmileSection' whose volatility at every strike is @source@'s plus @spread@ (which may
-- change over time, since it's a live 'GenQuote' rather than a fixed number)
{#fun qlSpreadedSmileSection as spreadedSmileSection{withSmileSection*`SmileSection'
  ,withQuote*`GenQuote q'
  ,preErrorCheck-`String'errorCheck*-}->`SmileSection'peekSmileSection*#}

-- |@source@ re-anchored to a different ATM level ('Nothing' reproduces upstream's own default,
-- which recomputes the ATM level from @source@ itself). @source@'s volatility at every other
-- strike is unchanged -- use 'smileSectionAtmLevel' to observe what this changed.
{#fun qlAtmSmileSection as atmSmileSection{withSmileSection*`SmileSection'
  ,fromMaybeDouble`Maybe Double' -- ^atm
  ,preErrorCheck-`String'errorCheck*-}->`SmileSection'peekSmileSection*#}

-- |a smile section calibrated to a market smile (strikes/vols given directly, not as live
-- quotes -- calibration runs once, eagerly, at construction). alpha\/beta\/nu\/rho\/vegaWeighted
-- are the SABR calibration's initial guess and fixed\/free flags; endCriteria\/optimization
-- method are left at QuantLib's own internal defaults (a raw, Haskell-finalized EndCriteria or
-- OptimizationMethod handle can't safely be stored for this object's full lifetime -- see the
-- qlXxxFitting comment in "QuantLib.Internal.Enum" for the same ownership hazard elsewhere).
sabrInterpolatedSmileSection :: Day -- ^optionDate
  -> GenQuote q1 -- ^forward
  -> [Double] -- ^strikes
  -> Bool -- ^hasFloatingStrikes
  -> GenQuote q2 -- ^atmVolatility
  -> [GenQuote q3] -- ^vols
  -> Double -- ^alpha
  -> Double -- ^beta
  -> Double -- ^nu
  -> Double -- ^rho
  -> SabrInterpolatedSmileSectionOpts -> IO SabrInterpolatedSmileSection
sabrInterpolatedSmileSection optionDate forward strikes hasFloatingStrikes atmVolatility vols
  alpha beta nu rho opts = do
  dc <- maybe (dayCounter Actual365FixedStandard) return (sabrDayCounter opts)
  sabrInterpolatedSmileSection_ optionDate forward strikes hasFloatingStrikes atmVolatility vols
    alpha beta nu rho (sabrIsAlphaFixed opts) (sabrIsBetaFixed opts) (sabrIsNuFixed opts)
    (sabrIsRhoFixed opts) (sabrVegaWeighted opts) dc (sabrShift opts)

{#fun qlSabrInterpolatedSmileSection as sabrInterpolatedSmileSection_{withDay*`Day'
  ,withQuote*`GenQuote q1' -- ^forward
  ,withDoubleArray*`[Double]'& -- ^strikes
  ,`Bool' -- ^hasFloatingStrikes
  ,withQuote*`GenQuote q2' -- ^atmVolatility
  ,withQuoteArray*`[GenQuote q3]'& -- ^vols
  ,`Double' -- ^alpha
  ,`Double' -- ^beta
  ,`Double' -- ^nu
  ,`Double' -- ^rho
  ,`Bool' -- ^isAlphaFixed
  ,`Bool' -- ^isBetaFixed
  ,`Bool' -- ^isNuFixed
  ,`Bool' -- ^isRhoFixed
  ,`Bool' -- ^vegaWeighted
  ,withDayCounter*`DayCounter'
  ,`Double' -- ^shift
  ,preErrorCheck-`String'errorCheck*-}->`SabrInterpolatedSmileSection'peekSabrInterpolatedSmileSection*#}

-- |upcast to the generic 'SmileSection' interface (e.g. for 'smileSectionVolatility'\/'smileSectionVariance').
-- A fresh-@shared_ptr@ upcast, always safe -- not the reverse (downcast) direction.
{#fun qlSabrInterpolatedSmileSectionAsSmileSection as sabrInterpolatedSmileSectionAsSmileSection{withSabrInterpolatedSmileSection*`SabrInterpolatedSmileSection',preErrorCheck-`String'errorCheck*-}->`SmileSection'peekSmileSection*#}

-- |calibrated alpha (post-fit; can differ from the initial guess passed to
-- 'sabrInterpolatedSmileSection' unless @sabrIsAlphaFixed@ was set).
{#fun qlSabrInterpolatedSmileSectionAlpha as sabrInterpolatedSmileSectionAlpha{withSabrInterpolatedSmileSection*`SabrInterpolatedSmileSection',preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |calibrated beta, see 'sabrInterpolatedSmileSectionAlpha'
{#fun qlSabrInterpolatedSmileSectionBeta as sabrInterpolatedSmileSectionBeta{withSabrInterpolatedSmileSection*`SabrInterpolatedSmileSection',preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |calibrated nu, see 'sabrInterpolatedSmileSectionAlpha'
{#fun qlSabrInterpolatedSmileSectionNu as sabrInterpolatedSmileSectionNu{withSabrInterpolatedSmileSection*`SabrInterpolatedSmileSection',preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |calibrated rho, see 'sabrInterpolatedSmileSectionAlpha'
{#fun qlSabrInterpolatedSmileSectionRho as sabrInterpolatedSmileSectionRho{withSabrInterpolatedSmileSection*`SabrInterpolatedSmileSection',preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |root-mean-square calibration error
{#fun qlSabrInterpolatedSmileSectionRmsError as sabrInterpolatedSmileSectionRmsError{withSabrInterpolatedSmileSection*`SabrInterpolatedSmileSection',preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |maximum calibration error
{#fun qlSabrInterpolatedSmileSectionMaxError as sabrInterpolatedSmileSectionMaxError{withSabrInterpolatedSmileSection*`SabrInterpolatedSmileSection',preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |the reason the SABR calibration's optimizer stopped
{#fun qlSabrInterpolatedSmileSectionEndCriteria as sabrInterpolatedSmileSectionEndCriteria{withSabrInterpolatedSmileSection*`SabrInterpolatedSmileSection',preErrorCheck-`String'errorCheck*-}->`EndCriteriaType'#}

-- |implements the conversion between swap dates and swap (time) length
{#fun qlSwaptionVolatilityStructureSwapLength1 as swapLength'{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv'
  ,withDay*`Day' -- ^start
  ,withDay*`Day' -- ^end
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |implements the conversion between swap tenor and swap (time) length
{#fun qlSwaptionVolatilityStructureSwapLength as swapLength{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv',fromEnumQuantity`(Word,TimeUnit)'&,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |returns the volatility for a given option date and swap tenor
{#fun qlSwaptionVolatilityStructureVolatility1 as volatilityForPeriod'{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv'
  ,withDay*`Day' -- ^optionDate
  ,fromEnumQuantity`(Word,TimeUnit)'& -- ^swapTenor
  ,`Double' -- ^strike
  ,`Bool' -- ^extrapolate
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |returns the volatility for a given option time and swap tenor
{#fun qlSwaptionVolatilityStructureVolatility2 as volatilityForPeriod{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv'
  ,`Double' -- ^optionTime
  ,fromEnumQuantity`(Word,TimeUnit)'& -- ^swapTenor
  ,`Double' -- ^strike
  ,`Bool' -- ^extrapolate
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |returns the volatility for a given option tenor and swap length
{#fun qlSwaptionVolatilityStructureVolatility3 as volatilityForTenor{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv'
  ,fromEnumQuantity`(Word,TimeUnit)'& -- ^optionTenor
  ,`Double' -- ^swapLength
  ,`Double' -- ^strike
  ,`Bool' -- ^extrapolate
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |returns the volatility for a given option date and swap length
{#fun qlSwaptionVolatilityStructureVolatility4 as volatilityForTenor'{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv'
  ,withDay*`Day' -- ^optionDate
  ,`Double' -- ^swapLength
  ,`Double' -- ^strike
  ,`Bool' -- ^extrapolate
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |returns the volatility for a given option time and swap length
{#fun qlSwaptionVolatilityStructureVolatility5 as volatility{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv'
  ,`Double' -- ^optionTime
  ,`Double' -- ^swapLength
  ,`Double' -- ^strike
  ,`Bool' -- ^extrapolate
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |returns the volatility for a given option tenor and swap tenor
{#fun qlSwaptionVolatilityStructureVolatility as volatilityForPeriods{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv'
  ,fromEnumQuantity`(Word,TimeUnit)'& -- ^optionTenor
  ,fromEnumQuantity`(Word,TimeUnit)'& -- ^swapTenor
  ,`Double' -- ^strike
  ,`Bool' -- ^extrapolate
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |A constant callable-bond volatility, no time-strike dependence -- floating reference date,
-- floating market data
{#fun qlCallableBondConstantVolatility1 as callableBondConstantVolatility'{fromIntegral`Word',withCalendar*`Calendar',withQuote*`GenQuote q',withDayCounter*`DayCounter',preErrorCheck-`String'errorCheck*-}->`CallableBondVolatilityStructure'peekCallableBondVolatilityStructure*#}

-- |as 'callableBondConstantVolatility\'', but a fixed reference date
{#fun qlCallableBondConstantVolatility as callableBondConstantVolatility{withDay*`Day',withQuote*`GenQuote q',withDayCounter*`DayCounter',preErrorCheck-`String'errorCheck*-}->`CallableBondVolatilityStructure'peekCallableBondVolatilityStructure*#}

-- |fixed reference date, floating market data
{#fun qlConstantCapFloorTermVolatility1 as constantCapFloorTermVolatility'{withDay*`Day',withCalendar*`Calendar',`BusinessDayConvention',withQuote*`GenQuote q',withDayCounter*`DayCounter',preErrorCheck-`String'errorCheck*-}->`VolatilityTermStructure'peekVolatilityTermStructure*#}

-- |floating reference date, floating market data
{#fun qlConstantCapFloorTermVolatility as constantCapFloorTermVolatility{fromIntegral`Word',withCalendar*`Calendar',`BusinessDayConvention',withQuote*`GenQuote q',withDayCounter*`DayCounter',preErrorCheck-`String'errorCheck*-}->`VolatilityTermStructure'peekVolatilityTermStructure*#}

-- |A 'SwaptionVolatilityStructure' whose volatility at every point is @source@'s plus @spread@
-- (which may change over time, since it's a live 'GenQuote' rather than a fixed number)
{#fun qlSpreadedSwaptionVolatility as spreadedSwaptionVolatility{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv',withQuote*`GenQuote q',preErrorCheck-`String'errorCheck*-}->`SwaptionVolatilityStructure'peekSwaptionVolatilityStructure*#}

-- |as 'spreadedSwaptionVolatility', for 'OptionletVolatilityStructure' rather than
-- 'SwaptionVolatilityStructure'
{#fun qlSpreadedOptionletVolatility as spreadedOptionletVol{withOptionletVolatilityStructure*`GenOptionletVolatilityStructure ov',withQuote*`GenQuote q',preErrorCheck-`String'errorCheck*-}->`OptionletVolatilityStructure'peekOptionletVolatilityStructure*#}

-- |A swaption vol surface behind a relinkable handle. The result /is/ a
-- 'SwaptionVolatilityStructure': pass it anywhere one is expected and everything built on it
-- keeps tracking whatever the handle currently points at, so a later 'linkSwaptionVolTo'
-- reprices already-constructed instruments without rebuilding them. Mirrors
-- 'QuantLib.TermStructure.Yield.relinkableYieldTermStructure'.
{#fun qlRelinkableSwaptionVolatilityStructure as relinkableSwaptionVolatilityStructure{withMaybeSwaptionVolatilityStructure*`Maybe (GenSwaptionVolatilityStructure sv)'
  ,preErrorCheck-`String'errorCheck*-}->`RelinkableSwaptionVolatilityStructure'peekRelinkableSwaptionVolatilityStructure*#}

-- |Point a relinkable swaption vol handle at a different surface. Everything already built on
-- the handle reprices against the new surface, with no engine rebuilt. Named distinctly from
-- 'QuantLib.TermStructure.Yield.linkTo' and 'linkBlackVolTo' because
-- 'BlackVolTermStructure'\/'SwaptionVolatilityStructure'\/'OptionletVolatilityStructure' all
-- live in this one module and a bare 'linkTo' per type would collide with its own siblings,
-- not just with 'Yield.chs'\/'Quote.chs'.
{#fun qlRelinkableSwaptionVolatilityStructureLinkTo as linkSwaptionVolTo{withRelinkableSwaptionVolatilityStructure*`RelinkableSwaptionVolatilityStructure'
  ,withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv',preErrorCheck-`String'errorCheck*-}->`()'#}

-- |A constant local volatility, no time-asset dependence -- floating reference date, floating
-- market data. Local and Black volatility coincide when volatility is at most time dependent, so
-- this is effectively a proxy for 'blackConstantVol''.
{#fun qlLocalConstantVol1 as localConstantVol'{fromIntegral`Word',withCalendar*`Calendar',withQuote*`GenQuote q',withDayCounter*`DayCounter',preErrorCheck-`String'errorCheck*-}->`LocalVolTermStructure'peekLocalVolTermStructure*#}

-- |as 'localConstantVol\'', but a fixed reference date
{#fun qlLocalConstantVol as localConstantVol{withDay*`Day',withQuote*`GenQuote q',withDayCounter*`DayCounter',preErrorCheck-`String'errorCheck*-}->`LocalVolTermStructure'peekLocalVolTermStructure*#}

-- |a local vol term structure derived from a 'BlackVarianceCurve' (no strike dependence): local
-- vol at time @t@ is the derivative of the Black variance curve's total variance
{#fun qlLocalVolCurve as localVolCurve{withBlackVarianceCurve*`BlackVarianceCurve',preErrorCheck-`String'errorCheck*-}->`LocalVolTermStructure'peekLocalVolTermStructure*#}

-- |@origTS@ re-anchored to a new reference date, tracking @origTS@ for later changes. Only
-- financially sensible for a time-dependent (not asset-dependent) source structure.
{#fun qlImpliedVolTermStructure as impliedVolTermStructure{withBlackVolTermStructure*`GenBlackVolTermStructure bv',withDay*`Day',preErrorCheck-`String'errorCheck*-}->`BlackVolTermStructure'peekBlackVolTermStructure*#}

-- |fixed reference date, floating market data
capFloorTermVolCurve' :: Day -> Calendar -> BusinessDayConvention -> [(Word, TimeUnit, GenQuote q)] -> DayCounter -> IO VolatilityTermStructure
capFloorTermVolCurve' d c bd ntq = qlCapFloorTermVolCurve1 d c bd n t q where (n, t, q) = unzip3 ntq
{#fun qlCapFloorTermVolCurve1{withDay*`Day',withCalendar*`Calendar',`BusinessDayConvention',withIntArray*`[Word]'&,withEnumArray*`[TimeUnit]'&,withQuoteArray*`[GenQuote q]'&,withDayCounter*`DayCounter',preErrorCheck-`String'errorCheck*-}->`VolatilityTermStructure'peekVolatilityTermStructure*#}

-- |floating reference date, floating market data
capFloorTermVolCurve :: Word -> Calendar -> BusinessDayConvention -> [(Word, TimeUnit, GenQuote q)] -> DayCounter -> IO VolatilityTermStructure
capFloorTermVolCurve d c bd ntq = qlCapFloorTermVolCurve d c bd n t q where (n, t, q) = unzip3 ntq
{#fun qlCapFloorTermVolCurve{fromIntegral`Word',withCalendar*`Calendar',`BusinessDayConvention',withIntArray*`[Word]'&,withEnumArray*`[TimeUnit]'&,withQuoteArray*`[GenQuote q]'&,withDayCounter*`DayCounter',preErrorCheck-`String'errorCheck*-}->`VolatilityTermStructure'peekVolatilityTermStructure*#}

-- |A Black volatility curve built from time-dependent (ATM) market vols, interpolating on total
-- variance (linear by default, or the given 'Interpolation') -- no strike dependence; see
-- 'blackVarianceSurface' for that.
blackVarianceCurve :: Day -> [(Day, Double)] -> DayCounter -> Bool -- ^forceMonotoneVariance
  -> Maybe Interpolation -> IO BlackVarianceCurve
blackVarianceCurve d dq dc f i = uncurryNested (qlBlackVarianceCurve d dd q dc f) (qlInterpolation' i) where (dd, q) = unzip dq
{#fun qlBlackVarianceCurve{withDay*`Day',withDayArray*`[Day]'&,withDoubleArray*`[Double]'&,withDayCounter*`DayCounter',`Bool',`Int',`Int',`Int',preErrorCheck-`String'errorCheck*-}->`BlackVarianceCurve'peekBlackVarianceCurve*#}

-- |The @interpolator@ is applied through @BlackVarianceSurface::setInterpolation@ right after
-- construction; 'Bilinear' reproduces upstream's default. Both interpolators reproduce
-- @blackVolMatrix@ exactly at its own (date, strike) nodes -- they only differ between them.
blackVarianceSurface :: Day -> Calendar -> [Day] -- ^dates
  -> [Double] -- ^strikes
  -> Matrix Double -- ^blackVolMatrix
  -> DayCounter
  -> BlackVarianceSurfaceExtrapolation -- ^lowerExtrapolation
  -> BlackVarianceSurfaceExtrapolation -- ^upperExtrapolation
  -> Interpolation2D -- ^interpolator
  -> IO BlackVolTermStructure
blackVarianceSurface d c ds s (Matrix mr mc md) = qlBlackVarianceSurface d c ds s mr mc md
{#fun qlBlackVarianceSurface{withDay*`Day',withCalendar*`Calendar',withDayArray*`[Day]'&,withDoubleArray*`[Double]'&,fromIntegral`Word',fromIntegral`Word',withDoubleArrayRaw*`[Double]',withDayCounter*`DayCounter',`BlackVarianceSurfaceExtrapolation',`BlackVarianceSurfaceExtrapolation',fromEnumC`Interpolation2D',preErrorCheck-`String'errorCheck*-}->`BlackVolTermStructure'peekBlackVolTermStructure*#}

-- |Builds a Black volatility surface from a rectangular vol grid via
-- 'PiecewiseBlackVarianceSurface::makeFromGrid': one interpolated smile section per date
-- column, linear in total variance between columns -- a fixed interpolation scheme, unlike
-- 'blackVarianceSurface''s configurable 2-D interpolator.
piecewiseBlackVarianceSurface :: Day -> [Day] -- ^dates
  -> [Double] -- ^strikes
  -> Matrix Double -- ^blackVols
  -> DayCounter
  -> IO BlackVolTermStructure
piecewiseBlackVarianceSurface d ds s (Matrix mr mc md) dc = qlPiecewiseBlackVarianceSurface d ds s mr mc md dc
{#fun qlPiecewiseBlackVarianceSurface{withDay*`Day',withDayArray*`[Day]'&,withDoubleArray*`[Double]'&,fromIntegral`Word',fromIntegral`Word',withDoubleArrayRaw*`[Double]',withDayCounter*`DayCounter',preErrorCheck-`String'errorCheck*-}->`BlackVolTermStructure'peekBlackVolTermStructure*#}

-- |A Black volatility surface parameterized by market deltas (put\/call deltas and, optionally,
-- an ATM quote) rather than fixed strikes -- the standard FX vol quoting convention. Constructed
-- with upstream's own defaults for the trailing options; use 'blackVolatilitySurfaceDeltaFull'
-- to override them.
blackVolatilitySurfaceDelta :: Day -> [Day] -- ^dates
  -> [Double] -- ^putDeltas
  -> [Double] -- ^callDeltas
  -> Bool -- ^hasAtm
  -> Matrix Double -- ^blackVolMatrix
  -> DayCounter -> Calendar -> GenQuote q -- ^spot
  -> GenYieldTermStructure y1 -- ^domesticTS
  -> GenYieldTermStructure y2 -- ^foreignTS
  -> IO BlackVolatilitySurfaceDelta
blackVolatilitySurfaceDelta d ds pd cd hasAtm (Matrix mr mc md) dc cal spot dts fts =
  blackVolatilitySurfaceDelta_ d ds pd cd hasAtm mr mc md dc cal spot dts fts
    Spot AtmDeltaNeutral Nothing SmileLinear False FlatVolatility (0, Days) Fwd AtmDeltaNeutral Nothing

-- |As 'blackVolatilitySurfaceDelta', but takes a 'BlackVolatilitySurfaceDeltaOpts' record for
-- the trailing options instead of hardcoding upstream's defaults.
blackVolatilitySurfaceDeltaFull :: Day -> [Day] -> [Double] -> [Double] -> Bool -> Matrix Double
  -> DayCounter -> Calendar -> GenQuote q -> GenYieldTermStructure y1 -> GenYieldTermStructure y2
  -> BlackVolatilitySurfaceDeltaOpts -> IO BlackVolatilitySurfaceDelta
blackVolatilitySurfaceDeltaFull d ds pd cd hasAtm (Matrix mr mc md) dc cal spot dts fts opts =
  blackVolatilitySurfaceDelta_ d ds pd cd hasAtm mr mc md dc cal spot dts fts
    (bvsdDeltaType opts) (bvsdAtmType opts) (bvsdAtmDeltaType opts)
    (bvsdInterpolationMethod opts) (bvsdFlatStrikeExtrapolation opts) (bvsdTimeExtrapolationType opts)
    (bvsdSwitchTenor opts) (bvsdLongTermDeltaType opts) (bvsdLongTermAtmType opts) (bvsdLongTermAtmDeltaType opts)

{#fun qlBlackVolatilitySurfaceDelta as blackVolatilitySurfaceDelta_{withDay*`Day',withDayArray*`[Day]'&
  ,withDoubleArray*`[Double]'& -- ^putDeltas
  ,withDoubleArray*`[Double]'& -- ^callDeltas
  ,`Bool' -- ^hasAtm
  ,fromIntegral`Word',fromIntegral`Word',withDoubleArrayRaw*`[Double]' -- ^blackVolMatrix
  ,withDayCounter*`DayCounter',withCalendar*`Calendar',withQuote*`GenQuote q' -- ^spot
  ,withYieldTermStructure*`GenYieldTermStructure y1' -- ^domesticTS
  ,withYieldTermStructure*`GenYieldTermStructure y2' -- ^foreignTS
  ,fromEnumC`DeltaType' -- ^deltaType
  ,fromEnumC`AtmType' -- ^atmType
  ,fromMaybeEnum`Maybe DeltaType' -- ^atmDeltaType
  ,fromEnumC`SmileInterpolationMethod' -- ^interpolationMethod
  ,`Bool' -- ^flatStrikeExtrapolation
  ,fromEnumC`BlackVolTimeExtrapolationType' -- ^timeExtrapolationType
  ,fromEnumQuantity`(Int,TimeUnit)'& -- ^switchTenor
  ,fromEnumC`DeltaType' -- ^longTermDeltaType
  ,fromEnumC`AtmType' -- ^longTermAtmType
  ,fromMaybeEnum`Maybe DeltaType' -- ^longTermAtmDeltaType
  ,preErrorCheck-`String'errorCheck*-}->`BlackVolatilitySurfaceDelta'peekBlackVolatilitySurfaceDelta*#}

-- |The Black vol smile at a given time to expiry (year fraction from the reference date), built
-- by interpolating\/extrapolating the delta-quoted surface. The returned 'SmileSection' does not
-- track later changes to the surface's spot\/curve handles -- recreate it if those change.
{#fun qlBlackVolatilitySurfaceDeltaSmile1 as blackVolSmile{withBlackVolatilitySurfaceDelta*`BlackVolatilitySurfaceDelta'
  ,`Double' -- ^t
  ,preErrorCheck-`String'errorCheck*-}->`SmileSection'peekSmileSection*#}

-- |As 'blackVolSmile', for a given expiry 'Day' instead of a year fraction.
{#fun qlBlackVolatilitySurfaceDeltaSmile as blackVolSmile'{withBlackVolatilitySurfaceDelta*`BlackVolatilitySurfaceDelta'
  ,withDay*`Day' -- ^d
  ,preErrorCheck-`String'errorCheck*-}->`SmileSection'peekSmileSection*#}

-- |floating reference date, floating market data
capFloorTermVolSurface :: Word -> Calendar -> BusinessDayConvention -> [(Word, TimeUnit)] -- ^optionTenors
  -> [Double] -- ^strikes
  -> Matrix (GenQuote q) -- ^volatilities
  -> DayCounter -> IO CapFloorTermVolSurface
capFloorTermVolSurface d c bd t s (Matrix mr mc md) = qlCapFloorTermVolSurface d c bd pl pu s mr mc md where (pl, pu) = unzip t
{#fun qlCapFloorTermVolSurface{fromIntegral`Word',withCalendar*`Calendar',`BusinessDayConvention',withIntArray*`[Word]'&,withEnumArray*`[TimeUnit]'&,withDoubleArray*`[Double]'&,fromIntegral`Word',fromIntegral`Word',withQuoteArrayRaw*`[GenQuote q]',withDayCounter*`DayCounter',preErrorCheck-`String'errorCheck*-}->`CapFloorTermVolSurface'peekCapFloorTermVolSurface*#}

-- |fixed reference date, floating market data
capFloorTermVolSurface' :: Day -> Calendar -> BusinessDayConvention -> [(Word, TimeUnit)] -- ^optionTenors
  -> [Double] -- ^strikes
  -> Matrix (GenQuote q) -- ^volatilities
  -> DayCounter -> IO CapFloorTermVolSurface
capFloorTermVolSurface' d c bd t s (Matrix mr mc md) = qlCapFloorTermVolSurface1 d c bd pl pu s mr mc md where (pl, pu) = unzip t
{#fun qlCapFloorTermVolSurface1{withDay*`Day',withCalendar*`Calendar',`BusinessDayConvention',withIntArray*`[Word]'&,withEnumArray*`[TimeUnit]'&,withDoubleArray*`[Double]'&,fromIntegral`Word',fromIntegral`Word',withQuoteArrayRaw*`[GenQuote q]',withDayCounter*`DayCounter',preErrorCheck-`String'errorCheck*-}->`CapFloorTermVolSurface'peekCapFloorTermVolSurface*#}

-- |fixed reference date, floating market data. Pass an empty 'Matrix' (@Matrix 0 0 []@) for @shifts@
-- when no shift is needed -- upstream treats a zero-row shift matrix as all-zero.
swaptionVolatilityMatrix' :: Day -> Calendar -> BusinessDayConvention
  -> [(Word, TimeUnit)] -- ^optionTenors
  -> [(Word, TimeUnit)] -- ^swapTenors
  -> Matrix (GenQuote q) -- ^volatilities
  -> DayCounter
  -> Bool -- ^flatExtrapolation
  -> VolatilityType
  -> Matrix Double -- ^shifts
  -> IO SwaptionVolatilityStructure
swaptionVolatilityMatrix' d c bdc ot st (Matrix vr vc vd) dc' fe ty (Matrix sr sc sd) =
  qlSwaptionVolatilityMatrix d c bdc opl opu spl spu vr vc vd dc' fe ty sr sc sd
  where (opl, opu) = unzip ot; (spl, spu) = unzip st
{#fun qlSwaptionVolatilityMatrix{withDay*`Day',withCalendar*`Calendar',`BusinessDayConvention'
  ,withIntArray*`[Word]'&,withEnumArray*`[TimeUnit]'&
  ,withIntArray*`[Word]'&,withEnumArray*`[TimeUnit]'&
  ,fromIntegral`Word',fromIntegral`Word',withQuoteArrayRaw*`[GenQuote q]'
  ,withDayCounter*`DayCounter',`Bool',`VolatilityType'
  ,fromIntegral`Word',fromIntegral`Word',withDoubleArrayRaw*`[Double]'
  ,preErrorCheck-`String'errorCheck*-}->`SwaptionVolatilityStructure'peekSwaptionVolatilityStructure*#}

-- |floating reference date, floating market data. See 'swaptionVolatilityMatrix\'' for the
-- @shifts@ convention (@Matrix 0 0 []@ for "no shift").
swaptionVolatilityMatrix :: Calendar -> BusinessDayConvention
  -> [(Word, TimeUnit)] -- ^optionTenors
  -> [(Word, TimeUnit)] -- ^swapTenors
  -> Matrix (GenQuote q) -- ^volatilities
  -> DayCounter
  -> Bool -- ^flatExtrapolation
  -> VolatilityType
  -> Matrix Double -- ^shifts
  -> IO SwaptionVolatilityStructure
swaptionVolatilityMatrix c bdc ot st (Matrix vr vc vd) dc' fe ty (Matrix sr sc sd) =
  qlSwaptionVolatilityMatrix1 c bdc opl opu spl spu vr vc vd dc' fe ty sr sc sd
  where (opl, opu) = unzip ot; (spl, spu) = unzip st
{#fun qlSwaptionVolatilityMatrix1{withCalendar*`Calendar',`BusinessDayConvention'
  ,withIntArray*`[Word]'&,withEnumArray*`[TimeUnit]'&
  ,withIntArray*`[Word]'&,withEnumArray*`[TimeUnit]'&
  ,fromIntegral`Word',fromIntegral`Word',withQuoteArrayRaw*`[GenQuote q]'
  ,withDayCounter*`DayCounter',`Bool',`VolatilityType'
  ,fromIntegral`Word',fromIntegral`Word',withDoubleArrayRaw*`[Double]'
  ,preErrorCheck-`String'errorCheck*-}->`SwaptionVolatilityStructure'peekSwaptionVolatilityStructure*#}

-- |A SABR-calibrated swaption volatility cube: fits a SABR smile at every (option tenor, swap
-- tenor) node from an ATM surface plus a grid of vol spreads. The result /is/ a
-- 'SwaptionVolatilityStructure' -- pass it anywhere one is expected (pricing engines,
-- 'smileSection'\/'volatilityForPeriod''\/etc.) -- but its own extra getters
-- ('sparseSabrParameters', 'denseSabrParameters', 'marketVolCube', 'volCubeAtmCalibrated',
-- 'sabrSwaptionVolatilityCubeAtmStrike'\/'\'') only accept this concrete type, not the generic one.
--
-- @endCriteria@\/@optMethod@ are not exposed: 'SabrSwaptionVolatilityCube' stores them as
-- @shared_ptr@ members for its full lifetime, and hasquant's 'EndCriteria'\/'OptimizationMethod'
-- handles are raw, Haskell-finalized pointers rather than @shared_ptr@ boxes -- the same ownership
-- hazard already avoided for 'sabrInterpolatedSmileSection' and
-- 'QuantLib.TermStructure.Yield.fittedBondDiscountCurve''s fitting methods. Upstream's internal
-- Levenberg-Marquardt\/EndCriteria defaults apply at every calibrated node instead.
--
-- @volSpreads@ and @parametersGuess@ are both flattened over the (optionTenor x swapTenor)
-- product as the *outer* index (row = j*nSwapTenors+k, j over @optionTenors@, k over
-- @swapTenors@) -- not one row per @optionTenor@ the way 'swaptionVolatilityMatrix'''s grid is:
-- @matrixRows == length optionTenors * length swapTenors@ for both. @volSpreads@'s columns are
-- one per @strikeSpreads@ entry; @parametersGuess@'s columns are always exactly 4, in order
-- alpha\/beta\/nu\/rho.
--
-- Calibration is lazy: unlike 'sabrInterpolatedSmileSection', construction here does /not/ force
-- an eager fit, so this call can succeed even for inputs that will later fail to calibrate -- the
-- error only surfaces on the first 'smileSection'\/'volatilityForPeriod''\/diagnostic call.
sabrSwaptionVolatilityCube :: GenSwaptionVolatilityStructure sv -- ^atmVolStructure
  -> [(Word, TimeUnit)] -- ^optionTenors
  -> [(Word, TimeUnit)] -- ^swapTenors
  -> [Double] -- ^strikeSpreads
  -> Matrix (GenQuote q1) -- ^volSpreads
  -> GenSwapIndex sidx1 -- ^swapIndexBase
  -> GenSwapIndex sidx2 -- ^shortSwapIndexBase
  -> Bool -- ^vegaWeightedSmileFit
  -> Matrix (GenQuote q2) -- ^parametersGuess (alpha, beta, nu, rho per node)
  -> Bool -- ^isAlphaFixed
  -> Bool -- ^isBetaFixed
  -> Bool -- ^isNuFixed
  -> Bool -- ^isRhoFixed
  -> Bool -- ^isAtmCalibrated: if 'True', @atmVolStructure@ must be a discrete grid structure
  -- (e.g. 'swaptionVolatilityMatrix'' or another cube) -- upstream's ATM-recalibration path
  -- ('denseSabrParameters'\/one branch of 'volCubeAtmCalibrated') downcasts it to
  -- @SwaptionVolatilityDiscrete@ and dereferences the result unchecked, which crashes given a
  -- flat 'constantSwaptionVolatility'\/'\''.
  -> Maybe Double -- ^maxErrorTolerance
  -> Maybe Double -- ^errorAccept
  -> Bool -- ^useMaxError
  -> Word -- ^maxGuesses
  -> Bool -- ^backwardFlat
  -> Double -- ^cutoffStrike
  -> IO SabrSwaptionVolatilityCube
sabrSwaptionVolatilityCube atm ot st ss (Matrix vr vc vd) sidx1 sidx2 vw (Matrix pr pc pd)
  iaf ibf inf irf iac met eat ume mg bf cs =
  qlSabrSwaptionVolatilityCube atm opl opu spl spu ss vr vc vd sidx1 sidx2 vw pr pc pd
    iaf ibf inf irf iac met eat ume mg bf cs
  where (opl, opu) = unzip ot; (spl, spu) = unzip st
{#fun qlSabrSwaptionVolatilityCube{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv'
  ,withIntArray*`[Word]'&,withEnumArray*`[TimeUnit]'&
  ,withIntArray*`[Word]'&,withEnumArray*`[TimeUnit]'&
  ,withDoubleArray*`[Double]'&
  ,fromIntegral`Word',fromIntegral`Word',withQuoteArrayRaw*`[GenQuote q1]'
  ,withSwapIndex*`GenSwapIndex sidx1',withSwapIndex*`GenSwapIndex sidx2'
  ,`Bool'
  ,fromIntegral`Word',fromIntegral`Word',withQuoteArrayRaw*`[GenQuote q2]'
  ,`Bool',`Bool',`Bool',`Bool'
  ,`Bool'
  ,fromMaybeDouble`Maybe Double',fromMaybeDouble`Maybe Double',`Bool',fromIntegral`Word'
  ,`Bool',`Double'
  ,preErrorCheck-`String'errorCheck*-}->`SabrSwaptionVolatilityCube'peekSabrSwaptionVolatilityCube*#}

-- |The non-SABR, linear-interpolation swaption volatility cube: interpolates the given
-- @volSpreads@ rather than calibrating a smile model. No 'EndCriteria'\/'OptimizationMethod'
-- hazard here -- this class never calibrates anything. See 'sabrSwaptionVolatilityCube' for the
-- @volSpreads@ flattening convention (identical here, minus @parametersGuess@).
interpolatedSwaptionVolatilityCube :: GenSwaptionVolatilityStructure sv -- ^atmVolStructure
  -> [(Word, TimeUnit)] -- ^optionTenors
  -> [(Word, TimeUnit)] -- ^swapTenors
  -> [Double] -- ^strikeSpreads
  -> Matrix (GenQuote q) -- ^volSpreads
  -> GenSwapIndex sidx1 -- ^swapIndexBase
  -> GenSwapIndex sidx2 -- ^shortSwapIndexBase
  -> Bool -- ^vegaWeightedSmileFit
  -> IO InterpolatedSwaptionVolatilityCube
interpolatedSwaptionVolatilityCube atm ot st ss (Matrix vr vc vd) sidx1 sidx2 vw =
  qlInterpolatedSwaptionVolatilityCube atm opl opu spl spu ss vr vc vd sidx1 sidx2 vw
  where (opl, opu) = unzip ot; (spl, spu) = unzip st
{#fun qlInterpolatedSwaptionVolatilityCube{withSwaptionVolatilityStructure*`GenSwaptionVolatilityStructure sv'
  ,withIntArray*`[Word]'&,withEnumArray*`[TimeUnit]'&
  ,withIntArray*`[Word]'&,withEnumArray*`[TimeUnit]'&
  ,withDoubleArray*`[Double]'&
  ,fromIntegral`Word',fromIntegral`Word',withQuoteArrayRaw*`[GenQuote q]'
  ,withSwapIndex*`GenSwapIndex sidx1',withSwapIndex*`GenSwapIndex sidx2'
  ,`Bool'
  ,preErrorCheck-`String'errorCheck*-}->`InterpolatedSwaptionVolatilityCube'peekInterpolatedSwaptionVolatilityCube*#}

toMatrixDouble :: (Word, Word, [Double]) -> Matrix Double
toMatrixDouble (r, c, d) = Matrix r c d

-- |Per-node calibrated SABR parameters (alpha, beta, nu, rho columns) before ATM recalibration.
sparseSabrParameters :: SabrSwaptionVolatilityCube -> IO (Matrix Double)
sparseSabrParameters sv = toMatrixDouble <$> qlSabrSwaptionVolatilityCubeSparseSabrParameters sv
{#fun qlSabrSwaptionVolatilityCubeSparseSabrParameters{withSabrSwaptionVolatilityCube*`SabrSwaptionVolatilityCube'
  ,prePtr-`Word'peekWord*,prePtr-`Word'peekWord*,preArray-`[Double]'&peekDoubleArray*
  ,preErrorCheck-`String'errorCheck*-}->`()'#}

-- |Per-node calibrated SABR parameters, meaningfully populated only when the cube was built with
-- @isAtmCalibrated = True@ (see 'sabrSwaptionVolatilityCube').
denseSabrParameters :: SabrSwaptionVolatilityCube -> IO (Matrix Double)
denseSabrParameters sv = toMatrixDouble <$> qlSabrSwaptionVolatilityCubeDenseSabrParameters sv
{#fun qlSabrSwaptionVolatilityCubeDenseSabrParameters{withSabrSwaptionVolatilityCube*`SabrSwaptionVolatilityCube'
  ,prePtr-`Word'peekWord*,prePtr-`Word'peekWord*,preArray-`[Double]'&peekDoubleArray*
  ,preErrorCheck-`String'errorCheck*-}->`()'#}

-- |The raw market vol grid the cube's SABR fit targets: ATM vol (interpolated from
-- @atmVolStructure@ at each node) plus @volSpreads@.
marketVolCube :: SabrSwaptionVolatilityCube -> IO (Matrix Double)
marketVolCube sv = toMatrixDouble <$> qlSabrSwaptionVolatilityCubeMarketVolCube sv
{#fun qlSabrSwaptionVolatilityCubeMarketVolCube{withSabrSwaptionVolatilityCube*`SabrSwaptionVolatilityCube'
  ,prePtr-`Word'peekWord*,prePtr-`Word'peekWord*,preArray-`[Double]'&peekDoubleArray*
  ,preErrorCheck-`String'errorCheck*-}->`()'#}

-- |Like 'marketVolCube', adjusted so the cube's own ATM row is consistent with @atmVolStructure@;
-- meaningfully populated only when the cube was built with @isAtmCalibrated = True@.
volCubeAtmCalibrated :: SabrSwaptionVolatilityCube -> IO (Matrix Double)
volCubeAtmCalibrated sv = toMatrixDouble <$> qlSabrSwaptionVolatilityCubeVolCubeAtmCalibrated sv
{#fun qlSabrSwaptionVolatilityCubeVolCubeAtmCalibrated{withSabrSwaptionVolatilityCube*`SabrSwaptionVolatilityCube'
  ,prePtr-`Word'peekWord*,prePtr-`Word'peekWord*,preArray-`[Double]'&peekDoubleArray*
  ,preErrorCheck-`String'errorCheck*-}->`()'#}

-- |ATM strike at a given (option date, swap tenor) node.
{#fun qlSabrSwaptionVolatilityCubeAtmStrike1 as sabrSwaptionVolatilityCubeAtmStrike'{withSabrSwaptionVolatilityCube*`SabrSwaptionVolatilityCube'
  ,withDay*`Day' -- ^optionDate
  ,fromEnumQuantity`(Word,TimeUnit)'& -- ^swapTenor
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |ATM strike at a given (option tenor, swap tenor) node, see 'sabrSwaptionVolatilityCubeAtmStrike\''
{#fun qlSabrSwaptionVolatilityCubeAtmStrike as sabrSwaptionVolatilityCubeAtmStrike{withSabrSwaptionVolatilityCube*`SabrSwaptionVolatilityCube'
  ,fromEnumQuantity`(Word,TimeUnit)'& -- ^optionTenor
  ,fromEnumQuantity`(Word,TimeUnit)'& -- ^swapTenor
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |ATM strike at a given (option date, swap tenor) node.
{#fun qlInterpolatedSwaptionVolatilityCubeAtmStrike1 as interpolatedSwaptionVolatilityCubeAtmStrike'{withInterpolatedSwaptionVolatilityCube*`InterpolatedSwaptionVolatilityCube'
  ,withDay*`Day' -- ^optionDate
  ,fromEnumQuantity`(Word,TimeUnit)'& -- ^swapTenor
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

-- |ATM strike at a given (option tenor, swap tenor) node, see
-- 'interpolatedSwaptionVolatilityCubeAtmStrike\''
{#fun qlInterpolatedSwaptionVolatilityCubeAtmStrike as interpolatedSwaptionVolatilityCubeAtmStrike{withInterpolatedSwaptionVolatilityCube*`InterpolatedSwaptionVolatilityCube'
  ,fromEnumQuantity`(Word,TimeUnit)'& -- ^optionTenor
  ,fromEnumQuantity`(Word,TimeUnit)'& -- ^swapTenor
  ,preErrorCheck-`String'errorCheck*-}->`Double'#}

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