Exemple #1
0
        public Handle <LocalVolTermStructure> localVolatility()
        {
            if (!updated_)
            {
                isStrikeIndependent_ = true;

                // constant Black vol?
                BlackConstantVol constVol = blackVolatility().link as BlackConstantVol;
                if (constVol != null)
                {
                    // ok, the local vol is constant too.
                    localVolatility_.linkTo(new LocalConstantVol(constVol.referenceDate(),
                                                                 constVol.blackVol(0.0, x0_.link.value()),
                                                                 constVol.dayCounter()));
                    updated_ = true;
                    return(localVolatility_);
                }

                // ok, so it's not constant. Maybe it's strike-independent?
                BlackVarianceCurve volCurve = blackVolatility().link as BlackVarianceCurve;
                if (volCurve != null)
                {
                    // ok, we can use the optimized algorithm
                    localVolatility_.linkTo(new LocalVolCurve(new Handle <BlackVarianceCurve>(volCurve)));
                    updated_ = true;
                    return(localVolatility_);
                }

                // ok, so it's strike-dependent. Never mind.
                localVolatility_.linkTo(new LocalVolSurface(blackVolatility_, riskFreeRate_, dividendYield_,
                                                            x0_.link.value()));
                updated_             = true;
                isStrikeIndependent_ = false;
                return(localVolatility_);
            }
            else
            {
                return(localVolatility_);
            }
        }
        public override void calculate()
        {
            double sigmaShift_vega  = 0.0001;
            double sigmaShift_volga = 0.0001;
            double spotShift_delta  = 0.0001 * spotFX_.link.value();
            double sigmaShift_vanna = 0.0001;

            Handle <Quote> x0Quote     = new Handle <Quote>(new SimpleQuote(spotFX_.link.value())); //used for shift
            Handle <Quote> atmVolQuote = new Handle <Quote>(new SimpleQuote(atmVol_.link.value())); //used for shift

            BlackVolTermStructure blackVolTS = new BlackConstantVol(Settings.evaluationDate(),
                                                                    new NullCalendar(), atmVolQuote, new Actual365Fixed());
            BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(x0Quote, foreignTS_, domesticTS_,
                                                                                   new Handle <BlackVolTermStructure>(blackVolTS));

            IPricingEngine engineBS = new AnalyticBarrierEngine(stochProcess);

            BlackDeltaCalculator blackDeltaCalculatorAtm = new BlackDeltaCalculator(
                Option.Type.Call, atmVol_.link.deltaType(), x0Quote.link.value(),
                domesticTS_.link.discount(T_), foreignTS_.link.discount(T_),
                atmVol_.link.value() * Math.Sqrt(T_));
            double atmStrike = blackDeltaCalculatorAtm.atmStrike(atmVol_.link.atmType());

            double call25Vol = vol25Call_.link.value();
            double put25Vol  = vol25Put_.link.value();

            BlackDeltaCalculator blackDeltaCalculatorPut25 = new BlackDeltaCalculator(
                Option.Type.Put, vol25Put_.link.deltaType(), x0Quote.link.value(),
                domesticTS_.link.discount(T_), foreignTS_.link.discount(T_),
                put25Vol * Math.Sqrt(T_));
            double put25Strike = blackDeltaCalculatorPut25.strikeFromDelta(-0.25);
            BlackDeltaCalculator blackDeltaCalculatorCall25 = new BlackDeltaCalculator(
                Option.Type.Call, vol25Call_.link.deltaType(), x0Quote.link.value(),
                domesticTS_.link.discount(T_), foreignTS_.link.discount(T_),
                call25Vol * Math.Sqrt(T_));
            double call25Strike = blackDeltaCalculatorCall25.strikeFromDelta(0.25);

            //here use vanna volga interpolated smile to price vanilla
            List <double> strikes = new List <double>();
            List <double> vols    = new List <double>();

            strikes.Add(put25Strike);
            vols.Add(put25Vol);
            strikes.Add(atmStrike);
            vols.Add(atmVol_.link.value());
            strikes.Add(call25Strike);
            vols.Add(call25Vol);
            VannaVolga vannaVolga = new VannaVolga(x0Quote.link.value(), domesticTS_.link.discount(T_),
                                                   foreignTS_.link.discount(T_), T_);
            Interpolation interpolation = vannaVolga.interpolate(strikes, strikes.Count, vols);

            interpolation.enableExtrapolation();
            StrikedTypePayoff payoff    = arguments_.payoff as StrikedTypePayoff;
            double            strikeVol = interpolation.value(payoff.strike());

            //vannila option price
            double vanillaOption = Utils.blackFormula(payoff.optionType(), payoff.strike(),
                                                      x0Quote.link.value() * foreignTS_.link.discount(T_) / domesticTS_.link.discount(T_),
                                                      strikeVol * Math.Sqrt(T_),
                                                      domesticTS_.link.discount(T_));

            //spot > barrier up&out 0
            if (x0Quote.link.value() >= arguments_.barrier && arguments_.barrierType == Barrier.Type.UpOut)
            {
                results_.value = 0.0;
                results_.additionalResults["VanillaPrice"]    = adaptVanDelta_? bsPriceWithSmile_ : vanillaOption;
                results_.additionalResults["BarrierInPrice"]  = adaptVanDelta_? bsPriceWithSmile_ : vanillaOption;
                results_.additionalResults["BarrierOutPrice"] = 0.0;
            }
            //spot > barrier up&in vanilla
            else if (x0Quote.link.value() >= arguments_.barrier && arguments_.barrierType == Barrier.Type.UpIn)
            {
                results_.value = adaptVanDelta_? bsPriceWithSmile_ : vanillaOption;
                results_.additionalResults["VanillaPrice"]    = adaptVanDelta_? bsPriceWithSmile_ : vanillaOption;
                results_.additionalResults["BarrierInPrice"]  = adaptVanDelta_? bsPriceWithSmile_ : vanillaOption;
                results_.additionalResults["BarrierOutPrice"] = 0.0;
            }
            //spot < barrier down&out 0
            else if (x0Quote.link.value() <= arguments_.barrier && arguments_.barrierType == Barrier.Type.DownOut)
            {
                results_.value = 0.0;
                results_.additionalResults["VanillaPrice"]    = adaptVanDelta_? bsPriceWithSmile_ : vanillaOption;
                results_.additionalResults["BarrierInPrice"]  = adaptVanDelta_? bsPriceWithSmile_ : vanillaOption;
                results_.additionalResults["BarrierOutPrice"] = 0.0;
            }
            //spot < barrier down&in vanilla
            else if (x0Quote.link.value() <= arguments_.barrier && arguments_.barrierType == Barrier.Type.DownIn)
            {
                results_.value = adaptVanDelta_? bsPriceWithSmile_ : vanillaOption;
                results_.additionalResults["VanillaPrice"]    = adaptVanDelta_? bsPriceWithSmile_ : vanillaOption;
                results_.additionalResults["BarrierInPrice"]  = adaptVanDelta_? bsPriceWithSmile_ : vanillaOption;
                results_.additionalResults["BarrierOutPrice"] = 0.0;
            }
            else
            {
                //set up BS barrier option pricing
                //only calculate out barrier option price
                // in barrier price = vanilla - out barrier
                Barrier.Type barrierTyp;
                if (arguments_.barrierType == Barrier.Type.UpOut)
                {
                    barrierTyp = arguments_.barrierType;
                }
                else if (arguments_.barrierType == Barrier.Type.UpIn)
                {
                    barrierTyp = Barrier.Type.UpOut;
                }
                else if (arguments_.barrierType == Barrier.Type.DownOut)
                {
                    barrierTyp = arguments_.barrierType;
                }
                else
                {
                    barrierTyp = Barrier.Type.DownOut;
                }

                BarrierOption barrierOption = new BarrierOption(barrierTyp,
                                                                arguments_.barrier.GetValueOrDefault(),
                                                                arguments_.rebate.GetValueOrDefault(),
                                                                (StrikedTypePayoff)arguments_.payoff,
                                                                arguments_.exercise);

                barrierOption.setPricingEngine(engineBS);

                //BS price with atm vol
                double priceBS = barrierOption.NPV();

                double priceAtmCallBS = Utils.blackFormula(Option.Type.Call, atmStrike,
                                                           x0Quote.link.value() * foreignTS_.link.discount(T_) / domesticTS_.link.discount(T_),
                                                           atmVol_.link.value() * Math.Sqrt(T_),
                                                           domesticTS_.link.discount(T_));
                double price25CallBS = Utils.blackFormula(Option.Type.Call, call25Strike,
                                                          x0Quote.link.value() * foreignTS_.link.discount(T_) / domesticTS_.link.discount(T_),
                                                          atmVol_.link.value() * Math.Sqrt(T_),
                                                          domesticTS_.link.discount(T_));
                double price25PutBS = Utils.blackFormula(Option.Type.Put, put25Strike,
                                                         x0Quote.link.value() * foreignTS_.link.discount(T_) / domesticTS_.link.discount(T_),
                                                         atmVol_.link.value() * Math.Sqrt(T_),
                                                         domesticTS_.link.discount(T_));

                //market price
                double priceAtmCallMkt = Utils.blackFormula(Option.Type.Call, atmStrike,
                                                            x0Quote.link.value() * foreignTS_.link.discount(T_) / domesticTS_.link.discount(T_),
                                                            atmVol_.link.value() * Math.Sqrt(T_),
                                                            domesticTS_.link.discount(T_));

                double price25CallMkt = Utils.blackFormula(Option.Type.Call, call25Strike,
                                                           x0Quote.link.value() * foreignTS_.link.discount(T_) / domesticTS_.link.discount(T_),
                                                           call25Vol * Math.Sqrt(T_),
                                                           domesticTS_.link.discount(T_));
                double price25PutMkt = Utils.blackFormula(Option.Type.Put, put25Strike,
                                                          x0Quote.link.value() * foreignTS_.link.discount(T_) / domesticTS_.link.discount(T_),
                                                          put25Vol * Math.Sqrt(T_),
                                                          domesticTS_.link.discount(T_));


                //Analytical Black Scholes formula for vanilla option
                NormalDistribution norm  = new NormalDistribution();
                double             d1atm = (Math.Log(x0Quote.link.value() * foreignTS_.link.discount(T_) /
                                                     domesticTS_.link.discount(T_) / atmStrike)
                                            + 0.5 * Math.Pow(atmVolQuote.link.value(), 2.0) * T_) /
                                           (atmVolQuote.link.value() * Math.Sqrt(T_));
                double vegaAtm_Analytical = x0Quote.link.value() * norm.value(d1atm) * Math.Sqrt(T_) *
                                            foreignTS_.link.discount(T_);
                double vannaAtm_Analytical = vegaAtm_Analytical / x0Quote.link.value() *
                                             (1.0 - d1atm / (atmVolQuote.link.value() * Math.Sqrt(T_)));
                double volgaAtm_Analytical = vegaAtm_Analytical * d1atm * (d1atm - atmVolQuote.link.value() * Math.Sqrt(T_)) /
                                             atmVolQuote.link.value();

                double d125call = (Math.Log(x0Quote.link.value() * foreignTS_.link.discount(T_) /
                                            domesticTS_.link.discount(T_) / call25Strike)
                                   + 0.5 * Math.Pow(atmVolQuote.link.value(), 2.0) * T_) / (atmVolQuote.link.value() * Math.Sqrt(T_));
                double vega25Call_Analytical = x0Quote.link.value() * norm.value(d125call) * Math.Sqrt(T_) *
                                               foreignTS_.link.discount(T_);
                double vanna25Call_Analytical = vega25Call_Analytical / x0Quote.link.value() *
                                                (1.0 - d125call / (atmVolQuote.link.value() * Math.Sqrt(T_)));
                double volga25Call_Analytical = vega25Call_Analytical * d125call *
                                                (d125call - atmVolQuote.link.value() * Math.Sqrt(T_)) / atmVolQuote.link.value();

                double d125Put = (Math.Log(x0Quote.link.value() * foreignTS_.link.discount(T_) /
                                           domesticTS_.link.discount(T_) / put25Strike)
                                  + 0.5 * Math.Pow(atmVolQuote.link.value(), 2.0) * T_) / (atmVolQuote.link.value() * Math.Sqrt(T_));
                double vega25Put_Analytical = x0Quote.link.value() * norm.value(d125Put) * Math.Sqrt(T_) *
                                              foreignTS_.link.discount(T_);
                double vanna25Put_Analytical = vega25Put_Analytical / x0Quote.link.value() *
                                               (1.0 - d125Put / (atmVolQuote.link.value() * Math.Sqrt(T_)));
                double volga25Put_Analytical = vega25Put_Analytical * d125Put *
                                               (d125Put - atmVolQuote.link.value() * Math.Sqrt(T_)) / atmVolQuote.link.value();


                //BS vega
                ((SimpleQuote)atmVolQuote.currentLink()).setValue(atmVolQuote.link.value() + sigmaShift_vega);
                barrierOption.recalculate();
                double vegaBarBS = (barrierOption.NPV() - priceBS) / sigmaShift_vega;

                ((SimpleQuote)atmVolQuote.currentLink()).setValue(atmVolQuote.link.value() - sigmaShift_vega);//setback

                //BS volga

                //vegaBar2
                //base NPV
                ((SimpleQuote)atmVolQuote.currentLink()).setValue(atmVolQuote.link.value() + sigmaShift_volga);
                barrierOption.recalculate();
                double priceBS2 = barrierOption.NPV();

                //shifted npv
                ((SimpleQuote)atmVolQuote.currentLink()).setValue(atmVolQuote.link.value() + sigmaShift_vega);
                barrierOption.recalculate();
                double vegaBarBS2 = (barrierOption.NPV() - priceBS2) / sigmaShift_vega;
                double volgaBarBS = (vegaBarBS2 - vegaBarBS) / sigmaShift_volga;

                ((SimpleQuote)atmVolQuote.currentLink()).setValue(atmVolQuote.link.value()
                                                                  - sigmaShift_volga
                                                                  - sigmaShift_vega);                     //setback

                //BS Delta
                //base delta
                ((SimpleQuote)x0Quote.currentLink()).setValue(x0Quote.link.value() + spotShift_delta);//shift forth
                barrierOption.recalculate();
                double priceBS_delta1 = barrierOption.NPV();

                ((SimpleQuote)x0Quote.currentLink()).setValue(x0Quote.link.value() - 2 * spotShift_delta);//shift back
                barrierOption.recalculate();
                double priceBS_delta2 = barrierOption.NPV();

                ((SimpleQuote)x0Quote.currentLink()).setValue(x0Quote.link.value() + spotShift_delta);//set back
                double deltaBar1 = (priceBS_delta1 - priceBS_delta2) / (2.0 * spotShift_delta);

                //shifted delta
                ((SimpleQuote)atmVolQuote.currentLink()).setValue(atmVolQuote.link.value() + sigmaShift_vanna); //shift sigma
                ((SimpleQuote)x0Quote.currentLink()).setValue(x0Quote.link.value() + spotShift_delta);          //shift forth
                barrierOption.recalculate();
                priceBS_delta1 = barrierOption.NPV();

                ((SimpleQuote)x0Quote.currentLink()).setValue(x0Quote.link.value() - 2 * spotShift_delta);//shift back
                barrierOption.recalculate();
                priceBS_delta2 = barrierOption.NPV();

                ((SimpleQuote)x0Quote.currentLink()).setValue(x0Quote.link.value() + spotShift_delta);//set back
                double deltaBar2 = (priceBS_delta1 - priceBS_delta2) / (2.0 * spotShift_delta);

                double vannaBarBS = (deltaBar2 - deltaBar1) / sigmaShift_vanna;

                ((SimpleQuote)atmVolQuote.currentLink()).setValue(atmVolQuote.link.value() - sigmaShift_vanna);//set back

                //Matrix
                Matrix A = new Matrix(3, 3, 0.0);

                //analytical
                A[0, 0] = vegaAtm_Analytical;
                A[0, 1] = vega25Call_Analytical;
                A[0, 2] = vega25Put_Analytical;
                A[1, 0] = vannaAtm_Analytical;
                A[1, 1] = vanna25Call_Analytical;
                A[1, 2] = vanna25Put_Analytical;
                A[2, 0] = volgaAtm_Analytical;
                A[2, 1] = volga25Call_Analytical;
                A[2, 2] = volga25Put_Analytical;

                Vector b = new Vector(3, 0.0);
                b[0] = vegaBarBS;
                b[1] = vannaBarBS;
                b[2] = volgaBarBS;

                //Vector q = inverse(A) * b; TODO implements transpose
                Vector q = Matrix.inverse(A) * b;


                //touch probability
                CumulativeNormalDistribution cnd = new CumulativeNormalDistribution();
                double mu = domesticTS_.link.zeroRate(T_, Compounding.Continuous).value() -
                            foreignTS_.link.zeroRate(T_, Compounding.Continuous).value() -
                            Math.Pow(atmVol_.link.value(), 2.0) / 2.0;
                double h2 = (Math.Log(arguments_.barrier.GetValueOrDefault() / x0Quote.link.value()) + mu * T_) /
                            (atmVol_.link.value() * Math.Sqrt(T_));
                double h2Prime = (Math.Log(x0Quote.link.value() / arguments_.barrier.GetValueOrDefault()) + mu * T_) /
                                 (atmVol_.link.value() * Math.Sqrt(T_));
                double probTouch = 0.0;
                if (arguments_.barrierType == Barrier.Type.UpIn || arguments_.barrierType == Barrier.Type.UpOut)
                {
                    probTouch = cnd.value(h2Prime) + Math.Pow(arguments_.barrier.GetValueOrDefault() / x0Quote.link.value(),
                                                              2.0 * mu / Math.Pow(atmVol_.link.value(), 2.0)) * cnd.value(-h2);
                }
                else
                {
                    probTouch = cnd.value(-h2Prime) + Math.Pow(arguments_.barrier.GetValueOrDefault() / x0Quote.link.value(),
                                                               2.0 * mu / Math.Pow(atmVol_.link.value(), 2.0)) * cnd.value(h2);
                }
                double p_survival = 1.0 - probTouch;

                double lambda = p_survival;
                double adjust = q[0] * (priceAtmCallMkt - priceAtmCallBS)
                                + q[1] * (price25CallMkt - price25CallBS)
                                + q[2] * (price25PutMkt - price25PutBS);
                double outPrice = priceBS + lambda * adjust;//
                double inPrice;

                //adapt Vanilla delta
                if (adaptVanDelta_ == true)
                {
                    outPrice += lambda * (bsPriceWithSmile_ - vanillaOption);
                    //capfloored by (0, vanilla)
                    outPrice = Math.Max(0.0, Math.Min(bsPriceWithSmile_, outPrice));
                    inPrice  = bsPriceWithSmile_ - outPrice;
                }
                else
                {
                    //capfloored by (0, vanilla)
                    outPrice = Math.Max(0.0, Math.Min(vanillaOption, outPrice));
                    inPrice  = vanillaOption - outPrice;
                }

                if (arguments_.barrierType == Barrier.Type.DownOut || arguments_.barrierType == Barrier.Type.UpOut)
                {
                    results_.value = outPrice;
                }
                else
                {
                    results_.value = inPrice;
                }

                results_.additionalResults["VanillaPrice"]    = vanillaOption;
                results_.additionalResults["BarrierInPrice"]  = inPrice;
                results_.additionalResults["BarrierOutPrice"] = outPrice;
                results_.additionalResults["lambda"]          = lambda;
            }
        }
        public override void calculate()
        {
            double sigmaShift_vega  = 0.001;
            double sigmaShift_volga = 0.0001;
            double spotShift_delta  = 0.0001 * spotFX_.link.value();
            double sigmaShift_vanna = 0.0001;

            Utils.QL_REQUIRE(arguments_.barrierType == DoubleBarrier.Type.KnockIn ||
                             arguments_.barrierType == DoubleBarrier.Type.KnockOut, () =>
                             "Only same type barrier supported");

            Handle <Quote> x0Quote     = new Handle <Quote>(new SimpleQuote(spotFX_.link.value()));
            Handle <Quote> atmVolQuote = new Handle <Quote>(new SimpleQuote(atmVol_.link.value()));

            BlackVolTermStructure blackVolTS = new BlackConstantVol(Settings.evaluationDate(),
                                                                    new NullCalendar(), atmVolQuote, new Actual365Fixed());

            BlackScholesMertonProcess stochProcess = new BlackScholesMertonProcess(x0Quote, foreignTS_, domesticTS_,
                                                                                   new Handle <BlackVolTermStructure>(blackVolTS));

            IPricingEngine engineBS = getOriginalEngine_(stochProcess, series_);

            BlackDeltaCalculator blackDeltaCalculatorAtm = new BlackDeltaCalculator(
                Option.Type.Call, atmVol_.link.deltaType(), x0Quote.link.value(),
                domesticTS_.link.discount(T_), foreignTS_.link.discount(T_),
                atmVol_.link.value() * Math.Sqrt(T_));

            double atmStrike = blackDeltaCalculatorAtm.atmStrike(atmVol_.link.atmType());

            double call25Vol = vol25Call_.link.value();
            double put25Vol  = vol25Put_.link.value();
            BlackDeltaCalculator blackDeltaCalculatorPut25 = new BlackDeltaCalculator(
                Option.Type.Put, vol25Put_.link.deltaType(), x0Quote.link.value(),
                domesticTS_.link.discount(T_), foreignTS_.link.discount(T_),
                put25Vol * Math.Sqrt(T_));
            double put25Strike = blackDeltaCalculatorPut25.strikeFromDelta(-0.25);
            BlackDeltaCalculator blackDeltaCalculatorCall25 = new BlackDeltaCalculator(
                Option.Type.Call, vol25Call_.link.deltaType(), x0Quote.link.value(),
                domesticTS_.link.discount(T_), foreignTS_.link.discount(T_),
                call25Vol * Math.Sqrt(T_));
            double call25Strike = blackDeltaCalculatorCall25.strikeFromDelta(0.25);

            //here use vanna volga interpolated smile to price vanilla
            List <double> strikes = new List <double>();
            List <double> vols    = new List <double>();

            strikes.Add(put25Strike);
            vols.Add(put25Vol);
            strikes.Add(atmStrike);
            vols.Add(atmVol_.link.value());
            strikes.Add(call25Strike);
            vols.Add(call25Vol);
            VannaVolga vannaVolga = new VannaVolga(x0Quote.link.value(), foreignTS_.link.discount(T_),
                                                   foreignTS_.link.discount(T_), T_);
            Interpolation interpolation = vannaVolga.interpolate(strikes, strikes.Count, vols);

            interpolation.enableExtrapolation();
            StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff;

            Utils.QL_REQUIRE(payoff != null, () => "invalid payoff");
            double strikeVol = interpolation.value(payoff.strike());
            //vannila option price
            double vanillaOption = Utils.blackFormula(payoff.optionType(), payoff.strike(),
                                                      x0Quote.link.value() * foreignTS_.link.discount(T_) / domesticTS_.link.discount(T_),
                                                      strikeVol * Math.Sqrt(T_),
                                                      domesticTS_.link.discount(T_));

            //already out
            if ((x0Quote.link.value() > arguments_.barrier_hi || x0Quote.link.value() < arguments_.barrier_lo) &&
                arguments_.barrierType == DoubleBarrier.Type.KnockOut)
            {
                results_.value = 0.0;
                results_.additionalResults["VanillaPrice"]    = adaptVanDelta_? bsPriceWithSmile_ : vanillaOption;
                results_.additionalResults["BarrierInPrice"]  = adaptVanDelta_? bsPriceWithSmile_ : vanillaOption;
                results_.additionalResults["BarrierOutPrice"] = 0.0;
            }
            //already in
            else if ((x0Quote.link.value() > arguments_.barrier_hi || x0Quote.link.value() < arguments_.barrier_lo) &&
                     arguments_.barrierType == DoubleBarrier.Type.KnockIn)
            {
                results_.value = adaptVanDelta_? bsPriceWithSmile_ : vanillaOption;
                results_.additionalResults["VanillaPrice"]    = adaptVanDelta_? bsPriceWithSmile_ : vanillaOption;
                results_.additionalResults["BarrierInPrice"]  = adaptVanDelta_? bsPriceWithSmile_ : vanillaOption;
                results_.additionalResults["BarrierOutPrice"] = 0.0;
            }
            else
            {
                //set up BS barrier option pricing
                //only calculate out barrier option price
                // in barrier price = vanilla - out barrier
                //StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff;
                DoubleBarrierOption doubleBarrierOption = new DoubleBarrierOption(
                    arguments_.barrierType,
                    arguments_.barrier_lo.GetValueOrDefault(),
                    arguments_.barrier_hi.GetValueOrDefault(),
                    arguments_.rebate.GetValueOrDefault(),
                    payoff,
                    arguments_.exercise);

                doubleBarrierOption.setPricingEngine(engineBS);

                //BS price
                double priceBS = doubleBarrierOption.NPV();

                double priceAtmCallBS = Utils.blackFormula(Option.Type.Call, atmStrike,
                                                           x0Quote.link.value() * foreignTS_.link.discount(T_) / domesticTS_.link.discount(T_),
                                                           atmVol_.link.value() * Math.Sqrt(T_),
                                                           domesticTS_.link.discount(T_));
                double price25CallBS = Utils.blackFormula(Option.Type.Call, call25Strike,
                                                          x0Quote.link.value() * foreignTS_.link.discount(T_) / domesticTS_.link.discount(T_),
                                                          atmVol_.link.value() * Math.Sqrt(T_),
                                                          domesticTS_.link.discount(T_));
                double price25PutBS = Utils.blackFormula(Option.Type.Put, put25Strike,
                                                         x0Quote.link.value() * foreignTS_.link.discount(T_) / domesticTS_.link.discount(T_),
                                                         atmVol_.link.value() * Math.Sqrt(T_),
                                                         domesticTS_.link.discount(T_));

                //market price
                double priceAtmCallMkt = Utils.blackFormula(Option.Type.Call, atmStrike,
                                                            x0Quote.link.value() * foreignTS_.link.discount(T_) / domesticTS_.link.discount(T_),
                                                            atmVol_.link.value() * Math.Sqrt(T_),
                                                            domesticTS_.link.discount(T_));
                double price25CallMkt = Utils.blackFormula(Option.Type.Call, call25Strike,
                                                           x0Quote.link.value() * foreignTS_.link.discount(T_) / domesticTS_.link.discount(T_),
                                                           call25Vol * Math.Sqrt(T_),
                                                           domesticTS_.link.discount(T_));
                double price25PutMkt = Utils.blackFormula(Option.Type.Put, put25Strike,
                                                          x0Quote.link.value() * foreignTS_.link.discount(T_) / domesticTS_.link.discount(T_),
                                                          put25Vol * Math.Sqrt(T_),
                                                          domesticTS_.link.discount(T_));

                //Analytical Black Scholes formula
                NormalDistribution norm  = new NormalDistribution();
                double             d1atm = (Math.Log(x0Quote.link.value() * foreignTS_.link.discount(T_) / domesticTS_.link.discount(T_) / atmStrike)
                                            + 0.5 * Math.Pow(atmVolQuote.link.value(), 2.0) * T_) / (atmVolQuote.link.value() * Math.Sqrt(T_));
                double vegaAtm_Analytical  = x0Quote.link.value() * norm.value(d1atm) * Math.Sqrt(T_) * foreignTS_.link.discount(T_);
                double vannaAtm_Analytical = vegaAtm_Analytical / x0Quote.link.value() * (1.0 - d1atm / (atmVolQuote.link.value() * Math.Sqrt(T_)));
                double volgaAtm_Analytical = vegaAtm_Analytical * d1atm * (d1atm - atmVolQuote.link.value() * Math.Sqrt(T_)) / atmVolQuote.link.value();

                double d125call = (Math.Log(x0Quote.link.value() * foreignTS_.link.discount(T_) / domesticTS_.link.discount(T_) / call25Strike)
                                   + 0.5 * Math.Pow(atmVolQuote.link.value(), 2.0) * T_) / (atmVolQuote.link.value() * Math.Sqrt(T_));
                double vega25Call_Analytical  = x0Quote.link.value() * norm.value(d125call) * Math.Sqrt(T_) * foreignTS_.link.discount(T_);
                double vanna25Call_Analytical = vega25Call_Analytical / x0Quote.link.value() * (1.0 - d125call / (atmVolQuote.link.value() * Math.Sqrt(T_)));
                double volga25Call_Analytical = vega25Call_Analytical * d125call * (d125call - atmVolQuote.link.value() * Math.Sqrt(T_)) / atmVolQuote.link.value();

                double d125Put = (Math.Log(x0Quote.link.value() * foreignTS_.link.discount(T_) / domesticTS_.link.discount(T_) / put25Strike)
                                  + 0.5 * Math.Pow(atmVolQuote.link.value(), 2.0) * T_) / (atmVolQuote.link.value() * Math.Sqrt(T_));
                double vega25Put_Analytical  = x0Quote.link.value() * norm.value(d125Put) * Math.Sqrt(T_) * foreignTS_.link.discount(T_);
                double vanna25Put_Analytical = vega25Put_Analytical / x0Quote.link.value() * (1.0 - d125Put / (atmVolQuote.link.value() * Math.Sqrt(T_)));
                double volga25Put_Analytical = vega25Put_Analytical * d125Put * (d125Put - atmVolQuote.link.value() * Math.Sqrt(T_)) / atmVolQuote.link.value();


                //BS vega
                ((SimpleQuote)atmVolQuote.currentLink()).setValue(atmVolQuote.link.value() + sigmaShift_vega);
                doubleBarrierOption.recalculate();
                double vegaBarBS = (doubleBarrierOption.NPV() - priceBS) / sigmaShift_vega;
                ((SimpleQuote)atmVolQuote.currentLink()).setValue(atmVolQuote.link.value() - sigmaShift_vega);//setback

                //BS volga

                //vegaBar2
                //base NPV
                ((SimpleQuote)atmVolQuote.currentLink()).setValue(atmVolQuote.link.value() + sigmaShift_volga);
                doubleBarrierOption.recalculate();
                double priceBS2 = doubleBarrierOption.NPV();

                //shifted npv
                ((SimpleQuote)atmVolQuote.currentLink()).setValue(atmVolQuote.link.value() + sigmaShift_vega);
                doubleBarrierOption.recalculate();
                double vegaBarBS2 = (doubleBarrierOption.NPV() - priceBS2) / sigmaShift_vega;
                double volgaBarBS = (vegaBarBS2 - vegaBarBS) / sigmaShift_volga;
                ((SimpleQuote)atmVolQuote.currentLink()).setValue(atmVolQuote.link.value()
                                                                  - sigmaShift_volga
                                                                  - sigmaShift_vega);                        //setback

                //BS Delta
                //base delta
                ((SimpleQuote)x0Quote.currentLink()).setValue(x0Quote.link.value() + spotShift_delta);//shift forth
                doubleBarrierOption.recalculate();
                double priceBS_delta1 = doubleBarrierOption.NPV();

                ((SimpleQuote)x0Quote.currentLink()).setValue(x0Quote.link.value() - 2 * spotShift_delta);//shift back
                doubleBarrierOption.recalculate();
                double priceBS_delta2 = doubleBarrierOption.NPV();

                ((SimpleQuote)x0Quote.currentLink()).setValue(x0Quote.link.value() + spotShift_delta);//set back
                double deltaBar1 = (priceBS_delta1 - priceBS_delta2) / (2.0 * spotShift_delta);

                //shifted vanna
                ((SimpleQuote)atmVolQuote.currentLink()).setValue(atmVolQuote.link.value() + sigmaShift_vanna); //shift sigma
                //shifted delta
                ((SimpleQuote)x0Quote.currentLink()).setValue(x0Quote.link.value() + spotShift_delta);          //shift forth
                doubleBarrierOption.recalculate();
                priceBS_delta1 = doubleBarrierOption.NPV();

                ((SimpleQuote)x0Quote.currentLink()).setValue(x0Quote.link.value() - 2 * spotShift_delta);//shift back
                doubleBarrierOption.recalculate();
                priceBS_delta2 = doubleBarrierOption.NPV();

                ((SimpleQuote)x0Quote.currentLink()).setValue(x0Quote.link.value() + spotShift_delta);//set back
                double deltaBar2 = (priceBS_delta1 - priceBS_delta2) / (2.0 * spotShift_delta);

                double vannaBarBS = (deltaBar2 - deltaBar1) / sigmaShift_vanna;

                ((SimpleQuote)atmVolQuote.currentLink()).setValue(atmVolQuote.link.value() - sigmaShift_vanna);//set back

                //Matrix
                Matrix A = new Matrix(3, 3, 0.0);

                //analytical
                A[0, 0] = vegaAtm_Analytical;
                A[0, 1] = vega25Call_Analytical;
                A[0, 2] = vega25Put_Analytical;
                A[1, 0] = vannaAtm_Analytical;
                A[1, 1] = vanna25Call_Analytical;
                A[1, 2] = vanna25Put_Analytical;
                A[2, 0] = volgaAtm_Analytical;
                A[2, 1] = volga25Call_Analytical;
                A[2, 2] = volga25Put_Analytical;

                Vector b = new Vector(3, 0.0);
                b[0] = vegaBarBS;
                b[1] = vannaBarBS;
                b[2] = volgaBarBS;
                Vector q = Matrix.inverse(A) * b;

                double H = arguments_.barrier_hi.GetValueOrDefault();
                double L = arguments_.barrier_lo.GetValueOrDefault();
                double theta_tilt_minus = ((domesticTS_.link.zeroRate(T_, Compounding.Continuous).value() -
                                            foreignTS_.link.zeroRate(T_, Compounding.Continuous).value()) /
                                           atmVol_.link.value() - atmVol_.link.value() / 2.0) * Math.Sqrt(T_);
                double h = 1.0 / atmVol_.link.value() * Math.Log(H / x0Quote.link.value()) / Math.Sqrt(T_);
                double l = 1.0 / atmVol_.link.value() * Math.Log(L / x0Quote.link.value()) / Math.Sqrt(T_);
                CumulativeNormalDistribution cnd = new CumulativeNormalDistribution();

                double doubleNoTouch = 0.0;
                for (int j = -series_; j < series_; j++)
                {
                    double e_minus = 2 * j * (h - l) - theta_tilt_minus;
                    doubleNoTouch += Math.Exp(-2.0 * j * theta_tilt_minus * (h - l)) * (cnd.value(h + e_minus) - cnd.value(l + e_minus))
                                     - Math.Exp(-2.0 * j * theta_tilt_minus * (h - l) + 2.0 * theta_tilt_minus * h) *
                                     (cnd.value(h - 2.0 * h + e_minus) - cnd.value(l - 2.0 * h + e_minus));
                }

                double p_survival = doubleNoTouch;

                double lambda = p_survival;
                double adjust = q[0] * (priceAtmCallMkt - priceAtmCallBS)
                                + q[1] * (price25CallMkt - price25CallBS)
                                + q[2] * (price25PutMkt - price25PutBS);
                double outPrice = priceBS + lambda * adjust;//
                double inPrice;

                //adapt Vanilla delta
                if (adaptVanDelta_ == true)
                {
                    outPrice += lambda * (bsPriceWithSmile_ - vanillaOption);
                    //capfloored by (0, vanilla)
                    outPrice = Math.Max(0.0, Math.Min(bsPriceWithSmile_, outPrice));
                    inPrice  = bsPriceWithSmile_ - outPrice;
                }
                else
                {
                    //capfloored by (0, vanilla)
                    outPrice = Math.Max(0.0, Math.Min(vanillaOption, outPrice));
                    inPrice  = vanillaOption - outPrice;
                }

                if (arguments_.barrierType == DoubleBarrier.Type.KnockOut)
                {
                    results_.value = outPrice;
                }
                else
                {
                    results_.value = inPrice;
                }

                results_.additionalResults["VanillaPrice"]    = vanillaOption;
                results_.additionalResults["BarrierInPrice"]  = inPrice;
                results_.additionalResults["BarrierOutPrice"] = outPrice;
                results_.additionalResults["lambda"]          = lambda;
            }
        }
Exemple #4
0
        public override void calculate(DateTime calcDate, FP_Parameter fp_parameter)
        {
            // master data load

            this.indexOptionDAO_.SelectOwn();

            // market data load
            
            // index data
            clsHDAT_MARKETDATA_TB clstb = new clsHDAT_MARKETDATA_TB();

            string calcDateStr = calcDate.ToString("yyyyMMdd");
            QLNet.Settings.setEvaluationDate(calcDate);

            clstb.REF_DT = calcDateStr;
            clstb.INDEX_CD = this.indexOptionDAO_.UNDERLYING_INDEX_CD;

            int checkNum = clstb.SelectOwn();

            if (checkNum == 0) { throw new Exception("market data does not exist : " + calcDateStr + " " + clstb.INDEX_CD); }

            double indexData = clstb.LAST;

            // curveData --------------------------------------------------

            string curve_cd = "IRSKRW";
            
            YieldCurve curveManager = new YieldCurve();

            curveManager.loadCurveData(calcDate,curve_cd,clsHDAT_CURVEDATA_TB.RATE_TYP_Type.YTM);
            QLNet.YieldTermStructure yield_ts = curveManager.yieldCurve();

            // calculate

            string maturityDateStr = this.indexOptionDAO_.MATURITY_DT;

            System.Globalization.CultureInfo us
                = new System.Globalization.CultureInfo("en-US");

            DateTime maturityDate = DateTime.ParseExact(maturityDateStr, "yyyyMMdd", us);

            DayCounter dc = new Actual365Fixed();
            Calendar cal = new NullCalendar();

            double vol = 0.3;

            double strike = this.indexOptionDAO_.STRIKE;
            PlainVanillaPayoff strikePayoff = new PlainVanillaPayoff(Option.Type.
                Call, strike);

            Exercise exercise = new EuropeanExercise(maturityDate);

            VanillaOption q_option = new VanillaOption(strikePayoff,exercise);

            Handle<Quote> x0 = new Handle<Quote>(new SimpleQuote(indexData));
            FlatForward flatForward = new FlatForward(calcDate,0.01,dc);
            Handle<YieldTermStructure> dividendTS = new Handle<YieldTermStructure>(flatForward);
            Handle<YieldTermStructure> riskFreeTS = new Handle<YieldTermStructure>(yield_ts);
            BlackConstantVol blackConstVol = new BlackConstantVol(calcDate,cal,vol,dc);
            Handle<BlackVolTermStructure> blackVolTS = new Handle<BlackVolTermStructure>(blackConstVol);

            GeneralizedBlackScholesProcess process =new GeneralizedBlackScholesProcess(x0 ,dividendTS,riskFreeTS,blackVolTS);
            
            AnalyticEuropeanEngine europeanEngine = new AnalyticEuropeanEngine(process);

            q_option.setPricingEngine(europeanEngine);

            double value = q_option.NPV(); 
            double indexMultiplier = this.indexOptionDAO_.INDEX_MULTIPLIER;
            int quantity = this.indexOptionDAO_.QUANTITY;

            clsHITM_FP_GREEKRESULT_TB result_tb = new clsHITM_FP_GREEKRESULT_TB();

            result_tb.FP_GREEKRESULT_ID = IDGenerator.getNewGreekResultID(this.indexOptionDAO_.INSTRUMENT_ID,calcDateStr);
            result_tb.CALC_DT = calcDateStr;
            result_tb.INSTRUMENT_ID = this.indexOptionDAO_.INSTRUMENT_ID;
            result_tb.INSTRUMENT_TYP = this.indexOptionDAO_.INSTRUMENT_TYP;
            result_tb.UNDERLYING_ID = "KOSPI200";
            result_tb.UNDERLYING_VALUE = indexData;
            //result_tb.SEQ = 1;
            result_tb.DELTA = (q_option.delta() * indexData / 100) * indexMultiplier * quantity; // 1% Delta
            result_tb.GAMMA = 0.5 * (q_option.gamma() * indexData / 100) * indexMultiplier * quantity; // 1% Gamma
            result_tb.VEGA = q_option.vega() / 100 * indexMultiplier * quantity; // 1% point Vega
            result_tb.CALC_PRICE = value * indexMultiplier * quantity;
            result_tb.CALCULATED_FLAG = (int)clsHITM_FP_GREEKRESULT_TB.CALCULATED_FLAG_Type.CALCULATED;
            result_tb.CALCULATED_TIME = DateTime.Now.ToString("HHmmss"); ;
            result_tb.CALCULATE_TYP = (int)clsHITM_FP_GREEKRESULT_TB.CALCULATE_TYP_Type.ANALYTICS;

            // price

            if (result_tb.UpdateDateResult() == 0)
            { throw new Exception("update result fail. no exist , calcDate : " + calcDate.ToString("yyyyMMdd") + " , inst_id : " + result_tb.INSTRUMENT_ID); }

            // delta

            // gamma and others : no exist ?


        }