Example #1
0
        public void Populate(IStochasticProcess container, EstimationResult estimate)
        {
            bool found;

            this.s0 = new ModelParameter(PopulateHelper.GetValue("S0", estimate.Names, estimate.Values, out found), this.s0.Description);

            bool errors = RetrieveCurve(container.Context, false);

            if (!errors)
            {
                PFunction rFunc     = estimate.Objects[0] as PFunction;
                PFunction rFuncDest = this.r.fVRef() as PFunction;
                rFuncDest.Expr = rFunc.Expr;

                PFunction qFunc     = estimate.Objects[1] as PFunction;
                PFunction qFuncDest = this.q.fVRef() as PFunction;
                qFuncDest.Expr = qFunc.Expr;
                //Calibrator assumes dividend yield is a step constant function, the simulation model must be coherent with that assumption.
                qFuncDest.m_Function.iType = DVPLUtils.EInterpolationType.ZERO_ORDER_LEFT;


                PFunction2D.PFunction2D localVolSrc  = estimate.Objects[2] as PFunction2D.PFunction2D;
                PFunction2D.PFunction2D localVolDest = this.localVol.fVRef() as PFunction2D.PFunction2D;
                localVolDest.Expr          = localVolSrc.Expr;
                localVolDest.Interpolation = localVolSrc.Interpolation;
            }
        }
Example #2
0
        /// <summary>
        /// This method allows to fit the implied volatility using different models.
        /// </summary>
        /// <param name="Hdataset"></param>
        /// <returns></returns>
        IFunction FitImplVolModel(CallPriceMarketData Hdataset)
        {
            int model = 1;

            switch (model)
            {
            case 0:
                PFunction2D.PFunction2D pf = new PFunction2D.PFunction2D(Hdataset.Maturity, Hdataset.Strike, Hdataset.Volatility);
                pf.Interpolation = DVPLUtils.EInterpolationType.LEAST_SQUARES;
                pf.Extrapolation = DVPLUtils.ExtrapolationType.USEMODEL;
                pf.Parse(null);
                return(pf);

            case 1:

                //define a model for fitting the implied volatility
                Fairmat.Statistics.LinearModel impVol = new Fairmat.Statistics.LinearModel(
                    new Fairmat.Statistics.Predictor[] {
                    delegate(Vector xx) { return(1); },
                    delegate(Vector xx) { return(xx[0]); },
                    delegate(Vector xx) { return(xx[1]); },
                    delegate(Vector xx) { return(System.Math.Pow(xx[0], 2)); },
                    delegate(Vector xx) { return(System.Math.Pow(xx[1], 2)); },
                    delegate(Vector xx) { return(xx[0] * xx[1]); },
                });

                // Unroll matrix and coordinate vectors in order to make it suitable
                // for the Quadratic model implementation.

                int    n     = Hdataset.Volatility.R * Hdataset.Volatility.C;
                Matrix xy    = new Matrix(n, 2);
                Vector z     = new Vector(n);
                int    count = 0;
                for (int x = 0; x < Hdataset.Volatility.R; x++)
                {
                    for (int y = 0; y < Hdataset.Volatility.C; y++)
                    {
                        if (Hdataset.Volatility[x, y] > 0.01)
                        {
                            xy[count, Range.All] = (new Vector()
                            {
                                Hdataset.Maturity[x], Hdataset.Strike[y]
                            }).T;
                            z[count]             = Hdataset.Volatility[x, y];
                            count++;
                        }
                    }
                }
                xy.Resize(count, xy.C);
                z.Resize(count);
                impVol.Estimate(xy, z);
                return(impVol);
            }

            return(null);
        }
Example #3
0
        private EstimationResult FairmatEstimate(CurveMarketData discountingCurve, CallPriceMarketData Hdataset)
        {
            EquityCalibrationData HCalData = new EquityCalibrationData(Hdataset, discountingCurve);
            //HCalData.Setup(Hdataset, discountingCurve);

            bool hasArbitrage = HCalData.HasArbitrageOpportunity(10e-2);

            if (hasArbitrage)
            {
                Console.WriteLine("Market data contains arbitrage opportunity");
            }

            this.r = new DVPLDOM.PFunction(discountingCurve.Durations, discountingCurve.Values);
            this.q = HCalData.dyFunc as PFunction;

            //this.q.Expr = (double[,])ArrayHelper.Concat(HCalData.MaturityDY.ToArray(), HCalData.DividendYield.ToArray());
            this.r.Parse(null);
            this.q.Parse(null);

            Vector locVolMat, locVolStr;
            //IFunction fittedSurface = FitImplVolModel(Hdataset);
            //Matrix locVolMatrix = LocVolMatrixFromImpliedVol(Hdataset, fittedSurface, out locVolMat, out locVolStr);
            CallPriceSurface fittedSurface = CallPriceSurface.NoArbitrageSurface(HCalData);
            Matrix           locVolMatrix  = LocVolMatrixFromCallPrices(Hdataset, fittedSurface, out locVolMat, out locVolStr);

            Console.WriteLine(locVolMatrix);


            // Create dupire outputs.
            PFunction2D.PFunction2D localVol = new PFunction2D.PFunction2D(locVolMat, locVolStr, locVolMatrix);
            localVol.Parse(null);
            string[] names = new string[] { "S0" };
            Vector   param = new Vector(1);

            param[0] = Hdataset.S0;
            EstimationResult result = new EstimationResult(names, param);

            //result.Objects = new object[3];
            result.Objects    = new object[4];
            result.Objects[0] = this.r;
            result.Objects[1] = this.q;
            result.Objects[2] = localVol;
            result.Objects[3] = fittedSurface;

            //Console.WriteLine("r = " + HCalData.Rate.ToString());
            //Console.WriteLine("q = " + HCalData.DividendYield.ToString());
            return(result);
        }
        public void TestCalibration()
        {
            InterestRateMarketData IData = InterestRateMarketData.FromFile("../../TestData/IRMD-sample.xml");
            CallPriceMarketData    HData = CallPriceMarketData.FromFile("../../TestData/CallData-sample.xml");
            //InterestRateMarketData IData = InterestRateMarketData.FromFile("../../../EquityModels.Tests/TestData/IRMD-EU-30102012-close.xml");
            //CallPriceMarketData HData = CallPriceMarketData.FromFile("../../../EquityModels.Tests/TestData/30102012-SX5E_Index-HestonData.xml");
            //CallPriceMarketData HData = ObjectSerialization.ReadFromXMLFile("../../../EquityModels.Tests/TestData/FTSE.xml") as CallPriceMarketData;


            List <object> l = new List <object>();

            l.Add(IData.DiscountingCurve);
            l.Add(HData);

            DupireEstimator           DE       = new DupireEstimator();
            DupireCalibrationSettings settings = new DupireCalibrationSettings();

            settings.LocalVolatilityCalculation = LocalVolatilityCalculation.Method1;


            //settings.LocalVolatilityCalculation = LocalVolatilityCalculation.QuantLib;
            EstimationResult res = DE.Estimate(l, settings);
            //int nmat = HData.Maturity.Length;
            //int nstrike = HData.Strike.Length;

            int i = 5; // Maturity.
            int j = 4; // Strike.

            Engine.MultiThread = true;

            Document   doc = new Document();
            ProjectROV rov = new ProjectROV(doc);

            doc.Part.Add(rov);
            doc.DefaultProject.NMethods.m_UseAntiteticPaths = true;
            int    n_sim   = 10000;
            int    n_steps = 500;
            double strike  = HData.Strike[j];
            //double volatility = HData.Volatility[i, j];

            /*
             * PFunction2D.PFunction2D impvolfunc = new PFunction2D.PFunction2D(rov);
             * impvolfunc = res.Objects[3] as PFunction2D.PFunction2D;
             * impvolfunc.VarName = "impvol";
             * rov.Symbols.Add(impvolfunc);
             * double volatility = impvolfunc.Evaluate(HData.Maturity[i], HData.Strike[j]);
             */
            double volatility = 0.2;
            double maturity   = HData.Maturity[i];

            ModelParameter Pstrike = new ModelParameter(strike, string.Empty, "strike");

            rov.Symbols.Add(Pstrike);
            AFunction payoff = new AFunction(rov);

            payoff.VarName = "payoff";
            payoff.m_IndependentVariables = 1;
            payoff.m_Value = (RightValue)("max(x1 - strike ; 0)");
            rov.Symbols.Add(payoff);

            bool           found;
            double         S0  = PopulateHelper.GetValue("S0", res.Names, res.Values, out found);
            ModelParameter PS0 = new ModelParameter(S0, string.Empty, "S0");

            rov.Symbols.Add(PS0);
            PFunction rfunc = new PFunction(rov);

            rfunc         = res.Objects[0] as PFunction;
            rfunc.VarName = "r";
            rov.Symbols.Add(rfunc);

            PFunction qfunc = new PFunction(rov);

            qfunc         = res.Objects[1] as PFunction;
            qfunc.VarName = "q";
            rov.Symbols.Add(qfunc);

            PFunction2D.PFunction2D volfunc = new PFunction2D.PFunction2D(rov);
            volfunc         = res.Objects[2] as PFunction2D.PFunction2D;
            volfunc.VarName = "localvol";
            rov.Symbols.Add(volfunc);
            DupireProcess process = new DupireProcess();

            process.s0       = (ModelParameter)"S0";
            process.r        = (ModelParameter)"@r";
            process.q        = (ModelParameter)"@q";
            process.localVol = (ModelParameter)"@localvol";
            double rate = rfunc.Evaluate(maturity);
            double dy   = qfunc.Evaluate(maturity);

            StochasticProcessExtendible s = new StochasticProcessExtendible(rov, process);

            rov.Processes.AddProcess(s);

            // Set the discounting.
            RiskFreeInfo rfi = rov.GetDiscountingModel() as RiskFreeInfo;

            rfi.ActualizationType = EActualizationType.RiskFree;
            rfi.m_deterministicRF = rate;
            OptionTree op = new OptionTree(rov);

            op.PayoffInfo.PayoffExpression          = "payoff(v1)";
            op.PayoffInfo.Timing.EndingTime.m_Value = (RightValue)maturity;
            op.PayoffInfo.European = true;
            rov.Map.Root           = op;

            rov.NMethods.Technology      = ETechType.T_SIMULATION;
            rov.NMethods.PathsNumber     = n_sim;
            rov.NMethods.SimulationSteps = n_steps;
            ROVSolver solver = new ROVSolver();

            solver.BindToProject(rov);
            solver.DoValuation(-1);
            if (rov.HasErrors)
            {
                rov.DisplayErrors();
            }

            Assert.IsFalse(rov.HasErrors);
            ResultItem price       = rov.m_ResultList[0] as ResultItem;
            double     samplePrice = price.value;
            double     sampleDevSt = price.stdDev / Math.Sqrt((double)n_sim);

            Console.WriteLine("Surf = " + volfunc.Expr);

            // Calculation of the theoretical value of the call.
            double theoreticalPrice = BlackScholes.Call(rate, S0, strike, volatility, maturity, dy);

            Console.WriteLine("Theoretical Price  = " + theoreticalPrice.ToString());
            Console.WriteLine("Monte Carlo Price  = " + samplePrice);
            Console.WriteLine("Standard Deviation = " + sampleDevSt.ToString());
            double tol = 4.0 * sampleDevSt;

            doc.WriteToXMLFile("Dupire.fair");
            Assert.LessOrEqual(Math.Abs(theoreticalPrice - samplePrice), tol);
        }
        private EstimationResult QuantLibEstimate(CurveMarketData discoutingCurve, CallPriceMarketData Hdataset)
        {
            EquityCalibrationData HCalData = new EquityCalibrationData(Hdataset, discoutingCurve);

            bool hasArbitrage = HCalData.HasArbitrageOpportunity(10e-2);
            if (hasArbitrage)
                Console.WriteLine("Market data contains arbitrage opportunity");

            this.r = new DVPLDOM.PFunction(discoutingCurve.Durations,discoutingCurve.Values);
            this.q = HCalData.dyFunc as PFunction;

            //this.r.Parse(null);
            //this.q.Parse(null);

            Hdataset.Volatility = new Matrix(Hdataset.CallPrice.R, Hdataset.CallPrice.C);
            for (int i = 0; i < Hdataset.Volatility.R; i++)
            {
                double m=Hdataset.Maturity[i];
                for (int j = 0; j < Hdataset.Volatility.C; j++)
                {
                    if (Hdataset.CallPrice[i, j] > 0)
                    {
                        var bs = new Fairmat.Finance.BlackScholes(r.Evaluate(m), Hdataset.S0, Hdataset.Strike[j], 0, m, q.Evaluate(m));
                        //Hdataset.Volatility[i, j] = Hdataset.Volatility[i, j] * Hdataset.Volatility[i, j] * Hdataset.Maturity[i];

                        //Hdataset.Volatility[i, j] = bs.ImpliedCallVolatility(Hdataset.CallPrice[i, j]);
                    }
                }
            }

            Console.WriteLine(Hdataset.Volatility);

            IFunction impVol = FitImplVolModel(Hdataset);

            Document doc = new Document();
            ProjectROV prj = new ProjectROV(doc);
            doc.Part.Add(prj);
            prj.Symbols.Add(impVol);
            // doc.WriteToXMLFile("impVol.fair");

            int nmat = calibrationSettings.LocalVolatilityMaturities;
            int nstrike = calibrationSettings.LocalVolatilityStrikes;
            double lastMat = Hdataset.Maturity[SymbolicIntervalExtremes.End];
            double lastStr = Hdataset.Strike[SymbolicIntervalExtremes.End];
            Vector locVolMat = Vector.Linspace(Hdataset.Maturity[0], lastMat, nmat);
            Vector locVolStr = Vector.Linspace(Hdataset.Strike[0], lastStr, nstrike);
            Matrix locVolMatrix = new Matrix(nmat, nstrike);
            double t, dt, forwardValue, y, dy, strike, strikep, strikem, w, wp, wm, dwdy;
            double d2wdy2, den1, den2, den3, strikept, strikemt, wpt, wmt, dwdt;
            Integrate integrate = new Integrate(this);

            for (int i = 0; i < nmat; i++)
            {
                t = locVolMat[i];
                forwardValue = Hdataset.S0 * Math.Exp(integrate.AdaptLobatto(0.0, t));
                for (int j = 0; j < nstrike; j++)
                {
                    strike = locVolStr[j];
                    y = Math.Log(strike / forwardValue);
                    dy = ((Math.Abs(y) > 0.001) ? y * 0.0001 : 0.000001);

                    // strike derivative
                    strikep = strike * Math.Exp(dy);
                    strikem = strike / Math.Exp(dy);
                    w = impVol.Evaluate(t, strike);
                    wp = impVol.Evaluate(t, strikep);
                    wm = impVol.Evaluate(t, strikem);
                    dwdy = (wp - wm) / (2.0 * dy);
                    d2wdy2 = (wp - 2.0 * w + wm) / (dy * dy);

                    // time derivative
                    if (t == 0.0)
                    {
                        dt = 0.0001;
                        strikept = strike * Math.Exp(integrate.AdaptLobatto(0.0, t + dt));
                        wpt = impVol.Evaluate(t + dt, strikept);
                        // if (wpt < w)
                        //    Console.WriteLine("Decreasing variance at strike {0} between time {1} and time {2}", strike, t, t + dt);
                        dwdt = (wpt - w) / dt;
                    }
                    else
                    {
                        dt = Math.Min(0.0001, t / 2.0);
                        strikept = strike * Math.Exp(integrate.AdaptLobatto(t, t + dt));
                        strikemt = strike * Math.Exp(-integrate.AdaptLobatto(t - dt, t));
                        wpt = impVol.Evaluate(t + dt, strikept);
                        wmt = impVol.Evaluate(t + dt, strikemt);

                        //if (wpt < w)
                        //    Console.WriteLine("Decreasing variance at strike {0} between time {1} and time {2}", strike, t, t + dt);
                        //if (w < wmt)
                        //    Console.WriteLine("Decreasing variance at strike {0} between time {1} and time {2}", strike, t-dt, t);
                        dwdt = (wpt - wmt) / (2.0 * dt);
                    }
                    if (dwdy == 0.0 && d2wdy2 == 0.0)
                        locVolMatrix[i, j] = Math.Sqrt(dwdt);
                    else
                    {
                        den1 = 1.0 - y / w * dwdy;
                        den2 = 0.25 * (-0.25 - 1.0 / w + y * y / w / w) * dwdy * dwdy;
                        den3 = 0.5 * d2wdy2;
                        locVolMatrix[i, j] = dwdt / (den1 + den2 + den3);
                        //if (locVolMatrix[i,j] < 0.0)
                        //    Console.WriteLine("Negative local vol^2 at strike {0} and time {1}; " +
                        //        "Black vol surface is not smooth enought.", strike, t);
                    }
                }
            }

            // Create dupire outputs.
            Console.WriteLine(locVolMat);
            PFunction2D.PFunction2D localVol = new PFunction2D.PFunction2D(locVolMat, locVolStr, locVolMatrix);
            localVol.Parse(null);
            string[] names = new string[] { "S0" };
            Vector param = new Vector(1);
            param[0] = Hdataset.S0;
            EstimationResult result = new EstimationResult(names, param);
            //result.Objects = new object[3];
            result.Objects = new object[4];
            result.Objects[0] = this.r;
            result.Objects[1] = this.q;
            result.Objects[2] = localVol;
            result.Objects[3] = impVol;
            //Console.WriteLine("r = " + HCalData.Rate.ToString());
            //Console.WriteLine("q = " + HCalData.DividendYield.ToString());
            return result;
        }
Example #6
0
        /// <summary>
        /// This method allows to fit the implied volatility using different models.
        /// </summary>
        /// <param name="Hdataset"></param>
        /// <returns></returns>
        IFunction FitImplVolModel(CallPriceMarketData Hdataset)
        {
            int model = 1;
            switch (model)
            {
                case 0:
                    PFunction2D.PFunction2D pf = new PFunction2D.PFunction2D(Hdataset.Maturity, Hdataset.Strike, Hdataset.Volatility);
                    pf.Interpolation = DVPLUtils.EInterpolationType.LEAST_SQUARES;
                    pf.Extrapolation = DVPLUtils.ExtrapolationType.USEMODEL;
                    pf.Parse(null);
                    return pf;
                case 1:

                    //define a model for fitting the implied volatility
                    Fairmat.Statistics.LinearModel impVol = new Fairmat.Statistics.LinearModel(
                                                            new Fairmat.Statistics.Predictor[] {
                                                            delegate(Vector xx) { return 1; },
                                                            delegate(Vector xx) { return xx[0]; },
                                                            delegate(Vector xx) { return xx[1]; },
                                                            delegate(Vector xx) { return System.Math.Pow(xx[0], 2); },
                                                            delegate(Vector xx) { return System.Math.Pow(xx[1], 2); },
                                                            delegate(Vector xx) { return xx[0] * xx[1]; }, });

                    // Unroll matrix and coordinate vectors in order to make it suitable
                    // for the Quadratic model implementation.

                    int n = Hdataset.Volatility.R * Hdataset.Volatility.C;
                    Matrix xy = new Matrix(n, 2);
                    Vector z = new Vector(n);
                    int count = 0;
                    for (int x = 0; x < Hdataset.Volatility.R; x++)
                    {
                        for (int y = 0; y < Hdataset.Volatility.C; y++)
                        {
                            if (Hdataset.Volatility[x, y] > 0.01)
                            {
                                xy[count, Range.All] = (new Vector() { Hdataset.Maturity[x],Hdataset.Strike[y] }).T;
                                z[count] = Hdataset.Volatility[x, y];
                                count++;
                            }
                        }
                    }
                    xy.Resize(count, xy.C);
                    z.Resize(count);
                    impVol.Estimate(xy, z);
                    return impVol;
            }

            return null;
        }
Example #7
0
        private EstimationResult FairmatEstimate(CurveMarketData discountingCurve, CallPriceMarketData Hdataset)
        {
            EquityCalibrationData HCalData = new EquityCalibrationData(Hdataset, discountingCurve);
            //HCalData.Setup(Hdataset, discountingCurve);

            bool hasArbitrage = HCalData.HasArbitrageOpportunity(10e-2);
            if (hasArbitrage)
                Console.WriteLine("Market data contains arbitrage opportunity");

            this.r = new DVPLDOM.PFunction(discountingCurve.Durations,discountingCurve.Values);
            this.q = HCalData.dyFunc as PFunction;

            //this.q.Expr = (double[,])ArrayHelper.Concat(HCalData.MaturityDY.ToArray(), HCalData.DividendYield.ToArray());
            this.r.Parse(null);
            this.q.Parse(null);

            Vector locVolMat, locVolStr;
            //IFunction fittedSurface = FitImplVolModel(Hdataset);
            //Matrix locVolMatrix = LocVolMatrixFromImpliedVol(Hdataset, fittedSurface, out locVolMat, out locVolStr);
            CallPriceSurface fittedSurface = CallPriceSurface.NoArbitrageSurface(HCalData);
            Matrix locVolMatrix = LocVolMatrixFromCallPrices(Hdataset, fittedSurface, out locVolMat, out locVolStr);
            Console.WriteLine(locVolMatrix);

            // Create dupire outputs.
            PFunction2D.PFunction2D localVol = new PFunction2D.PFunction2D(locVolMat, locVolStr, locVolMatrix);
            localVol.Parse(null);
            string[] names = new string[] { "S0" };
            Vector param = new Vector(1);
            param[0] = Hdataset.S0;
            EstimationResult result = new EstimationResult(names, param);
            //result.Objects = new object[3];
            result.Objects = new object[4];
            result.Objects[0] = this.r;
            result.Objects[1] = this.q;
            result.Objects[2] = localVol;
            result.Objects[3] = fittedSurface;

            //Console.WriteLine("r = " + HCalData.Rate.ToString());
            //Console.WriteLine("q = " + HCalData.DividendYield.ToString());
            return result;
        }
Example #8
0
        private EstimationResult QuantLibEstimate(CurveMarketData discoutingCurve, CallPriceMarketData Hdataset)
        {
            EquityCalibrationData HCalData = new EquityCalibrationData(Hdataset, discoutingCurve);

            bool hasArbitrage = HCalData.HasArbitrageOpportunity(10e-2);

            if (hasArbitrage)
            {
                Console.WriteLine("Market data contains arbitrage opportunity");
            }

            this.r = new DVPLDOM.PFunction(discoutingCurve.Durations, discoutingCurve.Values);
            this.q = HCalData.dyFunc as PFunction;

            //this.r.Parse(null);
            //this.q.Parse(null);

            Hdataset.Volatility = new Matrix(Hdataset.CallPrice.R, Hdataset.CallPrice.C);
            for (int i = 0; i < Hdataset.Volatility.R; i++)
            {
                double m = Hdataset.Maturity[i];
                for (int j = 0; j < Hdataset.Volatility.C; j++)
                {
                    if (Hdataset.CallPrice[i, j] > 0)
                    {
                        var bs = new Fairmat.Finance.BlackScholes(r.Evaluate(m), Hdataset.S0, Hdataset.Strike[j], 0, m, q.Evaluate(m));
                        //Hdataset.Volatility[i, j] = Hdataset.Volatility[i, j] * Hdataset.Volatility[i, j] * Hdataset.Maturity[i];

                        //Hdataset.Volatility[i, j] = bs.ImpliedCallVolatility(Hdataset.CallPrice[i, j]);
                    }
                }
            }

            Console.WriteLine(Hdataset.Volatility);

            IFunction impVol = FitImplVolModel(Hdataset);

            Document   doc = new Document();
            ProjectROV prj = new ProjectROV(doc);

            doc.Part.Add(prj);
            prj.Symbols.Add(impVol);
            // doc.WriteToXMLFile("impVol.fair");

            int       nmat = calibrationSettings.LocalVolatilityMaturities;
            int       nstrike = calibrationSettings.LocalVolatilityStrikes;
            double    lastMat = Hdataset.Maturity[SymbolicIntervalExtremes.End];
            double    lastStr = Hdataset.Strike[SymbolicIntervalExtremes.End];
            Vector    locVolMat = Vector.Linspace(Hdataset.Maturity[0], lastMat, nmat);
            Vector    locVolStr = Vector.Linspace(Hdataset.Strike[0], lastStr, nstrike);
            Matrix    locVolMatrix = new Matrix(nmat, nstrike);
            double    t, dt, forwardValue, y, dy, strike, strikep, strikem, w, wp, wm, dwdy;
            double    d2wdy2, den1, den2, den3, strikept, strikemt, wpt, wmt, dwdt;
            Integrate integrate = new Integrate(this);

            for (int i = 0; i < nmat; i++)
            {
                t            = locVolMat[i];
                forwardValue = Hdataset.S0 * Math.Exp(integrate.AdaptLobatto(0.0, t));
                for (int j = 0; j < nstrike; j++)
                {
                    strike = locVolStr[j];
                    y      = Math.Log(strike / forwardValue);
                    dy     = ((Math.Abs(y) > 0.001) ? y * 0.0001 : 0.000001);

                    // strike derivative
                    strikep = strike * Math.Exp(dy);
                    strikem = strike / Math.Exp(dy);
                    w       = impVol.Evaluate(t, strike);
                    wp      = impVol.Evaluate(t, strikep);
                    wm      = impVol.Evaluate(t, strikem);
                    dwdy    = (wp - wm) / (2.0 * dy);
                    d2wdy2  = (wp - 2.0 * w + wm) / (dy * dy);

                    // time derivative
                    if (t == 0.0)
                    {
                        dt       = 0.0001;
                        strikept = strike * Math.Exp(integrate.AdaptLobatto(0.0, t + dt));
                        wpt      = impVol.Evaluate(t + dt, strikept);
                        // if (wpt < w)
                        //    Console.WriteLine("Decreasing variance at strike {0} between time {1} and time {2}", strike, t, t + dt);
                        dwdt = (wpt - w) / dt;
                    }
                    else
                    {
                        dt       = Math.Min(0.0001, t / 2.0);
                        strikept = strike * Math.Exp(integrate.AdaptLobatto(t, t + dt));
                        strikemt = strike * Math.Exp(-integrate.AdaptLobatto(t - dt, t));
                        wpt      = impVol.Evaluate(t + dt, strikept);
                        wmt      = impVol.Evaluate(t + dt, strikemt);

                        //if (wpt < w)
                        //    Console.WriteLine("Decreasing variance at strike {0} between time {1} and time {2}", strike, t, t + dt);
                        //if (w < wmt)
                        //    Console.WriteLine("Decreasing variance at strike {0} between time {1} and time {2}", strike, t-dt, t);
                        dwdt = (wpt - wmt) / (2.0 * dt);
                    }
                    if (dwdy == 0.0 && d2wdy2 == 0.0)
                    {
                        locVolMatrix[i, j] = Math.Sqrt(dwdt);
                    }
                    else
                    {
                        den1 = 1.0 - y / w * dwdy;
                        den2 = 0.25 * (-0.25 - 1.0 / w + y * y / w / w) * dwdy * dwdy;
                        den3 = 0.5 * d2wdy2;
                        locVolMatrix[i, j] = dwdt / (den1 + den2 + den3);
                        //if (locVolMatrix[i,j] < 0.0)
                        //    Console.WriteLine("Negative local vol^2 at strike {0} and time {1}; " +
                        //        "Black vol surface is not smooth enought.", strike, t);
                    }
                }
            }

            // Create dupire outputs.
            Console.WriteLine(locVolMat);
            PFunction2D.PFunction2D localVol = new PFunction2D.PFunction2D(locVolMat, locVolStr, locVolMatrix);
            localVol.Parse(null);
            string[] names = new string[] { "S0" };
            Vector   param = new Vector(1);

            param[0] = Hdataset.S0;
            EstimationResult result = new EstimationResult(names, param);

            //result.Objects = new object[3];
            result.Objects    = new object[4];
            result.Objects[0] = this.r;
            result.Objects[1] = this.q;
            result.Objects[2] = localVol;
            result.Objects[3] = impVol;
            //Console.WriteLine("r = " + HCalData.Rate.ToString());
            //Console.WriteLine("q = " + HCalData.DividendYield.ToString());
            return(result);
        }