콘텐츠로 이동

JSON 보내기 및 받기

이 튜토리얼에서는 JSON 메시지를 보내고 받는 방법을 설명합니다.

TCP 및 WebSocket

JSON 작업 시 TCP 연결 또는 WebSocket 연결 중 하나를 사용할 수 있습니다.

JSON 보내기

통합에서 JSON을 사용하기로 선택한 경우, cTrader 백엔드에 유효한 JSON을 포함하는 문자열을 보내야 합니다. 이러한 문자열로 전달되는 JSON 객체는 다음 키를 포함해야 합니다.

값 데이터 타입 정의
"clientMsgId" 문자열 메시지의 고유 ID. 이 ID는 클라이언트 측에서 생성하고 할당해야 합니다.
"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})

필요한 로직을 구현한 후에는 이러한 메시지를 나타내는 클래스의 새 인스턴스를 생성한 다음 선호하는 TCP 또는 WebSocket 클라이언트에 전달하여 cTrader 백엔드에 새 메시지를 보낼 수 있어야 합니다.

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 문자열을 받을 때 필요한 타입으로 역직렬화할 수 있습니다.