def test_american_call():
    spot_fx_rate = 1.20

    call_option = FXVanillaOption(expiry_date,
                                  strike_fx_rate,
                                  "EURUSD",
                                  OptionTypes.AMERICAN_CALL,
                                  1000000,
                                  "USD")
    valueAmerican = call_option.value(valuation_date,
                                      spot_fx_rate,
                                      dom_discount_curve,
                                      for_discount_curve,
                                      model)['v']

    assert round(valueAmerican, 4) == 0.0255

    spot_fx_rate = 1.80

    call_option = FXVanillaOption(expiry_date,
                                  strike_fx_rate,
                                  "EURUSD",
                                  OptionTypes.AMERICAN_CALL,
                                  1000000,
                                  "USD")
    valueAmerican = call_option.value(valuation_date,
                                      spot_fx_rate,
                                      dom_discount_curve,
                                      for_discount_curve,
                                      model)['v']

    assert round(valueAmerican, 4) == 0.5500
def test_european_call():
    spot_fx_rate = 1.20

    call_option = FXVanillaOption(expiry_date,
                                  strike_fx_rate,
                                  "EURUSD",
                                  OptionTypes.EUROPEAN_CALL,
                                  notional,
                                  "USD")
    valueEuropean = call_option.value(valuation_date,
                                      spot_fx_rate,
                                      dom_discount_curve,
                                      for_discount_curve,
                                      model)['v']

    assert round(valueEuropean, 4) == 0.0251

    spot_fx_rate = 1.80

    call_option = FXVanillaOption(expiry_date,
                                  strike_fx_rate,
                                  "EURUSD",
                                  OptionTypes.EUROPEAN_CALL,
                                  notional,
                                  "USD")
    valueEuropean = call_option.value(valuation_date,
                                      spot_fx_rate,
                                      dom_discount_curve,
                                      for_discount_curve,
                                      model)['v']

    assert round(valueEuropean, 4) == 0.5277
def test_FinFXVanillaOptionWystupExample1():

    # Example from Book extract by Uwe Wystup with results in Table 1.2
    # https://mathfinance.com/wp-content/uploads/2017/06/FXOptionsStructuredProducts2e-Extract.pdf

    # Not exactly T=1.0 but close so don't exact exact agreement
    # (in fact I do not get exact agreement even if I do set T=1.0)
    valuation_date = Date(13, 2, 2018)
    expiry_date = Date(13, 2, 2019)

    # In BS the FX rate is the price in domestic of one unit of foreign
    # In case of EURUSD = 1.3 the domestic currency is USD and foreign is EUR
    # DOM = USD , FOR = EUR
    ccy1 = "EUR"
    ccy2 = "USD"
    ccy1CCRate = 0.030  # EUR
    ccy2CCRate = 0.025  # USD

    currency_pair = ccy1 + ccy2  # Always ccy1ccy2
    spot_fx_rate = 1.20
    strike_fx_rate = 1.250
    volatility = 0.10

    notional = 1000000.0

    dom_discount_curve = DiscountCurveFlat(valuation_date, ccy2CCRate)
    for_discount_curve = DiscountCurveFlat(valuation_date, ccy1CCRate)

    model = BlackScholes(volatility)

    # Two examples to show that changing the notional currency and notional
    # keeps the value unchanged
    notional = 1000000.0
    call_option = FXVanillaOption(expiry_date, strike_fx_rate, currency_pair,
                                  OptionTypes.EUROPEAN_CALL, notional, "EUR",
                                  2)

    value = call_option.value(1.0, spot_fx_rate, dom_discount_curve,
                              for_discount_curve, model)

    notional = 1250000.0
    call_option = FXVanillaOption(expiry_date, strike_fx_rate, currency_pair,
                                  OptionTypes.EUROPEAN_CALL, notional, "USD",
                                  2)

    value = call_option.value(valuation_date, spot_fx_rate, dom_discount_curve,
                              for_discount_curve, model)

    delta = call_option.delta(valuation_date, spot_fx_rate, dom_discount_curve,
                              for_discount_curve, model)

    testCases.header("value", "delta")
    testCases.print(value, delta)
def test_FinFXVanillaOptionBloombergExample():

    # Example Bloomberg Pricing at
    # https://stackoverflow.com/questions/48778712/fx-vanilla-call-price-in-quantlib-doesnt-match-bloomberg

    valuation_date = Date(13, 2, 2018)
    expiry_date = Date(15, 2, 2019)

    # In BS the FX rate is the price in domestic of one unit of foreign
    # In case of EURUSD = 1.3 the domestic currency is USD and foreign is EUR
    # DOM = USD , FOR = EUR
    forName = "EUR"
    domName = "USD"
    forDepoRate = 0.05  # EUR
    domDepoRate = 0.02  # USD

    currency_pair = forName + domName  # Always FORDOM
    spot_fx_rate = 1.30
    strike_fx_rate = 1.3650
    volatility = 0.20

    spot_days = 0
    settlement_date = valuation_date.add_weekdays(spot_days)
    maturity_date = settlement_date.add_months(12)
    notional = 1000000.0
    notional_currency = "EUR"
    calendar_type = CalendarTypes.TARGET

    depos = []
    fras = []
    swaps = []
    depo = IborDeposit(settlement_date, maturity_date, domDepoRate,
                       DayCountTypes.ACT_360, notional, calendar_type)
    depos.append(depo)
    dom_discount_curve = IborSingleCurve(valuation_date, depos, fras, swaps)

    depos = []
    fras = []
    swaps = []
    depo = IborDeposit(settlement_date, maturity_date, forDepoRate,
                       DayCountTypes.ACT_360, notional, calendar_type)
    depos.append(depo)
    for_discount_curve = IborSingleCurve(valuation_date, depos, fras, swaps)

    model = BlackScholes(volatility)

    call_option = FXVanillaOption(expiry_date, strike_fx_rate, currency_pair,
                                  OptionTypes.EUROPEAN_CALL, notional,
                                  notional_currency, 2)

    value = call_option.value(valuation_date, spot_fx_rate, dom_discount_curve,
                              for_discount_curve, model)

    delta = call_option.delta(valuation_date, spot_fx_rate, dom_discount_curve,
                              for_discount_curve, model)

    testCases.header("value", "delta")
    testCases.print(value, delta)
示例#5
0
def test_FinFXVanillaOptionWystupExample2():
    # Example Bloomberg Pricing at
    # https://stackoverflow.com/questions/48778712/fx-vanilla-call-price-in-quantlib-doesnt-match-bloomberg

    valuation_date = Date(13, 2, 2018)
    expiry_date = Date(13, 2, 2019)

    # In BS the FX rate is the price in domestic of one unit of foreign
    # In case of EURUSD = 1.3 the domestic currency is USD and foreign is EUR
    # DOM = USD , FOR = EUR
    ccy1 = "EUR"
    ccy2 = "USD"
    ccy1CCRate = 0.0396  # EUR
    ccy2CCRate = 0.0357  # USD

    currency_pair = ccy1 + ccy2  # Always ccy1ccy2
    spot_fx_rate = 0.9090
    strike_fx_rate = 0.9090
    volatility = 0.12

    notional = 1000000.0

    dom_discount_curve = DiscountCurveFlat(valuation_date, ccy2CCRate)
    for_discount_curve = DiscountCurveFlat(valuation_date, ccy1CCRate)

    model = BlackScholes(volatility)

    # Two examples to show that changing the notional currency and notional
    # keeps the value unchanged
    notional = 1000000.0
    call_option = FXVanillaOption(expiry_date, strike_fx_rate, currency_pair,
                                  OptionTypes.EUROPEAN_PUT, notional, "EUR", 2)

    value = call_option.value(valuation_date, spot_fx_rate, dom_discount_curve,
                              for_discount_curve, model)

    assert round(value['v'], 4) == 0.0436
    assert round(value['cash_dom'], 4) == 43612.8769
    assert round(value['cash_for'], 4) == 47978.9625
    assert round(value['pips_dom'], 4) == 0.0436
    assert round(value['pips_for'], 4) == 0.0528
    assert round(value['pct_dom'], 4) == 0.0480
    assert round(value['pct_for'], 4) == 0.0480
    assert round(value['not_dom'], 4) == 909000.0
    assert round(value['not_for'], 4) == 1000000.0
    assert value['ccy_dom'] == 'USD'
    assert value['ccy_for'] == 'EUR'

    delta = call_option.delta(valuation_date, spot_fx_rate, dom_discount_curve,
                              for_discount_curve, model)

    assert round(delta['pips_spot_delta'], 4) == -0.4700
    assert round(delta['pips_fwd_delta'], 4) == -0.4890
    assert round(delta['pct_spot_delta_prem_adj'], 4) == -0.5180
    assert round(delta['pct_fwd_delta_prem_adj'], 4) == -0.5389
示例#6
0
def test_FinFXVanillaOptionWystupExample2():

    # Example Bloomberg Pricing at
    # https://stackoverflow.com/questions/48778712/fx-vanilla-call-price-in-quantlib-doesnt-match-bloomberg

    valuation_date = Date(13, 2, 2018)
    expiry_date = Date(13, 2, 2019)

    # In BS the FX rate is the price in domestic of one unit of foreign
    # In case of EURUSD = 1.3 the domestic currency is USD and foreign is EUR
    # DOM = USD , FOR = EUR
    ccy1 = "EUR"
    ccy2 = "USD"
    ccy1CCRate = 0.0396  # EUR
    ccy2CCRate = 0.0357  # USD

    currency_pair = ccy1 + ccy2  # Always ccy1ccy2
    spot_fx_rate = 0.9090
    strike_fx_rate = 0.9090
    volatility = 0.12

    notional = 1000000.0

    dom_discount_curve = DiscountCurveFlat(valuation_date, ccy2CCRate)
    for_discount_curve = DiscountCurveFlat(valuation_date, ccy1CCRate)

    model = BlackScholes(volatility)

    # Two examples to show that changing the notional currency and notional
    # keeps the value unchanged
    notional = 1000000.0
    call_option = FXVanillaOption(expiry_date, strike_fx_rate, currency_pair,
                                  FinOptionTypes.EUROPEAN_PUT, notional, "EUR",
                                  2)

    value = call_option.value(valuation_date, spot_fx_rate, dom_discount_curve,
                              for_discount_curve, model)

    delta = call_option.delta(valuation_date, spot_fx_rate, dom_discount_curve,
                              for_discount_curve, model)

    testCases.header("value", "delta")
    testCases.print(value, delta)
def test_FinFXVanillaOptionHullExample():

    #   Example from Hull 4th edition page 284
    valuation_date = Date(1, 1, 2015)
    expiry_date = valuation_date.add_months(4)
    spot_fx_rate = 1.60
    volatility = 0.1411
    dom_interest_rate = 0.08
    forInterestRate = 0.11
    model = BlackScholes(volatility)
    dom_discount_curve = DiscountCurveFlat(valuation_date, dom_interest_rate)
    for_discount_curve = DiscountCurveFlat(valuation_date, forInterestRate)

    num_paths_list = [10000, 20000, 40000, 80000, 160000, 320000]

    testCases.header("NUMPATHS", "VALUE_BS", "VALUE_MC")
    strike_fx_rate = 1.60

    for num_paths in num_paths_list:

        call_option = FXVanillaOption(expiry_date, strike_fx_rate, "EURUSD",
                                      OptionTypes.EUROPEAN_CALL, 1000000,
                                      "USD")

        value = call_option.value(valuation_date, spot_fx_rate,
                                  dom_discount_curve, for_discount_curve,
                                  model)

        start = time.time()

        value_mc = call_option.value_mc(valuation_date, spot_fx_rate,
                                        dom_discount_curve, for_discount_curve,
                                        model, num_paths)

        end = time.time()
        duration = end - start
        testCases.print(num_paths, value, value_mc)

##########################################################################

    spot_fx_rates = np.arange(100, 200, 10)
    spot_fx_rates = spot_fx_rates / 100.0
    num_paths = 100000

    testCases.header("NUMPATHS", "CALL_VALUE_BS", "CALL_VALUE_MC")

    for spot_fx_rate in spot_fx_rates:

        call_option = FXVanillaOption(expiry_date, strike_fx_rate, "EURUSD",
                                      OptionTypes.EUROPEAN_CALL, 1000000,
                                      "USD")

        value = call_option.value(valuation_date, spot_fx_rate,
                                  dom_discount_curve, for_discount_curve,
                                  model)
        start = time.time()
        value_mc = call_option.value_mc(valuation_date, spot_fx_rate,
                                        dom_discount_curve, for_discount_curve,
                                        model, num_paths)
        end = time.time()
        duration = end - start
        testCases.print(num_paths, value, value_mc)

##########################################################################

    spot_fx_rates = np.arange(100, 200, 10) / 100.0
    num_paths = 100000

    testCases.header("SPOT FX RATE", "PUT_VALUE_BS", "PUT_VALUE_MC")

    for spot_fx_rate in spot_fx_rates:

        put_option = FXVanillaOption(expiry_date, strike_fx_rate, "EURUSD",
                                     OptionTypes.EUROPEAN_PUT, 1000000, "USD")

        value = put_option.value(valuation_date, spot_fx_rate,
                                 dom_discount_curve, for_discount_curve, model)
        start = time.time()
        value_mc = put_option.value_mc(valuation_date, spot_fx_rate,
                                       dom_discount_curve, for_discount_curve,
                                       model, num_paths)
        end = time.time()
        duration = end - start
        testCases.print(spot_fx_rate, value, value_mc)

##########################################################################

    spot_fx_rates = np.arange(100, 200, 10) / 100.0

    testCases.header("SPOT FX RATE", "CALL_VALUE_BS", "DELTA_BS", "VEGA_BS",
                     "THETA_BS", "RHO_BS")

    for spot_fx_rate in spot_fx_rates:
        call_option = FXVanillaOption(expiry_date, strike_fx_rate, "EURUSD",
                                      OptionTypes.EUROPEAN_CALL, 1000000,
                                      "USD")
        value = call_option.value(valuation_date, spot_fx_rate,
                                  dom_discount_curve, for_discount_curve,
                                  model)
        delta = call_option.delta(valuation_date, spot_fx_rate,
                                  dom_discount_curve, for_discount_curve,
                                  model)
        vega = call_option.vega(valuation_date, spot_fx_rate,
                                dom_discount_curve, for_discount_curve, model)
        theta = call_option.theta(valuation_date, spot_fx_rate,
                                  dom_discount_curve, for_discount_curve,
                                  model)
        #  call_option.rho(valuation_date,stock_price, interest_rate,
        #  dividend_yield, modelType, model_params)
        rho = 999
        testCases.print(spot_fx_rate, value, delta, vega, theta, rho)

    testCases.header("SPOT FX RATE", "PUT_VALUE_BS", "DELTA_BS", "VEGA_BS",
                     "THETA_BS", "RHO_BS")

    for spot_fx_rate in spot_fx_rates:
        put_option = FXVanillaOption(expiry_date, strike_fx_rate, "EURUSD",
                                     OptionTypes.EUROPEAN_PUT, 1000000, "USD")

        value = put_option.value(valuation_date, spot_fx_rate,
                                 dom_discount_curve, for_discount_curve, model)
        delta = put_option.delta(valuation_date, spot_fx_rate,
                                 dom_discount_curve, for_discount_curve, model)
        vega = put_option.vega(valuation_date, spot_fx_rate,
                               dom_discount_curve, for_discount_curve, model)
        theta = put_option.theta(valuation_date, spot_fx_rate,
                                 dom_discount_curve, for_discount_curve, model)
        # put_option.rho(valuation_date,stock_price, interest_rate, dividend_yield,
        # modelType, model_params)
        rho = 999
        testCases.print(spot_fx_rate, value, delta, vega, theta, rho)

##########################################################################

    testCases.header("SPOT FX RATE", "VALUE_BS", "VOL_IN", "IMPLD_VOL")

    spot_fx_rates = np.arange(100, 200, 10) / 100.0

    for spot_fx_rate in spot_fx_rates:
        call_option = FXVanillaOption(expiry_date, strike_fx_rate, "EURUSD",
                                      OptionTypes.EUROPEAN_CALL, 1000000,
                                      "USD")

        value = call_option.value(valuation_date, spot_fx_rate,
                                  dom_discount_curve, for_discount_curve,
                                  model)['v']

        impliedVol = call_option.implied_volatility(valuation_date,
                                                    spot_fx_rate,
                                                    dom_discount_curve,
                                                    for_discount_curve, value)

        testCases.print(spot_fx_rate, value, volatility, impliedVol)
示例#8
0
def test_FinFXOptionSABR():

    # UNFINISHED
    # There is no FXAmericanOption class. It is embedded in the FXVanillaOption
    # class. This test just compares it to the European

    valuation_date = Date(13, 2, 2018)
    expiry_date = Date(13, 2, 2019)

    # In BS the FX rate is the price in domestic of one unit of foreign
    # In case of EURUSD = 1.3 the domestic currency is USD and foreign is EUR
    # DOM = USD , FOR = EUR
    ccy1CCRate = 0.030  # EUR
    ccy2CCRate = 0.025  # USD

    spot_fx_rate = 1.20
    strike_fx_rate = 1.250
    volatility = 0.10

    notional = 1000000.0

    dom_discount_curve = DiscountCurveFlat(valuation_date, ccy2CCRate)
    for_discount_curve = DiscountCurveFlat(valuation_date, ccy1CCRate)

    model = BlackScholes(volatility)

    # Two examples to show that changing the notional currency and notional
    # keeps the value unchanged
    notional = 1000000.0

    spot_fx_rates = np.arange(50, 200, 10)/100.0

    testCases.header("OPTION", "FX_RATE", "VALUE_BS", "VOL_IN", "DIFF")

    for spot_fx_rate in spot_fx_rates:

        call_option = FXVanillaOption(expiry_date,
                                     strike_fx_rate,
                                     "EURUSD",
                                     OptionTypes.EUROPEAN_CALL,
                                     notional,
                                     "USD")

        valueEuropean = call_option.value(valuation_date,
                                         spot_fx_rate,
                                         dom_discount_curve,
                                         for_discount_curve,
                                         model)['v']

        call_option = FXVanillaOption(expiry_date,
                                     strike_fx_rate,
                                     "EURUSD",
                                     OptionTypes.AMERICAN_CALL,
                                     1000000,
                                     "USD")

        valueAmerican = call_option.value(valuation_date,
                                         spot_fx_rate,
                                         dom_discount_curve,
                                         for_discount_curve,
                                         model)['v']

        diff = (valueAmerican - valueEuropean)

        testCases.print("CALL:",
                        "%9.6f" % spot_fx_rate,
                        "%9.7f" % valueEuropean,
                        "%9.7f" % valueAmerican,
                        "%9.7f" % diff)

    testCases.header("OPTION", "FX_RATE", "VALUE_BS", "VOL_IN", "DIFF")

    for spot_fx_rate in spot_fx_rates:

        call_option = FXVanillaOption(expiry_date,
                                     strike_fx_rate,
                                     "EURUSD",
                                     OptionTypes.EUROPEAN_PUT,
                                     1000000,
                                     "USD")

        valueEuropean = call_option.value(valuation_date,
                                         spot_fx_rate,
                                         dom_discount_curve,
                                         for_discount_curve,
                                         model)['v']

        call_option = FXVanillaOption(expiry_date,
                                     strike_fx_rate,
                                     "EURUSD",
                                     OptionTypes.AMERICAN_PUT,
                                     1000000,
                                     "USD")

        valueAmerican = call_option.value(valuation_date,
                                         spot_fx_rate,
                                         dom_discount_curve,
                                         for_discount_curve,
                                         model)['v']

        diff = (valueAmerican - valueEuropean)
        testCases.print("PUT:",
                        "%9.6f" % spot_fx_rate,
                        "%9.7f" % valueEuropean,
                        "%9.7f" % valueAmerican,
                        "%9.7f" % diff)
def test_FinFXAmericanOption():

    # There is no FXAmericanOption class. It is embedded in the FXVanillaOption
    # class. This test just compares it to the European

    valuation_date = Date(13, 2, 2018)
    expiry_date = Date(13, 2, 2019)

    # In BS the FX rate is the price in domestic of one unit of foreign
    # In case of EURUSD = 1.3 the domestic currency is USD and foreign is EUR
    # DOM = USD , FOR = EUR
    ccy1 = "EUR"
    ccy2 = "USD"
    ccy1CCRate = 0.030  # EUR
    ccy2CCRate = 0.025  # USD

    currency_pair = ccy1 + ccy2  # Always ccy1ccy2
    spot_fx_rate = 1.20
    strike_fx_rate = 1.250
    volatility = 0.10

    dom_discount_curve = DiscountCurveFlat(valuation_date, ccy2CCRate)
    for_discount_curve = DiscountCurveFlat(valuation_date, ccy1CCRate)

    model = BlackScholes(volatility)

    # Two examples to show that changing the notional currency and notional
    # keeps the value unchanged

    testCases.header("SPOT FX RATE", "VALUE_BS", "VOL_IN", "IMPLD_VOL")

    spot_fx_rates = np.arange(50, 200, 10) / 100.0

    for spot_fx_rate in spot_fx_rates:

        call_option = FXVanillaOption(expiry_date, strike_fx_rate,
                                      currency_pair, OptionTypes.EUROPEAN_CALL,
                                      1000000, "USD")

        valueEuropean = call_option.value(valuation_date, spot_fx_rate,
                                          dom_discount_curve,
                                          for_discount_curve, model)['v']

        call_option = FXVanillaOption(expiry_date, strike_fx_rate, "EURUSD",
                                      OptionTypes.AMERICAN_CALL, 1000000,
                                      "USD")

        valueAmerican = call_option.value(valuation_date, spot_fx_rate,
                                          dom_discount_curve,
                                          for_discount_curve, model)['v']

        diff = (valueAmerican - valueEuropean)
        testCases.print(spot_fx_rate, valueEuropean, valueAmerican, diff)

    for spot_fx_rate in spot_fx_rates:

        call_option = FXVanillaOption(expiry_date, strike_fx_rate, "EURUSD",
                                      OptionTypes.EUROPEAN_PUT, 1000000, "USD")

        valueEuropean = call_option.value(valuation_date, spot_fx_rate,
                                          dom_discount_curve,
                                          for_discount_curve, model)['v']

        call_option = FXVanillaOption(expiry_date, strike_fx_rate, "EURUSD",
                                      OptionTypes.AMERICAN_PUT, 1000000, "USD")

        valueAmerican = call_option.value(valuation_date, spot_fx_rate,
                                          dom_discount_curve,
                                          for_discount_curve, model)['v']

        diff = (valueAmerican - valueEuropean)
        testCases.print(spot_fx_rate, valueEuropean, valueAmerican, diff)
示例#10
0
def test_FinFXVanillaOptionWystupExample1():
    # Example from Book extract by Uwe Wystup with results in Table 1.2
    # https://mathfinance.com/wp-content/uploads/2017/06/FXOptionsStructuredProducts2e-Extract.pdf

    # Not exactly T=1.0 but close so don't exact exact agreement
    # (in fact I do not get exact agreement even if I do set T=1.0)
    valuation_date = Date(13, 2, 2018)
    expiry_date = Date(13, 2, 2019)

    # In BS the FX rate is the price in domestic of one unit of foreign
    # In case of EURUSD = 1.3 the domestic currency is USD and foreign is EUR
    # DOM = USD , FOR = EUR
    ccy1 = "EUR"
    ccy2 = "USD"
    ccy1CCRate = 0.030  # EUR
    ccy2CCRate = 0.025  # USD

    currency_pair = ccy1 + ccy2  # Always ccy1ccy2
    spot_fx_rate = 1.20
    strike_fx_rate = 1.250
    volatility = 0.10

    notional = 1000000.0

    dom_discount_curve = DiscountCurveFlat(valuation_date, ccy2CCRate)
    for_discount_curve = DiscountCurveFlat(valuation_date, ccy1CCRate)

    model = BlackScholes(volatility)

    # Two examples to show that changing the notional currency and notional
    # keeps the value unchanged
    notional = 1000000.0
    call_option = FXVanillaOption(expiry_date, strike_fx_rate, currency_pair,
                                  OptionTypes.EUROPEAN_CALL, notional, "EUR",
                                  2)

    value = call_option.value(valuation_date, spot_fx_rate, dom_discount_curve,
                              for_discount_curve, model)

    notional = 1250000.0
    call_option = FXVanillaOption(expiry_date, strike_fx_rate, currency_pair,
                                  OptionTypes.EUROPEAN_CALL, notional, "USD",
                                  2)

    value = call_option.value(valuation_date, spot_fx_rate, dom_discount_curve,
                              for_discount_curve, model)

    assert round(value['v'], 4) == 0.0251
    assert round(value['cash_dom'], 4) == 25125.1772
    assert round(value['cash_for'], 4) == 20937.6477
    assert round(value['pips_dom'], 4) == 0.0251
    assert round(value['pips_for'], 4) == 0.0168
    assert round(value['pct_dom'], 4) == 0.0201
    assert round(value['pct_for'], 4) == 0.0209
    assert round(value['not_dom'], 4) == 1250000.0
    assert round(value['not_for'], 4) == 1000000.0
    assert value['ccy_dom'] == 'USD'
    assert value['ccy_for'] == 'EUR'

    delta = call_option.delta(valuation_date, spot_fx_rate, dom_discount_curve,
                              for_discount_curve, model)

    assert round(delta['pips_spot_delta'], 4) == 0.3315
    assert round(delta['pips_fwd_delta'], 4) == 0.3416
    assert round(delta['pct_spot_delta_prem_adj'], 4) == 0.3105
    assert round(delta['pct_fwd_delta_prem_adj'], 4) == 0.3200
示例#11
0
def test_FinFXVanillaOptionBloombergExample():
    # Example Bloomberg Pricing at
    # https://stackoverflow.com/questions/48778712/fx-vanilla-call-price-in-quantlib-doesnt-match-bloomberg

    valuation_date = Date(13, 2, 2018)
    expiry_date = Date(15, 2, 2019)

    # In BS the FX rate is the price in domestic of one unit of foreign
    # In case of EURUSD = 1.3 the domestic currency is USD and foreign is EUR
    # DOM = USD , FOR = EUR
    forName = "EUR"
    domName = "USD"
    forDepoRate = 0.05  # EUR
    domDepoRate = 0.02  # USD

    currency_pair = forName + domName  # Always FORDOM
    spot_fx_rate = 1.30
    strike_fx_rate = 1.3650
    volatility = 0.20

    spot_days = 0
    settlement_date = valuation_date.add_weekdays(spot_days)
    maturity_date = settlement_date.add_months(12)
    notional = 1000000.0
    notional_currency = "EUR"
    calendar_type = CalendarTypes.TARGET

    depos = []
    fras = []
    swaps = []
    depo = IborDeposit(settlement_date, maturity_date, domDepoRate,
                       DayCountTypes.ACT_360, notional, calendar_type)
    depos.append(depo)
    dom_discount_curve = IborSingleCurve(valuation_date, depos, fras, swaps)

    depos = []
    fras = []
    swaps = []
    depo = IborDeposit(settlement_date, maturity_date, forDepoRate,
                       DayCountTypes.ACT_360, notional, calendar_type)
    depos.append(depo)
    for_discount_curve = IborSingleCurve(valuation_date, depos, fras, swaps)

    model = BlackScholes(volatility)

    call_option = FXVanillaOption(expiry_date, strike_fx_rate, currency_pair,
                                  OptionTypes.EUROPEAN_CALL, notional,
                                  notional_currency, 2)

    value = call_option.value(valuation_date, spot_fx_rate, dom_discount_curve,
                              for_discount_curve, model)

    assert round(value['v'], 4) == 0.0601
    assert round(value['cash_dom'], 4) == 60145.5078
    assert round(value['cash_for'], 4) == 46265.7752
    assert round(value['pips_dom'], 4) == 0.0601
    assert round(value['pips_for'], 4) == 0.0339
    assert round(value['pct_dom'], 4) == 0.0441
    assert round(value['pct_for'], 4) == 0.0463
    assert round(value['not_dom'], 4) == 1365000.0
    assert round(value['not_for'], 4) == 1000000.0
    assert value['ccy_dom'] == 'USD'
    assert value['ccy_for'] == 'EUR'

    delta = call_option.delta(valuation_date, spot_fx_rate, dom_discount_curve,
                              for_discount_curve, model)

    assert round(delta['pips_spot_delta'], 4) == 0.3671
    assert round(delta['pips_fwd_delta'], 4) == 0.3859
    assert round(delta['pct_spot_delta_prem_adj'], 4) == 0.3208
    assert round(delta['pct_fwd_delta_prem_adj'], 4) == 0.3373