コード例 #1
0
 private void REPORT_FAILURE(string greekName,
                             StrikedTypePayoff payoff,
                             Exercise exercise,
                             DoubleBarrier.Type barrierType,
                             double barrier_lo,
                             double barrier_hi,
                             double s,
                             double q,
                             double r,
                             Date today,
                             double v,
                             double expected,
                             double calculated,
                             double error,
                             double tolerance)
 {
     QAssert.Fail(payoff.optionType() + " option with "
                  + barrierType + " barrier type:\n"
                  + "    barrier_lo:          " + barrier_lo + "\n"
                  + "    barrier_hi:          " + barrier_hi + "\n"
                  + payoff + " payoff:\n"
                  + exercise + " "
                  + payoff.optionType()
                  + "    spot value: " + s + "\n"
                  + "    strike:           " + payoff.strike() + "\n"
                  + "    dividend yield:   " + q + "\n"
                  + "    risk-free rate:   " + r + "\n"
                  + "    reference date:   " + today + "\n"
                  + "    maturity:         " + exercise.lastDate() + "\n"
                  + "    volatility:       " + v + "\n\n"
                  + "    expected " + greekName + ":   " + expected + "\n"
                  + "    calculated " + greekName + ": " + calculated + "\n"
                  + "    error:            " + error + "\n"
                  + "    tolerance:        " + tolerance);
 }
 public DoubleBarrierOption(DoubleBarrier.Type barrierType, double barrier_lo, double barrier_hi, double rebate, StrikedTypePayoff payoff, Exercise exercise) : this(NQuantLibcPINVOKE.new_DoubleBarrierOption((int)barrierType, barrier_lo, barrier_hi, rebate, StrikedTypePayoff.getCPtr(payoff), Exercise.getCPtr(exercise)), true)
 {
     if (NQuantLibcPINVOKE.SWIGPendingException.Pending)
     {
         throw NQuantLibcPINVOKE.SWIGPendingException.Retrieve();
     }
 }
コード例 #3
0
 public void REPORT_FAILURE_VANNAVOLGA(string greekName, DoubleBarrier.Type barrierType,
                                       double barrier1, double barrier2, double rebate,
                                       StrikedTypePayoff payoff, Exercise exercise, double s, double q,
                                       double r, Date today, double vol25Put, double atmVol, double vol25Call, double v,
                                       double expected, double calculated, double error, double tolerance)
 {
     QAssert.Fail("Double Barrier Option " + barrierType + " " + exercise + " "
                  + payoff.optionType() + " option with "
                  + payoff + " payoff:\n"
                  + "    underlying value: " + s + "\n"
                  + "    strike:           " + payoff.strike() + "\n"
                  + "    barrier 1:        " + barrier1 + "\n"
                  + "    barrier 2:        " + barrier2 + "\n"
                  + "    rebate :          " + rebate + "\n"
                  + "    dividend yield:   " + q + "\n"
                  + "    risk-free rate:   " + r + "\n"
                  + "    reference date:   " + today + "\n"
                  + "    maturity:         " + exercise.lastDate() + "\n"
                  + "    25PutVol:         " + +(vol25Put) + "\n"
                  + "    atmVol:           " + (atmVol) + "\n"
                  + "    25CallVol:        " + (vol25Call) + "\n"
                  + "    volatility:       " + v + "\n\n"
                  + "    expected " + greekName + ":   " + expected + "\n"
                  + "    calculated " + greekName + ": " + calculated + "\n"
                  + "    error:            " + error + "\n"
                  + "    tolerance:        " + tolerance);
 }
コード例 #4
0
        // helper object methods
        public double payoffKIKO(double spot, double variance,
                                 DoubleBarrier.Type barrierType,
                                 int maxIteration           = 1000,
                                 double requiredConvergence = 1e-8)
        {
            Utils.QL_REQUIRE(spot > 0.0,
                             () => "positive spot value required");

            Utils.QL_REQUIRE(variance >= 0.0,
                             () => "negative variance not allowed");

            double residualTime = process_.time(arguments_.exercise.lastDate());

            Utils.QL_REQUIRE(residualTime > 0.0,
                             () => "expiration time must be > 0");

            double cash       = payoff_.cashPayoff();
            double barrier_lo = arguments_.barrier_lo.Value;
            double barrier_hi = arguments_.barrier_hi.Value;

            if (barrierType == DoubleBarrier.Type.KOKI)
            {
                Utils.swap(ref barrier_lo, ref barrier_hi);
            }

            double sigmaq = variance / residualTime;
            double r      = process_.riskFreeRate().currentLink().zeroRate(residualTime, Compounding.Continuous,
                                                                           Frequency.NoFrequency).rate();
            double q = process_.dividendYield().currentLink().zeroRate(residualTime,
                                                                       Compounding.Continuous, Frequency.NoFrequency).rate();
            double b = r - q;

            double alpha   = -0.5 * (2 * b / sigmaq - 1);
            double beta    = -0.25 * Math.Pow((2 * b / sigmaq - 1), 2) - 2 * r / sigmaq;
            double Z       = Math.Log(barrier_hi / barrier_lo);
            double log_S_L = Math.Log(spot / barrier_lo);

            double tot = 0, term = 0;

            for (int i = 1; i < maxIteration; ++i)
            {
                double factor = Math.Pow(i * Const.M_PI / Z, 2) - beta;
                double term1  = (beta - Math.Pow(i * Const.M_PI / Z, 2) * Math.Exp(-0.5 * factor * variance)) / factor;
                double term2  = Math.Sin(i * Const.M_PI / Z * log_S_L);
                term = (2.0 / (i * Const.M_PI)) * term1 * term2;
                tot += term;
            }
            tot += 1 - log_S_L / Z;
            tot *= cash * Math.Pow(spot / barrier_lo, alpha);

            // Check if convergence is sufficiently fast
            Utils.QL_REQUIRE(Math.Abs(term) < requiredConvergence, () => "serie did not converge sufficiently fast");

            return(Math.Max(tot, 0.0));
        }
コード例 #5
0
 public DoubleBarrierOption(DoubleBarrier.Type barrierType,
                            double barrier_lo,
                            double barrier_hi,
                            double rebate,
                            StrikedTypePayoff payoff,
                            Exercise exercise)
     : base(payoff, exercise)
 {
     barrierType_ = barrierType;
     barrier_lo_  = barrier_lo;
     barrier_hi_  = barrier_hi;
     rebate_      = rebate;
 }
コード例 #6
0
            public double             tol;    // tolerance

            public DoubleBinaryOptionData(DoubleBarrier.Type barrierType, double barrier_lo, double barrier_hi, double cash,
                                          double s, double q, double r, double t, double v, double result, double tol) : this()
            {
                this.barrierType = barrierType;
                this.barrier_lo  = barrier_lo;
                this.barrier_hi  = barrier_hi;
                this.cash        = cash;
                this.s           = s;
                this.q           = q;
                this.r           = r;
                this.t           = t;
                this.v           = v;
                this.result      = result;
                this.tol         = tol;
            }
コード例 #7
0
            public double tol;    // tolerance

            public NewBarrierOptionData(DoubleBarrier.Type barrierType, double barrierlo, double barrierhi, Option.Type type, Exercise.Type exType, double strike, double s, double q, double r, double t, double v, double result, double tol)
            {
                this.barrierType = barrierType;
                this.barrierlo   = barrierlo;
                this.barrierhi   = barrierhi;
                this.type        = type;
                this.exType      = exType;
                this.strike      = strike;
                this.s           = s;
                this.q           = q;
                this.r           = r;
                this.t           = t;
                this.v           = v;
                this.result      = result;
                this.tol         = tol;
            }
コード例 #8
0
            public double tol;            // tolerance

            public DoubleBarrierFxOptionData(DoubleBarrier.Type barrierType, double barrier1, double barrier2, double rebate, Option.Type type, double strike, double s, double q, double r, double t, double vol25Put, double volAtm, double vol25Call, double v, double result, double tol)
            {
                this.barrierType = barrierType;
                this.barrier1    = barrier1;
                this.barrier2    = barrier2;
                this.rebate      = rebate;
                this.type        = type;
                this.strike      = strike;
                this.s           = s;
                this.q           = q;
                this.r           = r;
                this.t           = t;
                this.vol25Put    = vol25Put;
                this.volAtm      = volAtm;
                this.vol25Call   = vol25Call;
                this.v           = v;
                this.result      = result;
                this.tol         = tol;
            }
コード例 #9
0
        public void testVannaVolgaDoubleBarrierValues()
        {
            // Testing double-barrier FX options against Vanna/Volga values
            SavedSettings backup = new SavedSettings();

            DoubleBarrierFxOptionData[] values =
            {
                //                             BarrierType,                    barr.1, barr.2, rebate,         type,    strike,          s,         q,         r,  t, vol25Put,    volAtm,vol25Call,      vol,    result,   tol
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Call, 1.13321, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.11638, 0.14413, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Call, 1.22687, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.10088, 0.07456, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Call, 1.31179, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08925, 0.02710, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Call, 1.38843, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08463, 0.00569, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Call, 1.46047, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08412, 0.00013, 1.0e-4),

                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Put,  1.13321, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.11638, 0.00017, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Put,  1.22687, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.10088, 0.00353, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Put,  1.31179, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08925, 0.02221, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Put,  1.38843, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08463, 0.06049, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.1, 1.5, 0.0, Option.Type.Put,  1.46047, 1.30265, 0.0003541, 0.0033871, 1.0, 0.10087, 0.08925, 0.08463, 0.08412, 0.11103, 1.0e-4),

                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Call, 1.06145, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.12511, 0.19981, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Call, 1.19545, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.10890, 0.10389, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Call, 1.32238, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09444, 0.03555, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Call, 1.44298, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09197, 0.00634, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Call, 1.56345, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09261, 0.00000, 1.0e-4),

                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Put,  1.06145, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.12511, 0.00000, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Put,  1.19545, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.10890, 0.00436, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Put,  1.32238, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09444, 0.03173, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Put,  1.44298, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09197, 0.09346, 1.0e-4),
                new DoubleBarrierFxOptionData(DoubleBarrier.Type.KnockOut, 1.0, 1.6, 0.0, Option.Type.Put,  1.56345, 1.30265, 0.0009418, 0.0039788, 2.0, 0.10891, 0.09525, 0.09197, 0.09261, 0.17704, 1.0e-4),
            };

            DayCounter dc    = new Actual360();
            Date       today = new Date(05, Month.Mar, 2013);

            Settings.setEvaluationDate(today);

            SimpleQuote        spot      = new SimpleQuote(0.0);
            SimpleQuote        qRate     = new SimpleQuote(0.0);
            YieldTermStructure qTS       = Utilities.flatRate(today, qRate, dc);
            SimpleQuote        rRate     = new SimpleQuote(0.0);
            YieldTermStructure rTS       = Utilities.flatRate(today, rRate, dc);
            SimpleQuote        vol25Put  = new SimpleQuote(0.0);
            SimpleQuote        volAtm    = new SimpleQuote(0.0);
            SimpleQuote        vol25Call = new SimpleQuote(0.0);

            for (int i = 0; i < values.Length; i++)
            {
                for (int j = 0; j <= 1; j++)
                {
                    DoubleBarrier.Type barrierType = (DoubleBarrier.Type)j;
                    spot.setValue(values[i].s);
                    qRate.setValue(values[i].q);
                    rRate.setValue(values[i].r);
                    vol25Put.setValue(values[i].vol25Put);
                    volAtm.setValue(values[i].volAtm);
                    vol25Call.setValue(values[i].vol25Call);

                    StrikedTypePayoff payoff = new PlainVanillaPayoff(values[i].type, values[i].strike);

                    Date     exDate   = today + (int)(values[i].t * 365 + 0.5);
                    Exercise exercise = new EuropeanExercise(exDate);

                    Handle <DeltaVolQuote> volAtmQuote = new Handle <DeltaVolQuote>(
                        new DeltaVolQuote(new Handle <Quote>(volAtm), DeltaVolQuote.DeltaType.Fwd, values[i].t,
                                          DeltaVolQuote.AtmType.AtmDeltaNeutral));

                    //always delta neutral atm
                    Handle <DeltaVolQuote> vol25PutQuote = new Handle <DeltaVolQuote>(new DeltaVolQuote(-0.25,
                                                                                                        new Handle <Quote>(vol25Put), values[i].t, DeltaVolQuote.DeltaType.Fwd));

                    Handle <DeltaVolQuote> vol25CallQuote = new Handle <DeltaVolQuote>(new DeltaVolQuote(0.25,
                                                                                                         new Handle <Quote>(vol25Call), values[i].t, DeltaVolQuote.DeltaType.Fwd));

                    DoubleBarrierOption doubleBarrierOption = new DoubleBarrierOption(barrierType,
                                                                                      values[i].barrier1, values[i].barrier2, values[i].rebate, payoff, exercise);

                    double bsVanillaPrice = Utils.blackFormula(values[i].type, values[i].strike,
                                                               spot.value() * qTS.discount(values[i].t) / rTS.discount(values[i].t),
                                                               values[i].v * Math.Sqrt(values[i].t), rTS.discount(values[i].t));

                    IPricingEngine vannaVolgaEngine;

                    vannaVolgaEngine = new VannaVolgaDoubleBarrierEngine(volAtmQuote, vol25PutQuote, vol25CallQuote,
                                                                         new Handle <Quote>(spot),
                                                                         new Handle <YieldTermStructure>(rTS),
                                                                         new Handle <YieldTermStructure>(qTS),
                                                                         (process, series) => new WulinYongDoubleBarrierEngine(process, series),
                                                                         true,
                                                                         bsVanillaPrice);
                    doubleBarrierOption.setPricingEngine(vannaVolgaEngine);

                    double expected = 0;
                    if (barrierType == DoubleBarrier.Type.KnockOut)
                    {
                        expected = values[i].result;
                    }
                    else if (barrierType == DoubleBarrier.Type.KnockIn)
                    {
                        expected = (bsVanillaPrice - values[i].result);
                    }

                    double calculated = doubleBarrierOption.NPV();
                    double error      = Math.Abs(calculated - expected);
                    if (error > values[i].tol)
                    {
                        REPORT_FAILURE_VANNAVOLGA("value", values[i].barrierType,
                                                  values[i].barrier1, values[i].barrier2,
                                                  values[i].rebate, payoff, exercise, values[i].s,
                                                  values[i].q, values[i].r, today, values[i].vol25Put,
                                                  values[i].volAtm, values[i].vol25Call, values[i].v,
                                                  expected, calculated, error, values[i].tol);
                    }

                    vannaVolgaEngine = new VannaVolgaDoubleBarrierEngine(volAtmQuote, vol25PutQuote, vol25CallQuote,
                                                                         new Handle <Quote>(spot),
                                                                         new Handle <YieldTermStructure>(rTS),
                                                                         new Handle <YieldTermStructure>(qTS),
                                                                         (process, series) => new AnalyticDoubleBarrierEngine(process, series),
                                                                         true,
                                                                         bsVanillaPrice);
                    doubleBarrierOption.setPricingEngine(vannaVolgaEngine);

                    calculated = doubleBarrierOption.NPV();
                    error      = Math.Abs(calculated - expected);
                    double maxtol = 5.0e-3; // different engines have somewhat different results
                    if (error > maxtol)
                    {
                        REPORT_FAILURE_VANNAVOLGA("value", values[i].barrierType,
                                                  values[i].barrier1, values[i].barrier2,
                                                  values[i].rebate, payoff, exercise, values[i].s,
                                                  values[i].q, values[i].r, today, values[i].vol25Put,
                                                  values[i].volAtm, values[i].vol25Call, values[i].v,
                                                  expected, calculated, error, values[i].tol);
                    }
                }
            }
        }
コード例 #10
0
        public override void calculate()
        {
            Utils.QL_REQUIRE(arguments_.exercise.type() == Exercise.Type.European, () =>
                             "this engine handles only european options");

            PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff;

            Utils.QL_REQUIRE(payoff != null, () => "non-plain payoff given");

            double strike = payoff.strike();

            Utils.QL_REQUIRE(strike > 0.0, () => "strike must be positive");

            double spot = underlying();

            Utils.QL_REQUIRE(spot >= 0.0, () => "negative or null underlying given");
            Utils.QL_REQUIRE(!triggered(spot), () => "barrier(s) already touched");

            DoubleBarrier.Type barrierType = arguments_.barrierType;

            if (triggered(spot))
            {
                if (barrierType == DoubleBarrier.Type.KnockIn)
                {
                    results_.value = vanillaEquivalent(); // knocked in
                }
                else
                {
                    results_.value = 0.0; // knocked out
                }
            }
            else
            {
                switch (payoff.optionType())
                {
                case Option.Type.Call:
                    switch (barrierType)
                    {
                    case DoubleBarrier.Type.KnockIn:
                        results_.value = callKI();
                        break;

                    case DoubleBarrier.Type.KnockOut:
                        results_.value = callKO();
                        break;

                    case DoubleBarrier.Type.KIKO:
                    case DoubleBarrier.Type.KOKI:
                        Utils.QL_FAIL("unsupported double-barrier type: " + barrierType);
                        break;

                    default:
                        Utils.QL_FAIL("unknown double-barrier type: " + barrierType);
                        break;
                    }
                    break;

                case Option.Type.Put:
                    switch (barrierType)
                    {
                    case DoubleBarrier.Type.KnockIn:
                        results_.value = putKI();
                        break;

                    case DoubleBarrier.Type.KnockOut:
                        results_.value = putKO();
                        break;

                    case DoubleBarrier.Type.KIKO:
                    case DoubleBarrier.Type.KOKI:
                        Utils.QL_FAIL("unsupported double-barrier type: " + barrierType);
                        break;

                    default:
                        Utils.QL_FAIL("unknown double-barrier type: " + barrierType);
                        break;
                    }
                    break;

                default:
                    Utils.QL_FAIL("unknown type");
                    break;
                }
            }
        }
コード例 #11
0
        // helper object methods
        public double payoffAtExpiry(double spot, double variance,
                                     DoubleBarrier.Type barrierType,
                                     int maxIteration           = 100,
                                     double requiredConvergence = 1e-8)
        {
            Utils.QL_REQUIRE(spot > 0.0,
                             () => "positive spot value required");

            Utils.QL_REQUIRE(variance >= 0.0,
                             () => "negative variance not allowed");

            double residualTime = process_.time(arguments_.exercise.lastDate());

            Utils.QL_REQUIRE(residualTime > 0.0,
                             () => "expiration time must be > 0");

            // Option::Type type   = payoff_->optionType(); // this is not used ?
            double cash       = payoff_.cashPayoff();
            double barrier_lo = arguments_.barrier_lo.Value;
            double barrier_hi = arguments_.barrier_hi.Value;

            double sigmaq = variance / residualTime;
            double r      = process_.riskFreeRate().currentLink().zeroRate(residualTime, Compounding.Continuous,
                                                                           Frequency.NoFrequency).rate();
            double q = process_.dividendYield().currentLink().zeroRate(residualTime,
                                                                       Compounding.Continuous, Frequency.NoFrequency).rate();
            double b = r - q;

            double alpha    = -0.5 * (2 * b / sigmaq - 1);
            double beta     = -0.25 * Math.Pow((2 * b / sigmaq - 1), 2) - 2 * r / sigmaq;
            double Z        = Math.Log(barrier_hi / barrier_lo);
            double factor   = ((2 * Const.M_PI * cash) / Math.Pow(Z, 2)); // common factor
            double lo_alpha = Math.Pow(spot / barrier_lo, alpha);
            double hi_alpha = Math.Pow(spot / barrier_hi, alpha);

            double tot = 0, term = 0;

            for (int i = 1; i < maxIteration; ++i)
            {
                double term1 = (lo_alpha - Math.Pow(-1.0, i) * hi_alpha) /
                               (Math.Pow(alpha, 2) + Math.Pow(i * Const.M_PI / Z, 2));
                double term2 = Math.Sin(i * Const.M_PI / Z * Math.Log(spot / barrier_lo));
                double term3 = Math.Exp(-0.5 * (Math.Pow(i * Const.M_PI / Z, 2) - beta) * variance);
                term = factor * i * term1 * term2 * term3;
                tot += term;
            }

            // Check if convergence is sufficiently fast (for extreme parameters with big alpha the convergence can be very
            // poor, see for example Hui "One-touch double barrier binary option value")
            Utils.QL_REQUIRE(Math.Abs(term) < requiredConvergence, () => "serie did not converge sufficiently fast");

            if (barrierType == DoubleBarrier.Type.KnockOut)
            {
                return(Math.Max(tot, 0.0)); // KO
            }
            else
            {
                double discount = process_.riskFreeRate().currentLink().discount(
                    arguments_.exercise.lastDate());
                Utils.QL_REQUIRE(discount > 0.0,
                                 () => "positive discount required");
                return(Math.Max(cash * discount - tot, 0.0)); // KI
            }
        }
コード例 #12
0
        public override void calculate()
        {
            if (arguments_.barrierType == DoubleBarrier.Type.KIKO ||
                arguments_.barrierType == DoubleBarrier.Type.KOKI)
            {
                AmericanExercise ex = arguments_.exercise as AmericanExercise;
                Utils.QL_REQUIRE(ex != null, () => "KIKO/KOKI options must have American exercise");
                Utils.QL_REQUIRE(ex.dates()[0] <=
                                 process_.blackVolatility().currentLink().referenceDate(),
                                 () => "American option with window exercise not handled yet");
            }
            else
            {
                EuropeanExercise ex = arguments_.exercise as EuropeanExercise;
                Utils.QL_REQUIRE(ex != null, () => "non-European exercise given");
            }
            CashOrNothingPayoff payoff = arguments_.payoff as CashOrNothingPayoff;

            Utils.QL_REQUIRE(payoff != null, () => "a cash-or-nothing payoff must be given");

            double spot = process_.stateVariable().currentLink().value();

            Utils.QL_REQUIRE(spot > 0.0, () => "negative or null underlying given");

            double variance =
                process_.blackVolatility().currentLink().blackVariance(
                    arguments_.exercise.lastDate(),
                    payoff.strike());
            double barrier_lo = arguments_.barrier_lo.Value;
            double barrier_hi = arguments_.barrier_hi.Value;

            DoubleBarrier.Type barrierType = arguments_.barrierType;
            Utils.QL_REQUIRE(barrier_lo > 0.0,
                             () => "positive low barrier value required");
            Utils.QL_REQUIRE(barrier_hi > 0.0,
                             () => "positive high barrier value required");
            Utils.QL_REQUIRE(barrier_lo < barrier_hi,
                             () => "barrier_lo must be < barrier_hi");
            Utils.QL_REQUIRE(barrierType == DoubleBarrier.Type.KnockIn ||
                             barrierType == DoubleBarrier.Type.KnockOut ||
                             barrierType == DoubleBarrier.Type.KIKO ||
                             barrierType == DoubleBarrier.Type.KOKI,
                             () => "Unsupported barrier type");

            // degenerate cases
            switch (barrierType)
            {
            case DoubleBarrier.Type.KnockOut:
                if (spot <= barrier_lo || spot >= barrier_hi)
                {
                    // knocked out, no value
                    results_.value = 0;
                    results_.delta = 0;
                    results_.gamma = 0;
                    results_.vega  = 0;
                    results_.rho   = 0;
                    return;
                }
                break;

            case DoubleBarrier.Type.KnockIn:
                if (spot <= barrier_lo || spot >= barrier_hi)
                {
                    // knocked in - pays
                    results_.value = payoff.cashPayoff();
                    results_.delta = 0;
                    results_.gamma = 0;
                    results_.vega  = 0;
                    results_.rho   = 0;
                    return;
                }
                break;

            case DoubleBarrier.Type.KIKO:
                if (spot >= barrier_hi)
                {
                    // knocked out, no value
                    results_.value = 0;
                    results_.delta = 0;
                    results_.gamma = 0;
                    results_.vega  = 0;
                    results_.rho   = 0;
                    return;
                }
                else if (spot <= barrier_lo)
                {
                    // knocked in, pays
                    results_.value = payoff.cashPayoff();
                    results_.delta = 0;
                    results_.gamma = 0;
                    results_.vega  = 0;
                    results_.rho   = 0;
                    return;
                }
                break;

            case DoubleBarrier.Type.KOKI:
                if (spot <= barrier_lo)
                {
                    // knocked out, no value
                    results_.value = 0;
                    results_.delta = 0;
                    results_.gamma = 0;
                    results_.vega  = 0;
                    results_.rho   = 0;
                    return;
                }
                else if (spot >= barrier_hi)
                {
                    // knocked in, pays
                    results_.value = payoff.cashPayoff();
                    results_.delta = 0;
                    results_.gamma = 0;
                    results_.vega  = 0;
                    results_.rho   = 0;
                    return;
                }
                break;
            }

            AnalyticDoubleBarrierBinaryEngineHelper helper = new AnalyticDoubleBarrierBinaryEngineHelper(process_,
                                                                                                         payoff, arguments_);

            switch (barrierType)
            {
            case DoubleBarrier.Type.KnockOut:
            case DoubleBarrier.Type.KnockIn:
                results_.value = helper.payoffAtExpiry(spot, variance, barrierType);
                break;

            case DoubleBarrier.Type.KIKO:
            case DoubleBarrier.Type.KOKI:
                results_.value = helper.payoffKIKO(spot, variance, barrierType);
                break;

            default:
                results_.value = null;
                break;
            }
        }
コード例 #13
0
        public override void calculate()
        {
            PlainVanillaPayoff payoff = arguments_.payoff as PlainVanillaPayoff;

            Utils.QL_REQUIRE(payoff != null, () => "non-plain payoff given");
            Utils.QL_REQUIRE(payoff.strike() > 0.0, () => "strike must be positive");

            double K = payoff.strike();
            double S = process_.x0();

            Utils.QL_REQUIRE(S >= 0.0, () => "negative or null underlying given");
            Utils.QL_REQUIRE(!triggered(S), () => "barrier touched");

            DoubleBarrier.Type barrierType = arguments_.barrierType;
            Utils.QL_REQUIRE(barrierType == DoubleBarrier.Type.KnockOut ||
                             barrierType == DoubleBarrier.Type.KnockIn, () =>
                             "only KnockIn and KnockOut options supported");

            double L      = arguments_.barrier_lo.GetValueOrDefault();
            double H      = arguments_.barrier_hi.GetValueOrDefault();
            double K_up   = Math.Min(H, K);
            double K_down = Math.Max(L, K);
            double T      = residualTime();
            double rd     = riskFreeRate();
            double dd     = riskFreeDiscount();
            double rf     = dividendYield();
            double df     = dividendDiscount();
            double vol    = volatility();
            double mu     = rd - rf - vol * vol / 2.0;
            double sgn    = mu > 0 ? 1.0 : (mu < 0 ? -1.0 : 0.0);
            //rebate
            double R_L = arguments_.rebate.GetValueOrDefault();
            double R_H = arguments_.rebate.GetValueOrDefault();

            //european option
            EuropeanOption europeanOption         = new EuropeanOption(payoff, arguments_.exercise);
            IPricingEngine analyticEuropeanEngine = new AnalyticEuropeanEngine(process_);

            europeanOption.setPricingEngine(analyticEuropeanEngine);
            double european = europeanOption.NPV();

            double barrierOut = 0;
            double rebateIn   = 0;

            for (int n = -series_; n < series_; n++)
            {
                double d1      = D(S / H * Math.Pow(L / H, 2.0 * n), vol * vol + mu, vol, T);
                double d2      = d1 - vol * Math.Sqrt(T);
                double g1      = D(H / S * Math.Pow(L / H, 2.0 * n - 1.0), vol * vol + mu, vol, T);
                double g2      = g1 - vol * Math.Sqrt(T);
                double h1      = D(S / H * Math.Pow(L / H, 2.0 * n - 1.0), vol * vol + mu, vol, T);
                double h2      = h1 - vol * Math.Sqrt(T);
                double k1      = D(L / S * Math.Pow(L / H, 2.0 * n - 1.0), vol * vol + mu, vol, T);
                double k2      = k1 - vol * Math.Sqrt(T);
                double d1_down = D(S / K_down * Math.Pow(L / H, 2.0 * n), vol * vol + mu, vol, T);
                double d2_down = d1_down - vol * Math.Sqrt(T);
                double d1_up   = D(S / K_up * Math.Pow(L / H, 2.0 * n), vol * vol + mu, vol, T);
                double d2_up   = d1_up - vol * Math.Sqrt(T);
                double k1_down = D((H * H) / (K_down * S) * Math.Pow(L / H, 2.0 * n), vol * vol + mu, vol, T);
                double k2_down = k1_down - vol * Math.Sqrt(T);
                double k1_up   = D((H * H) / (K_up * S) * Math.Pow(L / H, 2.0 * n), vol * vol + mu, vol, T);
                double k2_up   = k1_up - vol * Math.Sqrt(T);

                if (payoff.optionType() == Option.Type.Call)
                {
                    barrierOut += Math.Pow(L / H, 2.0 * n * mu / (vol * vol)) *
                                  (df * S * Math.Pow(L / H, 2.0 * n) * (f_.value(d1_down) - f_.value(d1))
                                   - dd * K * (f_.value(d2_down) - f_.value(d2))
                                   - df * Math.Pow(L / H, 2.0 * n) * H * H / S * Math.Pow(H / S, 2.0 * mu / (vol * vol)) * (f_.value(k1_down) - f_.value(k1))
                                   + dd * K * Math.Pow(H / S, 2.0 * mu / (vol * vol)) * (f_.value(k2_down) - f_.value(k2)));
                }
                else if (payoff.optionType() == Option.Type.Put)
                {
                    barrierOut += Math.Pow(L / H, 2.0 * n * mu / (vol * vol)) *
                                  (dd * K * (f_.value(h2) - f_.value(d2_up))
                                   - df * S * Math.Pow(L / H, 2.0 * n) * (f_.value(h1) - f_.value(d1_up))
                                   - dd * K * Math.Pow(H / S, 2.0 * mu / (vol * vol)) * (f_.value(g2) - f_.value(k2_up))
                                   + df * Math.Pow(L / H, 2.0 * n) * H * H / S * Math.Pow(H / S, 2.0 * mu / (vol * vol)) * (f_.value(g1) - f_.value(k1_up)));
                }
                else
                {
                    Utils.QL_FAIL("option type not recognized");
                }

                double v1 = D(H / S * Math.Pow(H / L, 2.0 * n), -mu, vol, T);
                double v2 = D(H / S * Math.Pow(H / L, 2.0 * n), mu, vol, T);
                double v3 = D(S / L * Math.Pow(H / L, 2.0 * n), -mu, vol, T);
                double v4 = D(S / L * Math.Pow(H / L, 2.0 * n), mu, vol, T);
                rebateIn += dd * R_H * sgn * (Math.Pow(L / H, 2.0 * n * mu / (vol * vol)) * f_.value(sgn * v1) - Math.Pow(H / S, 2.0 * mu / (vol * vol)) * f_.value(-sgn * v2))
                            + dd * R_L * sgn * (Math.Pow(L / S, 2.0 * mu / (vol * vol)) * f_.value(-sgn * v3) - Math.Pow(H / L, 2.0 * n * mu / (vol * vol)) * f_.value(sgn * v4));
            }

            //rebate paid at maturity
            if (barrierType == DoubleBarrier.Type.KnockOut)
            {
                results_.value = barrierOut;
            }
            else
            {
                results_.value = european - barrierOut;
            }

            results_.additionalResults["vanilla"]    = european;
            results_.additionalResults["barrierOut"] = barrierOut;
            results_.additionalResults["barrierIn"]  = european - barrierOut;
        }