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

Как автоматизировать стратегию ручной торговли

Автоматизированная или алгоритмическая торговля предлагает несколько преимуществ по сравнению с ручной торговлей:

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

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

Определение паттернов стратегии ручной торговли

Для разработки алгоритма предположим, что мы вручную торгуем паттерн hammer для длинных входов и паттерн hanging man для коротких входов.

Паттерн hammer возникает во время нисходящего тренда и предполагает потенциальный бычий разворот. Паттерн hammer используется для определения входов на покупку.

Паттерн hanging man появляется во время восходящего тренда и указывает на потенциальный медвежий разворот. Паттерн hanging man используется для определения входов на продажу.

Разработка сиБота для торговли по стратегии ручной торговли

В cTrader Algo давайте создадим алгоритм, который реализует стратегию, описанную в предыдущем разделе.

Нажмите кнопку Создать на вкладке сиБот. Введите Patterns Strategy в поле имени и нажмите Создать.

В методе OnBarClosed() мы реализуем логику нашей стратегии. Наши входы должны соответствовать этим двум условиям:

  • Цена закрытия совпадает с максимальной ценой.
  • Размер свечи как минимум в пять раз больше тела свечи.

Начнем с определения параметров Volume, StopLoss и TakeProfit.

1
2
3
4
5
6
7
8
[Parameter(DefaultValue = 1000)]
public double Volume { get; set; }

[Parameter(DefaultValue = 10)]
public double StopLoss { get; set; }

[Parameter(DefaultValue = 10)]
public double TakeProfit { get; set; }

Затем мы пишем фрагмент кода для выполнения сделки на покупку, когда выполняются необходимые условия.

1
2
3
4
5
if (Bars.Last(0).Close == Bars.Last(0).High &&
            (Bars.Last(0).Close - Bars.Last(0).Open) < (Bars.Last(0).Close - Bars.Last(0).Low) * 0.2)
{
    ExecuteMarketOrder(TradeType.Buy, SymbolName, Volume, InstanceId, StopLoss, TakeProfit);
}
1
2
3
bar = api.Bars.Last(0)
if bar.Close == bar.High and (bar.Close - bar.Open) < (bar.Close - bar.Low) * 0.2:
    api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, api.Volume, api.InstanceId, api.StopLoss, api.TakeProfit)

С противоположной стороны, это условия, которые должны быть выполнены для наших входов на продажу:

  • Цена закрытия совпадает с минимальной ценой.
  • Размер свечи как минимум в пять раз больше тела свечи.

Аналогично, мы пишем фрагмент кода для выполнения сделки на продажу, когда выполняются необходимые условия.

1
2
3
4
5
if (Bars.Last(0).Close == Bars.Last(0).Low &&
                (Bars.Last(0).Open - Bars.Last(0).Close) < (Bars.Last(0).High - Bars.Last(0).Close) * 0.2)
{
    ExecuteMarketOrder(TradeType.Sell, SymbolName, Volume, InstanceId, StopLoss, TakeProfit);
}
1
2
if bar.Close == bar.Low and (bar.Open - bar.Close) < (bar.High - bar.Close) * 0.2:
    api.ExecuteMarketOrder(TradeType.Sell, api.SymbolName, api.Volume, api.InstanceId, api.StopLoss, api.TakeProfit)

Вы можете скопировать полный код ниже:

 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
using System;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Robots
{
    [Robot(AccessRights = AccessRights.None, AddIndicators = true)]
    public class PatternsStrategy : Robot
    {
        [Parameter(DefaultValue = 1000)]
        public double Volume { get; set; }

        [Parameter(DefaultValue = 10)]
        public double StopLoss { get; set; }

        [Parameter(DefaultValue = 10)]
        public double TakeProfit { get; set; }

        protected override void OnStart()
        {

        }

        protected override void OnBarClosed()
        {
            if (Bars.Last(0).Close == Bars.Last(0).High &&
            (Bars.Last(0).Close - Bars.Last(0).Open) < (Bars.Last(0).Close - Bars.Last(0).Low) * 0.2)
            {
                ExecuteMarketOrder(TradeType.Buy, SymbolName, Volume, InstanceId, StopLoss, TakeProfit);
            }

            if (Bars.Last(0).Close == Bars.Last(0).Low &&
            (Bars.Last(0).Open - Bars.Last(0).Close) < (Bars.Last(0).High - Bars.Last(0).Close) * 0.2)
            {
                ExecuteMarketOrder(TradeType.Sell, SymbolName, Volume, InstanceId, StopLoss, TakeProfit);
            }

        }

        protected override void OnStop()
        {

        }
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
import clr
clr.AddReference("cAlgo.API")
from cAlgo.API import *
from robot_wrapper import *

class PatternsStrategy():
    def on_start(self):
        pass

    def on_bar_closed(self):
        bar = api.Bars.Last(0)

        if bar.Close == bar.High and (bar.Close - bar.Open) < (bar.Close - bar.Low) * 0.2:
            api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, api.Volume, api.InstanceId, api.StopLoss, api.TakeProfit)

        if bar.Close == bar.Low and (bar.Open - bar.Close) < (bar.High - bar.Close) * 0.2:
            api.ExecuteMarketOrder(TradeType.Sell, api.SymbolName, api.Volume, api.InstanceId, api.StopLoss, api.TakeProfit)

    def on_stop(self):
        pass

Чтобы собрать сиБота, нажмите Ctrl+B или нажмите Собрать.

Чтобы провести бэктестинг сиБота, сначала добавим экземпляр. Выберите опцию Локально, укажите предпочтительные параметры и нажмите кнопку Добавить экземпляр.

Затем мы переходим на вкладку Бэктестинг, указываем период для операции бэктестинга и запускаем бэктестинг.

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

С успешной автоматизацией нашей стратегии мы можем использовать сиБота для совершения сделок от нашего имени.

Реализация стратегии разворота RSI

В нашем втором примере мы хотим реализовать стратегию, основанную на развороте индикатора Relative Strength Index (RSI). В этой стратегии мы открываем позиции, ожидая, что RSI развернет свое направление, и следуем этим правилам:

  • Когда значение RSI опускается ниже порога покупки RSI, мы открываем позицию на покупку.
  • Когда значение RSI поднимается выше порога продажи RSI, мы открываем позицию на продажу.

Давайте создадим новый сиБот, введем RSI Reversal Strategy в качестве его имени и нажмем Создать.

Как только появится редактор кода, добавьте System.Linq в верхнюю часть кода в качестве ссылки.

1
using System.Linq;

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

1
2
3
4
5
[Parameter(DefaultValue = 30)]
public int BuyLevel { get; set; }

[Parameter(DefaultValue = 70)]
public int SellLevel { get; set; }

Мы объявляем и инициализируем наш индикатор относительной силы.

1
2
3
4
5
6
private RelativeStrengthIndex _rsi;

protected override void OnStart()
{
    _rsi = Indicators.RelativeStrengthIndex(Bars.ClosePrices, 14);
}
1
2
3
class RSIReversalStrategy():
    def on_start(self):
        self._rsi = api.Indicators.RelativeStrengthIndex(api.Bars.ClosePrices, 14)

Затем мы реализуем условия, которые определяют нашу торговую логику.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
protected override void OnBarClosed()
{

    if (_rsi.Result.LastValue < BuyLevel)
    {
        if (Positions.Count == 0)
            ExecuteMarketOrder(TradeType.Buy, SymbolName, 1000);
        foreach (var position in Positions.Where(p => p.TradeType == TradeType.Sell))
        {
            position.Close();
        }

    }
    else if (_rsi.Result.LastValue > SellLevel)
    {
        if (Positions.Count == 0)
            ExecuteMarketOrder(TradeType.Sell, SymbolName, 1000);
        foreach (var position in Positions.Where(p => p.TradeType == TradeType.Buy))
        {
            position.Close();
        }
    }

}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
def on_bar_closed(self):
    rsi_value = self._rsi.Result.LastValue

    if rsi_value < api.BuyLevel:
        if api.Positions.Count == 0:
            api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 1000)
        for position in api.Positions:
            if position.TradeType == TradeType.Sell:
                position.Close()

    elif rsi_value > api.SellLevel:
        if api.Positions.Count == 0:
            api.ExecuteMarketOrder(TradeType.Sell, api.SymbolName, 1000)
        for position in api.Positions:
            if position.TradeType == TradeType.Buy:
                position.Close()

Вы можете скопировать полный код ниже:

 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
using System;
using System.Linq;
using cAlgo.API;
using cAlgo.API.Collections;
using cAlgo.API.Indicators;
using cAlgo.API.Internals;

namespace cAlgo.Robots
{
    [Robot(AccessRights = AccessRights.None, AddIndicators = true)]
    public class RSIReversalStrategy : Robot
    {
        [Parameter(DefaultValue = 30)]
        public int BuyLevel { get; set; }

        [Parameter(DefaultValue = 70)]
        public int SellLevel { get; set; }

        private RelativeStrengthIndex _rsi;

        protected override void OnStart()
        {
            _rsi = Indicators.RelativeStrengthIndex(Bars.ClosePrices, 14);
        }

        protected override void OnBarClosed()
        {

            if (_rsi.Result.LastValue < BuyLevel)
            {
                if (Positions.Count == 0)
                    ExecuteMarketOrder(TradeType.Buy, SymbolName, 1000);
                foreach (var position in Positions.Where(p => p.TradeType == TradeType.Sell))
                {
                    position.Close();
                }

            }
            else if (_rsi.Result.LastValue > SellLevel)
            {
                if (Positions.Count == 0)
                    ExecuteMarketOrder(TradeType.Sell, SymbolName, 1000);
                foreach (var position in Positions.Where(p => p.TradeType == TradeType.Buy))
                {
                    position.Close();
                }
            }

        }

        protected override void OnStop()
        {

        }
    }
}
 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
import clr
clr.AddReference("cAlgo.API")
from cAlgo.API import *
from robot_wrapper import *

class RSIReversalStrategy():
    def on_start(self):
        self._rsi = api.Indicators.RelativeStrengthIndex(api.Bars.ClosePrices, 14)

    def on_bar_closed(self):
        rsi_value = self._rsi.Result.LastValue

        if rsi_value < api.BuyLevel:
            if api.Positions.Count == 0:
                api.ExecuteMarketOrder(TradeType.Buy, api.SymbolName, 1000)
            for position in api.Positions:
                if position.TradeType == TradeType.Sell:
                    position.Close()

        elif rsi_value > api.SellLevel:
            if api.Positions.Count == 0:
                api.ExecuteMarketOrder(TradeType.Sell, api.SymbolName, 1000)
            for position in api.Positions:
                if position.TradeType == TradeType.Buy:
                    position.Close()

    def on_stop(self):
        pass

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

Мы можем снова проверить и просмотреть некоторые сделки, чтобы увидеть, как условия входа выполняются непосредственно перед входом в сделку.

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

Image title