예제 #1
0
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the price of the foreign exchange vanilla option product.
        /// <para>
        /// The price of the product is the value on the valuation date for one unit of the base currency
        /// and is expressed in the counter currency. The price does not take into account the long/short flag.
        /// See <seealso cref="#presentValue"/> for scaling and currency.
        ///
        /// </para>
        /// </summary>
        /// <param name="option">  the option product </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="volatilities">  the Black volatility provider </param>
        /// <returns> the price of the product </returns>
        public virtual double price(ResolvedFxVanillaOption option, RatesProvider ratesProvider, BlackFxOptionSmileVolatilities volatilities)
        {
            validate(ratesProvider, volatilities);
            double timeToExpiry = volatilities.relativeTime(option.Expiry);

            if (timeToExpiry <= 0d)
            {
                return(0d);
            }
            ResolvedFxSingle     underlyingFx = option.Underlying;
            Currency             ccyCounter   = option.CounterCurrency;
            double               df           = ratesProvider.discountFactor(ccyCounter, underlyingFx.PaymentDate);
            FxRate               forward      = fxPricer.forwardFxRate(underlyingFx, ratesProvider);
            CurrencyPair         currencyPair = underlyingFx.CurrencyPair;
            double               forwardRate  = forward.fxRate(currencyPair);
            double               strikeRate   = option.Strike;
            bool                 isCall       = option.PutCall.Call;
            SmileDeltaParameters smileAtTime  = volatilities.Smile.smileForExpiry(timeToExpiry);

            double[] strikes = smileAtTime.strike(forwardRate).toArray();
            double[] vols    = smileAtTime.Volatility.toArray();
            double   volAtm  = vols[1];

            double[] x        = vannaVolgaWeights(forwardRate, strikeRate, timeToExpiry, volAtm, strikes);
            double   priceFwd = BlackFormulaRepository.price(forwardRate, strikeRate, timeToExpiry, volAtm, isCall);

            for (int i = 0; i < 3; i += 2)
            {
                double priceFwdAtm   = BlackFormulaRepository.price(forwardRate, strikes[i], timeToExpiry, volAtm, isCall);
                double priceFwdSmile = BlackFormulaRepository.price(forwardRate, strikes[i], timeToExpiry, vols[i], isCall);
                priceFwd += x[i] * (priceFwdSmile - priceFwdAtm);
            }
            return(df * priceFwd);
        }
        public SwapTrade trade(double quantity, MarketData marketData, ReferenceData refData)
        {
            double  marketQuote = marketData.getValue(spreadId) + additionalSpread;
            FxRate  fxRate      = marketData.getValue(fxRateId);
            double  rate        = fxRate.fxRate(template.CurrencyPair);
            BuySell buySell     = quantity > 0 ? BuySell.SELL : BuySell.BUY;

            return(template.createTrade(marketData.ValuationDate, buySell, Math.Abs(quantity), rate, marketQuote, refData));
        }
예제 #3
0
        public FxSwapTrade trade(double quantity, MarketData marketData, ReferenceData refData)
        {
            FxRate  fxRate  = marketData.getValue(fxRateId);
            double  rate    = fxRate.fxRate(template.CurrencyPair);
            double  fxPts   = marketData.getValue(farForwardPointsId);
            BuySell buySell = quantity > 0 ? BuySell.BUY : BuySell.SELL;

            return(template.createTrade(marketData.ValuationDate, buySell, Math.Abs(quantity), rate, fxPts, refData));
        }
예제 #4
0
        public virtual void test_trade()
        {
            FxSwapCurveNode node     = FxSwapCurveNode.of(TEMPLATE, QUOTE_ID_PTS);
            FxSwapTrade     trade    = node.trade(1d, MARKET_DATA, REF_DATA);
            double          rate     = FX_RATE_NEAR.fxRate(EUR_USD);
            FxSwapTrade     expected = TEMPLATE.createTrade(VAL_DATE, BuySell.BUY, 1.0, rate, FX_RATE_PTS, REF_DATA);

            assertEquals(trade, expected);
            assertEquals(node.resolvedTrade(1d, MARKET_DATA, REF_DATA), trade.resolve(REF_DATA));
        }
        public virtual void test_trade()
        {
            XCcyIborIborSwapCurveNode node = XCcyIborIborSwapCurveNode.of(TEMPLATE, SPREAD_ID, SPREAD_ADJ);
            double    quantity             = -1234.56;
            SwapTrade trade    = node.trade(quantity, MARKET_DATA, REF_DATA);
            double    rate     = FX_EUR_USD.fxRate(Currency.EUR, Currency.USD);
            SwapTrade expected = TEMPLATE.createTrade(VAL_DATE, BUY, -quantity, rate, SPREAD_XCS + SPREAD_ADJ, REF_DATA);

            assertEquals(trade, expected);
            assertEquals(node.resolvedTrade(quantity, MARKET_DATA, REF_DATA), trade.resolve(REF_DATA));
        }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the implied Black volatility of the foreign exchange vanilla option product.
        /// </summary>
        /// <param name="option">  the option product </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="volatilities">  the Black volatility provider </param>
        /// <returns> the implied volatility of the product </returns>
        /// <exception cref="IllegalArgumentException"> if the option has expired </exception>
        public virtual double impliedVolatility(ResolvedFxVanillaOption option, RatesProvider ratesProvider, BlackFxOptionVolatilities volatilities)
        {
            double timeToExpiry = volatilities.relativeTime(option.Expiry);

            if (timeToExpiry <= 0d)
            {
                throw new System.ArgumentException("valuation is after option's expiry.");
            }
            FxRate       forward    = fxPricer.forwardFxRate(option.Underlying, ratesProvider);
            CurrencyPair strikePair = option.Underlying.CurrencyPair;

            return(volatilities.volatility(strikePair, option.Expiry, option.Strike, forward.fxRate(strikePair)));
        }
예제 #7
0
        /// <summary>
        /// Calculates the currency exposure of the foreign exchange vanilla option product.
        /// </summary>
        /// <param name="option">  the option product </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="volatilities">  the Black volatility provider </param>
        /// <returns> the currency exposure </returns>
        public virtual MultiCurrencyAmount currencyExposure(ResolvedFxVanillaOption option, RatesProvider ratesProvider, BlackFxOptionSmileVolatilities volatilities)
        {
            validate(ratesProvider, volatilities);
            double timeToExpiry = volatilities.relativeTime(option.Expiry);

            if (timeToExpiry <= 0d)
            {
                return(MultiCurrencyAmount.empty());
            }
            ResolvedFxSingle     underlyingFx           = option.Underlying;
            Currency             ccyCounter             = option.CounterCurrency;
            double               df                     = ratesProvider.discountFactor(ccyCounter, underlyingFx.PaymentDate);
            FxRate               forward                = fxPricer.forwardFxRate(underlyingFx, ratesProvider);
            CurrencyPair         currencyPair           = underlyingFx.CurrencyPair;
            double               spot                   = ratesProvider.fxRate(currencyPair);
            double               forwardRate            = forward.fxRate(currencyPair);
            double               fwdRateSpotSensitivity = fxPricer.forwardFxRateSpotSensitivity(option.PutCall.Call ? underlyingFx : underlyingFx.inverse(), ratesProvider);
            double               strikeRate             = option.Strike;
            bool                 isCall                 = option.PutCall.Call;
            SmileDeltaParameters smileAtTime            = volatilities.Smile.smileForExpiry(timeToExpiry);

            double[] strikes = smileAtTime.strike(forwardRate).toArray();
            double[] vols    = smileAtTime.Volatility.toArray();
            double   volAtm  = vols[1];

            double[] x        = vannaVolgaWeights(forwardRate, strikeRate, timeToExpiry, volAtm, strikes);
            double   priceFwd = BlackFormulaRepository.price(forwardRate, strikeRate, timeToExpiry, volAtm, isCall);
            double   deltaFwd = BlackFormulaRepository.delta(forwardRate, strikeRate, timeToExpiry, volAtm, isCall);

            for (int i = 0; i < 3; i += 2)
            {
                double priceFwdAtm   = BlackFormulaRepository.price(forwardRate, strikes[i], timeToExpiry, volAtm, isCall);
                double priceFwdSmile = BlackFormulaRepository.price(forwardRate, strikes[i], timeToExpiry, vols[i], isCall);
                priceFwd += x[i] * (priceFwdSmile - priceFwdAtm);
                double deltaFwdAtm   = BlackFormulaRepository.delta(forwardRate, strikes[i], timeToExpiry, volAtm, isCall);
                double deltaFwdSmile = BlackFormulaRepository.delta(forwardRate, strikes[i], timeToExpiry, vols[i], isCall);
                deltaFwd += x[i] * (deltaFwdSmile - deltaFwdAtm);
            }
            double         price          = df * priceFwd;
            double         delta          = df * deltaFwd * fwdRateSpotSensitivity;
            double         signedNotional = this.signedNotional(option);
            CurrencyAmount domestic       = CurrencyAmount.of(currencyPair.Counter, (price - delta * spot) * signedNotional);
            CurrencyAmount foreign        = CurrencyAmount.of(currencyPair.Base, delta * signedNotional);

            return(MultiCurrencyAmount.of(domestic, foreign));
        }
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the Black theta of the foreign exchange vanilla option product.
        /// <para>
        /// The theta is the negative of the first derivative of <seealso cref="#price"/> with respect to time parameter
        /// in Black formula (the discounted driftless theta).
        ///
        /// </para>
        /// </summary>
        /// <param name="option">  the option product </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="volatilities">  the Black volatility provider </param>
        /// <returns> the theta of the product </returns>
        public virtual double theta(ResolvedFxVanillaOption option, RatesProvider ratesProvider, BlackFxOptionVolatilities volatilities)
        {
            double timeToExpiry = volatilities.relativeTime(option.Expiry);

            if (timeToExpiry <= 0d)
            {
                return(0d);
            }
            ResolvedFxSingle underlying     = option.Underlying;
            FxRate           forward        = fxPricer.forwardFxRate(underlying, ratesProvider);
            CurrencyPair     strikePair     = underlying.CurrencyPair;
            double           forwardRate    = forward.fxRate(strikePair);
            double           strikeRate     = option.Strike;
            double           volatility     = volatilities.volatility(strikePair, option.Expiry, strikeRate, forwardRate);
            double           fwdTheta       = BlackFormulaRepository.driftlessTheta(forwardRate, strikeRate, timeToExpiry, volatility);
            double           discountFactor = ratesProvider.discountFactor(option.CounterCurrency, underlying.PaymentDate);

            return(discountFactor * fwdTheta);
        }
예제 #9
0
        //-------------------------------------------------------------------------
        /// <summary>
        /// Calculates the present value sensitivity of the foreign exchange vanilla option product.
        /// <para>
        /// The present value sensitivity of the product is the sensitivity of <seealso cref="#presentValue"/> to
        /// the underlying curves.
        /// </para>
        /// <para>
        /// The implied strikes and weights are fixed in this sensitivity computation.
        ///
        /// </para>
        /// </summary>
        /// <param name="option">  the option product </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="volatilities">  the Black volatility provider </param>
        /// <returns> the present value curve sensitivity of the product </returns>
        public virtual PointSensitivityBuilder presentValueSensitivityRatesStickyStrike(ResolvedFxVanillaOption option, RatesProvider ratesProvider, BlackFxOptionSmileVolatilities volatilities)
        {
            validate(ratesProvider, volatilities);
            double timeToExpiry = volatilities.relativeTime(option.Expiry);

            if (timeToExpiry <= 0d)
            {
                return(PointSensitivityBuilder.none());
            }
            ResolvedFxSingle     underlyingFx = option.Underlying;
            Currency             ccyCounter   = option.CounterCurrency;
            double               df           = ratesProvider.discountFactor(ccyCounter, underlyingFx.PaymentDate);
            FxRate               forward      = fxPricer.forwardFxRate(underlyingFx, ratesProvider);
            CurrencyPair         currencyPair = underlyingFx.CurrencyPair;
            double               forwardRate  = forward.fxRate(currencyPair);
            double               strikeRate   = option.Strike;
            bool                 isCall       = option.PutCall.Call;
            SmileDeltaParameters smileAtTime  = volatilities.Smile.smileForExpiry(timeToExpiry);

            double[] strikes = smileAtTime.strike(forwardRate).toArray();
            double[] vols    = smileAtTime.Volatility.toArray();
            double   volAtm  = vols[1];

            double[] x        = vannaVolgaWeights(forwardRate, strikeRate, timeToExpiry, volAtm, strikes);
            double   priceFwd = BlackFormulaRepository.price(forwardRate, strikeRate, timeToExpiry, volAtm, isCall);
            double   deltaFwd = BlackFormulaRepository.delta(forwardRate, strikeRate, timeToExpiry, volAtm, isCall);

            for (int i = 0; i < 3; i += 2)
            {
                double priceFwdAtm   = BlackFormulaRepository.price(forwardRate, strikes[i], timeToExpiry, volAtm, isCall);
                double priceFwdSmile = BlackFormulaRepository.price(forwardRate, strikes[i], timeToExpiry, vols[i], isCall);
                priceFwd += x[i] * (priceFwdSmile - priceFwdAtm);
                double deltaFwdAtm   = BlackFormulaRepository.delta(forwardRate, strikes[i], timeToExpiry, volAtm, isCall);
                double deltaFwdSmile = BlackFormulaRepository.delta(forwardRate, strikes[i], timeToExpiry, vols[i], isCall);
                deltaFwd += x[i] * (deltaFwdSmile - deltaFwdAtm);
            }
            double signedNotional            = this.signedNotional(option);
            PointSensitivityBuilder dfSensi  = ratesProvider.discountFactors(ccyCounter).zeroRatePointSensitivity(underlyingFx.PaymentDate).multipliedBy(priceFwd * signedNotional);
            PointSensitivityBuilder fwdSensi = fxPricer.forwardFxRatePointSensitivity(option.PutCall.Call ? underlyingFx : underlyingFx.inverse(), ratesProvider).multipliedBy(df * deltaFwd * signedNotional);

            return(dfSensi.combinedWith(fwdSensi));
        }
예제 #10
0
        /// <summary>
        /// Computes the present value sensitivity to the black volatilities used in the pricing.
        /// <para>
        /// The implied strikes and weights are fixed in this sensitivity computation.
        ///
        /// </para>
        /// </summary>
        /// <param name="option">  the option product </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="volatilities">  the Black volatility provider </param>
        /// <returns> the present value sensitivity </returns>
        public virtual PointSensitivityBuilder presentValueSensitivityModelParamsVolatility(ResolvedFxVanillaOption option, RatesProvider ratesProvider, BlackFxOptionSmileVolatilities volatilities)
        {
            validate(ratesProvider, volatilities);
            double timeToExpiry = volatilities.relativeTime(option.Expiry);

            if (timeToExpiry <= 0d)
            {
                return(PointSensitivityBuilder.none());
            }
            ResolvedFxSingle     underlyingFx = option.Underlying;
            Currency             ccyCounter   = option.CounterCurrency;
            double               df           = ratesProvider.discountFactor(ccyCounter, underlyingFx.PaymentDate);
            FxRate               forward      = fxPricer.forwardFxRate(underlyingFx, ratesProvider);
            CurrencyPair         currencyPair = underlyingFx.CurrencyPair;
            double               forwardRate  = forward.fxRate(currencyPair);
            double               strikeRate   = option.Strike;
            SmileDeltaParameters smileAtTime  = volatilities.Smile.smileForExpiry(timeToExpiry);

            double[] strikes = smileAtTime.strike(forwardRate).toArray();
            double[] vols    = smileAtTime.Volatility.toArray();
            double   volAtm  = vols[1];

            double[] x                         = vannaVolgaWeights(forwardRate, strikeRate, timeToExpiry, volAtm, strikes);
            double   vegaAtm                   = BlackFormulaRepository.vega(forwardRate, strikeRate, timeToExpiry, volAtm);
            double   signedNotional            = this.signedNotional(option);
            PointSensitivityBuilder sensiSmile = PointSensitivityBuilder.none();

            for (int i = 0; i < 3; i += 2)
            {
                double vegaFwdAtm = BlackFormulaRepository.vega(forwardRate, strikes[i], timeToExpiry, volAtm);
                vegaAtm -= x[i] * vegaFwdAtm;
                double vegaFwdSmile = BlackFormulaRepository.vega(forwardRate, strikes[i], timeToExpiry, vols[i]);
                sensiSmile = sensiSmile.combinedWith(FxOptionSensitivity.of(volatilities.Name, currencyPair, timeToExpiry, strikes[i], forwardRate, ccyCounter, df * signedNotional * x[i] * vegaFwdSmile));
            }
            FxOptionSensitivity sensiAtm = FxOptionSensitivity.of(volatilities.Name, currencyPair, timeToExpiry, strikes[1], forwardRate, ccyCounter, df * signedNotional * vegaAtm);

            return(sensiAtm.combinedWith(sensiSmile));
        }
        // the delta without discounting
        private double undiscountedDelta(ResolvedFxVanillaOption option, RatesProvider ratesProvider, BlackFxOptionVolatilities volatilities)
        {
            double timeToExpiry = volatilities.relativeTime(option.Expiry);

            if (timeToExpiry < 0d)
            {
                return(0d);
            }
            ResolvedFxSingle underlying  = option.Underlying;
            FxRate           forward     = fxPricer.forwardFxRate(underlying, ratesProvider);
            CurrencyPair     strikePair  = underlying.CurrencyPair;
            double           forwardRate = forward.fxRate(strikePair);
            double           strikeRate  = option.Strike;
            bool             isCall      = option.PutCall.Call;

            if (timeToExpiry == 0d)
            {
                return(isCall ? (forwardRate > strikeRate ? 1d : 0d) : (strikeRate > forwardRate ? -1d : 0d));
            }
            double volatility = volatilities.volatility(strikePair, option.Expiry, strikeRate, forwardRate);

            return(BlackFormulaRepository.delta(forwardRate, strikeRate, timeToExpiry, volatility, isCall));
        }
        /// <summary>
        /// Computes the present value sensitivity to the black volatility used in the pricing.
        /// <para>
        /// The result is a single sensitivity to the volatility used.
        ///
        /// </para>
        /// </summary>
        /// <param name="option">  the option product </param>
        /// <param name="ratesProvider">  the rates provider </param>
        /// <param name="volatilities">  the Black volatility provider </param>
        /// <returns> the present value sensitivity </returns>
        public virtual PointSensitivityBuilder presentValueSensitivityModelParamsVolatility(ResolvedFxVanillaOption option, RatesProvider ratesProvider, BlackFxOptionVolatilities volatilities)
        {
            if (volatilities.relativeTime(option.Expiry) <= 0d)
            {
                return(PointSensitivityBuilder.none());
            }
            ResolvedFxSingle underlying = option.Underlying;
            FxRate           forward    = fxPricer.forwardFxRate(underlying, ratesProvider);
            CurrencyPair     strikePair = underlying.CurrencyPair;
            CurrencyAmount   valueVega  = presentValueVega(option, ratesProvider, volatilities);

            return(FxOptionSensitivity.of(volatilities.Name, strikePair, volatilities.relativeTime(option.Expiry), option.Strike, forward.fxRate(strikePair), valueVega.Currency, valueVega.Amount));
        }
예제 #13
0
        /// <summary>
        /// Creates an {@code FxSwap} using decimal forward points, specifying a date adjustment.
        /// <para>
        /// The FX rate at the near date is specified as {@code nearRate}.
        /// The FX rate at the far date is equal to {@code nearRate + forwardPoints}
        /// Thus "FX forward spread" might be a better name for the concept.
        /// </para>
        /// <para>
        /// The two currencies are specified by the near FX rate.
        /// The amount must be specified using one of the currencies of the near FX rate.
        /// The near date must be before the far date.
        /// Conventions will be used to determine the base and counter currency.
        ///
        /// </para>
        /// </summary>
        /// <param name="amount">  the amount being exchanged, positive if being received in the near leg, negative if being paid </param>
        /// <param name="nearRate">  the near FX rate </param>
        /// <param name="decimalForwardPoints">  the decimal forward points, where the far FX rate is {@code (nearRate + forwardPoints)} </param>
        /// <param name="nearDate">  the near value date </param>
        /// <param name="farDate">  the far value date </param>
        /// <param name="paymentDateAdjustment">  the adjustment to apply to the payment dates </param>
        /// <returns> the FX swap </returns>
        /// <exception cref="IllegalArgumentException"> if the FX rate and amount do not have a currency in common </exception>
        public static FxSwap ofForwardPoints(CurrencyAmount amount, FxRate nearRate, double decimalForwardPoints, LocalDate nearDate, LocalDate farDate, BusinessDayAdjustment paymentDateAdjustment)
        {
            FxRate farRate = FxRate.of(nearRate.Pair, nearRate.fxRate(nearRate.Pair) + decimalForwardPoints);

            return(of(amount, nearRate, nearDate, farRate, farDate, paymentDateAdjustment));
        }
예제 #14
0
        /// <summary>
        /// Creates an {@code FxSwap} using decimal forward points.
        /// <para>
        /// The FX rate at the near date is specified as {@code nearRate}.
        /// The FX rate at the far date is equal to {@code nearRate + forwardPoints}.
        /// Thus "FX forward spread" might be a better name for the concept.
        /// </para>
        /// <para>
        /// The two currencies are specified by the near FX rate.
        /// The amount must be specified using one of the currencies of the near FX rate.
        /// The near date must be before the far date.
        /// Conventions will be used to determine the base and counter currency.
        ///
        /// </para>
        /// </summary>
        /// <param name="amount">  the amount being exchanged, positive if being received in the near leg, negative if being paid </param>
        /// <param name="nearRate">  the near FX rate </param>
        /// <param name="decimalForwardPoints">  the decimal forward points, where the far FX rate is {@code (nearRate + forwardPoints)} </param>
        /// <param name="nearDate">  the near value date </param>
        /// <param name="farDate">  the far value date </param>
        /// <returns> the FX swap </returns>
        /// <exception cref="IllegalArgumentException"> if the FX rate and amount do not have a currency in common </exception>
        public static FxSwap ofForwardPoints(CurrencyAmount amount, FxRate nearRate, double decimalForwardPoints, LocalDate nearDate, LocalDate farDate)
        {
            FxRate farRate = FxRate.of(nearRate.Pair, nearRate.fxRate(nearRate.Pair) + decimalForwardPoints);

            return(of(amount, nearRate, nearDate, farRate, farDate));
        }