Перейти к содержанию

Как обрабатывать события баров

События баров являются неотъемлемой частью жизненного цикла любого сиБота. Правильная обработка этих событий крайне важна для управления реакцией ваших сиБотов на новые рыночные условия. В этой статье и соответствующем видео мы продемонстрируем ключевые типы событий баров и обсудим обработчики этих событий, предоставляемые API cTrader.

  • Бар — относится к различным типам объектов, которые последовательно отображаются на торговом графике в cTrader. Это могут быть японские свечи, кирпичи Ренко, диапазонные бары или даже свечи Хайкен Аши.

Обработка события BarOpened

События баров происходят, когда новый бар начинает отображаться на торговом графике, связанном с сиБотом. Событие BarOpened происходит для нового бара, который только что начал отображаться на графике.

Обработка этого события осуществляется через метод OnBar(), который является унаследованным методом от базового класса Robot. Теперь мы создадим сиБота, который обрабатывает событие BarOpened как часть нашей стратегии для анализа рыночных настроений. Мы удалим методы OnStart() и OnStop() из шаблона и заменим обработчик OnTick() на обработчик OnBar().

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

сиБот должен быть запущен на графиках с таймфреймом D1 (дневной). На каждом баре он сравнивает разницу цены открытия с ценой открытия предыдущего бара и размещает новый ордер в подходящем направлении. Если разница цен незначительна, бот вместо этого закрывает все текущие открытые позиции.

Если мы запустим бэктестинг этого простого бота, результаты покажутся обнадеживающими.

Обработка события BarClosed

Когда открывается новый бар, у него фактически отсутствуют какие-либо ценовые данные, кроме цены открытия. Во многих случаях вам может потребоваться, чтобы ваш сиБот получал доступ к данным предыдущего бара для обеспечения плавного выполнения стратегии. Именно поэтому событие BarClosed происходит для бара, который только что закрылся (того, который непосредственно предшествует новому бару), и позволяет легко использовать его данные о цене и объеме. Когда срабатывает событие BarClosed, только что открывшийся бар полностью исключается из коллекции Bars

Для обработки события BarClosed API предоставляет метод OnBarClosed.

Примечание

В предыдущем примере мы использовали свойство Bars.LastBar.Open для получения цены открытия только что открывшегося бара. Если бы мы использовали то же свойство в методе OnBarClosed(), мы бы получили цену открытия бара, который только что закрылся.

Мы создадим простого сиБота, который использует обработчик OnBarClosed() следующим образом.

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

    }
}

сиБот обнаруживает восходящий паттерн (молот), оценивая длину нижней тени свечи. Если обнаружен паттерн молота, все ранее открытые позиции закрываются и размещается новый ордер на покупку со стоп-лоссом в 50 пипов.

Если мы проведем бэктестинг бота, мы получим достойные результаты.

Добавление пользовательских обработчиков событий

При обработке событий BarOpened и BarClosed вы также можете использовать немного другой синтаксис, назначая этим событиям пользовательские обработчики. В то время как OnBar() и OnBarClosed() срабатывают только один раз, вы можете назначить столько пользовательских обработчиков, сколько захотите, что позволяет добавлять сложную логику.

Примечание

Пользовательские обработчики событий должны быть добавлены в методе OnStart(). Пользовательские обработчики также должны принимать аргумент типа BarOpenedEventArgs (для события BarOpened) или BarClosedEventArgs (для события BarClosed).

 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(BarClosedEventArgs args) {}
void BarOpenedHandler(BarOpenedEventArgs args) {}

Мы создадим еще одного сиБота, который использует два пользовательских обработчика для события BarOpened, чтобы реагировать на возможные восходящие и нисходящие развороты.

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

сиБот проверяет, выше ли цена открытия только что открывшегося бара, чем цены закрытия двух предыдущих баров. Если это так, размещается ордер на покупку. Если цена открытия ниже цен закрытия двух предыдущих баров, размещается ордер на продажу. Использование двух отдельных обработчиков событий позволяет нам разделить нашу торговую логику на более мелкие компоненты, которые мы можем легко изменить позже при необходимости.

Результаты бэктестинга на таймфрейме D1 также положительные.

Обзор

Научившись правильно обрабатывать события баров, вы можете заставить своих сиБотов делать именно то, что вы хотите, чтобы они делали, и делать это тогда, когда вы этого хотите.