Вообщем, сейчас уже практически не понять, что есть что. Вопрос к аспиранту, а именно в чем необходимость данного хитросплетения?
Что я вижу сейчас:
- PlazaSystemTable явно лишний.
- Зачем-то в PlazaTable идет работа с потоками. Есть же менеджер потоков, есть PlazaTrader. В классе, описывающий метаданные, работа с потоками по идее быть не должно.
- Зачем нужен Records у PlazaTable?
Я думаю надо еще раз проговорить про организацию работы с потоками Плазы.
- Пользователей работает с метаданными. Явно, когда их редактируется через PlazaTable.Columns. Неявно, когда при старте сканируются ini схемы и восстанавливаются колонки автоматически в PlazaTable.Columns.
- Пользователь запускает экспорт через PlazaTrader.StartExport. Стартуют потоки как основные (которые в QuikTrader мапяться на объекты Security Trade Order и т.д.) так и дополнительные (думаю, маппинг лучше организовать как с Custom tables в QuikTrader). Какие именно нужны потоки - определяется на шаге 1.
Зачем здесь PlazaSystemTable? И PlazaMarketData?
Kommentare (15)
Anmelden oder Konto erstellen, Melden Sie sich an oder registrieren Sie sich, um einen Kommentar zu hinterlassen
По порядку:
Подытоживая: PlazaTable, PlazaSystemTable - схожие названия действительно путают: предлагай свой варианты. Вместе с этим, считаю, что оба класса имеют право на существование.
На мой взгляд, зря. Это все нужно засовывать в PlazaTable. PlazaColumns - это лишь базовый класс для контейнера колонок. У нас практически во всех таблицах есть 3 служебных поля. Вот ради них я и вынес это в отдельный класс PlazaColumns. Даже не думал, что его как-то по другому начнут использовать.🙂
А зачем вообще нужно хранить эти данные? Мое видение: подписались на поток. Поток отдает данные. Данные раздаются подписчикам (например, подписчику, преобразующий поток с опционами в Security). Не могу понять, когда пригодиться использование хранения?
Мне лично видеться только один единый способ подписки к потоком -> PlazaStreamManager.StartListener(PlazaTable). Его используют все - и PlazaTrader и пользовательский код фактически один и тем же способом: передаем PlazaTable, где указаны системные параметры, и начинаем через callback получать массивы данных... Я что-то упускаю?
Я думаю это точно так же можно проделать через PlazaTable - передавать не все объекты PlazaTable, а только те, что отвечают за опционы.
Согласен. Тогда предлагаю пока все что отвечает за метаданные перенести обратно в PlazaSystemTable (названия потоков, таблиц и т.д.). Посмотреть, можно ли обойтись без Records. И уж там поглядеть, что осталось от PlazaTable. Думаю, останеться немного.
Насчет фильтрации, я думаю надо делать это в PlazaStream. Или вынести это в отдельный класс PlazaStreamFilter.
А чтобы подписаться только на две колонки той же самой таблицы, нужно сделать вот это:
Внутри метода PlazaTable.CreateStream() конструктор PlazaStream создаст на лету ini-файл схему для передачи Плазе. Названия потока, схемы и таблицы он возьмет из свойства public PlazaSystemTable Table, который класс PlazaOptionSessionContentsColumns унаследовал от PlazaColumns. Пользователю ничего никаких названий указывать не надо. Никаких ini-файлов парсить тоже не надо.
Все понятно. Тогда от хранения отказываемся вообще. Данные в Плазе приходят по одной записи (строчке). Значит таким же методом транслируем данные клиенту?
Да, все правильно. Просто в предыдущем посте ты писал:
Это механизм № 2, и его нет.
Тут вот какой вопрос: предположим, что, чтобы замапить объекты Security типа опцион, нужно подписаться на поток FORTS_OPTINFO_REPL\opt_sess_contents. Пользователь берет и по какой-то причине передает в PlazaTrader не всю таблицу, а только некий набор колонок (см. кусок кода № 2 выше). Данные приходят, но не все. Объекты создаются, но некоторые свойства не мапятся. Это допустимая ситуация, или мы должны каким-то образом ее предотвратить?
Все метаданные по таблице уже живут в PlazaSystemTable. От Records можно отказаться вообще. PlazaTable нужен. Чем еще он удобен: через него приходят данные клиенту. Вот, например, вот так данные с двух потоков приходят в разные обработчики событий:
Если его убрать, получается, что данные будут приходить в PlazaStreamManager, который будет передавать их в PlazaTrader, котрый будет уже отдавать клиенту. Но тогда данные со всех потоков будут приходить через одно событие, а это 1) возможное узкое место в коде и 2) усложнение кода, потому что внутри события PlazaTrader будет гигантский switch statement
Попытаюсь сжато описать разграничение полномочий среди моих хитросплетений.
Еще раз повторюсь, мне кажется PlazaTable не совсем подходящее название для этого класса. Может быть PlazaSubscription или PlazaListener?
Да, я кажется понял идею. Был не прав. Тогда я за переименование. То, что сейчас PlazaSystemTable -> PlazaTable. PlazaTable -> PlazaSubscription или PlazaListener.
Но есть но. Приведу твой код:
Я бы написал так:
Нужно определить минимальный набор, с которым можно прожить. Тоесть, если пользователь имеет ini схему для особых таблиц (инструменты, заявки, сделки и т.д. - это все особые), у которых отсутствуют обязательные поля (это как раз те, что PlazaColumns.IsMandatory == true, но сейчас по ошибке они все true), то их нужно или дописать, или выбросить ошибку (пока предлагаю второе, так как я всегда против эвристики в коде).
Если же у него сверх необходимого в полях, то они идут в ExtensionInfo где ключом является PlazaColumn, а значение - то что получили из потока.
var optSessionTable = new PlazaTable(PlazaColumnRegistry.OptionSessionContents, new[] { PlazaColumnRegistry.OptionSessionContents.Isin, PlazaColumnRegistry.OptionSessionContents.IsinId }); _plazaTrader.StartListeners(optSessionTable);
optSessionListener1_DataInserted: 28800;43882;0;RTS-6.11M150611CA 100000;151364 optSessionListener2_DataInserted: 28800;43882;0;151331;88,66;8950,48;0;0;100000,00000;0;20101220000000000;20110615000000000;8975,37;151331;3274;151364;RI100000BF1;RTS-6.11M150611CA 100000;Июньский Марж.Амер.Call.100000 Фьюч.контр RTS-6.11;0;0,00000;0,00000;89065,00000;RTS;5,00000;1;2,84763;20110615000000000;89065,00000;115
Поскольку на один и тот же поток можно подписываться несколько раз (см. мой предыдущий пост), может быть, мы сами будем подписываться на стандратняе потоки, чтобы можно было правильно мапить все объекты, а клиент пусть делает, что хочет?
Да, согласен. Но это все равно не избавляет от факта присутствия "лишних" (ExtensionInfo) колонок? Они необходимы, и их нужно экспортировать не со стороны пользовательского кода, а через конфигурирование метаданных.
А стоит ли давать так делать?
Получается нужно обыгрывать такой сценарий: клиент запустил PlazaTrader, создал подписку на таблицу 1 с 3 колонками, вышел из программы. Мы должны запомнить, что его подписка состоит из 3 колонок. Он снова запустил PlazaTrader, добавил в подписку еще одну колонку, вышел из программы. Мы опять сохранили состояние. В таком случае нужно иметь в виду, что 1) родной формат схем-файлов Плазы не поддерживает сохранение параметров фильтрации и 2) название потока (FORTS_OPTINFO_REPL и т.д.) не указывается в файле, его нужно передавать в коде отдельно (кстати, почему так сделано, больше всего меня удивляет). Придется либо запихивать и 1) и 2) в комментарии, либо сохранять все внутри XML, то есть однозначно клиенту эти файлы показывать не стоит.
При первом обращении к PlazaTableRegistry они будут создаваться им, если файлов нет на диске. Если есть, то наоборот, их файлов будут считываться информация и заполняться PlazaTable.Columns тех таблиц, информация о которых присутствует на диске.
Предлагаю сохранять файлы не по выходу из программы, а когда меняется коллекция PlazaTable.Columns.
Фильтрацию (по инструменту) не нужно сохранять. Это динамическая информация и зависит от запущенных стратегий. Не запустил пользователь стратегию, данные не текут. Запустил, вызвал PlazaTrader.RegisterXXX - данные текут.
А как тогда потоки стартую если названия из не указывается?
Потому что в реальном времени потоки же не изменить. Вроде как Plaza сканирует схемы и уже потом не поменять метаданные. Я ошибаюсь?
Сейчас просто создавай потоки с Thread.IsBackground = true.
Вроде обсуждали про пул подключений для распараллеливания потоков. Я, когда писал PlazaStreamManager, сразу это и сделал.
Вот ini-файл для таблицы FORTS_OPTCOMMON_REPL\common (колонки не все)
А вот как инициализиурется поток в коде:
Меняем название потока, и с той же схемой инициализируем таблицу с таким же именем из другого потока:
Конечно, эти две таблицах не полностью соответствуют друг другу, но при желании (что я и сделал), можно создать выборочную схему с одинаковым набором колоннок.
По поводу остального напишу вечером. Кстати, позавчера вечером начал мапить объекты из потоков (см. метод PlazaTrader.OnNewDataFromOptionSessionContents())
В итоге то к чему пришли?
[dbscheme:CustReplScheme] table=common
; Общая информация по сессии [table:CustReplScheme:common] field=replID,i8 field=replRev,i8 field=replAct,i8 field=isin_id,i4 field=sess_id,i4 field=best_sell,d16.5 field=amount_sell,i4 field=best_buy,d16.5 field=amount_buy,i4 field=price,d16.5 field=trend,d16.5 field=amount,i4
А как Плаза отпределяет, что для потока FORTS_OPTCOMMON_REPL нужен вот тот файл ini а не какой то другой?
Пришли, что это будет в списке второстепенных задач по потокам, но я сделал сразу, потому что это оказалось быстрее, чем я предполагал.
У нее есть внутреннее знание 🙂 В следующем коде произойдет исключение, если хотя бы одна из колонок указана неправильно:
_dataStream.TableSet.InitFromIni2(_configFileName, "FORTS_OPTCOMMON_REPL");
Mea culpa. Вот правильный кусок кода:
_dataStream.StreamName = "FORTS_OPTCOMMON_REPL"; // вторым параметром указывается название dbScheme, можно "", если dbScheme:CustReplScheme (дефолтная) _dataStream.TableSet.InitFromIni2(_configFileName, "");