Ir para o conteúdo

Enviar e receber JSON

Neste tutorial, explicamos como pode enviar e receber mensagens JSON.

TCP e WebSocket

Ao trabalhar com JSON, pode usar uma ligação TCP ou uma ligação WebSocket.

Enviar JSON

Se optar por usar JSON na sua integração, terá de enviar strings contendo JSON válido para o backend do cTrader. Os objetos JSON passados como estas strings têm de conter as seguintes chaves.

Chave Tipo de dados do valor Definição
"clientMsgId" string O ID único de uma mensagem. Este ID tem de ser gerado e atribuído no lado do cliente.
"payloadType" integer O integer que representa a mensagem. Uma lista completa dos tipos de payload válidos está incluída no ProtoOAPayloadType.
"payload" Objeto JSON Um objeto JSON aninhado contendo o conteúdo real da mensagem.

Um exemplo de uma string válida (representando a mensagem ProtoOAApplicationAuthReq) pode ser encontrado abaixo.

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

Para enviar strings JSON corretas, precisará de criar um mecanismo personalizado de serialização na sua linguagem de programação escolhida.

Nos exemplos abaixo, definimos várias abordagens para lidar com a serialização. Pode (e deve) implementar a sua própria dependendo da sua linguagem de programação preferida e padrão(ões) de design.

Abaixo, definimos duas classes base e depois criamos uma representação personalizada da mensagem 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;
}

Criamos uma classe base para todas as mensagens da Open API e, para fins de demonstração, definimos a classe 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})

Após implementar a lógica necessária, deverá poder enviar novas mensagens para o backend do cTrader criando novas instâncias das classes que representam estas mensagens e depois passando-as para o seu cliente TCP ou WebSocket preferido.

Receber JSON

Para receber e processar mensagens JSON, tem de implementar um método para deserializar uma string JSON numa representação de uma mensagem da Open API.

Para implementar este método, pode ser útil inicializar um mapa (ou um dicionário) onde os tipos de payload podem ser chaves com os nomes das classes que representam mensagens atuando como valores. Para fins de tratamento de exceções, pode querer verificar se o tipo de payload da mensagem que recebeu é uma chave neste mapa ou dicionário. Se tal chave existir, pode deserializar a mensagem usando qualquer lógica adequada.

Após implementar tal método, pode usá-lo como um callback que é acionado sempre que receber uma nova mensagem.

Note que no exemplo abaixo TMessage é um 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;
    }
}

Downcasting

O método ReadMessage() não retorna realmente uma classe de mensagem específica; precisará de lidar com o downcasting separadamente ao receber uma mensagem.

Adicionamos o seguinte método à nossa classe ApplicationAuthReq.

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

Em seguida, adicionamos o nosso callback readMessage e recuperamos um payload de um dicionário.

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)

Downcasting

Como Python é duck-typed, não há necessidade de lidar com o downcasting separadamente. Pode deserializar a string JSON no tipo necessário ao recebê-la.