Przejdź do treści

Wysyłaj i odbieraj JSON

W tym samouczku wyjaśniamy, jak możesz wysyłać i odbierać komunikaty JSON.

TCP i WebSocket

Podczas pracy z JSON możesz używać połączenia TCP lub połączenia WebSocket.

Wyślij JSON

Jeśli zdecydujesz się użyć JSON w swojej integracji, będziesz musiał wysyłać ciągi znaków zawierające prawidłowy JSON do backendu cTrader. Obiekty JSON przekazywane jako te ciągi znaków muszą zawierać następujące klucze.

Klucz Typ danych wartości Definicja
"clientMsgId" string Unikalny identyfikator wiadomości. Ten identyfikator musi być wygenerowany i przypisany po stronie klienta.
"payloadType" integer Liczba całkowita reprezentująca wiadomość. Pełna lista prawidłowych typów ładunku znajduje się w ProtoOAPayloadType.
"payload" Obiekt JSON Zagnieżdżony obiekt JSON zawierający rzeczywistą zawartość wiadomości.

Przykład prawidłowego ciągu znaków (reprezentującego wiadomość ProtoOAApplicationAuthReq) można znaleźć poniżej.

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

Aby wysyłać prawidłowe ciągi znaków JSON, będziesz musiał utworzyć niestandardowy mechanizm serializacji w wybranym języku programowania.

W poniższych przykładach definiujemy kilka podejść do obsługi serializacji. Możesz (i powinieneś) zaimplementować własne, w zależności od preferowanego języka programowania i wzorca (wzorców) projektowych.

Poniżej definiujemy dwie klasy bazowe, a następnie tworzymy niestandardową reprezentację wiadomości 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;
}

Tworzymy klasę bazową dla wszystkich wiadomości Open API i, w celach demonstracyjnych, definiujemy klasę dla 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})

Po zaimplementowaniu wymaganej logiki powinieneś być w stanie wysyłać nowe wiadomości do backendu cTrader, tworząc nowe instancje klas reprezentujących te wiadomości, a następnie przekazując je do preferowanego klienta TCP lub WebSocket.

Odbierz JSON

Aby odbierać i przetwarzać wiadomości JSON, musisz zaimplementować metodę deserializacji ciągu znaków JSON do reprezentacji wiadomości Open API.

Aby zaimplementować tę metodę, pomocne może być zainicjowanie mapy (lub słownika), w której typy ładunku mogą być kluczami, a nazwy klas reprezentujących wiadomości działają jako wartości. W celach obsługi wyjątków możesz chcieć zweryfikować, czy typ ładunku otrzymanej wiadomości jest kluczem w tej mapie lub słowniku. Jeśli taki klucz istnieje, możesz zdeserializować wiadomość przy użyciu dowolnej odpowiedniej logiki.

Po zaimplementowaniu takiej metody możesz użyć jej jako wywołania zwrotnego, które jest wyzwalane za każdym razem, gdy otrzymasz nową wiadomość.

Należy pamiętać, że w poniższym przykładzie TMessage jest typem generycznym.

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

Rzutowanie w dół

Metoda ReadMessage() w rzeczywistości nie zwraca konkretnej klasy wiadomości; będziesz musiał obsłużyć rzutowanie w dół oddzielnie podczas odbierania wiadomości.

Dodajemy następującą metodę do naszej klasy ApplicationAuthReq.

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

Następnie dodajemy nasze wywołanie zwrotne readMessage i pobieramy ładunek ze słownika.

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)

Rzutowanie w dół

Ponieważ Python jest językiem z typowaniem kaczym, nie ma potrzeby oddzielnej obsługi rzutowania w dół. Możesz zdeserializować ciąg znaków JSON do wymaganego typu podczas jego odbierania.