Untitled

 avatar
user_0311771714
plain_text
2 years ago
2.3 kB
3
Indexable
Never
module CharFuncPricing
include("lambertw.jl")
include("Heston.jl")
include("SchobelZhu.jl")
export CosCharFuncPricer, makeCosCharFuncPricer, priceEuropean

struct CosCharFuncPricer{T}
    τ::T
    a::T
    b::T
    uk::Array{T,1}
    phi::Array{T,1}
    pi::T
    field
end


function makeCosCharFuncPricer(
    CC,
    R,
    pi::T,
    p::Union{HestonParams{T},SchobelZhuParams{T}},
    τ::T,
    m::Int,
    l::Int,
) where {T}
    c1, c2, c4 = computeCumulants(p, τ)
    c2 = c2 + sqrt(abs(c4))
    a = c1 - l * sqrt(abs(c2))
    b = c1 + l * sqrt(abs(c2))
    # println("a ",a," b ",b)
    z =  @. (1:m) * pi / (b - a)
    phiz = map(z -> evaluateCharFunc(CC, p, z, τ), z)
    phi = @. real(phiz) * cos(-z * a) - imag(phiz) * sin(-z * a)
    uk = zeros(R, m)
    return CosCharFuncPricer(τ, a, b, uk, phi, pi,R)
end

#we adopt here the alternative formula of LeFloch "More Robust Pricing of European Options Based on Fourier Cosine Series Expansions"
function priceEuropean(
    p::CosCharFuncPricer{T},
    isCall::Bool,
    strike::T,
    forward::T,
    discountDf::T,
) where {T}
    local pricePut
    x = log(forward / strike)
    if x >= -p.a && x >= p.b
        pricePut = zero(p.field)
    elseif x <= p.a || x <= -p.b
        pricePut = discountDf * (strike - forward)
    else
        uk = p.uk
        a = p.a
        b = p.b
        ea = exp(a)
        f = forward
        pi = p.pi
        logStrike = log(strike / f)
        estrike = strike / f
        coeff = 2 / (b - a) * (-(estrike - ea) + estrike * (logStrike - a))
        uk0 = coeff

        @inbounds for i = 1:length(uk)
            z = i * pi / (b - a)
            kPid = (logStrike - a) * z
            sk, ck = sincos(kPid)
            chi = (ck * estrike - 1 * ea + z * (sk * estrike)) / (1 + z^2)
            psi = sk / z
            coeff = 2 / (b - a) * (-chi + estrike * psi)
            uk[i] = coeff
        end
        phi0 = one(p.field) #real(cfi.phi[0])
        sumPut = phi0 * uk0 / 2
        @inbounds @simd for k = 1:length(uk)
            sumPut += p.phi[k] * p.uk[k]
        end
        pricePut = discountDf * f * sumPut
    end
    if isCall
        return pricePut + discountDf * (forward - strike)
    end
    return pricePut
end

end # module