def test_FinEquityForward(): valueDate = FinDate(13, 2, 2018) expiryDate = valueDate.addMonths(12) stockPrice = 130.0 forwardPrice = 125.0 # Locked discountRate = 0.05 dividendRate = 0.02 ########################################################################### expiryDate = valueDate.addMonths(12) notional = 100.0 discountCurve = FinDiscountCurveFlat(valueDate, discountRate) dividendCurve = FinDiscountCurveFlat(valueDate, dividendRate) equityForward = FinEquityForward(expiryDate, forwardPrice, notional, FinLongShort.LONG) testCases.header("SPOT FX", "FX FWD", "VALUE_BS") fwdPrice = equityForward.forward(valueDate, stockPrice, discountCurve, dividendCurve) fwdValue = equityForward.value(valueDate, stockPrice, discountCurve, dividendCurve) print(stockPrice, fwdPrice, fwdValue) testCases.print(stockPrice, fwdPrice, fwdValue)
def build_vol_surface(self, value_date): """Builds the implied volatility surface for a particular value date and calculates the benchmark strikes etc. Before we do any sort of interpolation later, we need to build the implied_vol vol surface. Parameters ---------- value_date : str Value date (need to have market data for this date) asset : str Asset name depo_tenor : str Depo tenor to use default - '1M' field : str Market data field to use default - 'close' """ self._value_date = self._market_util.parse_date(value_date) value_fin_date = self._findate(self._value_date) date_index = self._market_df.index == value_date # TODO: add whole rates curve dom_discount_curve = FinDiscountCurveFlat(value_fin_date, self._domCCRate[date_index]) for_discount_curve = FinDiscountCurveFlat(value_fin_date, self._forCCRate[date_index]) self._dom_discount_curve = dom_discount_curve self._for_discount_curve = for_discount_curve self._spot = float(self._spot_history[date_index][0]) # New implementation in FinancePy also uses 10d for interpolation self._fin_fx_vol_surface = FinFXVolSurface( value_fin_date, self._spot, self._asset, self._asset[0:3], dom_discount_curve, for_discount_curve, self._tenors.copy(), self._atm_vols[date_index][0], self._market_strangle25DeltaVols[date_index][0], self._risk_reversal25DeltaVols[date_index][0], self._market_strangle10DeltaVols[date_index][0], self._risk_reversal10DeltaVols[date_index][0], self._alpha, atmMethod=self._atm_method, deltaMethod=self._delta_method, volatilityFunctionType=self._vol_function_type, finSolverType=self._solver)
def test_FinEquityChooserOptionHaug(): ''' Following example in Haug Page 130 ''' valueDate = FinDate(1, 1, 2015) chooseDate = FinDate(2, 4, 2015) callExpiryDate = FinDate(1, 7, 2015) putExpiryDate = FinDate(2, 8, 2015) callStrike = 55.0 putStrike = 48.0 stockPrice = 50.0 volatility = 0.35 interestRate = 0.10 dividendYield = 0.05 model = FinModelBlackScholes(volatility) discountCurve = FinDiscountCurveFlat(valueDate, interestRate) dividendCurve = FinDiscountCurveFlat(valueDate, dividendYield) chooserOption = FinEquityChooserOption(chooseDate, callExpiryDate, putExpiryDate, callStrike, putStrike) v = chooserOption.value(valueDate, stockPrice, discountCurve, dividendCurve, model) v_mc = chooserOption.valueMC(valueDate, stockPrice, discountCurve, dividendCurve, model, 20000) v_haug = 6.0508 testCases.header("", "", "", "", "", "") testCases.print("FINANCEPY", v, "HAUG", v_haug, "MC", v_mc)
def test_FinEquityCliquetOption(): startDate = FinDate(1, 1, 2014) finalExpiryDate = FinDate(1, 1, 2017) freqType = FinFrequencyTypes.QUARTERLY optionType = FinOptionTypes.EUROPEAN_CALL cliquetOption = FinEquityCliquetOption(startDate, finalExpiryDate, optionType, freqType) valueDate = FinDate(1, 1, 2015) stockPrice = 100.0 volatility = 0.20 interestRate = 0.05 dividendYield = 0.02 model = FinModelBlackScholes(volatility) discountCurve = FinDiscountCurveFlat(valueDate, interestRate) dividendCurve = FinDiscountCurveFlat(valueDate, dividendYield) v = cliquetOption.value(valueDate, stockPrice, discountCurve, dividendCurve, model) testCases.header("LABEL", "VALUE") testCases.print("FINANCEPY", v)
def test_FinFXMktVolSurface4(verboseCalibration): # USDJPY Example from Paper by Uwe Wystup using Tables 4 # print("USDJPY EXAMPLE WYSTUP") valueDate = FinDate(20, 1, 2009) forName = "USD" domName = "JPY" forCCRate = 0.003525 # USD domCCRate = 0.0042875 # JPY domDiscountCurve = FinDiscountCurveFlat(valueDate, domCCRate) forDiscountCurve = FinDiscountCurveFlat(valueDate, forCCRate) currencyPair = forName + domName spotFXRate = 90.68 tenors = ['1M'] atmVols = [21.00] marketStrangle25DeltaVols = [0.184] riskReversal25DeltaVols = [-5.30] notionalCurrency = forName atmMethod = FinFXATMMethod.FWD_DELTA_NEUTRAL deltaMethod = FinFXDeltaMethod.SPOT_DELTA_PREM_ADJ fxMarket = FinFXVolSurface(valueDate, spotFXRate, currencyPair, notionalCurrency, domDiscountCurve, forDiscountCurve, tenors, atmVols, marketStrangle25DeltaVols, riskReversal25DeltaVols, atmMethod, deltaMethod) fxMarket.checkCalibration(verboseCalibration)
def test_example(): expiryDate = FinDate(1, 1, 2021) strikePrice = 105.0 optionTypeCall = FinOptionTypes.EUROPEAN_CALL optionTypePut = FinOptionTypes.EUROPEAN_PUT lookbackCall = FinEquityFixedLookbackOption(expiryDate, optionTypeCall, strikePrice) lookbackPut = FinEquityFixedLookbackOption(expiryDate, optionTypePut, strikePrice) valueDate = FinDate(1, 1, 2020) interestRate = 0.10 stockPrice = 100.0 dividendYield = 0.0 stockMinMax = 100.0 discountCurve = FinDiscountCurveFlat(valueDate, interestRate) dividendCurve = FinDiscountCurveFlat(valueDate, dividendYield) volatilities = [0.30] testCases.header("VALUE") for vol in volatilities: v = lookbackCall.value(valueDate, stockPrice, discountCurve, dividendCurve, vol, stockMinMax) testCases.print(v)
def test_FinEquityChooserOptionMatlab(): '''https://fr.mathworks.com/help/fininst/chooserbybls.html ''' valueDate = FinDate(1, 6, 2007) chooseDate = FinDate(31, 8, 2007) callExpiryDate = FinDate(2, 12, 2007) putExpiryDate = FinDate(2, 12, 2007) callStrike = 60.0 putStrike = 60.0 stockPrice = 50.0 volatility = 0.20 interestRate = 0.10 dividendYield = 0.05 model = FinModelBlackScholes(volatility) discountCurve = FinDiscountCurveFlat(valueDate, interestRate) dividendCurve = FinDiscountCurveFlat(valueDate, dividendYield) chooserOption = FinEquityChooserOption(chooseDate, callExpiryDate, putExpiryDate, callStrike, putStrike) v = chooserOption.value(valueDate, stockPrice, discountCurve, dividendCurve, model) v_mc = chooserOption.valueMC(valueDate, stockPrice, discountCurve, dividendCurve, model, 20000) v_matlab = 8.9308 testCases.header("", "", "", "", "", "") testCases.print("FINANCEPY", v, "MATLAB", v_matlab, "MC", v_mc)
def test_FinEquityChooserOptionDerivicom(): '''http://derivicom.com/support/finoptionsxl/index.html?complex_chooser.htm ''' valueDate = FinDate(1, 1, 2007) chooseDate = FinDate(1, 2, 2007) callExpiryDate = FinDate(1, 4, 2007) putExpiryDate = FinDate(1, 5, 2007) callStrike = 40.0 putStrike = 35.0 stockPrice = 38.0 volatility = 0.20 interestRate = 0.08 dividendYield = 0.0625 model = FinModelBlackScholes(volatility) discountCurve = FinDiscountCurveFlat(valueDate, interestRate) dividendCurve = FinDiscountCurveFlat(valueDate, dividendYield) chooserOption = FinEquityChooserOption(chooseDate, callExpiryDate, putExpiryDate, callStrike, putStrike) v = chooserOption.value(valueDate, stockPrice, discountCurve, dividendCurve, model) v_mc = chooserOption.valueMC(valueDate, stockPrice, discountCurve, dividendCurve, model, 20000) v_derivicom = 1.0989 testCases.header("", "", "", "", "", "") testCases.print("FINANCEPY", v, "DERIVICOM", v_derivicom, "MC", v_mc)
def test_FinFXMktVolSurface3(verboseCalibration): # EURUSD Example from Paper by Uwe Wystup using Tables 4 # print("EURUSD EXAMPLE WYSTUP") valueDate = FinDate(20, 1, 2009) forName = "EUR" domName = "USD" forCCRate = 0.020113 # EUR domCCRate = 0.003525 # USD domDiscountCurve = FinDiscountCurveFlat(valueDate, domCCRate) forDiscountCurve = FinDiscountCurveFlat(valueDate, forCCRate) currencyPair = forName + domName spotFXRate = 1.3088 tenors = ['1M'] atmVols = [21.6215] marketStrangle25DeltaVols = [0.7375] riskReversal25DeltaVols = [-0.50] notionalCurrency = forName atmMethod = FinFXATMMethod.FWD_DELTA_NEUTRAL deltaMethod = FinFXDeltaMethod.SPOT_DELTA fxMarket = FinFXVolSurface(valueDate, spotFXRate, currencyPair, notionalCurrency, domDiscountCurve, forDiscountCurve, tenors, atmVols, marketStrangle25DeltaVols, riskReversal25DeltaVols, atmMethod, deltaMethod) fxMarket.checkCalibration(verboseCalibration)
def test_FinFXMktVolSurface5(verboseCalibration): ########################################################################### # Here I remove the 10D Vols ########################################################################### if 1 == 1: # Example from Book extract by Iain Clark using Tables 3.3 and 3.4 # print("EURUSD EXAMPLE CLARK") valueDate = FinDate(10, 4, 2020) forName = "EUR" domName = "USD" forCCRate = 0.03460 # EUR domCCRate = 0.02940 # USD domDiscountCurve = FinDiscountCurveFlat(valueDate, domCCRate) forDiscountCurve = FinDiscountCurveFlat(valueDate, forCCRate) currencyPair = forName + domName spotFXRate = 1.3465 tenors = ['1M', '2M', '3M', '6M', '1Y', '2Y'] atmVols = [21.00, 21.00, 20.750, 19.400, 18.250, 17.677] marketStrangle25DeltaVols = [0.65, 0.75, 0.85, 0.90, 0.95, 0.85] riskReversal25DeltaVols = [-0.20, -0.25, -0.30, -0.50, -0.60, -0.562] marketStrangle10DeltaVols = [2.433, 2.83, 3.228, 3.485, 3.806, 3.208] riskReversal10DeltaVols = [-1.258, -1.297, -1.332, -1.408, -1.359, -1.208] marketStrangle10DeltaVols = None riskReversal10DeltaVols = None notionalCurrency = forName atmMethod = FinFXATMMethod.FWD_DELTA_NEUTRAL deltaMethod = FinFXDeltaMethod.SPOT_DELTA volFunctionType = FinVolFunctionTypes.CLARK alpha = 0.50 # FIT WINGS AT 10D if ALPHA = 1.0 fxMarketPlus = FinFXVolSurfacePlus(valueDate, spotFXRate, currencyPair, notionalCurrency, domDiscountCurve, forDiscountCurve, tenors, atmVols, marketStrangle25DeltaVols, riskReversal25DeltaVols, marketStrangle10DeltaVols, riskReversal10DeltaVols, alpha, atmMethod, deltaMethod, volFunctionType) fxMarketPlus.checkCalibration(False)
def test_FinFXMktVolSurface1(verboseCalibration): ########################################################################### if 1 == 1: # Example from Book extract by Iain Clark using Tables 3.3 and 3.4 # print("EURUSD EXAMPLE CLARK") valueDate = FinDate(10, 4, 2020) forName = "EUR" domName = "USD" forCCRate = 0.03460 # EUR domCCRate = 0.02940 # USD domDiscountCurve = FinDiscountCurveFlat(valueDate, domCCRate) forDiscountCurve = FinDiscountCurveFlat(valueDate, forCCRate) currencyPair = forName + domName spotFXRate = 1.3465 tenors = ['1M', '2M', '3M', '6M', '1Y', '2Y'] atmVols = [21.00, 21.00, 20.750, 19.400, 18.250, 17.677] marketStrangle25DeltaVols = [0.65, 0.75, 0.85, 0.90, 0.95, 0.85] riskReversal25DeltaVols = [-0.20, -0.25, -0.30, -0.50, -0.60, -0.562] marketStrangle10DeltaVols = [2.433, 2.83, 3.228, 3.485, 3.806, 3.208] riskReversal10DeltaVols = [ -1.258, -1.297, -1.332, -1.408, -1.359, -1.208 ] notionalCurrency = forName atmMethod = FinFXATMMethod.FWD_DELTA_NEUTRAL deltaMethod = FinFXDeltaMethod.SPOT_DELTA volFunctionType = FinVolFunctionTypes.CLARK5 alpha = 0.5 # FIT WINGS AT 10D if ALPHA = 1.0 fxMarketPlus = FinFXVolSurfacePlus( valueDate, spotFXRate, currencyPair, notionalCurrency, domDiscountCurve, forDiscountCurve, tenors, atmVols, marketStrangle25DeltaVols, riskReversal25DeltaVols, marketStrangle10DeltaVols, riskReversal10DeltaVols, alpha, atmMethod, deltaMethod, volFunctionType) fxMarketPlus.checkCalibration(False) if 1 == 0: # PLOT_GRAPHS: fxMarketPlus.plotVolCurves() plt.figure() dbns = fxMarketPlus.impliedDbns(0.5, 2.0, 1000) for i in range(0, len(dbns)): plt.plot(dbns[i]._x, dbns[i]._densitydx) plt.title(volFunctionType) print("SUM:", dbns[i].sum())
def test_FinFXMktVolSurface2(verboseCalibration): #print("==============================================================") # Example from Book extract by Iain Clarke using Tables 3.3 and 3.4 # print("EURJPY EXAMPLE CLARK") valueDate = FinDate(10, 4, 2020) forName = "EUR" domName = "JPY" forCCRate = 0.0294 # EUR domCCRate = 0.0171 # USD domDiscountCurve = FinDiscountCurveFlat(valueDate, domCCRate) forDiscountCurve = FinDiscountCurveFlat(valueDate, forCCRate) currencyPair = forName + domName spotFXRate = 90.72 tenors = ['1M', '2M', '3M', '6M', '1Y', '2Y'] atmVols = [21.50, 20.50, 19.85, 18.00, 15.95, 14.009] marketStrangle25DeltaVols = [0.35, 0.325, 0.300, 0.225, 0.175, 0.100] riskReversal25DeltaVols = [-8.350, -8.650, -8.950, -9.250, -9.550, -9.500] marketStrangle10DeltaVols = [3.704, 4.047, 4.396, 4.932, 5.726, 5.709] riskReversal10DeltaVols = [ -15.855, -16.467, -17.114, -17.882, -18.855, -18.217 ] alpha = 0.50 # Equally fit 10 and 25 Delta notionalCurrency = forName atmMethod = FinFXATMMethod.FWD_DELTA_NEUTRAL_PREM_ADJ deltaMethod = FinFXDeltaMethod.SPOT_DELTA_PREM_ADJ volFunctionType = FinVolFunctionTypes.CLARK5 fxMarketPlus = FinFXVolSurfacePlus( valueDate, spotFXRate, currencyPair, notionalCurrency, domDiscountCurve, forDiscountCurve, tenors, atmVols, marketStrangle25DeltaVols, riskReversal25DeltaVols, marketStrangle10DeltaVols, riskReversal10DeltaVols, alpha, atmMethod, deltaMethod, volFunctionType) # fxMarketPlus.checkCalibration(True) if PLOT_GRAPHS: fxMarketPlus.plotVolCurves() plt.figure() dbns = fxMarketPlus.impliedDbns(30, 120, 1000) for i in range(0, len(dbns)): plt.plot(dbns[i]._x, dbns[i]._densitydx) plt.title(volFunctionType) print("SUM:", dbns[i].sum())
def test_FinFXVanillaOptionWystupExample2(): # Example Bloomberg Pricing at # https://stackoverflow.com/questions/48778712/fx-vanilla-call-price-in-quantlib-doesnt-match-bloomberg valueDate = FinDate(13, 2, 2018) expiryDate = FinDate(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 currencyPair = ccy1 + ccy2 # Always ccy1ccy2 spotFXRate = 0.9090 strikeFXRate = 0.9090 volatility = 0.12 notional = 1000000.0 domDiscountCurve = FinDiscountCurveFlat(valueDate, ccy2CCRate) forDiscountCurve = FinDiscountCurveFlat(valueDate, ccy1CCRate) model = FinFXModelBlackScholes(volatility) # Two examples to show that changing the notional currency and notional # keeps the value unchanged notional = 1000000.0 callOption = FinFXVanillaOption(expiryDate, strikeFXRate, currencyPair, FinOptionTypes.EUROPEAN_PUT, notional, "EUR", 2) value = callOption.value( valueDate, spotFXRate, domDiscountCurve, forDiscountCurve, model) delta = callOption.delta( valueDate, spotFXRate, domDiscountCurve, forDiscountCurve, model) testCases.header("value", "delta") testCases.print(value, delta)
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) valueDate = FinDate(13, 2, 2018) expiryDate = FinDate(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 currencyPair = ccy1 + ccy2 # Always ccy1ccy2 spotFXRate = 1.20 strikeFXRate = 1.250 volatility = 0.10 notional = 1000000.0 domDiscountCurve = FinDiscountCurveFlat(valueDate, ccy2CCRate) forDiscountCurve = FinDiscountCurveFlat(valueDate, ccy1CCRate) model = FinFXModelBlackScholes(volatility) # Two examples to show that changing the notional currency and notional # keeps the value unchanged notional = 1000000.0 callOption = FinFXVanillaOption(expiryDate, strikeFXRate, currencyPair, FinOptionTypes.EUROPEAN_CALL, notional, "EUR", 2) value = callOption.value(1.0, spotFXRate, domDiscountCurve, forDiscountCurve, model) notional = 1250000.0 callOption = FinFXVanillaOption(expiryDate, strikeFXRate, currencyPair, FinOptionTypes.EUROPEAN_CALL, notional, "USD", 2) value = callOption.value(valueDate, spotFXRate, domDiscountCurve, forDiscountCurve, model) delta = callOption.delta(valueDate, spotFXRate, domDiscountCurve, forDiscountCurve, model) testCases.header("value", "delta") testCases.print(value, delta)
def test_FinFXMktVolSurface1(): ########################################################################### if 1 == 1: # Example from Book extract by Iain Clarke using Tables 3.3 and 3.4 # print("EURUSD EXAMPLE CLARKE") valueDate = FinDate(10, 4, 2020) forName = "EUR" domName = "USD" forCCRate = 0.03460 # EUR domCCRate = 0.02940 # USD domDiscountCurve = FinDiscountCurveFlat(valueDate, domCCRate) forDiscountCurve = FinDiscountCurveFlat(valueDate, forCCRate) currencyPair = forName + domName spotFXRate = 1.3465 tenors = ['1M', '2M', '3M', '6M', '1Y', '2Y'] atmVols = [21.00, 21.00, 20.750, 19.400, 18.250, 17.677] marketStrangle25DeltaVols = [0.65, 0.75, 0.85, 0.90, 0.95, 0.85] riskReversal25DeltaVols = [-0.20, -0.25, -0.30, -0.50, -0.60, -0.562] notionalCurrency = forName atmMethod = FinFXATMMethod.FWD_DELTA_NEUTRAL deltaMethod = FinFXDeltaMethod.SPOT_DELTA fxMarket = FinFXVolSurface(valueDate, spotFXRate, currencyPair, notionalCurrency, domDiscountCurve, forDiscountCurve, tenors, atmVols, marketStrangle25DeltaVols, riskReversal25DeltaVols, atmMethod, deltaMethod) # fxMarket.checkCalibration(True) if PLOT_GRAPHS: fxMarket.plotVolCurves() dbns = fxMarket.impliedDbns(0.5, 2.5, 1000)
def test_FinFXMktVolSurface2(verboseCalibration): #print("==============================================================") # Example from Book extract by Iain Clarke using Tables 3.3 and 3.4 # print("EURJPY EXAMPLE CLARKE") valueDate = FinDate(10, 4, 2020) forName = "EUR" domName = "JPY" forCCRate = 0.0294 # EUR domCCRate = 0.0171 # USD domDiscountCurve = FinDiscountCurveFlat(valueDate, domCCRate) forDiscountCurve = FinDiscountCurveFlat(valueDate, forCCRate) currencyPair = forName + domName spotFXRate = 90.72 tenors = ['1M', '2M', '3M', '6M', '1Y', '2Y'] atmVols = [21.50, 20.50, 19.85, 18.00, 15.95, 14.009] marketStrangle25DeltaVols = [0.35, 0.325, 0.300, 0.225, 0.175, 0.100] riskReversal25DeltaVols = [-8.350, -8.650, -8.950, -9.250, -9.550, -9.500] marketStrangle10DeltaVols = [3.704, 4.047, 4.396, 4.932, 5.726, 5.709] riskReversal10DeltaVols = [-15.855, -16.467, -17.114, -17.882, -18.855, -18.217] notionalCurrency = forName atmMethod = FinFXATMMethod.FWD_DELTA_NEUTRAL_PREM_ADJ deltaMethod = FinFXDeltaMethod.SPOT_DELTA_PREM_ADJ fxMarket = FinFXVolSurfacePlus(valueDate, spotFXRate, currencyPair, notionalCurrency, domDiscountCurve, forDiscountCurve, tenors, atmVols, marketStrangle25DeltaVols, riskReversal25DeltaVols, marketStrangle10DeltaVols, riskReversal10DeltaVols, atmMethod, deltaMethod) fxMarket.checkCalibration(verboseCalibration)
def testBlackModelCheck(): # Checking Andersen paper using Black's model # Used to check swaption price below - we have Ts = 1 and Te = 4 # Expect a price around 122 cents which is what I find. valuationDate = FinDate(1, 1, 2020) liborCurve = FinDiscountCurveFlat(valuationDate, 0.06, FinFrequencyTypes.SEMI_ANNUAL) settlementDate = FinDate(1, 1, 2020) exerciseDate = FinDate(1, 1, 2021) maturityDate = FinDate(1, 1, 2024) fixedCoupon = 0.06 fixedFrequencyType = FinFrequencyTypes.SEMI_ANNUAL fixedDayCountType = FinDayCountTypes.THIRTY_E_360_ISDA notional = 100.0 # Pricing a PAY swaptionType = FinSwapTypes.PAY swaption = FinIborSwaption(settlementDate, exerciseDate, maturityDate, swaptionType, fixedCoupon, fixedFrequencyType, fixedDayCountType, notional) model = FinModelBlack(0.20) v = swaption.value(valuationDate, liborCurve, model) testCases.header("LABEL", "VALUE") testCases.print("BLACK'S MODEL PRICE:", v * 100)
def test_FinEquityCliquetOptionHaug(): ''' Following example in Haug Page 130 ''' startDate = FinDate(1, 1, 2015) finalExpiryDate = FinDate(1, 1, 2017) freqType = FinFrequencyTypes.QUARTERLY optionType = FinOptionTypes.EUROPEAN_CALL cliquetOption = FinEquityCliquetOption(startDate, finalExpiryDate, optionType, freqType) valueDate = FinDate(1, 8, 2016) stockPrice = 50.0 volatility = 0.35 interestRate = 0.10 dividendYield = 0.05 model = FinModelBlackScholes(volatility) discountCurve = FinDiscountCurveFlat(valueDate, interestRate) v = cliquetOption.value(valueDate, stockPrice, discountCurve, dividendYield, model) testCases.header("LABEL", "VALUE") testCases.print("FINANCEPY", v)
def test_FinBondOptionAmericanConvergenceONE(): # Build discount curve settlementDate = FinDate(1, 12, 2019) discountCurve = FinDiscountCurveFlat(settlementDate, 0.05) # Bond details maturityDate = FinDate(1, 9, 2025) issueDate = FinDate(1, 9, 2016) coupon = 0.05 freqType = FinFrequencyTypes.SEMI_ANNUAL accrualType = FinDayCountTypes.ACT_ACT_ICMA bond = FinBond(issueDate, maturityDate, coupon, freqType, accrualType) # Option Details expiryDate = FinDate(1, 12, 2020) strikePrice = 100.0 face = 100.0 testCases.header("TIME", "N", "PUT_AMER", "PUT_EUR", "CALL_AME", "CALL_EUR") timeSteps = range(30, 100, 10) for numTimeSteps in timeSteps: sigma = 0.20 a = 0.1 start = time.time() optionType = FinOptionTypes.AMERICAN_PUT bondOption1 = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model1 = FinModelRatesBK(sigma, a, numTimeSteps) v1put = bondOption1.value(settlementDate, discountCurve, model1) optionType = FinOptionTypes.EUROPEAN_PUT bondOption2 = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model2 = FinModelRatesBK(sigma, a, numTimeSteps) v2put = bondOption2.value(settlementDate, discountCurve, model2) optionType = FinOptionTypes.AMERICAN_CALL bondOption1 = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model1 = FinModelRatesBK(sigma, a, numTimeSteps) v1call = bondOption1.value(settlementDate, discountCurve, model1) optionType = FinOptionTypes.EUROPEAN_CALL bondOption2 = FinBondOption(bond, expiryDate, strikePrice, face, optionType) model2 = FinModelRatesBK(sigma, a, numTimeSteps) v2call = bondOption2.value(settlementDate, discountCurve, model2) end = time.time() period = end - start testCases.print(period, numTimeSteps, v1put, v2put, v1call, v2call)
def test_OIS(): startDate = FinDate(2018, 11, 30) endDate = FinDate(2028, 6, 20) endDate = startDate.addMonths(60) oisRate = 0.04 isPayer = True fixedFreq = FinFrequencyTypes.ANNUAL fixedDayCount = FinDayCountTypes.ACT_ACT_ISDA floatFreq = FinFrequencyTypes.ANNUAL floatDayCount = FinDayCountTypes.ACT_ACT_ISDA notional = ONE_MILLION ois = FinOIS(startDate, endDate, oisRate, fixedFreq, fixedDayCount, floatFreq, floatDayCount, isPayer, notional) valueDate = FinDate(2018, 11, 30) marketRate = 0.05 indexCurve = FinDiscountCurveFlat(valueDate, marketRate, FinFrequencyTypes.ANNUAL) v = ois.value(startDate, indexCurve) testCases.header("LABEL", "VALUE") testCases.print("SWAP_VALUE", v)
def test_FinLiborCapletHull(): # Hull Page 703, example 29.3 todayDate = FinDate(20, 6, 2019) valuationDate = todayDate maturityDate = valuationDate.addTenor("2Y") liborCurve = FinDiscountCurveFlat(valuationDate, 0.070, FinFrequencyTypes.QUARTERLY, FinDayCountTypes.THIRTY_E_360) k = 0.08 capFloorType = FinLiborCapFloorTypes.CAP capFloor = FinLiborCapFloor(valuationDate, maturityDate, capFloorType, k, None, FinFrequencyTypes.QUARTERLY, FinDayCountTypes.THIRTY_E_360) # Value cap using a single flat cap volatility model = FinModelBlack(0.20) capFloor.value(valuationDate, liborCurve, model) # Value cap by breaking it down into caplets using caplet vols capletStartDate = valuationDate.addTenor("1Y") capletEndDate = capletStartDate.addTenor("3M") vCaplet = capFloor.valueCapletFloorLet(valuationDate, capletStartDate, capletEndDate, liborCurve, model) # Cannot match Hull due to dates being adjusted testCases.header("CORRECT PRICE", "MODEL PRICE") testCases.print(517.29, vCaplet)
def test_OIS(): # Here I follow the example in # https://blog.deriscope.com/index.php/en/excel-quantlib-overnight-index-swap startDate = FinDate(30, 11, 2018) endDate = FinDate(30, 11, 2023) endDate = startDate.addMonths(60) oisRate = 0.04 swapType = FinSwapTypes.PAYER fixedFreq = FinFrequencyTypes.ANNUAL fixedDayCount = FinDayCountTypes.ACT_360 floatFreq = FinFrequencyTypes.ANNUAL floatDayCount = FinDayCountTypes.ACT_360 notional = ONE_MILLION ois = FinOIRSwap(startDate, endDate, swapType, oisRate, fixedFreq, fixedDayCount, floatFreq, floatDayCount, notional) valueDate = FinDate(2018, 11, 30) marketRate = 0.05 indexCurve = FinDiscountCurveFlat(valueDate, marketRate, FinFrequencyTypes.ANNUAL) v = ois.value(startDate, [], [], indexCurve, indexCurve) testCases.header("LABEL", "VALUE") testCases.print("SWAP_VALUE", v) print(v)
def test_FinFloatIborLeg(): effectiveDate = FinDate(28, 10, 2020) maturityDate = FinDate(28, 10, 2025) spread = 0.0 freqType = FinFrequencyTypes.ANNUAL dayCountType = FinDayCountTypes.THIRTY_360_BOND notional = 10.0 * ONE_MILLION legPayRecType = FinSwapTypes.PAY calendarType = FinCalendarTypes.TARGET busDayAdjustType = FinBusDayAdjustTypes.FOLLOWING dateGenRuleType = FinDateGenRuleTypes.BACKWARD paymentLag = 0 principal = 0.0 swapFloatLeg = FinFloatLeg(effectiveDate, maturityDate, legPayRecType, spread, freqType, dayCountType, notional, principal, paymentLag, calendarType, busDayAdjustType, dateGenRuleType) liborCurve = FinDiscountCurveFlat(effectiveDate, 0.05) firstFixing = 0.03 v = swapFloatLeg.value(effectiveDate, liborCurve, liborCurve, firstFixing)
def test_FinFXMktVolSurface2(): #print("==============================================================") # Example from Book extract by Iain Clarke using Tables 3.3 and 3.4 #print("EURJPY EXAMPLE CLARKE") valueDate = FinDate(10, 4, 2020) forName = "EUR" domName = "JPY" forCCRate = 0.0294 # EUR domCCRate = 0.0171 # USD domDiscountCurve = FinDiscountCurveFlat(valueDate, domCCRate) forDiscountCurve = FinDiscountCurveFlat(valueDate, forCCRate) currencyPair = forName + domName spotFXRate = 90.72 tenors = ['1M', '2M', '3M', '6M', '1Y', '2Y'] atmVols = [21.50, 21.00, 19.85, 18.00, 15.95, 14.009] marketStrangle25DeltaVols = [0.35, 0.325, 0.30, 0.225, 0.175, 0.10] riskReversal25DeltaVols = [-8.35, -8.65, -8.95, -9.25, -9.550, -9.500] notionalCurrency = forName atmMethod = FinFXATMMethod.FWD_DELTA_NEUTRAL_PREM_ADJ deltaMethod = FinFXDeltaMethod.SPOT_DELTA_PREM_ADJ fxMarket = FinFXVolSurface(valueDate, spotFXRate, currencyPair, notionalCurrency, domDiscountCurve, forDiscountCurve, tenors, atmVols, marketStrangle25DeltaVols, riskReversal25DeltaVols, atmMethod, deltaMethod) # fxMarket.checkCalibration(True) if PLOT_GRAPHS: fxMarket.plotVolCurves()
def testFinModelBlackScholes(): valueDate = FinDate(8, 5, 2015) expiryDate = FinDate(15, 1, 2016) strikePrice = 130.0 stockPrice = 127.62 volatility = 0.20 interestRate = 0.001 dividendYield = 0.0163 optionType = FinOptionTypes.AMERICAN_CALL euOptionType = FinOptionTypes.EUROPEAN_CALL amOption = FinEquityAmericanOption(expiryDate, strikePrice, optionType) ameuOption = FinEquityAmericanOption(expiryDate, strikePrice, euOptionType) euOption = FinEquityVanillaOption(expiryDate, strikePrice, euOptionType) discountCurve = FinDiscountCurveFlat(valueDate, interestRate, FinFrequencyTypes.CONTINUOUS, FinDayCountTypes.ACT_365F) numStepsPerYear = 400 modelTree = FinModelBlackScholes(volatility, FinModelBlackScholesTypes.CRR_TREE, {'numStepsPerYear': numStepsPerYear}) v = amOption.value(valueDate, stockPrice, discountCurve, dividendYield, modelTree) # print(v) modelApprox = FinModelBlackScholes(volatility, FinModelBlackScholesTypes.BARONE_ADESI, None) v = amOption.value(valueDate, stockPrice, discountCurve, dividendYield, modelApprox) # print(v) v = ameuOption.value(valueDate, stockPrice, discountCurve, dividendYield, modelTree) # print(v) v = euOption.value(valueDate, stockPrice, discountCurve, dividendYield, modelTree) # print(v) amTreeValue = [] amBAWValue = [] euTreeValue = [] euAnalValue = [] volatility = 0.20
def test_FinFXMktVolSurface1(verboseCalibration): ########################################################################### if 1 == 1: # Example from Book extract by Iain Clarke using Tables 3.3 and 3.4 # print("EURUSD EXAMPLE CLARKE") valueDate = FinDate(10, 4, 2020) forName = "EUR" domName = "USD" forCCRate = 0.03460 # EUR domCCRate = 0.02940 # USD domDiscountCurve = FinDiscountCurveFlat(valueDate, domCCRate) forDiscountCurve = FinDiscountCurveFlat(valueDate, forCCRate) currencyPair = forName + domName spotFXRate = 1.3465 tenors = ['1M', '2M', '3M', '6M', '1Y', '2Y'] atmVols = [21.00, 21.00, 20.750, 19.400, 18.250, 17.677] marketStrangle25DeltaVols = [0.65, 0.75, 0.85, 0.90, 0.95, 0.85] riskReversal25DeltaVols = [-0.20, -0.25, -0.30, -0.50, -0.60, -0.562] notionalCurrency = forName atmMethod = FinFXATMMethod.FWD_DELTA_NEUTRAL deltaMethod = FinFXDeltaMethod.SPOT_DELTA # EXPLORE AND TEST DIFFERENT CATEGORICAL PARAMETERS for atmMethod in FinFXATMMethod: for deltaMethod in FinFXDeltaMethod: for volFunctionType in FinVolFunctionTypes: fxMarket = FinFXVolSurface( valueDate, spotFXRate, currencyPair, notionalCurrency, domDiscountCurve, forDiscountCurve, tenors, atmVols, marketStrangle25DeltaVols, riskReversal25DeltaVols, atmMethod, deltaMethod, volFunctionType) fxMarket.checkCalibration(verboseCalibration)
def test_FinEquityVarianceSwap(): startDate = FinDate(20, 3, 2018) tenor = "3M" strike = 0.3 * 0.3 volSwap = FinEquityVarianceSwap(startDate, tenor, strike) valuationDate = FinDate(20, 3, 2018) stockPrice = 100.0 dividendYield = 0.0 dividendCurve = FinDiscountCurveFlat(valuationDate, dividendYield) maturityDate = startDate.addMonths(3) atmVol = 0.20 atmK = 100.0 skew = -0.02 / 5.0 # defined as dsigma/dK strikes = np.linspace(50.0, 135.0, 18) vols = volSkew(strikes, atmVol, atmK, skew) volCurve = FinEquityVolCurve(valuationDate, maturityDate, strikes, vols) strikeSpacing = 5.0 numCallOptions = 10 numPutOptions = 10 r = 0.05 discountCurve = FinDiscountCurveFlat(valuationDate, r) useForward = False testCases.header("LABEL", "VALUE") k1 = volSwap.fairStrike(valuationDate, stockPrice, dividendCurve, volCurve, numCallOptions, numPutOptions, strikeSpacing, discountCurve, useForward) testCases.print("REPLICATION VARIANCE:", k1) k2 = volSwap.fairStrikeApprox(valuationDate, stockPrice, strikes, vols) testCases.print("DERMAN SKEW APPROX for K:", k2)
def test_FinFixedOIS(): # Here I follow the example in # https://blog.deriscope.com/index.php/en/excel-quantlib-overnight-index-swap effectiveDate = FinDate(30, 11, 2018) endDate = FinDate(30, 11, 2023) endDate = effectiveDate.addMonths(60) oisRate = 0.04 fixedLegType = FinSwapTypes.PAY fixedFreqType = FinFrequencyTypes.ANNUAL fixedDayCount = FinDayCountTypes.ACT_360 floatFreqType = FinFrequencyTypes.ANNUAL floatDayCount = FinDayCountTypes.ACT_360 floatSpread = 0.0 notional = ONE_MILLION paymentLag = 1 ois = FinOIS(effectiveDate, endDate, fixedLegType, oisRate, fixedFreqType, fixedDayCount, notional, paymentLag, floatSpread, floatFreqType, floatDayCount) # print(ois) valueDate = effectiveDate marketRate = 0.05 oisCurve = FinDiscountCurveFlat(valueDate, marketRate, FinFrequencyTypes.ANNUAL) v = ois.value(effectiveDate, oisCurve) # print(v) # ois._fixedLeg.printValuation() # ois._floatLeg.printValuation() testCases.header("LABEL", "VALUE") testCases.print("SWAP_VALUE", v)
def test_FinBondEmbeddedOptionQUANTLIB(): # Based on example at the nice blog on Quantlib at # http://gouthamanbalaraman.com/blog/callable-bond-quantlib-python.html # I get a price of 68.97 for 1000 time steps which is higher than the # 68.38 found in blog article. But this is for 40 grid points. # Note also that a basis point vol of 0.120 is 12% which is VERY HIGH! valuationDate = FinDate(16, 8, 2016) settlementDate = valuationDate.addWeekDays(3) ########################################################################### discountCurve = FinDiscountCurveFlat(valuationDate, 0.035, FinFrequencyTypes.SEMI_ANNUAL) ########################################################################### issueDate = FinDate(15, 9, 2010) maturityDate = FinDate(15, 9, 2022) coupon = 0.025 freqType = FinFrequencyTypes.QUARTERLY accrualType = FinDayCountTypes.ACT_ACT_ICMA bond = FinBond(issueDate, maturityDate, coupon, freqType, accrualType) ########################################################################### # Set up the call and put times and prices ########################################################################### nextCallDate = FinDate(15, 9, 2016) callDates = [nextCallDate] callPrices = [100.0] for i in range(1, 24): nextCallDate = nextCallDate.addMonths(3) callDates.append(nextCallDate) callPrices.append(100.0) putDates = [] putPrices = [] # the value used in blog of 12% bp vol is unrealistic sigma = 0.12 # basis point volatility a = 0.03 puttableBond = FinBondEmbeddedOption(issueDate, maturityDate, coupon, freqType, accrualType, callDates, callPrices, putDates, putPrices) testCases.header("BOND PRICE", "PRICE") v = bond.cleanPriceFromDiscountCurve(settlementDate, discountCurve) testCases.print("Bond Pure Price:", v) testCases.header("TIME", "NumTimeSteps", "BondWithOption", "BondPure") timeSteps = range(100, 1000, 100) values = [] for numTimeSteps in timeSteps: model = FinModelRatesHW(sigma, a, numTimeSteps) start = time.time() v = puttableBond.value(settlementDate, discountCurve, model) end = time.time() period = end - start testCases.print(period, numTimeSteps, v['bondwithoption'], v['bondpure']) values.append(v['bondwithoption']) if plotGraphs: plt.figure() plt.title("Puttable Bond Price Convergence") plt.plot(timeSteps, values)
def test_FinEquityBasketOption(): import time valueDate = FinDate(2015, 1, 1) expiryDate = FinDate(2016, 1, 1) volatility = 0.30 interestRate = 0.05 discountCurve = FinDiscountCurveFlat(valueDate, interestRate) ########################################################################## # Homogeneous Basket ########################################################################## numAssets = 5 volatilities = np.ones(numAssets) * volatility dividendYields = np.ones(numAssets) * 0.01 stockPrices = np.ones(numAssets) * 100 betaList = np.linspace(0.0, 0.999999, 11) testCases.header("NumPaths", "Beta", "Value", "ValueMC", "TIME") for beta in betaList: for numPaths in [10000]: callOption = FinEquityBasketOption(expiryDate, 100.0, FinOptionTypes.EUROPEAN_CALL, numAssets) betas = np.ones(numAssets) * beta corrMatrix = betaVectorToCorrMatrix(betas) start = time.time() v = callOption.value(valueDate, stockPrices, discountCurve, dividendYields, volatilities, corrMatrix) vMC = callOption.valueMC(valueDate, stockPrices, discountCurve, dividendYields, volatilities, corrMatrix, numPaths) end = time.time() duration = end - start testCases.print(numPaths, beta, v, vMC, duration) ########################################################################## # INHomogeneous Basket ########################################################################## numAssets = 5 volatilities = np.array([0.3, 0.2, 0.25, 0.22, 0.4]) dividendYields = np.array([0.01, 0.02, 0.04, 0.01, 0.02]) stockPrices = np.array([100, 105, 120, 100, 90]) betaList = np.linspace(0.0, 0.999999, 11) testCases.header("NumPaths", "Beta", "Value", "ValueMC", "TIME") for beta in betaList: for numPaths in [10000]: callOption = FinEquityBasketOption(expiryDate, 100.0, FinOptionTypes.EUROPEAN_CALL, numAssets) betas = np.ones(numAssets) * beta corrMatrix = betaVectorToCorrMatrix(betas) start = time.time() v = callOption.value(valueDate, stockPrices, discountCurve, dividendYields, volatilities, corrMatrix) vMC = callOption.valueMC(valueDate, stockPrices, discountCurve, dividendYields, volatilities, corrMatrix, numPaths) end = time.time() duration = end - start testCases.print(numPaths, beta, v, vMC, duration) ########################################################################## # Homogeneous Basket ########################################################################## numAssets = 5 volatilities = np.ones(numAssets) * volatility dividendYields = np.ones(numAssets) * 0.01 stockPrices = np.ones(numAssets) * 100 betaList = np.linspace(0.0, 0.999999, 11) testCases.header("NumPaths", "Beta", "Value", "ValueMC", "TIME") for beta in betaList: for numPaths in [10000]: callOption = FinEquityBasketOption(expiryDate, 100.0, FinOptionTypes.EUROPEAN_PUT, numAssets) betas = np.ones(numAssets) * beta corrMatrix = betaVectorToCorrMatrix(betas) start = time.time() v = callOption.value(valueDate, stockPrices, discountCurve, dividendYields, volatilities, corrMatrix) vMC = callOption.valueMC(valueDate, stockPrices, discountCurve, dividendYields, volatilities, corrMatrix, numPaths) end = time.time() duration = end - start testCases.print(numPaths, beta, v, vMC, duration) ########################################################################## # INHomogeneous Basket ########################################################################## numAssets = 5 volatilities = np.array([0.3, 0.2, 0.25, 0.22, 0.4]) dividendYields = np.array([0.01, 0.02, 0.04, 0.01, 0.02]) stockPrices = np.array([100, 105, 120, 100, 90]) betaList = np.linspace(0.0, 0.999999, 11) testCases.header("NumPaths", "Beta", "Value", "ValueMC", "TIME") for beta in betaList: for numPaths in [10000]: callOption = FinEquityBasketOption(expiryDate, 100.0, FinOptionTypes.EUROPEAN_PUT, numAssets) betas = np.ones(numAssets) * beta corrMatrix = betaVectorToCorrMatrix(betas) start = time.time() v = callOption.value(valueDate, stockPrices, discountCurve, dividendYields, volatilities, corrMatrix) vMC = callOption.valueMC(valueDate, stockPrices, discountCurve, dividendYields, volatilities, corrMatrix, numPaths) end = time.time() duration = end - start testCases.print(numPaths, beta, v, vMC, duration)