Anexo 4 PROGRAMA PARA EL CÁLCULO DEL PRECIO CRITICO MEDIANTE METODOS NUMERICOS BASADOS EN ÁRBOLES BINOMIALES ANEXO 4 PROGRAMA PARA EL CÁLCULO DEL PRECIO CRITICO MEDIANTE METODOS NUMERICOS BASADOS EN ARBOLES BINOMIALES 1. INTERFASES DE ENTRADA DE DATOS La Figura 1 muestra la estructura básica del programa y la Figura 2 muestra las interfases de entrada de datos creadas como parte del modelo formulado para la valoración de opciones con miras a la determinación del Precio Crítico mediante métodos numéricos. Como puede verse, paralelamente con el módulo de cálculo de opciones reales se desarrolló un módulo de cálculo de opciones financieras, sobre el cual no se hace referencia en el cuerpo de la tesis, por no ser parte de sus objetivos, y por tratarse básicamente de un módulo de cálculo de opciones financieras que no se diferencia de los muchos disponibles en el mercado. Este módulo calcula el valor de diverso tipo de opciones, tanto por métodos numéricos (aplicando árboles binomiales) como por métodos analíticos (aplicando las ecuaciones de Black, Scholes y Merton). Centrándonos en el módulo para opciones reales en el mercado eléctrico, vemos que los parámetros de entrada del programa son, tal como se señala en la tesis: 1 • El escenario hidrológico (definición del período hidrológico estándar, en cuanto a duración de cada uno de las condiciones hidroclimáticas que lo conforman). • Parámetros de volatilidad del mercado bajo cada una de tales condiciones hidroclimáticas. • Tasas de descuento libre de riesgo y corregida con prima de riesgo. • Precio en el momento cero o precio “semilla” para el inicio de la simulación del proceso markoviano de variación de dicho precio con el tiempo. • Parámetros económicos y técnicos del proyecto bajo análisis: costo unitario de instalación, costo unitario de operación y factor de planta. Algunos otros parámetros tales como el horizonte de análisis o el número de simulaciones efectuadas en una interación son manipulados internamente. Una vez proporcionada la información básica se procede a seleccionar el método de cálculo del árbol binomial, bien sea exhaustivo o mediante simulaciones. Al terminar de correr el programa proporciona el valor esperado del proyecto, el valor esperado de las opciones de invertir de inmediato y de esperar para invertir, y el valor del precio crítico estimado. Adicionalmente, quien ejecuta el programa puede recoger información como el número de iteraciones efectuadas y los resultados provisionales obtenidos en cada iteración dentro del proceso de aproximaciones sucesivas, y el tiempo de ejecución. Vale la pena aclarar que este programa fue diseñado como una herramienta de modelación de la metodología propuesta en la tesis, y no como un sistema amigable a cualquier usuario, que pueda ser aprovechado en todo su potencial aún por legos en el tema o en la herramienta de programación utilizada. El uso del programa es bastante interactivo con el ambiente Visual, en el cual el 2 usuario debe encontrarse en todo momento. Muchas de las potencialidades del programa, en cuanto sensibilidades a diversos parámetros, fueron manipuladas internamente para efectos de la ejecución de ésta tesis. El numeral siguiente contiene el código de los diferentes módulos que conforman el programa. INICIO Menú Principal OPCIONES REALES En inversiones en generación elélctrica OPCIONES FINANCIERAS ENTRADA DE DATOS SELECCION DEL TIPO EJECUCION Europea Métodos Numéricos Acciones Monedas Indices Futuros Solución Exahustiva Simulaciones Trayectoria Crítica Americana Método Analítico Acciones Monedas Indices Futuros ENTRADA DE DATOS EJECUCION Figura 1. Estructura básica del programa 3 Figura 2. Algunas de las interfases del programa, relativas a Opciones Reales aplicadas a inversiones en el Sector Eléctrico Colombiano 4 Figura 2. Algunas de las interfases del programa, relativas a Opciones Reales aplicadas a inversiones en el Sector Eléctrico Colombiano. (Continuación). 5 2. CODIGO DEL PROGRAMA MenuPrincipal . frm Private Sub Com_MnPpal1_Click() Load OpcFinancieras OpcFinancieras.Visible = True End Sub Private Sub Com_MnPpal2_Click() Load OpcReales_Part1 OpcReales_Part1.Visible = True End Sub OpcReal-1aParte.frm Dim FieldDirty As Boolean Private Sub Cancela_Click() Unload OpcReales_Part1 Unload OpcReales_Part2 Unload OpcReales_Part3 End Sub Private Sub Entrada_Change(Index As Integer) FieldDirty = True End Sub Private Sub ComNext1_Click() OpcReales_Part2.Visible = True End Sub Private Sub Form_Load() Load OpcReales_Part2 Load OpcReales_Part3 Text_hidro(0).Text = Duracion_Normal Text_hidro(1).Text = Duracion_Normal_Nino Text_hidro(2).Text = Duracion_Nino Text_hidro(3).Text = Duracion_Nino_Normal Text_merca(0).Text = Volatilidad_Normal Text_merca(1).Text = Volatilidad_Normal_Nino Text_merca(2).Text = Volatilidad_Nino Text_merca(3).Text = Volatilidad_Nino_Normal Text_hidro(0).Enabled = False Text_hidro(1).Enabled = False Text_hidro(2).Enabled = False Text_hidro(3).Enabled = False Text_merca(0).Enabled = False Text_merca(1).Enabled = False Text_merca(2).Enabled = False Text_merca(3).Enabled = False Text_hidro(0).BackColor = &HE0E0E0 Text_hidro(1).BackColor = &HE0E0E0 Text_hidro(2).BackColor = &HE0E0E0 Text_hidro(3).BackColor = &HE0E0E0 6 Text_merca(0).BackColor = &HE0E0E0 Text_merca(1).BackColor = &HE0E0E0 Text_merca(2).BackColor = &HE0E0E0 Text_merca(3).BackColor = &HE0E0E0 DuraNormal = Duracion_Normal DuraNormalNino = Duracion_Normal_Nino DuraNino = Duracion_Nino DuraNinoNormal = Duracion_Nino_Normal VolatiNormal = Volatilidad_Normal VolatiNormalNino = Volatilidad_Normal_Nino VolatiNino = Volatilidad_Nino VolatiNinoNormal = Volatilidad_Nino_Normal End Sub Private Sub Com_Hidro_Defecto_Click(Index As Integer) Text_hidro(0).Text = Duracion_Normal Text_hidro(1).Text = Duracion_Normal_Nino Text_hidro(2).Text = Duracion_Nino Text_hidro(3).Text = Duracion_Nino_Normal Text_hidro(0).Enabled = False Text_hidro(1).Enabled = False Text_hidro(2).Enabled = False Text_hidro(3).Enabled = False Text_hidro(0).BackColor = &HE0E0E0 Text_hidro(1).BackColor = &HE0E0E0 Text_hidro(2).BackColor = &HE0E0E0 Text_hidro(3).BackColor = &HE0E0E0 End Sub Private Sub Text_hidro_GotFocus(Index As Integer) Text_hidro(Index).SelStart = 0 Text_hidro(Index).SelLength = Len(Text_hidro(Index).Text) End Sub Private Sub Com_Hidro_Usuario_Click(Index As Integer) Text_hidro(0).Enabled = True Text_hidro(1).Enabled = True Text_hidro(2).Enabled = True Text_hidro(3).Enabled = True Text_hidro(0).BackColor = &HFFFFFF Text_hidro(1).BackColor = &HFFFFFF Text_hidro(2).BackColor = &HFFFFFF Text_hidro(3).BackColor = &HFFFFFF End Sub Private Sub Enter_Hidro_Click() DuraNormal = Val(Text_hidro(0).Text) DuraNormalNino = Val(Text_hidro(1).Text) DuraNino = Val(Text_hidro(2).Text) DuraNinoNormal = Val(Text_hidro(3).Text) 'Prueba de escritura: 'Debug.Print CStr(DuraNormal) & CStr(DuraNormalNino) & CStr(DuraNino) & CStr(DuraNinoNormal) End Sub Private Sub Com_merca_Defecto_Click(Index As Integer) Text_merca(0).Text = Volatilidad_Normal Text_merca(1).Text = Volatilidad_Normal_Nino Text_merca(2).Text = Volatilidad_Nino 7 Text_merca(3).Text = Volatilidad_Nino_Normal Text_merca(0).Enabled = False Text_merca(1).Enabled = False Text_merca(2).Enabled = False Text_merca(3).Enabled = False Text_merca(0).BackColor = &HE0E0E0 Text_merca(1).BackColor = &HE0E0E0 Text_merca(2).BackColor = &HE0E0E0 Text_merca(3).BackColor = &HE0E0E0 End Sub Private Sub Text_merca_GotFocus(Index As Integer) Text_merca(Index).SelStart = 0 Text_merca(Index).SelLength = Len(Text_merca(Index).Text) End Sub Private Sub Com_merca_Usuario_Click(Index As Integer) Text_merca(0).Enabled = True Text_merca(1).Enabled = True Text_merca(2).Enabled = True Text_merca(3).Enabled = True Text_merca(0).BackColor = &HFFFFFF Text_merca(1).BackColor = &HFFFFFF Text_merca(2).BackColor = &HFFFFFF Text_merca(3).BackColor = &HFFFFFF End Sub Private Sub Enter_merca_Click() VolatiNormal = Val(Text_merca(0).Text) VolatiNormalNino = Val(Text_merca(1).Text) VolatiNino = Val(Text_merca(2).Text) VolatiNinoNormal = Val(Text_merca(3).Text) 'Prueba de escritura: 'Debug.Print CStr(VolatiNormal) & CStr(VolatiNormalNino) & CStr(VolatiNino) & CStr(VolatiNinoNormal) End Sub OpcReal-2aParte.frm Private Sub Cancela2_Click() Unload OpcReales_Part1 Unload OpcReales_Part2 Unload OpcReales_Part3 End Sub Private Sub ComNext2_Click() OpcReales_Part3.Visible = True End Sub Private Sub ComPrevio2_Click() OpcReales_Part2.Visible = False End Sub Private Sub Form_Load() Text_Gral(0).Text = Tasa_Risk_Free Text_Gral(1).Text = Tasa_Risk_Prime Text_Gral(2).Text = Precio_Hoy Text_Gral(0).Enabled = False Text_Gral(1).Enabled = False 8 Text_Gral(2).Enabled = False Text_Gral(0).BackColor = &HE0E0E0 Text_Gral(1).BackColor = &HE0E0E0 Text_Gral(2).BackColor = &HE0E0E0 TasaRiskFree = Tasa_Risk_Free TasaRiskPrime = Tasa_Risk_Prime PrecioHoy = Precio_Hoy End Sub Private Sub Com_Gral_Defecto_Click(Index As Integer) Text_Gral(0).Text = Tasa_Risk_Free Text_Gral(1).Text = Tasa_Risk_Prime Text_Gral(2).Text = Precio_Hoy Text_Gral(0).Enabled = False Text_Gral(1).Enabled = False Text_Gral(2).Enabled = False Text_Gral(0).BackColor = &HE0E0E0 Text_Gral(1).BackColor = &HE0E0E0 Text_Gral(2).BackColor = &HE0E0E0 End Sub Private Sub Text_gral_GotFocus(Index As Integer) Text_Gral(Index).SelStart = 0 Text_Gral(Index).SelLength = Len(Text_Gral(Index).Text) End Sub Private Sub Com_gral_Usuario_Click(Index As Integer) Text_Gral(0).Enabled = True Text_Gral(1).Enabled = True Text_Gral(2).Enabled = True Text_Gral(0).BackColor = &HFFFFFF Text_Gral(1).BackColor = &HFFFFFF Text_Gral(2).BackColor = &HFFFFFF End Sub Private Sub Enter_gral_Click() TasaRiskFree = Val(Text_Gral(0).Text) TasaRiskPrime = Val(Text_Gral(1).Text) PrecioHoy = Val(Text_Gral(2).Text) 'Prueba de escritura: 'Debug.Print CStr(VolatiNormal) & CStr(VolatiNormalNino) & CStr(VolatiNino) & CStr(VolatiNinoNormal) End Sub Private Sub Text_Proy_Change(Index As Integer) CostoInversion = Val(Text_Proy(0)) FactorPlanta = Val(Text_Proy(1)) CostoOperacion = Val(Text_Proy(2)) End Sub OpcReales-3aParte.frm Private Sub Cancela3_Click() Unload OpcReales_Part1 Unload OpcReales_Part2 Unload OpcReales_Part3 End Sub 9 Private Sub ComNext3_Click() If CheckMetodo(0).Value = 1 Then EjecutaExhaustiva_1 End If If CheckMetodo(1).Value = 1 Then EjecutaSimulacion_1 End If If CheckMetodo(2).Value = 1 Then ' EjecutaWorstPath_1 'este metodo fue finalmente eliminado pues no aplicaba End If If CheckMetodo(3).Enabled And CheckMetodo(3).Value = 1 Then EjecutaAnalitica_1 End If End Sub Private Sub ComPrevio3_Click() OpcReales_Part3.Visible = False End Sub Private Sub Form_GotFocus() If VolatiNormal = VolatiNormalNino _ And VolatiNino = VolatiNinoNormal _ And VolatiNormal = VolatiNino Then CheckMetodo(3).Enabled = True CheckMetodo(3).BackColor = &H80000009 Else CheckMetodo(3).Enabled = False CheckMetodo(3).BackColor = &H80000004 End If End Sub Private Sub Form_Load() For i = 0 To 3 CheckMetodo(i).Value = 0 Next i If VolatiNormal = VolatiNormalNino _ And VolatiNino = VolatiNinoNormal _ And VolatiNormal = VolatiNino Then CheckMetodo(3).Enabled = True CheckMetodo(3).BackColor = &H80000009 Else CheckMetodo(3).Enabled = False CheckMetodo(3).BackColor = &H80000004 End If End Sub Private Sub EjecutaExhaustiva_1() Msg = "Método: EVALUACION EXHAUSTIVA DEL ARBOL BINOMIAL" & Chr(13) & Chr(13) Msg = Msg + "La ejecución de los cálculos por el método de evaluación" & Chr(13) Msg = Msg + "exhaustiva del árbol binomial puede requerir gran cantidad" & Chr(13) Msg = Msg + "de memoria en disco y tiempo de proceso." & Chr(13) Msg = Msg + "No se recomienda utilizar este método para casos con mas de" & Chr(13) Msg = Msg + "20 deltas de tiempo. Si no desea resolución mensual para el" & Chr(13) Msg = Msg + "para el período de analisis establecido, varíe los parámetros" & Chr(13) Msg = Msg + "de entrada antes de ejecutar este método." & Chr(13) & Chr(13) Msg = Msg + "Está seguro que desea continuar ahora?" Estilo = vbYesNo + vbQuestion + vbDefaultButton1 + vbApplicationModal MsgResp = MsgBox(Msg, Estilo, "Ejecución por el método exhaustivo") 10 If MsgResp = vbNo Then Exit Sub End If Load ExeExhaustiva ExeExhaustiva.Show vbModal End Sub Private Sub EjecutaSimulacion_1() Msg = "Método: EVALUACION DEL ARBOL BINOMIAL A TRAVES DE" & Chr(13) Msg = Msg + " UN CONJUNTO DE SIMULACIONES " & Chr(13) & Chr(13) Msg = Msg + "La ejecución de los cálculos por el método de simulaciones" & Chr(13) Msg = Msg + "sucesivas de la trayectoria aleatoria seguida por el precio" & Chr(13) Msg = Msg + "requiere una cantidad de tiempo proporcional al número de" & Chr(13) Msg = Msg + "simulaciones que se desee efectuar en cada iteración." & Chr(13) Msg = Msg + "La precisión del resultado obtenido no es muy alta, si se" & Chr(13) Msg = Msg + "efectua un número razonable de simulaciones. El número total de" & Chr(13) Msg = Msg + "posibles trayectorias es de 2^n." & Chr(13) & Chr(13) Msg = Msg + "Está seguro que desea continuar ahora?" Estilo = vbYesNo + vbQuestion + vbDefaultButton1 + vbApplicationModal MsgResp = MsgBox(Msg, Estilo, "Ejecución por el método de simulación") If MsgResp = vbNo Then Exit Sub End If Load ExeSimulacion ExeSimulacion.Show vbModal End Sub Private Sub EjecutaWorstPath_1() Msg = "Método: EVALUACION DE LA TRAYECTORIA MAS DESFAVORABLE" & Chr(13) Msg = Msg + " EN EL ARBOL BINOMIAL" & Chr(13) & Chr(13) Msg = Msg + "La determinación del Precio Crítico por el método de evaluación" & Chr(13) Msg = Msg + "de la trayectoria mas defavorable que puede seguir el precio" & Chr(13) Msg = Msg + "dentro de las posibles establecidas por el árbol binomial, es" & Chr(13) Msg = Msg + "la manera mas rápida y eficiente dentro de las soluciones numé-" & Chr(13) Msg = Msg + "ricas planteadas, y la que ofrece una mejor aproximación a la" & Chr(13) Msg = Msg + "solución. Se recomienda la aplicación de este método en todos" & Chr(13) Msg = Msg + "los casos." & Chr(13) & Chr(13) Msg = Msg + "Está seguro que desea continuar ahora?" Estilo = vbYesNo + vbQuestion + vbDefaultButton1 + vbApplicationModal MsgResp = MsgBox(Msg, Estilo, "Ejecución por el método de la trayectoria crítica") If MsgResp = vbNo Then Exit Sub End If 'Load ExeWorstPath 'ExeWorstPath.Show vbModal End Sub Private Sub EjecutaAnalitica_1() Msg = "Método: SOLUCION ANALITICA DE LAS ECUACIONES" & Chr(13) & Chr(13) Msg = Msg + "Las ecuaciones diferenciales de segundo orden cuya solución" & Chr(13) Msg = Msg + "arroja expresiones para la determinación del valor del proyecto" & Chr(13) Msg = Msg + "y de la opción de invertir en función del precio en cada delta" & Chr(13) Msg = Msg + "de tiempo, y para el cálculo del precio crítico en función de" & Chr(13) Msg = Msg + "las características del proyecto, parten de la supocisión de" & Chr(13) Msg = Msg + "volatilidad constante durante un período de análisis infinito." & Chr(13) Msg = Msg + "Estos supuestos llevan a valores altos del precio crítico." & Chr(13) & Chr(13) Msg = Msg + "Está seguro que desea continuar ahora?" Estilo = vbYesNo + vbQuestion + vbDefaultButton1 + vbApplicationModal 11 MsgResp = MsgBox(Msg, Estilo, "Ejecución por el método de la trayectoria crítica") If MsgResp = vbNo Then Exit Sub End If Load ExeAnalitica ExeAnalitica.Show vbModal End Sub Exe_Exhaustiva.frm Dim CancelaProcess As Boolean Dim TimeInitial As Variant Private Sub Form_Load() CancelButton.Caption = "Cancel" CancelButton.Cancel = True CancelButton.Default = True CancelaProcess = False Label1.Alignment = vbCenter Label1.Caption = "Presione OK para iniciar la ejecución y" & Chr(13) & "Cancelar o Esc para suspenderla" Label2.Visible = False Label3.Visible = False Label4.Visible = False End Sub Private Sub OKButton_Click() OKButton.Enabled = False CancelaProcess = False Timer1.Enabled = True Timer1.Interval = 1000 Label3.Visible = True Label3.Caption = "0% procesado" EjecutaExhaustiva_Nueva End Sub Private Sub Timer1_Timer() Label2.Caption = "Tiempo de Ejecución: " & Format(Time - TimeInitial, "Long Time") End Sub Private Sub CancelButton_Click() If Not CancelaProcess Then CancelaProcess = True OKButton.Enabled = True Label1.Alignment = vbCenter Label1.Caption = "Proceso detenido por el usuario." & Chr(13) _ & "Presione OK para reiniciarlo, o Esc para regresar" Label2.Visible = False Else Unload ExeExhaustiva End If End Sub Function RoundNum(Num As Variant) As Single Dim NumString As String, NumStringRound As String Dim NumDecimales As Integer Dim DotPosition As Long NumDecimales = 5 NumString = CStr(CDec(Num)) 12 DotPosition = InStr(1, NumString, ".", vbTextCompare) If DotPosition > 0 Then NumStringRound = Left(NumString, DotPosition) If Val(Mid(NumString, DotPosition + NumDecimales + 1, 3)) < Val("500") Then NumStringRound = NumStringRound & Mid(NumString, DotPosition + 1, NumDecimales) Else NumStringRound = NumStringRound & Right(Format(Val(Mid(NumString, DotPosition, NumDecimales + 1)) + 10 ^ (-NumDecimales), "######0." & String(NumDecimales, "0")), NumDecimales) End If Else NumStringRound = NumString End If RoundNum = Val(NumStringRound) RoundNum = Val(Left(NumString, DotPosition) & Mid(NumString, DotPosition + 1, 4)) End Function Private Sub EjecutaExhaustiva_Nueva() 'Trabaja sin el uso de archivos, y sin la concepcion de los sub-arboles 'Calcula todas las trayectorias posibles, y cada una desde el principio hasta el final 'Para la definición de las trayectorias usa un archivo binario del cual lee unos (sube) 'y ceros (baja), el cual es pre-creado mediante el programa CerosyUnos Dim Periodo1 As Single, Periodo2 As Single Dim Periodo3 As Single, Periodo4 As Single Dim NewItera As Boolean Dim NumCiclos As Integer, NumSteps As Integer Dim PercenProcesado As Single, NumIteraciones As Integer Dim NumPaths As Double Dim Msg As String, MsgResp As Integer Dim RndNumber As Single Dim S As Single 'precio comercial del activo al inicio de un subarbol Dim NewS As Single 'valor de S [precio del activo (energia)] momento 0, al inicio de una iteracion Dim OldS As Single 'anterior valor de S para efectos de la iteracion Dim X As Single 'strike price de la opcion Dim r As Single 'tasa libre de riesgo anual Dim z_chosen As Single 'volatilidad anual Dim z(300) As Single Dim T As Double 'Tiempo de maduracion en un sub-arbol, a partir del momento cero Dim DeltaT As Double 'Tamaño del Delta de tiempo que 'se considera para el arbol binomial Dim n As Integer 'numero de particiones de tiempo 'para el arbol binomial Dim u As Double 'delta up Dim d As Double 'delta down Dim p As Double 'probabilidad de que suba el precio Dim q As Double 'tasa de rendimiento cuando hay 'dividendo de pago continuo Dim OldV As Double 'valor del proyecto Dim OldV_Exito As Double 'valor del proyecto Dim NewV As Double Dim NewV_Exito As Double Dim OldP As Double 'probabilidad de llegar a cierto precio Dim NewP As Double Dim Old_r As Double 'tasa de descuento acumulada hasta el nodo Dim New_r As Double Dim OldSini As Double 'Precio semilla para la anterior iteracion Dim NewSini As Double 'Precio semilla para la nueva iteracion 13 Dim CostOpera As Double Dim CeroUno As Byte 'Variable 1/0 que dice si el precio sube o baja en un mes dado Dim ValorEsperadoProyec As Double Dim ValorEsperadoProyec_Exito As Double Dim ValorEsp_X As Double Dim VarCriterio As Single Dim MinS As Double, MaxS As Double Dim NumFile As Integer, NameFile As String Label1.Alignment = vbCenter Label1.Caption = "Ejecución en Proceso." & Chr(13) & "Espere por favor." NumFile = 1 NameFile = "caminos" 'archivo binomial, contiene secuencias de ceros y unos 'creado previamente con otro programa, y utilizado para 'definir exhaustivamente los posible caminos en el arbol binomial CeroUno = 1 S = FactorPlanta * 8760 * PrecioHoy / 1000 'Precio de la energia producida por 1kW instalado en un ano. 'PrecioHoy esta dado en USD/MWh, luego, USD/MWh x MWh/1000kWh x 8760h/año x FC = USD/kW-año S = S / 12 'para hacerlo mensual X = CostoInversion 'strike price = costo de inversion (en el momento cero) CostOpera = CostoOperacion 'dado en USD/kW-anno...Costo de operar un kW instalado durante todo el anno. CostOpera = CostOpera / 12 'para hacerlo mensual r = TasaRiskFree q = Tasa_Risk_Prime - Tasa_Risk_Free 'OJO es una aproximacion que estamos haciendo aqui Periodo1 = DuraNormal Periodo2 = DuraNormal + DuraNormalNino Periodo3 = DuraNormal + DuraNormalNino + DuraNino Periodo4 = DuraNormal + DuraNormalNino + DuraNino + DuraNinoNormal T = Periodo4 n=T 'No. de pasos del sub-arbol binomial (meses duracion del periodo hidrologico) T = T / 12 'esto pasa un T en meses a anos, porque las tasas son anuales DeltaT = 1 / (n / T) 'Sale de la propocionalidad: 'n/(#de deltas en un año)=T/año If Int(Periodo_Analisis * 12 / n) = Periodo_Analisis * 12 / n Then NumCiclos = Periodo_Analisis * 12 / n Else NumCiclos = Int(Periodo_Analisis * 12 / n) + 1 End If NumSteps = Periodo_Analisis * 12 NumPaths = 2 ^ (Periodo_Analisis * 12) 'Crea los arreglos de volatilidad y tasa de descuento que serán usados en adelate, para los cálculos de todas las trayectorias cont = 0 For j = 1 To NumCiclos 'el numero de periodos hidrologicos estandar que hay en el periodo de analisis For i = 1 To n Step 1 'el numero de meses que tiene un periodo hidrologico estandar If i = 1 Or i = Periodo1 + 1 Or i = Periodo2 + 1 _ Or i = Periodo3 + 1 Or i = Periodo4 + 1 Then If i <= Periodo1 Then z_chosen = VolatiNormal ElseIf (i > Periodo1) And (i <= Periodo2) Then z_chosen = VolatiNormalNino ElseIf i > Periodo2 And i <= Periodo3 Then z_chosen = VolatiNino ElseIf i > Periodo3 And i <= Periodo4 Then z_chosen = VolatiNinoNormal End If 14 End If cont = cont + 1 z(cont) = z_chosen Next i Next j 'Comienzo de iteraciones para hallar el Pcritico en aproximaciones sucesivas MinS = 0 'con S=0, CriterioEvaluacion es negativo MaxS = S 'estos extremos son corregidos durante el proceso PercenProcesado = 0 NumIteraciones = 1 TimeInitial = Time Label2.Visible = True Label2.Caption = "Tiempo de Ejecución: " & Format(0, "Long Time") Label4 = "Iteración No.: " & CStr(NumIteraciones) Label4.Visible = True NewItera = True Repeat_Count = 0 OldSini = 0 Do While NewItera Open NameFile For Binary As #NumFile NewSini = S ValorEsperadoProyec_Exito = 0 ValorEsperadoProyec = 0 ValorEsp_X = 0 For ll = 0 To NumPaths - 1 'comienzo de generacion de todos los posibles recorridos por cada iteracion Old_r = 1 'tasa de descuento en el momento cero OldS = NewSini 'precio en el momento cero, de la ll-esimo camino o trayectoria del arbol binomial, en esta iteracion OldP = 1 'probabilidad del precio en el momento cero de cada simulacion OldV = OldS - CostOpera 'suponiendo por el momento que el volumen de ventas = 1, y el costo de operacion = 0 'de hecho Vini deberia ser 0, porque en el periodo cero no deberiamos considerar produccion 'lo dejamos asi por el momento, por la prueba de escritorio OldV_Exito = 0 For i = 1 To NumSteps 'recorre mes a mes cada una de los posibles caminos u = Exp(z(i) * (DeltaT ^ 0.5)) d=1/u ' p = (Exp((r - q) * DeltaT) - d) / (u - d) p = (Exp((r) * DeltaT) - d) / (u - d) New_r = Old_r * Exp(-r * DeltaT) 'Debug.Print "u=" & CStr(u) & " d=" & CStr(d) & " p=" & CStr(p) & " r=" & CStr(New_r) Get #NumFile, , CeroUno 'Debug.Print "cero uno =" & CStr(CeroUno) If CeroUno = 1 Then NewS = OldS * u NewP = OldP * p NewV = OldV + IIf(NewS - CostOpera > 0, _ NewS - CostOpera, 0) * New_r ElseIf CeroUno = 0 Then NewS = OldS * d NewP = OldP * (1 - p) NewV = OldV + IIf(NewS - CostOpera > 0, _ NewS - CostOpera, 0) * New_r End If NewV_Exito = OldV_Exito + IIf(NewS - CostOpera > 0, _ NewS - CostOpera, 0) * New_r / Exp(-r * DeltaT) OldS = NewS OldP = NewP 15 OldV = NewV OldV_Exito = NewV_Exito Old_r = New_r If CancelaProcess Then Exit For End If If i Mod 10 = 0 Then DoEvents End If Next i 'delta de tiempo en uno de los caminos del arbol binomial (cubre todo el periodo de analisis) If CancelaProcess Then Exit For End If If ll Mod 10 = 0 Then DoEvents End If PercenProcesado = PercenProcesado + 1 / NumPaths Label3.Caption = CStr(Int(PercenProcesado * 100)) & "% procesado" Sij = NewS 'Finaliza un camino (la trayectoria completa en todo el periodo operativo) Pij = NewP 'y almacena los resultados al final de la trayectoria Vij = NewV 'Debug.Print "Camino ll=" & CStr(ll) & " S=" & CStr(Sij) & " p=" & CStr(Pij) & " V=" & CStr(Vij) 'Acumula el resultado de la simulacion al Valor esperado de la opcion y del proyecto ValorEsperadoProyec = ValorEsperadoProyec _ + Pij * Vij If NewV_Exito > X Then ValorEsperadoProyec_Exito = ValorEsperadoProyec_Exito _ + Pij * NewV_Exito ValorEsp_X = ValorEsp_X + Pij * X 'Se calcula el valor esperado de proyecto e inversión considerando 'únicamente las trayectorias exitosas. La probabilidad de cada 'trayectoria es la misma, e igual a 1/NumSimula. 'Se asume que NO se invierte en caso de trayectoria no exitosa. 'En trayectoria NO exitosa, Invesión=0, ValorProyecto=0 'Trayectoria exitosa es aquella en la cual V > X al final de la trayec. End If 'Nota: no es necesario descontar a valor presente los valores 'esperados de proyecto y opcion, porque Vij ya esta descontado 'al momento cero (seria descontar estos valores dos veces) Next ll 'siguiente camino dentro de la misma iteracion If CancelaProcess Then Exit Do 'no sigue con mas iteraciones End If 'Valor esperado de la opcion y del proyecto Debug.Print "Valor esperado proyecto casos exitosos en t=1 : " & CStr(ValorEsperadoProyec_Exito) Debug.Print "Valor esperado inversión casos exitosos en t=1 : " & CStr(ValorEsp_X) Debug.Print "Valor esperado proyecto TODOS los casos en t=0 : " & CStr(ValorEsperadoProyec) 'Aplicacion del criterio para la determinacion de Precio Critico: 'Valor esperado proyecto >= Costo Inversion + Valor esperado Opcion DE ESPERAR 'Valor Opción de Esperar = ValorEsp Trayectorias exitosas en t=1 ' - ValorEsp de Inversión en t=1 'este último se calcula como Inversion*(Probabilidad de exito), la cual es 'la sumatoria de las probabilidades de las trayectorias exitosas 'Este valor se descuenta al momento cero para compararlo con el VP del valor 'esperado del proyecto considerando todas las trayectorias 16 'Pasando el costo de inversión al primer miembro de la desigualdad, establecemos 'la condición como: ' VP0 E(proy) - I = exp(-r dt) * [VP1 E(Tray.Exitosas) - E(I)] 'VP0 es valor presente en t=0, VP1 es valor presente en t=1 VoyHaHallarPrecioCritico = True If VoyHaHallarPrecioCritico Then VarCriterio = CDec(ValorEsperadoProyec) - X - Exp(-r * DeltaT) * (CDec(ValorEsperadoProyec_Exito) CDec(ValorEsp_X)) VarCriterio = VarCriterio 'VarCriterio = ValorEsperadoProyec - X - ValorEsperadoOpcion If VarCriterio > -1 And VarCriterio < 1 Then NewItera = False Else If RoundNum(NewSini) = RoundNum(OldSini) Then Repeat_Count = Repeat_Count + 1 If Repeat_Count = 3 Then NewItera = False End If End If If VarCriterio < 0 Then If NewSini > MinS Then If NewSini >= MaxS Then MaxS = NewSini + Abs(MaxS - MinS) S = MaxS MinS = NewSini Else MinS = NewSini S = IIf(MinS > NewSini, MinS, NewSini) + Abs(MaxS - MinS) / 2 End If Else S = IIf(MinS > NewSini, MinS, NewSini) + Abs(MaxS - MinS) / 2 End If Else If NewSini < MaxS Then If NewSini <= MinS Then MinS = NewSini - Abs(MaxS - MinS) S = MinS MaxS = NewSini Else MaxS = NewSini S = IIf(MaxS < NewSini, MaxS, NewSini) - Abs(MaxS - MinS) / 2 End If Else S = IIf(MaxS < S, MaxS, NewSini) - Abs(MaxS - MinS) / 2 End If End If End If End If 'si voy a hallar el precio critico OldSini = NewSini Debug.Print "VarCriterio =" & CStr(VarCriterio) Debug.Print "roundVarCri =" & CStr(RoundNum(VarCriterio)) Debug.Print "oldS= " & CStr(OldSini) & " S= " & CStr(S) PercenProcesado = 0 NumIteraciones = NumIteraciones + 1 Label4 = "Iteración No.: " & CStr(NumIteraciones) 17 Close 'cierra el archivo binomial, con lo cual al volver a abrirlo queda listo para leer desde el primer byte Loop 'cierra el ciclo de iteraciones en busca de Pcritico Debug.Print "Numero Iteraci = " & CStr(NumIteraciones) Debug.Print "TIEMPO inicial = " & Format(TimeInitial, "Long Time") Debug.Print "TIEMPO final = " & Format(Time, "Long Time") Debug.Print "Precio Critico = " & CStr(NewSini) Open "Resultados.txt" For Output As #5 Write #5, "Numero Iteraci = " & CStr(NumIteraciones) Write #5, "TIEMPO inicial = " & Format(TimeInitial, "Long Time") Write #5, "TIEMPO final = " & Format(Time, "Long Time") Write #5, "Precio Critico = " & CStr(NewSini) Write #5, "Valor Esperado Proy. Exitoso en t=1: " & CStr(ValorEsperadoProyec_Exito) Write #5, "Valor esperado Inver. Exitoso en t=1: " & CStr(ValorEsp_X) Write #5, "Valor esperado del proyecto en t=0: " & CStr(ValorEsperadoProyec) Write #5, " " Close Timer1.Enabled = False Label3.Visible = False Label4.Caption = "Proceseo Finalizado" If Not CancelaProcess Then CancelaProcess = True Label1.Alignment = vbLeftJustify Label1.Caption = "Convergencia lograda en el proceso." & Chr(13) _ & Chr(13) & "Para las condiciones establecidas," _ & Chr(13) & "el Precio Crítico estimado es : " _ & Format(NewSini, "#,##0.000") & " US Mils" CancelButton.Caption = "Continuar >" End If End Sub Exe_Simulación.frm Dim CancelaProcess As Boolean Dim TimeInitial As Variant Private Sub Form_Load() CancelButton.Caption = "Cancel" CancelButton.Cancel = True CancelButton.Default = True CancelaProcess = False Label1.Alignment = vbCenter Label1.Caption = "Presione OK para iniciar la ejecución y" & Chr(13) & "Cancelar o Esc para suspenderla" Label2.Visible = False Label3.Visible = False Label4.Visible = False End Sub Private Sub OKButton_Click() OKButton.Enabled = False CancelaProcess = False Timer1.Enabled = True Timer1.Interval = 1000 Label3.Visible = True Label3.Caption = "0% procesado" EjecutaSimulaciones End Sub 18 Private Sub Timer1_Timer() Label2.Caption = "Tiempo de Ejecución: " & Format(Time - TimeInitial, "Long Time") End Sub Private Sub CancelButton_Click() If Not CancelaProcess Then CancelaProcess = True OKButton.Enabled = True Label1.Alignment = vbCenter Label1.Caption = "Proceso detenido por el usuario." & Chr(13) _ & "Presione OK para reiniciarlo, o Esc para regresar" Label2.Visible = False Else Unload ExeSimulacion End If End Sub Private Sub EjecutaSimulaciones() Dim Periodo1 As Single, Periodo2 As Single Dim Periodo3 As Single, Periodo4 As Single Dim NewItera As Boolean Dim NumCiclos As Integer, NumSteps As Integer Dim PercenProcesado As Single, NumIteraciones As Integer Dim NumPaths As Double Dim NumSimula As Double Dim NumSubArboles As Integer Dim Msg As String, MsgResp As Integer Dim RndNumber As Single Dim S As Single 'precio comercial del activo al inicio de un subarbol Dim NewS As Single 'valor de S [precio del activo (energia)] momento 0, al inicio de una iteracion Dim OldS As Single 'anterior valor de S para efectos de la iteracion Dim X As Single 'strike price de la opcion Dim r As Single 'tasa libre de riesgo anual Dim z_chosen As Single 'volatilidad anual Dim z(300) As Single Dim T As Single 'Tiempo de maduracion en un sub-arbol, a partir del momento cero Dim DeltaT As Single 'Tamaño del Delta de tiempo que 'se considera para el arbol binomial Dim n As Integer 'numero de particiones de tiempo 'para el arbol binomial Dim u As Double 'delta up Dim d As Double 'delta down Dim p As Double 'probabilidad de que suba el precio Dim q As Single 'tasa de rendimiento cuando hay 'dividendo de pago continuo Dim OldV As Double 'valor del proyecto descontado a t=0, considerando TODOS los steps Dim NewV As Double Dim OldV_Exito As Double 'valor del proyecto descontado a t=1, considerando todos los steps MENOS el primero Dim NewV_Exito As Double Dim OldP As Double 'probabilidad de llegar a cierto precio Dim NewP As Double Dim Old_r As Double 'tasa de descuento acumulada hasta el nodo Dim New_r As Double Dim OldSini As Single 'Precio semilla para la anterior iteracion Dim NewSini As Single 'Precio semilla para la nueva iteracion Dim Sij As Single 'coleccion de precios finales obtenidos en cada simulacion Dim Pij As Single 'coleccion de las probabilidades correspondientes 19 Dim Vij As Double 'coleccion de valores del proyecto para los paths establecidos en cada simulacion Dim CostOpera As Single Dim ValorEspProyEn0 As Double 'valor esperado del proyecto, en el momento cero, cualquier caso Dim ValorEspProyExitosoEn1 As Double 'valor esperado del proyecto en el momento 1, solo casos exitosos Dim ValorEsp_X As Double 'valor esperado de X considerando sólo las trayectorias exitosas Dim VarCriterio As Single Dim MinS As Single, MaxS As Single Label1.Alignment = vbCenter Label1.Caption = "Ejecución en Proceso." & Chr(13) & "Espere por favor." 'S = PrecioHoy S = FactorPlanta * 8760 * PrecioHoy / 1000 'Precio de la energia producida por 1kW instalado en un ano. 'PrecioHoy esta dado en USD/MWh, luego, USD/MWh x MWh/1000kWh x 8760h/año x FC = USD/kW-año S = S / 12 'para hacerlo mensual X = CostoInversion 'strike price = costo de inversion (en el momento cero) CostOpera = CostoOperacion 'dado en USD/kW-anno...Costo de operar un kW instalado durante todo el anno. CostOpera = CostOpera / 12 'para hacerlo mensual r = TasaRiskFree q = Tasa_Risk_Prime - Tasa_Risk_Free 'es una aproximacion que estamos haciendo aqui Periodo1 = DuraNormal Periodo2 = DuraNormal + DuraNormalNino Periodo3 = DuraNormal + DuraNormalNino + DuraNino Periodo4 = DuraNormal + DuraNormalNino + DuraNino + DuraNinoNormal T = Periodo4 n=T 'No. de pasos del sub-arbol binomial (meses duracion del periodo hidrologico) T = T / 12 'esto pasa un T en meses a anos, porque las tasas son anuales DeltaT = 1 / (n / T) 'Sale de la propocionalidad: 'n/(#de deltas en un año)=T/año If Int(Periodo_Analisis * 12 / n) = Periodo_Analisis * 12 / n Then NumCiclos = Periodo_Analisis * 12 / n Else NumCiclos = Int(Periodo_Analisis * 12 / n) + 1 End If NumSteps = Periodo_Analisis * 12 NumPaths = 2 ^ (Periodo_Analisis * 12) cont = 0 For j = 1 To NumCiclos 'el numero de periodos hidrologicos estandar que hay en el periodo de analisis For i = 1 To n Step 1 'el numero de meses que tiene un periodo hidrologico estandar If i = 1 Or i = Periodo1 + 1 Or i = Periodo2 + 1 _ Or i = Periodo3 + 1 Or i = Periodo4 + 1 Then If i <= Periodo1 Then z_chosen = VolatiNormal ElseIf (i > Periodo1) And (i <= Periodo2) Then z_chosen = VolatiNormalNino ElseIf i > Periodo2 And i <= Periodo3 Then z_chosen = VolatiNino ElseIf i > Periodo3 And i <= Periodo4 Then z_chosen = VolatiNinoNormal End If End If cont = cont + 1 z(cont) = z_chosen Next i Next j NumSimula = 0.2 * Int(2 ^ (Periodo_Analisis * 12)) Randomize Open "Resultados.txt" For Output As #1 20 NumCorridas = 1 For zz = 1 To NumCorridas 'Este FOR se utilizo para hacer n corridas con un mismo número de simulaciones dado S = FactorPlanta * 8760 * PrecioHoy / 1000 S = S / 12 MinS = 0 'con S=0, CriterioEvaluacion es negativo MaxS = S 'estos extremos son corregidos durante el proceso PercenProcesado = 0 NumIteraciones = 1 TimeInitial = Time Label2.Visible = True Label2.Caption = "Tiempo de Ejecución: " & Format(0, "Long Time") Label4 = "Iteración No.: " & CStr(NumIteraciones) Label4.Visible = True NewItera = True Repeat_Count = 0 OldSini = 0 'Comienzo de iteraciones para hallar el Pcritico en aproximaciones sucesivas Do While NewItera 'se quita este Do While si no voy a hallar el precio critico, 'sino los valores esperados con un precio ya dado NewSini = S ValorEspProyExitosoEn1 = 0 ValorEspProyEn0 = 0 ValorEsp_X = 0 NN = NumSimula For ll = 0 To NumSimula - 1 'comienzo de simulaciones por cada iteracion Old_r = 1 OldS = NewSini 'precio en el momento cero, de la ll-esima simulacion de esta iteracion OldP = 1 'probabilidad del precio en el momento cero de cada simulacion OldV = OldS - CostOpera 'estamos suponiendo por el momento que el volumen de ventas = 1, y el costo de operacion = 0 'Vini deberia ser 0, porque en el periodo cero no deberiamos considerar produccion 'lo dejamos asi por el momento, por la prueba de escritorio OldV_Exito = 0 For i = 1 To NumSteps 'recorre mes a mes cada una de los posibles caminos simulados u = Exp(z(i) * (DeltaT ^ 0.5)) d=1/u p = (Exp((r) * DeltaT) - d) / (u - d) New_r = Old_r * Exp(-r * DeltaT) 'Debug.Print "i= " & CStr(i) & " u= " & CStr(u) & " d= " & CStr(d) & " p= " & CStr(p)& " r=" & CStr(New_r) RndNumber = Rnd() If RndNumber >= 0 And RndNumber < p Then NewS = OldS * u NewP = OldP * p ElseIf RndNumber > p And RndNumber <= 1 Then NewS = OldS * d NewP = OldP * (1 - p) End If NewV = OldV + IIf(NewS - CostOpera > 0, _ NewS - CostOpera, 0) * New_r NewV_Exito = OldV_Exito + IIf(NewS - CostOpera > 0, _ NewS - CostOpera, 0) * New_r / Exp(-r * DeltaT) OldS = NewS OldP = NewP OldV = NewV OldV_Exito = NewV_Exito Old_r = New_r 21 If CancelaProcess Then Exit For End If Next i 'delta de tiempo en un ciclo hidrologico If CancelaProcess Then Exit For End If If ll Mod 10 = 0 Then DoEvents End If PercenProcesado = PercenProcesado + 1 / NumSimula Label3.Caption = CStr(Int(PercenProcesado * 100)) & "% procesado" Debug.Print "Simulacion ll=" & CStr(ll) & " S=" & CStr(NewS) & " p=" & CStr(NewP) & " V=" & CStr(NewV) 'Acumula el resultado de la simulacion al Valor esperado de la opcion y del proyecto ValorEspProyEn0 = ValorEspProyEn0 + 1 / NN * NewV 'ya que todas las simulaciones son equiprobables, pues son generadas aleatoriamente If NewV_Exito > X Then ValorEspProyExitosoEn1 = ValorEspProyExitosoEn1 _ + 1 / NN * NewV_Exito ValorEsp_X = ValorEsp_X + 1 / NN * X 'Se calcula el valor esperado de proyecto e inversión considerando 'únicamente las trayectorias exitosas. La probabilidad de cada 'trayectoria es la misma, e igual a 1/NumSimula. 'Se asume que NO se invierte en caso de trayectoria no exitosa. 'En trayectoria NO exitosa, Invesión=0, ValorProyecto=0 'Trayectoria exitosa es aquella en la cual V > X al final de la trayec. End If 'Nota: no es necesario descontar a valor presente los valores 'esperados de proyecto y opcion, porque NewV ya esta descontado 'al momento cero (seria descontar estos valores dos veces), y 'para NewV_exito ya se hizo la corrección, para descontarlo al t=1 Next ll 'siguiente simulacion dentro de la misma iteracion If CancelaProcess Then Exit Do 'no sigue con mas iteraciones End If 'Valor esperado de inversión y proyecto en caso de exito y VE original (en t=0 y considerando TODAS las trayectorias) Debug.Print "Valor esperado proyecto casos exitosos en t=1 : " & CStr(ValorEspProyExitosoEn1) Debug.Print "Valor esperado inversión casos exitosos en t=1 : " & CStr(ValorEsp_X) Debug.Print "Valor esperado proyecto TODOS los casos en t=0 : " & CStr(ValorEspProyEn0) 'Aplicacion del criterio para la determinacion de Precio Critico: 'Valor esperado proyecto >= Costo Inversion + Valor esperado Opcion DE ESPERAR 'Valor Opción de Esperar = ValorEsp Trayectorias exitosas en t=1 ' - ValorEsp de Inversión en t=1 'este último se calcula como Inversion*(Probabilidad de exito), la cual es 'la sumatoria de las probabilidades de las trayectorias exitosas 'Este valor se descuenta al momento cero para compararlo con el VP del valor 'esperado del proyecto considerando todas las trayectorias 'Pasando el costo de inversión al primer miembro de la desigualdad, establecemos 'la condición como: ' VP0 E(proy) - I = exp(-r dt) * [VP1 E(Tray.Exitosas) - E(I)] 'VP0 es valor presente en t=0, VP1 es valor presente en t=1 VoyHaHallarPrecioCritico = True If VoyHaHallarPrecioCritico Then 22 VarCriterio = CDec(ValorEspProyEn0) - X - Exp(-r * DeltaT) * _ (CDec(ValorEspProyExitosoEn1) - CDec(ValorEsp_X)) AUX4 = RoundNum(VarCriterio) AUX4 = AUX4 If AUX4 > -1 And AUX4 < 1 Then NewItera = False Else If RoundNum(NewSini) = RoundNum(OldSini) Then Repeat_Count = Repeat_Count + 1 If Repeat_Count = 3 Then NewItera = False End If End If If VarCriterio < 0 Then If NewSini > MinS Then If NewSini >= MaxS Then MaxS = NewSini + Abs(MaxS - MinS) S = MaxS MinS = NewSini Else MinS = NewSini S = MinS + Abs(MaxS - MinS) / 2 End If Else S = IIf(MinS > NewSini, MinS, NewSini) + Abs(MaxS - MinS) / 2 End If Else If NewSini < MaxS Then If NewSini <= MinS Then MinS = NewSini - Abs(MaxS - MinS) S = MinS MaxS = NewSini Else MaxS = NewSini S = IIf(MaxS < NewSini, MaxS, NewSini) - Abs(MaxS - MinS) / 2 End If Else S = IIf(MaxS < S, MaxS, NewSini) - Abs(MaxS - MinS) / 2 End If End If Pini = 1 Vini = S r_ini = 1 End If 'AUX4 > -1 y <1 OldSini = NewSini Debug.Print "VarCriterio =" & CStr(VarCriterio) Debug.Print "oldS= " & CStr(OldSini) & " S= " & CStr(S) PercenProcesado = 0 NumIteraciones = NumIteraciones + 1 Label4 = "Iteración No.: " & CStr(NumIteraciones) End If 'End If del si VoyHaHallarPrecioCritico o no Loop 'cierra el ciclo de iteraciones en busca de Pcritico Debug.Print "Numero Iteraci = " & CStr(NumIteraciones) Debug.Print "TIEMPO inicial = " & Format(TimeInitial, "Long Time") Debug.Print "TIEMPO final = " & Format(Time, "Long Time") Debug.Print "TIEMPO transcur= " & Format(Time - TimeInitial, "Long Time") 23 Debug.Print "Precio Critico = " & CStr(NewSini) Write #1, "Num Simulaciones= " & CStr(NumSimula) Write #1, "Corrida No. =" & CStr(zz) Write #1, "Numero Iteraci = " & CStr(NumIteraciones) Write #1, "TIEMPO inicial = " & Format(TimeInitial, "Long Time") Write #1, "TIEMPO final = " & Format(Time, "Long Time") Write #1, "Precio Critico = " & CStr(NewSini) Write #1, "Valor Esperado Proy. Exitoso en t=1: " & CStr(ValorEspProyExitosoEn1) Write #1, "Valor esperado Inver. Exitoso en t=1: " & CStr(ValorEsp_X) Write #1, "Valor esperado del proyecto en t=0: " & CStr(ValorEspProyEn0) Write #1, " " Write #1, CStr(NumSimula) & CStr(zz) & CStr(NumIteraciones) & Format(TimeInitial, "Long Time") & Format(Time, "Long Time") & CStr(NewSini) & CStr(ValorEspProyExitosoEn1) & CStr(ValorEsp_X) & CStr(ValorEspProyEn0) Write #1, " " Write #1, " " Timer1.Enabled = False Label3.Visible = False Label4.Caption = "Proceseo Finalizado" If Not CancelaProcess Then CancelaProcess = True Label1.Alignment = vbLeftJustify Label1.Caption = "Convergencia lograda en el proceso." & Chr(13) _ & Chr(13) & "Para las condiciones establecidas," _ & Chr(13) & "el Precio Crítico estimado es : " _ & Format(NewSini, "#,##0.000") & " US Mils" CancelButton.Caption = "Continuar >" End If Next zz Close End Sub Function RoundNum(Num As Variant) As Single Dim NumString As String, NumStringRound As String Dim DotPosition As Long NumString = CStr(CDec(Num)) DotPosition = InStr(1, NumString, ".", vbTextCompare) If DotPosition > 0 Then NumStringRound = Left(NumString, DotPosition) If Val(Mid(NumString, DotPosition + 7, 3)) < Val("500") Then NumStringRound = NumStringRound & Mid(NumString, DotPosition + 1, 6) Else NumStringRound = NumStringRound & Right(Format(Val(Mid(NumString, DotPosition, 7)) + 0.000001, "######0.000000"), 6) End If Else NumStringRound = NumString End If If Val(NumStringRound) = 0 Then RoundNum = 0# Else RoundNum = Val(NumStringRound) End If End Function 24 Exe_Analítica.frm Dim CancelaProcess As Boolean Dim TimeInitial As Variant Private Sub Form_Load() CancelButton.Caption = "Cancel" CancelButton.Cancel = True CancelButton.Default = True CancelaProcess = False Label1.Alignment = vbCenter Label1.Caption = "Presione OK para iniciar la ejecución y" & Chr(13) & "Cancelar o Esc para suspenderla" Label2.Visible = False Label3.Visible = False Label4.Visible = False End Sub Private Sub OKButton_Click() OKButton.Enabled = False CancelaProcess = False Timer1.Enabled = True Timer1.Interval = 1000 'Label3.Visible = True 'Label3.Caption = "0% procesado" EjecutaAnalitica End Sub Private Sub Timer1_Timer() Label2.Caption = "Tiempo de Ejecución: " & Format(Time - TimeInitial, "Long Time") End Sub Private Sub CancelButton_Click() If Not CancelaProcess Then CancelaProcess = True OKButton.Enabled = True Label1.Alignment = vbCenter Label1.Caption = "Proceso detenido por el usuario." & Chr(13) _ & "Presione OK para reiniciarlo, o Esc para regresar" Label2.Visible = False Else Unload ExeAnalitica End If End Sub Private Sub EjecutaAnalitica() 'Se toma la solucion ya planteada en Model_PC.sim, para 'la "Plataforma". Se hacen coincidir los nombres de las 'variables con los utilizados en el modelo en PowerSim. 'La solucion esta basada en Dixit & Pyndick Investment under Uncertainty Dim NumCiclos As Integer, NumSimula As Integer Dim RndNumber As Single Dim Sigma As Single 'Volatilidad, que tiene que ser igual para todos los periodos Dim r As Single 'Retorno libre de riesgo. Tasa de descuento Dim Delta As Single 'Dividendo propio del sector, en este caso, energia 'Delta=Mu-Alfa, siendo Mu el retorno total esperado, y Alfa el retorno de capital '(en analogia con el arrendamiento de una propiedad, Alfa es la valorizacion de la misma, 'y Delta es el canon de su arrendamiento. Mu es el retorno total de la propiedad) 25 Dim Alfa As Single Dim Beta_1 As Single, Beta_2 As Single Dim K_1 As Single, B_2 As Single Dim A As Single Dim P_asterisco As Double 'Precio Critico, todas las demas son parametros de la solucion de la ecuacion Dim FC As Single 'Factor de planta Dim F_de_P As Double 'Valor de la opcion, como funcion del precio (cambia cada DeltaT) Dim V_de_P As Double 'Valor del proyecto, como funcion del precio (cambia cada DeltaT) Dim P_t As Double 'Precio del asset en cada DeltaT Dim P_t_menos_1 As Double 'Precio en el perido inmediatamente anterior Dim P_semilla 'Precio en el momento cero Dim Invers As Single 'Costo unitario de inversion Dim CostoOpera As Single 'Costo de Operacion Dim ValorEsperadoProyec As Double Dim ValorEsperadoOpcion As Double Dim Error As Single Label1.Alignment = vbCenter Label1.Caption = "Ejecución en Proceso." & Chr(13) & "Espere por favor." Sigma = VolatiNormal 'que debe ser igual a la volatilidad en cualquier otro periodo hidrologico r = Tasa_Risk_Free Delta = Tasa_Risk_Prime - Tasa_Risk_Free 'es una aproximacion que estamos haciendo aqui Alfa = Tasa_Risk_Free If Delta = 0 Then NN = MsgBox("ERROR! El parámetro Delta (dividendo) no puede ser igual a CERO", vbCritical, "CANCELACION DEL PROCEDIMIENTO") Exit Sub End If FC = FactorPlanta P_semilla = FactorPlanta * 8760 * PrecioHoy / 1000 'PrecioHoy es en USD/MWh. Se trata de hallar 'P_semilla = PrecioHoy 'el precio de la energia producida por 1 kW instalado 'en un año...USD/MWh x MWh/1000kWh x 8760h/año x FC = USD/kW-año Invers = CostoInversion 'esta dado en USD/kW...Es inversion en 1 kW instalado CostoOpera = CostoOperacion 'esta dado en USD/kW-ano...costos de operacion de un kW instalado en un anno DeltaT = 1 / 12 'porque la unidad de tiempo que usamos es meses 'pero todas las tasas estan dadas anualmente TimeInitial = Time Label2.Visible = True Label2.Caption = "Tiempo de Ejecución: " & Format(0, "Long Time") 'Label4 = "Iteración No.: " & CStr(NumIteraciones) 'Label4.Visible = True 'Todos los parametros para el calculo del precio critico estan dados 'en terminos anuales. Por tanto, la produccion considerada como unidad 'para definicion del precio, ha de ser tambien anual. (Precio 'de energia producida en un anno, costo de produccion anual). Beta_1 = 1 / 2 - (r - Delta) / Sigma ^ 2 + Sqr(((r - Delta) / Sigma ^ 2 - 1 / 2) ^ 2 + 2 * r / Sigma ^ 2) Beta_2 = 1 / 2 - (r - Delta) / Sigma ^ 2 - Sqr(((r - Delta) / Sigma ^ 2 - 1 / 2) ^ 2 + 2 * r / Sigma ^ 2) Debug.Print "beta1=" & CStr(Beta_1) & " beta2=" & CStr(Beta_2) Debug.Print "costoOpera=" & CStr(CostoOperacion) Debug.Print "delta=" & CStr(Delta) & " r=" & CStr(r) If CostoOperacion = 0 Then K_1 = 0 Else K_1 = ((CostoOpera) ^ (1 - Beta_1)) / (Beta_1 - Beta_2) K_1 = K_1 * (Beta_2 / r - (Beta_2 - 1) / Delta) End If If CostoOperacion = 0 Then B_2 = 0 Else 26 B_2 = (CostoOpera ^ (1 - Beta_2)) / (Beta_1 - Beta_2) B_2 = B_2 * (Beta_1 / r - (Beta_1 - 1) / Delta) End If 'Solucion por un metodo numerico de la ecuacion para P* (precio critico) Error = 10000000000# Ecuacion = P_semilla Do While Error > 0.00001 DoEvents P_asterisco = Ecuacion Ecuacion = (Beta_1 * (CostoOpera / r + Invers) - (Beta_1 - Beta_2) * B_2 * P_asterisco ^ Beta_2) * Delta / (Beta_1 - 1) Debug.Print "ecuacion=" & CStr(Ecuacion) Error = Abs(P_asterisco - Ecuacion) Debug.Print "error=" & CStr(Error) If CancelaProcess Then Exit Do End If Loop Debug.Print "Precio Critico=" & CStr(P_asterisco) A = (P_asterisco ^ (1 - Beta_1)) * (Beta_2 * B_2 * (P_asterisco ^ (Beta_2 - 1)) + 1 / Delta) / Beta_1 'Simulacion del comportamiento del precio, y consecuentemente 'del valor del proyecto y del valor de la opcion, para 'determinacion de su Valor Esperado. La simulacion se efectua 'en terminos anuales, ya que todos los parametros estan dados o 'calculados en esos terminos. Hacemos: DeltaT = 1 '1 año, para Alfa, Delta, etc anuales ValorEsperadoOpcion = 0 ValorEsperadoProyec = 0 NumSimula = 100 P_t = P_semilla Randomize NumSimula = 100 For ll = 0 To NumSimula - 1 For i = 0 To Periodo_Analisis P_t_menos_1 = P_t RndNumber = 2 * Rnd - 1 'Debug.Print "RndNumber=" & CStr(RndNumber) 'RndNumber = Rnd() 'OJO OJO ESTE # deberia corresponder a una distribucion 'NORMAL, y no es asi..estamos obteniendo #s con distri uniforme 'Hay que cambiar esto. Rnd retorna un No. entre 0 y 1 (siempre +) P_t = P_t_menos_1 + Alfa * P_t_menos_1 * DeltaT _ + Sigma * P_t_menos_1 * DeltaT * RndNumber V_de_P = IIf(P_t < CostoOpera, K_1 * P_t ^ Beta_1, _ B_2 * P_t ^ Beta_2 + P_t / Delta - CostoOpera / r) F_de_P = IIf(Beta_1 <> 0, A * P_t ^ Beta_1, _ IIf(V_de_P > Invers, V_de_P - Invers, 0)) Next i Debug.Print "simula=" & CStr(ll) Debug.Print "pt=" & CStr(P_t) & " Vp=" & CStr(V_de_P) & " Fp=" & CStr(F_de_P) DoEvents If CancelaProcess Then Exit For End If ValorEsperadoProyec = ValorEsperadoProyec _ + 1 / NumSimula * V_de_P 27 ValorEsperadoOpcion = ValorEsperadoOpcion _ + 1 / NumSimula * F_de_P P_t = P_semilla Next ll Debug.Print "Valor esperado de la opcion al final =" & CStr(ValorEsperadoOpcion) Debug.Print "Valor esperado del proyecto al final =" & CStr(ValorEsperadoProyec) Timer1.Enabled = False Label3.Visible = False Label4.Caption = "Proceseo Finalizado" If Not CancelaProcess Then CancelaProcess = True Label1.Alignment = vbLeftJustify Label1.Caption = "Convergencia lograda en el proceso." & Chr(13) _ & Chr(13) & "Para las condiciones establecidas," _ & Chr(13) & "el Precio Crítico estimado es : " _ & Format(P_asterisco, "#,##0.000") & " US Mils" CancelButton.Caption = "Continuar >" End If End Sub OpcionFinan.frm Private Sub InfoInput_Click() Load InfoBasica InfoBasica.Visible = True End Sub Private Sub OptActivo_Click(Index As Integer) If OptActivo(Index).Value = False Then For i = 0 To 3 If i = Index Then OptActivo(i) = True Else OptActivo(i) = False End If Next i End If Activo = Index End Sub Private Sub OptTipo_Click(Index As Integer) If OptTipo(Index).Value = False Then For i = 0 To 1 If i = Index Then OptTipo(i) = True Else OptTipo(i) = False End If Next i End If TipOpcion = Index End Sub Private Sub Salida_Click() Unload OpcFinancieras End Sub 28 InfoBasicaFinanciera.frm Dim FieldDirty As Boolean Private Sub Cancela_Click() Unload InfoBasica End Sub Private Sub Entrada_Change(Index As Integer) FieldDirty = True End Sub Private Sub Form_Load() If Activo = 0 Then Label_Titulo.Caption = "OPCION SOBRE ACCIONES" Label_Dividendo.Visible = False For i = 0 To 2 OptDividendo(i).Visible = True OptDividendo(i).Enabled = True Next i OptDividendo(0) = True Entrada(6).Left = 3480 Entrada(6).BackColor = &H80000013 Entrada(6).Visible = True Entrada(6).Enabled = False InputDividendos.Visible = True InputDividendos.Enabled = False Else For i = 0 To 2 OptDividendo(i).Visible = False OptDividendo(i).Enabled = False Next i Entrada(6).Left = 3240 Entrada(6).Visible = True Entrada(6).Enabled = True InputDividendos.Enabled = False InputDividendos.Visible = False Select Case Activo Case 1 Label_Titulo.Caption = "OPCION SOBRE MONEDA EXTRANJERA" Label_Dividendo.Caption = "Tasa de interés extranjera libre de riesgo (% anual)" Case 2 Label_Titulo.Caption = "OPCION SOBRE INDICE BURSATIL" Label_Dividendo.Caption = "Rendimiento (dividendo) del portafolio subyacente al indice (% anual)" Case 3 Label_Titulo.Caption = "OPCION SOBRE CONTRATO A FUTURO" Label_Dividendo.Visible = False Entrada(6).Visible = False End Select End If End Sub Private Sub Entrada_GotFocus(Index As Integer) Entrada(Index).SelStart = 0 Entrada(Index).SelLength = Len(Entrada(Index).Text) End Sub 29 Private Sub Entrada_LostFocus(Index As Integer) If Val(Entrada(5).Text) > 30 Then MsgBox "Digite un número menor que 30" Entrada(5).SetFocus Entrada(5).SelStart = 0 Entrada(5).SelLength = Len(Entrada(Index).Text) End If End Sub Private Sub Tiempo1_Click(Index As Integer) If Tiempo1(Index).Value = False Then For i = 0 To 2 If i = Index Then Tiempo1(i) = True Else Tiempo1(i) = False End If Next i End If End Sub Private Sub OptDividendo_Click(Index As Integer) If OptDividendo(Index).Value = False Then For i = 0 To 2 If i = Index Then OptDividendo(i) = True Else OptDividendo(i) = False End If Next i End If Select Case Index Case 0 Entrada(6).Enabled = False Entrada(6).BackColor = &H80000013 InputDividendos.Enabled = False Case 1 Entrada(6).Enabled = True Entrada(6).BackColor = &H80000005 InputDividendos.Enabled = False Case 2 Entrada(6).Enabled = False Entrada(6).BackColor = &H80000013 InputDividendos.Enabled = True End Select End Sub Private Sub ComEjecuta_Click() Dim i As Integer, j As Integer Dim d1 As Double, d2 As Double Dim Msg As String, MsgResp As Integer Dim S As Double 'precio comercial del activo Dim X As Double 'strike price de la opcion Dim r As Single 'tasa libre de riesgo anual Dim z As Single 'volatilidad anual Dim T As Single 'Tiempo de maduracion a partir de ahora Dim DeltaT As Single 'Tamaño del Delta de tiempo que 'se considera para el arbol binomial 30 Dim n As Integer 'numero de particiones de tiempo 'para el arbol binomial Dim u As Double 'delta up Dim d As Double 'delta down Dim p As Double 'probabilidad de que suba el precio Dim q As Single 'tasa de rendimiento cuando hay 'dividendo de pago continuo Dim Sij() As Single 'valor del activo en el 'periodo i, nodo j Dim c_fij() As Single 'valor de la opcion call en el 'periodo i, nodo j Dim p_fij() As Single 'valor de la opcion put en el 'periodo i, nodo j For i = 0 To 5 If Not IsNumeric(Entrada(i).Text) Then Msg = "La entrada en todos los campos debe ser numérica" Msg = Msg + Chr(13) + " Intente nuevamente" Estilo = vbOKOnly + vbCritical + vbDefaultButton1 + vbApplicationModal MsgResp = MsgBox(Msg, Estilo, "Tipo de dato incorrecto") Exit Sub End If Next i S = Val(Entrada(0).Text) X = Val(Entrada(1).Text) r = Val(Entrada(2).Text) z = Val(Entrada(3).Text) T = Val(Entrada(4).Text) n = Val(Entrada(5).Text) q = Val(Entrada(6).Text) If Tiempo1(0) Then T = T / 365 ElseIf Tiempo1(1) Then T = T / 12 End If DeltaT = 1 / (n / T) 'Sale de la propocionalidad: 'n/(#de deltas en un año)=T/año ReDim Sij(n, n) As Single ReDim c_fij(n, n) As Single ReDim p_fij(n, n) As Single u = Exp(z * (DeltaT ^ 0.5)) d=1/u p = (Exp((r - q) * DeltaT) - d) / (u - d) 'binomial resumida (solo sirve para Europeas) If TipOpcion = 0 Then ca = 0 'call price pu = 0 'put price For j = 0 To n ca = ca + fac(n, j) * (p ^ j * (1 - p) ^ (n - j)) * IIf(0 > u ^ j * d ^ (n - j) * S - X, 0, u ^ j * d ^ (n - j) * S - X) * Exp(-(r - q) * n * DeltaT) pu = pu + fac(n, j) * (p ^ j * (1 - p) ^ (n - j)) * IIf(0 > X - u ^ j * d ^ (n - j) * S, 0, X - u ^ j * d ^ (n - j) * S) * Exp(-(r - q) * n * DeltaT) Next j Debug.Print "binomial Europea" Debug.Print "call= " & CStr(ca) Debug.Print "put = " & CStr(pu) End If 'binomial completa If TipOpcion = 1 Then 31 Call ArbolBinomial(S, X, r, z, n, q, DeltaT, Sij(), c_fij(), p_fij()) 'Estimados de los hedge parameters: ' delta: cambio en el precio de la opcion, respecto al cambio en el precio del activo S ' gamma: cambio en Delta, respecto al cambio en S (aqui se calcula en el tiempo 2DeltaT) ' theta: cambio en el precio de la opcion con el tiempo, cuando todo lo demas es constante ' vega : cambio en el precio de la opcion, dado un cambio en la volatilidad (es necesario recalcular el arbol) ' Rho : c_delta = (c_fij(1, 1) - c_fij(1, 0)) / (S * u - S * d) c_gamma = ((c_fij(2, 2) - c_fij(2, 1)) / (S * u ^ 2 - S) - (c_fij(2, 1) - c_fij(2, 0)) / (S - S * d ^ 2)) / (0.5 * (S * u ^ 2 - S * d ^ 2)) c_theta = (c_fij(2, 1) - c_fij(0, 0)) / (2 * DeltaT) p_delta = (p_fij(1, 1) - p_fij(1, 0)) / (S * u - S * d) p_gamma = ((p_fij(2, 2) - p_fij(2, 1)) / (S * u ^ 2 - S) - (p_fij(2, 1) - p_fij(2, 0)) / (S - S * d ^ 2)) / (0.5 * (S * u ^ 2 - S * d ^ 2)) p_theta = (p_fij(2, 1) - p_fij(0, 0)) / (2 * DeltaT) Debug.Print "delta= " & CStr(p_delta) Debug.Print "gamma= " & CStr(p_gamma) Debug.Print "theta= " & CStr(p_theta) End If 'black-scholes (revisar) d1 = (Log(S / X) + (r - q + z ^ 2 / 2) * T) / (z * T ^ 0.5) d2 = d1 - (z * T ^ 0.5) ca = S * Exp(-q * T) * DistNormal(d1) - X * Exp(-r * T) * DistNormal(d2) pu = X * Exp(-r * T) * DistNormal(-d2) - S * Exp(-q * T) * DistNormal(-d1) Debug.Print "black-sholes" Debug.Print "call= " & CStr(ca) Debug.Print "put = " & CStr(pu) End Sub Sub ArbolBinomial(S As Double, X As Double, _ r As Single, z As Single, _ n As Integer, q As Single, _ DeltaT As Single, _ Sij, c_fij, p_fij) u = Exp(z * (DeltaT ^ 0.5)) d=1/u p = (Exp((r - q) * DeltaT) - d) / (u - d) Debug.Print "Binomial Americana" For i = n To 0 Step -1 For j = i To 0 Step -1 Sij(i, j) = S * u ^ j * d ^ (i - j) If i = n Then c_fij(i, j) = IIf(Sij(i, j) - X > 0, Sij(i, j) - X, 0) p_fij(i, j) = IIf(X - Sij(i, j) > 0, X - Sij(i, j), 0) Else Aux1 = Sij(i, j) - X Aux2 = Exp(-(r) * DeltaT) * (p * c_fij(i + 1, j + 1) + (1 - p) * c_fij(i + 1, j)) c_fij(i, j) = IIf(Aux1 > Aux2, Aux1, Aux2) Aux1 = X - Sij(i, j) Aux2 = Exp(-(r) * DeltaT) * (p * p_fij(i + 1, j + 1) + (1 - p) * p_fij(i + 1, j)) p_fij(i, j) = IIf(Aux1 > Aux2, Aux1, Aux2) End If Debug.Print "i= " & CStr(i) & " j= " & CStr(j) Debug.Print "s= " & CStr(Sij(i, j)) & " c=" & CStr(c_fij(i, j)) & " p=" & CStr(p_fij(i, j)) Next j 32 Next i End Sub Function fac(num1 As Integer, num2 As Integer) As Double Dim fac1 As Double, fac2 As Double fac1 = 1 fac2 = 1 fac3 = 1 For i = 1 To num1 fac1 = fac1 * i Next i For i = 1 To num2 fac2 = fac2 * i Next i For i = 1 To (num1 - num2) fac3 = fac3 * i Next i fac = fac1 / fac2 / fac3 End Function Function DistNormal(param As Double) As Double Y = Abs(param) PI = 3.14159265358979 Alfa = 0.33267 a1 = 0.4361836 a2 = -0.1201676 a3 = 0.937298 k = 1 / (1 + Alfa * Y) NorPrima = Exp(-Y ^ 2 / 2) / (2 * PI) ^ 0.5 DistNormal = 1 - (a1 * k + a2 * k ^ 2 + a3 * k ^ 3) * NorPrima If param < 0 Then DistNormal = 1 - DistNormal End If End Function ModuloOpciones.bas Public PrecioHoy As Single Public CostoInversion As Single Public FactorPlanta As Single Public Const Volatilidad_Nino_Normal = 1 Public Const Tasa_Risk_Free = 0.08 Public Const Tasa_Risk_Prime = 0.14 Public Const Precio_Hoy = 20 Public Const Periodo_Analisis = 20 'años Variable a ser definida internamente Public Const errdbBaseAlreadyExists = 3204 Public Const Duracion_Nino = 12 Public Const Duracion_Nino_Normal = 4 Public Const Volatilidad_Normal = 0.5 Public Const Volatilidad_Normal_Nino = 1 Public Const Volatilidad_Nino = 0.75 Public Activo As Integer '0 = Stock '1 = Currency '2 = Index (stock index) '3 = Futures Public TipOpcion As Integer '0 = Europea '1 = Americana Public DuraNormal As Single Public DuraNormalNino As Single Public DuraNino As Single Public DuraNinoNormal As Single Public VolatiNormal As Single Public VolatiNormalNino As Single Public VolatiNino As Single Public VolatiNinoNormal As Single Public TasaRiskFree As Single Public TasaRiskPrime As Single Public CostoOperacion As Single Public Const Duracion_Normal = 36 'meses Public Const Duracion_Normal_Nino = 4 33