Estructura básica de un sistema en VBA

A la hora de diseñar un sistema utilizando el entorno VBA se suelen repetir ciertos patrones de diseño, lo cual nos permite generar un modelo básico de estructura de sistemas, facilitándonos la labor de desarrollo y disminuyendo el nivel de errores a la hora de programar.

Un ejemplo en el que se utiliza este modelo lo observamos en el sistema Default System al que pueden acceder desde el siguiente enlace:


También tenemos disponible el sistema en PDV:

Default System en PDV

La finalidad del sistema Default System  no es otra sino la de acercar a los usuarios de Visual Chart los métodos más utilizados a la hora de realizar un sistema automático de trading.

Funcionamiento del sistema

Este sistema se basa en un cruce de Medias para decidir el punto de entrada, así como en distintos stops de pérdida y beneficio para decidir el punto de salida.


El sistema tiene, además, la opción de liquidar posiciones al finalizar la sesión para cuando se desea operar en intradía.


Diseño del sistema

Tal y como decíamos, lo más interesante de éste sistema es que sigue la estructura básica que nos va a servir como modelo para cualquier estrategia de características similares, que son:

    1.  Entrada a mercado.
    2.  Utilización de stoploss, objetivo de beneficios y trailingstop.

Distinguiremos entres la zona de órdenes de salida y la zona de órdenes de entrada.

Zona de ordenes de salida.
A la hora de colocar los stops y el objetivo, el diseño siempre se repite:


'-- Market of Current Entry
gmp = .GetMarketPosition
'--- EXITS
If gmp <> 0 Then
    gep = .GetEntryPrice
    '-- Init Trailing Price
    If Lastgmp <> gmp Then PriceTS = gep
    '-- Exit Long
    If gmp = 1 And Not CrossT = -1 Then
        If TargetProfit <> 0 Then
            .ExitLong AtLimit, ContractsNumber, gep + TargetProfit * pip
        End If
        If TrailingStop <> 0 Then
            If .High > PriceTS Then PriceTS = .High
            .ExitLong AtStop, ContractsNumber, PriceTS - TrailingStop * pip
        End If
        If StopLoss <> 0 Then .ExitLong AtStop, ContractsNumber, gep - StopLoss * pip
    '-- Exit Short
    ElseIf gmp = -1 And Not CrossT = 1 Then
        If TargetProfit <> 0 Then
            .ExitShort AtLimit, ContractsNumber, gep - TargetProfit * pip
        End If
        If TrailingStop <> 0 Then
            If .Low < PriceTS Then PriceTS = .Low
            .ExitShort AtStop, ContractsNumber, PriceTS + TrailingStop * pip
        End If
        If StopLoss <> 0 Then .ExitShort AtStop, ContractsNumber, gep + StopLoss * pip
    End If
End If

De donde cabe destacar que:

1. Primero comprobamos si estamos abiertos (gmp <> 0). Luego lanzamos las órdenes para la posición abierta a largos o bien para la posición abierta a cortos.

2. La variable PriceTS se utiliza para llevar el control de la mejor posición alcanzada: De manera que el trailingstop la utiliza como referencia. Cuando se produce un cambio de posición (Lastgmp<> gmp), actualizamos la variable con el precio de la nueva entrada.

3. A fin de sólo enviar una orden en STOP por cada entrada, comparamos el precio de salida del stoploss y del trailingstop y sólo enviamos aquel que esté más próximo al precio de entrada.

Zona de órdenes de entrada
Para este tipo de sistemas, las órdenes de entrada son lanzadas a mercado. La señal que activa la compra o la venta, en el caso del sistema DefaultSystem, es la variable CrossT. Esta variable cambia su estado a 1 cuando el cruce es alcista y a -1 cuando el cruce es bajista. El resto del tiempo permanece a cero.

Cabe recordar a los usuarios, que los sistemas no ejecutan las órdenes a mercado en el momento de producirse la señal (en este caso, el cruce de las medias), sino que sucede una vez que finaliza la barra donde se ha producido la señal.

El diseño de la zona de órdenes de entrada es el siguiente:


'--- ENTRIES
If gmp <> 1 Then
    '-- Case of Cross Up, entry long
    If CrossT = 1 Then
        .Buy AtClose, ContractsNumber
        If StopLoss <> 0 Then .ExitLong AtStop, ContractsNumber, .Close - StopLoss * pip
        If TargetProfit <> 0 Then .ExitLong AtLimit, ContractsNumber, .Close + TargetProfit * pip
    End If
End If
If gmp <> -1 Then
    '-- Case of Cross Down, entry short
    If CrossT = -1 Then
        .Sell AtClose, ContractsNumber
        If StopLoss <> 0 Then .ExitShort AtStop, ContractsNumber, .Close + StopLoss * pip
        If TargetProfit <> 0 Then .ExitShort AtLimit, ContractsNumber, .Close - TargetProfit * pip
    End If
End If

De donde cabe destacar que:

1. Una vez que estamos abiertos a largo o corto, no permitimos que vuelva a entrar en el mismo sentido.

2. Volvemos a repetir el lanzamiento de las órdenes de salida. Esto es necesario hacerlo si queremos tener activas las órdenes de salida en la primera barra en la que estamos abiertos.

3. La diferencia entre las órdenes de salida lanzadas para la primera barra y las órdenes lanzadas para el resto de barras, es que el precio de referencia será el precio de cierre de la barra, pues aún no disponemos del valor que nos devuelve la función GetEntryPrice.

Comentarios

  1. Si les surge alguna pregunta o necesitan alguna aclaración, no duden en dejar sus comentarios: Entre todos trataremos de solucionarlos.

    ResponderEliminar
  2. Hola, he estado mirando un poco el código para poder saber como funciona. Quería preguntar la variable Bar que se pasa en System_OnCalculateBar
    Que és ? No se si teneis algún esquema para ver el funcionamiento de como se ejecuta el sistema sobre los gráficos. Algo más gráfico o una doc de las funciones.

    Saludos,

    ResponderEliminar
  3. La variable BAR marca el número de barra en la que nos encontramos en cada iteración. Cuando insertamos un sistema, el sistema primero aplica el método OnCalculateBar sobre las n barras históricas del gráfico, y a partir de ahí, sobre las siguientes barras que vayan dándose en tiempo real. De modo que:
    La primera barra del histórico vale 0, y por tanto, Bar = 0 para OnCalculateBar sobre esa barra.
    La segunda barra del histórico vale 1, y por tanto, Bar =1 para OnCalculateBar sobre esa barra.
    La n-ésima barra del histórico vale (n-1), y por tanto, Bar =(n-1) para OnCalculateBar sobre esa barra.
    Si no le ha quedado algo claro, no dude en volver a consultarnos, ok?
    Respecto al documento que nos solicita sobre cómo se aplica el sistema al gráfico, tendremos en cuenta su solicitud y desarrollaremos un diagrama explicativo que publicaremos en posteriores entradas.
    Gracias por el comentario!

    ResponderEliminar

Publicar un comentario

Entradas populares de este blog

Trading Tools: Descarga de históricos para Visual Chart 6

Indicador Cuidatar

El indicador Volume Distribution