def testImpliedVolatility_NEW(): valueDate = FinDate(1, 1, 2015) stockPrice = 100.0 interestRate = 0.05 dividendYield = 0.03 discountCurve = FinDiscountCurveFlat(valueDate, interestRate) dividendCurve = FinDiscountCurveFlat(valueDate, dividendYield) 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 optionTypes = [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 = FinModelBlackScholes(vol) for timeToExpiry in timesToExpiry: expiryDate = valueDate.addYears(timeToExpiry) for strike in strikes: for optionType in optionTypes: option = FinEquityVanillaOption(expiryDate, strike, optionType) value = option.value(valueDate, stockPrice, discountCurve, dividendCurve, model) intrinsic = option.intrinsic(valueDate, stockPrice, discountCurve, dividendCurve) # 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.impliedVolatility(valueDate, stockPrice, discountCurve, dividendCurve, value) numTests += 1 errVol = np.abs(impliedVol - vol) if errVol > tol: testCases.print(optionType, timeToExpiry, stockPrice, strike, intrinsic, value, vol, impliedVol) # These fails include ones due to the zero time value numFails += 1 testCases.print(optionType, timeToExpiry, stockPrice, strike, stockPrice, value, vol, impliedVol) assert numFails == 694, "Num Fails has changed."
def test_FinEquityVanillaOption(): valueDate = FinDate(2015, 1, 1) expiryDate = FinDate(2015, 7, 1) stockPrice = 100 volatility = 0.30 interestRate = 0.05 dividendYield = 0.01 model = FinEquityModelBlackScholes(volatility) discountCurve = FinDiscountCurveFlat(valueDate, interestRate) numPathsList = [10000, 20000, 40000, 80000, 160000, 320000] testCases.header("NUMPATHS", "VALUE_BS", "VALUE_MC", "TIME") for numPaths in numPathsList: callOption = FinEquityVanillaOption(expiryDate, 100.0, FinOptionTypes.EUROPEAN_CALL) value = callOption.value(valueDate, stockPrice, discountCurve, dividendYield, model) start = time.time() valueMC = callOption.valueMC(valueDate, stockPrice, discountCurve, dividendYield, model, numPaths) end = time.time() duration = end - start testCases.print(numPaths, value, valueMC, duration) ############################################################################### stockPrices = range(80, 120, 2) numPaths = 100000 testCases.header("NUMPATHS", "VALUE_BS", "VALUE_MC", "TIME") useSobol = True for stockPrice in stockPrices: callOption = FinEquityVanillaOption(expiryDate, 100.0, FinOptionTypes.EUROPEAN_CALL) value = callOption.value(valueDate, stockPrice, discountCurve, dividendYield, model) start = time.time() useSobol = False valueMC1 = callOption.valueMC(valueDate, stockPrice, discountCurve, dividendYield, model, numPaths, useSobol) useSobol = True valueMC2 = callOption.valueMC(valueDate, stockPrice, discountCurve, dividendYield, model, numPaths, useSobol) end = time.time() duration = end - start testCases.print(numPaths, value, valueMC, duration) ############################################################################### stockPrices = range(80, 120, 2) numPaths = 100000 testCases.header("STOCK PRICE", "VALUE_BS", "VALUE_MC", "TIME") for stockPrice in stockPrices: putOption = FinEquityVanillaOption(expiryDate, 100.0, FinOptionTypes.EUROPEAN_PUT) value = putOption.value(valueDate, stockPrice, discountCurve, dividendYield, model) start = time.time() valueMC = putOption.valueMC(valueDate, stockPrice, discountCurve, dividendYield, model, numPaths) end = time.time() duration = end - start testCases.print(stockPrice, value, valueMC, duration) ############################################################################### stockPrices = range(80, 120, 2) testCases.header("STOCK PRICE", "VALUE_BS", "DELTA_BS", "VEGA_BS", "THETA_BS", "RHO_BS") for stockPrice in stockPrices: callOption = FinEquityVanillaOption(expiryDate, 100.0, FinOptionTypes.EUROPEAN_CALL) value = callOption.value(valueDate, stockPrice, discountCurve, dividendYield, model) delta = callOption.delta(valueDate, stockPrice, discountCurve, dividendYield, model) vega = callOption.vega(valueDate, stockPrice, discountCurve, dividendYield, model) theta = callOption.theta(valueDate, stockPrice, discountCurve, dividendYield, model) # callOption.rho(valueDate,stockPrice, interestRate, dividendYield, modelType, modelParams) rho = 999 testCases.print(stockPrice, value, delta, vega, theta, rho) testCases.header("STOCK PRICE", "VALUE_BS", "DELTA_BS", "VEGA_BS", "THETA_BS", "RHO_BS") for stockPrice in stockPrices: putOption = FinEquityVanillaOption(expiryDate, 100.0, FinOptionTypes.EUROPEAN_PUT) value = putOption.value(valueDate, stockPrice, discountCurve, dividendYield, model) delta = putOption.delta(valueDate, stockPrice, discountCurve, dividendYield, model) vega = putOption.vega(valueDate, stockPrice, discountCurve, dividendYield, model) theta = putOption.theta(valueDate, stockPrice, discountCurve, dividendYield, model) # putOption.rho(valueDate,stockPrice, interestRate, dividendYield, # modelType, modelParams) rho = 999 testCases.print(stockPrice, value, delta, vega, theta, rho) ############################################################################### testCases.header("STOCK PRICE", "VALUE_BS", "VOL_IN", "IMPLD_VOL") stockPrices = range(60, 150, 2) for stockPrice in stockPrices: callOption = FinEquityVanillaOption(expiryDate, 100.0, FinOptionTypes.EUROPEAN_CALL) value = callOption.value(valueDate, stockPrice, discountCurve, dividendYield, model) impliedVol = callOption.impliedVolatility(valueDate, stockPrice, discountCurve, dividendYield, value) testCases.print(stockPrice, value, volatility, impliedVol)
def testImpliedVolatility(): valueDate = FinDate(1, 1, 2015) stockPrice = 100 interestRate = 0.05 dividendYield = 0.01 discountCurve = FinDiscountCurveFlat(valueDate, interestRate) strikes = [10, 20, 50, 100, 150, 200] timesToExpiry = [0.003, 0.01, 0.1, 0.5, 1.0, 2.0, 5.0] expiryDates = valueDate.addYears(timesToExpiry) sigmas = [0.01, 0.10, 0.50, 1.0] optionTypes = [FinOptionTypes.EUROPEAN_CALL, FinOptionTypes.EUROPEAN_PUT] testCases.header("OPT_TYPE", "EXP_DATE", "STRIKE", "STOCK_PRICE", "VALUE", "INPUT_VOL", "IMPLIED_VOL") tol = 1e-6 numTests = 0 numFails = 0 for vol in sigmas: model = FinModelBlackScholes(vol) for expiryDate in expiryDates: for strike in strikes: for optionType in optionTypes: option = FinEquityVanillaOption(expiryDate, 100.0, optionType) value = option.value(valueDate, stockPrice, discountCurve, dividendYield, model) impliedVol = option.impliedVolatility( valueDate, stockPrice, discountCurve, dividendYield, value) numTests += 1 if np.abs(impliedVol - vol) > tol: numFails += 1 # print(optionType, expiryDate, strike, # stockPrice, value, vol, impliedVol) testCases.print(optionType, expiryDate, strike, stockPrice, value, vol, impliedVol) print("Num Tests", numTests, "numFails", numFails) ############################################################################### K = [10, 20, 50, 100, 150, 200] T = [0.003, 0.01, 0.1, 0.5, 1.0, 2.0, 5.0] sigma = [0.01, 0.10, 0.50, 1.0] optionTypes = [FinOptionTypes.EUROPEAN_CALL, FinOptionTypes.EUROPEAN_PUT] stockPrice = 100 HOURS_PER_YEAR = 365.25 * 24 convergenceFailure = 0 assertionFailure = 0 noResult = 0 successful = 0 numberTests = 0 totalElapsedTime = 0. for t in T: expDate = valueDate.addHours(t * HOURS_PER_YEAR) for k in K: for vol in sigma: bs_model = FinModelBlackScholes(vol) for type_ in optionTypes: option = FinEquityVanillaOption(expDate, k, type_) value = option.value(valueDate, stockPrice, discountCurve, dividendYield, bs_model) if value < 1e-10: continue try: start_time = time.time() impliedVol = option.impliedVolatility_v2( valueDate, stockPrice, discountCurve, dividendYield, value) assert abs(impliedVol - vol) < 0.10 except FinError: noResult += 1 except AssertionError: assertionFailure += 1 print("-----------------") print( f"Did not converge to expected value: {round(impliedVol, 2)} vs {vol}" ) print("INPUTS\n", "Type:", type_.name, "ttm:", t, "strike:", k, "Expected IV:", vol, "BS Price:", value) except RuntimeError: import traceback traceback.print_exc() convergenceFailure += 1 print("INPUTS\n", "Type:", type_.name, "ttm:", t, "strike:", k, "Expected IV:", vol) except Exception: import traceback traceback.print_exc() noResult += 1 else: successful += 1 totalElapsedTime += time.time() - start_time finally: numberTests += 1 print("\nSuccessful:", successful) print("Convergence failure:", convergenceFailure) print("Inaccurate result:", assertionFailure) print("No result (price too low)", noResult) print("TOTAL:", numberTests) print("Mean time:", 1e6 * totalElapsedTime / successful, "us")