Saltar a contenido

Cómo automatizar una estrategia de operación manual

Las operaciones automatizadas o algorítmicas ofrecen varias ventajas sobre las operaciones manuales:

  • Los sistemas automatizados eliminan la toma de decisiones emocional y ejecutan operaciones con mayor precisión, velocidad y eficiencia.
  • Los algoritmos implementan consistentemente estrategias de operación avanzadas mientras que las medidas de gestión de riesgos se aplican de manera confiable.
  • Los algoritmos permiten hacer backtesting de estrategias utilizando datos históricos y diversificar en múltiples activos y mercados simultáneamente.

La API de cTrader Algo permite a los operadores automatizar estrategias manuales complejas, permitiéndoles capitalizar las muchas ventajas de las operaciones algorítmicas. En este artículo y su vídeo adjunto, aprenderá cómo automatizar estrategias manuales intrincadas y transformar secuencias de operaciones en algoritmos.

Identificar los patrones de la estrategia manual

Para desarrollar un algoritmo, supongamos que estamos operando manualmente el patrón de martillo para entradas largas y el patrón de hombre colgado para entradas cortas.

Un martillo ocurre durante una tendencia bajista y sugiere una posible reversión alcista. El patrón de martillo se utiliza para identificar entradas de compra.

Un hombre colgado aparece durante una tendencia alcista e indica una posible reversión bajista. El patrón de hombre colgado se utiliza para identificar entradas de venta.

Desarrollar un cBot para operar la estrategia manual

En cTrader Algo, vamos a crear un algoritmo que implemente la estrategia descrita en la sección anterior.

Haga clic en el botón Nuevo bajo la pestaña cBot. Escriba Estrategia de Patrones en el campo de nombre y haga clic en Crear.

En el método OnBarClosed(), implementamos la lógica de nuestra estrategia. Nuestras entradas tienen que cumplir estas dos condiciones:

  • El precio de cierre coincide con el precio más alto.
  • El tamaño de la vela es al menos cinco veces mayor que el cuerpo de la vela.

Comenzamos definiendo los parámetros Volume, StopLoss y 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; }

Luego escribimos un fragmento para ejecutar una operación de compra cuando se cumplen las condiciones requeridas.

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)

En el lado opuesto, estas son las condiciones que deben cumplirse para nuestras entradas de venta:

  • El precio de cierre coincide con el precio más bajo.
  • El tamaño de la vela es al menos cinco veces mayor que el cuerpo de la vela.

De manera similar, escribimos un fragmento para ejecutar una operación de venta cuando se cumplen las condiciones requeridas.

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)

Puede copiar el código completo a continuación:

 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

Para construir el cBot, presione Ctrl+B o haga clic en Construir.

Para hacer backtesting del cBot, primero añadimos una instancia. Seleccione la opción Localmente, especifique sus parámetros preferidos y haga clic en el botón Añadir instancia.

Luego navegamos a la pestaña Backtesting, especificamos un período para la operación de backtesting e iniciamos el backtesting.

Una vez que el proceso de backtesting esté completo, podemos inspeccionar las operaciones. Verá que las condiciones de entrada se cumplen justo antes de que se ingrese cada operación.

Con la automatización exitosa de nuestra estrategia, podemos emplear el cBot para realizar operaciones en nuestro nombre.

Implementar la estrategia de reversión del RSI

En nuestro segundo ejemplo, queremos implementar una estrategia basada en la reversión del indicador Relative Strength Index (RSI). En esta estrategia, entramos en posiciones esperando que el RSI invierta su dirección y seguimos estas reglas:

  • Cuando el valor del RSI se mueve por debajo del umbral de compra del RSI, entramos en una posición de compra.
  • Cuando el valor del RSI se mueve por encima del umbral de venta del RSI, entramos en una posición de venta.

Vamos a crear un nuevo cBot, ingresamos Estrategia de Reversión RSI como su nombre y hacemos clic en Crear.

Una vez que aparezca el editor de código, agregue System.Linq en la parte superior del código como referencia.

1
using System.Linq;

Agreguemos dos parámetros que nos permitirán modificar los umbrales antes de ejecutar el cBot.

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

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

Declaramos e inicializamos nuestro indicador de fuerza relativa.

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)

Luego implementamos las condiciones que definen nuestra lógica de operación.

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

Puede copiar el código completo a continuación:

 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

Construyamos nuestra estrategia, agreguemos una instancia y hagamos backtesting, como lo hicimos con la estrategia anterior.

Podemos inspeccionar y revisar algunas operaciones nuevamente para ver las condiciones de entrada cumpliéndose justo antes de que se ingrese una operación.

Este artículo ha demostrado cómo identificar una estrategia manual y convertirla en una automatizada, permitiendo operaciones de trading algorítmico.

Image title