Ir para o conteúdo

Amostras de código cBot

Esta página fornece vários exemplos de código Python e C# para criar robôs de negociação e desenvolver algoritmos. Note que nenhum dos cBots listados abaixo garante quaisquer retornos financeiros. Certifique-se de fazer testes de verificação e personalizar os seus cBots antes de implementar quaisquer instâncias numa conta real.

Repositórios de amostras de cBot

Amostras abrangentes de código cBot, incluindo modelos prontos para executar para várias estratégias automatizadas e estilos de negociação, estão disponíveis em repositórios separados de Python e C# no GitHub.

Operações síncronas

Todos os cBots nesta secção executam as suas operações de forma síncrona.

Executar ordens de mercado

  • Um cBot simples que executa operações bem-sucedidas

    O seguinte robô de negociação cria uma ordem de mercado ao iniciar e guarda o resultado na variável result.

    Se a execução da ordem for bem-sucedida, o preço de entrada é impresso no registo.

     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}")
    

    Saída do registo

    • O cBot "Novo cBot" foi iniciado com sucesso para EURUSD, h1.
    • A executar Ordem de Mercado para Comprar 10000 EURUSD
    • A execução da Ordem de Mercado para Comprar 10000 EURUSD foi BEM-SUCEDIDA, Posição PID14576001
    • O preço de entrada da posição é 1,19067
  • Um cBot simples com parâmetros personalizáveis

    Ao declarar várias propriedades do cBot, pode transformá-las em parâmetros personalizáveis usando a declaração [Parameter()]. Quando uma nova instância do seu cBot é lançada, você (ou outros utilizadores) poderá atribuir valores personalizados a estes.

    Considere o seguinte exemplo.

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

    Nota

    Os cBots Python usam parâmetros personalizáveis declarados nos seus ficheiros .cs.

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

    No exemplo acima, definimos as seguintes características:

    • O nome do parâmetro. Posteriormente, aparecerá na interface do cTrader ("Período SMA").
    • O valor predefinido do parâmetro que se aplicará a todas as novas instâncias, a menos que seja alterado pelos utilizadores (DefaultValue = 14).

    No código abaixo, mostramos como a propriedade SmaPeriod pode ser usada num robô de negociação 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

    Os cBots Python usam parâmetros personalizáveis declarados nos seus ficheiros .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}")
    

    O nosso robô utiliza a propriedade personalizável SmaPeriod e, ao iniciar, passa o seu valor para o método Indicators.GetIndicator<SampleSMA>(). Este método retorna um valor de média móvel simples para o período especificado.

    Ao criar uma instância de cBot, todos os parâmetros ajustáveis podem ser configurados na janela Adicionar instância.

    Quando lançado, o cBot informa-nos qual foi o último valor da média móvel simples a cada tick.

    Saída do registo

    • A instância do CBot [Sample cBot Reference SMA, EURUSD, h1] foi iniciada.
    • 0,975685714285714
    • 0,975681428571429
    • 0,97568
    • A instância do CBot [Sample cBot Reference SMA, EURUSD, h1] foi interrompida pelo utilizador.
  • Executar uma ordem de mercado com mais argumentos

    No exemplo anterior, passámos o número mínimo possível de argumentos para o método ExecuteMarketOrder(). Eram o tipo de negociação (TradeType.Buy), o símbolo (Symbol) e o volume (-1).

    O método ExecuteMarketOrder() pode ser chamado com argumentos adicionais como Label, StopLoss, TakeProfit e Comment. O exemplo abaixo especifica a etiqueta ("order 1"), o mecanismo de proteção de stop-loss (10) e o nível 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}")
    

    Saída do registo

    • O cBot "Novo cBot" foi iniciado com sucesso para EURUSD, h1.
    • A executar Ordem de Mercado para Comprar 10000 EURUSD (SL: 10, TP: 10)
    • A execução da Ordem de Mercado para Comprar 10000 EURUSD (SL: 10, TP: 10) foi BEM-SUCEDIDA, Posição PID14576098
    • O preço de entrada da posição é 1,1896
    • O preço de SL da posição é 1,1886

Modificar uma posição

No exemplo abaixo, apenas adicionamos um valor de take profit (10) quando uma ordem é executada. Depois, modificamos a posição para adicionar um 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}")

Saída de registo

Fechar uma posição

  • Realizar um fecho total

    A amostra de código abaixo coloca uma ordem de mercado. Se o lucro bruto da posição resultante exceder um determinado valor (null && position.GrossProfit > 10), é fechada.

     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()
    

    Saída do registo

    • O cBot "Novo cBot" foi iniciado com sucesso para EURUSD, h1.
    • A executar Ordem de Mercado para Comprar 10000 EURUSD
    • A execução da Ordem de Mercado para Comprar 10000 EURUSD foi BEM-SUCEDIDA, Posição PID14576180
  • Realizar um fecho parcial

    Vamos modificar o exemplo anterior para criar duas ordens de mercado com as mesmas etiquetas ("myLabel"). Em cada nova barra, o nosso robô de negociação fechará exatamente metade de uma destas ordens, mas apenas se o seu volume for igual ou superior a 20.000.

    Também usamos o método Positions.FindAll(). Ele retorna uma lista de posições que podemos percorrer.

     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)
    

    Saída do registo

    • O cBot "Novo cBot" foi iniciado com sucesso para EURUSD, h1.
    • A executar Ordem de Mercado para Comprar 20000 EURUSD
    • A execução da Ordem de Mercado para Comprar 20000 EURUSD foi BEM-SUCEDIDA, Posição PID14579299
    • A executar Ordem de Mercado para Comprar 30000 EURUSD
    • A execução da Ordem de Mercado para Comprar 30000 EURUSD foi BEM-SUCEDIDA, Posição PID14579300

Criar ordens pendentes

  • Criar ordens de limite e stop

    As ordens de limite e stop são ordens pendentes; apesar disso, são criadas de forma semelhante às ordens de mercado. No entanto, ao criar ordens de limite e stop, também tem de especificar o seu preço-alvo e não há intervalo de mercado.

    Este cBot cria duas ordens de limite e uma ordem de stop. Em seguida, percorre as ordens e imprime as suas etiquetas e IDs no registo.

     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}")
    

    Saída do registo

    • O cBot "Novo cBot" foi iniciado com sucesso para EURUSD, h1.
    • A colocar Ordem de Limite para Comprar 10000 EURUSD (Preço: 1,19036)
    • A colocação da Ordem de Limite para Comprar 10000 EURUSD (Preço: 1,19036) foi BEM-SUCEDIDA, Ordem Pendente OID25220794
    • A colocar Ordem de Limite para Comprar 20000 EURUSD (Preço: 1,19017)
    • A colocação da Ordem de Limite para Comprar 20000 EURUSD (Preço: 1,19017) foi BEM-SUCEDIDA, Ordem Pendente OID25220795
    • A colocar Ordem de Stop para Comprar 10000 EURUSD (Preço: 1,19040)
    • A colocação da Ordem de Stop para Comprar 10000 EURUSD (Preço: 1,19040) foi BEM-SUCEDIDA, Ordem Pendente OID25220796
    • Ordem colocada com etiqueta myLimitOrder, id 25220794
    • Ordem colocada com etiqueta myLimitOrder, id 25220795
    • Ordem colocada com etiqueta myStopOrder, id 25220796
  • Criar ordens pendentes com mais parâmetros

    Tal como no caso das ordens de mercado, também pode especificar a etiqueta da ordem, vários mecanismos de proteção, a data de expiração da ordem e fornecer um comentário.

     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}")
    

    Saída do registo

    • O cBot "Novo cBot" foi iniciado com sucesso para EURUSD, h1.
    • A colocar Ordem de Limite para Comprar 10000 EURUSD (Preço: 1,19049, SL: 10, Hora de Expiração: 12/05/2018 00:00:00)
    • A colocação da Ordem de Limite para Comprar 10000 EURUSD (Preço: 1,19049, SL: 10, Hora de Expiração: 12/05/2018 00:00:00) foi BEM-SUCEDIDA, Ordem Pendente OID25220807
    • A colocar Ordem de Stop para Comprar 10000 EURUSD (Preço: 1,19053, SL: 10, TP: 10)
    • A colocação da Ordem de Stop para Comprar 10000 EURUSD (Preço: 1,19053, SL: 10, TP: 10) foi BEM-SUCEDIDA, Ordem Pendente OID25220808
    • Ordem de Limite
    • SL da Primeira Ordem de Limite: 1,18949
    • SL da Segunda Ordem de Stop: 1,18953 TP: 1,19153

Modificar ordens pendentes

É possível modificar várias características das ordens pendentes.

O exemplo abaixo mostra como modificar o preço-alvo, os níveis de proteção ou a data e hora de expiração de uma ordem pendente.

 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)

Saída de registo

Cancelar ordens pendentes

A sintaxe para cancelar uma ordem é CancelPendingOrder(order), onde order é do tipo PendingOrder.

O exemplo abaixo mostra o cancelamento de todas as ordens com a 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 posição

É possível subscrever eventos relacionados com várias operações de negociação. Por exemplo, para testar se uma posição é aberta, subscrevemos um evento que é acionado para todos os objetos Position na abertura.

 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}")

Saída de registo

Da mesma forma, é possível subscrever eventos que são acionados sempre que uma posição é fechada.

 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")

Saída de registo

Conversão de coordenadas

O cBot abaixo permite aos utilizadores colocar ordens de limite numa direção adequada simplesmente clicando com o botão direito do rato num gráfico. Consegue isto convertendo as coordenadas Y do rato em coordenadas Y do gráfico (que, para símbolos, correspondem aos preços dos 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)

Execução assíncrona

As amostras de código acima são projetadas para implementar robôs de negociação usando execução síncrona. Tanto C# como Python suportam operações assíncronas, permitindo que o seu cBot execute várias ações dentro do mesmo período de tempo.

Executar ordens de mercado de forma assíncrona

A sintaxe dos métodos assíncronos é semelhante à dos síncronos. Embora aceitem os mesmos tipos de argumentos, o seu tipo de retorno é TradeOperation em vez de TradeResult.

  • Operações assíncronas básicas

    O seguinte cBot demonstra como funcionam as operações assíncronas. Uma ordem de mercado é criada; na próxima condicional, o cBot verifica se a operação está a ser executada.

     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")
    

    Saída do registo

    • O cBot "Novo cBot" foi iniciado com sucesso para EURUSD, h1.
    • A executar Ordem de Mercado para Comprar 10000 EURUSD
    • A operação está a ser executada
    • A executar Ordem de Mercado para Comprar 10000 EURUSD BEM-SUCEDIDA, Posição PID14579532
  • Executar uma ordem

    O próximo exemplo destaca a diferença entre métodos síncronos e assíncronos.

    O cBot verifica se uma operação está a ser executada logo após chamar um método assíncrono. Faz isso novamente após chamar um método síncrono. A saída de registo para estas duas açõ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")
    

    Saída do registo

    • O cBot "Novo cBot" foi iniciado com sucesso para EURUSD, h1.
    • A executar Ordem de Mercado para Comprar 10000 EURUSD
    • A operação está a ser executada
    • A executar Ordem de Mercado para Comprar 20000 EURUSD
    • A executar Ordem de Mercado para Comprar 10000 EURUSD BEM-SUCEDIDA, Posição PID14579541
    • A executar Ordem de Mercado para Comprar 20000 EURUSD BEM-SUCEDIDA, Posição PID14579542
    • Operação executada
  • Executar uma ordem com mais parâmetros

    O seguinte cBot coloca uma ordem especificando a sua etiqueta ("myLabel"), níveis de proteção (10, 10), símbolo (SymbolName) e volume (10000).

    O exemplo também contém a coleção Positions e o método FindAll(). Find() e FindAll() podem ser usados para encontrar posições com a mesma etiqueta, símbolo e tipo de negociação.

     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()            
    

    Saída do registo

    • O cBot "Novo cBot" foi iniciado com sucesso para EURUSD, h1.
    • A executar Ordem de Mercado para Comprar 10000 EURUSD (SL: 10, TP: 10)
    • A executar Ordem de Mercado para Comprar 10000 EURUSD (SL: 10, TP: 10) BEM-SUCEDIDA, Posição PID14579719
    • Compra a 1.19087 SL null
    • Compra a 1.19357 SL 1.19257
    • cBot Novo cBot" foi parado para EURUSD, h1."

Modificar posição de forma assíncrona

O cBot abaixo coloca uma ordem de mercado e depois modifica a posição recém-aberta.

 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)        

Saída de registo

Fechar uma posição de forma assíncrona

O próximo exemplo demonstra o fecho de uma posição de forma assíncrona, se ela existir.

O método Find() é usado para procurar na coleção Positions a posição com uma 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()        

Saída de registo

Colocar ordens de limite e stop de forma assíncrona

Como mencionado acima, colocar ordens pendentes é semelhante a criar ordens de mercado.

No entanto, existem algumas pequenas diferenças nos argumentos entre estes dois métodos. O intervalo de mercado está ausente da lista de argumentos. Além disso, tem de especificar o preço alvo, e pode passar um argumento opcional especificando a data de validade da ordem.

 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)    

Saída de registo

Modificar ordens pendentes de forma assíncrona

O seguinte cBot modifica ordens de limite de forma assí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)

Saída de registo

Cancelar ordens pendentes de forma assíncrona

  • Cancelar todas as ordens pendentes

    O cBot abaixo cancela de forma assíncrona todas as ordens pendentes atuais.

     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)
    

    Saída do registo

    • cBot "cancelar ordem pendente" foi iniciado com sucesso para EURUSD, h1.
    • A cancelar ordem pendente OID274705
    • A cancelar ordem pendente OID274706
    • A cancelar ordem pendente OID274707
    • A cancelar ordem pendente OID274708
    • A cancelar ordem pendente OID274709
    • A cancelar ordem pendente OID274705 BEM-SUCEDIDA, Ordem Pendente OID274705
    • A cancelar ordem pendente OID274706 BEM-SUCEDIDA, Ordem Pendente OID274706
    • A cancelar ordem pendente OID274707 BEM-SUCEDIDA, Ordem Pendente OID274707
    • A cancelar ordem pendente OID274708 BEM-SUCEDIDA, Ordem Pendente OID274708
    • A cancelar ordem pendente OID274709 BEM-SUCEDIDA, Ordem Pendente OID274709
  • Cancelar ordens pendentes com uma determinada etiqueta

    Este cBot apenas cancela ordens pendentes com uma determinada etiqueta.

     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)
    

Funções de callback para métodos assíncronos

Uma vez que um resultado é retornado, o uso de operações assíncronas frequentemente requer controlar a execução. Para lidar com isto, pode adicionar uma função de callback no final da lista de parâmetros de todos os métodos assíncronos.

Esta função será chamada assim que uma resposta for recebida do servidor. Por exemplo, poderia ser chamada quando uma posição é aberta, modificada ou fechada.

  • Ordem de mercado assíncrona com um callback

     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}")
    

    Saída do registo

    • O cBot "Novo cBot" foi iniciado com sucesso para EURUSD, h1.
    • A executar Ordem de Mercado para Comprar 10000 EURUSD
    • TradeOperation (A executar Ordem de Mercado para Comprar 10000 EURUSD EM EXECUÇÃO)
    • A executar Ordem de Mercado para Comprar 10000 EURUSD BEM-SUCEDIDA, Posição PID14579835
    • TradeResult (Sucesso, Posição: PID14579835)
    • Posição 14579835 aberta a 1.19414
  • Usando expressões lambda

    Em vez de definir um método de callback nomeado, pode usar expressões lambda.

    No seguinte exemplo, quando uma ordem é colocada, a descrição do resultado será impressa no registo.

    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())))
    

    Saída do registo

    • O cBot "Novo cBot" foi iniciado com sucesso para EURUSD, h1.
    • A colocar Ordem de Limite para Comprar 10000 EURUSD (Preço: 1.19320)
    • A colocar Ordem de Limite para Comprar 10000 EURUSD (Preço: 1.19320) BEM-SUCEDIDA, Ordem Pendente OID25222083
    • TradeResult (Sucesso, Ordem Pendente: OID25222083)

Image title