Ejemplo n.º 1
0
def getGaussianSobol(numPoints, dimension):
    ''' Sobol Gaussian quasi random points generator based on graycode order.
    The generated points follow a normal distribution. '''
    points = getUniformSobol(numPoints, dimension)

    for i in range(numPoints):
        for j in range(dimension):
            points[i, j] = norminvcdf(points[i, j])
    return points
Ejemplo n.º 2
0
def LMMSimulateFwdsMF(numForwards, numFactors, numPaths, numeraireIndex, fwd0,
                      lambdas, taus, useSobol, seed):
    ''' Multi-Factor Arbitrage-free simulation of forward Libor curves in the
    spot measure following Hull Page 768. Given an initial forward curve,
    volatility factor term structure. The 3D matrix of forward rates by path,
    time and forward point is returned. '''

    np.random.seed(seed)

    if len(lambdas) != numFactors:
        raise FinError("Lambda does not have the right number of factors")

    if len(lambdas[0]) != numForwards:
        raise FinError("Lambda does not have the right number of forwards")

    # Even number of paths for antithetics
    numPaths = 2 * int(numPaths / 2)
    halfNumPaths = int(numPaths / 2)
    fwd = np.empty((numPaths, numForwards, numForwards))
    fwdB = np.zeros(numForwards)

    numTimes = numForwards

    if useSobol == 1:
        numDimensions = numTimes * numFactors
        rands = getUniformSobol(halfNumPaths, numDimensions)
        gMatrix = np.empty((numPaths, numTimes, numFactors))
        for iPath in range(0, halfNumPaths):
            for j in range(0, numTimes):
                for q in range(0, numFactors):
                    col = j * numFactors + q
                    u = rands[iPath, col]
                    g = norminvcdf(u)
                    gMatrix[iPath, j, q] = g
                    gMatrix[iPath + halfNumPaths, j, q] = -g
    elif useSobol == 0:
        gMatrix = np.empty((numPaths, numTimes, numFactors))
        for iPath in range(0, halfNumPaths):
            for j in range(0, numTimes):
                for q in range(0, numFactors):
                    g = np.random.normal()
                    gMatrix[iPath, j, q] = g
                    gMatrix[iPath + halfNumPaths, j, q] = -g
    else:
        raise FinError("Use Sobol must be 0 or 1.")

    for iPath in range(0, numPaths):
        # Initial value of forward curve at time 0
        for iFwd in range(0, numForwards):
            fwd[iPath, 0, iFwd] = fwd0[iFwd]

        for j in range(0, numForwards - 1):  # TIME LOOP
            dtj = taus[j]
            sqrtdtj = np.sqrt(dtj)

            for k in range(j, numForwards):  # FORWARDS LOOP

                muA = 0.0
                for i in range(j + 1, k + 1):
                    fi = fwd[iPath, j, i]
                    ti = taus[i]
                    zz = 0.0
                    for q in range(0, numFactors):
                        zij = lambdas[q][i - j]
                        zkj = lambdas[q][k - j]
                        zz += zij * zkj
                    muA += fi * ti * zz / (1.0 + fi * ti)

                itoTerm = 0.0
                for q in range(0, numFactors):
                    itoTerm += lambdas[q][k - j] * lambdas[q][k - j]

                randomTerm = 0.0
                for q in range(0, numFactors):
                    wq = gMatrix[iPath, j, q]
                    randomTerm += lambdas[q][k - j] * wq
                randomTerm *= sqrtdtj

                x = np.exp(muA * dtj - 0.5 * itoTerm * dtj + randomTerm)
                fwdB[k] = fwd[iPath, j, k] * x

                muB = 0.0
                for i in range(j + 1, k + 1):
                    fi = fwdB[k]
                    ti = taus[i]
                    zz = 0.0
                    for q in range(0, numFactors):
                        zij = lambdas[q][i - j]
                        zkj = lambdas[q][k - j]
                        zz += zij * zkj
                    muB += fi * ti * zz / (1.0 + fi * ti)

                muC = 0.5 * (muA + muB)

                x = np.exp(muC * dtj - 0.5 * itoTerm * dtj + randomTerm)
                fwd[iPath, j + 1, k] = fwd[iPath, j, k] * x

    return fwd
Ejemplo n.º 3
0
def LMMSimulateFwds1F(numForwards, numPaths, numeraireIndex, fwd0, gammas,
                      taus, useSobol, seed):
    ''' One factor Arbitrage-free simulation of forward Libor curves in the
    spot measure following Hull Page 768. Given an initial forward curve,
    volatility term structure. The 3D matrix of forward rates by path, time
    and forward point is returned. This function is kept mainly for its
    simplicity and speed.

    NB: The Gamma volatility has an initial entry of zero. This differs from
    Hull's indexing by one and so is why I do not subtract 1 from the index as
    Hull does in his equation 32.14.

    The Number of Forwards is the number of points on the initial curve to the
    trade maturity date.

    But be careful: a cap that matures in 10 years with quarterly caplets has
    40 forwards BUT the last forward to reset occurs at 9.75 years. You should
    not simulate beyond this time. If you give the model 10 years as in the
    Hull examples, you need to simulate 41 (or in this case 11) forwards as the
    final cap or ratchet has its reset in 10 years. '''

    if len(gammas) != numForwards:
        raise FinError("Gamma vector does not have right number of forwards")

    if len(fwd0) != numForwards:
        raise FinError("The length of fwd0 is not equal to numForwards")

    if len(taus) != numForwards:
        raise FinError("The length of Taus is not equal to numForwards")

    np.random.seed(seed)
    # Even number of paths for antithetics
    numPaths = 2 * int(numPaths / 2)
    halfNumPaths = int(numPaths / 2)
    fwd = np.empty((numPaths, numForwards, numForwards))
    fwdB = np.zeros(numForwards)

    numTimes = numForwards

    if useSobol == 1:
        numDimensions = numTimes
        rands = getUniformSobol(halfNumPaths, numDimensions)
        gMatrix = np.empty((numPaths, numTimes))
        for iPath in range(0, halfNumPaths):
            for j in range(0, numTimes):
                u = rands[iPath, j]
                g = norminvcdf(u)
                gMatrix[iPath, j] = g
                gMatrix[iPath + halfNumPaths, j] = -g
    elif useSobol == 0:
        gMatrix = np.empty((numPaths, numTimes))
        for iPath in range(0, halfNumPaths):
            for j in range(0, numTimes):
                g = np.random.normal()
                gMatrix[iPath, j] = g
                gMatrix[iPath + halfNumPaths, j] = -g
    else:
        raise FinError("Use Sobol must be 0 or 1")

    for iPath in prange(0, numPaths):
        # Initial value of forward curve at time 0
        for iFwd in range(0, numForwards):
            fwd[iPath, 0, iFwd] = fwd0[iFwd]

        for j in range(0, numForwards - 1):  # TIME LOOP
            dtj = taus[j]
            sqrtdtj = np.sqrt(dtj)
            w = gMatrix[iPath, j]

            for k in range(j, numForwards):  # FORWARDS LOOP
                zkj = gammas[k - j]
                muA = 0.0

                for i in range(j + 1, k + 1):
                    fi = fwd[iPath, j, i]
                    zij = gammas[i - j]
                    ti = taus[i]
                    muA += zkj * fi * ti * zij / (1.0 + fi * ti)

                # predictor corrector
                x = np.exp(muA * dtj - 0.5 * (zkj**2) * dtj +
                           zkj * w * sqrtdtj)
                fwdB[k] = fwd[iPath, j, k] * x

                muB = 0.0
                for i in range(j + 1, k + 1):
                    fi = fwdB[k]
                    zij = gammas[i - j]
                    ti = taus[i]
                    muB += zkj * fi * ti * zij / (1.0 + fi * ti)

                muC = 0.5 * (muA + muB)

                x = np.exp(muC * dtj - 0.5 * (zkj**2) * dtj +
                           zkj * w * sqrtdtj)
                fwd[iPath, j + 1, k] = fwd[iPath, j, k] * x

    return fwd
Ejemplo n.º 4
0
def test_FinMath():

    xValues = np.linspace(-6.0, 6.0, 13)

    start = time.time()

    testCases.header("FUNCTION", "X", "Y")
    for x in xValues:
        y = normcdf(x, 1)
        testCases.print("NORMCDF1", x, y)

    end = time.time()
    duration = end - start
    testCases.header("LABEL", "TIME")
    testCases.print("Fast N(x) takes ", duration)

    ##########################################################################

    testCases.header("FUNCTION", "X", "Y")

    start = time.time()
    for x in xValues:
        y = normcdf(x, 2)
        testCases.print("NORMCDF2", x, y)

    end = time.time()
    duration = end - start
    testCases.header("LABEL", "TIME")
    testCases.print("Slow N(x) takes ", duration)

    ##########################################################################

    testCases.header("FUNCTION", "X", "Y")

    start = time.time()
    for x in xValues:
        y = normcdf(x, 3)
        testCases.print("NORMCDF3", x, y)

    end = time.time()
    duration = end - start

    testCases.header("LABEL", "TIME")
    testCases.print("Trap N(x) takes ", duration)

    ##########################################################################

    xValues = np.linspace(-6.0, 6.0, 20)

    testCases.header("X", "Y1", "Y2", "Y3", "DIFF1", "DIFF2")

    for x in xValues:
        y1 = normcdf(x, 1)
        y2 = normcdf(x, 2)
        y3 = normcdf(x, 3)
        diff1 = y3 - y1
        diff2 = y3 - y2
        testCases.print(x, y1, y2, y3, diff1, diff2)

    ##########################################################################

    xValues = np.linspace(-6.0, 6.0, 20)

    testCases.header("X", "Y1", "Y2", "INV_Y1", "INV_Y2", "DIFF1", "DIFF2")

    for x_in in xValues:
        y1 = normcdf(x_in, 1)
        y2 = normcdf(x_in, 2)
        x_out1 = norminvcdf(y1)
        x_out2 = norminvcdf(y2)
        diff1 = x_out1 - x_in
        diff2 = x_out2 - x_in
        testCases.print(x, y1, y2, x_out1, x_out2, diff1, diff2)