Attribute VB_Name = "FINAN_DERIV_BINOMIAL_LIBR" Option Explicit 'Requires that all variables to be declared explicitly. Option Base 1 'The "Option Base" statement allows to specify 0 or 1 as the 'default first index of arrays. '************************************************************************************ '************************************************************************************ '© Copyright NicoSystem 2009. All rights reserved by Rafael Nicolas Fermin Cota, 'San Francisco, CA. USA www.rnfc.org 'nfermincota.hba2005@ivey.ca '************************************************************************************ '************************************************************************************ 'FUNCTION : CRR_BINOMIAL_OPTION_FUNC 'DESCRIPTION : Classical binomial model ' Simplifying algebraic terms in the binomial model of ' Cox-Ross-Rubinstein for american options the ' speed against the usual solution is improved by a ' factor of 40 - 50. '---------------------------------------------------------------------------- ' It does not heal the combinatorical curse of double ' looping for American options ... '---------------------------------------------------------------------------- 'LIBRARY : DERIVATIVES 'GROUP : BINOMIAL 'ID : 001 'AUTHOR : RAFAEL NICOLAS FERMIN COTA 'LAST UPDATE : 01/29/2009 '************************************************************************************ '************************************************************************************ Function CRR_BINOMIAL_OPTION_FUNC(ByVal SPOT As Double, _ ByVal STRIKE As Double, _ ByVal TENOR As Double, _ ByVal RATE As Double, _ ByVal DIVD As Double, _ ByVal SIGMA As Double, _ ByVal nSTEPS As Long, _ Optional ByVal OPTION_FLAG As Integer = 1) Dim i As Long Dim j As Long Dim ii As Double Dim jj As Double Dim DELTA_VAL As Double Dim MULT_VAL As Double Dim FACT_VAL As Double Dim INV_FACT_VAL As Double Dim X_VAL As Double Dim UP_VAL As Double Dim DOWN_VAL As Double Dim PROB_VAL As Double Dim STAR_VAL As Double Dim SQR_VAL As Double Dim TEMP_VAL As Double Dim OPTION_VALUE_ARR As Variant ' working array for Leisen Reimer tree On Error GoTo ERROR_LABEL ReDim OPTION_VALUE_ARR(0 To nSTEPS + 1) If OPTION_FLAG <> 1 Then: OPTION_FLAG = -1 If (0 < nSTEPS And 0 < SPOT And 0 < STRIKE And 0 < TENOR And 0 < SIGMA) Then Else CRR_BINOMIAL_OPTION_FUNC = -2 Exit Function End If X_VAL = STRIKE / SPOT DELTA_VAL = TENOR / CDbl(nSTEPS) FACT_VAL = Exp(RATE * DELTA_VAL) MULT_VAL = Exp((RATE - DIVD) * DELTA_VAL) UP_VAL = Exp(SIGMA * Sqr(DELTA_VAL)) DOWN_VAL = 1 / UP_VAL PROB_VAL = (MULT_VAL - DOWN_VAL) / (UP_VAL - DOWN_VAL) STAR_VAL = 1 - PROB_VAL INV_FACT_VAL = 1 / FACT_VAL SQR_VAL = UP_VAL * UP_VAL ii = UP_VAL ^ (-2 - nSTEPS) For i = 1 To nSTEPS + 1 ii = SQR_VAL * ii TEMP_VAL = OPTION_FLAG * (ii - X_VAL) ' check against pay off If (0 <= TEMP_VAL) Then OPTION_VALUE_ARR(i - 1) = TEMP_VAL Else: OPTION_VALUE_ARR(i - 1) = 0# End If Next i jj = UP_VAL ^ (-2 - nSTEPS) For j = nSTEPS To 1 Step -1 jj = jj * UP_VAL ii = jj For i = 1 To j OPTION_VALUE_ARR(i - 1) = (PROB_VAL * OPTION_VALUE_ARR(i) + _ STAR_VAL * OPTION_VALUE_ARR(i - 1)) * INV_FACT_VAL ii = SQR_VAL * ii TEMP_VAL = OPTION_FLAG * (ii - X_VAL) ' check against pay off If (OPTION_VALUE_ARR(i - 1) <= TEMP_VAL) Then OPTION_VALUE_ARR(i - 1) = TEMP_VAL Else End If Next Next CRR_BINOMIAL_OPTION_FUNC = SPOT * OPTION_VALUE_ARR(0) Exit Function ERROR_LABEL: CRR_BINOMIAL_OPTION_FUNC = Err.number End Function '************************************************************************************ '************************************************************************************ '© Copyright NicoSystem 2009. All rights reserved by Rafael Nicolas Fermin Cota, 'San Francisco, CA. USA www.rnfc.org 'nfermincota.hba2005@ivey.ca '************************************************************************************ '************************************************************************************ 'FUNCTION : CRR_BINOMIAL_GREEKS_FUNC 'DESCRIPTION : Cox-Ross-Rubinstein binomial Greeks 'LIBRARY : DERIVATIVES 'GROUP : BITRINOMIAL 'ID : 002 'AUTHOR : RAFAEL NICOLAS FERMIN COTA 'LAST UPDATE : 01/29/2009 '************************************************************************************ '************************************************************************************ Function CRR_BINOMIAL_GREEKS_FUNC(ByVal SPOT As Double, _ ByVal STRIKE As Double, _ ByVal EXPIRATION As Double, _ ByVal RISK_FREE_RATE As Double, _ ByVal CARRY_COST As Double, _ ByVal VOLATILITY As Double, _ ByVal nSTEPS As Long, _ Optional ByVal OPTION_FLAG As Integer = 1, _ Optional ByVal EXERCISE_TYPE As Integer = 1, _ Optional ByVal COUNT_BASIS As Double = 365, _ Optional ByVal OUTPUT As Integer = 0) 'OPTION_FLAG: 1 --> Call Else: Put 'EXERCISE_TYPE: 0 --> European Else: American Dim i As Long Dim j As Long Dim k As Long Dim U_VAL As Double Dim D_VAL As Double Dim P_VAL As Double Dim DELTA_VAL As Double Dim DISCOUNT_VAL As Double Dim TEMP_VECTOR As Variant Dim OPTION_VALUE_ARR As Variant On Error GoTo ERROR_LABEL ReDim OPTION_VALUE_ARR(0 To nSTEPS + 1) Select Case OPTION_FLAG Case 1 ', "c", "call" 'Call k = 1 Case Else 'Put k = -1 End Select DELTA_VAL = EXPIRATION / nSTEPS U_VAL = Exp(VOLATILITY * Sqr(DELTA_VAL)) D_VAL = 1 / U_VAL P_VAL = (Exp(CARRY_COST * DELTA_VAL) - D_VAL) / (U_VAL - D_VAL) DISCOUNT_VAL = Exp(-RISK_FREE_RATE * DELTA_VAL) For i = 0 To nSTEPS OPTION_VALUE_ARR(i) = MAXIMUM_FUNC(0, k * (SPOT * U_VAL ^ i * _ D_VAL ^ (nSTEPS - i) - STRIKE)) Next i ReDim TEMP_VECTOR(1 To 4, 1 To 2) TEMP_VECTOR(1, 1) = "Option value" TEMP_VECTOR(2, 1) = "Delta" TEMP_VECTOR(3, 1) = "Gamma" TEMP_VECTOR(4, 1) = "Theta" For j = nSTEPS - 1 To 0 Step -1 For i = 0 To j Select Case EXERCISE_TYPE Case 0 ', "e", "EURO" 'European OPTION_VALUE_ARR(i) = (P_VAL * OPTION_VALUE_ARR(i + 1) + _ (1 - P_VAL) * OPTION_VALUE_ARR(i)) * _ DISCOUNT_VAL Case Else 'American OPTION_VALUE_ARR(i) = MAXIMUM_FUNC((k * (SPOT * U_VAL ^ i * _ D_VAL ^ (j - i) - STRIKE)), _ (P_VAL * OPTION_VALUE_ARR(i + 1) + _ (1 - P_VAL) * OPTION_VALUE_ARR(i)) * _ DISCOUNT_VAL) End Select Next i If j = 2 Then TEMP_VECTOR(3, 2) = ((OPTION_VALUE_ARR(2) - _ OPTION_VALUE_ARR(1)) / _ (SPOT * U_VAL ^ 2 - SPOT) _ - (OPTION_VALUE_ARR(1) - _ OPTION_VALUE_ARR(0)) / (SPOT - _ SPOT * D_VAL ^ 2)) / (0.5 * (SPOT * _ U_VAL ^ 2 - SPOT * D_VAL ^ 2)) TEMP_VECTOR(4, 2) = OPTION_VALUE_ARR(1) End If If j = 1 Then TEMP_VECTOR(2, 2) = (OPTION_VALUE_ARR(1) - _ OPTION_VALUE_ARR(0)) / _ (SPOT * U_VAL - SPOT * D_VAL) End If Next j TEMP_VECTOR(4, 2) = (TEMP_VECTOR(4, 2) - OPTION_VALUE_ARR(0)) / _ (2 * DELTA_VAL) / COUNT_BASIS TEMP_VECTOR(1, 2) = OPTION_VALUE_ARR(0) '-------------------------------------------------------------------------------- Select Case OUTPUT '-------------------------------------------------------------------------------- Case 0 '-------------------------------------------------------------------------------- CRR_BINOMIAL_GREEKS_FUNC = TEMP_VECTOR '-------------------------------------------------------------------------------- Case Else '-------------------------------------------------------------------------------- ReDim TEMP_VECTOR(1 To 7, 1 To 2) TEMP_VECTOR(1, 1) = "Critical Volatility" 'Lower volatility than this will give negative probabilities in tree TEMP_VECTOR(2, 1) = "Minimum time nSTEPS" 'Number of time nSTEPS equal or higher that will avoid negative probabilities TEMP_VECTOR(3, 1) = "dt" 'Time STEP TEMP_VECTOR(4, 1) = "u" 'Up jump - Size TEMP_VECTOR(5, 1) = "d" 'Down jump - Size TEMP_VECTOR(6, 1) = "p" 'Up probability TEMP_VECTOR(7, 1) = "1-p" 'One minus up probability TEMP_VECTOR(1, 2) = CARRY_COST * Sqr(DELTA_VAL) TEMP_VECTOR(2, 2) = Int(EXPIRATION / (VOLATILITY / CARRY_COST) ^ 2) + 1 TEMP_VECTOR(3, 2) = EXPIRATION / nSTEPS TEMP_VECTOR(4, 2) = Exp(VOLATILITY * Sqr(DELTA_VAL)) TEMP_VECTOR(5, 2) = Exp(-VOLATILITY * Sqr(DELTA_VAL)) TEMP_VECTOR(6, 2) = (Exp(CARRY_COST * DELTA_VAL) - TEMP_VECTOR(5, 2)) / _ (TEMP_VECTOR(4, 2) - TEMP_VECTOR(5, 2)) TEMP_VECTOR(7, 2) = 1 - TEMP_VECTOR(6, 2) CRR_BINOMIAL_GREEKS_FUNC = TEMP_VECTOR '-------------------------------------------------------------------------------- End Select '-------------------------------------------------------------------------------- Exit Function ERROR_LABEL: CRR_BINOMIAL_GREEKS_FUNC = Err.number End Function '************************************************************************************ '************************************************************************************ '© Copyright NicoSystem 2009. All rights reserved by Rafael Nicolas Fermin Cota, 'San Francisco, CA. USA www.rnfc.org 'nfermincota.hba2005@ivey.ca '************************************************************************************ '************************************************************************************ 'FUNCTION : CRR_MULTI_DIMENSION_BINOMINAL_TREE_FUNC 'DESCRIPTION : Cox-Ross-Rubinstein binomial tree multidimensional 'LIBRARY : DERIVATIVES 'GROUP : BITRINOMIAL 'ID : 003 'AUTHOR : RAFAEL NICOLAS FERMIN COTA 'LAST UPDATE : 01/29/2009 '************************************************************************************ '************************************************************************************ Function CRR_MULTI_DIMENSION_BINOMINAL_TREE_FUNC( _ ByVal SPOT As Double, _ ByVal STRIKE As Double, _ ByVal EXPIRATION As Double, _ ByVal RISK_FREE_RATE As Double, _ ByVal CARRY_COST As Double, _ ByVal VOLATILITY As Double, _ ByVal nSTEPS As Long, _ Optional ByVal OPTION_FLAG As Integer = 1, _ Optional ByVal EXERCISE_TYPE As Integer = 0, _ Optional ByVal VERSION As Integer = 0) ' EXERCISE_TYPE = 0 for European, Else for American Dim i As Long Dim j As Long Dim k As Long Dim U_VAL As Double Dim D_VAL As Double Dim P_VAL As Double Dim DT_VAL As Double Dim DF_VAL As Double Dim NODE_ARR As Variant Dim TREE_MATRIX As Variant On Error GoTo ERROR_LABEL '------------------------------------------------------------------------------------- Select Case VERSION '------------------------------------------------------------------------------------- Case 0 'The well-known Cox-Ross-Rubinstein binomial tree can be used to price ' European and American options ' - on stocks w/o dividends (b=r) ' - on stocks w/o paying continuous dividend yield q (b=r-q) ' - futures (b=0) ' - on currencies (CARRY_COST = RISK_FREE_RATE - rforeign) '------------------------------------------------------------------------------------- ReDim NODE_ARR(0 To nSTEPS + 1) If OPTION_FLAG = 1 Then 'k is the put-call multiplicator k = 1 ' positive for call option Else 'If OPTION_FLAG = "p" Then k = -1 ' negative for put option End If DT_VAL = EXPIRATION / nSTEPS U_VAL = Exp(VOLATILITY * Sqr(DT_VAL)) D_VAL = 1 / U_VAL P_VAL = (Exp(CARRY_COST * DT_VAL) - D_VAL) / (U_VAL - D_VAL) DF_VAL = Exp(-RISK_FREE_RATE * DT_VAL) For i = 0 To nSTEPS NODE_ARR(i) = MAXIMUM_FUNC(0, k * (SPOT * U_VAL ^ i * D_VAL ^ (nSTEPS - i) - STRIKE)) Next i For j = nSTEPS - 1 To 0 Step -1: For i = 0 To j If EXERCISE_TYPE = 0 Then 'European NODE_ARR(i) = (P_VAL * NODE_ARR(i + 1) + (1 - P_VAL) * NODE_ARR(i)) * DF_VAL Else 'If EXERCISE_TYPE = "a" Then 'American NODE_ARR(i) = _ MAXIMUM_FUNC((k * (SPOT * U_VAL ^ i * D_VAL ^ (Abs(i - j)) - STRIKE)), _ (P_VAL * NODE_ARR(i + 1) + (1 - P_VAL) * NODE_ARR(i)) * DF_VAL) End If Next i Next j CRR_MULTI_DIMENSION_BINOMINAL_TREE_FUNC = NODE_ARR(0) 'default first index of arrays. '------------------------------------------------------------------------------------- Case Else ' This adapted 3D function returns at each node of the binomial tree ' - the value of the underlying asset (SPOT) - NODE_ARR(i,j,1) ' - option price - NODE_ARR(i,j,2)' '------------------------------------------------------------------------------------- ReDim NODE_ARR(0 To nSTEPS + 1, 0 To nSTEPS, 0 To 1) ReDim TREE_MATRIX(0 To 2 * (nSTEPS + 1) - 1, 0 To nSTEPS) If OPTION_FLAG = 1 Then 'Call k = 1 Else 'If OPTION_FLAG = "p" Then k = -1 End If DT_VAL = EXPIRATION / nSTEPS U_VAL = Exp(VOLATILITY * Sqr(DT_VAL)) D_VAL = 1 / U_VAL P_VAL = (Exp(CARRY_COST * DT_VAL) - D_VAL) / (U_VAL - D_VAL) DF_VAL = Exp(-RISK_FREE_RATE * DT_VAL) For i = 0 To nSTEPS NODE_ARR(i, nSTEPS, 0) = SPOT * U_VAL ^ i * D_VAL ^ (nSTEPS - i) NODE_ARR(i, nSTEPS, 1) = MAXIMUM_FUNC(0, k * (SPOT * U_VAL ^ i * D_VAL ^ (nSTEPS - i) - STRIKE)) Next i For j = nSTEPS - 1 To 0 Step -1: For i = 0 To j NODE_ARR(i, j, 0) = SPOT * U_VAL ^ i * D_VAL ^ (j - i) If EXERCISE_TYPE = 0 Then 'European NODE_ARR(i, j, 1) = (P_VAL * NODE_ARR(i + 1, j + 1, 1) + _ (1 - P_VAL) * NODE_ARR(i, j + 1, 1)) * DF_VAL Else 'If EXERCISE_TYPE = "a" Then 'American NODE_ARR(i, j, 1) = _ MAXIMUM_FUNC((k * (SPOT * U_VAL ^ i * D_VAL ^ (Abs(i - j)) - STRIKE)), _ (P_VAL * NODE_ARR(i + 1, j + 1, 1) + (1 - P_VAL) * _ NODE_ARR(i, j + 1, 1)) * DF_VAL) End If Next i Next j 'initialize TREE_MATRIX() For j = 0 To UBound(TREE_MATRIX, 2) For i = 0 To UBound(TREE_MATRIX, 1) TREE_MATRIX(i, j) = " " Next i Next j ' For j = nSTEPS To 0 Step -1 'columns For i = 0 To j 'rows TREE_MATRIX(2 * (j - i), j) = NODE_ARR(i, j, 0) TREE_MATRIX(2 * (j - i) + 1, j) = NODE_ARR(i, j, 1) Next i Next j CRR_MULTI_DIMENSION_BINOMINAL_TREE_FUNC = TREE_MATRIX '------------------------------------------------------------------------------------- End Select '------------------------------------------------------------------------------------- Exit Function ERROR_LABEL: CRR_MULTI_DIMENSION_BINOMINAL_TREE_FUNC = Err.number End Function '************************************************************************************ '************************************************************************************ '© Copyright NicoSystem 2009. All rights reserved by Rafael Nicolas Fermin Cota, 'San Francisco, CA. USA www.rnfc.org 'nfermincota.hba2005@ivey.ca '************************************************************************************ '************************************************************************************ 'FUNCTION : BINOMIAL_TREE_OPTION_PRICE_FUNC 'DESCRIPTION : Plain Vanilla Binomial Function 'LIBRARY : DERIVATIVES 'GROUP : BINOMIAL 'ID : 004 'AUTHOR : RAFAEL NICOLAS FERMIN COTA 'LAST UPDATE : 01/29/2009 '************************************************************************************ '************************************************************************************ Function BINOMIAL_TREE_OPTION_PRICE_FUNC(ByVal SPOT As Double, _ ByVal STRIKE As Double, _ ByVal TENOR As Double, _ ByVal RATE As Double, _ ByVal DIVD As Double, _ ByVal SIGMA As Double, _ ByVal nSTEPS As Long, _ Optional ByVal OPTION_FLAG As Integer = 1, _ Optional ByVal EXERCISE_TYPE As Integer = 1) ' EXERCISE_TYPE = 0 for European, Else for American Dim i As Long Dim j As Long Dim UP_VAL As Double Dim DOWN_VAL As Double Dim PROB_VAL As Double Dim DISC_FACT As Double Dim DELTA_TENOR As Double Dim TEMP_VECTOR As Variant On Error GoTo ERROR_LABEL ReDim TEMP_VECTOR(0 To nSTEPS + 1) If OPTION_FLAG <> 1 Then: OPTION_FLAG = -1 DELTA_TENOR = TENOR / nSTEPS UP_VAL = Exp(SIGMA * Sqr(DELTA_TENOR)) DOWN_VAL = 1 / UP_VAL PROB_VAL = (Exp(DIVD * DELTA_TENOR) - DOWN_VAL) / (UP_VAL - DOWN_VAL) DISC_FACT = Exp(-RATE * DELTA_TENOR) For i = 0 To nSTEPS TEMP_VECTOR(i) = MAXIMUM_FUNC(0, OPTION_FLAG * (SPOT * UP_VAL ^ i * _ DOWN_VAL ^ (nSTEPS - i) - STRIKE)) Next i For j = nSTEPS - 1 To 0 Step -1: For i = 0 To j If EXERCISE_TYPE = 0 Then 'European TEMP_VECTOR(i) = (PROB_VAL * TEMP_VECTOR(i + 1) + _ (1 - PROB_VAL) * TEMP_VECTOR(i)) * DISC_FACT Else 'If EXERCISE_TYPE = 1 Then 'American TEMP_VECTOR(i) = MAXIMUM_FUNC((OPTION_FLAG * (SPOT * UP_VAL ^ i * _ DOWN_VAL ^ (Abs(i - j)) - STRIKE)), _ (PROB_VAL * TEMP_VECTOR(i + 1) + (1 - PROB_VAL) * _ TEMP_VECTOR(i)) * DISC_FACT) End If Next i Next j BINOMIAL_TREE_OPTION_PRICE_FUNC = TEMP_VECTOR(0) Exit Function ERROR_LABEL: BINOMIAL_TREE_OPTION_PRICE_FUNC = Err.number End Function '************************************************************************************ '************************************************************************************ '© Copyright NicoSystem 2009. All rights reserved by Rafael Nicolas Fermin Cota, 'San Francisco, CA. USA www.rnfc.org 'nfermincota.hba2005@ivey.ca '************************************************************************************ '************************************************************************************ 'FUNCTION : BINOMIAL_TREE_CONSTANT_PRICE_FUNC 'DESCRIPTION : The following model is built under the assumption that cash paid to 'owners of the underlying, such as dividends and interest, are paid 'continuously at constant rate over the life of the option. This 'assumption is relatively accurate for valuing puts generally, and calls 'on bonds, commodities, currencies and stock index portfolios. 'LIBRARY : DERIVATIVES 'GROUP : BITRINOMIAL 'ID : 005 'AUTHOR : RAFAEL NICOLAS FERMIN COTA 'LAST UPDATE : 01/29/2009 '************************************************************************************ '************************************************************************************ Function BINOMIAL_TREE_CONSTANT_PRICE_FUNC(ByVal SPOT As Double, _ ByVal STRIKE As Double, _ ByVal EXPIRATION As Double, _ ByVal RISK_FREE_RATE As Double, _ ByVal DIVIDEND_YIELD As Double, _ ByVal VOLATILITY As Double, _ ByVal nSTEPS As Long, _ Optional ByVal OPTION_FLAG As Integer = 1, _ Optional ByVal EXERCISE_TYPE As Integer = 0, _ Optional ByVal VERSION As Integer = 0, _ Optional ByVal OUTPUT As Integer = 0) 'SPOT: Underlying asset current price. 'STRIKE: Price at which the underlying can be bought (for calls) or 'sold (for puts). 'EXPIRATION: Maturity scaled on an annualized basis 'RISK_FREE_RATE: The cost of funds for the number of days to MATURITY 'It should corresponds to the period to the record date, not the option MATURITY 'DIVIDEND_YIELD: Yield paid on the underlying asset matching 'the option's MATURITY. 'VOLATILITY: Annualized volatility of the underlying asset price 'nSTEPS --> Number of nSTEPS (e.g. One-month intervals) 'OPTION_FLAG: 1 for call, and -1 for put. 'EXERCISE_TYPE: 0 For European, 1 For American, 2 For Early Exercise Condition 'VERSION: 0 for Standard Cox - Rubinstein tree setup, and 1 for Binomial JR Dim i As Long Dim j As Long Dim SPOT_VECTOR As Variant Dim OPTION_VECTOR As Variant Dim EARLY_VECTOR As Variant Dim DISCOUNT_FACTOR As Double 'Discount Factor Dim DELTA_TIME As Double 'time step in the tree Dim GROWTH_FACTOR As Double Dim UP_STEP_SIZE As Double Dim DOWN_STEP_SIZE As Double Dim PROB_UP_MOVE As Double Dim PROB_DOWN_MOVE As Double On Error GoTo ERROR_LABEL If OPTION_FLAG <> 1 Then: OPTION_FLAG = -1 'Put DELTA_TIME = EXPIRATION / nSTEPS DISCOUNT_FACTOR = Exp(-RISK_FREE_RATE * DELTA_TIME) ' the stock price S move to S*UP_STEP_SIZE and S*DOWN_STEP_SIZE in the ' next time step of the tree Select Case VERSION Case 0 'Standard Cox - Rubinstein tree setup UP_STEP_SIZE = Exp(VOLATILITY * DELTA_TIME ^ (0.5)) DOWN_STEP_SIZE = 1 / UP_STEP_SIZE GROWTH_FACTOR = Exp((RISK_FREE_RATE - DIVIDEND_YIELD) * DELTA_TIME) 'cost of carry term PROB_UP_MOVE = (GROWTH_FACTOR - DOWN_STEP_SIZE) / (UP_STEP_SIZE - DOWN_STEP_SIZE) PROB_DOWN_MOVE = 1 - PROB_UP_MOVE Case Else 'JR UP_STEP_SIZE = Exp(((RISK_FREE_RATE - DIVIDEND_YIELD) - 0.5 * VOLATILITY ^ 2) * DELTA_TIME _ + VOLATILITY * DELTA_TIME ^ (0.5)) DOWN_STEP_SIZE = Exp(((RISK_FREE_RATE - DIVIDEND_YIELD) - 0.5 * VOLATILITY ^ 2) * DELTA_TIME _ - VOLATILITY * DELTA_TIME ^ (0.5)) PROB_UP_MOVE = 0.5 PROB_DOWN_MOVE = (1 - PROB_UP_MOVE) End Select ReDim SPOT_VECTOR(0 To nSTEPS, 1 To 1) ReDim OPTION_VECTOR(0 To nSTEPS, 1 To 1) ReDim EARLY_VECTOR(0 To nSTEPS, 1 To 1) ' Initialise asset prices at MATURITY SPOT_VECTOR(0, 1) = SPOT * (DOWN_STEP_SIZE ^ nSTEPS) For i = 1 To nSTEPS SPOT_VECTOR(i, 1) = SPOT_VECTOR(i - 1, 1) * UP_STEP_SIZE / DOWN_STEP_SIZE Next i ' initialise option values at MATURITY For i = 0 To nSTEPS OPTION_VECTOR(i, 1) = MAXIMUM_FUNC(0#, OPTION_FLAG * SPOT_VECTOR(i, 1) _ - OPTION_FLAG * STRIKE) EARLY_VECTOR(i, 1) = 0 Next i Select Case EXERCISE_TYPE ' stepping back the tree Case 0 ', "EURO" For j = nSTEPS - 1 To 0 Step -1 For i = 0 To j OPTION_VECTOR(i, 1) = DISCOUNT_FACTOR * (PROB_UP_MOVE * _ OPTION_VECTOR(i + 1, 1) + PROB_DOWN_MOVE * OPTION_VECTOR(i, 1)) Next i Next j Case 1 ', "AMER" For j = nSTEPS - 1 To 0 Step -1 For i = 0 To j OPTION_VECTOR(i, 1) = DISCOUNT_FACTOR * (PROB_UP_MOVE * _ OPTION_VECTOR(i + 1, 1) + PROB_DOWN_MOVE * OPTION_VECTOR(i, 1)) SPOT_VECTOR(i, 1) = SPOT_VECTOR(i, 1) * UP_STEP_SIZE OPTION_VECTOR(i, 1) = MAXIMUM_FUNC(OPTION_VECTOR(i, 1), OPTION_FLAG _ * SPOT_VECTOR(i, 1) - OPTION_FLAG * STRIKE) Next i Next j Case Else 'CALCULATING EARLY EXERCISE CONDITIONS For j = nSTEPS - 1 To 0 Step -1 For i = 0 To j OPTION_VECTOR(i, 1) = DISCOUNT_FACTOR * (PROB_UP_MOVE * _ OPTION_VECTOR(i + 1, 1) + PROB_DOWN_MOVE * OPTION_VECTOR(i, 1)) SPOT_VECTOR(i, 1) = SPOT_VECTOR(i, 1) * UP_STEP_SIZE If OPTION_VECTOR(i, 1) > (OPTION_FLAG * SPOT_VECTOR(i, 1) - _ OPTION_FLAG * STRIKE) Then EARLY_VECTOR(i, 1) = (PROB_UP_MOVE * EARLY_VECTOR(i + 1, 1) _ + PROB_DOWN_MOVE _ * EARLY_VECTOR(i, 1)) + DELTA_TIME Else EARLY_VECTOR(i, 1) = 0 End If Next i Next j End Select Select Case OUTPUT Case 0 BINOMIAL_TREE_CONSTANT_PRICE_FUNC = OPTION_VECTOR Case 1 If EXERCISE_TYPE = 2 Then BINOMIAL_TREE_CONSTANT_PRICE_FUNC = EARLY_VECTOR Else BINOMIAL_TREE_CONSTANT_PRICE_FUNC = "PLEASE CHOOSE EXERCISE_TYPE = 2" End If Case Else BINOMIAL_TREE_CONSTANT_PRICE_FUNC = SPOT_VECTOR End Select Exit Function ERROR_LABEL: BINOMIAL_TREE_CONSTANT_PRICE_FUNC = Err.number End Function '************************************************************************************ '************************************************************************************ '© Copyright NicoSystem 2009. All rights reserved by Rafael Nicolas Fermin Cota, 'San Francisco, CA. USA www.rnfc.org 'nfermincota.hba2005@ivey.ca '************************************************************************************ '************************************************************************************ 'FUNCTION : BINOMIAL_TREE_CONSTANT_DELTA_FUNC 'DESCRIPTION : PLAIN_VANILLA_BINOMIAL_DELTA 'LIBRARY : DERIVATIVES 'GROUP : BITRINOMIAL 'ID : 006 'AUTHOR : RAFAEL NICOLAS FERMIN COTA 'LAST UPDATE : 01/29/2009 '************************************************************************************ '************************************************************************************ Function BINOMIAL_TREE_CONSTANT_DELTA_FUNC(ByVal DELTA_SPOT As Double, _ ByVal SPOT As Double, _ ByVal STRIKE As Double, _ ByVal EXPIRATION As Double, _ ByVal RISK_FREE_RATE As Double, _ ByVal DIVIDEND_YIELD As Double, _ ByVal VOLATILITY As Double, _ ByVal nSTEPS As Long, _ Optional ByVal OPTION_FLAG As Integer = 1, _ Optional ByVal EXERCISE_TYPE As Integer = 0, _ Optional ByVal VERSION As Integer = 0) 'SPOT: Underlying asset current price. 'STRIKE: Price at which the underlying can be bought (for calls) or 'sold (for puts). 'EXPIRATION: Maturity scaled on an annualized basis 'RISK_FREE_RATE: The cost of funds for the number of days to MATURITY 'It should corresponds to the period to the record date, not the option MATURITY 'DIVIDEND_YIELD: Yield paid on the underlying asset matching 'the option's MATURITY. 'VOLATILITY: Annualized volatility of the underlying asset price 'nSTEPS --> Number of nSTEPS (e.g. One-month intervals) 'OPTION_FLAG: 1 for call, and -1 for put. 'EXERCISE_TYPE: 0 For European, 1 For American, 2 For Early Exercise Condition 'VERSION: 0 for Standard Cox - Rubinstein tree setup, and 1 for Binomial JR Dim ATEMP_MATRIX As Variant Dim BTEMP_MATRIX As Variant On Error GoTo ERROR_LABEL ATEMP_MATRIX = BINOMIAL_TREE_CONSTANT_PRICE_FUNC(SPOT + DELTA_SPOT, STRIKE, _ EXPIRATION, RISK_FREE_RATE, DIVIDEND_YIELD, VOLATILITY, nSTEPS, OPTION_FLAG, EXERCISE_TYPE, VERSION, 0) BTEMP_MATRIX = BINOMIAL_TREE_CONSTANT_PRICE_FUNC(SPOT, STRIKE, _ EXPIRATION, RISK_FREE_RATE, DIVIDEND_YIELD, VOLATILITY, nSTEPS, OPTION_FLAG, EXERCISE_TYPE, VERSION, 0) BINOMIAL_TREE_CONSTANT_DELTA_FUNC = (ATEMP_MATRIX(LBound(ATEMP_MATRIX, 1), LBound(ATEMP_MATRIX, 2)) _ - BTEMP_MATRIX(LBound(BTEMP_MATRIX, 1), LBound(BTEMP_MATRIX, 2))) / DELTA_SPOT Exit Function ERROR_LABEL: BINOMIAL_TREE_CONSTANT_DELTA_FUNC = Err.number End Function '************************************************************************************ '************************************************************************************ '© Copyright NicoSystem 2009. All rights reserved by Rafael Nicolas Fermin Cota, 'San Francisco, CA. USA www.rnfc.org 'nfermincota.hba2005@ivey.ca '************************************************************************************ '************************************************************************************ 'FUNCTION : BINOMIAL_TREE_NON_CONSTANT_PRICE_FUNC 'DESCRIPTION : 'LIBRARY : DERIVATIVES 'GROUP : BITRINOMIAL 'ID : 007 'AUTHOR : RAFAEL NICOLAS FERMIN COTA 'LAST UPDATE : 01/29/2009 '************************************************************************************ '************************************************************************************ Function BINOMIAL_TREE_NON_CONSTANT_PRICE_FUNC(ByVal SPOT As Double, _ ByVal STRIKE As Double, _ ByVal VOLATILITY As Double, _ ByVal EXPIRATION As Double, _ ByVal nSTEPS As Long, _ ByVal RF_RISK_FREE_RATE As Double, _ ByVal DIVIDEND_YIELD As Double, _ ByRef DIVIDEND_YIELD_RNG As Variant, _ Optional ByVal OUTPUT As Integer = 0) 'VOLATILITY --> Standard Deviation (Ann) 'EXPIRATION --> Time to maturity (yrs) 'nSTEPS --> Number of nSTEPS (e.g. One-month intervals) 'RF_RISK_FREE_RATE --> Riskless RISK_FREE_RATE (Ann) 'DIVIDEND_YIELD--> Dividend Yield -Continuous Payout RISK_FREE_RATE (Ann) 'FIRST ROW OF DIVIDEND_YIELD_RNG MUST BE THE PERIOD IN ASCENDING ORDER 'SECOND ROW OF DIVIDEND_YIELD_RNG MUST BE THE DIVIDEND YIELD (CONTINUOUS PAYOUT 'RISK_FREE_RATE FOR THE PERIOD) 'THIRD ROW OF DIVIDEND_YIELD_RNG MUST BE THE DIVIDEND CASH$$$ '--------------------------Example------------------------------ 'Period 0 1 2 3 '% Div 0.00% 0.00% 0.00% 0.00% '$ Div 0.00 0.00 0.00 0.00 '--------------------------------------------------------------- Dim i As Long Dim j As Long Dim k As Long Dim AROW As Long Dim SROW As Long Dim SCOLUMN As Long Dim TEMP_SUM As Double Dim TEMP_YIELD As Double Dim SPOT_PV As Double Dim GROWTH_FACTOR As Double '(GROWTH_FACTOR) per step Dim UP_STEP_SIZE As Double '(UP_STEP_SIZE) Dim DOWN_STEP_SIZE As Double '(DOWN_STEP_SIZE) Dim PROB_UP_MOVE As Double '(p) Dim DELTA_TIME As Double '(dt) Dim UP_STATE_PRICE As Double Dim DOWN_STATE_PRICE As Double Dim YIELD_MATRIX As Variant Dim ASSET_MATRIX As Variant Dim EURO_CALL_MATRIX As Variant Dim EURO_PUT_MATRIX As Variant Dim AMER_CALL_MATRIX As Variant Dim AMER_PUT_MATRIX As Variant On Error GoTo ERROR_LABEL If nSTEPS <= 1 Then: GoTo ERROR_LABEL YIELD_MATRIX = DIVIDEND_YIELD_RNG If IsArray(YIELD_MATRIX) = False Then: GoTo ERROR_LABEL DELTA_TIME = EXPIRATION / nSTEPS GROWTH_FACTOR = Exp((RF_RISK_FREE_RATE - DIVIDEND_YIELD) * DELTA_TIME) 'per step UP_STEP_SIZE = Exp(VOLATILITY * Sqr(DELTA_TIME)) DOWN_STEP_SIZE = 1 / UP_STEP_SIZE PROB_UP_MOVE = (GROWTH_FACTOR - DOWN_STEP_SIZE) / _ (UP_STEP_SIZE - DOWN_STEP_SIZE) UP_STATE_PRICE = PROB_UP_MOVE * Exp(-RF_RISK_FREE_RATE * DELTA_TIME) DOWN_STATE_PRICE = (1 - PROB_UP_MOVE) * Exp(-RF_RISK_FREE_RATE * DELTA_TIME) If (UBound(YIELD_MATRIX, 2)) < nSTEPS + 1 Then YIELD_MATRIX = MATRIX_ADD_COLUMNS_FUNC(YIELD_MATRIX, UBound(YIELD_MATRIX, 2) + 1, _ (nSTEPS + 1 - UBound(YIELD_MATRIX, 2))) For i = 1 To nSTEPS + 1 YIELD_MATRIX(1, i) = i - 1 Next i End If YIELD_MATRIX = MATRIX_ADD_ROWS_FUNC(YIELD_MATRIX, UBound(YIELD_MATRIX, 2) + 1, 2) 'ADD ROWS FOR THE PRESENT VALUE CALCULATIONS YIELD_MATRIX(4, nSTEPS + 1) = YIELD_MATRIX(3, nSTEPS + 1) / _ GROWTH_FACTOR ^ YIELD_MATRIX(1, nSTEPS + 1) YIELD_MATRIX(5, nSTEPS + 1) = 0 * GROWTH_FACTOR ^ YIELD_MATRIX(1, nSTEPS + 1) TEMP_SUM = YIELD_MATRIX(5, nSTEPS + 1) For i = nSTEPS To 1 Step -1 YIELD_MATRIX(4, i) = YIELD_MATRIX(3, i) / GROWTH_FACTOR ^ _ YIELD_MATRIX(1, i) 'PV(t=0) $ Div TEMP_SUM = TEMP_SUM + YIELD_MATRIX(4, i + 1) YIELD_MATRIX(5, i) = TEMP_SUM * GROWTH_FACTOR ^ _ YIELD_MATRIX(1, i) 'NPV(T=t) Fut $ Div Next i SPOT_PV = SPOT - YIELD_MATRIX(5, 1) ReDim ASSET_MATRIX(0 To nSTEPS * 2 + 2, 0 To nSTEPS + 1) ReDim EURO_CALL_MATRIX(0 To nSTEPS * 2 + 2, 0 To nSTEPS + 1) ReDim EURO_PUT_MATRIX(0 To nSTEPS * 2 + 2, 0 To nSTEPS + 1) ReDim AMER_CALL_MATRIX(0 To nSTEPS * 2 + 2, 0 To nSTEPS + 1) ReDim AMER_PUT_MATRIX(0 To nSTEPS * 2 + 2, 0 To nSTEPS + 1) '---------------------------------------------------------------------------------------- '------------------------------FIRST PASS: ASSET GRID '---------------------------------------------------------------------------------------- j = 2 SCOLUMN = 1 SROW = nSTEPS + 1 ASSET_MATRIX(SROW, 1) = SPOT Do Until j > nSTEPS + 1 k = 1 SCOLUMN = SCOLUMN + 1 SROW = SROW + 1 ASSET_MATRIX(SROW, SCOLUMN) = ((ASSET_MATRIX(SROW - 1, SCOLUMN - 1) - _ YIELD_MATRIX(5, SCOLUMN - 1)) * DOWN_STEP_SIZE + YIELD_MATRIX(5, SCOLUMN) _ + YIELD_MATRIX(3, SCOLUMN)) * (1 - YIELD_MATRIX(2, SCOLUMN)) - _ YIELD_MATRIX(3, SCOLUMN) 'Do the lower cells in the grid' If YIELD_MATRIX(2, SCOLUMN) <> 0 Or YIELD_MATRIX(3, SCOLUMN) <> 0 Then ' Check for dividends' TEMP_YIELD = (ASSET_MATRIX(SROW - 1, SCOLUMN - 1) - _ YIELD_MATRIX(5, SCOLUMN - 1)) * DOWN_STEP_SIZE + _ YIELD_MATRIX(5, SCOLUMN) + YIELD_MATRIX(3, SCOLUMN) Else TEMP_YIELD = 0 End If ASSET_MATRIX(SROW + 1, SCOLUMN) = TEMP_YIELD Do Until k > j - 1 AROW = SROW - 2 * k ASSET_MATRIX(AROW, SCOLUMN) = ((ASSET_MATRIX(AROW + 1, SCOLUMN - 1) - _ YIELD_MATRIX(5, SCOLUMN - 1)) * UP_STEP_SIZE + YIELD_MATRIX(5, SCOLUMN) + _ YIELD_MATRIX(3, SCOLUMN)) * (1 - YIELD_MATRIX(2, SCOLUMN)) - _ YIELD_MATRIX(3, SCOLUMN) 'Do the upper cells in the grid' If YIELD_MATRIX(2, SCOLUMN) <> 0 Or YIELD_MATRIX(3, SCOLUMN) <> 0 Then ' Check for dividends' TEMP_YIELD = (ASSET_MATRIX(AROW + 1, SCOLUMN - 1) - _ YIELD_MATRIX(5, SCOLUMN - 1)) * UP_STEP_SIZE + _ YIELD_MATRIX(5, SCOLUMN) + YIELD_MATRIX(3, SCOLUMN) Else TEMP_YIELD = 0 End If ASSET_MATRIX(AROW + 1, SCOLUMN) = TEMP_YIELD k = k + 1 Loop j = j + 1 Loop '---------------------------------------------------------------------------------- Select Case OUTPUT '---------------------------------------------------------------------------------- Case 0 '---------------------------------------------------------------------------------- ASSET_MATRIX(1, 1) = "ASSET GRID" '------------------------------------HOUSE KEEPING------------------------------------- For j = 1 To UBound(ASSET_MATRIX, 2) For i = 1 To UBound(ASSET_MATRIX, 1) If IsEmpty(ASSET_MATRIX(i, j)) = True Then: ASSET_MATRIX(i, j) = "" Next i Next j '-------------------------------------------------------------------------------------- BINOMIAL_TREE_NON_CONSTANT_PRICE_FUNC = ASSET_MATRIX '---------------------------------------------------------------------------------- Case 1 '---------------------------------------------------------------------------------- '---------------------------------------------------------------------------------------- '------------------------------SECOND PASS: EURO CALL OPTION '---------------------------------------------------------------------------------------- EURO_CALL_MATRIX(1, 1) = "EURO CALL GRID" SROW = (2 * nSTEPS) + 1 SCOLUMN = nSTEPS + 1 j = nSTEPS '--------------------Do loop for payoff values at final period' k = 0 Do Until k = j + 1 AROW = SROW - 2 * k EURO_CALL_MATRIX(AROW, SCOLUMN) = _ MAXIMUM_FUNC(ASSET_MATRIX(AROW, SCOLUMN) - STRIKE, 0) k = k + 1 Loop '------------------------------------Start column loop (over J)' Do Until j = 0 j = j - 1 SCOLUMN = 1 + j SROW = SROW - 1 k = 0 '------------------------------Start row loop (over k)' Do Until k = j + 1 AROW = SROW - (2 * k) EURO_CALL_MATRIX(AROW, SCOLUMN) = EURO_CALL_MATRIX(AROW + 1, _ SCOLUMN + 1) * DOWN_STATE_PRICE _ + EURO_CALL_MATRIX(AROW - 1, SCOLUMN + 1) * UP_STATE_PRICE k = k + 1 Loop Loop '------------------------------------HOUSE KEEPING------------------------------------- For j = 1 To UBound(EURO_CALL_MATRIX, 2) For i = 1 To UBound(EURO_CALL_MATRIX, 1) If IsEmpty(EURO_CALL_MATRIX(i, j)) = True Then: _ EURO_CALL_MATRIX(i, j) = "" Next i Next j BINOMIAL_TREE_NON_CONSTANT_PRICE_FUNC = EURO_CALL_MATRIX '---------------------------------------------------------------------------------------- Case 2 '---------------------------------------------------------------------------------------- '------------------------------THIRD PASS: EURO PUT OPTION '---------------------------------------------------------------------------------------- EURO_PUT_MATRIX(1, 1) = "EURO PUT GRID" SROW = (2 * nSTEPS) + 1 SCOLUMN = nSTEPS + 1 j = nSTEPS '--------------------Do loop for payoff values at final period' k = 0 Do Until k = j + 1 AROW = SROW - 2 * k EURO_PUT_MATRIX(AROW, SCOLUMN) = MAXIMUM_FUNC(STRIKE - _ ASSET_MATRIX(AROW, SCOLUMN), 0) k = k + 1 Loop '------------------------------------Start column loop (over J)' Do Until j = 0 j = j - 1 SCOLUMN = 1 + j SROW = SROW - 1 k = 0 '------------------------------Start row loop (over k)' Do Until k = j + 1 AROW = SROW - (2 * k) EURO_PUT_MATRIX(AROW, SCOLUMN) = EURO_PUT_MATRIX(AROW + 1, SCOLUMN + 1) _ * DOWN_STATE_PRICE + EURO_PUT_MATRIX(AROW - 1, SCOLUMN + 1) * _ UP_STATE_PRICE k = k + 1 Loop Loop '------------------------------------HOUSE KEEPING------------------------------------- For j = 1 To UBound(EURO_PUT_MATRIX, 2) For i = 1 To UBound(EURO_PUT_MATRIX, 1) If IsEmpty(EURO_PUT_MATRIX(i, j)) = True Then: _ EURO_PUT_MATRIX(i, j) = "" Next i Next j BINOMIAL_TREE_NON_CONSTANT_PRICE_FUNC = EURO_PUT_MATRIX '---------------------------------------------------------------------------------- Case 3 '---------------------------------------------------------------------------------------- '------------------------------FORTH PASS: AMER CALL OPTION '---------------------------------------------------------------------------------------- AMER_CALL_MATRIX(1, 1) = "AMER CALL GRID" SROW = (2 * nSTEPS) + 1 SCOLUMN = nSTEPS + 1 j = nSTEPS '--------------------Do loop for payoff values at final period' k = 0 Do Until k = j + 1 AROW = SROW - 2 * k AMER_CALL_MATRIX(AROW, SCOLUMN) = _ MAXIMUM_FUNC(ASSET_MATRIX(AROW, SCOLUMN) - STRIKE, 0) k = k + 1 Loop '------------------------------------Start Column loop (Over J)' Do Until j = 0 j = j - 1 SCOLUMN = 1 + j SROW = SROW - 1 k = 0 '--------------Dividend this period? => base early ex value on pre-div price' '--------------------------------Start row loop (over k)' Do Until k = j + 1 AROW = SROW - (2 * k) AMER_CALL_MATRIX(AROW, SCOLUMN) = _ MAXIMUM_FUNC(MAXIMUM_FUNC(ASSET_MATRIX(AROW, _ SCOLUMN), ASSET_MATRIX(AROW + 1, SCOLUMN)) - STRIKE, _ (AMER_CALL_MATRIX(AROW + 1, SCOLUMN + 1) * DOWN_STATE_PRICE + _ AMER_CALL_MATRIX(AROW - 1, SCOLUMN + 1) * UP_STATE_PRICE)) If AMER_CALL_MATRIX(AROW, SCOLUMN) <> _ AMER_CALL_MATRIX(AROW + 1, SCOLUMN + 1) _ * DOWN_STATE_PRICE + AMER_CALL_MATRIX(AROW - 1, SCOLUMN + 1) * _ UP_STATE_PRICE Then AMER_CALL_MATRIX(AROW - 1, SCOLUMN) = CStr("--> EARLY EX. <--") Else AMER_CALL_MATRIX(AROW - 1, SCOLUMN) = "" End If k = k + 1 Loop Loop '------------------------------------HOUSE KEEPING------------------------------------- For j = 1 To UBound(AMER_CALL_MATRIX, 2) For i = 1 To UBound(AMER_CALL_MATRIX, 1) If IsEmpty(AMER_CALL_MATRIX(i, j)) = True Then: _ AMER_CALL_MATRIX(i, j) = "" Next i Next j BINOMIAL_TREE_NON_CONSTANT_PRICE_FUNC = AMER_CALL_MATRIX '---------------------------------------------------------------------------------- Case Else '---------------------------------------------------------------------------------------- '------------------------------FIFTH PASS: EURO PUT OPTION '---------------------------------------------------------------------------------------- AMER_PUT_MATRIX(1, 1) = "AMER PUT GRID" SROW = (2 * nSTEPS) + 1 SCOLUMN = nSTEPS + 1 j = nSTEPS '--------------------Do loop for payoff values at final period' k = 0 Do Until k = j + 1 AROW = SROW - 2 * k AMER_PUT_MATRIX(AROW, SCOLUMN) = MAXIMUM_FUNC(STRIKE - _ ASSET_MATRIX(AROW, SCOLUMN), 0) k = k + 1 Loop '------------------------------------Start Column loop (Over J)' Do Until j = 0 j = j - 1 SCOLUMN = 1 + j SROW = SROW - 1 k = 0 '--------------Dividend this period? => base early ex value on pre-div price' '--------------------------------Start row loop (over k)' Do Until k = j + 1 AROW = SROW - (2 * k) AMER_PUT_MATRIX(AROW, SCOLUMN) = MAXIMUM_FUNC(STRIKE - _ ASSET_MATRIX(AROW, SCOLUMN), (AMER_PUT_MATRIX(AROW + 1, SCOLUMN + 1) * _ DOWN_STATE_PRICE + AMER_PUT_MATRIX(AROW - 1, SCOLUMN + 1) * _ UP_STATE_PRICE)) If AMER_PUT_MATRIX(AROW, SCOLUMN) <> AMER_PUT_MATRIX(AROW + 1, SCOLUMN + 1) _ * DOWN_STATE_PRICE + AMER_PUT_MATRIX(AROW - 1, SCOLUMN + 1) * _ UP_STATE_PRICE Then AMER_PUT_MATRIX(AROW - 1, SCOLUMN) = CStr("--> EARLY EX. <--") Else AMER_PUT_MATRIX(AROW - 1, SCOLUMN) = "" End If k = k + 1 Loop Loop '------------------------------------HOUSE KEEPING------------------------------------- For j = 1 To UBound(AMER_PUT_MATRIX, 2) For i = 1 To UBound(AMER_PUT_MATRIX, 1) If IsEmpty(AMER_PUT_MATRIX(i, j)) = True Then: _ AMER_PUT_MATRIX(i, j) = "" Next i Next j '-------------------------------------------------------------------------------------- BINOMIAL_TREE_NON_CONSTANT_PRICE_FUNC = AMER_PUT_MATRIX '------------------------------------------------------------------------------------------ End Select '------------------------------------------------------------------------------------------ Exit Function ERROR_LABEL: BINOMIAL_TREE_NON_CONSTANT_PRICE_FUNC = Err.number End Function