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

Grid cBot

Обзор стратегии

Grid cBot реализует стратегию сеточной торговли, при которой несколько ордеров на покупку или продажу инструмента размещаются с регулярными ценовыми интервалами или «шагами», образуя «сетку» позиций. По мере изменения цены инструмента постоянно открываются новые позиции, чтобы воспользоваться колебаниями.

Grid cBot использует комбинацию простой арифметики и логических проверок для открытия позиций, расчета прибыли и управления своими торговыми операциями. Он наиболее эффективен на рынках с ограниченным диапазоном или боковым движением. Он также хорошо работает в условиях низкой волатильности и на рынках с известными уровнями сопротивления и поддержки.

Создание сиБота

Узнайте, как создавать сиБотов, используя C# или Python, в наших пошаговых руководствах.

Код Grid cBot доступен в наших публичных репозиториях C# и Python. Тот же код предоставляется в качестве шаблона в мастере создания алгоритмов в cTrader Windows или Mac, или вы можете просто скопировать и использовать приведенный ниже фрагмент кода:

 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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
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 Grid : Robot
    {
        [Parameter("Volume (lots)", DefaultValue = 0.01, MinValue = 0.01, Step = 0.01)]
        public double VolumeInLots { get; set; }

        [Parameter("Trade Side")]
        public TradeType TradeType { get; set; }

        [Parameter("Step (pips)", DefaultValue = 5, MinValue = 0.1, Step = 0.1)]
        public double StepPips { get; set; }

        [Parameter("Target Profit", DefaultValue = 20)]
        public double TargetProfit { get; set; }

        private bool enoughMoney = true;

        protected override void OnStart()
        {
            if (GridPositions.Length == 0)
                OpenPosition();
        }

        protected override void OnTick()
        {
            if (GridPositions.Sum(p => p.NetProfit) >= TargetProfit)
            {
                Print("Target profit is reached. Closing all grid positions");
                CloseGridPositions();
                Print("All grid positions are closed. Stopping cBot");
                Stop();
            }
            if (GridPositions.Length > 0 && enoughMoney)
            {
                var lastGridPosition = GridPositions.OrderBy(p => p.Pips).Last();
                var distance = CalculateDistanceInPips(lastGridPosition);

                if (distance >= StepPips)
                    OpenPosition();
            }
        }

        private Position[] GridPositions
        {
            get
            {
                return Positions
                    .Where(p => p.SymbolName == SymbolName && p.TradeType == TradeType)
                    .ToArray();
            }
        }

        private double CalculateDistanceInPips(Position position)
        {
            if (position.TradeType == TradeType.Buy)
                return (position.EntryPrice - Symbol.Ask) / Symbol.PipSize;
            else
                return (Symbol.Bid - position.EntryPrice) / Symbol.PipSize;
        }

        private void OpenPosition()
        {
            var result = ExecuteMarketOrder(TradeType, SymbolName, Symbol.QuantityToVolumeInUnits(VolumeInLots), "Grid");
            if (result.Error == ErrorCode.NoMoney)
            {
                enoughMoney = false;
                Print("Not enough money to open additional positions");
            }
        }

        private void CloseGridPositions()
        {
            while (GridPositions.Length > 0)
            {
                foreach (var position in GridPositions)
                {
                    ClosePosition(position);
                }
            }
        }
    }
}
 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
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import clr

clr.AddReference("cAlgo.API")

# Import cAlgo API types
from cAlgo.API import *

# Import trading wrapper functions
from robot_wrapper import *

class GridSample():
    def on_start(self):
        self.volumeInUnits = api.Symbol.QuantityToVolumeInUnits(api.VolumeInLots)
        self.enoughMoney = True
        if len(self.get_grid_positions()) == 0:
            self.open_position()

    def on_tick(self):
        grid_positions = self.get_grid_positions()
        net_profit_sum = sum([p.NetProfit for p in grid_positions])
        if net_profit_sum >= api.TargetProfit:
            api.Print("Target profit is reached. Closing all grid positions")
            self.close_grid_positions()
            api.Print("All grid positions are closed. Stopping cBot")
            api.Stop()

        if len(grid_positions) > 0 and self.enoughMoney == True:
            position_with_highest_pips = sorted(grid_positions, key=lambda pos: pos.Pips, reverse=True)[0]
            distance = self.get_distance_in_pips(position_with_highest_pips)          
            if distance >= api.StepPips:
                self.open_position()

    def get_grid_positions(self):
        return [pos for pos in api.Positions if pos.SymbolName == api.SymbolName and pos.TradeType == api.TradeType]

    def open_position(self):
        result = api.ExecuteMarketOrder(api.TradeType, api.SymbolName, self.volumeInUnits, "Grid")
        if result.Error == ErrorCode.NoMoney:
            self.enoughMoney = False
            api.Print("Not enough money to open additional positions")

    def close_grid_positions(self):
        for position in self.get_grid_positions():
            position.Close()

        if len(self.get_grid_positions()) > 0:
            self.close_grid_positions()

    def get_distance_in_pips(self, position):
        return (position.EntryPrice - api.Symbol.Ask if position.TradeType == TradeType.Buy else api.Symbol.Bid - position.EntryPrice) / api.Symbol.PipSize

Интеграция индикатора

Grid cBot не полагается на какой-либо индикатор для определения своей сеточной стратегии; он не пытается предсказать, пойдет ли цена инструмента вверх или вниз. Вместо этого он нацелен на прибыльные сделки от движения цены в любом направлении.

СиБот выполняет сделки на основе этого простого правила: если цена инструмента изменяется более чем на указанное количество пипов (определяемое параметром StepPips), сиБот открывает новую позицию.

Расчет и логика

Исполнение первой сделки

Когда сиБот запускается, он проверяет, есть ли открытые позиции в сетке. Если открытых позиций нет, сиБот немедленно открывает первую позицию с помощью метода OpenPosition(). Этот первый шаг гарантирует, что сетка начинается с начальной сделки на основе указанной стороны торговли (TradeType).

Мониторинг прибыли

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

Целевая прибыль — это сумма чистой прибыли от каждой позиции в сетке.

\[ \text{Total net profit} = \sum_{i=1}^{n} \text{NetProfit}(p_i) \]

\(n\) — количество открытых позиций в сетке

\(\text{NetProfit}(p_i)\) — чистая прибыль позиции \(i\)

Открытие позиций

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

Для позиций на покупку:

\[ D_b = \frac{P_e - P_a}{S} \]

Для позиций на продажу:

\[ D_s = \frac{P_b - P_e}{S} \]

\(D_b\) — расстояние в пипах между ценой входа и текущей ценой покупки.

\(D_s\) — расстояние в пипах между текущей ценой продажи и ценой входа.

\(P_e\) — цена, по которой была открыта последняя позиция на покупку для инструмента.

\(P_a\) — текущая цена покупки для инструмента.

\(P_b\) — текущая цена продажи для инструмента.

\(S\) — стоимость одного пипа для инструмента.

Если рассчитанное расстояние больше или равно определенному размеру шага (StepPips), открывается новая позиция с помощью метода OpenPosition().

Каждый раз перед открытием новой позиции сиБот проверяет и подтверждает, что для операции достаточно средств. Если средств недостаточно, сиБот прекращает попытки открыть новые позиции и записывает в журнал сообщение «Not enough money to open additional positions».

Закрытие позиций

Как только TargetProfit достигнута, сиБот записывает в журнал сообщение «Target profit is reached. Closing all grid positions».

Затем метод CloseGridPositions() проходит по всем открытым позициям в сетке, закрывает их, после чего сиБот записывает в журнал сообщение «All grid positions are closed. Остановка сиБота". После этого сиБот останавливается.

Параметры

Параметр Единица Определение Советы
Количество Лот Объем каждой сделки. Консервативные трейдеры могут указать небольшие размеры лота, чтобы снизить риск и тщательно управлять им, особенно на волатильном рынке. Таким образом, любые потенциальные убытки минимизируются, если рынок движется против сетки.

Агрессивные трейдеры могут указать большие размеры лота, чтобы максимизировать прибыль, когда они уверены в рынке. Хотя этот подход более рискованный, он приносит большую прибыль, когда сетка эффективно захватывает большие колебания цен.
Сторона сделки — Направление сделки (покупка или продажа). На растущем рынке трейдеры могут выбрать покупку. Когда инструмент временно откатывается вниз, сиБот покупает на более низких уровнях. Когда рынок движется обратно вверх, каждая позиция на покупку становится прибыльной.

На падающем рынке трейдеры могут выбрать продажу. Когда цена инструмента временно откатывается вверх, сиБот продает на более высоких уровнях. Когда рынок движется обратно вниз, каждая позиция на продажу становится прибыльной.
Шаг Пип Расстояние между двумя последовательными позициями сетки. Чем меньше шаг, тем чаще открываются новые сделки, в то время как больший шаг приводит к меньшему количеству сделок. На боковом рынке или рынке с низкой волатильностью трейдеры могут установить небольшое значение. Эта настройка гарантирует, что сиБот открывает позиции чаще и захватывает небольшие колебания цен, особенно когда цена движется в узком диапазоне.

На трендовых или более волатильных рынках трейдеры могут установить большое значение. Эта настройка уменьшает количество открываемых сделок, позволяет сиБоту захватывать более крупные движения и помогает избежать чрезмерной торговли во время сильных трендов.
Целевая прибыль — Совокупная прибыль в валюте счета, которая должна быть достигнута, прежде чем сиБот закроет все открытые позиции и прекратит торговлю. Трейдеры, стремящиеся к быстрой, небольшой прибыли, могут установить низкое значение. Эта настройка гарантирует, что сетка закрывается, как только получена небольшая прибыль, минимизируя риск удержания позиций слишком долго на волатильных рынках.

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

Приложение

Рынки в диапазоне или боковые рынки

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

Пример использования

Рассмотрим сценарий, когда EURUSD остается в диапазоне между 1,1000 и 1,1100. СиБот открывает позиции на покупку, когда цена падает ближе к 1,1000, и открывает позиции на продажу около 1,1100. Когда цена колеблется между этими уровнями, сиБот получает прибыль от каждого колебания.

Лучшие практики

  • Установите небольшой размер шага, чтобы захватывать частые колебания цен.
  • Установите умеренную целевую прибыль, чтобы сетка закрывалась часто, позволяя вам получать небольшую, стабильную прибыль.
  • Следите за новостями рынка или предстоящими событиями, которые могут привести к пробою из диапазона и вызвать большие просадки.

Рынки с низкой волатильностью

На рынках с низкой волатильностью движения цен, как правило, медленные и менее выраженные. Поскольку цена движется постепенно, Grid cBot получает достаточно времени для открытия нескольких позиций без риска больших, быстрых рыночных движений.

Пример использования

Рассмотрим сценарий, когда USDJPY демонстрирует низкую волатильность, как это часто бывает во время азиатской торговой сессии. Grid cBot может открывать позиции с небольшим размером шага и захватывать небольшие, постепенные движения цен, которые происходят в эти спокойные часы.

Лучшие практики

  • Используйте узкий размер шага, чтобы использовать меньшие движения цен, типичные для рынков с низкой волатильностью.
  • Установите низкий объем сделки, чтобы снизить риск в случае неожиданного увеличения волатильности.
  • Следите за рыночными условиями, неожиданными новостями или событиями и будьте готовы быстро остановить сиБота.

Рынки с известными уровнями

Grid cBot может хорошо работать на рынках с сильными, четко определенными уровнями поддержки и сопротивления. Эти уровни действуют как ценовые барьеры и заставляют рынок часто отскакивать назад, создавая диапазон, который сиБот может использовать.

Пример использования

Рассмотрим сценарий, когда цена золота (XAUUSD) колеблется между сильным уровнем поддержки на 2 000 долларов США и уровнем сопротивления на 2 050 долларов США. Grid cBot открывает ордера на покупку около 2 000 долларов США и ордера на продажу около 2 050 долларов США, получая прибыль от отскока цены между этими уровнями.

Лучшие практики

  • Установите размер шага на основе волатильности рынка. Рынок с высокой волатильностью может потребовать больших размеров шага, в то время как рынки с низкой волатильностью могут использовать меньшие шаги.
  • Используйте Grid cBot на рынках с хорошо установленными уровнями поддержки и сопротивления, чтобы избежать попадания в пробой.
  • Будьте осторожны с событиями или новостями, которые могут вызвать пробой, чтобы избежать больших убытков. СиБот не готов справиться с тем, что рынок пробивает уровни поддержки или сопротивления.

Ненаправленные рынки

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

Пример использования

Рассмотрим сценарий, при котором EURCHF движется ненаправленно — обычное явление, учитывая стабильность экономики еврозоны и Швейцарии. Grid cBot может открывать позиции с небольшим размером шага, получая прибыль от частых колебаний без опасений по поводу крупных направленных трендов.

Лучшие практики

  • Используйте небольшой размер шага для улавливания частых ценовых движений.
  • Рассмотрите возможность установки низкого объема сделки для управления риском в случае, если рынок перейдет в тренд.

Обзор

Grid cBot работает исходя из предположения, что как на бычьих, так и на медвежьих рынках будут откаты или коррекции. Он покупает по низкой цене и продает по высокой на бычьих рынках и продает по высокой цене и покупает по низкой на медвежьих рынках; сиБот фиксирует прибыль, когда рынок возобновляет основной тренд после откатов.

Поскольку сиБот не использует индикаторы, он не может оценить, находится ли рынок в тренде или во флэте. Он просто открывает позиции исключительно на основе движения цены, игнорируя рыночные настроения или силу тренда.

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

Помимо настройки сиБота для применения своих личных стратегий, трейдеры могут рассмотреть возможность добавления индикаторов для фильтрации сделок на основе рыночных условий:

  • Moving Averages (MA) могут помочь определить рыночный тренд, позволяя сиБоту торговать только в направлении тренда.
  • Relative Strength Index (RSI) может сигнализировать о перекупленности или перепроданности, помогая сиБоту избегать открытия новых позиций, когда рынок перерастянут в одном направлении.
  • Bollinger Bands могут дать представление о волатильности цены, позволяя сиБоту корректировать расстояние между уровнями сетки или воздерживаться от торговли в периоды высокой волатильности.