def testBlackScholes(): valuation_date = Date(8, 5, 2015) expiry_date = Date(15, 1, 2016) strike_price = 130.0 stock_price = 127.62 volatility = 0.20 interest_rate = 0.001 dividend_yield = 0.0163 option_type = OptionTypes.AMERICAN_CALL euOptionType = OptionTypes.EUROPEAN_CALL amOption = EquityAmericanOption(expiry_date, strike_price, option_type) ameuOption = EquityAmericanOption(expiry_date, strike_price, euOptionType) euOption = EquityVanillaOption(expiry_date, strike_price, euOptionType) discount_curve = DiscountCurveFlat(valuation_date, interest_rate, FrequencyTypes.CONTINUOUS, DayCountTypes.ACT_365F) dividend_curve = DiscountCurveFlat(valuation_date, dividend_yield, FrequencyTypes.CONTINUOUS, DayCountTypes.ACT_365F) num_steps_per_year = 400 modelTree = BlackScholes(volatility, BlackScholesTypes.CRR_TREE, num_steps_per_year) v = amOption.value(valuation_date, stock_price, discount_curve, dividend_curve, modelTree) # print(v) modelApprox = BlackScholes(volatility, BlackScholesTypes.BARONE_ADESI) v = amOption.value(valuation_date, stock_price, discount_curve, dividend_curve, modelApprox) # print(v) v = ameuOption.value(valuation_date, stock_price, discount_curve, dividend_curve, modelTree) # print(v) v = euOption.value(valuation_date, stock_price, discount_curve, dividend_curve, modelTree) # print(v) amTreeValue = [] amBAWValue = [] euTreeValue = [] euAnalValue = [] volatility = 0.20
def test_EquityChooserOptionDerivicom(): """http://derivicom.com/support/finoptionsxl/index.html?complex_chooser.htm """ valuation_date = Date(1, 1, 2007) chooseDate = Date(1, 2, 2007) call_expiry_date = Date(1, 4, 2007) put_expiry_date = Date(1, 5, 2007) call_strike = 40.0 put_strike = 35.0 stock_price = 38.0 volatility = 0.20 interest_rate = 0.08 dividend_yield = 0.0625 model = BlackScholes(volatility) discount_curve = DiscountCurveFlat(valuation_date, interest_rate) dividend_curve = DiscountCurveFlat(valuation_date, dividend_yield) chooserOption = EquityChooserOption(chooseDate, call_expiry_date, put_expiry_date, call_strike, put_strike) v = chooserOption.value(valuation_date, stock_price, discount_curve, dividend_curve, model) v_mc = chooserOption.value_mc(valuation_date, stock_price, discount_curve, dividend_curve, model, 20000) v_derivicom = 1.0989 testCases.header("", "", "", "", "", "") testCases.print("FINANCEPY", v, "DERIVICOM", v_derivicom, "MC", v_mc)
def test_EquityChooserOptionMatlab(): """https://fr.mathworks.com/help/fininst/chooserbybls.html """ valuation_date = Date(1, 6, 2007) chooseDate = Date(31, 8, 2007) call_expiry_date = Date(2, 12, 2007) put_expiry_date = Date(2, 12, 2007) call_strike = 60.0 put_strike = 60.0 stock_price = 50.0 volatility = 0.20 interest_rate = 0.10 dividend_yield = 0.05 model = BlackScholes(volatility) discount_curve = DiscountCurveFlat(valuation_date, interest_rate) dividend_curve = DiscountCurveFlat(valuation_date, dividend_yield) chooserOption = EquityChooserOption(chooseDate, call_expiry_date, put_expiry_date, call_strike, put_strike) v = chooserOption.value(valuation_date, stock_price, discount_curve, dividend_curve, model) v_mc = chooserOption.value_mc(valuation_date, stock_price, discount_curve, dividend_curve, model, 20000) v_matlab = 8.9308 testCases.header("", "", "", "", "", "") testCases.print("FINANCEPY", v, "MATLAB", v_matlab, "MC", v_mc)
def test_EquityChooserOptionHaug(): """ Following example in Haug Page 130 """ valuation_date = Date(1, 1, 2015) choose_date = Date(2, 4, 2015) call_expiry_date = Date(1, 7, 2015) put_expiry_date = Date(2, 8, 2015) call_strike = 55.0 put_strike = 48.0 stock_price = 50.0 volatility = 0.35 interest_rate = 0.10 dividend_yield = 0.05 model = BlackScholes(volatility) discount_curve = DiscountCurveFlat(valuation_date, interest_rate) dividend_curve = DiscountCurveFlat(valuation_date, dividend_yield) chooserOption = EquityChooserOption(choose_date, call_expiry_date, put_expiry_date, call_strike, put_strike) v = chooserOption.value(valuation_date, stock_price, discount_curve, dividend_curve, model) v_mc = chooserOption.value_mc(valuation_date, stock_price, discount_curve, dividend_curve, model, 20000) v_haug = 6.0508 testCases.header("", "", "", "", "", "") testCases.print("FINANCEPY", v, "HAUG", v_haug, "MC", v_mc)
def test_FinFXDigitalOption(): # 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 = 1.0 dom_discount_curve = DiscountCurveFlat(valuation_date, ccy2CCRate) for_discount_curve = DiscountCurveFlat(valuation_date, ccy1CCRate) model = BlackScholes(volatility) digital_option = FXDigitalOption(expiry_date, strike_fx_rate, currency_pair, OptionTypes.DIGITAL_CALL, notional, "USD") spot_fx_rate = np.linspace(0.01, 2.0, 10) value = digital_option.value(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, model)
def test_EquityChooserOptionHaug(): """ Following example in Haug Page 130 """ valuation_date = Date(1, 1, 2015) choose_date = Date(2, 4, 2015) call_expiry_date = Date(1, 7, 2015) put_expiry_date = Date(2, 8, 2015) call_strike = 55.0 put_strike = 48.0 stock_price = 50.0 volatility = 0.35 interest_rate = 0.10 dividend_yield = 0.05 model = BlackScholes(volatility) discount_curve = DiscountCurveFlat(valuation_date, interest_rate) dividend_curve = DiscountCurveFlat(valuation_date, dividend_yield) chooserOption = EquityChooserOption(choose_date, call_expiry_date, put_expiry_date, call_strike, put_strike) v = chooserOption.value(valuation_date, stock_price, discount_curve, dividend_curve, model) v_mc = chooserOption.value_mc(valuation_date, stock_price, discount_curve, dividend_curve, model, 20000) v_haug = 6.0508 assert round(v, 4) == 6.0342 assert round(v_haug, 4) == 6.0508 assert round(v_mc, 4) == 6.0587
def test_EquityChooserOptionDerivicom(): """http://derivicom.com/support/finoptionsxl/index.html?complex_chooser.htm """ valuation_date = Date(1, 1, 2007) chooseDate = Date(1, 2, 2007) call_expiry_date = Date(1, 4, 2007) put_expiry_date = Date(1, 5, 2007) call_strike = 40.0 put_strike = 35.0 stock_price = 38.0 volatility = 0.20 interest_rate = 0.08 dividend_yield = 0.0625 model = BlackScholes(volatility) discount_curve = DiscountCurveFlat(valuation_date, interest_rate) dividend_curve = DiscountCurveFlat(valuation_date, dividend_yield) chooserOption = EquityChooserOption(chooseDate, call_expiry_date, put_expiry_date, call_strike, put_strike) v = chooserOption.value(valuation_date, stock_price, discount_curve, dividend_curve, model) v_mc = chooserOption.value_mc(valuation_date, stock_price, discount_curve, dividend_curve, model, 20000) v_derivicom = 1.0989 assert round(v, 4) == 1.1052 assert round(v_derivicom, 4) == 1.0989 assert round(v_mc, 4) == 1.1095
def test_vega_theta(): # 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) strike_fx_rate = 1.6 call_option = FXVanillaOption(expiry_date, strike_fx_rate, "EURUSD", OptionTypes.EUROPEAN_CALL, 1000000, "USD") vega = call_option.vega(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, model) assert round(vega, 4) == 0.3518 theta = call_option.theta(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, model) assert round(theta, 4) == -0.0504
def test_value_mc(): # 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 = 100000 strike_fx_rate = 1.6 call_option = FXVanillaOption(expiry_date, strike_fx_rate, "EURUSD", OptionTypes.EUROPEAN_CALL, 1000000, "USD") value_mc = call_option.value_mc(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, model, num_paths) assert round(value_mc, 4) == 0.0429 put_option = FXVanillaOption(expiry_date, strike_fx_rate, "EURUSD", OptionTypes.EUROPEAN_PUT, 1000000, "USD") value_mc = put_option.value_mc(valuation_date, spot_fx_rate, dom_discount_curve, for_discount_curve, model, num_paths) assert round(value_mc, 4) == 0.0582
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)
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
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_BBGOneTouchOption(): # 1YR ONETOUCH ON EURUSD valuation_date = Date(3, 12, 2021) expiry_date = Date(5, 12, 2022) barrier_level = 1.1865 # THIS IS NUMBER OF DOLLARS PER EURO spot_fx_rate = 1.1300 # EURUSD volatility = 0.06075 model = BlackScholes(volatility) forRate = 0.00593 # EUR domRate = -0.00414 # USD num_paths = 50000 num_steps_per_year = 252 domCurve = DiscountCurveFlat(valuation_date, domRate) forCurve = DiscountCurveFlat(valuation_date, forRate) payment_size = 1000000 # EUR optionType = TouchOptionTypes.UP_AND_IN_CASH_AT_EXPIRY option = FXOneTouchOption(expiry_date, optionType, barrier_level, payment_size) v = option.value(valuation_date, spot_fx_rate, domCurve, forCurve, model) v_mc = option.value_mc(valuation_date, spot_fx_rate, domCurve, forCurve, model, num_steps_per_year, num_paths) d = option.delta(valuation_date, spot_fx_rate, domCurve, forCurve, model) g = option.gamma(valuation_date, spot_fx_rate, domCurve, forCurve, model) v = option.vega(valuation_date, spot_fx_rate, domCurve, forCurve, model) # I SHOULD GET 49.4934% OR 494,934 in EUR # VEGA IS 68,777.26 # GAMMA IS 916,285 # DELTA IS -9560266 print(optionType) print("Value:", v) print("Value MC:", v_mc) print("Delta: ", d) print("Gamma:", g) print("Vega:", v)
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_black_scholes(): v = amOption.value(valuation_date, stock_price, discount_curve, dividend_curve, modelTree) assert round(v, 4) == 6.8391 modelApprox = BlackScholes(volatility, BlackScholesTypes.BARONE_ADESI) v = amOption.value(valuation_date, stock_price, discount_curve, dividend_curve, modelApprox) assert round(v, 4) == 6.8277 v = ameuOption.value(valuation_date, stock_price, discount_curve, dividend_curve, modelTree) assert round(v, 4) == 6.7510 v = euOption.value(valuation_date, stock_price, discount_curve, dividend_curve, modelTree) assert round(v, 4) == 6.7493
def test_EquityCliquetOption(): start_date = Date(1, 1, 2014) final_expiry_date = Date(1, 1, 2017) freq_type = FrequencyTypes.QUARTERLY option_type = OptionTypes.EUROPEAN_CALL cliquetOption = EquityCliquetOption(start_date, final_expiry_date, option_type, freq_type) valuation_date = Date(1, 1, 2015) stock_price = 100.0 volatility = 0.20 interest_rate = 0.05 dividend_yield = 0.02 model = BlackScholes(volatility) discount_curve = DiscountCurveFlat(valuation_date, interest_rate) dividend_curve = DiscountCurveFlat(valuation_date, dividend_yield) v = cliquetOption.value(valuation_date, stock_price, discount_curve, dividend_curve, model) assert round(v, 4) == 34.5287
def test_EquityCliquetOption(): start_date = Date(1, 1, 2014) final_expiry_date = Date(1, 1, 2017) freq_type = FrequencyTypes.QUARTERLY option_type = FinOptionTypes.EUROPEAN_CALL cliquetOption = EquityCliquetOption(start_date, final_expiry_date, option_type, freq_type) valuation_date = Date(1, 1, 2015) stock_price = 100.0 volatility = 0.20 interest_rate = 0.05 dividend_yield = 0.02 model = BlackScholes(volatility) discount_curve = DiscountCurveFlat(valuation_date, interest_rate) dividend_curve = DiscountCurveFlat(valuation_date, dividend_yield) v = cliquetOption.value(valuation_date, stock_price, discount_curve, dividend_curve, model) testCases.header("LABEL", "VALUE") testCases.print("FINANCEPY", v)
def testEquityAmericanOption(): valuation_date = Date(1, 1, 2016) expiry_date = Date(1, 1, 2017) stock_price = 50.0 interest_rate = 0.06 dividend_yield = 0.04 volatility = 0.40 strike_price = 50.0 discount_curve = DiscountCurveFlat(valuation_date, interest_rate) dividend_curve = DiscountCurveFlat(valuation_date, dividend_yield) testCases.banner("================== EUROPEAN PUT =======================") put_option = EquityAmericanOption(expiry_date, strike_price, FinOptionTypes.EUROPEAN_PUT) model = BlackScholes(volatility, BlackScholesTypes.CRR_TREE, 100) value = put_option.value(valuation_date, stock_price, discount_curve, dividend_curve, model) delta = put_option.delta(valuation_date, stock_price, discount_curve, dividend_curve, model) gamma = put_option.gamma(valuation_date, stock_price, discount_curve, dividend_curve, model) theta = put_option.theta(valuation_date, stock_price, discount_curve, dividend_curve, model) testCases.header("OPTION_TYPE", "VALUE", "DELTA", "GAMMA", "THETA") testCases.print("EUROPEAN_PUT_BS", value, delta, gamma, theta) option = EquityAmericanOption(expiry_date, strike_price, FinOptionTypes.EUROPEAN_PUT) testCases.header("OPTION_TYPE", "NUMSTEPS", "VALUE DELTA GAMMA THETA", "TIME") num_steps_list = [100, 200, 500, 1000, 2000] for num_steps in num_steps_list: model = BlackScholes(volatility, BlackScholesTypes.CRR_TREE, num_steps) start = time.time() results = option.value(valuation_date, stock_price, discount_curve, dividend_curve, model) end = time.time() duration = end - start testCases.print("EUROPEAN_PUT_TREE", num_steps, results, duration) testCases.banner("================== AMERICAN PUT =======================") option = EquityAmericanOption(expiry_date, strike_price, FinOptionTypes.AMERICAN_PUT) testCases.header("OPTION_TYPE", "NUMSTEPS", "VALUE DELTA GAMMA THETA", "TIME") for num_steps in num_steps_list: model = BlackScholes(volatility, BlackScholesTypes.CRR_TREE, num_steps) start = time.time() results = option.value(valuation_date, stock_price, discount_curve, dividend_curve, model) end = time.time() duration = end - start testCases.print("AMERICAN_PUT", num_steps, results, duration) testCases.banner( "================== EUROPEAN CALL =======================") call_option = EquityAmericanOption(expiry_date, strike_price, FinOptionTypes.EUROPEAN_CALL) value = call_option.value(valuation_date, stock_price, discount_curve, dividend_curve, model) delta = call_option.delta(valuation_date, stock_price, discount_curve, dividend_curve, model) gamma = call_option.gamma(valuation_date, stock_price, discount_curve, dividend_curve, model) theta = call_option.theta(valuation_date, stock_price, discount_curve, dividend_curve, model) testCases.header("OPTION_TYPE", "VALUE", "DELTA", "GAMMA", "THETA") testCases.print("EUROPEAN_CALL_BS", value, delta, gamma, theta) option = EquityAmericanOption(expiry_date, strike_price, FinOptionTypes.EUROPEAN_CALL) testCases.header("OPTION_TYPE", "NUMSTEPS", "VALUE DELTA GAMMA THETA", "TIME") for num_steps in num_steps_list: model = BlackScholes(volatility, BlackScholesTypes.CRR_TREE, num_steps) start = time.time() results = option.value(valuation_date, stock_price, discount_curve, dividend_curve, model) end = time.time() duration = end - start testCases.print("EUROPEAN_CALL_TREE", num_steps, results, duration) testCases.banner( "================== AMERICAN CALL =======================") testCases.header("OPTION_TYPE", "NUMSTEPS", "VALUE DELTA GAMMA THETA", "TIME") option = EquityAmericanOption(expiry_date, strike_price, FinOptionTypes.AMERICAN_CALL) for num_steps in num_steps_list: model = BlackScholes(volatility, BlackScholesTypes.CRR_TREE, num_steps) start = time.time() results = option.value(valuation_date, stock_price, discount_curve, dividend_curve, model) end = time.time() duration = end - start testCases.print("AMERICAN_CALL", num_steps, results, duration)
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)
def test_EquityDigitalOption(): underlying_type = FinDigitalOptionTypes.CASH_OR_NOTHING valuation_date = Date(1, 1, 2015) expiry_date = Date(1, 1, 2016) stock_price = 100.0 volatility = 0.30 interest_rate = 0.05 dividend_yield = 0.01 discount_curve = DiscountCurveFlat(valuation_date, interest_rate) dividend_curve = DiscountCurveFlat(valuation_date, dividend_yield) model = BlackScholes(volatility) import time call_option_values = [] call_option_valuesMC = [] num_paths_list = [ 10000, 20000, 40000, 80000, 160000, 320000, 640000, 1280000, 2560000 ] testCases.header("NumLoops", "ValueBS", "ValueMC", "TIME") for num_paths in num_paths_list: call_option = EquityDigitalOption(expiry_date, 100.0, OptionTypes.EUROPEAN_CALL, underlying_type) value = call_option.value(valuation_date, stock_price, discount_curve, dividend_curve, model) start = time.time() value_mc = call_option.value_mc(valuation_date, stock_price, discount_curve, dividend_curve, model, num_paths) end = time.time() duration = end - start testCases.print(num_paths, value, value_mc, duration) call_option_values.append(value) call_option_valuesMC.append(value_mc) # plt.figure(figsize=(10,8)) # plt.plot(num_paths_list, call_option_values, color = 'b', label="Call Option") # plt.plot(num_paths_list, call_option_valuesMC, color = 'r', label = "Call Option MC") # plt.xlabel("Num Loops") # plt.legend(loc='best') ########################################################################## stock_prices = range(50, 150, 50) call_option_values = [] call_optionDeltas = [] call_optionVegas = [] call_optionThetas = [] for stock_price in stock_prices: call_option = EquityDigitalOption(expiry_date, 100.0, OptionTypes.EUROPEAN_CALL, underlying_type) value = call_option.value(valuation_date, stock_price, discount_curve, dividend_curve, model) delta = call_option.delta(valuation_date, stock_price, discount_curve, dividend_curve, model) vega = call_option.vega(valuation_date, stock_price, discount_curve, dividend_curve, model) theta = call_option.theta(valuation_date, stock_price, discount_curve, dividend_curve, model) call_option_values.append(value) call_optionDeltas.append(delta) call_optionVegas.append(vega) call_optionThetas.append(theta) put_option_values = [] put_optionDeltas = [] put_optionVegas = [] put_optionThetas = [] for stock_price in stock_prices: put_option = EquityDigitalOption(expiry_date, 100.0, OptionTypes.EUROPEAN_PUT, underlying_type) value = put_option.value(valuation_date, stock_price, discount_curve, dividend_curve, model) delta = put_option.delta(valuation_date, stock_price, discount_curve, dividend_curve, model) vega = put_option.vega(valuation_date, stock_price, discount_curve, dividend_curve, model) theta = put_option.theta(valuation_date, stock_price, discount_curve, dividend_curve, model) put_option_values.append(value) put_optionDeltas.append(delta) put_optionVegas.append(vega) put_optionThetas.append(theta)
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 testConvergence(): valuation_date = Date(1, 1, 2014) startAveragingDate = Date(1, 6, 2014) expiry_date = Date(1, 1, 2015) stock_price = 100.0 volatility = 0.20 interest_rate = 0.30 dividend_yield = 0.10 num_observations = 120 # daily as we have a half year accruedAverage = None K = 100 seed = 1976 model = BlackScholes(volatility) discount_curve = DiscountCurveFlat(valuation_date, interest_rate) dividend_curve = DiscountCurveFlat(valuation_date, dividend_yield) asianOption = EquityAsianOption(startAveragingDate, expiry_date, K, OptionTypes.EUROPEAN_CALL, num_observations) testCases.header( "K", "Geometric", "Turnbull_Wakeman", "Curran", "FastMC", "FastMC_CV") valuesTurnbull = [] valuesCurran = [] valuesGeometric = [] valuesMC_fast = [] valuesMC_CV = [] num_paths_list = [5000] for num_paths in num_paths_list: accruedAverage = stock_price * 1.1 value_mc_fast = asianOption._value_mc_fast(valuation_date, stock_price, discount_curve, dividend_curve, model, num_paths, seed, accruedAverage) value_mc_CV = asianOption.value_mc(valuation_date, stock_price, discount_curve, dividend_curve, model, num_paths, seed, accruedAverage) valueGeometric = asianOption.value(valuation_date, stock_price, discount_curve, dividend_curve, model, AsianOptionValuationMethods.GEOMETRIC, accruedAverage) valueTurnbullWakeman = asianOption.value(valuation_date, stock_price, discount_curve, dividend_curve, model, AsianOptionValuationMethods.TURNBULL_WAKEMAN, accruedAverage) valueCurran = asianOption.value(valuation_date, stock_price, discount_curve, dividend_curve, model, AsianOptionValuationMethods.CURRAN, accruedAverage) valuesGeometric.append(valueGeometric) valuesTurnbull.append(valueTurnbullWakeman) valuesCurran.append(valueCurran) valuesMC_fast.append(value_mc_fast) valuesMC_CV.append(value_mc_CV) testCases.print( num_paths, valueGeometric, valueTurnbullWakeman, valueCurran, value_mc_fast, value_mc_CV)
def testMCTimings(): valuation_date = Date(1, 1, 2014) startAveragingDate = Date(1, 6, 2014) expiry_date = Date(1, 1, 2015) stock_price = 100.0 volatility = 0.20 interest_rate = 0.30 dividend_yield = 0.10 num_observations = 120 # daily as we have a half year accruedAverage = None K = 100 seed = 1976 model = BlackScholes(volatility) discount_curve = DiscountCurveFlat(valuation_date, interest_rate) dividend_curve = DiscountCurveFlat(valuation_date, dividend_yield) asianOption = EquityAsianOption(startAveragingDate, expiry_date, K, OptionTypes.EUROPEAN_CALL, num_observations) testCases.header( "NUMPATHS", "VALUE", "TIME", "VALUE_MC", "TIME", "VALUE_MC_CV", "TIME") valuesMC = [] valuesMC_fast = [] valuesMC_fast_CV = [] tvaluesMC = [] tvaluesMC_fast = [] tvaluesMC_fast_CV = [] num_paths_list = [5000] for num_paths in num_paths_list: accruedAverage = stock_price * 1.1 start = time.time() value_mc = asianOption.value_mc(valuation_date, stock_price, discount_curve, dividend_curve, model, num_paths, seed, accruedAverage) end = time.time() t_MC = end - start start = time.time() value_mc_fast = asianOption._value_mc_fast(valuation_date, stock_price, discount_curve, dividend_curve, model, num_paths, seed, accruedAverage) end = time.time() t_MC_fast = end - start start = time.time() value_mc_fast_CV = asianOption.value_mc(valuation_date, stock_price, discount_curve, dividend_curve, model, num_paths, seed, accruedAverage) end = time.time() t_MC_fast_CV = end - start valuesMC.append(value_mc) valuesMC_fast.append(value_mc_fast) valuesMC_fast_CV.append(value_mc_fast_CV) tvaluesMC.append(t_MC) tvaluesMC_fast.append(t_MC_fast) tvaluesMC_fast_CV.append(t_MC_fast_CV) testCases.print( num_paths, value_mc, t_MC, value_mc_fast, t_MC_fast, value_mc_fast_CV, t_MC_fast_CV)
def testTimeEvolution(): startAveragingDate = Date(1, 1, 2015) expiry_date = Date(1, 1, 2016) stock_price = 100.0 volatility = 0.20 interest_rate = 0.30 dividend_yield = 0.10 num_observations = 100 # weekly as we have a year accruedAverage = None K = 100 seed = 1976 model = BlackScholes(volatility) asianOption = EquityAsianOption(startAveragingDate, expiry_date, K, OptionTypes.EUROPEAN_CALL, num_observations) testCases.header( "Date", "Geometric", "Turnbull_Wakeman", "Curran", "FastMC", "FastMC_CV") valuesTurnbull = [] valuesCurran = [] valuesGeometric = [] valuesMC_fast = [] valuesMC_CV = [] valuation_dates = [] valuation_dates.append(Date(1, 4, 2014)) valuation_dates.append(Date(1, 6, 2014)) valuation_dates.append(Date(1, 8, 2014)) valuation_dates.append(Date(1, 2, 2015)) valuation_dates.append(Date(1, 4, 2015)) valuation_dates.append(Date(1, 6, 2015)) valuation_dates.append(Date(1, 8, 2015)) num_paths = 10000 for valuation_date in valuation_dates: accruedAverage = stock_price * 0.9 discount_curve = DiscountCurveFlat(valuation_date, interest_rate) dividend_curve = DiscountCurveFlat(valuation_date, dividend_yield) value_mc_fast = asianOption._value_mc_fast(valuation_date, stock_price, discount_curve, dividend_curve, model, num_paths, seed, accruedAverage) value_mc_CV = asianOption.value_mc(valuation_date, stock_price, discount_curve, dividend_curve, model, num_paths, seed, accruedAverage) valueGeometric = asianOption.value(valuation_date, stock_price, discount_curve, dividend_curve, model, AsianOptionValuationMethods.GEOMETRIC, accruedAverage) valueTurnbullWakeman = asianOption.value(valuation_date, stock_price, discount_curve, dividend_curve, model, AsianOptionValuationMethods.TURNBULL_WAKEMAN, accruedAverage) valueCurran = asianOption.value(valuation_date, stock_price, discount_curve, dividend_curve, model, AsianOptionValuationMethods.CURRAN, accruedAverage) valuesGeometric.append(valueGeometric) valuesTurnbull.append(valueTurnbullWakeman) valuesCurran.append(valueCurran) valuesMC_fast.append(value_mc_fast) valuesMC_CV.append(value_mc_CV) testCases.print( str(valuation_date), valueGeometric, valueTurnbullWakeman, valueCurran, value_mc_fast, value_mc_CV)
def test_FinBinomialTree(): stock_price = 50.0 risk_free_rate = 0.06 dividend_yield = 0.04 volatility = 0.40 valuation_date = Date(1, 1, 2016) expiry_date = Date(1, 1, 2017) model = BlackScholes(volatility) discount_curve = DiscountCurveFlat(valuation_date, risk_free_rate) dividend_curve = DiscountCurveFlat(valuation_date, dividend_yield) num_steps_list = [100, 500, 1000, 2000, 5000] strike_price = 50.0 testCases.banner("================== EUROPEAN PUT =======================") put_option = EquityVanillaOption(expiry_date, strike_price, OptionTypes.EUROPEAN_PUT) value = put_option.value(valuation_date, stock_price, discount_curve, dividend_curve, model) delta = put_option.delta(valuation_date, stock_price, discount_curve, dividend_curve, model) gamma = put_option.gamma(valuation_date, stock_price, discount_curve, dividend_curve, model) theta = put_option.theta(valuation_date, stock_price, discount_curve, dividend_curve, model) testCases.header("BS Value", "BS Delta", "BS Gamma", "BS Theta") testCases.print(value, delta, gamma, theta) payoff = EquityTreePayoffTypes.VANILLA_OPTION exercise = EquityTreeExerciseTypes.EUROPEAN params = np.array([-1, strike_price]) testCases.header("NumSteps", "Results", "TIME") for num_steps in num_steps_list: start = time.time() tree = EquityBinomialTree() results = tree.value(stock_price, discount_curve, dividend_curve, volatility, num_steps, valuation_date, payoff, expiry_date, payoff, exercise, params) end = time.time() duration = end - start testCases.print(num_steps, results, duration) testCases.banner("================== AMERICAN PUT =======================") payoff = EquityTreePayoffTypes.VANILLA_OPTION exercise = EquityTreeExerciseTypes.AMERICAN params = np.array([-1, strike_price]) testCases.header("NumSteps", "Results", "TIME") for num_steps in num_steps_list: start = time.time() tree = EquityBinomialTree() results = tree.value(stock_price, discount_curve, dividend_curve, volatility, num_steps, valuation_date, payoff, expiry_date, payoff, exercise, params) end = time.time() duration = end - start testCases.print(num_steps, results, duration) testCases.banner( "================== EUROPEAN CALL =======================") call_option = EquityVanillaOption(expiry_date, strike_price, OptionTypes.EUROPEAN_CALL) value = call_option.value(valuation_date, stock_price, discount_curve, dividend_curve, model) delta = call_option.delta(valuation_date, stock_price, discount_curve, dividend_curve, model) gamma = call_option.gamma(valuation_date, stock_price, discount_curve, dividend_curve, model) theta = call_option.theta(valuation_date, stock_price, discount_curve, dividend_curve, model) testCases.header("BS Value", "BS Delta", "BS Gamma", "BS Theta") testCases.print(value, delta, gamma, theta) payoff = EquityTreePayoffTypes.VANILLA_OPTION exercise = EquityTreeExerciseTypes.EUROPEAN params = np.array([1.0, strike_price]) testCases.header("NumSteps", "Results", "TIME") for num_steps in num_steps_list: start = time.time() tree = EquityBinomialTree() results = tree.value(stock_price, discount_curve, dividend_curve, volatility, num_steps, valuation_date, payoff, expiry_date, payoff, exercise, params) end = time.time() duration = end - start testCases.print(num_steps, results, duration) testCases.banner( "================== AMERICAN CALL =======================") payoff = EquityTreePayoffTypes.VANILLA_OPTION exercise = EquityTreeExerciseTypes.AMERICAN params = np.array([1.0, strike_price]) testCases.header("NumSteps", "Results", "TIME") for num_steps in num_steps_list: start = time.time() tree = EquityBinomialTree() results = tree.value(stock_price, discount_curve, dividend_curve, volatility, num_steps, valuation_date, payoff, expiry_date, payoff, exercise, params) end = time.time() duration = end - start testCases.print(num_steps, results, duration)
volatility = 0.20 interest_rate = 0.05 dividend_yield = 0.02 stock_price = 80 B = 110.0 K = 100.0 option_type = EquityBarrierTypes.DOWN_AND_OUT_CALL drift = interest_rate - dividend_yield scheme = FinGBMNumericalScheme.NORMAL process_type = ProcessTypes.GBM discount_curve = DiscountCurveFlat(valuation_date, interest_rate) dividend_curve = DiscountCurveFlat(valuation_date, dividend_yield) model = BlackScholes(volatility) num_observations_per_year = 100 def test_down_and_out_call(): option_type = EquityBarrierTypes.DOWN_AND_OUT_CALL option = EquityBarrierOption( expiry_date, K, option_type, B, num_observations_per_year) value = option.value( valuation_date, stock_price, discount_curve, dividend_curve, model)
def test_EquityOneTouchOption(): # Examples Haug Page 180 Table 4-22 # Agreement not exact at t is not exactly 0.50 valuation_date = Date(1, 1, 2016) expiry_date = Date(2, 7, 2016) interest_rate = 0.10 volatility = 0.20 barrier_level = 100.0 # H model = BlackScholes(volatility) dividend_yield = 0.03 num_paths = 10000 num_steps_per_year = 252 discount_curve = DiscountCurveFlat(valuation_date, interest_rate) dividend_curve = DiscountCurveFlat(valuation_date, dividend_yield) stock_price = 105.0 payment_size = 15.0 testCases.header("================================= CASH ONLY") downTypes = [ FinTouchOptionPayoffTypes.DOWN_AND_IN_CASH_AT_HIT, FinTouchOptionPayoffTypes.DOWN_AND_IN_CASH_AT_EXPIRY, FinTouchOptionPayoffTypes.DOWN_AND_OUT_CASH_OR_NOTHING ] testCases.header("TYPE", "VALUE", "VALUE_MC") for downType in downTypes: option = EquityOneTouchOption(expiry_date, downType, barrier_level, payment_size) v = option.value(valuation_date, stock_price, discount_curve, dividend_curve, model) v_mc = option.value_mc(valuation_date, stock_price, discount_curve, dividend_curve, model, num_steps_per_year, num_paths) testCases.print("%60s " % downType, "%9.5f" % v, "%9.5f" % v_mc) stock_price = 95.0 payment_size = 15.0 upTypes = [ FinTouchOptionPayoffTypes.UP_AND_IN_CASH_AT_HIT, FinTouchOptionPayoffTypes.UP_AND_IN_CASH_AT_EXPIRY, FinTouchOptionPayoffTypes.UP_AND_OUT_CASH_OR_NOTHING ] testCases.header("TYPE", "VALUE", "VALUE_MC") for upType in upTypes: option = EquityOneTouchOption(expiry_date, upType, barrier_level, payment_size) v = option.value(valuation_date, stock_price, discount_curve, dividend_curve, model) v_mc = option.value_mc(valuation_date, stock_price, discount_curve, dividend_curve, model, num_steps_per_year, num_paths) testCases.print("%60s " % upType, "%9.5f" % v, "%9.5f" % v_mc) ########################################################################### stock_price = 105.0 testCases.banner("================= ASSET ONLY") downTypes = [ FinTouchOptionPayoffTypes.DOWN_AND_IN_ASSET_AT_HIT, FinTouchOptionPayoffTypes.DOWN_AND_IN_ASSET_AT_EXPIRY, FinTouchOptionPayoffTypes.DOWN_AND_OUT_ASSET_OR_NOTHING ] testCases.header("TYPE", "VALUE", "VALUE_MC") for downType in downTypes: option = EquityOneTouchOption(expiry_date, downType, barrier_level) v = option.value(valuation_date, stock_price, discount_curve, dividend_curve, model) v_mc = option.value_mc(valuation_date, stock_price, discount_curve, dividend_curve, model, num_steps_per_year, num_paths) testCases.print("%60s " % downType, "%9.5f" % v, "%9.5f" % v_mc) stock_price = 95.0 upTypes = [ FinTouchOptionPayoffTypes.UP_AND_IN_ASSET_AT_HIT, FinTouchOptionPayoffTypes.UP_AND_IN_ASSET_AT_EXPIRY, FinTouchOptionPayoffTypes.UP_AND_OUT_ASSET_OR_NOTHING ] for upType in upTypes: option = EquityOneTouchOption(expiry_date, upType, barrier_level) v = option.value(valuation_date, stock_price, discount_curve, dividend_curve, model) v_mc = option.value_mc(valuation_date, stock_price, discount_curve, dividend_curve, model, num_steps_per_year, num_paths) testCases.print("%60s " % upType, "%9.5f" % v, "%9.5f" % v_mc)
def test_EquityVanillaOptionFactored(): valuation_date = Date(1, 1, 2015) expiry_date = Date(1, 7, 2015) stock_price = 100 volatility = 0.30 interest_rate = 0.05 dividend_yield = 0.01 model = BlackScholes(volatility) discount_curve = DiscountCurveFlat(valuation_date, interest_rate) num_paths_list = [10000, 20000, 40000, 80000, 160000, 320000] testCases.header("NUMPATHS", "VALUE_BS", "VALUE_MC", "TIME") for num_paths in num_paths_list: call_option = EquityVanillaOptionOLD( expiry_date, 100.0, FinOptionTypes.EUROPEAN_CALL) value = call_option.value(valuation_date, stock_price, discount_curve, dividend_yield, model) start = time.time() value_mc = call_option.value_mc(valuation_date, stock_price, discount_curve, dividend_yield, model, num_paths) end = time.time() duration = end - start testCases.print(num_paths, value, value_mc, duration) ############################################################################### stock_prices = range(80, 120, 10) num_paths = 100000 testCases.header("NUMPATHS", "CALL_VALUE_BS", "CALL_VALUE_MC", "CALL_VALUE_MC_SOBOL", "TIME") useSobol = True for stock_price in stock_prices: call_option = EquityVanillaOptionOLD(expiry_date, 100.0, FinOptionTypes.EUROPEAN_CALL) value = call_option.value(valuation_date, stock_price, discount_curve, dividend_yield, model) start = time.time() useSobol = False value_mc1 = call_option.value_mc(valuation_date, stock_price, discount_curve, dividend_yield, model, num_paths, useSobol) useSobol = True value_mc2 = call_option.value_mc(valuation_date, stock_price, discount_curve, dividend_yield, model, num_paths, useSobol) end = time.time() duration = end - start testCases.print(num_paths, value, value_mc1, value_mc2, duration) ############################################################################### stock_prices = range(80, 120, 10) num_paths = 100000 testCases.header("NUMPATHS", "PUT_VALUE_BS", "PUT_VALUE_MC", "PUT_VALUE_MC_SOBOL", "TIME") for stock_price in stock_prices: put_option = EquityVanillaOptionOLD(expiry_date, 100.0, FinOptionTypes.EUROPEAN_PUT) value = put_option.value(valuation_date, stock_price, discount_curve, dividend_yield, model) start = time.time() useSobol = False value_mc1 = put_option.value_mc(valuation_date, stock_price, discount_curve, dividend_yield, model, num_paths, useSobol) useSobol = True value_mc2 = put_option.value_mc(valuation_date, stock_price, discount_curve, dividend_yield, model, num_paths, useSobol) end = time.time() duration = end - start testCases.print(num_paths, value, value_mc1, value_mc2, duration) ############################################################################### stock_prices = range(80, 120, 10) testCases.header("STOCK PRICE", "CALL_VALUE_BS", "CALL_DELTA_BS", "CALL_VEGA_BS", "CALL_THETA_BS", "CALL_RHO_BS") for stock_price in stock_prices: call_option = EquityVanillaOptionOLD(expiry_date, 100.0, FinOptionTypes.EUROPEAN_CALL) value = call_option.value(valuation_date, stock_price, discount_curve, dividend_yield, model) delta = call_option.delta(valuation_date, stock_price, discount_curve, dividend_yield, model) vega = call_option.vega(valuation_date, stock_price, discount_curve, dividend_yield, model) theta = call_option.theta(valuation_date, stock_price, discount_curve, dividend_yield, model) rho = call_option.rho(valuation_date, stock_price, discount_curve, dividend_yield, model) testCases.print(stock_price, value, delta, vega, theta, rho) ########################################################################### testCases.header("STOCK PRICE", "PUT_VALUE_BS", "PUT_DELTA_BS", "PUT_VEGA_BS", "PUT_THETA_BS", "PUT_RHO_BS") for stock_price in stock_prices: put_option = EquityVanillaOptionOLD(expiry_date, 100.0, FinOptionTypes.EUROPEAN_PUT) value = put_option.value(valuation_date, stock_price, discount_curve, dividend_yield, model) delta = put_option.delta(valuation_date, stock_price, discount_curve, dividend_yield, model) vega = put_option.vega(valuation_date, stock_price, discount_curve, dividend_yield, model) theta = put_option.theta(valuation_date, stock_price, discount_curve, dividend_yield, model) rho = put_option.rho(valuation_date, stock_price, discount_curve, dividend_yield, model) testCases.print(stock_price, value, delta, vega, theta, rho) ############################################################################### testCases.header("STOCK PRICE", "VALUE_BS", "VOL_IN", "IMPLD_VOL") stock_prices = range(60, 150, 10) for stock_price in stock_prices: call_option = EquityVanillaOptionOLD( expiry_date, 100.0, FinOptionTypes.EUROPEAN_CALL) value = call_option.value( valuation_date, stock_price, discount_curve, dividend_yield, model) impliedVol = call_option.implied_volatility( valuation_date, stock_price, discount_curve, dividend_yield, value) testCases.print(stock_price, value, volatility, impliedVol)
def testImpliedVolatility_NEW(): valuation_date = Date(1, 1, 2015) stock_price = 100.0 interest_rate = 0.05 dividend_yield = 0.03 discount_curve = DiscountCurveFlat(valuation_date, interest_rate) dividend_curve = DiscountCurveFlat(valuation_date, dividend_yield) strikes = np.linspace(50, 150, 11) timesToExpiry = [0.003, 0.01, 0.1, 0.5, 1.0, 2.0, 5.0] sigmas = np.arange(1, 100, 5) / 100.0 option_types = [FinOptionTypes.EUROPEAN_CALL, FinOptionTypes.EUROPEAN_PUT] testCases.header("OPT_TYPE", "TEXP", "STOCK_PRICE", "STRIKE", "INTRINSIC", "VALUE", "INPUT_VOL", "IMPLIED_VOL") tol = 1e-5 numTests = 0 numFails = 0 for vol in sigmas: model = BlackScholes(vol) for time_to_expiry in timesToExpiry: expiry_date = valuation_date.add_years(time_to_expiry) for strike in strikes: for option_type in option_types: option = EquityVanillaOption(expiry_date, strike, option_type) value = option.value(valuation_date, stock_price, discount_curve, dividend_curve, model) intrinsic = option.intrinsic(valuation_date, stock_price, discount_curve, dividend_curve) # I remove the cases where the time value is zero # This is arbitrary but 1e-10 seems good enough to me impliedVol = -999 if value - intrinsic > 1e-10: impliedVol = option.implied_volatility( valuation_date, stock_price, discount_curve, dividend_curve, value) numTests += 1 errVol = np.abs(impliedVol - vol) if errVol > tol: testCases.print(option_type, time_to_expiry, stock_price, strike, intrinsic, value, vol, impliedVol) # These fails include ones due to the zero time value numFails += 1 testCases.print(option_type, time_to_expiry, stock_price, strike, stock_price, value, vol, impliedVol) assert numFails == 694, "Num Fails has changed."
def test_FinNumbaNumbaParallel(useSobol): valuation_date = Date(1, 1, 2015) expiry_date = Date(1, 7, 2015) stock_price = 100 volatility = 0.30 interest_rate = 0.05 dividend_yield = 0.01 seed = 2021 model = BlackScholes(volatility) discount_curve = DiscountCurveFlat(valuation_date, interest_rate) useSobolInt = int(useSobol) testCases.header("NUMPATHS", "VALUE_BS", "VALUE_MC", "TIME") call_option = EquityVanillaOption(expiry_date, 100.0, OptionTypes.EUROPEAN_CALL) value = call_option.value(valuation_date, stock_price, discount_curve, dividend_yield, model) num_points = 20 v_exact = [value] * num_points num_paths_list = np.arange(1, num_points+1, 1) * 1000000 NUMBA_ONLY_v = [] NUMBA_ONLY_t = [] print("NUMBA ONLY") for num_paths in num_paths_list: start = time.time() value_mc = call_option.value_mc_numba_only(valuation_date, stock_price, discount_curve, dividend_yield, model, num_paths, seed, useSobolInt) end = time.time() duration = end - start print("%10d %9.5f %9.5f %9.6f" % (num_paths, value, value_mc, duration)) NUMBA_ONLY_v.append(value_mc) NUMBA_ONLY_t.append(duration) NUMBA_PARALLEL_v = [] NUMBA_PARALLEL_t = [] print("NUMBA PARALLEL") for num_paths in num_paths_list: start = time.time() value_mc = call_option.value_mc_numba_parallel(valuation_date, stock_price, discount_curve, dividend_yield, model, num_paths, seed, useSobolInt) end = time.time() duration = end - start print("%10d %9.5f %9.5f %9.6f" % (num_paths, value, value_mc, duration)) NUMBA_PARALLEL_v.append(value_mc) NUMBA_PARALLEL_t.append(duration) ########################################################################### import matplotlib.pyplot as plt if useSobol: title = "SOBOL: NUMBA VS NUMBA + PARALLEL" else: title = "PSEUDORANDOM: NUMBA VS NUMBA + PARALLEL" plt.figure(figsize=(8, 6)) plt.plot(num_paths_list, NUMBA_ONLY_t, 'o-', label="NUMBA ONLY") plt.plot(num_paths_list, NUMBA_PARALLEL_t, 'o-', label="NUMBA PARALLEL") plt.xlabel("Number of Paths") plt.ylabel("Wall Time (s)") plt.legend() plt.title(title) plt.figure(figsize=(8, 6)) plt.plot(num_paths_list, v_exact, label="EXACT") plt.plot(num_paths_list, NUMBA_ONLY_v, 'o-', label="NUMBA ONLY") plt.plot(num_paths_list, NUMBA_PARALLEL_v, 'o-', label="NUMBA PARALLEL") plt.xlabel("Number of Paths") plt.ylabel("Option Value") plt.legend() plt.title(title)