Трендовый робот на основе индикатора Bollinger

  1. Filip

    Регистрация:
    10.05.16
    Сообщения:
    28
    Был на сайте:
    20.08.17

    Трендовый робот на основе индикатора Bollinger.


    Торговая логика робота:

    Стратегия реверсивная.

    Вход лонг : Закрытие свечки происходит выше верхнего значения индикатора Bollinger. Пробитие индикатора вверх.

    Вход шорт: Закрытие свечки происходит ниже нижнего значения индикатора Bollinger. Пробитие индикатора вниз.


    Выход из Лонга: Закрытие свечки происходит ниже нижнего значения индикатора Bollinger. Пробитие индикатора вниз.

    Выход из Шорта: Закрытие свечки происходит выше верхнего значения индикатора Bollinger. Пробитие индикатора вверх.


    Окно с настройками стратегии:

    1. Режим. On - включен. Off - отключен; OnlyLong - входим только в лонг; OnlyShort - входим только в шорт; OnlyClosePosition - закрываем позиции.

    2. Объем фиксированный - количество лотов на вход.

    3. Проскальзывание - величина проскальзывания в пунктах.


    Настройка индикатора:

    Настройка Bollinger используемого в алгоритме робота

    осуществляется как стандартная настройка и индикатора через меню настроек индикаторов при нажатии правой кнопки мыши на графике


    Filip
    05.12.2016 18:02
    #1
  2. Pherino

    Регистрация:
    05.05.17
    Сообщения:
    7
    Был на сайте:
    18.07.20

    Здравствуйте!

    Решил переделать поведение робота на открытие/закрытие позиции при касании параболика. Подписался на событие

    _tab.CandleUpdateEvent += LogicToUpdateLastCandle;

    Сам метод выглядит так (добавил свои комментарии).

            private void LogicToUpdateLastCandle(List<Candle> candles)
            {
                // если не торгуем, то выход
                if (Regime == BotTradeRegime.Off) return;
    
                // если баров меньше трёх, то выход
                if (candles.Count < 3) return;
    
                // берем открытие на предыдущем (закрытом) баре
                decimal _prevOpen = candles[candles.Count - 2].Open;
    
                // берем значение параболика на предыдущем (закрытом) баре 
                decimal _prevSAR = _sar.Values[_sar.Values.Count - 2];
    
                // если открытие было выше параболика, то "тренд" вверх
                Boolean upTrend = _prevOpen > _prevSAR;
    
                // если текущий хай (активного бара) выше предыдущего параболика, то касание вверх
                Boolean touchUp = candles[candles.Count - 1].High >= _prevSAR;
    
                // если текущий лоу (активного бара) ниже предыдущего параболика, то касание вниз
                Boolean touchDn = candles[candles.Count - 1].Low <= _prevSAR;
                
                // касание вверх учитываем на "тренде" вниз
                touchUp = touchUp && !upTrend;
                
                // касание вниз учитываем на "тренде" вверх
                touchDn = touchDn && upTrend;
    
                // текущая позиция (0: отсутстсвует, 1: лонг, -1: шорт)
                Int32 currentPos = 100;
                // если открытых позиций нет или их кол-во равно нулю, то currentPos = 0
                if ( _tab.PositionsOpenAll == null || _tab.PositionsOpenAll.Count == 0 ) currentPos = 0;
                
                // последняя позиция
                Position lastPos;
                if (currentPos == 100)
                {
                    // берем последнюю позицию
                    // и вот тут сомнения в правильности использования PositionsOpenAll
                    // может быть правильнее брать PositionsAll ?? 
                    lastPos = _tab.PositionsOpenAll[0];
                    // если позиция в процессе открытия или закрытия, то выход
                    if (lastPos.State == PositionStateType.Opening) return;
                    if (lastPos.State == PositionStateType.Closing) return;
                    // возвращаем в currentPos в зависимости от lastPos.Direction
                    currentPos = lastPos.Direction == Side.None ? 0 : lastPos.Direction == Side.Buy ? 1 : -1;
                }
    
                // если позиции нет
                if (currentPos == 0) {
                    // если касание вверх и режим не только шорт, то купить по рынку
                    if (touchUp && Regime != BotTradeRegime.OnlyShort) _tab.BuyAtMarket(VolumeFix);
                    // если касание вниз и режим не только лонг, то продать по рынку
                    if (touchDn && Regime != BotTradeRegime.OnlyLong) _tab.SellAtMarket(VolumeFix);
                    return;
                }
    
                // если сейчас шорт и касание вверх
                if (currentPos < 0 && touchUp ) {
                    // купить по рынку
                    _tab.BuyAtMarket(VolumeFix);
                    // если режим закрытия позиций или только шорт, то выход
                    if (Regime == BotTradeRegime.OnlyClosePosition) return;
                    if (Regime == BotTradeRegime.OnlyShort) return;
                    // еще купить по рынку
                    _tab.BuyAtMarket(VolumeFix);
                    return;
                }
    
                // если сейчас лонг и касание вниз
                if (currentPos > 0 && touchDn ) {
                    // продать по рынку
                    _tab.SellAtMarket(VolumeFix);
                    // если режим закрытия позиций или только лонг, то выход
                    if (Regime == BotTradeRegime.OnlyClosePosition) return;
                    if (Regime == BotTradeRegime.OnlyLong) return;
                    // еще продать по рынку
                    _tab.SellAtMarket(VolumeFix);
                    return;
                }
            }
    

    Пару раз сработало как положено, но в следующее касание робот начал кидать заявки в рынок, пока в транзакциях квика не появилось:

    Превышено максимальное количество транзакций 30 в интервале 1 сек
    Ошибка создания заявки. [GW][332] "Нехватка средств по лимитам клиента."

    Подозреваю, что я где-то не разобрался со статусами позиций. Прошу помочь в этом вопросе. Спасибо заранее.

    Pherino
    17.02.2020 15:24
    #2
  3. Алексей Ван Команда форума

    Регистрация:
    02.02.13
    Сообщения:
    960
    Был на сайте:
    27.10.20
    Цитата: Pherino

    Здравствуйте!

     

    Превышено максимальное количество транзакций 30 в интервале 1 сек
    Ошибка создания заявки. [GW][332] "Нехватка средств по лимитам клиента."

    Подозреваю, что я где-то не разобрался со статусами позиций. Прошу помочь в этом вопросе. Спасибо заранее.

    Не вижу ошибки по тому что есть. Надо ж разбираться сидеть. Переделывайте. Для начала откажитесь от своего С++ стайла. Там же есть перечисления нормальные. 

    Алексей Ван
    17.02.2020 16:26
    #3
  4. Pherino

    Регистрация:
    05.05.17
    Сообщения:
    7
    Был на сайте:
    18.07.20

    Фрагмент определения текущей позиции currentPos заменил на такой:

    // получить все позиции
    List<Position> positions = _tab.PositionsAll;
    // если пусто, то currentPos = 0
    if (positions == null || positions.Count == 0) currentPos = 0;
    else {
        // если есть открывающиеся позиции, то выход
        if (_tab.PositionsAll.FindAll(position => position.State == PositionStateType.Opening) != null) return;
        // если есть закрывающиеся позиции, то выход
        if (_tab.PositionsAll.FindAll(position => position.State == PositionStateType.Closing) != null) return;
    
        // получить открытые позиии
        positions = _tab.PositionsAll.FindAll(position => position.State == PositionStateType.Open);
        // если открытых нет, то currentPos = 0
        if (positions == null || positions.Count == 0) currentPos = 0;
        else {
            // взять первую открытую позицию
            Position lastPos = positions[0];
            currentPos = lastPos.Direction == Side.None ? 0 : lastPos.Direction == Side.Buy ? 1 : -1;
        }
    }
    

    Пока наблюдаю.

    Pherino
    17.02.2020 16:43
    #4