Skip to content

How to Automate a Manual Trading Strategy

Automated or algorithmic trading offers several advantages over manual trading:

  • Automated systems eliminate emotional decision-making and execute trades with increased precision, speed and efficiency.
  • Algorithms consistently implement advanced trading strategies while risk management measures are reliably enforced.
  • Algorithms enable backtesting strategies using historical data and diversifying across multiple assets and markets simultaneously.

The cTrader Algo API empowers traders to automate complex manual strategies, allowing them to capitalise on the many advantages of algorithmic trading. In this article and its accompanying video, you will learn how to automate intricate manual strategies and transform sequences of operations into algorithms.

Identify the Manual Strategy Patterns

To develop an algorithm, let’s assume we are manually trading the hammer pattern for long entries and the hanging man pattern for short entries.

A hammer occurs during a downtrend and suggests a potential bullish reversal. The hammer pattern is used to identify buy entries.

A hanging man appears during an uptrend and indicates a potential bearish reversal. The hanging man pattern is used to identify sell entries.

Develop a cBot to Trade the Manual Strategy

In cTrader Algo, let's create an algorithm that implements the strategy described in the previous section.

Click the 'New' button under the 'cBot' tab. Type in 'Patterns Strategy' in the name field and then click 'Create'.

In the OnBarClosed() method, we implement the logic for our strategy. Our entries have to meet these two conditions:

  • The close price matches the high price.
  • The candle size is at least five times larger than the candle body.

We start by defining the Volume, StopLoss and TakeProfit parameters.

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

Then we write a snippet to execute a buy trade when the required conditions are met.

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

On the opposite side, these are the conditions that must be met for our sell entries:

  • The close price matches the low price.
  • The candle size is at least five times larger than the candle body.

Similarly, we write a snippet to execute a sell trade when the required conditions are met.

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

You can copy the full code below:

 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()
        {

        }
    }
}

To build the cBot, press Ctrl+B or click 'Build'.

To backtest the cBot, we first add an instance. Select the 'Locally' option, specify your preferred parameters and click the 'Add instance' button.

We then navigate to the 'Backtesting' tab, specify a period for the backtesting operation and start backtesting.

Once the backtesting process completes, we can inspect trades. You will see that the entry conditions are met just before each trade is entered.

With the successful automation of our strategy, we can employ the cBot to make trades on our behalf.

Implement the RSI Reversal Strategy

In our second example, we want to implement a strategy based on the Relative Strength Index (RSI) indicator reversal. In this strategy, we enter positions expecting the RSI to reverse its direction and follow these rules:

  • When the RSI value moves below the RSI buy threshold, we enter a buy position.
  • When the RSI value moves above the RSI sell threshold, we enter a sell position.

Let’s create a new cBot, input 'RSI Reversal Strategy' as its name and click 'Create'.

Once the code editor appears, add System.Linq as a reference to the lines of code at the top.

1
using System.Linq;

Let’s add two parameters that will allow us to modify the thresholds before we run the cBot.

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

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

We declare and initialise our relative strength indicator.

1
2
3
4
5
6
private RelativeStrengthIndex _rsi;

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

We then implement the conditions that define our trading logic.

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

}

You can copy the full code below:

 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()
        {

        }
    }
}

Let’s build our strategy, add an instance and backtest it, just as we did with the previous strategy.

We can inspect and review some trades again to see the entry conditions being met just before a trade is entered.

This article has demonstrated how to identify a manual strategy and convert it into an automated one, allowing for algo-trading operations. For more information on cTrader Algo, see our documentation or post a question on our forum.

Subscribe to our YouTube channel