Skip to content

How to Handle Bar Events

Bar events are essential to the lifecycle of any cBot. Properly handling these events is crucial for managing how your cBots react to new market conditions. In this article and its corresponding video, we will demonstrate the key types of bar events and discuss the handlers for these events exposed by the cTrader API.

Note

The term 'bar' refers to different types of objects that are sequentially drawn on the trading chart by cTrader. It could be candlesticks, Renko bricks, Range bars or even Heiken-Anshi candles.

Handling the BarOpened Event

Bar events occur when a new bar starts to be plotted on the trading chart to which a cBot is attached. The BarOpened event occurs for the new bar that has just started to be drawn on the chart.

Handling this event is done via the OnBar() method, which an inherited method from the base Robot class. We will now create a cBot that handles the BarOpened event as part of our strategy for analysing market sentiment. We will delete the OnStart() and OnStop() methods from the template and replace the OnTick() handler with the OnBar() handler.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
protected override void OnBar()
{
    var previousBar = Bars[Bars.Count - 2];
    var priceDifference = ((Bars.LastBar.Open - previousBar.Open) / previousBar.Open) * 100;
    if (priceDifference > 1)
    {
        ExecuteMarketOrder(TradeType.Buy, SymbolName, 10000);
    }
    else if (priceDifference < -1)
    {
        ExecuteMarketOrder(TradeType.Sell, SymbolName, 10000);
    }
    else 
    {
        foreach (var position in Positions) 
        {
            position.Close();
        }
    }
}

The cBot is supposed to be launched on charts with the D1 timeframe. On every bar, it compares the open price difference with the previous bar open price and places a new order in a suitable direction. If the price difference is insignificant, the bot instead closes all currently open positions.

If we run a backtest of this simple bot, the results seem to be encouraging.

Handling the BarClosed Event

When a new bar just opens, it effectively lacks any price data apart from its open price. In many cases, you may want your cBot to access data from the previous bar too so that your strategy is executed smoothly. This is why the BarClosed event occurs for the bar that has just closed (i.e., the one immediately prior to the new bar) and allows you to easily use its price and volume data. When the BarClosed event is triggered, the newly opened bar is entirely omitted from the Bars collection

To handle the BarClosed event, the API exposes the OnBarClosed method.

Note

In the previous example, we used the Bars.LastBar.Open property to get the open price of the newly opened bar. If we used the same property in the OnBarClosed() method, we would get the open price of the bar that has just closed.

We will create a simple cBot that uses the OnBarClosed() handler as follows.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
protected override void OnBarClosed()
{
    var lowCloseDifference = ((Bars.LastBar.Close - Bars.LastBar.Low) / Bars.LastBar.Close) * 100;
    if (lowCloseDifference > 0.5)
    {
        foreach (var position in Positions)
        {
            position.Close();
        }
        ExecuteMarketOrder(TradeType.Buy, SymbolName, 10000, null, null, 50);

    }
}

The cBot detect a bullish 'hammer' pattern evaluating the length of the bottom wick of a candle. If a hammer pattern is detected, all previously open positions are closed and a new buy order is placed with a 50-pip stop loss.

If we backtest the bot, we will get decent results.

Adding Custom Event Handlers

When handling the BarOpened and BarClosed events, you can also use a slightly different syntax by assigning these events with custom handlers. While OnBar() and OnBarClosed() are only triggered once, you can assign as many custom handlers as you want, which allows for adding complex logic.

Note

Custom event handlers must be added in the OnStart() method. Custom handlers must also accept an argument of the BarOpenedEventArgs (for the BarOpened event) or the BarClosedEventArgs (for the BarClosed event) types.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
protected override void OnStart() 
{
    Bars.BarClosed += BarClosedHandler;
    Bars.BarClosed += AnotherClosedHandler;
    Bars.BarOpened += BarOpenedHandler;
}

void BarClosedHandler(BarClosedEventArgs args) {}
void AnotherClosedHandler(BardClosedEventArgs args) {}
void BarOpenedHandler(BarOpenedEventArgs args) {}

We will create another cBot that uses two custom handlers for the BarOpened event to react to possible bullish and bearish reversals.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
protected override void OnStart() 
{
    Bars.BarOpened += BullishReversal;
    Bars.BarOpened += BearishReversal;

}

private void BullishReversal(BarOpenedEventArgs args) 
{
    if (Bars.LastBar.Open > Bars.Last(1).Close && Bars.LastBar.Open > Bars.Last(2).Close) 
    {
        ExecuteMarketOrder(TradeType.Buy, SymbolName, 10000, null, 10, 50);
    }
}

private void BearishReversal(BarOpenedEventArgs args) 
{
    if (Bars.LastBar.Open < Bars.Last(1).Close && Bars.LastBar.Open < Bars.Last(2).Close) 
    {
        ExecuteMarketOrder(TradeType.Sell, SymbolName, 10000, null, 10, 50);
    }
}

The bot checks if the open price of the newly opened bar is higher than the close prices of two preceeding bars. If this is the case, a buy order is placed. If the open price is lower than the close prices of two preceding bars, a sell order is placed. The use of two separate event handlers allows us to separate our trading logic into smaller components which we can easily modify later if needed.

The results of backtesting on a D1 timeframe are also positive.

Summary

By learning how to properly handle bar events, you can make your cBots do exactly what you want them to do and you want them to do it. To learn more about using and developing cBots, feel free to browse other sections of the documentation and subscribe to our YouTube channel to be notified when we publish a new video.

Subscribe to our YouTube channel