示例#1
0
        /*! \warning currently, this method returns the Black-Scholes
                 implied volatility using analytic formulas for
                 European options and a finite-difference method
                 for American and Bermudan options. It will give
                 unconsistent results if the pricing was performed
                 with any other methods (such as jump-diffusion
                 models.)

        \warning options with a gamma that changes sign (e.g.,
                 binary options) have values that are <b>not</b>
                 monotonic in the volatility. In these cases, the
                 calculation can fail and the result (if any) is
                 almost meaningless.  Another possible source of
                 failure is to have a target value that is not
                 attainable with any volatility, e.g., a target
                 value lower than the intrinsic value in the case
                 of American options.
        */
        //public double impliedVolatility(double price, GeneralizedBlackScholesProcess process,
        //       double accuracy = 1.0e-4, int maxEvaluations = 100, double minVol = 1.0e-7, double maxVol = 4.0) {
        public double impliedVolatility(double targetValue, GeneralizedBlackScholesProcess process,
                                        double accuracy, int maxEvaluations, double minVol, double maxVol) {

            if(isExpired()) throw new ApplicationException("option expired");

            SimpleQuote volQuote = new SimpleQuote();

            GeneralizedBlackScholesProcess newProcess = ImpliedVolatilityHelper.clone(process, volQuote);

            // engines are built-in for the time being
            IPricingEngine engine;
            switch (exercise_.type()) {
                case Exercise.Type.European:
                    engine = new AnalyticEuropeanEngine(newProcess);
                    break;
                case Exercise.Type.American:
                    engine = new FDAmericanEngine(newProcess);
						  break;
                case Exercise.Type.Bermudan:
                    engine = new FDBermudanEngine(newProcess);
						  break;
                default:
                    throw new ArgumentException("unknown exercise type");
            }

            return ImpliedVolatilityHelper.calculate(this, engine, volQuote, targetValue, accuracy,
                                                     maxEvaluations, minVol, maxVol);
        }
        public override void calculate()
        {
            Utils.QL_REQUIRE(process_.x0() > 0.0, () => "negative or null underlying given");

            StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff;

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

            Exercise exercise = arguments_.exercise;

            double t = process_.riskFreeRate().link.dayCounter().yearFraction(process_.riskFreeRate().link.referenceDate(),
                                                                              exercise.lastDate());

            double a     = model_.link.parameters()[0];
            double sigma = model_.link.parameters()[1];
            double eta   = process_.blackVolatility().link.blackVol(exercise.lastDate(), payoff.strike());

            double varianceOffset;

            if (a * t > Math.Pow(Const.QL_EPSILON, 0.25))
            {
                double v  = sigma * sigma / (a * a) * (t + 2 / a * Math.Exp(-a * t) - 1 / (2 * a) * Math.Exp(-2 * a * t) - 3 / (2 * a));
                double mu = 2 * rho_ * sigma * eta / a * (t - 1 / a * (1 - Math.Exp(-a * t)));

                varianceOffset = v + mu;
            }
            else
            {
                // low-a algebraic limit
                double v  = sigma * sigma * t * t * t * (1 / 3.0 - 0.25 * a * t + 7 / 60.0 * a * a * t * t);
                double mu = rho_ * sigma * eta * t * t * (1 - a * t / 3.0 + a * a * t * t / 12.0);

                varianceOffset = v + mu;
            }

            Handle <BlackVolTermStructure> volTS = new Handle <BlackVolTermStructure>(
                new ShiftedBlackVolTermStructure(varianceOffset, process_.blackVolatility()));

            GeneralizedBlackScholesProcess adjProcess =
                new GeneralizedBlackScholesProcess(process_.stateVariable(),
                                                   process_.dividendYield(),
                                                   process_.riskFreeRate(),
                                                   volTS);

            AnalyticEuropeanEngine bsmEngine = new AnalyticEuropeanEngine(adjProcess);

            VanillaOption option = new VanillaOption(payoff, exercise);

            option.setupArguments(bsmEngine.getArguments());

            bsmEngine.calculate();

            results_ = bsmEngine.getResults() as OneAssetOption.Results;
        }
示例#3
0
        /*! \warning currently, this method returns the Black-Scholes
         *       implied volatility using analytic formulas for
         *       European options and a finite-difference method
         *       for American and Bermudan options. It will give
         *       unconsistent results if the pricing was performed
         *       with any other methods (such as jump-diffusion
         *       models.)
         *
         * \warning options with a gamma that changes sign (e.g.,
         *       binary options) have values that are <b>not</b>
         *       monotonic in the volatility. In these cases, the
         *       calculation can fail and the result (if any) is
         *       almost meaningless.  Another possible source of
         *       failure is to have a target value that is not
         *       attainable with any volatility, e.g., a target
         *       value lower than the intrinsic value in the case
         *       of American options.
         */
        //public double impliedVolatility(double price, GeneralizedBlackScholesProcess process,
        //       double accuracy = 1.0e-4, int maxEvaluations = 100, double minVol = 1.0e-7, double maxVol = 4.0) {
        public double impliedVolatility(double targetValue, GeneralizedBlackScholesProcess process,
                                        double accuracy, int maxEvaluations, double minVol, double maxVol)
        {
            if (isExpired())
            {
                throw new ApplicationException("option expired");
            }

            SimpleQuote volQuote = new SimpleQuote();

            GeneralizedBlackScholesProcess newProcess = ImpliedVolatilityHelper.clone(process, volQuote);

            // engines are built-in for the time being
            IPricingEngine engine;

            switch (exercise_.type())
            {
            case Exercise.Type.European:
                engine = new AnalyticEuropeanEngine(newProcess);
                break;

            case Exercise.Type.American:
                throw new NotImplementedException();
                // engine = new FDAmericanEngine(newProcess);
                break;

            case Exercise.Type.Bermudan:
                throw new NotImplementedException();
                // engine = new FDBermudanEngine(newProcess);
                break;

            default:
                throw new ArgumentException("unknown exercise type");
            }

            return(ImpliedVolatilityHelper.calculate(this, engine, volQuote, targetValue, accuracy,
                                                     maxEvaluations, minVol, maxVol));
        }
        public override void calculate()
        {
            AmericanExercise ex = arguments_.exercise as AmericanExercise;

            Utils.QL_REQUIRE(ex != null, () => "non-American exercise given");
            Utils.QL_REQUIRE(ex.payoffAtExpiry(), () => "payoff must be at expiry");
            Utils.QL_REQUIRE(ex.dates()[0] <= process_.blackVolatility().link.referenceDate(), () =>
                             "American option with window exercise not handled yet");

            StrikedTypePayoff payoff = arguments_.payoff as StrikedTypePayoff;

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

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

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

            double variance = process_.blackVolatility().link.blackVariance(ex.lastDate(), payoff.strike());
            double?barrier  = arguments_.barrier;

            Utils.QL_REQUIRE(barrier > 0.0, () => "positive barrier value required");
            Barrier.Type barrierType = arguments_.barrierType;

            // KO degenerate cases
            if ((barrierType == Barrier.Type.DownOut && spot <= barrier) ||
                (barrierType == Barrier.Type.UpOut && spot >= barrier))
            {
                // knocked out, no value
                results_.value       = 0;
                results_.delta       = 0;
                results_.gamma       = 0;
                results_.vega        = 0;
                results_.theta       = 0;
                results_.rho         = 0;
                results_.dividendRho = 0;
                return;
            }

            // KI degenerate cases
            if ((barrierType == Barrier.Type.DownIn && spot <= barrier) ||
                (barrierType == Barrier.Type.UpIn && spot >= barrier))
            {
                // knocked in - is a digital european
                Exercise exercise = new EuropeanExercise(arguments_.exercise.lastDate());

                IPricingEngine engine = new AnalyticEuropeanEngine(process_);

                VanillaOption opt = new VanillaOption(payoff, exercise);
                opt.setPricingEngine(engine);
                results_.value       = opt.NPV();
                results_.delta       = opt.delta();
                results_.gamma       = opt.gamma();
                results_.vega        = opt.vega();
                results_.theta       = opt.theta();
                results_.rho         = opt.rho();
                results_.dividendRho = opt.dividendRho();
                return;
            }

            double riskFreeDiscount = process_.riskFreeRate().link.discount(ex.lastDate());

            AnalyticBinaryBarrierEngine_helper helper = new AnalyticBinaryBarrierEngine_helper(
                process_, payoff, ex, arguments_);

            results_.value = helper.payoffAtExpiry(spot, variance, riskFreeDiscount);
        }
示例#5
0
        VanillaOption makeOption(StrikedTypePayoff payoff, Exercise exercise, Quote u, YieldTermStructure q,
            YieldTermStructure r, BlackVolTermStructure vol, EngineType engineType, int binomialSteps, int samples)
        {
            GeneralizedBlackScholesProcess stochProcess = makeProcess(u, q, r, vol);

             IPricingEngine engine;
             switch (engineType)
             {
            case EngineType.Analytic:
               engine = new AnalyticEuropeanEngine(stochProcess);
               break;
            case EngineType.JR:
               engine = new BinomialVanillaEngine<JarrowRudd>(stochProcess, binomialSteps);
               break;
            case EngineType.CRR:
               engine = new BinomialVanillaEngine<CoxRossRubinstein>(stochProcess, binomialSteps);
               break;
            case EngineType.EQP:
               engine = new BinomialVanillaEngine<AdditiveEQPBinomialTree>(stochProcess, binomialSteps);
               break;
            case EngineType.TGEO:
               engine = new BinomialVanillaEngine<Trigeorgis>(stochProcess, binomialSteps);
               break;
            case EngineType.TIAN:
               engine = new BinomialVanillaEngine<Tian>(stochProcess, binomialSteps);
               break;
            case EngineType.LR:
               engine = new BinomialVanillaEngine<LeisenReimer>(stochProcess, binomialSteps);
               break;
            case EngineType.JOSHI:
               engine = new BinomialVanillaEngine<Joshi4>(stochProcess, binomialSteps);
               break;
            case EngineType.FiniteDifferences:
               engine = new FDEuropeanEngine(stochProcess, binomialSteps, samples);
               break;
            case EngineType.Integral:
               engine = new IntegralEngine(stochProcess);
               break;
            //case EngineType.PseudoMonteCarlo:
            //  engine = MakeMCEuropeanEngine<PseudoRandom>(stochProcess)
            //      .withSteps(1)
            //      .withSamples(samples)
            //      .withSeed(42);
            //  break;
            //case EngineType.QuasiMonteCarlo:
            //  engine = MakeMCEuropeanEngine<LowDiscrepancy>(stochProcess)
            //      .withSteps(1)
            //      .withSamples(samples);
            //  break;
            default:
               throw new ArgumentException("unknown engine type");
             }

             VanillaOption option = new EuropeanOption(payoff, exercise);
             option.setPricingEngine(engine);
             return option;
        }
示例#6
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;
        }
示例#7
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 ?


        }