Órdenes compuestas

En esta entrada se va a mostrar cómo crear órdenes complejas del tipo OCO, OSO, bracket, trailing stop, etc. Algunos tipos de órdenes están incluidos en Visual Chart pero pueden no estar soportados por el broker.

La aplicación de este ejemplo desarrolla de una forma simple la operación bracket que consiste en lanzar una orden junto con una limitada de beneficios y un stop de pérdidas. Si se ejecuta la limitada, el stop se cancela automáticamente y viceversa (entre ellas actúan como una OCO: Order Cancel Order).

De esta forma, con un solo clic de ratón se lanza una orden, junto con la toma de beneficios o la limitación de pérdidas, todo gestionado automáticamente.

ComposedOrders

El resto de tipos de órdenes (y las que se le puedan ocurrir a cada lector) se pueden implementar de forma similar. También puede, si se desea, crearse una capa de abstracción que permita llevar a cabo estas operaciones de una forma más simple.

Orden Bracket

La aplicación es parecida a la del ejemplo Operar desarrollado en https://speakertrading.wordpress.com/2012/12/28/operar/ aunque incluye un par de controles para determinar la distancia a la que se fija el máximo de pérdida y la recogida de beneficios. Se recomienda leer primero el post indicado pues esta entrada se centra exclusivamente en la implementación de la orden bracket.

En el constructor de la ventana se añaden un par de líneas junto a la creación del objeto VCT_Trader (el encargado de la operativa) para saber cuándo se ejecuta la orden y si se cancela alguna orden.

_trader = new VCT_TraderClass();

_trader.OnTotalExecutedOrder += _trader_OnTotalExecutedOrder;

_trader.OnCancelledOrder += _trader_OnCancelledOrder;

También se añaden 3 variables a la ventana para las órdenes bracket:

private VCT_Order _order;

private VCT_Order _order1;

private VCT_Order _order2;

Cuando se ejecuta una orden (tras pulsar el botón de comprar o vender), se ejecuta el evento OnTotalExecutedOrder, que se implementa en _trader_OnTotalExecutedOrder en la ventana.

private void _trader_OnTotalExecutedOrder(VCT_Order order)
{
   if (order.OrderID == _order.OrderID)
   {
      double profit = (double)OcoNumericProfit.Value;
      double loss = (double)OcoNumericLoss.Value;
      RunBracketStrategy(order, profit, loss);
   }
   else if (order.OrderID == _order1.OrderID || order.OrderID == _order2.OrderID)
   {
      ApplyBracketStrategy(order);
   }
}

Interesa distinguir la ejecución de la primera orden de la ejecución posterior de la limitada o stop. Las dos comparaciones que se hacen sirven para saber cuál de las órdenes se ha ejecutado.

Si se ejecuta la primera orden (la correspondiente a haber pulsado el botón de comprar o vender), se invoca a la función RunBracketStrategy indicando la distancia configurada en la ventana para la toma de beneficios y la limitación de pérdidas:

private void RunBracketStrategy(VCT_Order order, double profit, double loss)
{
   this._order = order;

   bool buy = order.OrderSide == enumVCTOrderSide.VCT_OS_Buy;
   int volumen = (int)NumericVolumen.Value;

   _order1 = CrearOrden(!buy, volumen);
   _order2 = CrearOrden(!buy, volumen);
   _order1.OrderType = enumVCTOrderType.VCT_OT_StopMarket;
   _order2.OrderType = enumVCTOrderType.VCT_OT_Limit;

   if (buy)
   {
      _order1.StopPrice = _order.Price - loss;
      _order2.Price = _order.Price + profit;
   }
   else
   {
      _order1.StopPrice = _order.Price + loss;
      _order2.Price = _order.Price - profit;
   }

   _trader.SendOrderEx(_order1);
   _trader.SendOrderEx(_order2);
}

En esta función se crean las órdenes limitada y stop. Si la orden principal ha sido de comprar, la limitada y stop serán de vender y viceversa. La función CrearOrden devuelve un VCT_Order configurado como orden a mercado, de ahí que se modifique el tipo de orden a stop y limitada. Por último resta configurar la distancia del stop y de la limitada, que depende de si se trata de una compra o una venta y ejecutar ambas órdenes.

Estas órdenes, entre ellas, deben funcionar como una OCO: cuando una se ejecuta, la otra ya no es de interés y debe cancelarse.

Tal como se ha visto en _trader_OnTotalExecutedOrder, la segunda comparación trata esta parte: si se ejecuta la segunda o tercera orden (las de la OCO: stop o limitada), cancelamos la otra. Esto se hace en la función ApplyBracketStrategy:

private void ApplyBracketStrategy(VCT_Order order)
{
   if (order.OrderID == _order1.OrderID)
   {
      _order1 = order;
      _trader.CancelOrder(_order2.OrderID);
   }
   else if (order.OrderID == _order2.OrderID)
   {
      _order2 = order;
      _trader.CancelOrder(_order1.OrderID);
   }
}

Tan simple como comprobar cuál de las órdenes se ha ejecutado y cancelar la otra.

Limitaciones/Mejoras

Como es habitual, se trata de un ejemplo muy sencillo, con fines exclusivamente didácticos. Una limitación importante es que no se gestiona la ejecución parcial de órdenes. Si se ejecutan 2 de 5 contratos, deben lanzarse dos órdenes (stop y limitada) de 2 contratos. Si posteriormente se ejecutan los otros 3 contratos, hay que modificar las órdenes añadiendo 3 contratos más (o ejecutar nuevas órdenes stop y limitada con 3 contratos).

Si la aplicación se cierra con el stop y la limitada en mercado, la relación OCO existente entre ellas se pierde. Se deben guardar en disco estas relaciones para que al ejecutar de nuevo la aplicación, se sepa que entre ellas existe una relación OCO. Igualmente, si se envía a mercado la orden bracket y antes de ejecutarse se cierra la aplicación hay que almacenar que se trata de una orden bracket y la distancia a la que se han fijado la toma de beneficios y la limitación de las pérdidas para poder ejecutar la limitada y stop cuando la bracket se ejecute. La casuística es grande, si se ejecuta la orden bracket teniendo la aplicación cerrada la limitada y stop no se habrán ejecutado. Al arrancar la aplicación habría que ver si entre las órdenes ejecutadas está la orden bracket y, de ser así, lanzar la limitada y stop correspondiente.

Para una aplicación profesional es recomendable crear clases independientes tipo BracketOrder, OCOOrder… que traten toda la casuística y cuyo uso sea sencillo.

En la ventana, debería mostrarse gráficamente (con una tabla) donde está el precio actual y las órdenes.

Archivo Zip Descargar C# ComposedOrder.zip.

Archivo Zip Descargar VB .NET ComposedOrder_vb.zip.

Si te ha gustado la entrada, considera hacer una donación Donar. ¿Por qué donar?

Esta entrada fue publicada en Código fuente, Programación, Sistemas automáticos y etiquetada , . Guarda el enlace permanente.

4 respuestas a Órdenes compuestas

  1. Alberto dijo:

    Hola estoy siguiendo tu blog ya que estoy preparando un sistema con VC como parte de mi pfc. ¿Sabes si se puede poner un trailing stop mediante PDV?

    • Siento no poder ayudarte pero no se casi nada de PDV. Me es más sencillo programar en VBA o .NET que con PDV y nunca me he detenido a ver como funciona. Con VBA si puede hacerse:
      – Define una variable para el trailing.
      – Cuando compres, la variable se situa en el precio de compra menos la distancia del trailing.
      – En cada CalculateBar, si el precio sube, la variable se actualiza (cierre actual menos distancia). Si no lo hace, se deja con el valor que tuviese. Si el precio baja por debajo de la variable del trailing, se dispara el stop.
      – Para las ventas lo mismo pero en sentido inverso.

      • Raúl dijo:

        Hola SpeakerTrading,
        este fin de semana descubrí tu blog y me parece muy interesante, quiero acabar de leer todos tus post. Me gustaría poder ponerme en contacto contigo pero no veo tu correo, si puedes enviamelo. Muchas gracias

      • Hola Raúl

        Espero que sea de tu agrado el contenido del blog.

        Te envío mi dirección

Deja un comentario