Saltar a contenido

Ejemplos de código de cBot

Esta página proporciona varios ejemplos de código en Python y C# para crear robots de operaciones y desarrollar algoritmos. Tenga en cuenta que ninguno de los cBots enumerados a continuación garantiza ningún rendimiento financiero. Asegúrese de realizar backtesting y personalizar sus cBots antes de implementar cualquier instancia en una cuenta real.

Repositorios de ejemplos de cBot

Hay disponibles ejemplos completos de código de cBot, incluidas plantillas listas para ejecutar para diversas estrategias automatizadas y estilos de operación, en repositorios separados de Python y C# en GitHub.

Operaciones sincrónicas

Todos los cBots de esta sección ejecutan sus operaciones de forma sincrónica.

Ejecutar órdenes de mercado

  • Un cBot simple que realiza operaciones exitosas

    El siguiente robot de operaciones crea una orden de mercado al iniciarse y guarda el resultado en la variable result.

    Si la ejecución de la orden es exitosa, el precio de entrada se imprime en el registro.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            var result = ExecuteMarketOrder(TradeType.Buy, SymbolName, 10000);
    
            if (result.IsSuccessful)
            {
                var position = result.Position;
                Print("Position entry price is {0}", position.EntryPrice);
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    class Sample_cBot():
        def on_start(self):
            result = api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 10000)
    
            if result.IsSuccessful:
                position = result.Position
                api.Print(f"Position entry price is {position.EntryPrice}")
    

    Salida del registro

    • El cBot "Nuevo cBot" se inició correctamente para EURUSD, h1.
    • Ejecutando Orden de Mercado para Comprar 10000 EURUSD
    • La ejecución de la Orden de Mercado para Comprar 10000 EURUSD TUVO ÉXITO, Posición PID14576001
    • El precio de entrada de la posición es 1.19067
  • Un cBot simple con parámetros personalizables

    Al declarar varias propiedades de cBot, puede convertirlas en parámetros personalizables utilizando la declaración [Parameter()]. Cuando se lanza una nueva instancia de su cBot, usted (u otros usuarios) podrán asignar valores personalizados a estos.

    Considere el siguiente ejemplo.

    1
    2
    [Parameter("SMA Period", DefaultValue = 14)]
    public int SmaPeriod { get; set; }
    

    Nota

    Los cBots de Python utilizan parámetros personalizables declarados en sus archivos .cs.

    1
    2
    [Parameter("SMA Period", DefaultValue = 14)]
    public int SmaPeriod { get; set; }
    

    En el ejemplo anterior, definimos las siguientes características:

    • El nombre del parámetro. Posteriormente, aparecerá en la interfaz de usuario de cTrader ("SMA Period").
    • El valor predeterminado del parámetro que se aplicará a todas las nuevas instancias a menos que los usuarios lo cambien (DefaultValue = 14).

    En el código a continuación, mostramos cómo se puede utilizar la propiedad SmaPeriod en un robot de operaciones real.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    [Robot(TimeZone = TimeZones.UTC, AccessRights = AccessRights.None)]
    public class SamplecBotReferenceSMA : Robot
    {
        [Parameter("Source")]
        public DataSeries Source { get; set; }
    
        [Parameter("SMA Period", DefaultValue = 14)]
        public int SmaPeriod { get; set; }
    
        private SampleSMA sma;
    
        protected override void OnStart()
        {
            sma = Indicators.GetIndicator<SampleSMA>(Source, SmaPeriod);
        }
    
        protected override void OnTick()
        {
            Print("{0}", sma.Result.LastValue);
        }
    }
    

    Nota

    Los cBots de Python utilizan parámetros personalizables declarados en sus archivos .cs.

    1
    2
    3
    4
    5
    6
    class Sample_cBot():
        def on_start(self):
            self.sma = api.Indicators.GetIndicator<SampleSMA>(api.Source, api.SmaPeriod)
    
        def on_tick(self):
            api.Print(f"{self.sma.Result.LastValue}")
    

    Nuestro bot toma la propiedad personalizable SmaPeriod y, al inicio, pasa su valor al método Indicators.GetIndicator<SampleSMA>(). Este método devuelve un valor de media móvil simple para el período especificado.

    Al crear una instancia de cBot, todos los parámetros ajustables se pueden configurar en la ventana Agregar instancia.

    Cuando se inicia, el cBot nos informa cuál fue el último valor de la media móvil simple en cada tick.

    Salida del registro

    • Se inició la instancia de CBot [Sample cBot Reference SMA, EURUSD, h1].
    • 0.975685714285714
    • 0.975681428571429
    • 0.97568
    • Se detuvo la instancia de CBot [Sample cBot Reference SMA, EURUSD, h1].
  • Ejecutar una orden de mercado con más argumentos

    En el ejemplo anterior, pasamos el número mínimo posible de argumentos al método ExecuteMarketOrder(). Estos fueron el tipo de operación (TradeType.Buy), el símbolo (Symbol) y el volumen (-1).

    El método ExecuteMarketOrder() se puede llamar con argumentos adicionales como Label, StopLoss, TakeProfit y Comment. El ejemplo a continuación especifica la etiqueta ("order 1"), el mecanismo de protección de stop loss (10) y el nivel de take profit (10).

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    [Robot(TimeZone = TimeZones.UTC)]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            var result = ExecuteMarketOrder(TradeType.Buy, SymbolName, 10000, "order 1", 10, 10);
    
            if (result.IsSuccessful)
            {
                var position = result.Position;
                Print("Position entry price is {0}", position.EntryPrice);
                Print("Position SL price is {0}", position.StopLoss);
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    class Sample_cBot():
        def on_start(self):
            result = api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 10000, "order 1", 10, 10)
    
            if result.IsSuccessful:
                position = result.Position
                api.Print(f"Position entry price is {position.EntryPrice}")
                api.Print(f"Position SL price is {position.StopLoss}")
    

    Salida del registro

    • El cBot "Nuevo cBot" se inició correctamente para EURUSD, h1.
    • Ejecutando Orden de Mercado para Comprar 10000 EURUSD (SL: 10, TP: 10)
    • La ejecución de la Orden de Mercado para Comprar 10000 EURUSD (SL: 10, TP: 10) TUVO ÉXITO, Posición PID14576098
    • El precio de entrada de la posición es 1.1896
    • El precio de SL de la posición es 1.1886

Modificar una posición

En el ejemplo siguiente, solo agregamos un valor de take profit (10) cuando se ejecuta una orden. Después, modificamos la posición para agregar un stop loss.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
[Robot()]
public class SamplecBbot : Robot
{
    protected override void OnStart()
    {
        var result = ExecuteMarketOrder(TradeType.Buy, SymbolName, 10000,
                                "order 1", null, 10);
        if (result.IsSuccessful)
        {
            var position = result.Position;
            Print("Position SL price is {0}", position.StopLoss);

            var stopLoss = position.EntryPrice - 10*Symbol.PipSize;
            ModifyPosition(position, stopLoss, position.TakeProfit);

            Print("New Position SL price is {0}", position.StopLoss);

        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
class Sample_cBot():
    def on_start(self):
        result = api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 10000, "order 1", None, 10)

        if result.IsSuccessful:
            position = result.Position
            api.Print(f"Position SL price is {position.StopLoss}")
            stopLoss = position.EntryPrice - 10 * api.Symbol.PipSize
            api.ModifyPosition(position, stopLoss, position.TakeProfit)
            api.Print(f"New Position SL price is {position.StopLoss}")

Salida del registro

Cerrar una posición

  • Realizar un cierre completo

    El ejemplo de código a continuación coloca una orden de mercado. Si el beneficio bruto de la posición resultante supera un cierto valor (null && position.GrossProfit > 10), se cierra.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            ExecuteMarketOrder(TradeType.Buy, SymbolName, 10000, "myLabel");
        }
    
        protected override void OnTick()
        {
            var position = Positions.Find("myLabel");
            if (position != null && position.GrossProfit > 10)
            {
                ClosePosition(position);
                Stop();
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Sample_cBot():
        def on_start(self):
            api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 10000, "myLabel")
    
        def on_tick(self):
            position = api.Positions.Find("myLabel")
            if position is not None and position.GrossProfit > 10:
                api.ClosePosition(position)
                api.Stop()
    

    Salida del registro

    • El cBot "Nuevo cBot" se inició correctamente para EURUSD, h1.
    • Ejecutando Orden de Mercado para Comprar 10000 EURUSD
    • La ejecución de la Orden de Mercado para Comprar 10000 EURUSD TUVO ÉXITO, Posición PID14576180
  • Realizar un cierre parcial

    Modificaremos el ejemplo anterior para crear dos órdenes de mercado con las mismas etiquetas ("myLabel"). En cada nueva barra, nuestro robot de operaciones cerrará exactamente la mitad de una de estas órdenes, pero solo si su volumen es igual o superior a 20,000.

    También utilizamos el método Positions.FindAll(). Devuelve una lista de posiciones por las que podemos iterar.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            ExecuteMarketOrder(TradeType.Buy, SymbolName, 20000, "myLabel");
            ExecuteMarketOrder(TradeType.Buy, SymbolName, 30000, "myLabel");
        }
    
        protected override void OnBar()
        {
            var positions = Positions.FindAll("myLabel", SymbolName, TradeType.Buy);
    
            foreach (var position in positions)
            {
                if (position.VolumeInUnits >= 20000)
                {
                    ClosePosition(position, 15000);
                }
            }
        }
    }
    
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    class Sample_cBot():
        def on_start(self):
            api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 20000, "myLabel")
            api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 30000, "myLabel")
    
        def on_tick(self):
            positions = api.Positions.FindAll("myLabel", api.SymbolName, TradeType.Buy)
            for position in positions:
                if position.VolumeInUnits >= 20000:
                    api.ClosePosition(position, 15000)
    

    Salida del registro

    • El cBot "Nuevo cBot" se inició correctamente para EURUSD, h1.
    • Ejecutando Orden de Mercado para Comprar 20000 EURUSD
    • La ejecución de la Orden de Mercado para Comprar 20000 EURUSD TUVO ÉXITO, Posición PID14579299
    • Ejecutando Orden de Mercado para Comprar 30000 EURUSD
    • La ejecución de la Orden de Mercado para Comprar 30000 EURUSD TUVO ÉXITO, Posición PID14579300

Crear órdenes pendientes

  • Crear órdenes limitadas y de stop

    Las órdenes limitadas y de stop son órdenes pendientes; a pesar de esto, se crean de manera similar a las órdenes de mercado. Sin embargo, al crear órdenes limitadas y de stop, también debe especificar su precio objetivo y no hay rango de mercado.

    Este cBot crea dos órdenes limitadas y una orden de stop. Luego itera a través de las órdenes e imprime sus etiquetas e ID en el registro.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            PlaceLimitOrder(TradeType.Buy, SymbolName, 10000, Symbol.Bid, "myLimitOrder");
            PlaceLimitOrder(TradeType.Buy, SymbolName, 20000, Symbol.Bid-2*Symbol.PipSize,
                    "myLimitOrder");
            PlaceStopOrder(TradeType.Buy, SymbolName, 10000, Symbol.Ask, "myStopOrder");
    
            foreach (var pendingOrder in PendingOrders)
            {
                Print("Order placed with label {0}, id {1}", pendingOrder.Label, pendingOrder.Id);
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    class Sample_cBot():
        def on_start(self):
            api.PlaceLimitOrder(TradeType.Buy, api.SymbolName, 10000, api.Symbol.Bid, "myLimitOrder")
            api.PlaceLimitOrder(TradeType.Buy, api.SymbolName, 20000, api.Symbol.Bid - 2 * api.Symbol.PipSize, "myLimitOrder")
            api.PlaceStopOrder(TradeType.Buy, api.SymbolName, 10000, api.Symbol.Ask, "myStopOrder")
    
            for pendingOrder in api.PendingOrders:
                Print(f"Order placed with label {pendingOrder.Label}, id {pendingOrder.Id}")
    

    Salida del registro

    • El cBot "Nuevo cBot" se inició correctamente para EURUSD, h1.
    • Colocando Orden Limitada para Comprar 10000 EURUSD (Precio: 1.19036)
    • La colocación de la Orden Limitada para Comprar 10000 EURUSD (Precio: 1.19036) TUVO ÉXITO, Orden Pendiente OID25220794
    • Colocando Orden Limitada para Comprar 20000 EURUSD (Precio: 1.19017)
    • La colocación de la Orden Limitada para Comprar 20000 EURUSD (Precio: 1.19017) TUVO ÉXITO, Orden Pendiente OID25220795
    • Colocando Orden de Stop para Comprar 10000 EURUSD (Precio: 1.19040)
    • La colocación de la Orden de Stop para Comprar 10000 EURUSD (Precio: 1.19040) TUVO ÉXITO, Orden Pendiente OID25220796
    • Orden colocada con etiqueta myLimitOrder, id 25220794
    • Orden colocada con etiqueta myLimitOrder, id 25220795
    • Orden colocada con etiqueta myStopOrder, id 25220796
  • Crear órdenes pendientes con más parámetros

    Al igual que con las órdenes de mercado, también puede especificar la etiqueta de la orden, varios mecanismos de protección, la fecha de vencimiento de la orden y proporcionar un comentario.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            var midnight = Server.Time.AddDays(1).Date;
    
            PlaceLimitOrder(TradeType.Buy, SymbolName, 10000, Symbol.Bid, "mySample_cBot", 10, null, midnight, "First");
    
            PlaceStopOrder(TradeType.Buy, SymbolName, 10000, Symbol.Ask, "mySample_cBot", 10, 10, null, "Second");
    
            foreach (var order in PendingOrders)
            {
                var sl = order.StopLoss == null ? "" : "SL: " + order.StopLoss;
                var tp = order.TakeProfit == null ? "" : " TP: " + order.TakeProfit;
    
                var text = string.Format("{0} {1}", sl, tp);
    
                if (order.OrderType == PendingOrderType.Limit)
                    Print(order.Comment + " Limit Order " + text);
                else
                    Print(order.Comment + " Stop Order " + text);
            }
        }
    }
    
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    class Sample_cBot():
        def on_start(self):
            midnight = api.Server.Time.AddDays(1).Date
    
            api.PlaceLimitOrder(TradeType.Buy, api.SymbolName, 10000, api.Symbol.Bid, "mySample_cBot", 10, None, midnight, "First")
            api.PlaceStopOrder(TradeType.Buy, api.SymbolName, 10000, api.Symbol.Ask, "mySample_cBot", 10, 10, None, "Second")
    
            for order in api.PendingOrders:
                sl = "" if order.StopLoss is None else f"SL: {order.StopLoss}"
                tp = "" if order.TakeProfit is None else f"TP: {order.TakeProfit}"
    
                api.Print(f"{order.Comment} {order.OrderType} Order {sl} {tp}")
    

    Salida del registro

    • El cBot "Nuevo cBot" se inició correctamente para EURUSD, h1.
    • Colocando Orden Limitada para Comprar 10000 EURUSD (Precio: 1.19049, SL: 10, Fecha de Vencimiento: 12/05/2018 00:00:00)
    • La colocación de la Orden Limitada para Comprar 10000 EURUSD (Precio: 1.19049, SL: 10, Fecha de Vencimiento: 12/05/2018 00:00:00) TUVO ÉXITO, Orden Pendiente OID25220807
    • Colocando Orden de Stop para Comprar 10000 EURUSD (Precio: 1.19053, SL: 10, TP: 10)
    • La colocación de la Orden de Stop para Comprar 10000 EURUSD (Precio: 1.19053, SL: 10, TP: 10) TUVO ÉXITO, Orden Pendiente OID25220808
    • Orden Limitada
    • SL de la Primera Orden Limitada: 1.18949
    • SL de la Segunda Orden de Stop: 1.18953 TP: 1.19153

Modificar órdenes pendientes

Es posible modificar varias características de las órdenes pendientes.

El ejemplo a continuación muestra cómo modificar el precio objetivo, los niveles de protección o la fecha y hora de vencimiento de una orden pendiente.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[Robot()]
public class Sample_cBot : Robot
{
    protected override void OnStart()
    {
        var price = Symbol.Ask + 10 * Symbol.PipSize;
        var expiry = Server.Time.AddHours(12);
        PlaceStopOrder(TradeType.Buy, SymbolName, 10000, price, "myLabel", 10, 10, expiry);
    }

    protected override void OnBar()
    {
        foreach (var order in PendingOrders)
        {
            if (order.Label == "myLabel")
            {
                double newPrice = Symbol.Ask + 5 * Symbol.PipSize;
                ModifyPendingOrder(order, newPrice, order.StopLossPips,
                                                            order.TakeProfitPips, order.ExpirationTime);
            }
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Sample_cBot():
    def on_start(self):
        price = api.Symbol.Ask + 10 * api.Symbol.PipSize
        expiry = Server.Time.AddHours(12)

        api.PlaceStopOrder(TradeType.Buy, api.SymbolName, 10000, price, "myLabel", 10, 10, expiry)

    def on_bar(self):
        for order in api.PendingOrders:
            if order.Label == "myLabel":
                newPrice = api.Symbol.Ask + 5 * api.Symbol.PipSize
                api.ModifyPendingOrder(order, newPrice, order.StopLossPips, order.TakeProfitPips, order.ExpirationTime)

Salida del registro

Cancelar órdenes pendientes

La sintaxis para cancelar una orden es CancelPendingOrder(order), donde order es de tipo PendingOrder.

El ejemplo a continuación muestra cómo cancelar todas las órdenes con la etiqueta "myLabel".

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
[Robot()]
public class Sample_cBot : Robot
{
    protected override void OnTick()
    {
        foreach (var order in PendingOrders)
        {
            if (order.Label == "myLabel")
            {
                CancelPendingOrder(order);
            }
        }
    }
}
1
2
3
4
5
class Sample_cBot():
    def on_tick(self):
        for order in api.PendingOrders:
            if order.Label == "myLabel":
                api.CancelPendingOrder(order)

Eventos de posiciones

Es posible suscribirse a eventos relacionados con diversas operaciones de trading. Por ejemplo, para comprobar si se abre una posición, nos suscribimos a un evento que se genera para todos los objetos Position al abrirse.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[Robot()]
public class Sample_cBot : Robot
{
    protected override void OnStart()
    {
        Positions.Opened += PositionsOnOpened;
        ExecuteMarketOrder(TradeType.Buy, Symbol, 10000, "myLabel", 10, 10);
    }

    private void PositionsOnOpened(PositionOpenedEventArgs args)
    {
        var pos = args.Position;
        Print("Position opened at {0}", pos.EntryPrice);
    }
}
1
2
3
4
5
6
7
8
class Sample_cBot():
    def on_start(self):
        api.Positions.Opened += self.on_position_opened
        api.ExecuteMarketOrder(TradeType.Buy, api.Symbol, 10000, "myLabel", 10, 10)

    def on_position_opened(self, args):
        pos = args.Position
        api.Print(f"Position opened at {pos.EntryPrice}")

Salida del registro

De manera similar, es posible suscribirse a eventos que se generan cada vez que se cierra una posición.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
[Robot()]
public class Sample_cBot : Robot
{
    protected override void OnStart()
    {
        Positions.Closed += PositionsOnClosed;
        ExecuteMarketOrder(TradeType.Buy, Symbol, 10000, "myLabel", 10, 10);
    }

    protected override void OnBar()
    {
        var position = Positions.Find("myLabel");
        if (position != null)
            ClosePosition(position);
    }

    private void PositionsOnClosed(PositionClosedEventArgs args)
    {
        var pos = args.Position;
        Print("Position closed with {0} profit", pos.GrossProfit);
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class Sample_cBot():
    def on_start(self):
        api.Positions.Closed += self.on_position_closed
        api.ExecuteMarketOrder(TradeType.Buy, api.Symbol, 10000, "myLabel", 10, 10)

    def on_bar(self):
        position = api.Positions.Find("myLabel")

        if position is not None:
            api.ClosePosition(position);            

    def on_position_closed(self, args):
        pos = args.Position
        api.Print(f"Position closed with {pos.GrossProfit} profit")

Salida del registro

Conversión de coordenadas

El cBot a continuación permite a los usuarios colocar órdenes limitadas en una dirección adecuada simplemente haciendo clic derecho en un gráfico. Lo logra convirtiendo las coordenadas Y del ratón a coordenadas Y del gráfico (que, para los símbolos, corresponden a los precios de los símbolos).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
[Robot(AccessRights = AccessRights.None)]
public class CoordinatesConverter : Robot
{
    protected override void OnStart()
    {
        Chart.MouseUp += Chart_MouseUp;
    }

    private void Chart_MouseUp(ChartMouseEventArgs obj)
    {
        var desiredPrice = Chart.YToYValue(obj.MouseY);
        var desiredTradeType = desiredPrice > Symbol.Bid ? TradeType.Sell : TradeType.Buy;
        PlaceLimitOrder(desiredTradeType, SymbolName, 10000, desiredPrice);
    }
}
1
2
3
4
5
6
7
8
class Sample_cBot():
    def on_start(self):
        api.Chart.MouseUp += self.on_chart_mouse_up        

    def on_chart_mouse_up(self, args):
        desiredPrice = api.Chart.YToYValue(args.MouseY)
        desiredTradeType = TradeType.Sell if desiredPrice > api.Symbol.Bid else TradeType.Buy
        api.PlaceLimitOrder(desiredTradeType, api.SymbolName, 10000, desiredPrice)

Ejecución asincrónica

Los ejemplos de código anteriores están diseñados para implementar robots de operaciones utilizando ejecución síncrona. Tanto C# como Python admiten operaciones asíncronas, lo que permite que su cBot realice varias acciones dentro del mismo marco temporal.

Ejecutar órdenes de mercado de forma asíncrona

La sintaxis de los métodos asíncronos es similar a la de los síncronos. Aunque aceptan los mismos tipos de argumentos, su tipo de retorno es TradeOperation en lugar de TradeResult.

  • Operaciones asíncronas básicas

    El siguiente cBot demuestra cómo funcionan las operaciones asíncronas. Se crea una orden de mercado; en la siguiente condicional, el cBot comprueba si la operación se está ejecutando.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            var operation = ExecuteMarketOrderAsync(TradeType.Buy, SymbolName, 10000);
    
            if (operation.IsExecuting)
            {
                Print("Operation Is Executing");
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    class Sample_cBot():
        def on_start(self):
            operation = api.ExecuteMarketOrderAsync(TradeType.Buy, api.SymbolName, 10000)
    
            if operation.IsExecuting:
                api.Print("Operation Is Executing")
    

    Salida del registro

    • El cBot "Nuevo cBot" se inició correctamente para EURUSD, h1.
    • Ejecutando Orden de Mercado para Comprar 10000 EURUSD
    • La Operación Se Está Ejecutando
    • La Ejecución de la Orden de Mercado para Comprar 10000 EURUSD TUVO ÉXITO, Posición PID14579532
  • Ejecutar una orden

    El siguiente ejemplo destaca la diferencia entre métodos síncronos y asíncronos.

    El cBot comprueba si una operación se está ejecutando justo después de llamar a un método asíncrono. Lo hace de nuevo después de llamar a un método síncrono. La salida del registro para estas dos acciones es diferente.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            var operation = ExecuteMarketOrderAsync(TradeType.Buy, SymbolName, 10000);
            Print(operation.IsExecuting ? "Operation Is Executing" : "Operation executed");
            ExecuteMarketOrder(TradeType.Buy, SymbolName, 20000);
            Print(operation.IsExecuting ? "Operation Is Executing" : "Operation executed");
        }
    }
    
    1
    2
    3
    4
    5
    6
    class Sample_cBot():
        def on_start(self):
            operation = api.ExecuteMarketOrderAsync(TradeType.Buy, api.SymbolName, 10000)
            api.Print("Operation Is Executing" if operation.IsExecuting else "Operation executed")
            api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 20000)
            api.Print("Operation Is Executing" if operation.IsExecuting else "Operation executed")
    

    Salida del registro

    • El cBot "Nuevo cBot" se inició correctamente para EURUSD, h1.
    • Ejecutando Orden de Mercado para Comprar 10000 EURUSD
    • La Operación Se Está Ejecutando
    • Ejecutando Orden de Mercado para Comprar 20000 EURUSD
    • La Ejecución de la Orden de Mercado para Comprar 10000 EURUSD TUVO ÉXITO, Posición PID14579541
    • La Ejecución de la Orden de Mercado para Comprar 20000 EURUSD TUVO ÉXITO, Posición PID14579542
    • Operación ejecutada
  • Ejecutar una orden con más parámetros

    El siguiente cBot coloca una orden especificando su etiqueta ("myLabel"), niveles de protección (10, 10), símbolo (SymbolName) y volumen (10000).

    El ejemplo también contiene la colección Positions y el método FindAll(). Find() y FindAll() se pueden usar para encontrar posiciones con la misma etiqueta, símbolo y tipo de operación.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            ExecuteMarketOrderAsync(TradeType.Buy, SymbolName, 10000, "myLabel", 10, 10);
        }
        protected override void OnTick()
        {
            var positions = Positions.FindAll("myLabel", SymbolName, TradeType.Buy);
    
            if (positions.Length == 0)
                return;
    
            foreach (var position in positions)
                Print("Buy at {0} SL {1}", position.EntryPrice, position.StopLoss);
    
            Stop();
        }
    }
    
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    class Sample_cBot():
        def on_start(self):
            api.ExecuteMarketOrderAsync(TradeType.Buy, api.SymbolName, 10000, "myLabel", 10, 10)
    
        def on_tick(self):
            positions = api.Positions.FindAll("myLabel", api.SymbolName, TradeType.Buy)
    
            if positions.Length == 0:
                return
    
            for position in positions:
                api.Print(f"Buy at {position.EntryPrice} SL {position.StopLoss}")
    
            api.Stop()            
    

    Salida del registro

    • El cBot "Nuevo cBot" se inició correctamente para EURUSD, h1.
    • Ejecutando Orden de Mercado para Comprar 10000 EURUSD (SL: 10, TP: 10)
    • La Ejecución de la Orden de Mercado para Comprar 10000 EURUSD (SL: 10, TP: 10) TUVO ÉXITO, Posición PID14579719
    • Compra a 1.19087 SL null
    • Compra a 1.19357 SL 1.19257
    • El cBot "Nuevo cBot" se detuvo para EURUSD, h1.

Modificar posición de forma asíncrona

El cBot a continuación coloca una orden de mercado y luego modifica la posición recién abierta.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
[Robot()]
public class Sample_cBot : Robot
{
    protected override void OnStart()
    {
        ExecuteMarketOrderAsync(TradeType.Buy, SymbolName, 10000, "myLabel", null, 10);
    }

    protected override void OnTick()
    {
        Position myPosition = Positions.Find("myLabel");
        if (myPosition != null && myPosition.StopLoss == null)
        {
            double stopLoss = Symbol.Bid - 10 * Symbol.PipSize;
            ModifyPositionAsync(myPosition, stopLoss, myPosition.TakeProfit);
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class Sample_cBot():
    def on_start(self):
        api.ExecuteMarketOrderAsync(TradeType.Buy, api.SymbolName, 10000, "myLabel", None, 10)

    def on_tick(self):
        myPosition = Positions.Find("myLabel")

        if myPosition is None or myPosition.StopLoss is not None:
            return

        stopLoss = api.Symbol.Bid - 10 * api.Symbol.PipSize

        api.ModifyPositionAsync(myPosition, stopLoss, myPosition.TakeProfit)        

Salida del registro

Cerrar una posición de forma asíncrona

El siguiente ejemplo demuestra cómo cerrar una posición de forma asíncrona si existe.

El método Find() se utiliza para buscar en la colección Positions la posición con una etiqueta específica.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
[Robot()]
public class Sample_cBot : Robot
{
    protected override void OnStart()
    {
        ExecuteMarketOrderAsync(TradeType.Buy, Symbol, 10000, "myLabel", null, 10);
    }

    protected override void OnTick()
    {
        Position myPosition = Positions.Find("myLabel");
        if (myPosition != null && myPosition.GrossProfit > 10)
        {
            ClosePositionAsync(myPosition);
            Stop();
        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Sample_cBot():
    def on_start(self):
        api.ExecuteMarketOrderAsync(TradeType.Buy, api.SymbolName, 10000, "myLabel", None, 10)

    def on_tick(self):
        myPosition = Positions.Find("myLabel")

        if myPosition is None or myPosition.GrossProfit <= 10:
            return

        api.ClosePositionAsync(myPosition)
        api.Stop()        

Salida del registro

Colocar órdenes limitadas y de stop de forma asíncrona

Como se indicó anteriormente, colocar órdenes pendientes es similar a crear órdenes de mercado.

Sin embargo, hay algunas ligeras diferencias en los argumentos entre estos dos métodos. El rango de mercado está ausente de la lista de argumentos. Además, debe especificar el precio objetivo, y puede pasar un argumento opcional que especifique la fecha de vencimiento de la orden.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
[Robot()]
public class Sample_cBot : Robot
{
    protected override void OnStart()
    {
        var expiry = Server.Time.AddHours(12);
        PlaceLimitOrderAsync(TradeType.Buy, SymbolName, 10000, Symbol.Bid, "myLabel", null, null, expiry);
        PlaceStopOrderAsync(TradeType.Buy, SymbolName, 10000, Symbol.Ask + 10 * Symbol.PipSize, "myLabel", null, null, expiry);
    }
}
1
2
3
4
5
class Sample_cBot():
    def on_start(self):
        expiry = api.Server.Time.AddHours(12)
        api.PlaceLimitOrderAsync(TradeType.Buy, api.SymbolName, 10000, api.Symbol.Bid, "myLabel", None, None, expiry)
        api.PlaceStopOrderAsync(TradeType.Buy, api.SymbolName, 10000, api.Symbol.Ask + 10 * api.Symbol.PipSize, "myLabel", None, None, expiry)    

Salida del registro

Modificar órdenes pendientes de forma asíncrona

El siguiente cBot modifica órdenes limitadas de forma asíncrona.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
[Robot()]
public class Sample_cBot : Robot
{
    protected override void OnStart()
    {
        var expiry = Server.Time.AddHours(12);
        PlaceLimitOrderAsync(TradeType.Buy, SymbolName, 10000, Symbol.Bid, "myLabel", null, 10, expiry);

    }
    protected override void OnTick()
    {
        foreach (var order in PendingOrders)
        {
            if (order.Label == "myLabel" && order.StopLoss == null)
                ModifyPendingOrderAsync(order, order.TargetPrice, 10, 10, null);
        }
    }
}
1
2
3
4
5
6
7
8
9
class Sample_cBot():
    def on_start(self):
        expiry = api.Server.Time.AddHours(12)
        api.PlaceLimitOrderAsync(TradeType.Buy, api.SymbolName, 10000, api.Symbol.Bid, "myLabel", None, 10, expiry)

    def on_tick(self):
        for order in api.PendingOrders:
            if order.Label == "myLabel" and order.StopLoss is None:
                api.ModifyPendingOrderAsync(order, order.TargetPrice, 10, 10, None)

Salida del registro

Cancelar órdenes pendientes de forma asíncrona

  • Cancelar todas las órdenes pendientes

    El cBot a continuación cancela de forma asíncrona todas las órdenes pendientes actuales.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnBar()
        {
            foreach (var pendingOrder in PendingOrders)
            {
                CancelPendingOrderAsync(pendingOrder);
            }
        }
    }
    
    1
    2
    3
    4
    class Sample_cBot():
        def on_bar(self):
            for order in api.PendingOrders:
                api.CancelPendingOrderAsync(order)
    

    Salida del registro

    • El cBot "cancelar orden pendiente" se inició correctamente para EURUSD, h1.
    • Cancelando orden pendiente OID274705
    • Cancelando orden pendiente OID274706
    • Cancelando orden pendiente OID274707
    • Cancelando orden pendiente OID274708
    • Cancelando orden pendiente OID274709
    • La Cancelación de la orden pendiente OID274705 TUVO ÉXITO, Orden Pendiente OID274705
    • La Cancelación de la orden pendiente OID274706 TUVO ÉXITO, Orden Pendiente OID274706
    • La Cancelación de la orden pendiente OID274707 TUVO ÉXITO, Orden Pendiente OID274707
    • La Cancelación de la orden pendiente OID274708 TUVO ÉXITO, Orden Pendiente OID274708
    • La Cancelación de la orden pendiente OID274709 TUVO ÉXITO, Orden Pendiente OID274709
  • Cancelar órdenes pendientes con una etiqueta determinada

    Este cBot solo cancela órdenes pendientes con una etiqueta determinada.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnBar()
        {
            foreach (var pendingOrder in PendingOrders)
            {
                if (pendingOrder.Label == "myLabel")
                    CancelPendingOrderAsync(pendingOrder);
            }
        }
    }
    
    1
    2
    3
    4
    5
    class Sample_cBot():
        def on_bar(self):
            for order in api.PendingOrders:
                if order.Label == "myLabel":
                    api.CancelPendingOrderAsync(order)
    

Funciones de devolución de llamada para métodos asíncronos

Una vez que se devuelve un resultado, el uso de operaciones asíncronas a menudo requiere controlar la ejecución. Para manejar esto, puede agregar una función de devolución de llamada al final de la lista de parámetros de todos los métodos asíncronos.

Esta función se llamará tan pronto como se reciba una respuesta del servidor. Por ejemplo, podría llamarse cuando se abre, modifica o cierra una posición.

  • Orden de mercado asíncrona con una devolución de llamada

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            var operation = ExecuteMarketOrderAsync(TradeType.Buy, SymbolName, 10000, PositionOpened);
            if (operation.IsExecuting)
                Print(operation.ToString());
            else
                Print(operation.TradeResult.ToString());
    
        }
    
        private void PositionOpened(TradeResult tradeResult)
        {
            var position = tradeResult.Position;
            Print(tradeResult.ToString());
            if (tradeResult.IsSuccessful)
                Print("Position {0} opened at {1}", position.Id, position.EntryPrice);
        }
    }
    
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    from System import Action
    
    class Sample_cBot():
        def on_start(self):
            operation = api.ExecuteMarketOrderAsync(TradeType.Buy, api.SymbolName, 10000, Action[TradeResult](self.on_position_opened))
    
            if (operation.IsExecuting)
                api.Print(operation.ToString())
            else
                api.Print(operation.TradeResult.ToString())
    
        def on_position_opened(self, tradeResult):
            position = tradeResult.Position
    
            api.Print(tradeResult.ToString())
    
            if tradeResult.IsSuccessful:
                api.Print(f"Position {position.Id} opened at {position.EntryPrice}")
    

    Salida del registro

    • El cBot "Nuevo cBot" se inició correctamente para EURUSD, h1.
    • Ejecutando Orden de Mercado para Comprar 10000 EURUSD
    • TradeOperation (Ejecutando Orden de Mercado para Comprar 10000 EURUSD EN EJECUCIÓN)
    • La Ejecución de la Orden de Mercado para Comprar 10000 EURUSD TUVO ÉXITO, Posición PID14579835
    • TradeResult (Éxito, Posición: PID14579835)
    • Posición 14579835 abierta a 1.19414
  • Uso de expresiones lambda

    En lugar de definir un método de devolución de llamada con nombre, puede usar expresiones lambda.

    En el siguiente ejemplo, cuando se coloca una orden, la descripción del resultado se imprimirá en el registro.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [Robot()]
    public class Sample_cBot : Robot
    {
        protected override void OnStart()
        {
            PlaceLimitOrderAsync(TradeType.Buy, SymbolName, 10000,
                    Symbol.Ask - 20 * Symbol.PipSize, "myLabel", result => Print(result.ToString()));
        }
    }
    
    1
    2
    3
    4
    5
    from System import Action
    
    class Samples():
        def on_start(self):
            operation = api.PlaceLimitOrderAsync(TradeType.Buy, api.SymbolName, 10000, api.Symbol.Ask - 20 * api.Symbol.PipSize, "myLabel", Action[TradeResult](lambda result: api.Print(result.ToString())))
    

    Salida del registro

    • El cBot "Nuevo cBot" se inició correctamente para EURUSD, h1.
    • Colocando Orden Limitada para Comprar 10000 EURUSD (Precio: 1.19320)
    • La Colocación de la Orden Limitada para Comprar 10000 EURUSD (Precio: 1.19320) TUVO ÉXITO, Orden Pendiente OID25222083
    • TradeResult (Éxito, Orden Pendiente: OID25222083)

Image title