Список задач
Atom
29.12.2010
Mikhail Sukhov


И так, предлагаю подытожить то, что нужно сделать и в каком порядке.

Задачи сгруппировал по группам (копировал из соседней ветки http://stocksharp.com/forum/1275/&p=2). Первая группа - самая приоритетная. Без нее делать задачи из следующей бессмысленно. Сами задачи внутри этой группы так же выстроены по очередности.

Базовая группа:

  1. Описать основные метаданные, как это сделано для Квика (DdeSecurityColumns, DdeTradeColumns и т.д.). Я это уже показал на примере класса PlazaFutureColumns, но там колонки не реальные. Предлагаю прямо разобрать по названию таблиц потоков, кто за какие будет отвечать (описывать в коде). Таблицы только основные: инструменты, заявки, сделки и т.д.
  2. Подписываться на произвольные потоки + отписываться.
  3. Получать стаканы. Производная от предыдущей задача. Выделил ее отдельно.
  4. Заявки (регистрация, снятие и перемещение). Я уже сделал через класс Message заполнение полей для отправки транзакций. Это дело надо доделать.
  5. Парсинг ответа от транзакций (внимание! всех транзакций, а не только, что в предыдущем пункте). Я не знаю, в каком виде они приходят, но могу сказать, какой результат должен быть. Это должно быть PlazaException с кодом ошибки (чтобы не мучится сравнение строчек в коде). И код не ввиде числа (что не так уж лучше строчки), а нормального перечисления (enum).


Первую задачу предлагаю сделать сообща. Остальные - разбираем по тем признакам, кто какие таблицы описывал (например, кто описал стакан, тот занимается задачей 3, кто инструменты - задачей 2, кто заявки - задачей 4).

Второстепенная группа:

  1. Дописать все остальные метаданные (позиции, счета, волатильность, маржа, клиринг, доп информация о деривативах, индексы).
  2. Фильтрация потоков. Так как Плаза не дает фильтр (камрад skuvv написал об этом), но в клиентском коде прописывать фильтры дело не благодарное, предлагаю это симулировать через RegisterXXX + UnRegisterXXX.
  3. Возможность задавать глубину стакана (как я понял, это влияет на то, к какому потоку необходимо цепляться).
  4. Поддержка агрегированного стакана и обычного. Для этого можно использовать GroupedQuote (внутри себя он будет содержать не агрегированные котировки).


Третьестепенная группа:

  1. С помощью метаданных научиться строить конфиги ini. Как вариант, через PlazaTable (куда собственно и будут добавляться колонки из пункта 1 пред группы). Сейчас ini файлы программно редактировать нельзя. И если роботу нужны спец колонки нужно менять формат ini схем. Я предлагаю до загрузки этих схем давать возможность менять из программно (парсить и менять ini файлы на лету). + как фича автоматически сканировать директорию при старте и создавать с правильным набором колонок сами PlazaTable. Возможно, здесь поможет TableSet.
  2. Время биржи.
  3. Все остальные транзакции (FutChangeClientMoney, OptChangeExpiration и т.д.).
  4. Составные инструменты.
  5. На форуме доступна x64 версия. Нужна прозрачная поддержка (без перекомпиляции) x86 и x64.
  6. Обертка над роутером (чтобы так же, не ручками править конфиги, а программно).
  7. Документация (как xml, так и обычная). Если нужно сделать как у S#, то необходимо использовать Sandcastle.


Особенности в работе.

Старайтесь писать так, как это принято в .NET и в частности C# коде.
Публичные методы классы и т.д. описывайте xml комментариями (лучше не сочинять, а копировать из документации Плазы, чтобы быть не с планеты Юпитер, а ближе к тем, кто будет это использовать и вторым глазом подглядывать в документацию).
Предлагаю использовать R# как средство для контроля качества кода.
Пишите юнит тесты (заведите отдельный проект в sln).

Теги:


Спасибо:


<< < 5 6 7 8  >
Mikhail Sukhov

Фотография
Дата: 30.01.2011
Ответить


Увидел такую подписку:
Код
plazaStream.DataBegin += (p) => OnPlazaStreamDataBegin(key, p);


Она плоха тем, что при таком подписывании нельзя будет отписаться от события и объект будет продолжать висеть в памяти (не так страшно при существующих гигабайтах, но все же). Лямбда выражения создают "на лету" метод обработчик, от которого потом не отписаться. Чтобы производить правильное освобождение ресурсов, нужно от них отказать вообще и писать по старинке:

Код
plazaStream.DataBegin += OnPlazaStreamDataBegin;


Я думаю, лучше сразу проговорить для чего вообще нужны лямбда. Они появились тогда, когда в .NET начал входить функциональный стиль. Для этого и только для этого их и придумали (явный пример - это LINQ). Я в своих примерах использовал лямбду не потому что так правильно. А потому что мне было лень писать правильно, и быстрее + короче написать как это сделали Вы. Но внутри S# я так конечно же не делаю, к чему призываю делать и в ПлазаТрейдере.[laugh]
Спасибо:

Mikhail Sukhov

Фотография
Дата: 30.01.2011
Ответить


skuvv
Добавил класс с кодами ошибок плазы - PlazaErrors
парсит код ошибки и возвращает текст
ps ктото начал заниматься ошибками - пользуйтесь


Я этим занимаюсь[blush]. Но пока нет времени доделать, так что большое спасибо, что помогли. Но раз уж сделали, вот и Вам code review:

1. public class Errors. Его не нужно сделать статическим? Нужен ли он для public?
2. Error_Code. Лучше параметры называть в C# стиле.
3. Dictionary<int, List<string>> List. Конечно же, это никакой не Лист. Но и Дикшинари тоже будет неправильно назвать. У этого поля должно быть осмысленное имя.
4. List.ElementAt(i) - лучше использовать List[i]. Так быстрее, особенно если это Dictionary.
5. BitConverter.GetBytes(Error_Code)[i] Можно написать проще - Error_Code.To<byte[]>()[i].
Спасибо:

aspirant

Фотография
Дата: 30.01.2011
Ответить


Mikhail Sukhov


1. Плохой код.

Код
try
{
    _dataStream.Close();
}
catch (System.Runtime.InteropServices.COMException e)    
{
    // Исправить обработку исключения
    System.Diagnostics.Trace.WriteLine("Exception {0:X}: {1}".Put(e.ErrorCode, e.Message));
}


Исключения нужно перехватывать как можно выше. Кто будет вызывать Close, тот пусть и этим занимается. А так ошибка просто проглотиться.


Я пока сделал такую заплату, чтобы можно было тестировать код (поэтому и оставил для себя комментарий). Вообще мне кажется, COMException нужно везде перехватывать и выдавать свои исключения, чтобы внешнему коду не видеть внутреннюю кухню. Если внешний код имеет дело с PlazaStream, то он и должен оперировать понятиями (читай методами, статусами и т.д.) PlazaStream.

Mikhail Sukhov

3.
Код
_dataStream.TableSet.set_rev(plazaTable.Name, _currentRevision++);
Это меняется на более элегантное, как подсказал R#:
Код
_dataStream.TableSet.rev[plazaTable.Name] = _currentRevision++;


исправлю.

Mikhail Sukhov

4. ReplicationStream и ReplicationScheme явно как то не так используется. Это же уровень метаданных, а именно таблица PlazaTable (таблица олицетворяет стрим данных, PlazaStream по этом олицетворению производит подключение). А получилось так, что эти два перечисления размазались по всем практически классам в Плазе. Нехорошо. Конструктора PlazaStream(PlazaTable plazaTable, TRequestType requestType) более чем достаточно. Зачем нужен еще один я не понял.

5. public void AddStream(string key, PlazaColumns schema, IEnumerable<PlazaColumn> columns) Выглядит как то не так. Зачем столько аргументов? Можно же ведь передать один PlazaTable и уже по нему создать стрим, и уже оперировать им в дальнейшем.


Иерархия данных в потоках репликации: ReplicationStream -> ReplicationScheme -> Table -> Field, т,е. у каждой плазовской таблицы (в PlazaTrader это PlazaColumns) есть только одно значение ReplicationStream и ReplicationScheme, поэтому я и счел нужным добавить эти поля в PlazaColumns, чтобы при создании PlazaStream значения ReplicationStream и ReplicationScheme можно было вычислить из PlazaColumns.

Есть два варианта получения данных репликации. Во-первых, можно передать Плазе полный или урезанный набор полей какой-то таблицы (создавать "свои" таблицы с полями из нескольких таблиц нельзя). Второй вариант запроса данных - без указания схемы (см. P2ClientGate.doc стр. 18: "Клиент также может не указывать никакой схемы при открытии потока, в этом случае сервер будет отдавать все данные, которые публикуются в потоке (далее этот режим будет называться «получение данных по схеме сервера»)". Поскольку такой вариант подключения существует, я предусмотрел второй конструктор PlazaStream, в котором только передается ReplicationStream. При таком подключении при получении данных через события нужно будет проверять название таблицы, именно поэтому у CP2DataStreamClass второй параметр событий StreamDataInserted, StreamDataUpdated и StreamDataDeleted - это string tableName.

AddStream(string key, PlazaColumns schema, IEnumerable<PlazaColumn> columns) я исправлю на AddStream(string key, PlazaTable plazaTable)
Спасибо:

aspirant

Фотография
Дата: 30.01.2011
Ответить


Mikhail Sukhov
Увидел такую подписку:
Код
plazaStream.DataBegin += (p) => OnPlazaStreamDataBegin(key, p);


Она плоха тем, что при таком подписывании нельзя будет отписаться от события и объект будет продолжать висеть в памяти (не так страшно при существующих гигабайтах, но все же). Лямбда выражения создают "на лету" метод обработчик, от которого потом не отписаться. Чтобы производить правильное освобождение ресурсов, нужно от них отказать вообще и писать по старинке:

Код
plazaStream.DataBegin += OnPlazaStreamDataBegin;


Я думаю, лучше сразу проговорить для чего вообще нужны лямбда. Они появились тогда, когда в .NET начал входить функциональный стиль. Для этого и только для этого их и придумали (явный пример - это LINQ). Я в своих примерах использовал лямбду не потому что так правильно. А потому что мне было лень писать правильно, и быстрее + короче написать как это сделали Вы. Но внутри S# я так конечно же не делаю, к чему призываю делать и в ПлазаТрейдере.[laugh]


Это пока временный вариант, потому что я пока еще не определился с окончательным набором параметров событий. По ходу написания добавил string key, а поскольку хотелось залить первый черновой вариант, оставил как есть.

Свои делегаты я убрал вообще. Вы правы, они лишние. Все вызовы событий передал через SafeInvoke.
Спасибо:

skuvv

Фотография
Дата: 31.01.2011
Ответить


Mikhail Sukhov
skuvv
Добавил класс с кодами ошибок плазы - PlazaErrors
парсит код ошибки и возвращает текст
ps ктото начал заниматься ошибками - пользуйтесь


Я этим занимаюсь[blush]. Но пока нет времени доделать, так что большое спасибо, что помогли. Но раз уж сделали, вот и Вам code review:

1. public class Errors. Его не нужно сделать статическим? Нужен ли он для public?
2. Error_Code. Лучше параметры называть в C# стиле.
3. Dictionary<int, List<string>> List. Конечно же, это никакой не Лист. Но и Дикшинари тоже будет неправильно назвать. У этого поля должно быть осмысленное имя.
4. List.ElementAt(i) - лучше использовать List[i]. Так быстрее, особенно если это Dictionary.
5. BitConverter.GetBytes(Error_Code)[i] Можно написать проще - Error_Code.To<byte[]>()[i].

Просто готовый был класс [smile]
насчет 4. в Dictionary таким способом (List[i]) доступ к ключу не получить вроде
Спасибо:

aspirant

Фотография
Дата: 31.01.2011
Ответить


Михаил,

Вопрос и комментарий.

Вопрос: еще раз хотел вернуться, потому что не совсем для себя уяснил. Как вам видится (изначально виделась) работа клиентского кода с PlazaTrader в применении к плазовским стримам (потоками репликации). При запуске PlazaTrader из клиентского кода, PlazaTrader подключается
  1. к стримам, чьи схемы расписаны в ini-файлах специальной папке?
  2. и/или клиентский код создает схемы программным путем на лету?

Во втором случае это будет происходить через создание экземпляра PlazaTable и передачу его в PlazaTrader или мы оставим PlazaStreamManager public? Сейчас он сделан public только в целях тестирования (чтобы можно было вызывать напрямую из тестового проекта).


Комментарий: наверное, перечисление PlazaTableTypes будет лишним. Как я понимаю, оно сделано для проверки совместимости PlazaTable и PlazaColumn (см. внизу)

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

plazaTrader.SecuritiesTable.Columns.Add(PlazaColumns.OrdersColumns.Direction)

и выбрасывать исключения при запуске программы.


Но тогда подразумевается, что в PlazaTable можно передать колонки из разных наследников PlazaColumns, но с одинаковым PlazaTableTypes. А это не пройдет. Еще раз повторюсь: "синтетические" схемы из колонок разных плазовских схем (PlazaColumns) создавать нельзя. Корректным при наполненни PlazaTable набором PlazaColumn'ов будет проверять каждую PlazaColumn на одинаковость с PlazaTable по ReplicationStream, ReplicationScheme и Table(Name).

Что вы на этот счет думаете?
Спасибо:

Mikhail Sukhov

Фотография
Дата: 31.01.2011
Ответить


aspirant

Вопрос: еще раз хотел вернуться, потому что не совсем для себя уяснил. Как вам видится (изначально виделась) работа клиентского кода с PlazaTrader в применении к плазовским стримам (потоками репликации). При запуске PlazaTrader из клиентского кода, PlazaTrader подключается
  1. к стримам, чьи схемы расписаны в ini-файлах специальной папке?
  2. и/или клиентский код создает схемы программным путем на лету?

Во втором случае это будет происходить через создание экземпляра PlazaTable и передачу его в PlazaTrader или мы оставим PlazaStreamManager public? Сейчас он сделан public только в целях тестирования (чтобы можно было вызывать напрямую из тестового проекта).


И то и другое. При старте настройки PlazaTable берутся из уже созданных ini файлов. Если их нет, то создается минимально допустимый набор метаданных (как это было сделано с Quik таблицами) и по свеже созданным таблицам создаются соответствующие ini файлы. Если клиентский код модифицирует PlazaTable, его действия так же применяются и к ini файлам.

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

aspirant

Но тогда подразумевается, что в PlazaTable можно передать колонки из разных наследников PlazaColumns, но с одинаковым PlazaTableTypes.


Я думаю, неправильно было изначально делать разные PlazaColumns с одинаковыми PlazaTableTypes. Я же не знал, что для одной сущности в Плазе триллион таблиц соответствует. Потому и написал изначально, Position Portfolio и т.д. Так что да, или его переделывать, или его выкидывать.
Спасибо:

aspirant

Фотография
Дата: 31.01.2011
Ответить


Mikhail Sukhov
Но мне не понятно эта иерархия. Стрим - репликация - таблица. Это реально нужная вещь, без которой Плаза не взлетит? Пока выглядит как избыточность.


Это не мои изобретения. Выдача данных клиентов Плазой строится следующим образом: есть несколько потоков репликации (FORTS_OPTINFO_REPL и т.д.). У каждого потока есть dbscheme. Вроде у каждого потока она одна, но пока не успел проверить точно. Зачем она нужна, если она одна, - ума не приложу. И наконец в каждом потоке есть от одной до несколько таблиц. Это их мы описывали наследниками PlazaColumns.

Чтобы подписаться на потоки и получать данные, я могу просто указать имя потока (второй конструктор PlazaStream). В этом случае будут приходить ВСЕ данные потока, т.е. если в нем несколько таблиц, например в FORTS_FUTINFO_REPL их 17 штук, их данные будут приходить через событие CP2DataStreamClass.StreamDataInserted вперемешку. Второй вариант - это, когда я отправляю на сервер содержимое ini-файла таблицы с обязательным указанием потока репликации, dbscheme, именем таблицы и списка нужных колонок запрашиваемой таблицы. В этом случае, понятно, приходят только запрошенные колонки запрошенной таблицы.

Из-за того, что процесс подписки на потоки построен именно таким образом, я считаю необходимым добавить в PlazaColumns

public abstract ReplicationStream ReplicationStream { get; }
public virtual ReplicationScheme ReplicationScheme { get { return ReplicationScheme.CustReplScheme; } }
public abstract string Table { get; }

У каждой таблицы потока репликации, т.е. наследника PlazaColumns, своя уникальная неизменная комбинация ReplicationStream + ReplicationScheme + Table. Она мне нужна для создания ini-файла.

Букв много. Надеюсь, что не запутал окончательно.

Спасибо:

Mikhail Sukhov

Фотография
Дата: 01.02.2011
Ответить


aspirant

public abstract ReplicationStream ReplicationStream { get; }
public virtual ReplicationScheme ReplicationScheme { get { return ReplicationScheme.CustReplScheme; } }
public abstract string Table { get; }

У каждой таблицы потока репликации, т.е. наследника PlazaColumns, своя уникальная неизменная комбинация ReplicationStream + ReplicationScheme + Table. Она мне нужна для создания ini-файла.

Букв много. Надеюсь, что не запутал окончательно.



Стало чуть понятнее. А где теперь делать проверку, что в таблицу попала правильная колонка?
Спасибо:

aspirant

Фотография
Дата: 02.02.2011
Ответить


Mikhail Sukhov
А где теперь делать проверку, что в таблицу попала правильная колонка?


Предлагаю у PlazaColumn сделать readonly поле Owner типа PlazaColumns, инициализировать его в конструкторе PlazaColumn. В конструкторе PlazaTable перебирать IEnumerable<PlazaColumn> columns и сравнивать у каждого элемента Owner.ReplicationStream, Owner.ReplicationScheme и Owner.Table c replicationStream, replicationScheme, переданными в конструктор PlazaTable.

Как вариант, можно убрать из параметров конструктора PlazaTable параметры ReplicationStream replicationStream, ReplicationScheme replicationScheme, string name вообще и считать, что правильные параметры ReplicationStream, ReplicationScheme, [Table]name указаны в первом элементе IEnumerable<PlazaColumn> columns. Соответственно, проверку на правильность остальных элементов IEnumerable<PlazaColumn> columns проводить с значениями полей первого элемента.

Не знаю, какой вариант правильнее?

Спасибо:
<< < 5 6 7 8  >

Добавить файлы через драг-н-дроп, , или вставить из буфера обмена.

loading
clippy