Esempio n. 1
0
        public void DoTestNormalCdfWest(double x)
        {
            var A = NormalCdf.NormalCdfHart(x);
            var B = NormalCdf.NormalCdfWest(x);

            Assert.AreEqual(A, B, 1e-8);
        }
        private double Phi(double S, double T, double gamma, double h, double i, double r, double b, double sigma)
        {
            double lambda = (-r + gamma * b + 0.5 * gamma * (gamma - 1) * sigma * sigma) * T;
            double d      = -(Math.Log(S / h) + (b + (gamma - 0.5) * sigma * sigma) * T) / sigma / Math.Sqrt(T);
            double kappa  = 2 * b / sigma / sigma + (2 * gamma - 1);
            double phi    = Math.Exp(lambda) * Math.Pow(S, gamma) * (NormalCdf.NormalCdfHart(d) - Math.Pow(i / S, kappa) * NormalCdf.NormalCdfHart(d - 2 * Math.Log(i / S) / sigma / Math.Sqrt(T)));

            return(phi);
        }
        private double GBS(OptionType optionType, double S, double X, double T, double r, double b, double sigma)
        {
            double d1 = (Math.Log(S / X) + (b + 0.5 * Math.Pow(sigma, 2)) * T) / (sigma * Math.Sqrt(T));
            double d2 = d1 - sigma * Math.Sqrt(T);

            var Gbs = (optionType == OptionType.Call)?
                      Math.Exp(-r * T) * (S * Math.Exp(b * T) * NormalCdf.NormalCdfHart(d1) - X * NormalCdf.NormalCdfHart(d2)):
                      -1.0 * Math.Exp(-r * T) * (S * Math.Exp(b * T) * NormalCdf.NormalCdfHart(-d1) - X * NormalCdf.NormalCdfHart(-d2));

            return(Gbs);
        }
Esempio n. 4
0
            private double CalcPV(double S1, double S2, double T, double r, double b1, double b2, double sigma1, double sigma2, double rho)
            {
                //for two asset cash or nothing option
                var d11 = (Math.Log(S1 / _X1) + (b1 - sigma1 * sigma1 * 0.5) * T) / sigma1 / Math.Sqrt(T);
                var d22 = (Math.Log(S2 / _X2) + (b2 - sigma2 * sigma2 * 0.5) * T) / sigma2 / Math.Sqrt(T);

                switch (_rainbowType)
                {
                //Haug
                case RainbowType.TwoAssetsCashOrNothing:
                    return((_optionType == OptionType.Call) ?
                           _K * Math.Exp(-r * T) * NormalCdf.NormalCdfGenz(d11, d22, rho) :
                           _K *Math.Exp(-r *T) * NormalCdf.NormalCdfGenz(-d11, -d22, rho));

                case RainbowType.TwoAssetsCashOrNothingUpDown:
                    return(_K * Math.Exp(-r * T) * NormalCdf.NormalCdfGenz(d11, -d22, -rho));

                case RainbowType.TwoAssetsCashOrNothingDownUp:
                    return(_K * Math.Exp(-r * T) * NormalCdf.NormalCdfGenz(-d11, d22, -rho));

                case RainbowType.BestCashOrNothing:
                case RainbowType.WorstCashOrNothing:
                    return(BestOrWorst(S1, S2, T, r, b1, b2, sigma1, sigma2, rho));

                //west
                case RainbowType.BestOfAssetsOrCash:
                    return(WestBestOfAssetsOrCash(S1, S2, T, r, b1, b2, sigma1, sigma2, rho));

                case RainbowType.Min:
                case RainbowType.Max:
                    if (_optionType == OptionType.Call)
                    {
                        return(WestRainbowCall(S1, S2, T, r, b1, b2, sigma1, sigma2, rho));
                    }
                    else
                    {       //put,  use put/call parity to price
                        double q1  = r - b1;
                        double q2  = r - b2;
                        var    vol = Math.Sqrt(sigma1 * sigma1 + sigma2 * sigma2 - 2.0 * rho * sigma1 * sigma2);
                        var    d21 = (Math.Log(S2 / S1) + (q1 - q2 - 0.5 * vol * vol) * T) / vol / Math.Sqrt(T);
                        var    d12 = (Math.Log(S1 / S2) + (q2 - q1 - 0.5 * vol * vol) * T) / vol / Math.Sqrt(T);

                        var VC0max = S1 * Math.Exp(-q1 * T) * NormalCdf.NormalCdfHart(-d21) + S2 * Math.Exp(-q2 * T) * NormalCdf.NormalCdfHart(-d12);
                        var VC0min = S1 * Math.Exp(-q1 * T) * NormalCdf.NormalCdfHart(d21) + S2 * Math.Exp(-q2 * T) * NormalCdf.NormalCdfHart(d12);

                        return((_rainbowType == RainbowType.Max) ?
                               WestRainbowCall(S1, S2, T, r, b1, b2, sigma1, sigma2, rho) - VC0max + _X1 * Math.Exp(-r * T) :
                               WestRainbowCall(S1, S2, T, r, b1, b2, sigma1, sigma2, rho) - VC0min + _X1 * Math.Exp(-r * T));
                    }

                default:
                    throw new PricingLibraryException("Unsupported rainbow option type");
                }
            }
Esempio n. 5
0
        private double FloatingPut(double S, double X, double T, double r, double b, double sigma, double Smax)
        {
            double b1  = (Math.Log(S / Smax) + (b + sigma * sigma / 2.0) * T) / sigma / Math.Sqrt(T);
            double b2  = b1 - sigma * Math.Sqrt(T);
            double put = 0.0;

            if (b == 0.0)
            {
                put = -S *Math.Exp(-r *T) * NormalCdf.NormalCdfHart(-b1) + Smax * Math.Exp(-r * T) * NormalCdf.NormalCdfHart(-b2)
                      + S * Math.Exp(-r * T) * sigma * Math.Sqrt(T) * (NormalCdf.NormalPdf(b1) + b1 * NormalCdf.NormalCdfHart(b1));
            }
            if (b != 0.0)
            {
                put = -S *Math.Exp((b - r) *T) * NormalCdf.NormalCdfHart(-b1) + Smax * Math.Exp(-r * T) * NormalCdf.NormalCdfHart(-b2)
                      + S * Math.Exp(-r * T) * sigma * sigma * 0.5 / b * (-Math.Pow(S / Smax, -2.0 * b / sigma / sigma) * NormalCdf.NormalCdfHart(b1 - 2.0 * b / sigma * Math.Sqrt(T)) + Math.Exp(b * T) * NormalCdf.NormalCdfHart(b1));
            }
            return(put);
        }
Esempio n. 6
0
        //Payoff:
        //FloatingCall: S - S_min
        //FloatingPut: S_max - S
        private double FloatingCall(double S, double X, double T, double r, double b, double sigma, double Smin)
        {
            double a1   = (Math.Log(S / Smin) + (b + sigma * sigma / 2.0) * T) / sigma / Math.Sqrt(T);
            double a2   = a1 - sigma * Math.Sqrt(T);
            double call = 0.0;

            if (b == 0.0)
            {
                call = S * Math.Exp(-r * T) * NormalCdf.NormalCdfHart(a1) - Smin * Math.Exp(-r * T) * NormalCdf.NormalCdfHart(a2)
                       + S * Math.Exp(-r * T) * sigma * Math.Sqrt(T) * (NormalCdf.NormalPdf(a1) + a1 * (NormalCdf.NormalCdfHart(a1) - 1));
            }
            if (b != 0.0)
            {
                call = S * Math.Exp((b - r) * T) * NormalCdf.NormalCdfHart(a1) - Smin * Math.Exp(-r * T) * NormalCdf.NormalCdfHart(a2)
                       + S * Math.Exp(-r * T) * sigma * sigma * 0.5 / b * (Math.Pow(S / Smin, -2.0 * b / sigma / sigma) * NormalCdf.NormalCdfHart(-a1 + 2.0 * b / sigma * Math.Sqrt(T)) - Math.Exp(b * T) * NormalCdf.NormalCdfHart(-a1));
            }
            return(call);
        }
        //private const double riskBumpSize = 1e-4;
        //private const double vegaBumpSize = 0.01;
        ////TODO: properly fix it,  increment 1 day, using daycount convention
        //private const double timeIncrement = 1.0 / 365.0;

        //private double CalDelta(double spot, double T, double sigma) => (CalcPV( spot + riskBumpSize, sigma, T, _r) - CalcPV(spot, sigma, T, _r))/ riskBumpSize;

        ////To avoid confusion, current barrier greek calc is handled in BaseNumericalOptionEngine
        ////public double Delta => CalDelta(_S, _T, _sigma);

        ////public double Gamma => CalDelta(_S + riskBumpSize, _T, _sigma) - CalDelta(_S, _T, _sigma);

        ////pv change per 0.01 absolute change in vol,  unlike other greeks, this number is not standardized
        ////public double Vega => CalcVega(_S, _T, _sigma); //CalcPV(_S, _sigma + vegaBumpSize, _T, _r) - CalcPV(_S, _sigma, _T, _r);

        //public double CalcVega(double spot, double T, double sigma) => CalcPV(spot, sigma + vegaBumpSize, T, _r) - CalcPV(spot, sigma, T, _r);

        //public double Theta => CalcPV(_S, _sigma, _T - timeIncrement, _r) - CalcPV(_S, _sigma, _T, _r);

        ////pv change per 1 bp absolute change in r
        //public double Rho => CalcPV(_S, _sigma, _T, _r + riskBumpSize) - CalcPV(_S, _sigma, _T, _r);

        ////higher order, cross effect
        //public double DDeltaDt => CalDelta(_S, _T- timeIncrement, _sigma) - CalDelta(_S, _T, _sigma);

        //public double DDeltaDvol => CalDelta(_S, _T, _sigma + 0.01) - CalDelta(_S, _T, _sigma);

        //public double DVegaDt => CalcVega(_S, _T - timeIncrement, _sigma) - CalcVega(_S, _T, _sigma);

        //public double DVegaDvol => (CalcVega(_S, _T, _sigma+vegaBumpSize) - CalcVega(_S, _T, _sigma));

        //expected barrier first exit time/barrier cross time
        public double StoppingTime()
        {   //From Dynamic hedging,  module G
            double lambda = _b / _sigma - _sigma / 2.0;
            double h      = 1.0 / _sigma * Math.Log(_H / _S);

            Func <bool, double> calcStoppingTimeDistribution = barrierHigherThanSpot =>
            {
                var sign = barrierHigherThanSpot ? 1.0 : -1.0;
                return((_T - h / lambda) * NormalCdf.NormalCdfHart((h / Math.Sqrt(_T) - lambda * Math.Sqrt(_T)) * sign)
                       - Math.Exp(2.0 * lambda * h) * (_T + h / lambda) * NormalCdf.NormalCdfHart((-h / Math.Sqrt(_T) - lambda * Math.Sqrt(_T)) * sign));
            };
            var tEffectivBarrier = h / lambda + calcStoppingTimeDistribution(_H > _S);
            var tVanilla         = _T;
            var tKnockedOut      = 0;

            if (_barrierType.Equals(BarrierType.DownAndIn) && _S <= _H)
            {
                return(tVanilla);
            }
            else if (_barrierType.Equals(BarrierType.UpAndIn) && _S >= _H)
            {
                return(tVanilla);
            }
            else if (_barrierType.Equals(BarrierType.DownAndOut) && _S <= _H)
            {
                return(tKnockedOut);
            }
            else if (_barrierType.Equals(BarrierType.UpAndOut) && _S >= _H)
            {
                return(tKnockedOut);
            }
            else
            {
                return(tEffectivBarrier);
            }
        }
Esempio n. 8
0
            //Haug 2007: Chapter 4.9 & 4.10
            //Payoff: max((S-X)/X,0) or max(S-X,0)
            private double CalcPV(double S, double T, double r, double b, double sigma, double t)
            {
                double rho = Math.Sqrt(t / T);
                double a1  = (Math.Log(S / _X) + (b + sigma * sigma * 0.5) * t) / sigma / Math.Sqrt(t);
                double a2  = a1 - sigma * Math.Sqrt(t);
                double z1  = (b + sigma * sigma * 0.5) * (T - t) / sigma / Math.Sqrt(T - t);
                double z2  = z1 - sigma * Math.Sqrt(T - t);
                double y1  = (Math.Log(S / _X) + (b + sigma * sigma * 0.5) * T) / sigma / Math.Sqrt(T);
                double y2  = y1 - sigma * Math.Sqrt(T);

                double C1 = Math.Exp((b - r) * (T - t)) * NormalCdf.NormalCdfHart(-a2) * NormalCdf.NormalCdfHart(z1) * Math.Exp(-r * t)
                            - Math.Exp(-r * T) * NormalCdf.NormalCdfHart(-a2) * NormalCdf.NormalCdfHart(z2) - Math.Exp(-r * T) * NormalCdf.NormalCdfGenz(a2, y2, rho)
                            + (S / _X) * Math.Exp((b - r) * T) * NormalCdf.NormalCdfGenz(a1, y1, rho);

                double P1 = -Math.Exp((b - r) * (T - t)) * NormalCdf.NormalCdfHart(a2) * NormalCdf.NormalCdfHart(-z1) * Math.Exp(-r * t)
                            + Math.Exp(-r * T) * NormalCdf.NormalCdfHart(a2) * NormalCdf.NormalCdfHart(-z2) + Math.Exp(-r * T) * NormalCdf.NormalCdfGenz(-a2, -y2, rho)
                            - (S / _X) * Math.Exp((b - r) * T) * NormalCdf.NormalCdfGenz(-a1, -y1, rho);

                double C2 = S * Math.Exp((b - r) * T) * NormalCdf.NormalCdfGenz(a1, y1, rho) - _X * Math.Exp(-r * T) * NormalCdf.NormalCdfGenz(a2, y2, rho)
                            - S * Math.Exp((b - r) * t) * NormalCdf.NormalCdfHart(-a1) * NormalCdf.NormalCdfHart(z2) * Math.Exp(-r * (T - t)) + S * Math.Exp((b - r) * T) * NormalCdf.NormalCdfHart(-a1) * NormalCdf.NormalCdfHart(z1);

                double P2 = -S *Math.Exp((b - r) *T) * NormalCdf.NormalCdfGenz(-a1, -y1, rho) + _X * Math.Exp(-r * T) * NormalCdf.NormalCdfGenz(-a2, -y2, rho)
                            + S * Math.Exp((b - r) * t) * NormalCdf.NormalCdfHart(a1) * NormalCdf.NormalCdfHart(-z2) * Math.Exp(-r * (T - t)) - S * Math.Exp((b - r) * T) * NormalCdf.NormalCdfHart(a1) * NormalCdf.NormalCdfHart(-z1);

                switch (_resetstrikeType)
                {
                case ResetStrikeType.PercentagePayoff:
                    return((_optionType == OptionType.Call) ? _notional * C1 : _notional *P1);

                case ResetStrikeType.NormalPayoff:
                    return((_optionType == OptionType.Call) ? _notional * C2 : _notional *P2);

                default:
                    throw new PricingLibraryException("Unsupported reset strike option type");
                }
            }
        private double CalcPV(Double S, Double sigma, Double T, Double r)
        {
            //TODO:  get risk free rate from curve,  here
            var b = _isOptionOnFutures ? 0.0 : r - _dividend;

            _mu     = (b - sigma * sigma / 2.0) / Math.Pow(sigma, 2.0);
            _lambda = _isOptionOnFutures ?
                      Math.Sqrt(_mu * _mu) :
                      Math.Sqrt(_mu * _mu + 2.0 * r / sigma / sigma);

            _z = Math.Log(_H / S) / sigma / Math.Sqrt(T) + _lambda * sigma * Math.Sqrt(T);

            _x1 = Math.Log(S / _X) / sigma / Math.Sqrt(T) + (1 + _mu) * sigma * Math.Sqrt(T);
            _x2 = Math.Log(S / _H) / sigma / Math.Sqrt(T) + (1 + _mu) * sigma * Math.Sqrt(T);
            _y1 = Math.Log(_H * _H / S / _X) / sigma / Math.Sqrt(T) + (1 + _mu) * sigma * Math.Sqrt(T);
            _y2 = Math.Log(_H / S) / sigma / Math.Sqrt(T) + (1 + _mu) * sigma * Math.Sqrt(T);

            _d1 = _isOptionOnFutures ?
                  (Math.Log(S / _X) + 0.5 * Math.Pow(sigma, 2.0) * T) / (sigma * Math.Sqrt(T)) :
                  (Math.Log(S / _X) + (b + 0.5 * Math.Pow(sigma, 2.0)) * T) / (sigma * Math.Sqrt(T)); //black scholes

            _d2 = _d1 - sigma * Math.Sqrt(T);

            //Note: given yield curve infra, we could
            //1. replace Math.Exp((b - r) * T)  with  market.DividendCurve.Value.GetDf(T)
            //2. replace Math.Exp(( -r) * T)  with  market.DiscountCurve.Value.GetDf(T)
            _A = _phi * S * Math.Exp((b - r) * T) * NormalCdf.NormalCdfHart(_phi * _x1) -
                 _phi * _X * Math.Exp(-r * T) * NormalCdf.NormalCdfHart(_phi * _x1 - _phi * sigma * Math.Sqrt(T));
            _B = _phi * S * Math.Exp((b - r) * T) * NormalCdf.NormalCdfHart(_phi * _x2) -
                 _phi * _X * Math.Exp(-r * T) * NormalCdf.NormalCdfHart(_phi * _x2 - _phi * sigma * Math.Sqrt(T));
            _C = _phi * S * Math.Exp((b - r) * T) * Math.Pow(_H / S, 2 * (_mu + 1)) * NormalCdf.NormalCdfHart(_yita * _y1) -
                 _phi * _X * Math.Exp(-r * T) * Math.Pow(_H / S, 2 * _mu) * NormalCdf.NormalCdfHart(_yita * _y1 - _yita * sigma * Math.Sqrt(T));
            _D = _phi * S * Math.Exp((b - r) * T) * Math.Pow(_H / S, 2 * (_mu + 1)) * NormalCdf.NormalCdfHart(_yita * _y2) -
                 _phi * _X * Math.Exp(-r * T) * Math.Pow(_H / S, 2 * _mu) * NormalCdf.NormalCdfHart(_yita * _y2 - _yita * sigma * Math.Sqrt(T));
            _E = _K * Math.Exp(-r * T) *
                 (NormalCdf.NormalCdfHart(_yita * _x2 - _yita * sigma * Math.Sqrt(T)) -
                  Math.Pow(_H / S, 2 * _mu) * NormalCdf.NormalCdfHart(_yita * _y2 - _yita * sigma * Math.Sqrt(T)));
            _F = _K *
                 (Math.Pow(_H / S, _mu + _lambda) * NormalCdf.NormalCdfHart(_yita * _z) +
                  Math.Pow(_H / S, _mu - _lambda) * NormalCdf.NormalCdfHart(_yita * _z - 2 * _yita * _lambda * sigma * Math.Sqrt(T)));

            _Gcall = Math.Exp(-r * T) * (S * Math.Exp(b * T) * NormalCdf.NormalCdfHart(_d1) - _X * NormalCdf.NormalCdfHart(_d2));
            _Gput  = -1.0 * Math.Exp(-r * T) * (S * Math.Exp(b * T) * NormalCdf.NormalCdfHart(-_d1) - _X * NormalCdf.NormalCdfHart(-_d2));

            //price here
            if (_barrierType.Equals(BarrierType.DownAndIn) && _optionType.Equals(OptionType.Call))
            {
                if (S <= _H)
                {
                    return(_notional * _Gcall);
                }
                if (_X >= _H)
                {
                    return(_notional * (_C + _E));
                }
                if (_X < _H)
                {
                    return(_notional * (_A - _B + _D + _E));
                }
            }
            if (_barrierType.Equals(BarrierType.UpAndIn) && _optionType.Equals(OptionType.Call))
            {
                if (S >= _H)
                {
                    return(_notional * _Gcall);
                }
                if (_X > _H)
                {
                    return(_notional * (_A + _E));
                }
                if (_X <= _H)
                {
                    return(_notional * (_B - _C + _D + _E));
                }
            }
            if (_barrierType.Equals(BarrierType.DownAndIn) && _optionType.Equals(OptionType.Put))
            {
                if (S <= _H)
                {
                    return(_notional * _Gput);
                }
                if (_X >= _H)
                {
                    return(_notional * (_B - _C + _D + _E));
                }
                if (_X < _H)
                {
                    return(_notional * (_A + _E));
                }
            }
            if (_barrierType.Equals(BarrierType.UpAndIn) && _optionType.Equals(OptionType.Put))
            {
                if (S >= _H)
                {
                    return(_notional * _Gput);
                }
                if (_X > _H)
                {
                    return(_notional * (_A - _B + _D + _E));
                }
                if (_X <= _H)
                {
                    return(_notional * (_C + _E));
                }
            }
            if (_barrierType.Equals(BarrierType.DownAndOut) && _optionType.Equals(OptionType.Call))
            {
                if (S <= _H)
                {
                    return(_notional * _rebate);         // already knocked out
                }
                if (_X >= _H)
                {
                    return(_notional * (_A - _C + _F));
                }
                if (_X < _H)
                {
                    return(_notional * (_B - _D + _F));
                }
            }
            if (_barrierType.Equals(BarrierType.UpAndOut) && _optionType.Equals(OptionType.Call))
            {
                if (S >= _H)
                {
                    return(_notional * _rebate);         // already knocked out
                }
                if (_X > _H)
                {
                    return(_notional * _F);
                }
                if (_X <= _H)
                {
                    return(_notional * (_A - _B + _C - _D + _F));
                }
            }
            if (_barrierType.Equals(BarrierType.DownAndOut) && _optionType.Equals(OptionType.Put))
            {
                if (S <= _H)
                {
                    return(_notional * _rebate);         // already knocked out
                }
                if (_X >= _H)
                {
                    return(_notional * (_A - _B + _C - _D + _F));
                }
                if (_X < _H)
                {
                    return(_notional * _F);
                }
            }
            if (_barrierType.Equals(BarrierType.UpAndOut) && _optionType.Equals(OptionType.Put))
            {
                if (S >= _H)
                {
                    return(_notional * _rebate);          // already knocked out
                }
                if (_X > _H)
                {
                    return(_notional * (_B - _D + _F));
                }
                if (_X <= _H)
                {
                    return(_notional * (_A - _C + _F));
                }
            }

            throw new PricingBaseException("Code should not reach here. Something is wrong.");
        }
Esempio n. 10
0
            //public double CalcPV(Double spotPrice, Double sigma, Double T, Double r)
            public double CalcPV(double S, double T, double sigma, double r, double b)
            {
                double omega = _binaryRebateType == BinaryRebateType.AtHit ? 0 : 1;
                double yita  = S < _X ? -1 : 1;

                double theta    = b / sigma - sigma / 2;
                double nu       = Math.Sqrt(theta * theta + 2 * (1 - omega) * r);
                double epsilon1 = (Math.Log(S / _X) - sigma * nu * T) / sigma / Math.Sqrt(T);
                double epsilon2 = (-Math.Log(S / _X) - sigma * nu * T) / sigma / Math.Sqrt(T);

                double pv = _cashOrNothingAmount * Math.Exp(-omega * r * T) * (Math.Pow((_X / S), (theta + nu) / sigma) * NormalCdf.NormalCdfHart(-yita * epsilon1)
                                                                               + Math.Pow((_X / S), (theta - nu) / sigma) * NormalCdf.NormalCdfHart(yita * epsilon2));

                return(pv * _notional);
            }
        public static void prepareBlackScholesInputs(
            double spotPrice,
            double riskfreeRateAtExerciseInput, double riskfreeRateAtMaturityInput, double dividendRateInput,
            double riskFreeCurveShiftInBp, double dividendCurveShiftInBp,
            Date maturityDate, Date exerciseDate, Date valuationDate,
            IOption trade,
            IDayCount curveDayCount,
            bool isOptionOnForward,
            bool isForwardFuturesOption,
            double strike,
            double sigma,
            out double nd1,  // P(x < d1)
            out double nd2,  // P(x < d2),
            out double riskfreeDfAtExercise,
            out double dfExerciseToMaturity,
            out double forwardPrice,
            double expiryDayRemainingLife = double.NaN,
            double timeIncrement          = 0.0
            )
        {
            double T = 0.0;

            if (!double.IsNaN(expiryDayRemainingLife))
            {
                T = expiryDayRemainingLife;
            }
            else
            {
                T = timeToMaturityFraction(valuationDate, exerciseDate, trade) + timeIncrement;
            }
            double riskfreeRateAtExercise, riskfreeRateAtMaturity;

            if (riskFreeCurveShiftInBp != 0.0)
            {
                riskfreeRateAtExercise = riskfreeRateAtExerciseInput + riskFreeCurveShiftInBp * 1e-4;
                riskfreeRateAtMaturity = riskfreeRateAtMaturityInput + riskFreeCurveShiftInBp * 1e-4;
            }
            else
            {
                riskfreeRateAtExercise = riskfreeRateAtExerciseInput;
                riskfreeRateAtMaturity = riskfreeRateAtMaturityInput;
            }
            var riskfreeDfAtMaturity = CalcDfFromZeroRate(riskfreeRateAtMaturity, maturityDate, valuationDate, curveDayCount);

            riskfreeDfAtExercise = CalcDfFromZeroRate(riskfreeRateAtExercise, exerciseDate, valuationDate, curveDayCount);

            double dividendRate;

            if (dividendCurveShiftInBp != 0.0)
            {
                dividendRate = dividendRateInput + dividendCurveShiftInBp / 1e4;
            }
            else
            {
                dividendRate = dividendRateInput;
            }

            //https://en.wikipedia.org/wiki/Black_model
            //if option on forward, discount to forward maturity day, and make sure maturity here is forward maturity, exercise is option exercise day
            //for other contracts,  pass maturity day = expiry day,  therefore _dfExerciseToMaturity = 1.0;
            dfExerciseToMaturity = (isOptionOnForward) ? riskfreeDfAtMaturity / riskfreeDfAtExercise : 1.0;

            var b = AnalyticalOptionPricerUtil.costOfCarry(isForwardFuturesOption, dividendRate, riskfreeRateAtExercise);

            forwardPrice = AnalyticalOptionPricerUtil.forwardPrice(
                isForwardFuturesOption,
                spotPrice,
                riskfreeDfAtExercise: riskfreeDfAtExercise,
                dividendRate: dividendRate,
                exerciseDate: exerciseDate,
                valuationDate: valuationDate,
                dayCount: trade.DayCount);

            var d1 = (Math.Log(spotPrice / strike) + (b + sigma * sigma / 2.0) * T) / (sigma * Math.Sqrt(T));
            var d2 = d1 - sigma * Math.Sqrt(T);

            nd1 = NormalCdf.NormalCdfHart(d1);  // P(x < d1)
            nd2 = NormalCdf.NormalCdfHart(d2);  // P(x < d2)

            //var nPrimceD1 = 1.0 / Math.Sqrt(2.0 * Math.PI) * Math.Exp(-d1 * d1 / 2.0); // derivative of N(d1)
            //var nPrimceD2 = 1.0 / Math.Sqrt(2.0 * Math.PI) * Math.Exp(-d2 * d2 / 2.0); // derivative of N(d2)
        }
Esempio n. 12
0
        //References: Levy(1997), Haug,Haug,and Margrabe(2003); Haug Chapter 4.20.3
        private double DiscreteArithmeticAverage(OptionType optionType, double S, double SA, double X, double t1, double T, double n, double m, double r, double b, double sigma)
        //t1: time to the next average point;
        //n: total number of averaging points;
        //m: observed number of averaging points;
        {
            double h      = (T - t1) / (n - 1); //TODO:  n-1 or n -m-1?
            double sigma2 = sigma * sigma;
            double o      = 2 * b + sigma2;
            double EA     = (b == 0) ? S : S / n * Math.Exp(b * t1) * (1 - Math.Exp(b * h * n)) / (1 - Math.Exp(b * h));

            //into average period
            if (m > 0)
            {
                if (SA > n / m * X)
                {
                    if (optionType == OptionType.Call)
                    {
                        SA = SA * m / n + EA * (n - m) / n;
                        return((SA - X) * Math.Exp(-r * T));
                    }
                    else
                    {
                        return(0);
                    }
                }
            }

            //when only one fixing left to maturity
            if (m == n - 1)
            {
                X = n * X - (n - 1) * SA;
                return(BS(optionType, S, X, T, r, b, sigma) * 1 / n);
            }

            double EA2 = (b == 0) ? S * S * Math.Exp(sigma2 * t1) / n / n *
                         (
                (1 - Math.Exp(sigma2 * h * n)) / (1 - Math.Exp(sigma2 * h)) +
                2.0 / (1 - Math.Exp(sigma2 * h)) *
                (n - (1 - Math.Exp(sigma2 * h * n)) / (1 - Math.Exp(sigma2 * h)))
                         ) :
                         S *S *Math.Exp(o *t1) / n / n *
                         (
                (1 - Math.Exp(o * h * n)) / (1 - Math.Exp(o * h)) +
                2.0 / (1 - Math.Exp((b + sigma2) * h)) *
                ((1 - Math.Exp(b * h * n)) / (1 - Math.Exp(b * h)) - (1 - Math.Exp(o * h * n)) / (1 - Math.Exp(o * h)))
                         );

            double sigmaNew = Math.Sqrt((Math.Log(EA2) - 2 * Math.Log(EA)) / T);


            if (m > 0)
            {
                if (n == m)
                {
                    return(0);
                }
                else
                {
                    X = n / (n - m) * X - m / (n - m) * SA;
                }
            }

            double d1 = (Math.Log(EA / X) + T * Math.Pow(sigmaNew, 2) / 2.0) / (sigmaNew * Math.Sqrt(T));
            double d2 = d1 - sigmaNew * Math.Sqrt(T);

            var OptionValue = (optionType == OptionType.Call) ?
                              Math.Exp(-r * T) * (EA * NormalCdf.NormalCdfHart(d1) - X * NormalCdf.NormalCdfHart(d2)) :
                              Math.Exp(-r * T) * (-EA * NormalCdf.NormalCdfHart(-d1) + X * NormalCdf.NormalCdfHart(-d2));

            return(OptionValue * (n - m) / n);
        }
        private double BAWPut(double S, double X, double T, double r, double b, double sigma, double ACCURACY = 1.0e-6)
        {
            double sigma_sqr = sigma * sigma;
            double time_sqrt = Math.Sqrt(T);
            double nn        = 2.0 * b / sigma_sqr;
            double m         = 2.0 * r / sigma_sqr;
            double K         = 1.0 - Math.Exp(-r * T);
            double q1        = (-(nn - 1) - Math.Sqrt(Math.Pow((nn - 1), 2.0) + 4.0 * m / K)) * 0.5;

            double q1_inf     = 0.5 * (-(nn - 1) - Math.Sqrt(Math.Pow((nn - 1), 2.0) + 4.0 * m));
            double S_star_inf = X / (1.0 - 1.0 / q1_inf);
            double h1         = -(b * T - 2.0 * sigma * time_sqrt) * (X / (S_star_inf - X));
            double S_seed     = S_star_inf + (X - S_star_inf) * Math.Exp(h1);

            int    no_iterations = 0; // iterate on S to find S_star, using Newton steps
            double Si            = S_seed;
            double g             = 1;
            double gprime        = 1.0;

            while ((Math.Abs(g) > ACCURACY) &&
                   (Math.Abs(gprime) > ACCURACY) && // to avoid exploding Newton's
                   (no_iterations++ < 500) &&
                   (Si > 0.0))
            {
                double bs = GBS(_optionType, Si, X, T, r, b, sigma);
                double d1 = (Math.Log(Si / X) + (b + 0.5 * sigma_sqr) * T) / (sigma * time_sqrt);
                g      = X - Si - bs + Si / q1 * (1 - Math.Exp((b - r) * T) * NormalCdf.NormalCdfHart(-d1));
                gprime = (1.0 / q1 - 1.0) * (1.0 - Math.Exp((b - r) * T) * NormalCdf.NormalCdfHart(-d1))
                         + (1.0 / q1) * Math.Exp((b - r) * T) * NormalCdf.NormalCdfHart(-d1) * (1.0 / (sigma * time_sqrt));
                Si = Si - (g / gprime);
            }
            ;

            double S_star = 0;

            if (Math.Abs(g) > ACCURACY)
            {
                S_star = S_seed;
            }                                                // did not converge
            else
            {
                S_star = Si;
            };
            double P = 0;
            double p = GBS(_optionType, S, X, T, r, b, sigma);

            if (S <= S_star)
            {
                P = X - S;
            }
            else
            {
                double d1 = (Math.Log(S_star / X) + (b + 0.5 * sigma_sqr) * T) / (sigma * time_sqrt);
                double A1 = -(1.0 - Math.Exp((b - r) * T) * NormalCdf.NormalCdfHart(-d1)) * (S_star / q1);
                P = p + A1 * Math.Pow((S / S_star), q1);
            };
            if (double.IsNaN(P))
            {
                return(p);
            }
            else
            {
                return(Math.Max(P, p));
            }
        }
        private double BAWCall(double S, double X, double T, double r, double b, double sigma, double ACCURACY = 1.0e-6)
        {
            double sigma_sqr = sigma * sigma;
            double time_sqrt = Math.Sqrt(T);
            double nn        = 2.0 * b / sigma_sqr;
            double m         = 2.0 * r / sigma_sqr;
            double K         = 1.0 - Math.Exp(-r * T);
            double q2        = (-(nn - 1) + Math.Sqrt(Math.Pow((nn - 1), 2.0) + 4.0 * m / K)) * 0.5;

            double q2_inf     = 0.5 * (-(nn - 1) + Math.Sqrt(Math.Pow((nn - 1), 2.0) + 4.0 * m));
            double S_star_inf = X / (1.0 - 1.0 / q2_inf);
            double h2         = -(b * T + 2.0 * sigma * time_sqrt) * (X / (S_star_inf - X));
            double S_seed     = X + (S_star_inf - X) * (1.0 - Math.Exp(h2));

            int    no_iterations = 0; // iterate on S to find S_star, using Newton steps
            double Si            = S_seed;
            double g             = 1;
            double gprime        = 1.0;

            while ((Math.Abs(g) > ACCURACY) &&
                   (Math.Abs(gprime) > ACCURACY) && // to avoid exploding Newton's
                   (no_iterations++ < 500) &&
                   (Si > 0.0))
            {
                double bs = GBS(_optionType, Si, X, T, r, b, sigma);
                double d1 = (Math.Log(Si / X) + (b + 0.5 * sigma_sqr) * T) / (sigma * time_sqrt);
                g      = (1.0 - 1.0 / q2) * Si - X - bs + (1.0 / q2) * Si * Math.Exp((b - r) * T) * NormalCdf.NormalCdfHart(d1);
                gprime = (1.0 - 1.0 / q2) * (1.0 - Math.Exp((b - r) * T) * NormalCdf.NormalCdfHart(d1))
                         + (1.0 / q2) * Math.Exp((b - r) * T) * NormalCdf.NormalCdfHart(d1) * (1.0 / (sigma * time_sqrt));
                Si = Si - (g / gprime);
            }
            ;

            double S_star = 0;

            if (Math.Abs(g) > ACCURACY)
            {
                S_star = S_seed;
            }                                                // did not converge
            else
            {
                S_star = Si;
            };
            double C = 0;
            double c = GBS(_optionType, S, X, T, r, b, sigma);

            if (S >= S_star)
            {
                C = S - X;
            }
            else
            {
                double d1 = (Math.Log(S_star / X) + (b + 0.5 * sigma_sqr) * T) / (sigma * time_sqrt);
                double A2 = (1.0 - Math.Exp((b - r) * T) * NormalCdf.NormalCdfHart(d1)) * (S_star / q2);
                C = c + A2 * Math.Pow((S / S_star), q2);
            };
            if (double.IsNaN(C))
            {
                return(c);
            }
            else
            {
                return(Math.Max(C, c));
            }
        }