Перейти к содержанию

Отправка и получение JSON

В этом руководстве мы объясняем, как вы можете отправлять и получать сообщения JSON.

TCP и WebSocket

При работе с JSON вы можете использовать либо TCP-соединение, либо WebSocket-соединение.

Отправка JSON

Если вы решите использовать JSON в своей интеграции, вам нужно будет отправлять строки, содержащие корректный JSON, в бэкенд cTrader. Объекты JSON, передаваемые в виде этих строк, должны содержать следующие ключи.

Ключ Тип данных значения Определение
"clientMsgId" строка Уникальный идентификатор сообщения. Этот идентификатор должен быть сгенерирован и назначен на стороне клиента.
"payloadType" строка Целое число, представляющее сообщение. Полный список допустимых типов полезной нагрузки включен в ProtoOAPayloadType.
"payload" Объект JSON Вложенный объект JSON, содержащий фактическое содержимое сообщения.

Пример допустимой строки (представляющей сообщение ProtoOAApplicationAuthReq) можно найти ниже.

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

Для отправки правильных строк JSON вам потребуется создать пользовательский механизм сериализации на выбранном вами языке программирования.

В приведенных ниже примерах мы определяем несколько подходов к обработке сериализации. Вы можете (и должны) реализовать свой собственный в зависимости от предпочитаемого языка программирования и шаблона(ов) проектирования.

Ниже мы определяем два базовых класса, а затем создаем пользовательское представление сообщения 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;
}

Мы создаем базовый класс для всех сообщений Open API и в демонстрационных целях определяем класс для 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})

После реализации необходимой логики вы сможете отправлять новые сообщения на серверную часть cTrader, создавая новые экземпляры классов, представляющих эти сообщения, а затем передавая их предпочитаемому клиенту TCP или WebSocket.

Получение JSON

Для получения и обработки сообщений JSON необходимо реализовать метод десериализации строки JSON в представление сообщения Open API.

Для реализации этого метода может быть полезно инициализировать карту (или словарь), где типы полезной нагрузки могут быть ключами, а имена классов, представляющих сообщения, — значениями. Для целей обработки исключений вы можете проверить, является ли тип полезной нагрузки полученного сообщения ключом в этой карте или словаре. Если такой ключ существует, вы можете десериализовать сообщение, используя любую подходящую логику.

После реализации такого метода вы можете использовать его в качестве обратного вызова, который срабатывает каждый раз при получении нового сообщения.

Обратите внимание, что в приведенном ниже примере TMessage является универсальным типом.

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

Понижающее приведение типов

Метод ReadMessage() фактически не возвращает конкретный класс сообщения; вам потребуется обрабатывать понижающее приведение типов отдельно при получении сообщения.

Мы добавляем следующий метод в наш класс ApplicationAuthReq.

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

Затем мы добавляем наш обратный вызов readMessage и извлекаем полезную нагрузку из словаря.

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)

Понижающее приведение типов

Поскольку Python использует утиную типизацию, нет необходимости обрабатывать понижающее приведение типов отдельно. Вы можете десериализовать строку JSON в требуемый тип при ее получении.