Saltar a contenido

Enviar y recibir JSON

En este tutorial, explicamos cómo puede enviar y recibir mensajes JSON.

TCP y WebSocket

Cuando trabaje con JSON, puede usar una conexión TCP o una conexión WebSocket.

Enviar JSON

Si elige usar JSON en su integración, tendrá que enviar cadenas que contengan JSON válido al backend de cTrader. Los objetos JSON pasados como estas cadenas tienen que contener las siguientes claves.

Clave Tipo de datos del valor Definición
"clientMsgId" string El ID único de un mensaje. Este ID debe generarse y asignarse en el lado del cliente.
"payloadType" integer El entero que representa el mensaje. La lista completa de tipos de carga útil válidos está incluida en ProtoOAPayloadType.
"payload" Objeto JSON Un objeto JSON anidado que contiene el contenido real del mensaje.

Se puede encontrar un ejemplo de una cadena válida (que representa el mensaje ProtoOAApplicationAuthReq) a continuación.

"{"clientMsgId": "cm_id_2", "payloadType": 2100, "payload": {"clientId": "34Rsd_T098asHkl","clientSecret": "validClientSecret"}}"

Para enviar cadenas JSON correctas, necesitará crear un mecanismo personalizado de serialización en su lenguaje de programación elegido.

En los ejemplos a continuación, definimos varios enfoques para manejar la serialización. Puede (y debe) implementar el suyo propio según su lenguaje de programación preferido y patrón(es) de diseño.

A continuación, definimos dos clases base y luego creamos una representación personalizada del mensaje ProtoOAApplicationAuthReq.

 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
public abstract class OpenAPIMessageBase
{
    public string ClientMsgId { get; set; }
    public abstract int PayloadType { get; }
}

public abstract class OpenAPIMessagePayloadBase { }

public class ApplicationAuthReq : OpenAPIMessageBase
{
    public ApplicationAuthReq() { }
    public ApplicationAuthReq(string clientId, string clientSecret)
    {
        this.Payload = new ApplicationAuthReqPayload(clientId, clientSecret);
        this.ClientMsgId = Guid.NewGuid().ToString();
    }

    public override int PayloadType => 2100;
    public ApplicationAuthReqPayload? Payload { get; set; }

}

public class ApplicationAuthReqPayload : OpenAPIMessagePayloadBase
{
    public ApplicationAuthReqPayload() { }
    public ApplicationAuthReqPayload(string clientId, string clientSecret)
    {
        this.ClientId = clientId;
        this.ClientSecret = clientSecret;
    }
    public string ClientId { get; set; } = string.Empty;
    public string ClientSecret { get; set; } = string.Empty;
}

Creamos una clase base para todos los mensajes de Open API y, con fines de demostración, definimos la clase para ProtoOAApplicationAuthReq.

 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
import uuid
import json

class OpenAPIMessage:

def payloadType(self):
    pass

def payload(self):
    pass

def clientMsgId(self):
    pass

def asJsonString(self):
    pass


class ApplicationAuthReq(OpenAPIMessage):

def __init__(self, clientId, clientSecret, clientMsgId = str(uuid.uuid4())):
    self.clientId = clientId
    self.clientSecret = client_secret
    self.payloadType = 2100
    self.clientMsgId = clientMsgId
    self.payload = {"clientId": self.clientId, "clientSecret": self.clientSecret}



def asJsonString(self):
    return json.dumps({"clientMsgId": self.clientMsgId, "payloadType": self.payloadType, "payload": self.payload})

Después de implementar la lógica requerida, debería poder enviar nuevos mensajes al backend de cTrader creando nuevas instancias de las clases que representan estos mensajes y luego pasándolas a su cliente TCP o WebSocket preferido.

Recibir JSON

Para recibir y procesar mensajes JSON, debe implementar un método para deserializar una cadena JSON en una representación de un mensaje de Open API.

Para implementar este método, puede resultarle útil inicializar un mapa (o un diccionario) donde los tipos de carga útil pueden ser claves con los nombres de las clases que representan mensajes actuando como valores. Para fines de manejo de excepciones, es posible que desee verificar si el tipo de carga útil del mensaje que ha recibido es una clave en este mapa o diccionario. Si existe tal clave, puede deserializar el mensaje usando cualquier lógica adecuada.

Después de implementar dicho método, puede usarlo como una devolución de llamada que se activa cada vez que recibe un nuevo mensaje.

Tenga en cuenta que en el ejemplo siguiente TMessage es un tipo genérico.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
public static class MessageReceivedCallbacks
{
    public static Dictionary<int, Type> messages = new Dictionary<int, Type>
    {
        {2100, typeof(ApplicationAuthReq) },

    };

    public static TMessage ReadMessage<TMessage>(string jsonString) where TMessage : OpenAPIMessageBase
    {
        JsonDocument doc = JsonDocument.Parse(jsonString);
        int payloadType = doc.RootElement.GetProperty("payloadType").GetInt32();

        if (!messages.TryGetValue(payloadType, out var type))
            throw new Exception("This payload type is not supported");

        var result = JsonSerializer.Deserialize(jsonString, type)  as TMessage;

        return result;
    }
}

Conversión descendente

El método ReadMessage() no devuelve realmente una clase de mensaje específica; necesitará manejar la conversión descendente por separado al recibir un mensaje.

Agregamos el siguiente método a nuestra clase ApplicationAuthReq.

1
2
3
@staticmethod
def fromJson(jsonDct):
    return ApplicationAuthReq(clientId=jsonDct['payload']['clientId'], clientSecret=jsonDct['payload']['clientSecret'], clientMsgId=jsonDct['clientMsgId'])

Luego agregamos nuestra devolución de llamada readMessage y recuperamos una carga útil de un diccionario.

1
2
3
4
5
6
7
8
9
class MessageReceivedCallbacks:

messagesDict = {2100: ApplicationAuthReq}

@staticmethod
def readMessage(jsonString):
    json_dct = json.loads(jsonString)
    payloadType = jsonDct['payloadType']
    return MessageReceivedCallbacks.messagesDict[payloadType].fromJson(jsonDct)

Conversión descendente

Como Python tiene tipado dinámico, no es necesario manejar la conversión descendente por separado. Puede deserializar la cadena JSON al tipo requerido cuando la reciba.