Package org.jquantlib.pricingengines.vanilla.finitedifferences

Source Code of org.jquantlib.pricingengines.vanilla.finitedifferences.FDVanillaEngine

/*
Copyright (C) 2007 Srinivas Hasti

This file is part of JQuantLib, a free-software/open-source library
for financial quantitative analysts and developers - http://jquantlib.org/

JQuantLib is free software: you can redistribute it and/or modify it
under the terms of the QuantLib license.  You should have received a
copy of the license along with this program; if not, please email
<jquant-devel@lists.sourceforge.net>. The license is also available online at
<http://www.jquantlib.org/index.php/LICENSE.TXT>.

This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the license for more details.

JQuantLib is based on QuantLib. http://quantlib.org/
When applicable, the original copyright notice follows this notice.
*/
package org.jquantlib.pricingengines.vanilla.finitedifferences;

import java.util.List;
import java.util.Vector;

import org.jquantlib.QL;
import org.jquantlib.instruments.OneAssetOption;
import org.jquantlib.instruments.Payoff;
import org.jquantlib.instruments.StrikedTypePayoff;
import org.jquantlib.math.SampledCurve;
import org.jquantlib.math.matrixutilities.Array;
import org.jquantlib.methods.finitedifferences.BoundaryCondition;
import org.jquantlib.methods.finitedifferences.NeumannBC;
import org.jquantlib.methods.finitedifferences.OperatorFactory;
import org.jquantlib.methods.finitedifferences.TridiagonalOperator;
import org.jquantlib.pricingengines.PricingEngine.Arguments;
import org.jquantlib.pricingengines.PricingEngine.Results;
import org.jquantlib.processes.GeneralizedBlackScholesProcess;
import org.jquantlib.time.Date;

/**
* Finite-differences pricing engine for BSM one asset options
* <p>
* The name is a misnomer as this is a base class for any finite difference scheme.  Its main job is to handle grid layout.
*
* @author Srinivas Hasti
*/
public class FDVanillaEngine {
    protected GeneralizedBlackScholesProcess process;
    protected /* @Size */ int timeSteps, gridPoints;
    protected boolean timeDependent;
    protected /* Real */ double requiredGridValue;
    protected Date exerciseDate;
    protected Payoff payoff;
    protected TridiagonalOperator finiteDifferenceOperator;
    protected SampledCurve intrinsicValues;
    protected List<BoundaryCondition<TridiagonalOperator>> bcS;
    // temporaries
    protected /* Real */ double sMin, center, sMax;

    //private double gridLogSpacing; //Not used
    private final static/* Real */double safetyZoneFactor = 1.1;


    //
    // public constructors
    //
    public FDVanillaEngine(final GeneralizedBlackScholesProcess process, final int timeSteps, final int gridPoints, final boolean timeDependent) {
        this.process = process;
        this.timeSteps = timeSteps;
        this.gridPoints = gridPoints;
        this.timeDependent = timeDependent;
        this.intrinsicValues = new SampledCurve(gridPoints);
        bcS = new Vector<BoundaryCondition<TridiagonalOperator>>();
    }


    //
    // public methods
    //

    public Array grid() {
        return intrinsicValues.grid();
    }


    //
    // protected methods
    //

    protected void setGridLimits() {
        setGridLimits(process.stateVariable().currentLink().value(), getResidualTime());
        ensureStrikeInGrid();
    }

    protected void setupArguments(final Arguments a) {
        final OneAssetOption.ArgumentsImpl args = (OneAssetOption.ArgumentsImpl) a;
        exerciseDate = args.exercise.lastDate();
        payoff = args.payoff;
        requiredGridValue = ((StrikedTypePayoff) (payoff)).strike();
    }

    protected void setGridLimits(/* Real */final double center, /* Time */final double t) {
        QL.require(center > 0.0 , "negative or null underlying given"); // QA:[RG]::verified // TODO: message
        this.center = center;
        /* Size */final int newGridPoints = safeGridPoints(gridPoints, t);
        if (newGridPoints > intrinsicValues.size())
            intrinsicValues = new SampledCurve(newGridPoints);

        /* Real */final double volSqrtTime = Math.sqrt(process.blackVolatility().currentLink().blackVariance(t, center));

        // the prefactor fine tunes performance at small volatilities
        /* Real */final double prefactor = 1.0 + 0.02 / volSqrtTime;
        /* Real */final double minMaxFactor = Math.exp(4.0 * prefactor * volSqrtTime);
        sMin = center / minMaxFactor; // underlying grid min value
        sMax = center * minMaxFactor; // underlying grid max value
    }

    protected void ensureStrikeInGrid() {
        // ensure strike is included in the grid
        final StrikedTypePayoff striked_payoff = (StrikedTypePayoff) (payoff);
        if (striked_payoff == null)
            return;
        /* Real */final double requiredGridValue = striked_payoff.strike();

        if (sMin > requiredGridValue / safetyZoneFactor) {
            sMin = requiredGridValue / safetyZoneFactor;
            // enforce central placement of the underlying
            sMax = center / (sMin / center);
        }
        if (sMax < requiredGridValue * safetyZoneFactor) {
            sMax = requiredGridValue * safetyZoneFactor;
            // enforce central placement of the underlying
            sMin = center / (sMax / center);
        }
    }

    protected void initializeInitialCondition() {
        intrinsicValues.setLogGrid(sMin, sMax);
        intrinsicValues.sample(new PayoffFunction(payoff));
    }

    protected void initializeOperator() {
        finiteDifferenceOperator = OperatorFactory.getOperator(process, intrinsicValues.grid(), getResidualTime(), timeDependent);
    }

    protected void initializeBoundaryConditions() {

        bcS.add(new NeumannBC(
                intrinsicValues.value(1)- intrinsicValues.value(0),
                NeumannBC.Side.Lower));

        bcS.add(new NeumannBC(
                intrinsicValues.value(intrinsicValues.size() - 1)- intrinsicValues.value(intrinsicValues.size() - 2),
                NeumannBC.Side.Upper));
    }

    protected/* Time */double getResidualTime() {
        return process.time(exerciseDate);
    }

    // safety check to be sure we have enough grid points.
    protected/* Size */int safeGridPoints(/* Size */final int gridPoints,
            /* Time */final double residualTime) {
        final int minGridPoints = 10;
        final int minGridPointsPerYear = 2;
        return Math.max(
                gridPoints,
                residualTime > 1.0
                ? (int) ((minGridPoints + (residualTime - 1.0) * minGridPointsPerYear))
                        : minGridPoints);
    }

    protected void calculate(final Results r) {
        throw new UnsupportedOperationException();
    }

}
TOP

Related Classes of org.jquantlib.pricingengines.vanilla.finitedifferences.FDVanillaEngine

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.