Saltar a contenido

Cómo añadir métodos a la API de cTrader

Los métodos de extensión son una herramienta crucial si desea añadir nueva funcionalidad a la API de cTrader. Utilizando una sintaxis relativamente simple, puede añadir nuevos comportamientos a cualquier clase de API predefinida, como Symbol o Position. Después de definir un método de extensión, puede llamarlo desde cualquier objeto de la clase que haya extendido.

Caso de uso para métodos de extensión

Primero, realizaremos una demostración rápida de por qué podría querer utilizar métodos de extensión.

Usando un cBot, queremos poder acceder al tamaño de una posición dada en lotes, ya que esta información afecta directamente a nuestra estrategia de operación preferida. Para hacerlo, podemos intentar inicializar una variable de la clase Position y luego intentar acceder a su método Lots().

1
2
Position position = Positions.Last();
Print(position.Lots());

Si simplemente escribimos el código tal cual, recibiremos un error que sugiere que el accesorio Lots() no existe en la API. Pero, ¿y si hubiera una forma de añadir un nuevo método a un miembro existente de la API sin afectar a ninguna otra funcionalidad?

Suponiendo que este método existiera, podríamos haber creado un cBot simple que, en cada barra, iterara sobre una lista de todas las posiciones actuales e imprimiera su tamaño en lotes en el registro. Definiríamos el método OnBar() de la siguiente manera.

1
2
3
4
5
6
protected override void OnBar()
{
    foreach (var position in Positions) {
        Print(position.Lots());
    }
}

Los métodos de extensión nos permiten añadir la funcionalidad Lots() en solo unas pocas líneas de código y luego reutilizarla cuando queramos en cualquier objeto de la clase Position. A continuación, explicamos cómo puede crear uno y proporcionamos varios ejemplos de algos que los utilizan.

Cómo funcionan los métodos de extensión

Al trabajar con métodos de extensión, tenga en cuenta las siguientes reglas.

  • Los métodos de extensión son siempre estáticos.

Para declarar un método estático, todo lo que tiene que hacer es usar la palabra clave static. A continuación, declare el método Lots() con un cuerpo vacío.

1
2
3
4
public static class MyExtensions {
    public static double Lots() {}

}
  • Los métodos de extensión pueden tener cualquier número de argumentos, pero el primer argumento siempre debe designar el tipo de datos/clase para el que se supone que se llamará al método, precedido por la palabra clave this.

Añadiremos un objeto de la clase Position como primer y único argumento del método Lots(). Como un objeto Position también contiene información sobre el símbolo para el que se abrió la posición, no necesitamos ningún otro argumento.

1
2
3
public static class MyExtensions {
    public static double Lots(this Position position) {}
}
  • Los métodos de extensión pueden contener cualquier lógica adecuada para los argumentos proporcionados.

No es necesario utilizar una sintaxis especial al definir el cuerpo de un método de extensión. Podemos tratarlo como cualquier otro método y, por lo tanto, podemos definir su cuerpo de la siguiente manera.

1
2
3
4
5
public static class MyExtensions {
    public static double Lots(this Position position) {
        return position.VolumeInUnits / position.Symbol.LotSize;
    }
}
  • Los métodos de extensión se pueden llamar como métodos de instancia o métodos estáticos.

Hay dos formas posibles de llamar a nuestro método de extensión en el código de un cBot.

Al utilizar la sintaxis de método de instancia, llamamos al método desde cualquier objeto adecuado del tipo Position.

1
2
var position = Positions.Last();
Print(position.Lots());

Al utilizar la sintaxis de método estático, podemos llamar a nuestro método de extensión después de especificar completamente su clase estática correspondiente.

1
2
var position = Positions.Last();
Print(MyExtensions.Lots(position));

Depende de usted determinar qué método de llamar a los métodos de extensión es el más conveniente.

Firmas de método

Cuando utilice la sintaxis de instancia, evite casos en los que sus métodos de extensión tengan las mismas firmas que cualquiera de los métodos de API incorporados (como Position.Close()). En estas situaciones, se llamará a un método incorporado cada vez que intente llamar a un método de extensión con la firma coincidente.

IntelliSense

Cuando intentamos llamar a un método de extensión, IntelliSense utiliza un icono especial para distinguirlo de los miembros de API incorporados.

Para demostrar nuestro nuevo método en acción, podemos crear un cBot que coloca tres órdenes al inicio, cada una con un volumen diferente. En cada barra, el cBot imprime el volumen de todas las posiciones actualmente abiertas en lotes.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
protected override void OnStart()
{
    ExecuteMarketOrder(TradeType.Buy, SymbolName, 10000);
    ExecuteMarketOrder(TradeType.Buy, SymbolName, 100000);
    ExecuteMarketOrder(TradeType.Buy, SymbolName, 50000);
}

protected override void OnBar()
{
    foreach (var position in Positions) {
        Print(position.Lots());
    }
}

Después de construir y lanzar nuestro cBot, deberíamos ver los valores correctos impresos en el registro.

Usar métodos de extensión en cBots

Ahora intentaremos crear un cBot más complejo. En cada barra, nuestro algo revisará la lista de posiciones actualmente abiertas y ajustará sus niveles de stop-loss para que estén en el punto de equilibrio. Para hacerlo, necesitaremos crear un método de extensión BreakEven() para la clase Position.

Creamos un nuevo cBot y lo renombramos. Después, eliminamos todo el código que no necesitamos y añadimos la clase MyExtensions.

1
2
3
public static class MyExtensions {

}

Nuestro código para el método BreakEven() es relativamente simple. Comprobamos si una posición tiene un stop loss, si su beneficio bruto es mayor que cero y si el stop loss actualmente establecido no es igual al precio de entrada de la posición. Si todas estas condiciones son verdaderas, modificamos el stop loss de la posición para que sea igual al precio de entrada de la posición.

1
2
3
4
5
6
7
public static class MyExtensions {
    public static void BreakEven(this Position position) {
        if (position.StopLoss is not null && position.GrossProfit > 0 && position.StopLoss != position.EntryPrice) {
            position.ModifyStopLossPrice(position.EntryPrice);
        }
    }
}

En el cBot en sí, no necesitamos usar ningún método que no sea OnBar(). En cada barra, le pedimos al cBot que realice una operación simple, es decir, iterar sobre la colección Positions y llamar al nuevo método BreakEven() para cada elemento en ella.

1
2
3
4
5
6
protected override void OnBar() 
{
    foreach (var position in Positions) {
        position.BreakEven();
    }
}

Después de construir y lanzar nuestro cBot, podemos verlo en acción. Puede ser un asistente de operaciones útil, especialmente al gestionar muchas posiciones abiertas.

Usar métodos de extensión en indicadores

También crearemos un indicador útil que se basa en métodos de extensión. El indicador medirá la volatilidad trazando el porcentaje en que el precio de un símbolo ha cambiado en cada barra en comparación con el precio de apertura de esa barra.

Para hacerlo, crearemos un nuevo indicador y lo renombraremos. En la ventana del editor de código, crearemos la clase MyExtensions para extender la clase Bar.

1
2
3
public static class MyExtensions {

}

También añadiremos el método PercentageChange(). En la variable priceChange, restamos el precio de cierre de una barra de su precio de apertura. El método devuelve nuestro cambio de precio dividido por el precio de apertura y multiplicado por 100.

1
2
3
4
5
6
7
8
public static class MyExtensions 
{
    public static double PercentageChange(this Bar bar) 
    {
        var priceChange = bar.Open - bar.Close;
        return priceChange / bar.Open * 100;
    }
}

En el código del indicador en sí, no tenemos necesidad del método Initialize() ni de parámetros innecesarios. En el cuerpo del método Calculate(), simplemente llamamos a nuestro nuevo método PercentageChange() en cada barra.

1
2
3
4
5
6
7
8
[Output("Main")]
public IndicatorDataSeries Result { get; set; }


public override void Calculate(int index)
{
    Result[index] = Bars[index].PercentageChange();
}

Después, guardamos y construimos nuestro indicador. Después de crear una instancia de él, deberíamos ver los cambios de porcentaje correctos trazados. Pueden utilizarse para determinar la volatilidad a corto y largo plazo, beneficiando a todo tipo de estrategias de operación.

Resumen

Para concluir, los métodos de extensión son una herramienta valiosa si desea crear código reutilizable que añada nuevas funcionalidades a la API de cTrader. Recomendamos encarecidamente experimentar con métodos de extensión, ya que pueden hacer que sus algos sean más eficientes y fáciles de mantener.