Saltar a contenido

C# para operaciones algorítmicas

Qué es C#

C# es un lenguaje de programación orientado a objetos que se utiliza para crear una amplia gama de servicios y aplicaciones. Su sintaxis clara y estructurada facilita su aprendizaje y lectura, incluso para principiantes, al tiempo que proporciona un enfoque estructurado para escribir código compacto y reutilizable.

¡Algoritmos C# en un minuto!

  • Incluso si nunca ha trabajado con C# antes, crear e implementar su primer bot o indicador solo lleva un par de minutos.
  • Como C# es fácil de usar, puede reescribir rápidamente cualquier fragmento de código de esta documentación para adaptarlo a sus necesidades.
  • Al usar C#, puede acceder a un gran número de bibliotecas que contienen clases y métodos predefinidos. Estos métodos pueden manejar eficientemente tareas comunes, dejándole libre para resolver problemas complejos de operaciones.
  • En C#, puede escribir código que no bloquee los hilos del servidor durante la ejecución. En otras palabras, puede iniciar ciertas tareas simultáneamente con otras tareas.

¿Qué es .NET?

Para que los programas C# se ejecuten, su código fuente debe compilarse en Lenguaje Intermedio (IL). Este código IL sigue la especificación de Infraestructura de Lenguaje Común (CLI) y luego se compila en instrucciones nativas de máquina en tiempo de ejecución. El marco .NET proporciona un entorno de ejecución virtual construido sobre extensas bibliotecas de clases y el Common Language Runtime (CLR), la implementación de Microsoft de la CLI.

Sin entrar en complejidades técnicas, .NET cumple las siguientes funciones:

  • Facilitar el desarrollo y la ejecución de aplicaciones: El SDK de .NET ya contiene varios compiladores y motores de compilación integrados, eliminando la necesidad de crear soluciones personalizadas.
  • Proporcionar bibliotecas de tiempo de ejecución: Al agregar nuevos tipos de datos o colecciones a su código, a menudo encontrará que .NET ya ofrece clases y métodos adecuados para la tarea.

Los fundamentos de C#

Tipos de datos y declaraciones de variables

Los tipos de datos son un medio para categorizar datos de modo que C# sepa exactamente cómo tratar las variables y propiedades. En las declaraciones de variables/propiedades, los tipos de datos siempre preceden al nombre de la variable/propiedad.

1
string developer = "I am developing cBots, plugins, and indicators!";

Alternativamente, puede usar la palabra clave var para evitar especificar un tipo de datos.

1
var developer = "I am developing cBots, plugins, and indicators!";

Objetos y clases

Piense en los objetos como abstracciones de entidades tangibles o intangibles. Estas entidades pueden tener ciertas características (propiedades) y pueden realizar varias operaciones (métodos). A su vez, las clases sirven como plantillas para la creación de objetos.

Como C# es un lenguaje orientado a objetos, las clases también pueden heredar propiedades y métodos de otras clases. Considere el siguiente ejemplo en el que declaramos una nueva clase NewBot que hereda de la clase Robot. También definimos algunas nuevas propiedades de clase.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/* We use the colon sign to designate inheritance.
Additionally, we used expressions in square brackets to
specify the parameters that apply to the entire class */
[Robot(AccessRights = AccessRights.None)]
public class NewBot : Robot
{
    /* We declare a custom class property and make it
    read-only. */
    public string CustomProperty { get; }

    /* In this declaration, we define the default value of a
    custom parameter. */
    [Parameter("BotName", DefaultValue = "Traders First!")]

    /* We declare the BotName property which is changeable via
    the "BotName" parameter. */
    public string BotName { get; }

    /* We also declare the BotComment parameter.
    It can be both read and set. */
    [Parameter("BotComment", DefaultValue = "Our super-duper bot!")]
    public string BotComment { get; set; }
}

Tipos de datos

Como C# es un lenguaje fuertemente tipado, es necesario especificar tipos de datos al declarar variables y propiedades de clase. En resumen, los tipos de datos constituyen clases únicas con diferentes conjuntos de comportamientos. Considere los siguientes ejemplos en los que se especifican varios tipos de datos para diferentes propiedades de clase y parámetros relacionados.

1
2
[Parameter("Price")]
public DataSeries Source { get; }

En el código anterior, el tipo de datos DataSeries representa una lista de valores de solo lectura y, por lo tanto, se utiliza típicamente para representar precios de mercado.

Cuando es necesario crear parámetros de múltiples opciones, puede usar el tipo de datos integrado enum como se detalla a continuación. Puede pensar en los enum como clases especiales que contienen varias constantes.

1
2
3
4
5
6
7
8
9
public enum Option
{
    First,
    Second,
    Third
}

[Parameter("Option", DefaultValue = Option.Third)]
public Option SelectedOption { get; set; }

Para acceder a una constante contenida en un enum, use la siguiente sintaxis.

1
var newOption = Option.First;

Si un parámetro o una propiedad necesita ser un número, lo más frecuente es que use los tipos de datos int (entero) o double (decimal). Aunque el tipo double tiene menos precisión que el tipo decimal, también consume menos recursos.

1
2
[Parameter("MA Periods", DefaultValue = 14, MinValue = 1, MaxValue = 20)]
public int Periods { get; set; }

Por último, el tipo bool típicamente representa una entrada de sí o no. Los valores sí y no corresponden a true y false, respectivamente.

1
2
[Parameter("Message", DefaultValue = true)]
public bool DisplayChartMessage { get; set; }

Espacios de nombres

Los espacios de nombres actúan como colecciones designadas de clases. Una vez que asigna una clase a un espacio de nombres, se puede acceder a ella posteriormente utilizando la notación Namespace.ClassName. Asignaremos nuestro NewBot al espacio de nombres CoolTradingBots.

1
2
3
4
5
6
7
8
namespace CoolTradingBots
{
    [Robot(AccessRights = AccessRights.None)]
    public class NewBot : Robot
    {
        // ...
    }
}

Métodos de clase

Los métodos de clase se definen después de la declaración de la clase. Todos los objetos de nuestra clase NewBot podrán llamar al método CustomTradeOperation(). Toma dos argumentos, a saber, un objeto Symbol y un objeto double. Se supone que nuestro método toma un símbolo y ejecuta algún tipo de acción de operación para el volumen especificado

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
namespace CoolTradingBots
{
    [Robot(AccessRights = AccessRights.None)]
    public class NewBot : Robot
    {
        // ... Defining the class parameters.

        // We declare the CustomTradeOperation method. 
        protected override void CustomTradeOperation(string symbolName, double volume)

        {
            // This space is for declaring the method logic. 
        }
    }
}

Bibliotecas de clases

Se puede acceder a las bibliotecas de clases (y, posteriormente, a los métodos de clase) por su espacio de nombres como se muestra en el siguiente ejemplo.

1
CoolTradingBots.NewBot.CustomTradeOperation(symbolName, 10000)

Alternativamente, puede escribir la palabra clave using al principio de su código para designar ciertos espacios de nombres y evitar redundancias. Considere el siguiente fragmento de código.

1
2
3
using CoolTradingBots;

NewBot.CustomTradeOperation(symbolName, 10000)

Declaraciones condicionales

Para usar declaraciones condicionales, use una palabra clave seguida de una expresión entre paréntesis. El siguiente ejemplo usa la palabra clave if para finalizar nuestro método CustomTradingOperation(). Para hacerlo, usamos el método EvaluateMarket() que está definido en el espacio de nombres Analytics.Actions.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
namespace CoolTradingBots
{
    [Robot(AccessRights = AccessRights.None)]
    public class NewBot : Robot
    {
        // ... Defining the class parameters.

        protected override void CustomTradeOperation(string symbolName, double volume)
        {
            // We declare and initialize the 'result' variable.
            var result = Analytics.Action.EvaluateMarket();

            // We use a conditional statement based on the IsSuccessful property.
            if (result.IsSuccessful)
            {
                Print("Operation successful!")
            }
        }
    }
}

Colecciones

Las colecciones se definen como contenedores que pueden almacenar uno o más objetos de una clase particular.

Las colecciones son totalmente indexables, lo que significa que se puede acceder a sus miembros pasando un cierto valor integer entre corchetes. Considere el siguiente ejemplo en el que el método Calculate() imprime las propiedades de una barra a la que se accede a través de su índice.

1
2
3
4
5
public override void Calculate(int index)
{
       var bar = Bars[index];
       Print($"{bar.Open} | {bar.High} | {bar.Low} | {bar.Close}");
}

Crear extensiones de cTrader

En el siguiente fragmento, creamos un robot de operaciones básico utilizando solo el conocimiento cubierto en las secciones anteriores.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System; 

namespace Spotware.cBots
{
    [Robot(AccessRights = AccessRights.None)]
    public class SuperAwesomeBot : Robot
    {

        /* In the below method, we define the operation(s) that our bot should
        perform when it is launched. */
        protected override void OnStart()
        {
            var result = ExecuteMarketOrder(TradeType.Buy, symbolName, 10000);

            /* We use a conditional statement using the IsSuccessful property of the
            TradeResult object. */
            if (result.IsSuccessful)
            {
                var position = result.Position;
                Print ("Position entry price is {0}", position.EntryPrice);
            } 
        }
    }
}

Operaciones síncronas y asíncronas

Como se indicó anteriormente, C# admite completamente las operaciones asíncronas. El diagrama a continuación define un ejemplo básico de cómo se realizan las actividades de operaciones en la ejecución síncrona.

graph TD
    A(Encontrar una señal técnica) ==> B(Ejecutar una orden de <br>mercado)
    B ==> C(Take Profit/Stop Loss <br>alcanzado)
    C ==> D(Cerrar la posición)
    D ==> A

La ejecución síncrona conlleva una desventaja importante. En el ejemplo anterior, la acción de ejecutar una orden de mercado ocupa completamente todos los hilos del servidor, lo que significa que su robot de operaciones no puede hacer nada más antes de que se complete esta operación.

Esto es menos que ideal cuando desea reaccionar rápidamente a los eventos del mercado y la volatilidad. Idealmente, su bot debería poder almacenar varias acciones o poner ciertas tareas en espera para participar en otras actividades más urgentes. Ampliaremos nuestro ejemplo para reflejar mejor cómo se realizan las operaciones asíncronas.

graph TD
    A([Encontrar una señal técnica]) ==> B([Colocar una orden de compra]) & C([Colocar una orden de venta para cobertura]) ==> D([Una orden alcanza su <br>take profit/stop loss])
    D ==> E([Cerrar la posición])
    E ==> A

En el ejemplo anterior, nuestro robot de operaciones colocó órdenes simultáneamente en ambas direcciones para cubrir sus posiciones. A diferencia de las operaciones sincrónicas, no es necesario esperar a que una operación se complete antes de proceder con otra. Esto amplía significativamente las oportunidades de los desarrolladores para crear robots de operaciones eficientes y fiables.

Tenga en cuenta que la ejecución asíncrona es diferente de la multihilo:

  • En la ejecución asíncrona, todas las tareas se inician en el mismo hilo. Cuando se almacenan o se ponen en espera, liberan este hilo y, cuando su ejecución continúa más tarde, ocurre en un hilo diferente elegido del grupo de hilos.
  • En la multihilo, todas las tareas comienzan en hilos diferentes y continúan su ejecución en sus hilos iniciales. No hay intercambio de hilos.

cTrader nunca invoca sus métodos en paralelo, por lo que no tiene que preocuparse por problemas de multihilo.

Image title