Архитектура системы - Санкт-Петербургская Международная

реклама
СЭТ СР СПбМТСБ
Шлюз коммуникационной системы
для подключения внешних систем
к Системе Электронных Торгов Срочного Рынка
СПбМТСБ
Руководство разработчикa
v.1.15
CMA Small Systems AB
2010
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
Содержание
Введение .................................................................................................................................................. 3
Архитектура системы .............................................................................................................................. 4
Функциональные возможности ШКС ..................................................................................................... 5
Особенности реализации ШКС .............................................................................................................. 6
Системные требования .......................................................................................................................... 6
Протокол Protobuf и его применение ..................................................................................................... 6
Требования к длине полей сообщений ...............................................................................................16
Обязательность полей заявок в зависимости от типа заявок ...........................................................18
Пример .proto-файла для обмена сообщениями со шлюзом (ШКС) ................................................19
Библиотека zmqCommClient.dll ............................................................................................................36
Интерфейс коммуникационного модуля ICommModule - описание методов ..................................37
Интерфейс очередей ICommQueue - описание методов ..................................................................38
Сценарий использования коммуникационного модуля и очередей .................................................40
Описание поставки ................................................................................................................................42
© CMA Small Systems AB, 2010
2
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
Введение
В данном руководстве описано применение шлюза коммуникационной системы
(ШКС), предназначенного для подключения к Системе Электронных Торгов Срочного
Рынка Санкт-Петербургской Международной Товарно-сырьевоя Биржи (СЭТ СР
СПбМТСБ) внешних (по отношению к ней) систем различного типа, осуществляющих
обмен информацией с СЭТ СР СПбМТСБ в режиме реального времени.
ШКС
представляет
собой
программную
часть
аппаратно-программного
интерфейса, предназначенного для обмена информацией между СЭТ СР СПбМТСБ и
внешними системами. Обмен информацией происходит в режиме реального времени и с
обеспечением приемлемого (с точки зрения СПбМТСБ) уровня защиты данных.
ШКС обеспечивает двунаправленную связь с торговой системой и содержит
программный интерфейс (API), который предназначен как для получения информации
из Фьючерсной Торговой Системы (сделки, котировки, инструменты и т.п.), так и для
выполнения активных транзакций (постановка/снятие заявок и т.п.). ШКС позволяет
подключать
к
Фьючерсной
Торговой
Системе
СПбМТСБ
внешние
системы
распространения торговой информации и сбора клиентских заявок.
© CMA Small Systems AB, 2010
3
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
Архитектура системы
Архитектура системы приведена на следующей диаграмме:
© CMA Small Systems AB, 2010
4
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
Функциональные возможности ШКС
ШКС обеспечивает выполнение следующих основных операций:
 подключение к СЭТ СР СПбМТСБ от имени пользователя СЭТ СР СПбМТСБ,
являющегося пользователем шлюза, с использованием передаваемого из
внешней системы идентификатора и пароля;
 передачу от внешней системы в СЭТ СР СПбМТСБ параметров подписки на
получение торговой информации или обновлений торговой информации в
соответствии с подписками;
 передачу от СЭТ СР СПбМТСБ во внешнюю систему торговой информации (или
ее обновлений), в соответствии с параметрами подписки;
 передачу от внешней системы в СЭТ СР СПбМТСБ требований на выполнение
активных транзакций (постановку и снятие заявок);
 передачу от СЭТ СР СПбМТСБ во внешнюю систему ответов СЭТ СР СПбМТСБ
на требования внешней системы на выполнение активных транзакций;
 передачу от СЭТ СР СПбМТСБ во внешнюю систему сообщений об ошибках,
произошедших
при
обработке
торговой
информации
(обновлений),
генерируемой по подписке, и ошибок при попытках исполнения активных
транзакций;
 отключение отдельных пользователей от СЭТ СР СПбМТСБ по команде
администратора шлюза.
Программа обеспечивает протоколирование следующих событий:
 подключение пользователей к СЭТ СР СПбМТСБ;
 получение от внешних систем требований
транзакций и содержание этих требований;
на
выполнение
активных
 получение от внешних систем параметров подписок для получения торговой
информации (обновлений) и значения этих параметров;
 отключение пользователей от СЭТ СР СПбМТСБ.
© CMA Small Systems AB, 2010
5
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
Особенности реализации ШКС
ШКС реализован в виде двух программных компонентов.
1.
Шлюз предназначен для подключения к СЭТ СР СПбМТСБ по протоколу Protobuf.
Доступны следующие варианты функционирования компонента:
2.

Под управление операционных систем семейства Microsoft Windows Windows
Server 2008 R2 или Microsoft Windows 7 и выше.

Под управлением операционной системы Linux. Доступны консольный и
фоновый (daemon) режимы работы.
Динамическая библиотека (zmqCommClient.dll), предоставляет прикладной
программный интерфейс (API) для подключения к ШКС.
Передача данных между внешними системами и шлюзом осуществляется при помощи
протокола TCP/IP с использованием брандмауэра.
Данные при этом передаются в виде двух отдельных потоков:

торговая информация, передаваемая от СЭТ СР СПбМТСБ в режиме подписки;

транзакционные данные, необходимые для осуществления торговых транзакций,
передаваемые в режиме «запрос-ответ».
Внешние системы могут используют сразу оба варианта подключения, так и каждый
поток в отдельности. Одно соединение используется для информационного обмена,
второе
–
для
обеспечения
транзакционного
обмена.
Шлюз
работает
в
многопользовательском режиме, то есть он может работать одновременно с многими
внешними системами, каждая из которых поддерживает один или два потока данных.
Системные требования
Для функционирования внешней системы с использованием библиотеки
zmqCommClient.dll
предъявляются
следующие
минимальные
требования
к
программному и аппаратному обеспечению комплекса:

Операционная система: Microsoft Windows Server R2 и Microsoft Windows 7 с
установленным Service Pack 2 и выше;

Компьютеры:
o
Процессор – Intel Core 2 Duo или выше;
o
ОЗУ – от 2Gb;
o
Жесткий диск с 10Gb свободного пространства;
o
Наличие Ethernet сетевой карты;
Данные требования не учитывают особенностей внешней системы и могут быть
скорректированы в сторону повышения с учетом ресурсов, необходимых внешней
системы для нормального функционирования.
Протокол Protobuf и его применение
Для подключения внешних систем к СЭТ СР СПбМТСБ, данные, которыми обмениваются
внешние системы и шлюз, соответствуют форматам, определяемым содержимым .protoфайлов протокола Google Protocol Buffers (Protobuf).
© CMA Small Systems AB, 2010
6
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
В .proto-файлах хранятся следующие настройки соединений:
 описание
доступных
внешней
системе
информационных
объектов
(наименований информационных объектов, состава полей и дополнительной
информации);
 описание доступных внешней системе полей информационных объектов
(наименований полей информационных объектов, их типа, формата и
дополнительной информации);
 описание доступных внешней системе активных транзакций (наименований
активных транзакций, состава полей и дополнительной информации);
 описание доступных внешней системе полей активных транзакций
(наименований полей активных транзакций, их типа, формата
и
дополнительной информации);
 описание откликов
транзакции;
СЭТ
СР
на
доступные
внешней
системе
Протокол
Protobuf
предложен
фирмой
Google
для
хранения
структурированных данных, он обладает эффективностью и гибкостью.
и
активные
передачи
Если не применять Protobuf, то задачу упаковки извлечения данных можно было бы
выполнять различными способами, например одним из перечисленных вариантов:

Можно сохранять и/или передавать данные в бинарном формате. Впоследствии
это приведет к проблемам из-за соответствий полей. После того, как ПО,
обрабатывающее эти данные, будет передано многим пользователям, станет
трудно менять формат данных, т.к. старое ПО не сможет обрабатывать данные в
новом формате.

Можно создать собственный формат сообщений, например, передавая четыре
целых числа 12, 3, -23, 67 в текстовой строке с разделителями "12:3:-23:67".
Этот подход прост и гибок, но требует написания индивидуальных фрагментов
кода для упаковки и синтаксического анализа (парсинга) передаваемых данных.
Этот подход приемлем только для очень простых структур данных.

Можно передавать структурированные данные в формате XML. Это хороший
способ, т.к. XML в значительной мере понятен для восприятия человеком и для
его обработки существует множество библиотек. Он особенно полезен, когда
нужно передавать ваши данные во многие сторонние приложения или проекты.
Однако, по сравнению с Protobuf, сообщения XML недостаточно компактны, а их
обработка достаточно сложна.
Protobuf был разработан, чтобы решать эту задачу без указанных выше недостатков.
Протокол Protobuf можно применять в ситуациях, когда не требуется передавать
большие и сложные структуры данных и когда не требуется такое присущее XML
свойство, как самоописывание (self-describing). При этом, по сравнению с XML,
сообщения Protobuf оказываются компактнее, проще и обрабатываются быстрее.
Сравните примеры сообщений в протоколах XML и Protobuf:
XML
<person>
<name>John Doe</name>
<email>jdoe@example.com</email>
</person>
Для синтаксического анализа требуется около
5000-10000 наносекунд.
Protobuf
person {
name: "John Doe"
email: "jdoe@example.com"
}
(в упакованном формате занимает
около 28 бит)
Для синтаксического анализа требуется
около 100-200 наносекунд
Пример кода, обрабатывающего сообщение XML из примера:
© CMA Small Systems AB, 2010
7
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
cout << "Name: "
<< person.getElementsByTagName("name")->item(0)->innerText()
<< endl;
cout << "E-mail: "
<< person.getElementsByTagName("email")->item(0)->innerText()
<< endl;
Пример кода, обрабатывающего сообщение Protobuf из примера:
cout << "Name: " << person.name() << endl;
cout << "E-mail: " << person.email() << endl;
По оценкам Google, по сравнению с XML, Protobuf обладает следующим достоинствами:
 проще
 объем передаваемых данных меньше в 3-10 раз
 скорость обработки выше в 20-100 раз
 обладает более простой, однозначной структурой
 на нем легче программировать классы доступа к данным
Информацию о протоколе Protobuf смотрите здесь: http://code.google.com/p/protobuf/
Документацию и учебные материалы по Protobuf смотрите здесь:
http://code.google.com/intl/ru/apis/protocolbuffers/docs/overview.html
http://code.google.com/intl/ru/apis/protocolbuffers/docs/proto.html
http://code.google.com/intl/ru/apis/protocolbuffers/docs/tutorials.html
Protobuf позволяет добавлять новые структуры в формат передаваемых данных без
необходимости внесения изменений в старые отлаженные и скомпилированные
программы.
Основные принципы использования Protobuf
Сообщения Protobuf не являются самоописывающими.
Сами передаваемые сообщения являются по сути парами "имя/значение". Структура
передаваемых данных задается в специальных .proto-файлах (определениях
сообщений).
Ниже приведен пример .proto-файла, задающего структуру информации о людях:
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
}
Формат сообщений несложен: каждый тип сообщений содержит одно или несколько
уникально нумерованных полей. Каждое поле имеет имя и тип.
Возможны следующие типы полей:
 числовой (целый, вещественный)
 логический
 строковый
© CMA Small Systems AB, 2010
8
Шлюз коммуникационной системы СЭТ СР СПбМТСБ


Руководство разработчика
бинарные данные без обработки (raw bytes)
другие типы данных, позволяющие создавать структурированные данные (как в
приведенном выше примере)
Когда определения сообщений созданы, они компилируются для применяемого вами
языка программирования, для формирования классов доступа к данным. Благодаря
этому становится возможным удобный доступ как к отдельным полям, так и к методам
для синтаксического анализа бинарных данных.
Например,
если
вы
программируете
на
С++,
то
вышеприведенного примера будет создан класс Person,
использовать для соответствующих сообщений.
при
компилировании
который можно будет
Вы сможете писать, например, такой код, формирующий исходящее сообщение и
записывающий его в файл:
Person person;
person.set_name("John Doe");
person.set_id(1234);
person.set_email("jdoe@example.com");
fstream output("myfile", ios::out | ios::binary);
person.SerializeToOstream(&output);
Это сообщение можно будет затем прочитать из файла и разобрать при помощи
следующего кода:
fstream input("myfile", ios::in | ios::binary);
Person person;
person.ParseFromIstream(&input);
cout << "Name: " << person.name() << endl;
cout << "E-mail: " << person.email() << endl;
При добавлении новых полей в сообщения сохраняется обратная совместимость со
старыми версиями программ (новые поля просто игнорируются при синтаксическом
анализе). Поэтому, при внесении дополнений в протоколы обмена сообщениями,
старые программы не перестанут работать.
Применение Protobuf при программировании на С++
Рассмотрим пример использования сообщений Protobuf в программе, обрабатывающей
адресную книгу.
Предполагается, что каждый человек имеет имя, идентификатор, адрес электронной
почты и контактный телефон.
© CMA Small Systems AB, 2010
9
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
Для обработки этих данных потребуется создать специфичный для них .proto-файл.
Синтаксис .proto-файлов несложен: для каждой передаваемой структуры данных
создается блок message, в котором для каждого поля указываются имя (name) и тип
(type). Синтаксис .proto-файлов похож на синтаксис C++ или Java. Ниже приведен
пример файла addressbook.proto для адресной книги:
package tutorial;
message Person {
required string name = 1;
required int32 id = 2;
optional string email = 3;
enum PhoneType {
MOBILE = 0;
HOME = 1;
WORK = 2;
}
message PhoneNumber {
required string number = 1;
optional PhoneType type = 2 [default = HOME];
}
repeated PhoneNumber phone = 4;
}
message AddressBook {
repeated Person person = 1;
}
Ниже описаны отдельные фрагменты этого файла:
package tutorial;
.proto-файл начинается с объявления пакета, что помогает предотвращать конфликты
именования между различными проектами. Для C++ будут генерироваться классы,
помещаемые в пространства имен, соответствующие именам пакетов.
Далее следуют определения типов сообщений (блоки message). Каждое определение
сообщения содержит описания одного или нескольких полей, относящихся к тем или
иным типам. Типом поля может быть стандартный тип (среди которых: логический bool, целый32 - int32, вещественный - float, двойной точности - double, строковый string).
Структуру передаваемых данных можно усложнять, указывая в качестве типа поля
типы сообщений, например, в вышеприведенном примере, определяется, что:
 сообщение Person содержит сообщения PhoneNumber
 сообщение AddressBook содержит сообщения Person
Можно даже определять типы сообщений внутри определений других типов сообщений.
Так, тип сообщений PhoneNumber определен внутри типа сообщений Person
Также можно создавать типы сообщений при помощи ключевого слова enum,
задающего возможные значения поля. В нашем примере поля с типом PhoneType могут
иметь только следующие значения:
 MOBILE
 HOME
 WORK
Цифры после знаков равенства (= 1
, = 2 и т.д.) около каждого из элементов
являются уникальными тегами, используемыми для преобразования в двоичный код.
Для тегов от 1 до 15 при преобразовании в двоичный код требуется лишь один байт,
поэтому их рекомендуется использовать для часто передаваемых данных.
Каждое поле обязательно должно сопровождаться одним из модификаторов (modifier):
© CMA Small Systems AB, 2010
10
Шлюз коммуникационной системы СЭТ СР СПбМТСБ



Руководство разработчика
required ("обязательное") - означает обязательность данного поля. При
отсутствии
поля,
имеющего
этот
модификатор,
сообщение
считается
неинициализированным
("uninitialized").
Создание
неинициализированных
сообщений может приводить к сообщению об ошибках, а синтаксический анализ
неинициализированных сообщений всегда возвращает значение
false.
Рекомендуется использовать этот модификатор с осторожностью, т.к.
впоследствии могут возникнуть трудности при попытке отказаться от таких
полей.
optional ("необязательное", "опциональное") - означает необязательность
данного поля. Если такое поле не задано, применяется значение по умолчанию
(default). Для простых типов вы можете задать свои собственные значения по
умолчанию, как в вышеприведенном примере типом телефона по умолчанию
является домашний телефон (default = HOME). Также применяются системные
значения по умолчанию: для чисел - ноль, для строк - пустая строка, для
логического типа - false.
repeated ("повторяющееся") - такое поле может повторяться много раз либо
отсутствовать (т.е. количество повторений поля - любое, включая ноль). Protobuf
не меняет порядка следования повторяющихся полей. Повторяющиеся поля
напоминают массивы переменной длины.
© CMA Small Systems AB, 2010
11
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
Генерирование исходного кода на С++ из .proto-файла
В комплекте поставки Protobuf имеется программа-кодогенератор, которая на основе
.proto-файла генерирует исходный код на поддерживаемых языков высокого уровня, в
том числе, код на языке С++. Программа-кодогенератор предоставляется бесплатно на
условиях, записанных в ее комментариях.
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
Protocol Buffers - Google's data interchange format
Copyright 2008 Google Inc. All rights reserved.
http://code.google.com/p/protobuf/
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Author: kenton@google.com (Kenton Varda)
// Based on original Protocol Buffers design by
// Sanjay Ghemawat, Jeff Dean, and others.
//
// Generates C++ code for a given .proto file.
#ifndef GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__
#define GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__
#include <string>
#include <google/protobuf/compiler/code_generator.h>
namespace
namespace
namespace
namespace
google {
protobuf {
compiler {
cpp {
// CodeGenerator implementation which generates a C++ source file and
// header. If you create your own protocol compiler binary and you want
// it to support C++ output, you can do so by registering an instance of this
// CodeGenerator with the CommandLineInterface in your main() function.
class LIBPROTOC_EXPORT CppGenerator : public CodeGenerator {
public:
CppGenerator();
~CppGenerator();
// implements CodeGenerator ---------------------------------------bool Generate(const FileDescriptor* file,
const string& parameter,
OutputDirectory* output_directory,
string* error) const;
private:
GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(CppGenerator);
};
}
}
}
// namespace cpp
// namespace compiler
// namespace protobuf
} // namespace google
#endif // GOOGLE_PROTOBUF_COMPILER_CPP_GENERATOR_H__
© CMA Small Systems AB, 2010
12
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
Подробности о генерировании кода, соответствующего .proto-файлу см. здесь:
http://code.google.com/intl/ru/apis/protocolbuffers/docs/proto.html
http://code.google.com/intl/ru/apis/protocolbuffers/docs/reference/cppgenerated.html#plugins
http://code.google.com/intl/ru/apis/protocolbuffers/docs/cpptutorial.html
Нашему примеру с адресной книгой будет соответствовать такой код:
// name
inline
inline
inline
inline
inline
inline
// id
inline
inline
inline
inline
bool has_name() const;
void clear_name();
const ::std::string& name() const;
void set_name(const ::std::string& value);
void set_name(const char* value);
::std::string* mutable_name();
bool has_id() const;
void clear_id();
int32_t id() const;
void set_id(int32_t value);
// email
inline bool has_email() const;
inline void clear_email();
inline const ::std::string& email() const;
inline void set_email(const ::std::string& value);
inline void set_email(const char* value);
inline ::std::string* mutable_email();
// phone
inline int phone_size() const;
inline void clear_phone();
inline const ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >&
phone() const;
inline ::google::protobuf::RepeatedPtrField< ::tutorial::Person_PhoneNumber >*
mutable_phone();
inline const ::tutorial::Person_PhoneNumber& phone(int index) const;
inline ::tutorial::Person_PhoneNumber* mutable_phone(int index);
inline ::tutorial::Person_PhoneNumber* add_phone();
Пример создания сообщения
#include <iostream>
#include <fstream>
#include <string>
#include "addressbook.pb.h"
using namespace std;
// This function fills in a Person message based on user input.
void PromptForAddress(tutorial::Person* person) {
cout << "Enter person ID number: ";
int id;
cin >> id;
person->set_id(id);
cin.ignore(256, '\n');
cout << "Enter name: ";
getline(cin, *person->mutable_name());
cout << "Enter email address (blank for none): ";
string email;
getline(cin, email);
if (!email.empty()) {
person->set_email(email);
}
while (true) {
cout << "Enter a phone number (or leave blank to finish): ";
string number;
getline(cin, number);
if (number.empty()) {
break;
}
tutorial::Person::PhoneNumber* phone_number = person->add_phone();
phone_number->set_number(number);
© CMA Small Systems AB, 2010
13
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
cout << "Is this a mobile, home, or work phone? ";
string type;
getline(cin, type);
if (type == "mobile") {
phone_number->set_type(tutorial::Person::MOBILE);
} else if (type == "home") {
phone_number->set_type(tutorial::Person::HOME);
} else if (type == "work") {
phone_number->set_type(tutorial::Person::WORK);
} else {
cout << "Unknown phone type. Using default." << endl;
}
}
}
// Main function: Reads the entire address book from a file,
//
adds one person based on user input, then writes it back out to the same
//
file.
int main(int argc, char* argv[]) {
// Verify that the version of the library that we linked against is
// compatible with the version of the headers we compiled against.
GOOGLE_PROTOBUF_VERIFY_VERSION;
if (argc != 2) {
cerr << "Usage:
return -1;
}
" << argv[0] << " ADDRESS_BOOK_FILE" << endl;
tutorial::AddressBook address_book;
{
// Read the existing address book.
fstream input(argv[1], ios::in | ios::binary);
if (!input) {
cout << argv[1] << ": File not found. Creating a new file." << endl;
} else if (!address_book.ParseFromIstream(&input)) {
cerr << "Failed to parse address book." << endl;
return -1;
}
}
// Add an address.
PromptForAddress(address_book.add_person());
{
// Write the new address book back to disk.
fstream output(argv[1], ios::out | ios::trunc | ios::binary);
if (!address_book.SerializeToOstream(&output)) {
cerr << "Failed to write address book." << endl;
return -1;
}
}
// Optional: Delete all global objects allocated by libprotobuf.
google::protobuf::ShutdownProtobufLibrary();
return 0;
}
© CMA Small Systems AB, 2010
14
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
Пример чтения сообщения
#include <iostream>
#include <fstream>
#include <string>
#include "addressbook.pb.h"
using namespace std;
// Iterates though all people in the AddressBook and prints info about them.
void ListPeople(const tutorial::AddressBook& address_book) {
for (int i = 0; i < address_book.person_size(); i++) {
const tutorial::Person& person = address_book.person(i);
cout << "Person ID: " << person.id() << endl;
cout << " Name: " << person.name() << endl;
if (person.has_email()) {
cout << " E-mail address: " << person.email() << endl;
}
for (int j = 0; j < person.phone_size(); j++) {
const tutorial::Person::PhoneNumber& phone_number = person.phone(j);
switch (phone_number.type()) {
case tutorial::Person::MOBILE:
cout << " Mobile phone #: ";
break;
case tutorial::Person::HOME:
cout << " Home phone #: ";
break;
case tutorial::Person::WORK:
cout << " Work phone #: ";
break;
}
cout << phone_number.number() << endl;
}
}
}
// Main function: Reads the entire address book from a file and prints all
//
the information inside.
int main(int argc, char* argv[]) {
// Verify that the version of the library that we linked against is
// compatible with the version of the headers we compiled against.
GOOGLE_PROTOBUF_VERIFY_VERSION;
if (argc != 2) {
cerr << "Usage:
return -1;
}
" << argv[0] << " ADDRESS_BOOK_FILE" << endl;
tutorial::AddressBook address_book;
{
// Read the existing address book.
fstream input(argv[1], ios::in | ios::binary);
if (!address_book.ParseFromIstream(&input)) {
cerr << "Failed to parse address book." << endl;
return -1;
}
}
ListPeople(address_book);
// Optional: Delete all global objects allocated by libprotobuf.
google::protobuf::ShutdownProtobufLibrary();
return 0;
}
© CMA Small Systems AB, 2010
15
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
Требования к длине полей сообщений
При проектировании клиентского ПО, разработчики должны обеспечить,
передаваемые поля сообщений не превышали следующих значений:
Поле
Код участника
Наименование участника
Код ИНН участника
Код КПП участника
Код ОГРН участника
Код ОКПО участника
Код пользователя (имя для входа в систему,
логин)
Наименование пользователя
Пароль пользователя для входа в систему
Код позиционного регистра
Наименование позиционного регистра
Код клиента
Наименование клиента
Код ИНН клиента
Код секции
Наименование секции
Код режима торгов
Наименование режима торгов
Код типа финансовых инструментов
Наименование типа финансовых инструментов
Код базиса поставки
Наименование базиса поставки
Код финансового инструмента
Наименование финансового инструмента
Код валюты финансового инструмента
Наименование валюты финансового инструмента
Код открытой позиции
чтобы
Макс. длина
12
70
20
20
20
20
12
70
32
25
70
16
70
20
16
70
16
70
12
70
16
70
16
70
12
32
Определяется по формуле:
(Код финансового инструмента) +
(Код позиционного регистра)
Код инструмента вместе с кодом режима торгов
Определяется по формуле:
(Код финансового инструмента) +
(Код режима торгов)
Наименование сессии
Код заявки
Уникальный (в пределах сессии) код заявки
Текст комментария в заявке
Описание результата исполнения заявки
Код сделки
Код события
Описание события
Код входящего сообщения
Текст входящего сообщения
Код состояния
Обозначение операционного дня
Наименование состояния
Переход между состояниями (ручной или
автоматический)
Код времени состояния
© CMA Small Systems AB, 2010
70
12
31
255
255
12
12
511
12
511
12
10
64
32
8
16
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Код статуса состояния
Код текстового сообщения
Текстовое сообщение
Код станции назначения
Наименование станции назначения
© CMA Small Systems AB, 2010
Руководство разработчика
32
12
512
12
64
17
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
Обязательность полей заявок в зависимости от типа заявок
В зависимости от типа, заявки имеют различный состав обязательных полей, в
соответствии с нижеприведенной таблицей:
ОБЯЗАТЕЛЬНОСТЬ ПОЛЕЙ В
РАЗЛИЧНЫХ ТИПАХ ЗАЯВОК
●- обязательные поля
Тип заявки
○ - необязательные поля
Специальная
Рыночная
Поставочная
Лимитированная
Ликвидационная
Поля
Адресная
× - не должно заполняться
Идентификатор сообщения (item_id)
×
×
×
×
×
×
Уникальный (в пределах сессии) номер
транзакции заявки (trn)
Тип заявки (type)
●
●
●
●
●
●
●
●
●
●
●
●
●
●
×
●
●
●
●
●
●
●
●
●
●
×
●
●
●
●
●
●
●
●
●
●
×
●
●
●
○
●
●
●
●
○
●
×
●
●
●
●
●
●
●
●
○
●
×
●
●
●
●
●
●
●
●
●
●
×
●
●
●
○
○
○
○
○
○
○
○
○
○
○
×
×
×
×
×
×
×
×
×
×
×
×
○
○
○
○
○
○
×
×
×
●
×
×
Параметры заявки (params)
Направление заявки (buy_sell)
Режим торгов (board)
Финансовый инструмент (security)
Позиционный регистр (account)
Цена (price)
Количество (qty)
Время жизни заявки (time_in_force)
Фирма (firm)
Клиент (client)
Контрагент для адресной заявки
(cp_firm)
Комментарий (comment)
Идентификатор заявки, формируемый
торговым сервером. Заполняется
только при отправлении из торговой
системы в клиринговую. (id)
Метка времени (time_stamp)
Флаг принадлежности заявки маркет
мейкеру (isMarketMaker)
Станция отправления/назначения
(destination)
© CMA Small Systems AB, 2010
18
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
Пример .proto-файла для обмена сообщениями со шлюзом (ШКС)
Ниже приведен пример .proto-файла для обмена сообщениями с ШКС. В рамках
примера использования библиотеки zmqCommClient.dll, поставляемой совместно с
данным руководством, разработчикам внешних систем будет предоставлен заранее
сгенерированный код на языке С++ для сборки и разбора сообщений. В случае
изменения используемого ё.proto-файла, разработчикам внешних систем надо будет
скомпилировать измененный .proto-файл и заменить соответствующие фрагменты
исходного кода внешних систем.
//
// Protocol Buffer messages description file for Futures Trading System
// $Id: FTEMessages.proto 37765 2010-12-06 15:38:20Z anpav $
//
package FTE;
option java_package = "se.highex.core2CF.server.ft.fmt.protobuf";
option java_outer_classname = "FTEProtos";
option optimize_for = SPEED;
// Набор типов возможных сообщений
// Префикс REQ_* используется для запросов
// Префикс REP_* используется для ответов на соответствующие запросы
//
enum MsgType
{
REQ_UNKNOWN
= -1;
/* Requests */
REQ_NEW_PARTICIPANT
= 1;
// Запрос на создание нового участника
REQ_NEW_USER
= 2;
// Запрос на создание нового пользователя
REQ_NEW_CLIENT
= 3;
// Запрос на создание нового клиента
REQ_NEW_ACCOUNT
= 4;
// Запрос на создание нового счета
REQ_NEW_SECTION
= 5;
// Запрос на создание новой секции
REQ_NEW_BOARD
= 6;
// Запрос на создание нового режима торгов
REQ_NEW_SECTYPE
= 7;
// Запрос на создание нового типа срочного контракта
REQ_NEW_SECURITY
= 8;
// Запрос на создание нового срочного контракта
REQ_LOGON
= 9;
// Регистрация в информационной или транзакционной подсистеме
REQ_LOGOFF
= 10; // Завершение работы в информационной или транзакционной подсистеме
REQ_ORDER
= 11; // Посылка заявки
REQ_CANCEL_ORDER
= 12; // Запрос на сняние заявки
REQ_OPEN_SECBOARD = 13; // Открытие режима торгов
REQ_CLOSE_SECBOARD = 14; // Закрытие режима торгов
REQ_SUSPEND_SECBOARD
= 15; // Приостановка режима торгов
REQ_RESUME_SECBOARD
= 16; // Продолжение нормального функционирования режима торгов
REQ_SUBSCRIBE
= 17; // Подпись на определенную информационную таблицу
REQ_UNSUBSCRIBE
= 18; // Запрос на завершение получения данных по определенной
информационной таблицы
REQ_ORDER_ALARM
= 19; // Сообщение о необычной заявке
REQ_TRADE_ALARM
= 20; // Сообщение о необычной сделке
REQ_CLOSE_DAY
= 21; // Запрос на закрытие торгового дня
REQ_SUSPEND_PARTICIPANT
= 22; // Блокировка участника
REQ_RESUME_PARTICIPANT
= 23; // Разблокировка участника
REQ_SUSPEND_USER
= 24; // Блокировка пользователя
REQ_RESUME_USER
= 25; // Разблокировка пользователя
REQ_SUSPEND_CLIENT
= 26; // Блокировка клиента
REQ_RESUME_CLIENT
= 27; // Разблокировка клиента
REQ_SUSPEND_ACCOUNT
= 28; // Блокировка регистра
REQ_RESUME_ACCOUNT
= 29; // Разбокировка регистра
REQ_SUSPEND_SECTION
= 30; // Блокировка секции
REQ_RESUME_SECTION
= 31; // Разблокировка секции
REQ_MEDDELANDE
= 32; // Посылки текстового сообщения
REQ_CLR_TRADE
= 33; // Запрос на регистрацию сделки в клиринговой системе
REQ_CLR_SETTLE_PRICE
= 34; // Запрос на регистрацию новой расчетной цены в клиринговой
системе
REQ_ACCEPT_ORDER
= 35; // Посылка аксепта из клиринговой системы
REQ_CLR_ORDER_REESTR
= 36; // Запрос на пересылку в клиринговую систему реестра заявок
REQ_CLR_TRADE_REESTR
= 37; // Запрос на пересылку в клиринговую систему реестра сделок
REQ_CLR_ORDER_CANC_REESTR = 38; // Запрос на пересылку в клиринговую систему реестра снятых
заявок
REQ_BRD_SECURITIES = 39; // Запрос на подготовку данных для открыти торгов по серии срочного
контракта
REQ_OPEN_BOARD
= 40; // Запрос на открытия для торгов режима торгов
REQ_CLOSE_BOARD_FOR_ORDERS= 41; // Запрос на закрытие приема заявок и "заморозка" принятых
заявокдля режима торгов
REQ_CLOSE_BOARD
= 42; // Запрос на закрытие режима торгов
REQ_HOLDING
= 43; // Запрос на передачу данных по холдингу из клиринговой системы
REQ_BD_STATE
= 44; // Зарезервировано. В текущей версии не используется
© CMA Small Systems AB, 2010
19
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
REQ_OPEN_BOARD_FOR_ORDERS = 45; // Запрос на повторное открытие режима торгов для приема
заявок
REQ_CLR_ORDER_REESTR_RFQ = 46; // Запрос на пересылку в клиринговую систему реестра заявок
RFQ
REQ_CLR_TRADE_REESTR_RFQ = 47; // Запрос на пересылку в клиринговую систему реестра сделок
RFQ
REQ_CLR_ORDER_REESTR_DELI = 48; // Запрос на пересылку в клиринговую систему реестра заявок
на физ. исполнение
REQ_CLR_TRADE_REESTR_DELI = 49; // Запрос на пересылку в клиринговую систему реестра сделок
на физ. исполнение
REQ_CLR_ORDER_REESTR_SPEC = 50; // Запрос на пересылку в клиринговую систему реестра заявок
специальной торговой сессии
REQ_CLR_TRADE_REESTR_SPEC = 51; // Запрос на пересылку в клиринговую систему реестра сделок
специальной торговой сессии
REQ_CLR_ORDER
= 52; // Запрос на проверку заявки в клиринговой системе
REQ_CLR_ORDER_RFQ = 53; // Запрос на проверку заявки во время ликвидационной сессии
REQ_CLR_ORDER_DELI = 54; // Запрос на проверку заявки на физическое исполнение
REQ_CLR_ORDER_SPEC = 55; // Запрос на проверку заявки во время специальной сессии
REQ_CLR_DELI_MATCH = 56; // Запрос на регистрацию сделки во время предпоставочной сессии
REQ_CLR_TRADE_RFQ = 57; // Запрос на регистрацию сделки в клиринговой системе во время RFQ
сессии
REQ_CLR_TRADE_DELI = 58; // Запрос на регистрацию сделки на физическую поставку в
клиринговой системе
REQ_CLR_TRADE_SPEC = 59; // Запрос на регистрацию сделки в клиринговой системе во воремя
специальной сессии
REQ_BD_SCHEDULE_UPDATE
= 60; // Запрос на изменение расписания бизнес-дня
REQ_FORCE_LOGOFF
= 61; // Принудительное завершение работы в информационной или
транзакционной подсистеме
REQ_CHANGE_PASSWORD
= 62; // Запрос на изменение пароля
REQ_CANC_ORDERS_BY_PARTICIPANT
= 63; // Запрос на снятие всех заявок партисипанта
REQ_CANC_ORDERS_BY_USER
= 64; // Запрос на снятие всех заявок пользователя
REQ_CANC_ORDERS_BY_CLIENT = 65; // Запрос на снятие всех заявок клиента
REQ_CANC_ORDERS_BY_ACCOUNT = 66; // Запрос на снятие всех заявок по счету
REQ_CANC_ORDERS_BY_SECURITY
= 67; // Запрос на снятие всех заявок по инструменту
REQ_CANC_ORDERS_BY_BOARD
= 68; // Запрос на снятие всех заявок по борду
REQ_CANC_ORDERS_BY_SECBOARD
= 69; // Запрос на снятие всех заявок по секборду
REQ_TABS_PARAMS
= 100; // Запрос на пересылку параметров внутренних таблиц
/*Replies*/
REP_OK
= 10000;
// Успешное завершение запроса
REP_BAD_UNKNOWN_REQ_TYPE
= 10001; //
REP_BAD_USER_NOT_FOUND
= 10002; //
REP_BAD_USER_NOT_LOGGED_ON = 10003; //
REP_BAD_USER_SUSPENDED
= 10004; //
REP_BAD_PARTICIPANT_SUSPENDED = 10005;
REP_BAD_USER_ALREADY_LOGGED_ON = 10006;
REP_BAD_INVALID_PASSWORD
= 10007; //
REP_BAD_BOARD_NOT_FOUND
= 10008; //
REP_BAD_SECBOARD_OVERFLOW
= 10009; //
REP_BAD_SECURITY_NOT_FOUND = 10010; //
REP_BAD_SECBOARD_EXISTS
= 10011; //
REP_BAD_ORDER_OVERFLOW
= 10012; //
REP_BAD_SECBOARD_NOT_FOUND = 10013; //
REP_BAD_SECBOARD_NOT_OPEN
= 10014; //
открыты
REP_BAD_ACCOUNT_NOT_FOUND
= 10015; //
REP_BAD_ACCOUNT_NOT_OWNED
= 10016; //
REP_BAD_ORDER_NOT_FOUND
= 10017; //
REP_BAD_INVALID_ORDER_STATUS = 10018; //
REP_BAD_CLIENT_NOT_FOUND
= 10019; //
REP_BAD_CLIENT_NOT_OWNED
= 10020; //
REP_BAD_PARTICIPANT_NOT_FOUND = 10021;
REP_BAD_PARTICIPANT_OVERFLOW = 10022; //
REP_BAD_USER_OVERFLOW
= 10023; //
REP_BAD_CLIENT_OVERFLOW
= 10024; //
REP_BAD_SECTION_OVERFLOW
= 10025; //
REP_BAD_INVALID_SECBOARD_STATUS = 10026;
контракта
REP_BAD_BOARD_OVERFLOW
= 10027; //
REP_BAD_SECTION_NOT_FOUND
= 10028; //
REP_BAD_SECTYPE_OVERFLOW
= 10029; //
REP_BAD_SECURITY_OVERFLOW
= 10030; //
REP_BAD_SECTYPE_NOT_FOUND
= 10031; //
REP_BAD_TRADE_OVERFLOW
= 10032; //
REP_BAD_ACCOUNT_OVERFLOW
= 10033; //
REP_BAD_CLOWN_NE_ACCOWN
= 10034; //
REP_BAD_INMSG_OVERFLOW
= 10035; //
REP_BAD_INVALID_PRICE
= 10036; //
© CMA Small Systems AB, 2010
Неизвестный тип запроса
Пользователь не найден
Пользователь не зарегистрирован в системе
Пользователь заблокирован
// Участник заблокирован
// Пользователь уже зарегистрирован в системе
Неправильный пароль
Режим торгов не найден
Таблица серий срочных контрактов переполнена
Серия срочного контракта не найдена
Серия срочного контракта уже существует
Таблица заявок переполнена
Серия срочного контракта не найдена
Торги по данной серии срочных контрактов не
Позиционный регистр не найден
Неверный идентификатор позиционного регистра
Заявка не найдена
Неверное состояние заявки
Клиент не найден
Неверный идентификатор клиента
// Участник торгов не найден
Таблица Участников торгов переполнена
Таблица пользователей переполнена
Таблица клиентов переполнена
Таблица секций переполнена
// Неверное состояние серии срочного
Таблица режимов торгов переполнена
Секция не найдена
Таблица типов срочных контрактов переполнена
Таблица срочных контрактов переполнена
Тип срочных контрактов не найден
Таблица сделок переполнена
Таблица позиционных регистров переполнена
Клиент не является владельцем счета
Таблица сообщений переполнена
Ошибка в указании цены
20
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
REP_BAD_WRONG_PARTICIPANT
= 10037; // Ошибка в идентификаторе участника
REP_BAD_CLEARING_NOT_AVAILABLE = 10038;
// Клиринговая система недоступна
REP_BAD_CLIENT_SUSPENDED
= 10039;
REP_BAD_ACCOUNT_SUSPENDED
= 10040;
позиционного регистра приостановлен
REP_BAD_SECTION_SUSPENDED
= 10041;
// Участие клиента приостановлено
// Допуск к осуществлению операций с данного
// Работа Секции приостановлена
REP_BAD_PARTICIPANT_NOT_SUSPENDED
= 10042;
// Допуск Участника торгов не
приостановлен
REP_BAD_USER_NOT_SUSPENDED = 10043; // Допуск пользователя к торгам не приостановлен
REP_BAD_CLIENT_NOT_SUSPENDED = 10044; // Участие клиента не приостановлено
REP_BAD_ACCOUNT_NOT_SUSPENDED = 10045;
// Допуск к осуществлению операций с данного
позиционного регистра не приостановлен
REP_BAD_SECTION_NOT_SUSPENDED = 10046;
// Работа Секции не приостановлена
REP_BAD_TXTMSG_OVERFLOW
= 10047; // Таблица сообщений переполнена
REP_BAD_ACCESS_RIGHTS
= 10048; // Доступ запрещен
// Ответы из клиринга
REP_CLR_LOGON_OK
= 10049;
REP_CLR_LOGON_BAD
= 10050;
REP_CLR_ORDER_OK
= 10051;
REP_CLR_ORDER_BAD
= 10052;
REP_CLR_ORDER_CANCEL_OK
=
REP_CLR_ORDER_CANCEL_BAD
=
REP_CLR_TRADE_OK
= 10055;
REP_CLR_TRADE_BAD
= 10056;
REP_CLR_SETTLE_PRICE_OK
=
REP_CLR_SETTLE_PRICE_BAD
=
// Регистрация в клиринговой системе завершилось успешно
// Регистрация в клиринговой системе была отклонена
// Заявка может участвововать в мэтчинге
// Заявка должна быть отклонена торговой системой
10053; // Подтверждение снятия заявки в клиринговой системе
10054; // Снятие заявки невозможно(***)
// Подтверждение регистрации сделки в клиринговой системе
// Регистрация сделки невозможна (***)
10057; // Подтверждение регистрации новой расчетной цены
10058; // Регистрация расчетной цены невозможна (***)
REP_BAD_UNKNOWN_REQUEST
= 10059; // Неизвестный запрос
REP_BAD_INVALID_QTY = 10060;
// Неверно указано количество
REP_BAD_ACCOUNT_TYPE = 10061;
// Ошибка в спецификации типа счета
REP_BAD_NO_BOARD_SECURITIES = 10062; // Ни одна серия срочных контрактов не представлена
для режима торгов
REP_BAD_INVALID_SEC_PARAMS = 10063; // Зарезервировано. Не используется в текущей версии
REP_BAD_OPERDAY_CLOSED
= 10064;
REP_BAD_NO_BOARD_POSITIONS = 10065;
режиме торгов
REP_BAD_ACCOUNT_NOT_ALLOWED = 10066;
торгов
REP_CLR_ORDER_REESTR_OK
REP_CLR_ORDER_REESTR_ERROR
REP_CLR_TRADE_REESTR_OK
REP_CLR_TRADE_REESTR_ERROR
=
=
=
=
REP_BAD_STATION_NOT_FOUND
REP_BAD_WRONG_STATION
= 10071;
= 10072;
REP_BAD_NOT_NEGDEALS = 10073;
10067;
10068;
10069;
10070;
// Торги закрыты
// Ни один из регистров не представлен в данном
// Регистр не может использоваться в данном режиме
//
//
//
//
Подтверждение
Ошибка приема
Подтверждение
Ошибка приема
приема и сверки реестра заявок
или сверки реестра заявок
приема и сверки реестра сделок
или сверки реестра сделок
// Неверный код станции
// Неверная станция для указаного направления платежа
// Тип заявки не адресная... поле Контрагент заполнено...
REP_BAD_NOT_ALL_MANDATORY_FIELDS
= 10074;
// Не все обязательные поля заполнены
REP_BAD_INVALID_ADDRESSEE
= 10075; // Неверный адресат
REP_BAD_CLIENT_ISNOT_ACC_OWNER = 10076;
// Клиент не является владельцем счета
REP_BAD_MESSAGE_NOT_CRYPTED = 10080; // Сообщение не зашифровано
REP_BAD_MESSAGE_NOT_SIGNED = 10081; // Сообщение не подписано
REP_BAD_INVALID_SIGNATURE
= 10082; // Ошибка проверки подписи
REP_BAD_CERTIFICATE_NOT_FOUND = 10083;
// Сертификат не зарегистрирован на
пользователя
REP_BAD_ORDER_TYPE_UNDEFINED = 10084; // Не задан тип заявки
REP_BAD_ORDER_PARAMS_UNDEFINED = 10085;
// Не заданы параметры заявки
REP_BAD_ORDER_BS_UNDEFINED = 10086; // Не задано направление заявки
REP_BAD_COUNTERPARTY_UNDEFINED = 10087;
// Не задан контрагент
REP_BAD_INVALID_MMF = 10088;
// Тип заявки не лимитированная... Задан флаг
маркетмейкера...
REP_BAD_ORDER_INVALID_PARAMS = 10089; // Неверные параметры заявки
REP_TABS_PARAMS
= 10100;
// Подтверждение получения параметров талиц
OK_CHANGES
= 11000;
// Новые данные по подписке на информационную таблицу
REP_BAD_FATAL_ERROR = 13000;
// Внутренняя ошибка
}
© CMA Small Systems AB, 2010
21
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
enum EncryptStatus {
UNENCRYPTED = 0;
CPRO = 1;
}
// Сообщение не зашифровано
// Сообщение зашифровано Crypto PRO
enum SignStatus {
UNSIGNED = 0;
CPRO_COMBINED = 1;
CPRO_SEPARATE = 2;
}
// Без подписи
// Подпись комбинирована с сообщением
// Подпись отдельно от сообщения
enum SignCheckResult {
SCHECK_OK = 0;
SCHECK_OTHER = 1;
SCHECK_NOCERT = 2;
SCHECK_EXPIRED = 3;
SCHECK_NOTRUST = 4;
SCHECK_NOSIGN = 5;
}
//
//
//
//
//
//
Руководство разработчика
Подпись проверена успешно
Подпись не валидна
Нет сертификата
Сертификат просрочен
Сертификат подписан неизвестным центром сертификации
Не подписано
message CryptoEnvelope
{
required int32 ver = 1; // Номер версии протокола
required EncryptStatus encrypted = 2;
// Признак использования шифрования
required SignStatus signed = 3;
// Признак использования подписи
optional bytes data = 4;
optional bytes signature = 5;
// Контейнер для пакета сообщений
// Контейнер для подписи, в случае SignStatus == CPRO_SEPARATE
}
// Обрамляющее сообщение "конверт" для всех прочих типов сообщений
// внутреннее сообщение помещается в поле data как сериализованное
//
message Envelope
{
optional int32 ver = 1; // Версия
optional string uid = 2;
// Идентификатор пользователя
optional string sid = 3;
// Идентификатор сессии пользователя
optional uint64 reqid = 4;
// Идентификатор запроса.
// В ответе на данный запрос сервер поместит в данное поле
// значение указанное клиентом в соответстующем запросе.
// Клиент может использовать данное поле для реализации алгоритмов
// связи запросов и ответов
optional uint64 cryptoMsgid = 7; // Служебное поле подситемы криптозащиты
optional uint64 timestamp = 8;
// Служебное поле подситемы криптозащиты
optional string cryptoUid = 9; // Служебное поле подситемы криптозащиты
optional SignCheckResult cryptoresult = 10; // Результат проверки подписи
optional bool origEncrypted = 11;
// Исходное сообщение было зашифровано
optional bool origSigned = 12; // Исходное сообщение было подписано
repeated MsgType type = 5;
// Тип сообщения
repeated bytes data = 6;
// Внутреннее сообщение
}
// Набор возможных статусов объектов
//
enum RowStatus
{
ACTIVE
= 1;
//
SUSPENDED
= 2;
//
DEFAULTED
= 3;
//
}
// Набор возможных статусов
//
enum SBStatus
{
SB_OPENED
=
SB_SUSPENDED
=
SB_CLOSED
=
SB_CLOSED_FOR_ORDERS =
}
системы
Активный
Приостановленный
Удаленный
режимов торгов
1;
2;
3;
4;
// Набор возможных типов заявок
//
enum OrderType
{
LIMIT
= 0;
© CMA Small Systems AB, 2010
//
//
//
//
Открыт
Приостановлен
Закрыт
Закрыт для заявок
// Лимитированная
22
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
MARKET
NEGDEALS
LIQUIDATION
DELIVERY
DELI_SPECIAL
=
=
=
=
=
1;
2;
3;
4;
5;
//
//
//
//
//
Рыночная
Адресная
Ликвидационная
Поставочная
Специальная
//
//
//
//
Безадресная
Адресная
Ликвидационная
Поставочная
Руководство разработчика
}
// Набор возможных типов сделок
//
enum TradeType
{
TRD_ORDINARY
= 0;
TRD_ADDRESS
= 1;
TRD_RFQ
= 2;
TRD_DELIVERY
= 3;
}
// Набор возможных типов режимов торгов
//
enum BoardType
{
BRD_NORMAL
= 0;
// Нормальный
BRD_RFQ
= 1;
// Ликвидационный
BRD_DELIVERY
= 2;
// Предпоставочный
BRD_DELI_SPECIAL
= 3;
// Специальный предпоставочный
}
// Набор возможных типов позиционных регистров
//
enum AccountType
{
ACC_NORMAL
= 0;
// Нормальный
ACC_RFQ
= 1;
// Ликвидационный
ACC_DELIVERY
= 2;
// Поставочный
ACC_GARANT
= 3;
// Гарантирующий
}
// Набор возможных параметров заявок
//
enum OrderParams
{
PIQ
= 0;
// put-in-queue, поставить в очередь
IOC
= 1;
// immediate-or-cancel, немедленно или отклонить
FOK
= 2;
// fill-or-kill, все или отклонить
}
// Набор возможных статусов
//
enum OrderStatus
{
QUEUED
=
MATCHED
=
CANCELED
=
WAIT_APPROVAL
=
FREEZED
=
}
заявок
0;
1;
2;
3;
4;
//
//
//
//
//
Помещена в очередь
Удовлетворена
Отменена
Ждет подтверждения
Заморожена (пользователь не может снять заявку)
// Набор возможных направлений заявок
//
enum BuySell
{
BUY
= 1;
// Купить
SELL
= 2;
// Продать
}
// Набор возможных типов пользователей
//
enum UserType
{
TRADER
= 0;
// Трейдер
MAKLER
= 1;
// Маклер
CLEARING
= 2;
// Клиринг
GATEWAY
= 3;
// Гейтвей
}
enum AddresseeType
{
© CMA Small Systems AB, 2010
23
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
ADDR_USER
ADDR_FIRM
ADDR_BROADCAST
= 0;
= 1;
= 2;
Руководство разработчика
// Пользователь
// Фирма
// Всем пользователям
}
// Набор возможных
//
enum Table
{
PARTICIPANTS
USERS
CLIENTS
ACCOUNTS
SECTIONS
BOARDS
SECTYPES
SECURITIES
SECBOARDS
HOLDINGS
ORDERS
TRADES
INMSGS
EVENTS
SCHEDULE
PRICE_HISTORY
TEXT_MESSAGES
STATIONS
DELIVERYBASIS
CERTIFICATES
}
типов информационных таблиц
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
1;
2;
3;
4;
5;
6;
7;
8;
9;
10;
11;
12;
13;
14;
15;
16;
17;
18;
19;
20;
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
Участники
Пользователи
Клиенты
Регистры
Секции
Режимы
Типы инструментов
Инструменты
Доступные для операций инструменты для определенных режимов торгов
Открытые позиции
Заявки
Сделки
Входные сообщения
События
Расписание
История изменений рыночной цены
Текстовые сообщения
Станции назначения
Базисы поставки
пользовательские сертификаты
// Типы событий в подсистеме наблюдения за нестандартными заявками и сделками
enum EventType
{
EVENT_ORDER_ALARM
= 1;
// Нестандартная заявка
EVENT_TRADE_ALARM
= 2;
// Нестандартная сделка
}
// Типы шифрования
enum EncryptType
{
ENCRYPT_NO
ENCRYPT_ALL
ENCRYPT_LOG_ON_OFF
}
// Типы подписи
enum SignType
{
SIGN_NO
SIGN_ALL
SIGN_LOG_ON_OFF
}
= 1; // Не шифровать
= 2; // Шифровать все сообщения
= 3; // Шифровать только Logon и Logoff
= 1; // Не подписывать
= 2; // Подписывать все сообщения
= 3; // Подписывать только Logon и Logoff
//Requests
// Рассылка информации о текстовых сообщениях
//
message Meddelande
{
optional string
addressee = 1; // Адресат
optional string
text
= 2; // Текст сообщения
optional uint32
priority
= 3; // Приоритет
optional AddresseeType
addr_type = 4 [default = ADDR_USER]; // Тип адресата
}
// Рассылка информации об участниках
//
message Participant
{
optional string
code
= 1;
optional string
name
= 2;
optional string
inn
= 3;
optional string
kpp
= 4;
optional string
ogrn
= 5;
optional string
okpo
= 6;
© CMA Small Systems AB, 2010
//
//
//
//
//
//
Код
Наименование
Код ИНН
Код КПП
Код ОГРН
Код ОКПО
24
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
}
// Рассылка информации о пользователях
//
message User
{
optional string
code
= 1;
optional string
name
= 2;
optional string
firm
= 3;
optional string
password
=
optional UserType
type
= 5;
optional EncryptType encrypt = 6;
optional SignType
sign
= 7;
}
//
//
//
4;
//
//
//
Код
Наименование
Участник торгов
// Пароль
Тип пользователя
Тип шифрования
Тип подписи
// Рассылка информации о клиентах
//
message Client
{
optional string
code
= 1; // Код
optional string
name
= 2; // Наименование
optional string
firm
= 3; // Участник торгов
optional string
inn
= 4; // Код ИНН
}
// Рассылка информации о позиционных регистрах
//
message Account
{
optional string
code
= 1; // Код
optional string
name
= 2; // Наименование
optional string
firm
= 3; // Участник торгов
optional string
client = 4; // Клиент
optional AccountType type
= 5; //
Тип регистра
}
// Рассылка информации о секциях
//
message Section
{
optional string
code
optional string
name
}
= 1; // Код
= 2; // Наименование
// Рассылка информации о режимах торгов
//
message Board
{
optional string
code
= 1; // Код
optional string
name
= 2; // Наименование
optional string
section = 3; // Секция
optional BoardType
type
= 4; //
Тип режима торгов
}
// Рассылка информации о типах срочных контрактов
//
message SecType
{
optional string
code
= 1; // Код
optional string
name
= 2; // Наименование
}
// Рассылка информации о срочных контрактах
//
message Security
{
optional string
code
= 1; // Код
optional string
name
= 2; // Наименование
optional string
sec_type
= 3; // Тип срочного контракта
optional uint32
lot_size
= 4; // Размер лота
optional uint64
price_step
= 5; // Шаг цены
optional string
currency_code = 6; // Код валюты
optional string
currency_name = 7; // Наименование валюты
optional int64
price_move_limit
= 8; // Абсолютное значение предела движения цены
optional uint32
price_move_limit_prc
= 9; // Процентное значение предела движения цены
optional uint32
limit_market_share
= 10; // Процентное значение лимита на долю рынка
optional int64
limit_market_share_threshold= 11; // Порог срабатывания лимита на долю рынка
optional string
delivery_basis = 12; // Наименование базиса поставки
© CMA Small Systems AB, 2010
25
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
optional string
delivery_basis_id
Руководство разработчика
= 13; // Код базиса поставки
}
// Запрос на изменение пароля пользователя
//
message ChangePassword
{
optional string user_name
= 1; // Идентификатор пользователя
optional string old_password
= 2; // Старый пароль
optional string new_password
= 3; // Новый пароль
}
// информации о периоде бизнес-дня
//
message BDState
{
required uint32
code
optional string
name
optional string
handle
optional string
start_time
optional string
act_start_time
optional string
status
optional string
bday
}
=
=
=
=
=
=
=
1;
2;
3;
4;
5;
6;
7;
//
//
//
//
//
//
//
Код
Название периода
Режим периода
Время начала периода
Актуальное время начала периода
Состояние
Бизнес день
// Запрос изменения расписания бизнес-дня
//
message BDScheduleUpdate
{
repeated BDState state
= 1; // периоды бизнес-дня
}
// Регистрация в информационном или транзакционном фиде
//
message Logon
{
optional uint64 item_id
= 1;
// Идентификатор сообщения
optional string uid
= 2;
// Идентификатор пользователя
optional string password
= 3;
// Пароль
optional uint32 decimal_scale
= 4 [default = 2]; // Количество десятичных знаков после
запятой
}
// Завершение работы с информационным или транзакционным фидом
//
message Logoff
{
optional uint64 item_id = 1;
// Идентификатор сообщения
optional string uid = 2;
// Идентификатор пользователя
optional string sid = 3;
// Идентификатор сессии
}
// Открытие режима торгов
//
message OpenSecBoard
{
required string
board
= 1; // Режим
required string
security
= 2; // Инструмент
//For Normal Board
optional uint64
open_price
= 3; //
Зарезервировано.
optional uint64
prev_market_price
= 4; //
Расчетная цена предыдушей сессии
optional string
order_metrix
= 5; // Метрики для выявления необычных заявок
optional string
trade_metrix
= 6; // Метрики для выявления необычных сделок
//For RFQ Board
optional uint32
qty
= 7; // Количество ликвидируемых контрактов
optional uint64
price_min
= 8; // Минимальная цена
optional uint64
price_max
= 9; // Максимальная цена
//Common
optional uint64
event_id
= 10; // Идентификатор события
}
// Посылка заявки
//
message Order
{
optional uint64
item_id
© CMA Small Systems AB, 2010
= 1; // Идентификатор сообщения
26
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
optional string
trn
= 2; // Номер транзакции. Формируется клиентом и
должен быть уникальным в рамках сессии
optional OrderType
type
= 3; // Тип заявки
optional OrderParams params
= 4; // Параметры заявки
optional BuySell
buy_sell
= 5; // Направление заявки
optional string
board
= 6; // Режим торгов
optional string
security
= 7; // Инструмент
optional string
account
= 8; // Регистр
optional uint64
price
= 9; // Цена
optional uint32
qty
= 10;// Количество
optional uint64
time_in_force
= 11 [default = 0];
// values from 0 to 10 are
reserved, 0 good-for-day
optional string
firm
= 12; // Фирма
optional string
client
= 13; // Клиент
optional string
cp_firm
= 14; // Контрагент для адресной заявки
optional string
comment
= 15; // Комментарий
optional string
id
= 16; // Идентификатор заявки. Формируется торговым
сервером. Заполняется только при отправлении из торговой системы в клиринговую.
optional uint64
time_stamp
= 17; // Время поступления заявки. Формируется
торговым сервером. Заполняется только при отправлении из торговой системы в клиринговую.
optional bool
isMarketMaker
= 18 [default = false]; // Флаг принадлежности заявки
маркет мейкеру
optional string
destination
= 19; // Код Станция отправления/назначения.
Заполняется клиентом только для поставочных заявок.
}
// Ответ на посылку заявки
//
message OrderRepOK
{
optional string
code
optional OrderStatus status
optional uint32
qty
optional uint32
qtyLeft
optional uint32
qty_executed
optional string
info
если статус заявки = Отменена
}
=
=
=
=
=
=
1;
2;
3;
4;
5;
6;
//
//
//
//
//
//
Идентификатор заявки
Статус
Количество
Количество неудовлетворенных инструментов
Количество удовлетворенных инструментов
Дополнительная информация. Заполняется только
// Запрос на акцепт заявки (только Клиринговая система может послать такой запрос)
//
message AcceptOrder
{
optional string
order_id
= 1; // Идентификатор заявки
optional uint32
qty
= 2; // Количество
}
// Запрос на сняние заявки
//
message CancelOrder
{
optional uint64
item_id = 1;
optional string
order_id = 2;
optional uint64
time_stamp = 3;
}
// Ответ на сняние заявки
//
message CancelOrderRepOK
{
optional string
optional uint32
optional uint32
optional uint32
}
code
qty
qtyLeft
qty_executed
// Идентификатор сообщения
// Идентификатор заявки
// Штамп времени
=
=
=
=
1;
2;
3;
4;
//
//
//
//
Идентификатор заявки
Количество
Количество неудовлетворенных инструментов
Количество удовлетворенных инструментов
// Подписка на определенную информационную таблицу
//
message Subscribe
{
required Table tab_id
= 1; // Идентификатор таблицы
optional int32 max_row_id
= 2; // Зарезервировано. Не используется в текущей версии
optional uint32 last_change_id = 3; // Идентификатор последнего полученного обновления
данной таблицы
// Используется при необходимости получения данных с определенного
// момента, а не с начала учета обновлений по данной таблице
}
© CMA Small Systems AB, 2010
27
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
// Запрос на отмену подписки
//
message Unsubscribe
{
required Table
tab_id = 1; // Идентификатор таблицы
}
// Информация о позиционном счете, допущенному к торговле серией срочного контракта
(BoardSecurity)
//
message BoardAccount
{
optional string
account
= 1; // Код позиционного регистра
optional uint32
buy_qty
= 2; // Количество контрактов на покупку
optional uint32
sell_qty
= 3; // Количество контрактов на продажу
}
// Информация о серии срочного контракта допущенного к торговле
//
message BoardSecurity
{
optional string
security
= 1; // Серия срочного контракта
//For Normal Board
optional uint64
optional uint64
optional string
optional string
open_price
prev_market_price
order_metrix
trade_metrix
//For RFQ Board
optional uint32
optional uint64
optional uint64
qty
= 6; //
Количество ликвидируемых контрактов
price_min = 7; // Минимальная цена
price_max = 8; // Максимальная цена
repeated BoardAccount
=
=
=
=
board_account
2;
3;
4;
5;
//
Зарезервировано
//
Расчетная цена предыдушей сессии
// Метрики для выявления необычных заявок
// Метрики для выявления необычных сделок
= 100; // Информация о позиционном регистре
}
// Запрос на загрузку серий срочных документов с набором допущенных позиционных регистров для
режима торгов
//
message BoardSecurities
{
optional string
board_name
= 1; // Режим торгов
repeated BoardSecurity security
= 2; // Информация о серии срочного контракта и регистрах
optional uint64
event_id
= 3; // Идентификатор события
}
//Replies
//
//
message TabParams
{
required Table
required uint32
}
message OrderAlarm
{
optional string
optional string
optional string
}
message TradeAlarm
{
optional string
optional string
optional string
}
tab_id = 1; // Идентификатор таблицы
size
= 2; // Размер в записях
order_id
metrix
info
= 1; // Идентификатор заявки
= 2; // Метрика, которая сработала
= 3; // Расширенная информация
trade_id
= 1; // Идентификатор сделки
metrix = 2; // Метрика, которая сработала
info
= 3; // Расширенная информация
// Новые данные по подписке на информационную таблицу
// Данное сообщение является обрамляющим для сообщений типа Info*
// Сообщение типа Info* помещается в поле rowData как сериализованное.
//
message RowChange
{
required Table
tabId
= 1; // Тип таблицы
© CMA Small Systems AB, 2010
28
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
required uint32 rowId
required uint32 changeId
optional bytes
rowData
// в виде сериализованного
Руководство разработчика
= 2; // Идентификатор строки
= 3; // Идентификатор обновления
= 4; // Новые или измененные строки информационной таблицы
сообщения типа Info*
}
// Новые данные по подпискам на информационные таблицы
// Данное сообщение является обрамляющим для сообщения типа RowChange
// Сообщения типа RowChange помещаются в поле row как сериализованные.
//
message Changes
{
required int32
ver
= 1; // Номер версии
repeated bytes
row
= 2; // Набор сериализованных сообщений типа RowChange
}
// Строка данных для информационной таблицы "Заявки"
//
message InfoOrder
{
optional string
code
= 1; // Идентификатор заявки
optional OrderStatus status
= 2; // Статус
optional OrderType
type
= 3; // Тип
optional OrderParams params
= 4; // Параметры
optional BuySell
buy_sell
= 5; // Направление
optional string
board
= 6; // Режим
optional string
security
= 7; // Инструмент
optional string
account
= 8; // Регистр
optional uint64
price
= 9; // Цена
optional uint32
qty
= 10; // Количество
optional uint32
qtyLeft
= 11; // Количество неудовлетворенных инструментов
optional uint64
time_in_force = 12 [default = 0]; // Время действия заявки. 0 - до конца
торговой сессии
optional string
user
= 13; // Пользователь
optional string
firm
= 14; // Участник
optional string
client
= 15; // Клиент
optional string
cp_firm
= 16; // Контрагент для адресной заявки
optional uint64
entry_time
= 17; // Время ввода
optional uint64
cancel_time
= 18 [default = 0]; // Время отмены
optional string
res_code
= 19; // Код результата
optional string
res_descr
= 20; // Описание результата
optional string
res_info
= 21; // Информация результата
optional string
comment
= 22; // Комментарий
optional string
trn
= 23; // Номер транзакции
optional uint32
qty_executed
= 24; // Количество удовлетворенных инструментов
optional bool
isMarketMaker = 25 [default = false]; // Флаг принадлежности заявки
маркет мейкеру
optional OrderStatus prev_status
= 26; // Предыдущий статус
optional string
destination
= 27; // Код станция отправления/назначения. Заполняется
клиентом только для поставочных заявок.
optional string
dest_name
= 28; // Наименование станции отправления/назначения.
Заполняется клиентом только для поставочных заявок.
}
// Строка данных для информационной таблицы "Сделки"
//
message InfoTrade
{
required string
code
= 1; // Код
optional BuySell
buy_sell
= 2; // Направление
optional string
board
= 3; // Режим
optional string
security
= 4; // Инструмент
optional uint64
price
= 5; // Цена
optional uint32
qty
= 6; // Количество
optional string
order_id
= 7; // Идентификатор заявки
optional uint64
trade_time
= 8; // Время сделки
optional string
firm
= 9; // Фирма
optional uint64
match_id
= 10; // Идентификатор спаривания
optional TradeType
trade_type
= 11; // Тип сделки
optional string
cp_firm
= 12; // Контрагент для адресной сделки
}
// Строка данных для таблицы событий
//
message InfoEvent
{
required string
code
= 1; // Код
required EventType
type
= 2; // Тип события
optional string
info
= 3; // Развернутая информация о событии
© CMA Small Systems AB, 2010
29
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
}
// Строка данных для информационной
//
message InfoParticipant
{
required string
code
=
optional string
name
=
optional RowStatus
status =
таблицы "Участники"
1; // Код
2; // Имя
3; // Статус
}
// Строка данных для информационной таблицы "Пользователи"
//
message InfoUser
{
required string
code
= 1; // Код
optional string
name
= 2; // Имя
optional RowStatus
status
= 3; // Статус
optional string
firm
= 4; // Участник
optional UserType
type
= 5; // Тип
optional uint64
logon_time
= 6; // Время последней регистрации с системе
optional uint64
logoff_time = 7; // Время последнего завершения работы с системой
optional string
password
= 8; // Пароль
}
// Строка данных для информационной
//
message InfoClient
{
required string
code
=
optional string
name
=
optional RowStatus
status =
optional string
firm
=
}
// Строка данных для информационной
//
message InfoAccount
{
required string
code
=
optional string
name
=
optional RowStatus
status =
optional string
firm
=
optional string
client =
optional AccountType type
=
}
таблицы "Клиенты"
1;
2;
3;
4;
//
//
//
//
Код
Имя
Статус
Участник
таблицы "Регистры"
1;
2;
3;
4;
5;
6;
//
//
//
//
//
//
Код
Имя
Статус
Участник
Клиент
Тип
// Строка данных для информационной таблицы "Открытые позиции"
//
message InfoHolding
{
optional string
code = 1;
// Код
optional string
account = 2;
// Регистр
optional string
security = 3;
// Серия срочного контракта
optional uint32
trade_income_buy_qty = 4; // Входящие Покупка
optional uint32
trade_income_sell_qty = 5; // Входящие Продажа
optional uint32
trade_buy_qty = 6;
// Текущая Покупка
optional uint32
trade_sell_qty = 7;
// Текущая Продажа
optional uint64
trade_buy_value = 8;
// Сумма затраченная на покупку
optional uint64
trade_sell_value = 9;
// Сумма вырученная при продаже
optional uint32
order_buy_qty = 10;
// План Покупка
optional uint32
order_sell_qty = 11;
// План Продажа
optional uint64
order_buy_value = 12;
// План трат на покупку
optional uint64
order_sell_value = 13;
// План выручки при продаже
optional uint64
settle_price = 14;
// Не используется
optional string
firm = 15;
// Участник
}
// Строка данных для информационной
//
message InfoSection
{
required string
code
=
optional string
name
=
optional RowStatus
status =
}
таблицы "Секции"
1; // Код
2; // Имя
3; // Статус
// Строка данных для информационной таблицы "Режимы"
© CMA Small Systems AB, 2010
30
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
//
message InfoBoard
{
required string
optional string
optional RowStatus
optional string
optional BoardType
}
code
=
name
=
status =
section =
type
=
// Строка данных для информационной
//
message InfoSectype
{
required string
code
=
optional string
name
=
optional RowStatus
status =
}
// Строка данных для информационной
//
message InfoDeliveryBasis
{
required string
code
=
optional string
name
=
optional RowStatus
status =
}
1;
2;
3;
4;
5;
//
//
//
//
//
Руководство разработчика
Код
Имя
Статус
Секция
Тип
таблицы "Типы инструментов"
1; // Код
2; // Имя
3; // Статус
таблицы "Базисы поставки"
1; // Код
2; // Имя
3; // Статус
// Строка данных для информационной таблицы "Инструменты"
//
message InfoSecurity
{
required string
code
= 1; // Код
optional string
name
= 2; // Имя
optional RowStatus
status
= 3; // Статус
optional string
sec_type
= 4; // Тип
optional uint32
lot_size
= 5; // Размер лота
optional uint64
price_step
= 6; // Шаг цены
optional string
currency_code
= 7; // Код валюты
optional string
currency_name
= 8; // Наименование валюты
optional uint64
price_move_limit
= 9; // Абсолютное значение предела движения цены
optional uint64
price_move_limit_prc = 10; // Процентное значение предела движения цены
optional uint64
limit_market_share = 11; // Процентное значение лимита на долю рынка
optional uint64
limit_market_share_threshold = 12; // Порог срабатывания лимита на долю
рынка
optional string
delivery_basis_code
= 13; // Код базиса поставки
optional string
delivery_basis_name
= 14; // Название базиса поставки
optional uint32
delivery_min_qty
= 15; // минимальное кол-во поставки
optional uint32
delivery_qty_step = 16; // шаг кол-ва поставки (вагонная норма)
optional string
first_trade_day
= 17; // первый торговый день для инструмента
optional string
last_trade_day
= 18; // последний торговый день для инструмента
optional string
execution_day
= 19; // день исполнения инструмента
optional uint32
optional uint32
income_qty
current_qty
= 20; // Сумма входных позиций
= 21; // Сумма текущих позиций
}
// Строка данных для информационной таблицы "Доступные для операций инструменты для определенных
режимов торгов"
//
message InfoSecboard
{
optional string
code
= 1; // Код
optional string
security
= 2; // Инструмент
optional string
board
= 3; // Режим
optional
optional
optional
optional
uint64
uint32
uint64
uint32
best_buy
buy_orders
best_sell
sell_orders
=
=
=
=
optional uint64
optional uint64
value_today
volume_today
= 8; // Объем в деньгах сегодня
= 9; // Объем в инструментах сегодня
optional uint64
optional uint64
optional uint64
open_price
prev_market_price
market_price
= 10; // Цена открытия
= 11; // Предыдущая расчетная цена
= 12; // Расчетная цена
© CMA Small Systems AB, 2010
4;
5;
6;
7;
//
//
//
//
Лучшая
Заявок
Лучшая
Заявок
покупка
на покупку
продажа
на продажу
31
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
optional int64
market_price_change = 13; // Изменение расчетной цены
optional uint64
optional uint32
optional uint64
last_trade_price
last_trade_qty
last_trade_time
= 14; // Цена последней сделки
= 15; // Количество последней сделки
= 16; // Время последней сделки
optional uint64
optional uint64
high_trade_price
low_trade_price
= 17; // Наибольшая цена сделки
= 18; // Наименьшая цена сделки
optional uint32
optional uint32
num_of_orders
= 19; // Количество заявок
num_of_active_orders= 20; // Количество активных заявок
optional uint32
num_of_trades
= 21; // Количество сделок
optional SBStatus
status
= 22; // Статус
optional BoardType board_type
// Поля для режима RFQ
optional uint32
qty
optional uint64
price_min
optional uint64
price_max
optional uint64
addr_value_today
optional uint64
addr_volume_today
сделкам
optional uint64
sell_order_value
optional uint64
sell_order_volume
продажу
optional uint64
buy_order_value
optional uint64
buy_order_volume
покупку
}
// Строка данных для информационной
//
message InfoState
{
required string code
optional string name
optional string bday
optional string handle
optional string start_time
optional string act_start_time
optional string finish_time
optional string act_finish_time
optional string status
}
= 23; // Тип режима
=
=
=
=
=
24;
25;
26;
27;
28;
//
//
//
//
//
Количество
Минимальная цена
Максимальная цена
Объем в деньгах сегодня по адресным сделкам
Объем в инструментах сегодня по адресным
= 29; // Объем в деньгах по активным заявкам на продажу
= 30; // Объем в инструментах по активным заявкам на
= 31; // Объем в деньгах по активным заявкам на покупку
= 32; // Объем в инструментах по активным заявкам на
таблицы "Расписание"
=
=
=
=
=
=
=
=
=
1;
2;
3;
4;
5;
6;
7;
8;
9;
//
//
//
//
//
//
//
//
//
Код
Название периода
Бизнес день
Режим торгов
Время начала периода
Актуальное время начала периода
Время окончания периода
Актуальное время окончания периода
Состояние
// Строка данных для информационной таблицы
//
message InfoMeddelande
{
optional string
code
= 1;
optional string
from
= 2;
optional string
to
= 3;
optional string
text
= 4;
optional uint64
entry_time
= 5;
optional uint32
priority
= 6;
optional string
to_firm
= 7;
}
"Текстовые сообщения"
// Строка данных для информационной таблицы
//
message InfoStation
{
optional string
basis_code = 1;
optional string
code
= 2;
optional string
name
= 3;
optional uint32
distance
= 4;
optional string
security
= 5;
optional BuySell
buy_sell
= 6;
}
"Станции назначения"
//
//
//
//
//
//
//
//
//
//
//
//
//
Код
Отправитель
Получатель
Текст сообщения
Время посылки сообщения
Приоритет
фирма получатель
Код станции базиса поставки
Код станции
Наименование станции
Расстояние от базиса поставки до станции
Инструмент
доставка/отгрузка
//Clearing requests. Запросы отправляемые в Клиринговую систему
// Запрос на регистрацию сделки
//
© CMA Small Systems AB, 2010
32
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
message Trade
{
optional uint64
optional string
optional string
optional uint64
optional uint32
optional uint64
optional uint64
}
item_id = 1;
trade_id = 2;
order_id = 3;
time_stamp = 4;
exec_qty = 5;
exec_price = 6;
match_id = 7;
//
//
//
//
//
//
//
Идентификатор
Идентификатор
Идентификатор
Штамп времени
Количество
Цена
Идентификатор
Руководство разработчика
сообщения
сделки
заявки
сделки
спаривания
// Запрос на регистрацию расчетной цены
//
message SettlementPrice
{
optional uint64 item_id = 1;
// Идентификатор сообщения
optional uint64 time_stamp = 2;
// Штамп времени изменения расчетной цены
optional string board = 3;
// Режим
optional string seccode = 4;
// Серия срочного контракта
optional uint64 price = 5;
// Цена
optional uint64 price_id = 6;
// Идентификатор цены
optional uint32 id = 7;
// Идентификатор изменения
}
//Clearing Replies. Ответы Клиринговой системы
// Описание причины
//
message Reason
{
optional string
optional string
optional string
}
отклонения заявки
code = 1; // Код ошибки
desc = 2; // Описание ошибки
info = 3; // Расширеная информация об ошибке
// Регистрация в системе завершилась успешно
//
message LogonOK
{
optional uint64 item_id = 1;
// Идентификатор сообщения
optional string sid = 2;
// Иденификатор сессии
optional uint64 last_item_id = 3;
// Идентификатор последнего сообщения
optional uint64 last_order_id = 4; // Идентификатор последней заявки
optional uint64 last_trade_id = 5; // Идентификатор последней сделки
optional uint64 last_price_id = 6; // Идентификатор последнего изменения цены
}
// Регистрация в системе была отклонена
//
message LogonBAD
{
optional uint64 item_id = 1; // Идентификатор сообщения
optional Reason reason = 2; // Описание ошибки
}
// Загрузка данных
//
message Holding
{
optional string
optional string
optional uint32
optional uint32
optional uint32
optional uint32
optional uint64
optional uint64
optional uint32
optional uint32
optional uint64
optional uint64
}
о позиционных регистрах
account = 1;
security = 2;
trade_income_buy_qty = 3;
trade_income_sell_qty = 4;
trade_buy_qty = 5;
trade_sell_qty = 6;
trade_buy_value = 7;
trade_sell_value = 8;
order_buy_qty = 9;
order_sell_qty = 10;
order_buy_value = 11;
order_sell_value = 12;
//
//
//
//
//
//
//
//
//
//
//
//
Регистр
Серия срочного контракта
Входящие Покупка
Входящие Продажа
Текущая Покупка
Текущая Продажа
Сумма затраченная на покупку
Сумма вырученная при продаже
План Покупка
План Продажа
План трат на покупку
План выручки при продаже
// Клиринговая система разрешает заявке участие в мэтчинге
//
message OrderOK
{
optional uint64 item_id = 1;
// Идентификатор сообщения
optional string order_id = 2;
// Идентификатор заявки
© CMA Small Systems AB, 2010
33
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
optional
optional
optional
optional
optional
uint32
uint32
uint64
uint64
uint64
order_buy_qty = 3;
order_sell_qty = 4;
order_buy_value = 5;
order_sell_value = 6;
order_settle_price = 7;
//
//
//
//
//
Руководство разработчика
План Покупка
План Продажа
План трат на покупку
План выручки при продаже
Не используется
}
// Клиринговая система отклоняет заявку
//
message OrderBAD
{
optional uint64 item_id = 1;
optional string order_id = 2;
optional Reason reason = 3;
optional bool
nak = 4 [default=false];
}
//
//
//
//
Идентификатор сообщения
Идентификатор заявки
Описание причины
отвергнута КС
// Клиринговая система успешно зарегистрировала снятие заявки
//
message OrderCancOK
{
optional uint64 item_id = 1;
// Идентификатор сообщения
optional string order_id = 2;
// Идентификатор заявки
optional uint32 order_buy_qty = 3;
// План Покупка
optional uint32 order_sell_qty = 4;
// План Продажа
optional uint64 order_buy_value = 5;
// План трат на покупку
optional uint64 order_sell_value = 6;
// План выручки при продаже
optional uint64 order_settle_price = 7;
// Не используется
}
// Клиринговая система не зарегистрировала снятие заявки
//
message OrderCancBAD
{
optional uint64 item_id = 1;
// Идентификатор сообщения
optional string order_id = 2; // Идентификатор заявки
optional Reason reason = 3;
// Описание причины
}
// Клиринговая система успешно зарегистрировала сделку
//
message TradeOK
{
optional uint64 item_id = 1;
// Идентификатор сообщения
optional string trade_id = 2;
// Идентификатор сделки
optional uint32 trade_buy_qty = 3;
// Текущая Покупка
optional uint32 trade_sell_qty = 4;
// Текущая Продажа
optional uint64 trade_buy_value = 5;
// Сумма затраченная на покупку
optional uint64 trade_sell_value = 6;
// Сумма вырученная при продаже
optional uint32 order_buy_qty = 7;
// План Покупка
optional uint32 order_sell_qty = 8;
// План Продажа
optional uint64 order_buy_value = 9;
// План трат на покупку
optional uint64 order_sell_value = 10;
// План выручки при продаже
optional uint64 trade_settle_price = 11;
// Не используется
}
// Клиринговая система не зарегистрировала сделку
//
message TradeBAD
{
optional uint64 item_id = 1;
// Идентификатор сообщения
optional string trade_id = 2; // Идентификатор сделки
optional Reason reason = 3;
// Описание причины
}
// Клиринговая система успешно приняла и проверила реестр заявок
//
message OrderReestrOK
{
optional uint64 item_id = 1;
// Идентификатор сообщения
}
// Клиринговая система отвергла реестр заявок
//
message OrderReestrBAD
{
optional uint64 item_id = 1;
// Идентификатор сообщения
optional Reason reason = 2;
// Описание причины
}
© CMA Small Systems AB, 2010
34
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
// Клиринговая система успешно приняла и проверила реестр сделок
//
message TradeReestrOK
{
optional uint64 item_id = 1;
// Идентификатор сообщения
}
// Клиринговая система отвергла реестр сделок
//
message TradeReestrBAD
{
optional uint64 item_id = 1;
// Идентификатор сообщения
optional Reason reason = 2;
// Описание причины
}
// Клиринговая система успешно зарегистрировала изменение расчетной цены
//
message SettlePriceOK
{
optional uint64 item_id = 1;
// Идентификатор сообщения
optional string board = 2;
// Режим торгов
optional string seccode = 3;
// Серия срочного контракта
optional uint64 price_id = 4;
// Идентификатор цены
optional uint32 id = 5;
// идентификатор изменения
}
// Клиринговая система не зарегистрировала изменение рачетной цены
//
message SettlePriceBAD
{
optional uint64 item_id = 1;
// Идентификатор сообщения
optional string board = 2;
// Режим торгов
optional string seccode = 3;
// Серия срочного контракта
optional Reason reason = 4;
// Описание причины
optional uint64 price_id = 5;
// Идентификатор цены
optional uint32 id = 6;
// Идентификатор изменения
}
// Запрос на снятие заявок по списку (Принимается только от Клиринговой системы)
//
message OrderCancReestr
{
repeated string order_id = 1; // Идентификатор заявки
}
// Реестр заявок
//
message OrderReestr
{
optional uint64 item_id = 1;
repeated InfoOrder order = 2;
}
// Реестр сделок
//
message TradeReestr
{
optional uint64 item_id = 1;
repeated InfoTrade trade = 2;
}
© CMA Small Systems AB, 2010
// Идентификатор сообщения
// Информация по заявке
// Идентификатор сообщения
// Информация по сделке
35
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
Библиотека zmqCommClient.dll
Программирование информационного обмена внешних систем с СЭТ СР СПбМТСБ через шлюз
ШКС осуществляется при помощи обращений к методам динамической библиотеки
zmqCommClient.dll.
Коммуникационный модуль экспортирует одну единственную функцию zmqCommClient.dll –
GetICommModule. Остальное взаимодействие библиотеки с внешним приложением организовано
с использованием интерфейсов, построенных на базе абстрактных классов C++.
Для передачи сообщений между коммуникационным модулем и программой используется
абстрация очереди. Реализация очереди не включена в код коммуникационного модуля ввиду
того, что очередь является внешним, по отношению к модулю, объектом. Поэтому реализации
очередей, т.е. интерфейса IcommQueue, является задачей программистов внешней системы. Для
этого можно воспользоваться образцом реализации, приведенного в подразделе "Пример кода
для реализации интерфейса ICommQueue".
Функция GetICommModule не имеет параметров и возвращает интерфейс ICommModule (в виде
указателя на С++ класс).
© CMA Small Systems AB, 2010
36
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
Интерфейс коммуникационного модуля ICommModule - описание
методов
bool Start(const char *iniFile, const char *commonSectonName);
Производит инициализацию коммуникационного модуля с использованием параметров
определенных в инициализационном файле.
Аргументы:
 const char *iniFile – имя конфигурационного .ini-файла
 const char *commonSectonName - имя секции конфигурационного .ini-файла модуля (не
используется коммуникационным модулем, поставляемым с примером)
Возвращаемое значение: true в случае успешной инициализации.
bool Stop()
Завершает работу коммуникационного модуля.
void* Connect(ICommQueue* input, const char *connSectonName)
Производит открытие соединения с сервисом торговой системы.
Аргументы:
 ICommQueue* input – указатель на очередь сообщений передаваемых клиентским
приложением коммуникационному модулю (исходящих с точки зрения клиентского
приложения).
 const char *connSectonName - имя секции инициализационного файла модуля с
параметрами соединения (не используется коммуникационным модулем, поставляемым с
примером)
Возвращаемое значение: указатель на объект, идентифицирующий успешно установленное
соединение, NULL в случае неуспеха.
void SetQueue(void* connect, ICommQueue* output);
Устанавливает в соответствия успешно открытому соединению очередь передаваемых
клиентскому программному обеспечению сообщений.
Аргументы:
 void* connect – указатель на объект, идентифицирующий успешно установленное
соединение (возвращенное в качестве результата вызово функции Connect)
 ICommQueue* output - указатель на очередь сообщений передаваемых клиентскому
приложению коммуникационным модулем (входящих с точки зрения клиентского приложения)
void Disconnect(void* connect);
Закрывает ранее открытое соединение с сервисом торгового сервера
Аргумент:
 void* connect – указатель на объект, идентифицирующий успешно установленное
соединение (возвращенное в качестве результата вызово функции Connect)
int GetLastError(void* connect, char *descrBuf, int bufLen);
Позволяет получить расширенную информацию об последней ошибке коммуникационного модуля
возникшей при при вызове функций Start и Connect
Аргументы:
 void* connect – указатель на объект, идентифицирующий успешно установленное
соединение (возвращенное в качестве результата вызово функции Connect)
 char *descrBuf – указатель на текстовый буфер для получения описания ошибки
 int bufLen – длина текстового буфера
Возвращаемое значение: расширенная информацию об последней ошибке
© CMA Small Systems AB, 2010
37
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
Интерфейс очередей ICommQueue - описание методов
Для простоты изложения, в настоящем разделе описано применение методов
интерфейса ICommQueue в предположении, что они вызываются внешней системой.
bool Put(void* connect, char* buffer, int32_t length, int32_t error );
Помещает информацию в буфер для передачи ее шлюзу (т.е. в конечном итоге для передачи
торговому серверу).
Аргументы:

void* connect – указатель на объект - идентификатор соединения (возвращаемое
значение после вызова функции ICommModule->Connect). В наших примерах обозначается
как Идентификатор_соединения.

char* buffer – указатель на буфер с данными

int32_t length – длина буфера с данными

int32_t error – признак того, что данные, передаваемые коммуникационному модулю,
представляют собой сообщение об ошибке. Клиентское программное обеспечение должно
передавать в качестве данного параметра только 0.
bool Get(void** connect, char** buffer, int32_t* length, int32_t* error, int64_t timeout)
Получает из буфера сообщений информацию от торговой системы, помещенную туда шлюзом.
При отсутствии сообщений данная функция блокирует выполнение соответствующего потока до
момента появления сообщения в очереди либо до истечения определенного таймаута.
Аргументы:
 void** connect – указатель на указатель куда будет помещен указатель на объект,
идентифицирующий успешно установленное соединение (возвращенное в качестве
результата вызова функции Connect)
 char** buffer – указатель на указатель куда будет помещен указатель на буфер данных
полученных от сервиса торговой системы
 int32_t* length – указатель на целое число куда будет помещено значение длины данных
полученных от сервиса торговой системы
 int32_t* error – указатель на целое число куда будет помещено неравное нулю значение в
случае если данные в буфере являются сообщением об ошибке. В этом случае клиентское
программное должно запротоколировать данное сообщение об ошибке, тем или иным образом
сообщить о ней пользователю и прекратить работу.
 int64_t timeout – таймаут ожидания в миллисекундах. Для бесконечного ожидания следует
использовать отрицательное значение -1.
Возвращаемое значение:
 true - если функция успешно поместила в переданные указатели указатели на сообщение
(информационный блок). Следует отметить что помимо нормального получения данных от
торгового сервиса, это может означать получения сообщения о коммуникационной
ошибке о чем будет сигнализировать ненулевое значение помещенное по адресу,
переданному функции в качестве предыдущего аргумента.
 false - если функции не удалось поместить в переданные указатели указатели на
сообщение (информационный блок). Это может произойти по причине истекшего таймаута
или по причине того, что очередь неработоспособна (остановлена по причине завершения
приложения либо коммуникационного сбоя). Признаком последнего является ненулевое
значение помещенное по адресу, переданному функции в качестве предыдущего
аргумента.
bool Stop();
Останавливает работу очереди. Вызывается в процессе завершения работы приложения
(закрытия соединения).
© CMA Small Systems AB, 2010
38
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
char* Alloc(int32_t length);
Выделяет память для информационного буфера, предназначенного для помещения в очередь
функцией Put
Аргумент:

int32_t length – требуемая длина информационного буфера.
bool Free(char* buffer);
Освобождает память информационного буфера, полученного из очереди функцией Get
int GetLastError(void* connect, char *descrBuf, int bufLen);
Возвращает расширенную информацию об последней ошибке вызова функций модуля
Аргументы:
 void* connect – указатель на объект, идентифицирующий успешно установленное
соединение (возвращенное в качестве результата вызова функции Connect)
 char *descrBuf – указатель на текстовый буфер для получения описания ошибки
 int bufLen – длина текстового буфера
int GetCount();
Возвращает количество сообщений (информационных буферов) в очереди.
© CMA Small Systems AB, 2010
39
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
Сценарий использования коммуникационного модуля и очередей
Коммуникационный модуль (Client Communication Module) и клиентское ПО (внешние
системы) обмениваются данными при помощи пар очередей. Каждый канал данных
обслуживается одной парой очередей.
Во входной очереди передаются данные от Client Communication Module к клиенту, а в
выходной очереди передаются данные от клиента к Client Communication Module.
Программный компонент, передающий данные, должен сначала выделить место для них
в очереди, а компонент, принимающий данные, должен освободить место в очереди,
после того, как он сохранит и/или обработает полученные данные.
В настоящее время предполагается использовать два потока данных:
 данные, получаемые по подписке (Информационный канал)
 транзакционные данные (Транзакционный канал)
ПО-клиент (внешняя система) может работать как с каким-либо одним каналом данных,
так и с двумя каналами (в последнем случае один клиент работает с четырьмя
очередями - двумя входными и двумя выходными).
Схема передачи данных показана ниже:
Основные действия клиента
1. Клиент загружает коммуникационный модуль (Client Communication Module) и
вызывает функцию GET_ICOM_MODULE_FUNCTION_NAME, чтобы получить указатель
на реализацию ICommModule.
2. Клиент вызывает ICommModule->Start(Имя ini-файла, Имя секции ini-файла),
чтобы инициализировать Client Communication Module.
Такой вызов можно выполнить внутри оператора if, чтобы совместить его с
проверкой успешности инициализации, например, так:
if(!pCommModule->Start(Имя ini-файла, Имя секции ini-файла))
{
Действия, выполняемые при неуспешной инициализации
© CMA Small Systems AB, 2010
40
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
}
3. Клиент создает объекты для входной и выходной очередей (обозначаются в
наших примерах как Входная_Очередь и Выходная_Очередь), реализующие
интерфейс ICommQueue.
4. Клиент вызывает ICommModule->Connect(Входная_Очередь), чтобы соединиться с
сервером. В качестве возвращаемого значения функции Connect, Client
Communication Module передает идентификатор соединения (connection_handle)
или, в случае ошибки, значение NULL.
Client Communication Module помещает данные, полученные от сервера во
входную очередь, указывая идентификатор соединения в качестве первого
параметра для ICommQueue->Put().
Для обнаружения ошибок соединения можно использовать оператор if с
условием, полученным как логическое отрицание возвращаемого значения
функции Connect:
connection = pCommModule->Connect(Входная_Очередь);
if(!connection)
{
Действия, выполняемые при неуспешном соединении
}
else
{
...
}
5. Клиент
вызывает
ICommModule->SetQueue(Идентификатор_соединения,
Выходная_Очередь), чтобы сообщить Client Communication Module выходную
очередь, в которую клиент будет выкладывать данные для передачи на сервер.
6. Клиент производит прием данных из входной очереди, обрабатывает их и
помещает свои выходные данные в выходную очередь. После обработки
входных данных клиент должен освобождать место в очереди, чтобы не
допускать утечки памяти.
7. После окончания своей основной работы, получив от сервера подтверждения о
приеме
отправленных
ему
данных,
клиент
вызывает
ICommModule->Disconnect(connection_handle), чтобы разорвать соединение и
отсоединиться от сервера.
После разрыва соединения, идентификатор соединения больше применяться не
должен, поэтому, чтобы повысить надежность работы ПО, значение переменной,
используемой для его хранения можно затереть:
pCommModule->Disconnect(Идентификатор_соединения);
connection = NULL;
8. Клиент вызывает ICommModule->Stop(), чтобы закрыть соединения и завершить
работу Client Communication Module.
9. При возникновении ошибок Client Communication Module записывает во входную
очередь (при помощи Put()) ненулевой признак ошибки, в буфере очереди при
этом передается краткое описание ошибки. В такой ситуации connection_handle
становится некорректным (invalid) и производится разрыв соединения.
10. Подробное описание последней ошибки вызова функций Client Communication
Module доступно через вызов:
ICommModule->GetLastError(Идентификатор_соединения,
Буфер_с_описанием_ошибки, Длина_буфера)
© CMA Small Systems AB, 2010
41
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
Использование ICommQueue
Интерфейс ICommQueue реализует обмен данными при помощи входной и выходной
очередей. В нижеприведенном описании сценария обмена данных ПО-клиент может
быть как отправителем, так и получателем данных.
1. Чтобы поместить данные в очередь, отправитель данных должен выделить
соответствующий
буфер
данных
(память)
при
помощи
вызова
ICommQueue->Alloc().
2. Этот буфер данных передается при помощи вызова ICommQueue->Put(). Он
принадлежит очереди (ICommQueue) и не должен освобождаться отправителем
данных. Поэтому данные появляются во входной очереди после того, как
коммуникационный модуль выполнит сначала вызов ICommQueue->Alloc(), а
затем ICommQueue->Put().
3. Получатель данных получает доступ к данным через вызов ICommQueue->Get().
4. После того, как получатель обработает и/или сохранит полученные данные, он
должен освободить их при помощи вызова ICommQueue->Free().
5. Чтобы узнать количество сообщений, ожидающих получения во входной
очереди, применяется вызов ICommQueue->GetCount().
6. Чтобы сообщить коммуникационному модулю, чтобы он прекратил ожидание
данных от клиента (т.е. завершить коммуникационные потоки), нужно вызвать
ICommQueue->Stop().
Для идентификации потоков передаваемых данных в вызовах в качестве параметра
указывается идентификатор соединения.
Описание поставки
Внешние системы взаимодействуют с ШКС, используя динамическую библиотеку
zmqCommClient.dll (входящую в комплект поставки) и ПО для работы с очередями,
которое должно быть написано разработчиками внешних систем самостоятельно (по
образцу, входящему в комплект поставки).
Примеры ПО для реализации очередей поставляются в виде упакованного архива, в
котором упакованы необходимые файлы, в том числе.proto-файл и сгенерированные из
него файлы для сборки, а также нербходимые для сборки файлы из дистрибутива
protobuf. Благодаря этому, разработчики внешних систем смогут ознакомиться с
работающими примерами кода для реализации взаимодействия со шлюзом, даже не
устанавливая protobuf.
Для сборки потребутеся ПО Visual Studio 2008 SP1 и Windows 2008 R2 или Windows 7,
при этом к характеристикам компьютера серьезных требований не предъявляется.
При распаковке архив раскрывается в директорию Samples, содержащую файл
Samples.sln и три поддиректории:
 Samples\protobuf - директория для средств по преобразованию .proto-файлов
во фрагменты кода на языках высокого уровня, реализующие обмен данными.
 Samples\SampleInfoClient - директория примера работы с информационным
потоком
 Samples\SampleTransClient - директория примера работы с транзакционным
потоком
© CMA Small Systems AB, 2010
42
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
Файл Samples.sln содержит проектное решение (solution), открываемое в Visual Studio.
В
каждой
из
двух
поддиректорий
Samples\SampleInfoClient
Samples\SampleTransClient содержатся следующие файлы и поддиректории:
Имя файла или поддиректории
Описание
FTEMessages.proto
FTEMessages.pb.h
FTEMessages.pb.cc
IOQueueEx.h
zmqCommClientI.ini
ZMQCommClient.lib
QCommModule.h
SampleInfoClient.cpp или
SampleTransClient.cpp
SampleInfoClient.vcproj или
SampleTransClient.vcproj
stdafx.h
stdafx.cpp
targetver.h
Release
© CMA Small Systems AB, 2010
и
.proto-файл, определяет структуру передаваемых
данных. В случае изменения .proto-файла,
описывающего форматы СЭТ СР СПбМТСБ,
разработчики получат обновленный .proto-файл,
который они должны будут преобразовать в код
на С++.. Для генерирования кода не потребуется
создавать
нового
ПО,
т.к.
разработчики
протокола Protobuf предоставляют бесплатное ПО
(включая исходные коды) для выполнения такого
преобразования.
Результат работы кодогенератора Protobuf
Результат работы кодогенератора Protobuf
Исходный код на С++
Конфигурационные настройки
коммуникационного модуля (см. описание после
данной таблицы)
Библиотека коммуникационного модуля
Исходный код на С++
Исходный код примеров на С++.
Файл SampleInfoClient.cpp имеется только в
директории
SampleInfoClient
и
реализует
очереди
для
передачи
информационных
сообщений.
Файл SampleTransClient.cpp имеется только в
директории SampleTransClient и реализует
очереди
для
передачи
транзакционных
сообщений.
Файл проектов для сборки транзакционного и
информационного клиентов
Исходный код на С++
Исходный код на С++ для подключения файла
stdafx.h
Исходный код на С++
Поддиректория для релизной сборки
43
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Release\LibTrace.dll
Release\ZMQCommClient.dll
Release\LibThread.dll
Release\libzmq.dll
Release\SampleInfoClient.exe
Руководство разработчика
Динамическая библиотека трассировки
Основная динамическая библиотека
коммуникационного модуля
Динамическая
библиотека
многопотоковой
обработки
Динамическая библиотека ZeroMQ
Исполняемая программа для передаваемого
примера
Далее приведены примеры и подробные описания некоторых из этих файлов.
Конфигурационные .ini-файлы для настройки коммуникационного модуля
Оба конфигурационных файла (для информационного обмена и для транзакций) имеют
одинаковую структуру и могут быть одинаковыми.
Пример конфигурационного файла:
[zmqclient]
LOG_FILE=zmqclientI.trc
LOG_LEVEL=10
ENDPOINT=tcp://192.168.19.10:35354
HEARTBEAT_INTERVAL=1500
HEARTBEAT_TIMEOUT=3000
Назначение настроек:
Параметр
Описание
Секция [zmqclient] (единственная секция, содержит все настройки)
Указывает трассировочный файл, в котором будут
сохранятся отладочные сообщения и сообщения об
ошибках
LOG_LEVEL
Уровень логирования. При нулевом значении этого
параметра регистрируются только сообщения об ошибках.
Максимальное значение обычно равно 10-12.
ENDPOINT
Характеристики соединения:
 обозначение протокола (tcp)
 ip-адрес компьютера, на котором запущен шлюз
 порт компьютера, на котором запущен шлюз. Для
информационных
сообщений
по
умолчанию
применяется порт 35355, для транзакций порт 35354.
Эти значения разделены символами ":" (двоеточием)
HEARTBEAT_INTERVAL
Интервал времени, через который отсылается пакет, даже
если отсутствует необходимость в передаче данных (это
нужно, чтобы дать серверу знать, что клиент активен.
Задается в миллисекундах.
HEARTBEAT_TIMEOUT
Время, по истечении которого клиент считает соединение
с сервером разорванным, в случае отсутствия активности,
т.е. входящих сообщений от сервера к клиенту. Задается
в миллисекундах.
LOG_FILE
© CMA Small Systems AB, 2010
44
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
Пример кода для реализации интерфейса ICommQueue
#pragma once
#include <list>
#include "QCommModule.h"
struct sQueueData_t
{
sQueueData_t( void*
connect, char* buffer, int32_t length, int32_t error )
: m_Connect( connect )
, m_Buf( buffer )
, m_Length( length )
, m_error(error)
{}
void*
m_Connect;
char*
m_Buf;
int32_t
m_Length;
int32_t
m_error;
};
class IOQueueEx : public ICommQueue
{
public:
IOQueueEx()
: m_non_empty(FALSE, TRUE)
, m_CanWait( true )
{}
~IOQueueEx()
{}
void Reset()
{
CSingleLock l(&m_cs, TRUE);
m_Queue.clear();
m_CanWait = true;
m_non_empty.ResetEvent();
}
bool Put(void* connect, char* buffer, int32_t length, int32_t error )
{
CSingleLock l(&m_cs, TRUE);
m_Queue.push_back( sQueueData_t( connect, buffer, length, error ) );
m_non_empty.SetEvent();
return true;
}
bool Get(void**
connect, char**
buffer, int32_t*
int64_t nMilliSeconds)
{
if(m_non_empty.Lock( (DWORD) nMilliSeconds ))
{
CSingleLock l(&m_cs, TRUE);
if( !m_Queue.size() )
{
*error = 0;
return false;
}
if(!m_CanWait)
{
*error = -1;
return false;
}
length,
int32_t*
error,
sQueueData_tdata = *m_Queue.begin();
m_Queue.erase( m_Queue.begin() );
*connect = data.m_Connect;
*buffer = data.m_Buf;
*length = data.m_Length;
*error = data.m_error;
if( !m_Queue.size() )
m_non_empty.ResetEvent();
return true;
}
*error = 0;
return false;
}
© CMA Small Systems AB, 2010
45
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
bool Stop()
{
CSingleLock l(&m_cs, TRUE);
m_CanWait = false;
m_non_empty.SetEvent();
return true;
}
char* Alloc(int32_t
length)
{
return new char[length];
}
bool Free(char*
buffer)
{
delete [] buffer;
return true;
}
int
GetLastError(void* connect, char*
{
return 0;
}
int
GetCount()
{
CSingleLock l(&m_cs, TRUE);
int i = m_Queue.size();
return i;
}
void SetAlive()
{
}
private:
CCriticalSection
m_cs;
CEventm_non_empty;
boolm_CanWait;
std::list<sQueueData_t>
m_Queue;
};
Руководство разработчика
descrBuf, int bufLen)
Пример кода для работы с информационным каналом
Ниже дан пример кода, реализующего передачу информационных сообщений,
поступающих от торгового сервера через ШКС к внешним системам в соответствии с
настройками подписки:
#include "stdafx.h"
#include "IOQueueEx.h"
CWinApp theApp;
using namespace std;
// декларация единственной экспортируемой функции коммуникационного модуля
// вообще говоря данная декларация должна находится в заголовочном файле модуля
// но ввиду многоплатформенности данного заголовочного файла ее там нет
// для возможности статической линковки коммуникационного модуля ее следует
// объявить нижеследующим образом
extern "C"
{
ICommModule* GetICommModule();
}
// экземпляр очереди для входящих сообщений
// оттуда следует читать сообщения приходящие от
// торгового сервера. Для чтения таких сообщений будет
// создан отдельный поток исполнения
IOQueueEx
queueIn;
// экземпляр очереди для исходящих сообщений
// туда следует помещать сообщения
// для их передачи торговому серверу
IOQueueEx
queueOut;
// хендл соединения с торговым сервисом
void*
connection = NULL;
// указатель на поток читающий очередь входящих сообщений
CWinThread*
thread = NULL;
// флаг сигнализирующий работоспособность соединения
// используется для корректной остановки потока
© CMA Small Systems AB, 2010
46
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
// читающего очередь входящих сообщений при закрытии
// соединения (завершении работы приложения)
bool
bOn = false;
// указатель на конверт сообщения посланный торговому серверу
// как синхронный запрос - запрос требующий ожидания аппликационного
// ответа
FTE::Envelope* pRequestSync = NULL;
// указатель на конверт сообщения аппликационного ответа на синхронный запрос
// в данном приложении используется для передачи ответа на синхронный запрос
// в главный поток приложения (из потока чтения очереди входящих сообщений)
// где производится его аналих
FTE::Envelope* pReplySync = NULL;
// эвент блокирующий работу приложения при посылке синхронного запроса
CEvent
waitReqSync(FALSE, TRUE);
// таймаут ожидания аппликационного ответа на синхронный запрос (в секундах)
int
nAppReplyTimeout = 10;
// асинхронная посылка сообщения (определенного параметром функции)
// торговому сервису
bool Request(FTE::Envelope* pReq)
{
int size = pReq->ByteSize();
if(size)
{
char* buffer = queueOut.Alloc(size);
pReq->SerializeToArray(buffer, size);
if(queueOut.Put(connection, buffer, size, 0))
return true;
queueOut.Free(buffer);
}
return false;
}
// синхронная посылка сообщения (определенного параметром функции)
// торговому сервису
bool RequestSync(FTE::Envelope* pReq)
{
bool bRes = false;
pRequestSync = pReq;
waitReqSync.ResetEvent();
if(Request(pReq))
{
bRes = ( (waitReqSync.Lock( nAppReplyTimeout != -1 ? nAppReplyTimeout * 1000 :
nAppReplyTimeout )) ? true : false);
}
pRequestSync = NULL;
return bRes;
}
// функция потока читающего очередь входящих сообщений
UINT AFX_CDECL ListeningThreadFunc(LPVOID p)
{
while(true)
{
void* connect = NULL;
char* buffer = NULL;
int32_t length = 0;
int32_t error = 0;
if(queueIn.Get(&connect, &buffer, &length, &error, -1))
{
if(error)
{
// получено сообщение об ошибке
// приложение должно запротоколировать данное сообщение
// и завершить работу (не реализовано в рамках данного примера)
cout << "Some error arrived" << buffer << endl;
queueIn.Free(buffer);
}
else
{
// получено сообщение от торгового сервиса - парсим его
FTE::Envelope* reply = new FTE::Envelope;
reply->ParseFromArray( buffer, length );
FTE::Envelope* pReq = NULL;
© CMA Small Systems AB, 2010
47
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
// в поле reqid мы могли передавать ссылку на синхронный запрос
// к торговому сервису. В этом случае сервис был обязан вернуть
// данную ссылку в поле reqid ответа
// проверяем наличие данного поля и его запролненность
if(!reply->has_reqid() || reply->reqid() == 0)
{}
else
pReq = (FTE::Envelope*) reply->reqid();
// проверяем является ли полученное сообщение ответом на синхронный запрос
// который мы с настоящее время ожидаем
if(pRequestSync != NULL && pReq == pRequestSync)
{
// полученное сообщение является ответом
// на посланный ранее синхронный запрос
// присваиваем ссылку на конверт ответа глобальной переменной pReplySync
// для последующего анализа в главном потоке приложения и
// выставляем эвент сигнализирующий о полученном ответе
// на синхронный запрос
pReplySync = reply;
waitReqSync.SetEvent();
}
else
{
// в рамках данного примера в качестве асинхронных ответов
// мы обрабатываем только сообщения типа FTE::OK_CHANGES
// (данные по открытым подпискам на информационные таблицы)
if( reply->type().size() == 0 || reply->type().Get(0) != FTE::OK_CHANGES )
{
// неизвестный тип сообщения - игнорируем его
}
else
{
FTE::Changes* change = new FTE::Changes;
if(reply->data().size() == 0)
{
// пустое сообщение - игнорируем его
// (вообще говоря такого быть не должно
// при попадании сюда управления возможна ошибка в сервере)
}
else
{
// парсим ответ
change->ParseFromString( reply->data().Get(0) );
for( int i = 0; i < change->row_size(); i++ )
{
FTE::RowChange* rc = new FTE::RowChange;
rc->ParseFromString( change->row( i ) );
// в рамках данного примера мы ожидает получения данных
// только по таблице Securities
// ответы по другим типам таблиц обрабатываются совершенно аналогично
if(rc->tabid() == FTE::SECURITIES)
{
FTE::InfoSecurity *pSec = new FTE::InfoSecurity;
pSec->ParseFromString( rc->rowdata() );
cout << "Got security information: " << pSec->code() << endl;
delete pSec;
}
delete rc;
}
delete change;
}
}
delete reply;
}
queueIn.Free(buffer);
}
}
// при сброшенном флаге завершаем управляющую функцию потока
if(!bOn)
break;
}
return 0;
© CMA Small Systems AB, 2010
48
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
}
void Test()
{
cout << "Sample information client" << endl;
string userId;
string password;
// = "MKL000010001";
// = "1";
// запрашиваем идентификатор пользователя и пароль
cout << "Please enter your user id: ";
cin >> userId;
cout << "Please enter your password: ";
cin >> password;
// инициализируем коммуникационный модуль
cout << "Initializing communication module...";
ICommModule* pCommModule = GetICommModule();
if(!pCommModule->Start("zmqCommClientI.ini"))
{
cout << "Communication module initialization failed" << endl;
return;
}
cout << "OK" << endl;
cout << "Connecting to trading service...";
// на всякий случай чистим очереди
// в данном примере они и так чистые, но в реальной приложении при повторном
// соединении с сервером следует не забывать об данной чистке
queueIn.Reset();
queueOut.Reset();
// устанавливаем соединение
connection = pCommModule->Connect(&queueIn);
if(!connection)
{
cout << "Failed" << endl;
return;
}
else
{
// устанавливаем очередь исходящих сообщений
pCommModule->SetQueue( connection, &queueOut );
// создаем поток для чтения очереди входящих сообщений
// для возможности дополнительной инициализации данных влияющих
// потока на работу потока создаем его в остановленном виде
thread = AfxBeginThread(ListeningThreadFunc, 0, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
thread->m_bAutoDelete = FALSE;
// флаг работоспособности соединения устанавливаем в true
bOn = true;
// пускаем поток
thread->ResumeThread();
}
cout << "OK" << endl;
// посылаем синхронное сообщение Logon
cout << "Sending logon...";
int
size;
char*
tmpBuf;
// создаем "protobuf" сообщение Logon
FTE::Logon*
logon = new FTE::Logon;
// заполняем его данными
logon->set_uid( userId );
logon->set_password( password );
size = logon->ByteSize();
tmpBuf = new char[size];
logon->SerializeToArray( tmpBuf, size );
delete logon;
// создаем "protobuf" сообщение Envelope // данное сообщение является обрамляющим для всех прочих сообщений
FTE::Envelope*
env = new FTE::Envelope;
© CMA Small Systems AB, 2010
49
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
env->set_ver( 1 );
// ВАЖНО
// заполняем поле reqid ссылкой на конверт нашего сообщения
// торговый сервис должен прислать данную ссылку в рамках ответа
env->set_reqid( (google::protobuf::uint64) env );
env->add_type(FTE::REQ_LOGON );
env->set_uid( userId );
env->add_data(tmpBuf, size );
delete [] tmpBuf;
// посылаем синхронный ответ
if(!RequestSync(env))
{
cout << "Failed" << endl;
return;
}
delete env;
// анализируем ответ
if(pReplySync && pReplySync->type().size() && pReplySync->type().Get(0) == FTE::REP_OK)
{
cout << "OK" << endl;
delete pReplySync;
pReplySync = NULL;
}
else
{
cout << "Failed - reply is bad" << endl;
return;
}
// подписываемся на таблицу Securities
// подписка на остальные типы таблиц производится совершенно аналогично
cout << "Subscribing to securities...";
FTE::Subscribe*
subscr = new FTE::Subscribe;
subscr->set_tab_id( FTE::SECURITIES );
subscr->set_max_row_id( -1 );
subscr->set_last_change_id( 0 );
size = subscr->ByteSize();
tmpBuf = new char[size];
subscr->SerializeToArray( tmpBuf, size );
delete subscr;
FTE::Envelope*
env1 = new FTE::Envelope;
env1->set_ver( 1 );
env1->set_reqid( 1 );
env1->add_type(FTE::REQ_SUBSCRIBE );
env1->set_uid( userId );
env1->add_data(tmpBuf, size );
delete [] tmpBuf;
// посылает запрос на подписку асинхронным образом
if(!Request(env1))
{
cout << "Failed" << endl;
return;
}
delete env1;
cout << "OK" << endl;
// ждем некоторое время пока прибудут данные по нашей подписке
// данный буду обработаны функцией потока чтения входящих сообщений
// и полученная информация выведена на консоль
::Sleep(10000);
// посылаем асинхронное сообщение Logoff
cout << "Sending logoff...";
FTE::Envelope*
env2 = new FTE::Envelope;
env2->set_ver( 1 );
env2->set_reqid( (google::protobuf::uint64) env2 );
env2->add_type(FTE::REQ_LOGOFF );
env2->set_uid( userId );
if(!Request(env2))
{
cout << "Failed" << endl;
© CMA Small Systems AB, 2010
50
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
return;
}
cout << "OK" << endl;
// закрываем соединение
cout << "Closing connection...";
// сбрасываем флаг для корректного завершения потока чтения
// очереди входящих сообщений
bOn = false;
// останавливаем очерель входящих сообщений
// функция Get очереди вернет false и признак ошибки
queueIn.Stop();
// ожидаем завершения потока чтения очереди входящих сообщений
::WaitForSingleObject(thread->m_hThread, INFINITE);
// очищаем данный потока
thread->Delete();
thread = NULL;
// разрываем соединение
pCommModule->Disconnect(connection);
connection = NULL;
cout << "OK" << endl;
}
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
// initialize MFC and print and error on failure
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: MFC initialization failed\n"));
nRetCode = 1;
}
else
{
// TODO: code your application's behavior here.
Test();
}
return nRetCode;
}
© CMA Small Systems AB, 2010
51
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
Пример кода для работы с транзакционным каналом
Ниже дан пример кода, реализующего передачу транзакционных сообщений:
#include "stdafx.h"
#include "IOQueueEx.h"
CWinApp theApp;
using namespace std;
// декларация единственной экспортируемой функции коммуникационного модуля
// вообще говоря данная декларация должна находится в заголовочном файле модуля
// но ввиду многоплатформенности данного заголовочного файла ее там нет
// для возможности статической линковки коммуникационного модуля ее следует
// объявить нежеследующем образом
extern "C"
{
ICommModule* GetICommModule();
}
// экземпляр очереди для входящих сообщений
// оттуда следует читать сообщения приходящие от
// торгового сервера. Для чтения таких сообщений будет
// создан отдельный поток исполнения
IOQueueEx
queueIn;
// экземпляр очереди для исходящих сообщений
// туда следует засовывать сообщения
// для их передачи торговому серверу
IOQueueEx
queueOut;
// хендл соединения с торговым сервисом
void*
connection = NULL;
// указатель на поток, читающий очередь входящих сообщений
CWinThread*
thread = NULL;
// флаг сигнализирующий работоспособность соединения
// используется для корректной остановки потока
// читающего очередь входящих сообщений при закрытии
// соединения (завершении работы приложения)
bool
bOn = false;
// указатель на конверт сообщения посланный торговому серверу
// как синхронный запрос - запрос требующий ожидания аппликационного
// ответа
FTE::Envelope* pRequestSync = NULL;
// указатель на конверт сообщения аппликационного ответа на синхронный запрос
// в данном приложении используется для передачи ответа на синхронный запрос
// в главный поток приложения (из потока чтения очереди входящих сообщений)
// где производится его аналих
FTE::Envelope* pReplySync = NULL;
// эвент блокирующий работу приложения при посылке синхронного запроса
CEvent
waitReqSync(FALSE, TRUE);
// таймаут ожидания аппликационного ответа на синхронный запрос (в секундах)
int
nAppReplyTimeout = 10;
// асинхронная посылка сообщения (определенного параметром функции)
// торговому сервису
bool Request(FTE::Envelope* pReq)
{
int size = pReq->ByteSize();
if(size)
{
char* buffer = queueOut.Alloc(size);
pReq->SerializeToArray(buffer, size);
if(queueOut.Put(connection, buffer, size, 0))
return true;
queueOut.Free(buffer);
}
return false;
}
© CMA Small Systems AB, 2010
52
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
// синхронная посылка сообщения (определенного параметром функции)
// торговому сервису
bool RequestSync(FTE::Envelope* pReq)
{
bool bRes = false;
pRequestSync = pReq;
waitReqSync.ResetEvent();
if(Request(pReq))
{
bRes = ( (waitReqSync.Lock( nAppReplyTimeout != -1 ? nAppReplyTimeout * 1000 :
nAppReplyTimeout )) ? true : false);
}
pRequestSync = NULL;
return bRes;
}
// функция потока читающего очередь входящих сообщений
UINT AFX_CDECL ListeningThreadFunc(LPVOID p)
{
while(true)
{
void* connect = NULL;
char* buffer = NULL;
int32_t length = 0;
int32_t error = 0;
if(queueIn.Get(&connect, &buffer, &length, &error, -1))
{
if(error)
{
// получено сообщение об ошибке
// приложение должно запротоколировать данное сообщение
// и завершить работу (не реализовано в рамках данного примера)
cout << "Some error arrived" << buffer << endl;
queueIn.Free(buffer);
}
else
{
// получено сообщение от торгового сервиса - парсим его
FTE::Envelope* reply = new FTE::Envelope;
reply->ParseFromArray( buffer, length );
FTE::Envelope* pReq = NULL;
// в поле reqid мы могли передавать ссылку на синхронный запрос
// к торговому сервису. В этом случае сервис был обязан вернуть
// данную ссылку в поле reqid ответа
// проверяем наличие данного поля и его запролненность
if(!reply->has_reqid() || reply->reqid() == 0)
{}
else
pReq = (FTE::Envelope*) reply->reqid();
// проверяем является ли полученное сообщение ответом на синхронный запрос
// который мы в настоящее время ожидаем
if(pRequestSync != NULL && pReq == pRequestSync)
{
// полученное сообщение является ответом
// на посланный ранее синхронный запрос
// присваиваем ссылку на конверт ответа глобальной переменной pReplySync
// для последующего анализа в главном потоке приложения и
// выставляем эвент сигнализирующий о полученном ответе
// на синхронный запрос
pReplySync = reply;
waitReqSync.SetEvent();
}
else
{
// в рамках данного примера в качестве асинхронных ответов
// мы обрабатываем только сообщения типа FTE::OK_CHANGES
// (данные по открытым подпискам на информационные таблицы)
if( reply->type().size() == 0 || reply->type().Get(0) != FTE::OK_CHANGES )
{
// неизвестный тип сообщения - игнорируем его
}
else
{
FTE::Changes* change = new FTE::Changes;
if(reply->data().size() == 0)
© CMA Small Systems AB, 2010
53
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
{
// пустое сообщение - игнорируем его
// (вообще говоря такого быть не должно
// при попадании сюда управления возможна ошибка в сервере)
}
else
{
// парсим ответ
change->ParseFromString( reply->data().Get(0) );
for( int i = 0; i < change->row_size(); i++ )
{
FTE::RowChange* rc = new FTE::RowChange;
rc->ParseFromString( change->row( i ) );
// в рамках данного примера мы ожидает получения данных
// только по таблице Securities
// ответы по другим типам таблиц обрабатыватся совершенно аналогично
if(rc->tabid() == FTE::SECURITIES)
{
FTE::InfoSecurity *pSec = new FTE::InfoSecurity;
pSec->ParseFromString( rc->rowdata() );
cout << "Got security information: " << pSec->code() << endl;
delete pSec;
}
delete rc;
}
delete change;
}
}
delete reply;
}
queueIn.Free(buffer);
}
}
// при сброшенном флаге завершаем управляющую функцию потока
if(!bOn)
break;
}
return 0;
}
void Test()
{
cout << "Sample transaction client" << endl;
string userId;
string password;
// = "MKL000010001";
// = "1";
// запрашиваем идентификатор пользователя и пароль
cout << "Please enter your user id: ";
cin >> userId;
cout << "Please enter your password: ";
cin >> password;
// инициализируем коммуникационный модуль
cout << "Initializing communication module...";
ICommModule* pCommModule = GetICommModule();
if(!pCommModule->Start("zmqCommClientI.ini"))
{
cout << "Communication module initialization failed" << endl;
return;
}
cout << "OK" << endl;
cout << "Connecting to trading service...";
// на всякий случай чистим очереди
// в данном примере они и так чистые, но в реальной приложении при повторном
// соединении с сервером следует не забывать об данной чистке
queueIn.Reset();
queueOut.Reset();
// устанавливаем соединение
connection = pCommModule->Connect(&queueIn);
if(!connection)
{
© CMA Small Systems AB, 2010
54
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
cout << "Failed" << endl;
return;
}
else
{
// устанавливаем очередь исходящих сообщений
pCommModule->SetQueue( connection, &queueOut );
// создаем поток для чтения очереди входящих сообщений
// для возможности дополнительной инициализации данных влияющих
// потока на работу потока создаем его в остановленном виде
thread = AfxBeginThread(ListeningThreadFunc, 0, THREAD_PRIORITY_NORMAL, 0, CREATE_SUSPENDED);
thread->m_bAutoDelete = FALSE;
// флаг работоспособности соединения в true
bOn = true;
// пускаем поток
thread->ResumeThread();
}
cout << "OK" << endl;
// посылаем синхронное сообщение Logon
cout << "Sending logon...";
int
size;
char*
tmpBuf;
// создаем "protobuf" сообщение Logon
FTE::Logon*
logon = new FTE::Logon;
// заполняем его данными
logon->set_uid( userId );
logon->set_password( password );
size = logon->ByteSize();
tmpBuf = new char[size];
logon->SerializeToArray( tmpBuf, size );
delete logon;
// создаем "protobuf" сообщение Envelope // данное сообщение является обрамляющим для всех прочих сообщений
FTE::Envelope*
env = new FTE::Envelope;
env->set_ver( 1 );
// ВАЖНО
// заполняем поле reqid ссылкой на конверт нашего сообщения
// торговый сервис должен прислать данную ссылку в рамках ответа
env->set_reqid( (google::protobuf::uint64) env );
env->add_type(FTE::REQ_LOGON );
env->set_uid( userId );
env->add_data(tmpBuf, size );
delete [] tmpBuf;
// посылаем синхронный ответ
if(!RequestSync(env))
{
cout << "Failed" << endl;
return;
}
delete env;
// анализируем аппликационный ответ
if(pReplySync && pReplySync->type().size() && pReplySync->type().Get(0) == FTE::REP_OK)
{
cout << "OK" << endl;
delete pReplySync;
pReplySync = NULL;
}
else
{
cout << "Failed - reply is bad" << endl;
return;
}
// посылаем синхронное сообщение выставления заявки по инструменту
//
cout << "Sending order...";
FTE::Order*
© CMA Small Systems AB, 2010
order = new FTE::Order;
55
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
// тип заявки - лимитированная
order->set_type( FTE::LIMIT );
// поместить заявку в очередь в случае невозможности ее немедленного исполнения
order->set_params( FTE::PIQ );
// параметры инструмента
// ВАЖНО! для успешного прогона теста нижеуказанный режим торгов для нижеуказанного
// инструмента должен быть открыт
order->set_board( "BRD_NORMAL" );
order->set_security( "FDDTS2AVI60" );
// торговый счет
order->set_account( "HMPC011000001001" );
// мы хотим купить
order->set_buy_sell( FTE::BUY );
// фирма, клиент, контрагент ...
order->set_firm( "ICP000010000" );
order->set_client( "GCP000110000" );
// определяем цену
// цена определяется в виде целого числа с предопределенный количеством
// условных десятичных знаком - 2 в нашем случае:
// цена ниже определяется как 10.00 единиц
DECIMAL d;
d.Lo64 = 1000;
order->set_price( d.Lo64 );
// определяем количество инструментов
order->set_qty( 5 );
size = order->ByteSize();
tmpBuf = new char[size];
order->SerializeToArray( tmpBuf, size );
delete order;
// создаем "protobuf" сообщение Envelope // данное сообщение является обрамляющим для всех прочих сообщений
env = new FTE::Envelope;
env->set_ver( 1 );
// ВАЖНО
// заполняем поле reqid ссылкой на конверт нашего сообщения
// торговый сервис должен прислать данную ссылку в рамках ответа
env->set_reqid( (google::protobuf::uint64) env );
env->add_type(FTE::REQ_ORDER );
env->set_uid( userId );
env->add_data(tmpBuf, size );
delete [] tmpBuf;
// посылаем синхронный ответ
if(!RequestSync(env))
{
cout << "Failed" << endl;
return;
}
delete env;
// анализируем ответ
if(pReplySync && pReplySync->type().size() && pReplySync->type().Get(0) == FTE::REP_OK)
{
cout << "OK" << endl;
delete pReplySync;
pReplySync = NULL;
}
else
{
cout << "Failed - reply is bad" << endl;
return;
}
// посылаем асинхронное сообщение Logoff
cout << "Sending logoff...";
FTE::Envelope*
env2 = new FTE::Envelope;
env2->set_ver( 1 );
© CMA Small Systems AB, 2010
56
Шлюз коммуникационной системы СЭТ СР СПбМТСБ
Руководство разработчика
env2->set_reqid( (google::protobuf::uint64) env2 );
env2->add_type(FTE::REQ_LOGOFF );
env2->set_uid( userId );
if(!Request(env2))
{
cout << "Failed" << endl;
return;
}
cout << "OK" << endl;
// закрываем соединение
cout << "Closing connection...";
// сбрасываем флаг для корректного завершения потока чтения
// очереди входящих сообщений
bOn = false;
// останавливаем очередь входящих сообщений
// функция Get очереди вернет false и признак ошибки
queueIn.Stop();
// ожидаем завершения потока чтения
// очереди входящих сообщений
::WaitForSingleObject(thread->m_hThread, INFINITE);
// очищаем данные потока
thread->Delete();
thread = NULL;
// разрываем соединение
pCommModule->Disconnect(connection);
connection = NULL;
cout << "OK" << endl;
}
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;
// initialize MFC and print and error on failure
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
_tprintf(_T("Fatal Error: MFC initialization failed\n"));
nRetCode = 1;
}
else
{
// TODO: code your application's behavior here.
Test();
}
return nRetCode;
}
© CMA Small Systems AB, 2010
57
Похожие документы
Скачать