{-# LANGUAGE MultiParamTypeClasses #-}
module Q.Options.ImpliedVol.StrikeInterpolation where

import           Data.Coerce
import qualified Numeric.GSL.Interpolation as GSL
import           Q.Interpolation
import           Q.SortedVector
import           Q.Types

data StrikeInterpolation = Linear
                         | CubicNatural
                         | CubicAkima
                         | CubicMonotone

data StrikeExtrapolation = Constant
                         | ConstantGradient
                         | ConstantCurvature

instance InterpolatorV StrikeInterpolation Strike Vol where
  interpolateV :: StrikeInterpolation
-> SortedVector Strike -> Vector Vol -> Strike -> Vol
interpolateV StrikeInterpolation
Linear        (SortedVector Vector Strike
strikes) Vector Vol
vols (Strike Double
k) =
    Double -> Vol
Vol (Double -> Vol) -> Double -> Vol
forall a b. (a -> b) -> a -> b
$ InterpolationMethod
-> Vector Double -> Vector Double -> Double -> Double
GSL.evaluateV InterpolationMethod
GSL.Linear (Vector Strike -> Vector Double
coerce Vector Strike
strikes) (Vector Vol -> Vector Double
coerce Vector Vol
vols) Double
k

  interpolateV StrikeInterpolation
CubicNatural  (SortedVector Vector Strike
strikes) Vector Vol
vols (Strike Double
k) =
    Double -> Vol
Vol (Double -> Vol) -> Double -> Vol
forall a b. (a -> b) -> a -> b
$ InterpolationMethod
-> Vector Double -> Vector Double -> Double -> Double
GSL.evaluateV InterpolationMethod
GSL.CSpline  (Vector Strike -> Vector Double
coerce Vector Strike
strikes) (Vector Vol -> Vector Double
coerce Vector Vol
vols) Double
k

  interpolateV StrikeInterpolation
CubicAkima    (SortedVector Vector Strike
strikes) Vector Vol
vols (Strike Double
k) =
    Double -> Vol
Vol (Double -> Vol) -> Double -> Vol
forall a b. (a -> b) -> a -> b
$ InterpolationMethod
-> Vector Double -> Vector Double -> Double -> Double
GSL.evaluateV InterpolationMethod
GSL.Akima  (Vector Strike -> Vector Double
coerce Vector Strike
strikes) (Vector Vol -> Vector Double
coerce Vector Vol
vols) Double
k


  interpolateV StrikeInterpolation
CubicMonotone (SortedVector Vector Strike
strikes) Vector Vol
vols (Strike Double
k) =
    -- The interpolation method should be Steffen but until the next
    -- version of hmatrix-gsl is release i am using Akima.
    Double -> Vol
Vol (Double -> Vol) -> Double -> Vol
forall a b. (a -> b) -> a -> b
$ InterpolationMethod
-> Vector Double -> Vector Double -> Double -> Double
GSL.evaluateV InterpolationMethod
GSL.Akima (Vector Strike -> Vector Double
coerce Vector Strike
strikes) (Vector Vol -> Vector Double
coerce Vector Vol
vols) Double
k