Vai al contenuto

Inviare e ricevere JSON

In questo tutorial, spieghiamo come puoi inviare e ricevere messaggi JSON.

TCP e WebSocket

Quando lavori con JSON, puoi utilizzare una connessione TCP o una connessione WebSocket.

Inviare JSON

Se scegli di utilizzare JSON nella tua integrazione, dovrai inviare stringhe contenenti JSON valido al backend di cTrader. Gli oggetti JSON passati come queste stringhe devono contenere le seguenti chiavi.

Chiave Tipo di dati del valore Definizione
"clientMsgId" string L'ID univoco di un messaggio. Questo ID deve essere generato e assegnato lato client.
"payloadType" integer L'intero che rappresenta il messaggio. Un elenco completo di tipi di payload validi è incluso nel ProtoOAPayloadType.
"payload" Oggetto JSON Un oggetto JSON nidificato contenente il contenuto effettivo del messaggio.

Un esempio di stringa valida (che rappresenta il messaggio ProtoOAApplicationAuthReq) può essere trovato di seguito.

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

Per inviare stringhe JSON corrette, dovrai creare un meccanismo personalizzato per la serializzazione nel linguaggio di programmazione scelto.

Negli esempi seguenti, definiamo diversi approcci per gestire la serializzazione. Puoi (e dovresti) implementare il tuo a seconda del linguaggio di programmazione e del/i pattern di progettazione preferiti.

Di seguito, definiamo due classi base e poi creiamo una rappresentazione personalizzata del messaggio 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;
}

Creiamo una classe base per tutti i messaggi Open API e, a scopo dimostrativo, definiamo la classe per 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})

Dopo aver implementato la logica richiesta, dovresti essere in grado di inviare nuovi messaggi al backend di cTrader creando nuove istanze delle classi che rappresentano questi messaggi e poi passandole al tuo client TCP o WebSocket preferito.

Ricevere JSON

Per ricevere ed elaborare messaggi JSON, devi implementare un metodo per deserializzare una stringa JSON in una rappresentazione di un messaggio Open API.

Per implementare questo metodo, potrebbe essere utile inizializzare una mappa (o un dizionario) dove i tipi di payload possono essere chiavi con i nomi delle classi che rappresentano i messaggi che fungono da valori. Per scopi di gestione delle eccezioni, potresti voler verificare se il tipo di payload del messaggio che hai ricevuto è una chiave in questa mappa o dizionario. Se tale chiave esiste, puoi deserializzare il messaggio utilizzando qualsiasi logica adatta.

Dopo aver implementato tale metodo, puoi utilizzarlo come callback che viene attivato ogni volta che ricevi un nuovo messaggio.

Nota che nell'esempio seguente TMessage è un tipo generico.

 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

Il metodo ReadMessage() non restituisce effettivamente una classe di messaggio specifica; dovrai gestire il downcasting separatamente quando ricevi un messaggio.

Aggiungiamo il seguente metodo alla nostra classe ApplicationAuthReq.

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

Quindi aggiungiamo il nostro callback readMessage e recuperiamo un payload da un dizionario.

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

Poiché Python è a tipizzazione dinamica, non c'è bisogno di gestire il downcasting separatamente. Puoi deserializzare la stringa JSON nel tipo richiesto quando la ricevi.