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 testAnalyticalModels(): # Reference see table 4.1 of Rouah book valueDate = FinDate(2015, 1, 1) expiryDate = FinDate(2015, 4, 1) v0 = 0.05 # initial variance of volatility theta = 0.05 # long term variance kappa = 2.0 # speed of variance reversion sigma = 0.10 # volatility of variance rho = -0.9 # correlation interestRate = 0.05 dividendYield = 0.01 seed = 2838 numSteps = 100 numPaths = 20000 stockPrice = 100.0 testCases.header("TIME", "RHO", "SIGMA", "K", "MC", "GATH", "LEWROU", "LEWIS", "WEBER", "MCERR") for sigma in [0.5, 0.75, 1.0]: for rho in [-0.9, -0.5, 0.0]: hestonModel = FinModelHeston(v0, kappa, theta, sigma, rho) for strikePrice in np.linspace(95, 105, 3): callOption = FinEquityVanillaOption( expiryDate, strikePrice, FinEquityOptionTypes.EUROPEAN_CALL) valueMC_Heston = hestonModel.value_MC(valueDate, callOption, stockPrice, interestRate, dividendYield, numPaths, numSteps, seed) start = time.time() valueGatheral = hestonModel.value_Gatheral( valueDate, callOption, stockPrice, interestRate, dividendYield) valueLewisRouah = hestonModel.value_Lewis_Rouah( valueDate, callOption, stockPrice, interestRate, dividendYield) valueLewis = hestonModel.value_Lewis(valueDate, callOption, stockPrice, interestRate, dividendYield) valueWeber = hestonModel.value_Weber(valueDate, callOption, stockPrice, interestRate, dividendYield) err = (valueMC_Heston - valueWeber) end = time.time() elapsed = end - start testCases.print( "%6.3f" % elapsed, "% 7.5f" % rho, "%7.5f" % sigma, "%7.2f" % strikePrice, "%12.9f" % valueMC_Heston, "%12.9f" % valueGatheral, # problem "%12.9f" % valueLewisRouah, "%12.9f" % valueLewis, "%12.9f" % valueWeber, "%12.9f" % err)
def testMonteCarlo(): import time # Reference see table 4.1 of Rouah book valueDate = FinDate(2015, 1, 1) expiryDate = FinDate(2016, 1, 1) v0 = 0.04 # initial variance of volatility theta = 0.04 # long term variance kappa = 2.0 # speed of variance reversion sigma = 1.0 # volatility of variance rho = -0.9 # correlation interestRate = 0.05 dividendYield = 0.01 seed = 238 stockPrice = 100.0 testCases.header("TIME", "RHO", "SIGMA", "K", "NSTEPS", "NPATHS", "FORMULA", "EULER_ERR", "EULLOG_ERR", "QE_ERR") for strikePrice in np.linspace(95, 105, 3): for numSteps in [25, 50]: for numPaths in [10000, 20000]: hestonModel = FinModelHeston(v0, kappa, theta, sigma, rho) callOption = FinEquityVanillaOption( expiryDate, strikePrice, FinEquityOptionTypes.EUROPEAN_CALL) valueWeber = hestonModel.value_Weber(valueDate, callOption, stockPrice, interestRate, dividendYield) start = time.time() valueMC_EULER = hestonModel.value_MC( valueDate, callOption, stockPrice, interestRate, dividendYield, numPaths, numSteps, seed, FinHestonNumericalScheme.EULER) valueMC_EULERLOG = hestonModel.value_MC( valueDate, callOption, stockPrice, interestRate, dividendYield, numPaths, numSteps, seed, FinHestonNumericalScheme.EULERLOG) valueMC_QUADEXP = hestonModel.value_MC( valueDate, callOption, stockPrice, interestRate, dividendYield, numPaths, numSteps, seed, FinHestonNumericalScheme.QUADEXP) err_EULER = (valueMC_EULER - valueWeber) err_EULERLOG = (valueMC_EULERLOG - valueWeber) err_QUADEXP = (valueMC_QUADEXP - valueWeber) end = time.time() elapsed = end - start testCases.print(elapsed, rho, sigma, strikePrice, numSteps, numPaths, valueWeber, err_EULER, err_EULERLOG, err_QUADEXP)
def test_FinBinomialTree(): stock_price = 50.0 riskFreeRate = 0.06 dividendYield = 0.04 volatility = 0.40 valuation_date = Date(1, 1, 2016) expiry_date = Date(1, 1, 2017) model = FinModelBlackScholes(volatility) discount_curve = DiscountCurveFlat(valuation_date, riskFreeRate) dividendCurve = DiscountCurveFlat(valuation_date, dividendYield) num_stepsList = [100, 500, 1000, 2000, 5000] strikePrice = 50.0 testCases.banner("================== EUROPEAN PUT =======================") putOption = FinEquityVanillaOption(expiry_date, strikePrice, FinOptionTypes.EUROPEAN_PUT) value = putOption.value(valuation_date, stock_price, discount_curve, dividendCurve, model) delta = putOption.delta(valuation_date, stock_price, discount_curve, dividendCurve, model) gamma = putOption.gamma(valuation_date, stock_price, discount_curve, dividendCurve, model) theta = putOption.theta(valuation_date, stock_price, discount_curve, dividendCurve, model) testCases.header("BS Value", "BS Delta", "BS Gamma", "BS Theta") testCases.print(value, delta, gamma, theta) payoff = FinEquityTreePayoffTypes.VANILLA_OPTION exercise = FinEquityTreeExerciseTypes.EUROPEAN params = np.array([-1, strikePrice]) testCases.header("NumSteps", "Results", "TIME") for num_steps in num_stepsList: start = time.time() tree = FinEquityBinomialTree() results = tree.value(stock_price, discount_curve, dividendCurve, 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 = FinEquityTreePayoffTypes.VANILLA_OPTION exercise = FinEquityTreeExerciseTypes.AMERICAN params = np.array([-1, strikePrice]) testCases.header("NumSteps", "Results", "TIME") for num_steps in num_stepsList: start = time.time() tree = FinEquityBinomialTree() results = tree.value(stock_price, discount_curve, dividendCurve, 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 =======================") callOption = FinEquityVanillaOption(expiry_date, strikePrice, FinOptionTypes.EUROPEAN_CALL) value = callOption.value(valuation_date, stock_price, discount_curve, dividendCurve, model) delta = callOption.delta(valuation_date, stock_price, discount_curve, dividendCurve, model) gamma = callOption.gamma(valuation_date, stock_price, discount_curve, dividendCurve, model) theta = callOption.theta(valuation_date, stock_price, discount_curve, dividendCurve, model) testCases.header("BS Value", "BS Delta", "BS Gamma", "BS Theta") testCases.print(value, delta, gamma, theta) payoff = FinEquityTreePayoffTypes.VANILLA_OPTION exercise = FinEquityTreeExerciseTypes.EUROPEAN params = np.array([1.0, strikePrice]) testCases.header("NumSteps", "Results", "TIME") for num_steps in num_stepsList: start = time.time() tree = FinEquityBinomialTree() results = tree.value(stock_price, discount_curve, dividendCurve, 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 = FinEquityTreePayoffTypes.VANILLA_OPTION exercise = FinEquityTreeExerciseTypes.AMERICAN params = np.array([1.0, strikePrice]) testCases.header("NumSteps", "Results", "TIME") for num_steps in num_stepsList: start = time.time() tree = FinEquityBinomialTree() results = tree.value(stock_price, discount_curve, dividendCurve, volatility, num_steps, valuation_date, payoff, expiry_date, payoff, exercise, params) end = time.time() duration = end - start testCases.print(num_steps, results, duration)
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 test_FinNumbaNumbaParallel(useSobol): valueDate = FinDate(1, 1, 2015) expiryDate = FinDate(1, 7, 2015) stockPrice = 100 volatility = 0.30 interestRate = 0.05 dividendYield = 0.01 seed = 2021 model = FinModelBlackScholes(volatility) discountCurve = FinDiscountCurveFlat(valueDate, interestRate) useSobolInt = int(useSobol) testCases.header("NUMPATHS", "VALUE_BS", "VALUE_MC", "TIME") callOption = FinEquityVanillaOption(expiryDate, 100.0, FinOptionTypes.EUROPEAN_CALL) value = callOption.value(valueDate, stockPrice, discountCurve, dividendYield, model) numPoints = 20 v_exact = [value] * numPoints numPathsList = np.arange(1, numPoints + 1, 1) * 1000000 NUMBA_ONLY_v = [] NUMBA_ONLY_t = [] print("NUMBA ONLY") for numPaths in numPathsList: start = time.time() valueMC = callOption.valueMC_NUMBA_ONLY(valueDate, stockPrice, discountCurve, dividendYield, model, numPaths, seed, useSobolInt) end = time.time() duration = end - start print("%10d %9.5f %9.5f %9.6f" % (numPaths, value, valueMC, duration)) NUMBA_ONLY_v.append(valueMC) NUMBA_ONLY_t.append(duration) NUMBA_PARALLEL_v = [] NUMBA_PARALLEL_t = [] print("NUMBA PARALLEL") for numPaths in numPathsList: start = time.time() valueMC = callOption.valueMC_NUMBA_PARALLEL(valueDate, stockPrice, discountCurve, dividendYield, model, numPaths, seed, useSobolInt) end = time.time() duration = end - start print("%10d %9.5f %9.5f %9.6f" % (numPaths, value, valueMC, duration)) NUMBA_PARALLEL_v.append(valueMC) 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(numPathsList, NUMBA_ONLY_t, 'o-', label="NUMBA ONLY") plt.plot(numPathsList, 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(numPathsList, v_exact, label="EXACT") plt.plot(numPathsList, NUMBA_ONLY_v, 'o-', label="NUMBA ONLY") plt.plot(numPathsList, NUMBA_PARALLEL_v, 'o-', label="NUMBA PARALLEL") plt.xlabel("Number of Paths") plt.ylabel("Option Value") plt.legend() plt.title(title)
def test_FinNumbaNumpySpeed(useSobol): valueDate = FinDate(1, 1, 2015) expiryDate = FinDate(1, 7, 2015) stockPrice = 100 volatility = 0.30 interestRate = 0.05 dividendYield = 0.01 seed = 1999 model = FinModelBlackScholes(volatility) discountCurve = FinDiscountCurveFlat(valueDate, interestRate) useSobolInt = int(useSobol) testCases.header("NUMPATHS", "VALUE_BS", "VALUE_MC", "TIME") callOption = FinEquityVanillaOption(expiryDate, 100.0, FinOptionTypes.EUROPEAN_CALL) value = callOption.value(valueDate, stockPrice, discountCurve, dividendYield, model) numPoints = 20 v_exact = [value] * numPoints ########################################################################### # DO UP TO 100K AS IT IS SLOW ########################################################################### numPathsList = np.arange(1, numPoints + 1, 1) * 100000 NONUMBA_NONUMPY_v = [] NONUMBA_NONUMPY_t = [] print("PURE PYTHON") for numPaths in numPathsList: start = time.time() valueMC = callOption.valueMC_NONUMBA_NONUMPY(valueDate, stockPrice, discountCurve, dividendYield, model, numPaths, seed, useSobolInt) end = time.time() duration = end - start print("%10d %9.5f %9.5f %9.6f" % (numPaths, value, valueMC, duration)) NONUMBA_NONUMPY_v.append(valueMC) NONUMBA_NONUMPY_t.append(duration + 1e-10) NUMPY_ONLY_v = [] NUMPY_ONLY_t = [] print("NUMPY ONLY") for numPaths in numPathsList: start = time.time() valueMC = callOption.valueMC_NUMPY_ONLY(valueDate, stockPrice, discountCurve, dividendYield, model, numPaths, seed, useSobolInt) end = time.time() duration = end - start print("%10d %9.5f %9.5f %9.6f" % (numPaths, value, valueMC, duration)) NUMPY_ONLY_v.append(valueMC) NUMPY_ONLY_t.append(duration + 1e-10) # speedUp = np.array(NONUMBA_NONUMPY_t)/np.array(NUMPY_ONLY_t) # print(NUMPY_ONLY_t) # print(NONUMBA_NONUMPY_t) # print(speedUp) if useSobol: title = "SOBOL: PURE PYTHON VS NUMPY" else: title = "PSEUDORANDOM: PURE PYTHON VS NUMPY" plt.figure(figsize=(8, 6)) plt.plot(numPathsList, NONUMBA_NONUMPY_t, 'o-', label="PURE PYTHON") plt.plot(numPathsList, NUMPY_ONLY_t, 'o-', label="NUMPY ONLY") plt.xlabel("Number of Paths") plt.ylabel("Wall Time (s)") plt.legend() plt.title(title) plt.figure(figsize=(8, 6)) plt.plot(numPathsList, v_exact, label="EXACT") plt.plot(numPathsList, NONUMBA_NONUMPY_v, 'o-', label="PURE PYTHON") plt.plot(numPathsList, NUMPY_ONLY_v, 'o-', label="NUMPY ONLY") plt.xlabel("Number of Paths") plt.ylabel("Option Value") plt.legend() plt.title(title) ########################################################################### # DO UP TO 10 MILLION NOW THAT WE HAVE NUMPY ########################################################################### numPathsList = np.arange(1, numPoints + 1, 1) * 1000000 NUMPY_ONLY_v = [] NUMPY_ONLY_t = [] print("NUMPY ONLY") for numPaths in numPathsList: start = time.time() valueMC = callOption.valueMC_NUMPY_ONLY(valueDate, stockPrice, discountCurve, dividendYield, model, numPaths, seed, useSobolInt) end = time.time() duration = end - start print("%10d %9.5f %9.5f %9.6f" % (numPaths, value, valueMC, duration)) NUMPY_ONLY_v.append(valueMC) NUMPY_ONLY_t.append(duration) NUMBA_NUMPY_v = [] NUMBA_NUMPY_t = [] print("NUMBA+NUMPY") for numPaths in numPathsList: start = time.time() valueMC = callOption.valueMC_NUMPY_NUMBA(valueDate, stockPrice, discountCurve, dividendYield, model, numPaths, seed, useSobolInt) end = time.time() duration = end - start print("%10d %9.5f %9.5f %9.6f" % (numPaths, value, valueMC, duration)) NUMBA_NUMPY_v.append(valueMC) NUMBA_NUMPY_t.append(duration) NUMBA_ONLY_v = [] NUMBA_ONLY_t = [] print("NUMBA ONLY") for numPaths in numPathsList: start = time.time() valueMC = callOption.valueMC_NUMBA_ONLY(valueDate, stockPrice, discountCurve, dividendYield, model, numPaths, seed, useSobolInt) end = time.time() duration = end - start print("%10d %9.5f %9.5f %9.6f" % (numPaths, value, valueMC, duration)) NUMBA_ONLY_v.append(valueMC) NUMBA_ONLY_t.append(duration) NUMBA_PARALLEL_v = [] NUMBA_PARALLEL_t = [] print("NUMBA PARALLEL") for numPaths in numPathsList: start = time.time() valueMC = callOption.valueMC_NUMBA_PARALLEL(valueDate, stockPrice, discountCurve, dividendYield, model, numPaths, seed, useSobolInt) end = time.time() duration = end - start print("%10d %9.5f %9.5f %9.6f" % (numPaths, value, valueMC, duration)) NUMBA_PARALLEL_v.append(valueMC) NUMBA_PARALLEL_t.append(duration) # speedUp = np.array(NUMBA_ONLY_t)/np.array(NUMBA_PARALLEL_t) # print("PARALLEL:", speedUp) ########################################################################### # COMPUTED USING NUMSTEPS FROM 1M to 10M ########################################################################### CPP_t = np.array([ 0.075, 0.155, 0.223, 0.313, 0.359, 0.421, 0.495, 0.556, 0.64, 0.702, 0.765, 0.841, 0.923, 0.982, 1.05, 1.125, 1.195, 1.261, 1.333, 1.408 ]) CPP_v = np.array([ 9.30872, 9.29576, 9.29422, 9.29832, 9.29863, 9.30153, 9.2994, 9.3025, 9.29653, 9.29875, 9.29897, 9.29996, 9.29931, 9.29796, 9.29784, 9.2992, 9.3001, 9.30093, 9.29876, 9.29921 ]) if useSobol: title = "SOBOL: COMPARING OPTIMISATIONS" else: title = "PSEUDORANDOM: COMPARING OPTIMISATIONS" plt.figure(figsize=(8, 6)) plt.plot(numPathsList, NUMPY_ONLY_t, 'o-', label="NUMPY ONLY") plt.plot(numPathsList, NUMBA_NUMPY_t, 'o-', label="NUMBA + NUMPY") plt.xlabel("Number of Paths") plt.ylabel("Wall Time (s)") plt.legend() plt.title(title) ########################################################################### if useSobol: title = "SOBOL: COMPARING OPTIMISATIONS" else: title = "PSEUDORANDOM: COMPARING OPTIMISATIONS" plt.figure(figsize=(8, 6)) plt.plot(numPathsList, NUMPY_ONLY_t, 'o-', label="NUMPY ONLY") plt.plot(numPathsList, NUMBA_NUMPY_t, 'o-', label="NUMBA + NUMPY") plt.plot(numPathsList, NUMBA_ONLY_t, 'o-', label="NUMBA ONLY") plt.plot(numPathsList, NUMBA_PARALLEL_t, 'o-', label="NUMBA PARALLEL") if useSobol == False: plt.plot(numPathsList, CPP_t, 'o-', label="C++") plt.xlabel("Number of Paths") plt.ylabel("Wall Time (s)") plt.legend() plt.title(title) ########################################################################### plt.figure(figsize=(8, 6)) plt.plot(numPathsList, v_exact, label="EXACT") plt.plot(numPathsList, NUMBA_ONLY_v, 'o-', label="NUMBA ONLY") plt.plot(numPathsList, CPP_v, 'o-', label="C++") plt.xlabel("Number of Paths") plt.ylabel("Option Value") plt.legend() plt.title(title)
def test_FinEquityVanillaOption(): valueDate = FinDate(1, 1, 2015) expiryDate = FinDate(1, 7, 2015) stockPrice = 100 volatility = 0.30 interestRate = 0.05 dividendYield = 0.01 model = FinModelBlackScholes(volatility) discountCurve = FinDiscountCurveFlat(valueDate, interestRate) dividendCurve = FinDiscountCurveFlat(valueDate, dividendYield) 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, dividendCurve, model) start = time.time() valueMC = callOption.valueMC(valueDate, stockPrice, discountCurve, dividendCurve, model, numPaths) end = time.time() duration = end - start testCases.print(numPaths, value, valueMC, duration) ############################################################################### stockPrices = range(80, 120, 10) numPaths = 100000 testCases.header("NUMPATHS", "CALL_VALUE_BS", "CALL_VALUE_MC", "CALL_VALUE_MC_SOBOL", "TIME") useSobol = True for stockPrice in stockPrices: callOption = FinEquityVanillaOption(expiryDate, 100.0, FinOptionTypes.EUROPEAN_CALL) value = callOption.value(valueDate, stockPrice, discountCurve, dividendCurve, model) start = time.time() useSobol = False valueMC1 = callOption.valueMC(valueDate, stockPrice, discountCurve, dividendCurve, model, numPaths, useSobol) useSobol = True valueMC2 = callOption.valueMC(valueDate, stockPrice, discountCurve, dividendCurve, model, numPaths, useSobol) end = time.time() duration = end - start testCases.print(numPaths, value, valueMC1, valueMC2, duration) ############################################################################### stockPrices = range(80, 120, 10) numPaths = 100000 testCases.header("NUMPATHS", "PUT_VALUE_BS", "PUT_VALUE_MC", "PUT_VALUE_MC_SOBOL", "TIME") for stockPrice in stockPrices: putOption = FinEquityVanillaOption(expiryDate, 100.0, FinOptionTypes.EUROPEAN_PUT) value = putOption.value(valueDate, stockPrice, discountCurve, dividendCurve, model) start = time.time() useSobol = False valueMC1 = putOption.valueMC(valueDate, stockPrice, discountCurve, dividendCurve, model, numPaths, useSobol) useSobol = True valueMC2 = putOption.valueMC(valueDate, stockPrice, discountCurve, dividendCurve, model, numPaths, useSobol) end = time.time() duration = end - start testCases.print(numPaths, value, valueMC1, valueMC2, duration) ############################################################################### stockPrices = range(80, 120, 10) testCases.header("STOCK PRICE", "CALL_VALUE_BS", "CALL_DELTA_BS", "CALL_VEGA_BS", "CALL_THETA_BS", "CALL_RHO_BS","CALL_VANNA_BS") for stockPrice in stockPrices: callOption = FinEquityVanillaOption(expiryDate, 100.0, FinOptionTypes.EUROPEAN_CALL) value = callOption.value(valueDate, stockPrice, discountCurve, dividendCurve, model) delta = callOption.delta(valueDate, stockPrice, discountCurve, dividendCurve, model) vega = callOption.vega(valueDate, stockPrice, discountCurve, dividendCurve, model) theta = callOption.theta(valueDate, stockPrice, discountCurve, dividendCurve, model) rho = callOption.rho(valueDate, stockPrice, discountCurve, dividendCurve, model) vanna = callOption.vanna(valueDate, stockPrice, discountCurve, dividendCurve, model) testCases.print(stockPrice, value, delta, vega, theta, rho, vanna) ########################################################################### testCases.header("STOCK PRICE", "PUT_VALUE_BS", "PUT_DELTA_BS", "PUT_VEGA_BS", "PUT_THETA_BS", "PUT_RHO_BS","PUT_VANNA_BS") for stockPrice in stockPrices: putOption = FinEquityVanillaOption(expiryDate, 100.0, FinOptionTypes.EUROPEAN_PUT) value = putOption.value(valueDate, stockPrice, discountCurve, dividendCurve, model) delta = putOption.delta(valueDate, stockPrice, discountCurve, dividendCurve, model) vega = putOption.vega(valueDate, stockPrice, discountCurve, dividendCurve, model) theta = putOption.theta(valueDate, stockPrice, discountCurve, dividendCurve, model) rho = putOption.rho(valueDate, stockPrice, discountCurve, dividendCurve, model) vanna = putOption.vanna(valueDate, stockPrice, discountCurve, dividendCurve, model) testCases.print(stockPrice, value, delta, vega, theta, rho, vanna)
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 testFinEquityAmericanOption(): valueDate = FinDate(2016, 1, 1) expiryDate = FinDate(2017, 1, 1) stockPrice = 50.0 interestRate = 0.06 dividendYield = 0.04 volatility = 0.40 strikePrice = 50.0 model = FinEquityModelBlackScholes(volatility) discountCurve = FinFlatCurve(valueDate, interestRate) numStepsList = [1000, 2000] testCases.banner("================== EUROPEAN PUT =======================") putOption = FinEquityVanillaOption( expiryDate, strikePrice, FinEquityOptionTypes.EUROPEAN_PUT) value = putOption.value( valueDate, stockPrice, discountCurve, dividendYield, model) delta = putOption.delta( valueDate, stockPrice, discountCurve, dividendYield, model) gamma = putOption.gamma( valueDate, stockPrice, discountCurve, dividendYield, model) theta = putOption.theta( valueDate, stockPrice, discountCurve, dividendYield, model) testCases.header("OPTION_TYPE", "VALUE", "DELTA", "GAMMA", "THETA") testCases.print("EUROPEAN_PUT_BS", value, delta, gamma, theta) option = FinEquityAmericanOption( expiryDate, strikePrice, FinEquityOptionTypes.EUROPEAN_PUT) testCases.header( "OPTION_TYPE", "NUMSTEPS", "VALUE DELTA GAMMA THETA", "TIME") for numSteps in numStepsList: start = time.time() results = option.value( valueDate, stockPrice, discountCurve, dividendYield, model, numSteps) end = time.time() duration = end - start testCases.print("EUROPEAN_PUT_TREE", numSteps, results, duration) testCases.banner("================== AMERICAN PUT =======================") option = FinEquityAmericanOption( expiryDate, strikePrice, FinEquityOptionTypes.AMERICAN_PUT) testCases.header( "OPTION_TYPE", "NUMSTEPS", "VALUE DELTA GAMMA THETA", "TIME") for numSteps in numStepsList: start = time.time() results = option.value( valueDate, stockPrice, discountCurve, dividendYield, model, numSteps) end = time.time() duration = end - start testCases.print("AMERICAN_PUT", numSteps, results, duration) testCases.banner( "================== EUROPEAN CALL =======================") callOption = FinEquityVanillaOption( expiryDate, strikePrice, FinEquityOptionTypes.EUROPEAN_CALL) value = callOption.value( valueDate, stockPrice, discountCurve, dividendYield, model) delta = callOption.delta( valueDate, stockPrice, discountCurve, dividendYield, model) gamma = callOption.gamma( valueDate, stockPrice, discountCurve, dividendYield, model) theta = callOption.theta( valueDate, stockPrice, discountCurve, dividendYield, model) testCases.header("OPTION_TYPE", "VALUE", "DELTA", "GAMMA", "THETA") testCases.print("EUROPEAN_CALL_BS", value, delta, gamma, theta) option = FinEquityAmericanOption( expiryDate, strikePrice, FinEquityOptionTypes.EUROPEAN_CALL) testCases.header( "OPTION_TYPE", "NUMSTEPS", "VALUE DELTA GAMMA THETA", "TIME") for numSteps in numStepsList: start = time.time() results = option.value( valueDate, stockPrice, discountCurve, dividendYield, model, numSteps) end = time.time() duration = end - start testCases.print("EUROPEAN_CALL", numSteps, results, duration) testCases.banner( "================== AMERICAN CALL =======================") testCases.header( "OPTION_TYPE", "NUMSTEPS", "VALUE DELTA GAMMA THETA", "TIME") option = FinEquityAmericanOption( expiryDate, strikePrice, FinEquityOptionTypes.AMERICAN_CALL) for numSteps in numStepsList: start = time.time() results = option.value( valueDate, stockPrice, discountCurve, dividendYield, model, numSteps) end = time.time() duration = end - start testCases.print("AMERICAN_CALL", numSteps, results, duration)
############################################################################### # Copyright (C) 2018, 2019, 2020 Dominic O'Kane ############################################################################### import numpy as np from financepy.utils.global_types import FinOptionTypes from financepy.products.equity.FinEquityVanillaOption import FinEquityVanillaOption from financepy.market.discount.curve_flat import DiscountCurveFlat from financepy.models.black_scholes import FinModelBlackScholes from financepy.utils.date import Date from financepy.utils.FinError import FinError expiryDate = Date(1, 7, 2015) call_option = FinEquityVanillaOption(expiryDate, 100.0, FinOptionTypes.EUROPEAN_CALL) put_option = FinEquityVanillaOption(expiryDate, 100.0, FinOptionTypes.EUROPEAN_PUT) valueDate = Date(1, 1, 2015) stockPrice = 100 volatility = 0.30 interestRate = 0.05 dividendYield = 0.01 model = FinModelBlackScholes(volatility) discountCurve = DiscountCurveFlat(valueDate, interestRate) dividendCurve = DiscountCurveFlat(valueDate, dividendYield) def test_call_option(): v = call_option.value(valueDate, stockPrice, discountCurve, dividendCurve,
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")