Curso de Programación. 11.2. Aplicar salidas desde la primera barra.
Esta semana vamos a dedicar el artículo de programación a la aplicación de las órdenes de salida desde la primera barra. Esta cuestión puede carecer de importancia para muchos, si bien aquellos que estén habituados a diseñar sistemas habrán observado cómo, efectivamente, nos podemos encontrar con un problema durante la primera barra de negociación de cada entrada en caso de no realizar una gestión lo suficientemente adecuada.
A continuación, vamos a explicar ésta causística y seguidamente usaremos un sistema basado en el indicador PivotPoint01 para ilustrar el proceso que hay que seguir.
Relativo a las órdenes de salida
Cuando diseñamos una estrategia automática y le añadimos operaciones de salida (objetivo de ganancias y stop de pérdidas), el proceso a seguir normalmente suele ser siempre similar. Pudiéndose resumir en los dos siguientes puntos:
1. Comprobamos si hay posiciones abiertas utilizando la función GetMarketPosition().
2. En caso de haberlas, lanzamos las órdenes de salida en función del precio de entrada, valor que nos es devuelto a través de la función GetEntryPrice().
Como vemos, éstas dos funciones son la base (salvo excepciones) para poder elaborar las órdenes de salida. Sin embargo, existe un problema común: Tanto una como otra función no actualizan sus datos hasta el cierre de la primera barra de negociación. Ejemplo: Si trabajamos en una compresión temporal de 60 minutos, y enviamos una nueva entrada a largos a las 15:00, GetMarketPosition() no actualiza su valor a 1 hasta las 16:00, esto es, hasta el cierre de la barra siguiente al lanzamiento de la orden.
¿Qué supone esto? Pues que, siguiendo el ejemplo, entre las 15:00 y las 16:00 tendremos una posición abierta al descubierto, ya que las órdenes de salida no se activan hasta las 16:00 horas.
El problema se acentúa conforme la compresión temporal es mayor, obviamente. En la imagen siguiente queda patente el problema:
El sistema usa un stop de pérdidas de 10 puntos. Entre el cierre de las 15:00 y el cierre de las 16:00 el movimiento del precio ha sido de 31 puntos, de modo que a la hora de enviar la orden de salida, el precio ya está muy por debajo de la misma, de ahí que la orden se cierre al precio de mercado. De ponernos un nivel máximo de pérdidas de 250 euros, hemos pasado a perder 775.
¿Qué hacer entonces? La solución que proponemos consistiría en realizar dos gestiones de órdenes de salida dentro del código del sistema:
1) Realizar una gestión de salida especial para la primera barra de vida de cada negocio.
2) Realizar la gestión de salida normal para el resto de barras (segunda, tercera, cuarta, etc...).
Gestión de salidas en primera barra
Para la gestión de salida especial tenemos un problema, y es que, tal y como hemos visto, no podemos hacer uso de las funciones GetMarketPosition() y sobre todo GetEntryPrice(). Por lo que realizaríamos el siguiente proceso:
1) Definir las órdenes de salida a la vez que se envía la orden de entrada en lugar de esperar a que la función GetMarketPosition() confirme la posición.
2) Usar precio actual (Close()) en caso de entrar a mercado o bien usar el precio de la orden de entrada en caso de que la orden sea en stop. Si la entrada es de tipo limitada, no es aconsejable enviar las órdenes de salida en la primera barra (este tema lo abordaremos más adelante).
Para que nos hagamos una idea, el diseño del sistema (en VBA) sería tal que así:
Estrategia Cruce con Pivot Point
Para finalizar, vamos a trasladar lo visto sobre una estrategia real. En este caso, aprovechamos el estudio del Pivot Point para desarrollar una estrategia que siga las siguientes consideraciones:
1) Cuando el precio cruce el nivel P + Filtro, tomar posiciones largas.
2) Cuando el precio cruce el nivel P - Filtro, tomar posiciones cortas.
3) Colocar un stop al nivel S1 o R1, según el sentido de la operación.
Además, debemos de controlar que el stop esté activo desde la primera barra.
Por último, añadiremos un horario ya que el sistema sólo va a operar en intradía.
El diseño del sistema quedaría de la siguiente forma:
Código PDV
Código VBA
A continuación, vamos a explicar ésta causística y seguidamente usaremos un sistema basado en el indicador PivotPoint01 para ilustrar el proceso que hay que seguir.
Relativo a las órdenes de salida
Cuando diseñamos una estrategia automática y le añadimos operaciones de salida (objetivo de ganancias y stop de pérdidas), el proceso a seguir normalmente suele ser siempre similar. Pudiéndose resumir en los dos siguientes puntos:
1. Comprobamos si hay posiciones abiertas utilizando la función GetMarketPosition().
2. En caso de haberlas, lanzamos las órdenes de salida en función del precio de entrada, valor que nos es devuelto a través de la función GetEntryPrice().
Como vemos, éstas dos funciones son la base (salvo excepciones) para poder elaborar las órdenes de salida. Sin embargo, existe un problema común: Tanto una como otra función no actualizan sus datos hasta el cierre de la primera barra de negociación. Ejemplo: Si trabajamos en una compresión temporal de 60 minutos, y enviamos una nueva entrada a largos a las 15:00, GetMarketPosition() no actualiza su valor a 1 hasta las 16:00, esto es, hasta el cierre de la barra siguiente al lanzamiento de la orden.
¿Qué supone esto? Pues que, siguiendo el ejemplo, entre las 15:00 y las 16:00 tendremos una posición abierta al descubierto, ya que las órdenes de salida no se activan hasta las 16:00 horas.
El problema se acentúa conforme la compresión temporal es mayor, obviamente. En la imagen siguiente queda patente el problema:
El sistema usa un stop de pérdidas de 10 puntos. Entre el cierre de las 15:00 y el cierre de las 16:00 el movimiento del precio ha sido de 31 puntos, de modo que a la hora de enviar la orden de salida, el precio ya está muy por debajo de la misma, de ahí que la orden se cierre al precio de mercado. De ponernos un nivel máximo de pérdidas de 250 euros, hemos pasado a perder 775.
¿Qué hacer entonces? La solución que proponemos consistiría en realizar dos gestiones de órdenes de salida dentro del código del sistema:
1) Realizar una gestión de salida especial para la primera barra de vida de cada negocio.
2) Realizar la gestión de salida normal para el resto de barras (segunda, tercera, cuarta, etc...).
Gestión de salidas en primera barra
Para la gestión de salida especial tenemos un problema, y es que, tal y como hemos visto, no podemos hacer uso de las funciones GetMarketPosition() y sobre todo GetEntryPrice(). Por lo que realizaríamos el siguiente proceso:
1) Definir las órdenes de salida a la vez que se envía la orden de entrada en lugar de esperar a que la función GetMarketPosition() confirme la posición.
2) Usar precio actual (Close()) en caso de entrar a mercado o bien usar el precio de la orden de entrada en caso de que la orden sea en stop. Si la entrada es de tipo limitada, no es aconsejable enviar las órdenes de salida en la primera barra (este tema lo abordaremos más adelante).
Para que nos hagamos una idea, el diseño del sistema (en VBA) sería tal que así:
If (.GetMarketPosition = 1) Then
'salida largos
.ExitLong AtStop, Contratos, .GetEntryPrice() - StopLoss
ElseIf (.GetMarketPosition = -1) Then
'salida cortos
.ExitShort AtStop, Contratos, .GetEntryPrice() + StopLoss
Else
'entradas
If (--- reglas de entrada a largo ---) Then
.Buy AtClose, Contratos
.ExitLong AtStop, Contratos, .Close() - StopLoss
ElseIf (--- reglas de entrada a corto ---) Then
.Sell AtClose, Contratos
.ExitShort AtStop, Contratos, .Close() + StopLoss
End If
End If
Estrategia Cruce con Pivot Point
Para finalizar, vamos a trasladar lo visto sobre una estrategia real. En este caso, aprovechamos el estudio del Pivot Point para desarrollar una estrategia que siga las siguientes consideraciones:
1) Cuando el precio cruce el nivel P + Filtro, tomar posiciones largas.
2) Cuando el precio cruce el nivel P - Filtro, tomar posiciones cortas.
3) Colocar un stop al nivel S1 o R1, según el sentido de la operación.
Además, debemos de controlar que el stop esté activo desde la primera barra.
Por último, añadiremos un horario ya que el sistema sólo va a operar en intradía.
El diseño del sistema quedaría de la siguiente forma:
Código PDV
Código VBA
'¡¡ Parameters
Dim Contratos As Long '1
Dim Filtro As Double '5
Dim HoraIni As Integer '930
Dim HoraFin As Double '1900
'Parameters !!
Dim pvtdata As DataIdentifier
Option Explicit
Public APP As SysUserApp
Implements System
Public Sub System_OnInitCalculate()
With APP
Dim horainipvt As Double
horainipvt = .GetSymbolInfo(SbiFirstSessionStart)
pvtdata = .GII(PVTPOINT01, Data, horainipvt, 0)
End With
End Sub
Public Sub System_OnCalculateBar(ByVal Bar As Long)
With APP
Dim r1 As Double
Dim p As Double
Dim pant As Double
Dim s1 As Double
'niveles
r1 = .GetIndicatorValue(pvtdata, 0, 2)
p = .GetIndicatorValue(pvtdata, 0, 3)
s1 = .GetIndicatorValue(pvtdata, 0, 4)
pant = .GetIndicatorValue(pvtdata, 1, 3)
If (.Time >= HoraIni And .Time < HoraFin) Then
If (.GetMarketPosition = 1) Then
'salida largos
.ExitLong AtStop, Contratos, s1
ElseIf (.GetMarketPosition = -1) Then
'salida cortos
.ExitShort AtStop, Contratos, r1
End If
'entradas
If (.Close() > p + Filtro And .Close(1) <= pant + Filtro) Then
.Buy AtClose, Contratos
.ExitLong AtStop, Contratos, s1
ElseIf (.Close() < p - Filtro And .Close(1) >= pant - Filtro) Then
.Sell AtClose, Contratos
.ExitShort AtStop, Contratos, r1
End If
Else
If (.GetMarketPosition = 1) Then
.ExitLong AtClose, Contratos
ElseIf (.GetMarketPosition = -1) Then
.ExitShort AtClose, Contratos
End If
End If
End With
End Sub
Comentarios
Publicar un comentario