Aller au contenu

Envoyer et recevoir du JSON

Dans ce tutoriel, nous expliquons comment vous pouvez envoyer et recevoir des messages JSON.

TCP et WebSocket

Lorsque vous travaillez avec JSON, vous pouvez utiliser soit une connexion TCP, soit une connexion WebSocket.

Envoyer du JSON

Si vous choisissez d'utiliser JSON dans votre intégration, vous devrez envoyer des chaînes contenant du JSON valide à l'arrière-plan de cTrader. Les objets JSON transmis sous forme de ces chaînes doivent contenir les clés suivantes.

Clé Type de données de la valeur Définition
"clientMsgId" string L'ID unique d'un message. Cet ID doit être généré et attribué côté client.
"payloadType" integer L'entier représentant le message. Une liste complète des types de charge utile valides est incluse dans ProtoOAPayloadType.
"payload" Objet JSON Un objet JSON imbriqué contenant le contenu réel du message.

Un exemple de chaîne valide (représentant le message ProtoOAApplicationAuthReq) peut être trouvé ci-dessous.

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

Pour envoyer des chaînes JSON correctes, vous devrez créer un mécanisme personnalisé de sérialisation dans le langage de programmation de votre choix.

Dans les exemples ci-dessous, nous définissons plusieurs approches pour gérer la sérialisation. Vous pouvez (et devriez) implémenter la vôtre en fonction de votre langage de programmation préféré et de vos modèles de conception.

Ci-dessous, nous définissons deux classes de base puis créons une représentation personnalisée du message 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;
}

Nous créons une classe de base pour tous les messages de l'Open API et, à des fins de démonstration, définissons la classe pour 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})

Après avoir implémenté la logique requise, vous devriez être en mesure d'envoyer de nouveaux messages à l'arrière-plan de cTrader en créant de nouvelles instances des classes représentant ces messages, puis en les transmettant à votre client TCP ou WebSocket préféré.

Recevoir du JSON

Pour recevoir et traiter des messages JSON, vous devez implémenter une méthode pour désérialiser une chaîne JSON en une représentation d'un message de l'Open API.

Pour implémenter cette méthode, vous pouvez trouver utile d'initialiser une map (ou un dictionnaire) où les types de charge utile peuvent être des clés avec les noms des classes représentant les messages agissant comme valeurs. Pour la gestion des exceptions, vous pouvez vérifier si le type de charge utile du message que vous avez reçu est une clé dans cette map ou ce dictionnaire. Si une telle clé existe, vous pouvez désérialiser le message en utilisant toute logique appropriée.

Après avoir implémenté une telle méthode, vous pouvez l'utiliser comme un callback qui est déclenché chaque fois que vous recevez un nouveau message.

Notez que dans l'exemple ci-dessous TMessage est un type générique.

 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;
    }
}

Downcast

La méthode ReadMessage() ne renvoie pas réellement une classe de message spécifique ; vous devrez gérer le downcast séparément lors de la réception d'un message.

Nous ajoutons la méthode suivante à notre classe ApplicationAuthReq.

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

Nous ajoutons ensuite notre callback readMessage et récupérons une charge utile à partir d'un dictionnaire.

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)

Downcast

Comme Python est à typage dynamique, il n'est pas nécessaire de gérer le downcast séparément. Vous pouvez désérialiser la chaîne JSON dans le type requis lors de sa réception.