Skip to content

cBot Lifecycle

In this article and its accompanying video, we step through the code structure and explain the logic behind the events and lifecycle of a cTrader cBot.

As a reminder, you can access your cBots in the 'Algo' application in cTrader. To create a new cBot, simply click on the 'New cBot' button or select this option in the drop-down shown below.

How to Interpret the Basic Template

After creating a new cBot, you should see the following basic structure in the code editor window.

 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
26
27
28
29
30
31
32
33
34
35
36
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Robots
{
    [Robot(AccessRights = AccessRights.None)]
    public class NewcBot : Robot
    {
        [Parameter(DefaultValue = "Hello world!")]
        public string Message { get; set; }

        protected override void OnStart()
        {
            // To learn more about cTrader Automate visit our Help Center:
            // https://help.ctrader.com/ctrader-automate

            Print(Message);
        }

        protected override void OnTick()
        {
            // Handle price updates here
        }

        protected override void OnStop()
        {
            // Handle cBot stop here
        }
    }
}

Note that are just three events displayed in the basic template; these events are handled by the OnStart(), OnTick(), and OnStop() methods. We will add two additional methods (OnBar() and OnException()) and explain how they work later; first, we will discuss the OnStart() method.

How to Use the OnStart() Method

The OnStart() method is triggered when a cBot first starts. It is used to initialize any variables you plan to use in your cBot including indicators, counters, event handlers, or timers.

Initial Code Template

The initial code template already includes a code statement to print a message to the log when a cBot starts. As you can see, our cBot has the Message parameter, and the OnStart() method passes the value of this parameter to the Print() method.

We can demonstrate how the OnStart() method works by simply starting the cBot instance in the 'Trade' application and opening the log tab to see the result.

We can also stop the cBot at any time, change the value of the Message parameter in the 'Parameters' tab, and restart our instance. On start, our new message will still be printed to the log.

How to Use the OnTick() Method

The OnTick() method is triggered every time the symbol bid or ask price changes. Inside this method, you can typically program position entry and exit conditions as well as any other auxiliary functions you need to run when a new tick of data arrives.

We will add the following code to the OnTick() method so that it prints a message to the log.

1
Print("OnTick. Bid: ", Symbol.Bid, ", Ask: ", Symbol.Ask);

As you can see below, our cBot now prints bid and ask prices to the log on every price change.

How to Use the OnBar() Method

The OnBar() method is not included in the default cBot code template so we will add the following code snippet to add it.

1
2
3
4
protected override void OnBar() 
{
    Print("OnBar");
}

The OnBar() method is triggered whenever a new bar or candle is drawn on the chart to which a cBot is attached. Similarly to the OnTick() method, you can use the OnBar() method to program the position entry and exit conditions as well as any other logics that need to be executed on the formation of each new bar.

How the OnBar() Method Is Triggered

If you have an H1 chart, a new bar is formed every hour, meaning that the OnBar() method will be called once per hour. If you have an m1 chart, the same method will be called once per minute.

Our OnBar() method will print "OnBar" on every new bar/candle. To demonstrate how it works, we will attach our cBot to an m1 chart and take a look at the log.

How to Use the OnStop() Method

The OnStop method is called when the cBot stops either by the user or via the code, when this happens any code inside the OnStop method is executed. This can be used to perform final operations, like closing positions.

We will add the following code to our OnStop() method - as usual, our cBot will print the value of the Message parameter when it is stopped.

1
Print(Message);

In the screenshot below, we launch and stop an instance of our cBot to demonstrate how it all works.

How to Use the OnException() Method

The OnException() method event is a form of fault-tolerance for your cBot to capture unhandled exceptions and allow you to decide what to do with them. It is not included in the default code template so we will add it ourselves using the following snippet.

1
2
3
4
protected override void OnException(Exception exception) 
{
    Print("Ooops, unhandled exception! No worries, cBot still alive");            
}

To trigger the OnException() method, we will write some code to capture an exception that occurs when we try to access information about a trade that no longer exists. We will add the code below to our OnStart() method.

1
ExecuteMarketOrder(TradeType.Buy, SymbolName, 1000, "my label");

The code we have written in the OnStart() method will execute a market order with the following configurable parameters.

  • The trade type will be a buy order.
  • The trade will be executed for the current symbol for the chart to which the cBot is attached.
  • The order volume will be 1,000 units.
  • The unique label attached to the order will be "my label".

We will also add the following code to the OnTick() method.

1
2
3
var position = Positions.Find("my label");
if (Positions.Find("my label") != null) Print("PositionId: ", position.Id);
Print("Message below");

The code we have written in the OnTick() method will find the position that was opened in the OnStart() method using the label name “my label”.

If the position is found with the same label, it will then print to the log the position ID of the open trade. It will also print another message called “Message below” as the next line of code is executed.

When our cBot is launched and the OnTick() method is called and the order is found, the cBot will print the order ID to the log and, after the order ID, it will print the "Message below" message.

As you can see, no exceptions are arising and our cBot does its job perfectly.

Now, however, we will manually close the position opened by the cBot and make small changes to the code so that an exception is guaranteed to happen. In the OnStart() method, we will change the order label to "cTrader". In the OnTick() method, we will comment out the condition that checks if there exists a position with the "my label" label.

Here is the final code of our cBot - note that this code will always trigger an exception.

 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
26
27
28
29
30
31
32
namespace cAlgo.Robots
{
    [Robot(AccessRights = AccessRights.None)]
    public class LifecycleTest : Robot
    {
        [Parameter(DefaultValue = "cTrader rocks!")]
        public string Message { get; set; }

        protected override void OnStart()
        {
            ExecuteMarketOrder(TradeType.Buy, SymbolName, 1000, "cTrader");
        }

        protected override void OnTick()
        {
            var position = Positions.Find("my label");
            //if (Positions.Find("my label") != null) 
            Print("PositionId: ", position.Id);
            Print("Message below");
        }

        protected override void OnStop()
        {
            Print(Message);
        }

        protected override void OnException(Exception exception) 
        {
            Print("Ooops, unhandled exception! No worries, cBot still alive");            
        }
    }
}

We will run the cBot again and see what happens.

What happened is that a new market order was created when the cBot started. The label attached to this order was "cTrader". In the OnTick() method, the code attempted to get a position with the label of “my label” and as we commented out the line of code with the conditional. It then attempted to print to the log the position ID.

This caused an exception error that would normally have stopped the cBot in previous versions of cTrader, but with the new OnException() method, we can now capture this and handle the error. The cBot will continue to run and we can log the error so it can be fixed.

Summary

In summary, the cBot lifecycle consists of several key events you can handle via the OnStart(), OnTick(), OnStop(), OnBar() and OnException() methods. By customizing how your cBot responds to major events, you can ensure that your algorithms behave exactly as expected.


Last update: May 4, 2023