aspirant
|
Дата: 18.03.2011
|
|
|
|
По порядку: Mikhail Sukhov 1. PlazaSystemTable явно лишний. У каждой таблицы в потоке помимо четкого набора полей (колоннок) есть еще три обязательных параметра: название потока, название схемы потока и название таблицы. Поскольку каждой таблице потоков соответствует свой наследник PlazaColumns, например, таблица rts_index - это класс PlazaIndexColumns, имело смысл в каждом наследнике PlazaColumns прописать эти три параметра. Первоначально я сделал это через абстрактные свойства базового класса PlazaColumns: ReplicationStream, ReplicationScheme и Table. Ты предложил более удобный вариант: через класс PlazaTable, который теперь называется PlazaSystemTable. Имя я изменил, потому что мне нужно было добавить класс PlazaTable. Если моему PlazaTable дать другое название (мне вчера вечером с лету ничего в голову не пришло), PlazaSystemTable можно обратно переименовать в PlazaTable. Mikhail Sukhov Зачем-то в PlazaTable идет работа с потоками. Есть же менеджер потоков, есть PlazaTrader. В классе, описывающий метаданные, работа с потоками по идее быть не должно. Мой PlazaTable метаданные не описывает (см. выше). Это класс своего рода контейнер по типу DataTable. Он используется для подписки на конкретный поток, получения и хранения данных из этого потока. Все управление потоками по-прежнему происходит внутри PlazaStreamManager. В дальнейшем PlazaTable сможет фильтровать данные. Mikhail Sukhov Зачем нужен Records у PlazaTable? В этом массиве хранятся данные, которые приходят из потока (см. предыдущий пункт). Mikhail Sukhov Я думаю надо еще раз проговорить про организацию работы с потоками Плазы. Мы прописали все метаданные Плазы. У нас есть механизм создания ini-файлов на лету (их не нужно парсить, они считываются/парсятся самой Плазой в методе CP2DataStreamClass.TableSet.InitFromIni2()). Мы можем использовать этот единый механизм, как для пользовательских подписок, так и для служебных (которые будут потом мапиться в классы). Если парсить файлы, зачем было прописывать метаданные? У нас будет два механизма подписки к потокам, а это только усложнит систему, а не упростит. Mikhail Sukhov Зачем здесь PlazaMarketData? У меня была такая мысль: а что если дать пользователю возможность запускать не все основные потоки, а только те, которые ему нужны. Например, если я работаю с фьючерсами, зачем мне информация по опционам? Или это бред чайника[confused] Тогда PlazaMarketData можно убрать вообще и стартовать основные потоки в конструкторе PlazaTrader или в отдельном методе. Mikhail Sukhov Вообщем, сейчас уже практически не понять, что есть что. Попробуй в тестовом коде подписаться на пару потоков и отследи, что происходит в дебагере. Mikhail Sukhov Вопрос к аспиранту, а именно в чем необходимость данного хитросплетения? Легче будет рефакторить и поддерживать в дальнейшем[smile] Половину функицонала PlazaTable можно засунуть в PlazaStreamManager, но тогда он будет знать очень много. А после того, как добавится фильтрация данных[omg] Подытоживая: PlazaTable, PlazaSystemTable - схожие названия действительно путают: предлагай свой варианты. Вместе с этим, считаю, что оба класса имеют право на существование.
|
|
Спасибо:
|
|
|
|
|
Mikhail Sukhov
|
Дата: 19.03.2011
|
|
|
|
aspirant У каждой таблицы в потоке помимо четкого набора полей (колоннок) есть еще три обязательных параметра: название потока, название схемы потока и название таблицы. Поскольку каждой таблице потоков соответствует свой наследник PlazaColumns, например, таблица rts_index - это класс PlazaIndexColumns, имело смысл в каждом наследнике PlazaColumns прописать эти три параметра. На мой взгляд, зря. Это все нужно засовывать в PlazaTable. PlazaColumns - это лишь базовый класс для контейнера колонок. У нас практически во всех таблицах есть 3 служебных поля. Вот ради них я и вынес это в отдельный класс PlazaColumns. Даже не думал, что его как-то по другому начнут использовать.[smile] aspirant Мой PlazaTable метаданные не описывает (см. выше). Это класс своего рода контейнер по типу DataTable. Он используется для подписки на конкретный поток, получения и хранения данных из этого потока. Все управление потоками по-прежнему происходит внутри PlazaStreamManager. В дальнейшем PlazaTable сможет фильтровать данные.
В этом массиве хранятся данные, которые приходят из потока (см. предыдущий пункт).
А зачем вообще нужно хранить эти данные? Мое видение: подписались на поток. Поток отдает данные. Данные раздаются подписчикам (например, подписчику, преобразующий поток с опционами в Security). Не могу понять, когда пригодиться использование хранения? aspirant Мы прописали все метаданные Плазы. У нас есть механизм создания ini-файлов на лету (их не нужно парсить, они считываются/парсятся самой Плазой в методе CP2DataStreamClass.TableSet.InitFromIni2()). Мы можем использовать этот единый механизм, как для пользовательских подписок, так и для служебных (которые будут потом мапиться в классы). Если парсить файлы, зачем было прописывать метаданные? У нас будет два механизма подписки к потокам, а это только усложнит систему, а не упростит.
Мне лично видеться только один единый способ подписки к потоком -> PlazaStreamManager.StartListener(PlazaTable). Его используют все - и PlazaTrader и пользовательский код фактически один и тем же способом: передаем PlazaTable, где указаны системные параметры, и начинаем через callback получать массивы данных... Я что-то упускаю? aspirant У меня была такая мысль: а что если дать пользователю возможность запускать не все основные потоки, а только те, которые ему нужны. Например, если я работаю с фьючерсами, зачем мне информация по опционам? Или это бред чайника[confused] Тогда PlazaMarketData можно убрать вообще и стартовать основные потоки в конструкторе PlazaTrader или в отдельном методе.
Я думаю это точно так же можно проделать через PlazaTable - передавать не все объекты PlazaTable, а только те, что отвечают за опционы. aspirant Легче будет рефакторить и поддерживать в дальнейшем[smile] Половину функицонала PlazaTable можно засунуть в PlazaStreamManager, но тогда он будет знать очень много. А после того, как добавится фильтрация данных[omg]
Согласен. Тогда предлагаю пока все что отвечает за метаданные перенести обратно в PlazaSystemTable (названия потоков, таблиц и т.д.). Посмотреть, можно ли обойтись без Records. И уж там поглядеть, что осталось от PlazaTable. Думаю, останеться немного. Насчет фильтрации, я думаю надо делать это в PlazaStream. Или вынести это в отдельный класс PlazaStreamFilter. aspirant Подытоживая: PlazaTable, PlazaSystemTable - схожие названия действительно путают: предлагай свой варианты. Вместе с этим, считаю, что оба класса имеют право на существование.
|
|
Спасибо:
|
|
|
|
|
aspirant
|
Дата: 19.03.2011
|
|
|
|
Mikhail Sukhov Это все нужно засовывать в PlazaTable. Не понял, как это сделать. Можешь объяснить, приведя код? Сейчас, чтобы подписаться, например, на таблицу FORTS_OPTINFO_REPL\opt_sess_contents, нужно сделать вот так: Кодvar optSessionTable = new PlazaTable(PlazaColumnRegistry.OptionSessionContents); _plazaTrader.StartListeners(optSessionTable); А чтобы подписаться только на две колонки той же самой таблицы, нужно сделать вот это: Кодvar optSessionTable = new PlazaTable(PlazaColumnRegistry.OptionSessionContents, new[] { PlazaColumnRegistry.OptionSessionContents.Isin, PlazaColumnRegistry.OptionSessionContents.IsinId }); _plazaTrader.StartListeners(optSessionTable);
Внутри метода PlazaTable.CreateStream() конструктор PlazaStream создаст на лету ini-файл схему для передачи Плазе. Названия потока, схемы и таблицы он возьмет из свойства public PlazaSystemTable Table, который класс PlazaOptionSessionContentsColumns унаследовал от PlazaColumns. Пользователю ничего никаких названий указывать не надо. Никаких ini-файлов парсить тоже не надо. Mikhail Sukhov А зачем вообще нужно хранить эти данные? Мое видение: подписались на поток. Поток отдает данные. Данные раздаются подписчикам (например, подписчику, преобразующий поток с опционами в Security). Не могу понять, когда пригодиться использование хранения? Все понятно. Тогда от хранения отказываемся вообще. Данные в Плазе приходят по одной записи (строчке). Значит таким же методом транслируем данные клиенту? Mikhail Sukhov Мне лично видеться только один единый способ подписки к потоком -> PlazaStreamManager.StartListener(PlazaTable). Его используют все - и PlazaTrader и пользовательский код фактически один и тем же способом: передаем PlazaTable, где указаны системные параметры, и начинаем через callback получать массивы данных... Я что-то упускаю? Да, все правильно. Просто в предыдущем посте ты писал: Mikhail Sukhov Пользователей работает с метаданными. Неявно, когда при старте сканируются ini схемы и восстанавливаются колонки автоматически в PlazaTable.Columns. Это механизм № 2, и его нет. Mikhail Sukhov aspirant У меня была такая мысль: а что если дать пользователю возможность запускать не все основные потоки, а только те, которые ему нужны. Например, если я работаю с фьючерсами, зачем мне информация по опционам? Или это бред чайника[confused] Тогда PlazaMarketData можно убрать вообще и стартовать основные потоки в конструкторе PlazaTrader или в отдельном методе.
Я думаю это точно так же можно проделать через PlazaTable - передавать не все объекты PlazaTable, а только те, что отвечают за опционы. Тут вот какой вопрос: предположим, что, чтобы замапить объекты Security типа опцион, нужно подписаться на поток FORTS_OPTINFO_REPL\opt_sess_contents. Пользователь берет и по какой-то причине передает в PlazaTrader не всю таблицу, а только некий набор колонок (см. кусок кода № 2 выше). Данные приходят, но не все. Объекты создаются, но некоторые свойства не мапятся. Это допустимая ситуация, или мы должны каким-то образом ее предотвратить? Mikhail Sukhov Согласен. Тогда предлагаю пока все что отвечает за метаданные перенести обратно в PlazaSystemTable (названия потоков, таблиц и т.д.). Посмотреть, можно ли обойтись без Records. И уж там поглядеть, что осталось от PlazaTable. Думаю, останеться немного. Все метаданные по таблице уже живут в PlazaSystemTable. От Records можно отказаться вообще. PlazaTable нужен. Чем еще он удобен: через него приходят данные клиенту. Вот, например, вот так данные с двух потоков приходят в разные обработчики событий: Кодvar optSessionTable = new PlazaTable(PlazaColumnRegistry.OptionSessionContents); optSessionTable.DataInserted += optSessionTable_DataInserted; var rtsIndexTable = new PlazaTable(PlazaColumnRegistry.RtsIndex); rtsIndexTable.DataInserted += rtsIndexTable_DataInserted; Если его убрать, получается, что данные будут приходить в PlazaStreamManager, который будет передавать их в PlazaTrader, котрый будет уже отдавать клиенту. Но тогда данные со всех потоков будут приходить через одно событие, а это 1) возможное узкое место в коде и 2) усложнение кода, потому что внутри события PlazaTrader будет гигантский switch statement Mikhail Sukhov Насчет фильтрации, я думаю надо делать это в PlazaStream. Или вынести это в отдельный класс PlazaStreamFilter. Фильтрацию тоже нужно делать в PlazaTable. Он же получает данные из потоков и передает их клиенту. Попытаюсь сжато описать разграничение полномочий среди моих хитросплетений. - За метаданные отвечают PlazaSystemTable и наследники PlazaColumns.
- PlazaStream - это работа с конкретным потоком (плазовский класс CP2DataStreamClass): создание ini-файла схемы, (пере)открытие потока, установка номера жизни.
- PlazaStreamManager создает подключения к Плазе, а также запускает подписки на потоки через PlazaStream в отдельных потоках. PlazaStream и PlazaStreamManager после отладки нужно скрыть от клиентского кода.
- PlazaTable хранит в себе конфигурацию подписки к конкретному потоку (название потока, схемы, таблицы + нужный набор колоннок). Он создает PlazaStream и подписывается на события получение данных, чтобы в дальнейшем транслировать их клиенту. Поскольку он пропускает их через себя, он сможет в дальнейшем их фильтровать.
Еще раз повторюсь, мне кажется PlazaTable не совсем подходящее название для этого класса. Может быть PlazaSubscription или PlazaListener?
|
|
Спасибо:
|
|
|
|
|
Mikhail Sukhov
|
Дата: 20.03.2011
|
|
|
|
aspirant Если его убрать, получается, что данные будут приходить в PlazaStreamManager, который будет передавать их в PlazaTrader, котрый будет уже отдавать клиенту. Но тогда данные со всех потоков будут приходить через одно событие, а это 1) возможное узкое место в коде и 2) усложнение кода, потому что внутри события PlazaTrader будет гигантский switch statement
.... поискапино
Еще раз повторюсь, мне кажется PlazaTable не совсем подходящее название для этого класса. Может быть PlazaSubscription или PlazaListener?
Да, я кажется понял идею. Был не прав. Тогда я за переименование. То, что сейчас PlazaSystemTable -> PlazaTable. PlazaTable -> PlazaSubscription или PlazaListener. Но есть но. Приведу твой код: Кодvar optSessionTable = new PlazaTable(PlazaColumnRegistry.OptionSessionContents, new[] { PlazaColumnRegistry.OptionSessionContents.Isin, PlazaColumnRegistry.OptionSessionContents.IsinId }); _plazaTrader.StartListeners(optSessionTable); 1. Я не проверял но более чем уверен, что плаза не дает два раза создать поток по одной и той же таблице с разными полями. 2. Ты опять мешаешь метаданные с Плаза потоками. Я бы написал так: Код // в этот момент (можно запихнуть в статический конструктор PlazaTableRegistry) // сканируется директория на предмет определения схем, и если уже создана схема ввиде файла для OptionSession // то PlazaTableRegistry.OptionSession.Columns уже заполнен какими то колонками, исходя из файла var optSessionTable = PlazaTableRegistry.OptionSession;
// проверяем, не добавлена ли уже необходимые колонки (были добавлены при предыдущем запуске, или же пользователь уже имеет файл с правильными настройками) if (!optSessionTable.Columns.Contains(PlazaColumnRegistry.OptionSessionContents.Isin)) { // при добавлении колонок автоматически меняется соответствующий ini файл на диске (пока я так понял этой фичи нет, но это не долго добавить). optSessionTable.Columns.AddRange(new[] { PlazaColumnRegistry.OptionSessionContents.Isin, PlazaColumnRegistry.OptionSessionContents.IsinId }); }
// тоесть мы метаданные готовим до того, как будет создан PlazaTrader и вызван Connect.
var optSessListener = new PlazaListener(PlazaTableRegistry.OptionSession); _plazaTrader.StartListeners(optSessListener);
|
|
Спасибо:
|
|
|
|
|
Mikhail Sukhov
|
Дата: 20.03.2011
|
|
|
|
aspirant Тут вот какой вопрос: предположим, что, чтобы замапить объекты Security типа опцион, нужно подписаться на поток FORTS_OPTINFO_REPL\opt_sess_contents. Пользователь берет и по какой-то причине передает в PlazaTrader не всю таблицу, а только некий набор колонок (см. кусок кода № 2 выше). Данные приходят, но не все. Объекты создаются, но некоторые свойства не мапятся. Это допустимая ситуация, или мы должны каким-то образом ее предотвратить?
Нужно определить минимальный набор, с которым можно прожить. Тоесть, если пользователь имеет ini схему для особых таблиц (инструменты, заявки, сделки и т.д. - это все особые), у которых отсутствуют обязательные поля (это как раз те, что PlazaColumns.IsMandatory == true, но сейчас по ошибке они все true), то их нужно или дописать, или выбросить ошибку (пока предлагаю второе, так как я всегда против эвристики в коде). Если же у него сверх необходимого в полях, то они идут в ExtensionInfo где ключом является PlazaColumn, а значение - то что получили из потока.
|
|
Спасибо:
|
|
|
|
|
aspirant
|
Дата: 20.03.2011
|
|
|
|
Mikhail Sukhov Но есть но. Приведу твой код: Кодvar optSessionTable = new PlazaTable(PlazaColumnRegistry.OptionSessionContents, new[] { PlazaColumnRegistry.OptionSessionContents.Isin, PlazaColumnRegistry.OptionSessionContents.IsinId }); _plazaTrader.StartListeners(optSessionTable); 1. Я не проверял но более чем уверен, что плаза не дает два раза создать поток по одной и той же таблице с разными полями. Сама Плаза дает, тем более что для каждого потока создается отдельное подключение (CP2ConnectionClass) с уникальным именем (в соответствии с рекомендациями разработчиков). Только что проверял: Код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
Правда раньше потоки хранились внутри PlazaStreamManager в словаре, и, если ключ явно не указывался, вместо ключа использовалось сочетание поток+таблица, поэтому два раза один и тот же поток, не указывая разные ключи, добавить было нельзя. Сейчас я словарь переделал в простой список, в который можно добавлять потоки по одной и той же таблице. Mikhail Sukhov 2. Ты опять мешаешь метаданные с Плаза потоками.
Я бы написал так:
[code] // в этот момент (можно запихнуть в статический конструктор PlazaTableRegistry) // сканируется директория на предмет определения схем, и если уже создана схема ввиде файла для OptionSession // то PlazaTableRegistry.OptionSession.Columns уже заполнен какими то колонками, исходя из файла var optSessionTable = PlazaTableRegistry.OptionSession; Вопросы: - Кто и в какой момент будет создавать эти схемы-файлы?
- Получается нужно обыгрывать такой сценарий: клиент запустил PlazaTrader, создал подписку на таблицу 1 с 3 колонками, вышел из программы. Мы должны запомнить, что его подписка состоит из 3 колонок. Он снова запустил PlazaTrader, добавил в подписку еще одну колонку, вышел из программы. Мы опять сохранили состояние. В таком случае нужно иметь в виду, что 1) родной формат схем-файлов Плазы не поддерживает сохранение параметров фильтрации и 2) название потока (FORTS_OPTINFO_REPL и т.д.) не указывается в файле, его нужно передавать в коде отдельно (кстати, почему так сделано, больше всего меня удивляет). Придется либо запихивать и 1) и 2) в комментарии, либо сохранять все внутри XML, то есть однозначно клиенту эти файлы показывать не стоит.
Mikhail Sukhov тоесть мы метаданные готовим до того, как будет создан PlazaTrader и вызван Connect. Почему это важно? Речь идет о создании одного-двух десятков маленьких текстовиков, причем делаться это будет один раз при подписке на поток. Еще важный момент: ты можешь добавить в класс PlazaTrader событие тип Unloading или Disposing, которые будет вызываться при выгрузке. Это нужно для PlazaStreamManager: все потоки (plaza streams) вертятся в отдельных потоках (threads), и, если в клиентском коде явно не вызывать PlazaStreamManager.Dispose(), программа будет висеть в памяти, а данные по-прежнему будут сыпаться.
|
|
Спасибо:
|
|
|
|
|
aspirant
|
Дата: 20.03.2011
Mikhail Sukhov Нужно определить минимальный набор, с которым можно прожить. Поскольку на один и тот же поток можно подписываться несколько раз (см. мой предыдущий пост), может быть, мы сами будем подписываться на стандратняе потоки, чтобы можно было правильно мапить все объекты, а клиент пусть делает, что хочет?
|
|
Спасибо:
|
|
|
|
|
Mikhail Sukhov
|
Дата: 20.03.2011
aspirant Mikhail Sukhov Нужно определить минимальный набор, с которым можно прожить. Поскольку на один и тот же поток можно подписываться несколько раз (см. мой предыдущий пост), может быть, мы сами будем подписываться на стандратняе потоки, чтобы можно было правильно мапить все объекты, а клиент пусть делает, что хочет? Да, согласен. Но это все равно не избавляет от факта присутствия "лишних" (ExtensionInfo) колонок? Они необходимы, и их нужно экспортировать не со стороны пользовательского кода, а через конфигурирование метаданных.
|
|
Спасибо:
|
|
|
|
|
Mikhail Sukhov
|
Дата: 20.03.2011
|
|
|
|
aspirant Сама Плаза дает, тем более что для каждого потока создается отдельное подключение (CP2ConnectionClass) с уникальным именем (в соответствии с рекомендациями разработчиков).
А стоит ли давать так делать? aspirant Mikhail Sukhov 2. Ты опять мешаешь метаданные с Плаза потоками.
Я бы написал так:
[code] // в этот момент (можно запихнуть в статический конструктор PlazaTableRegistry) // сканируется директория на предмет определения схем, и если уже создана схема ввиде файла для OptionSession // то PlazaTableRegistry.OptionSession.Columns уже заполнен какими то колонками, исходя из файла var optSessionTable = PlazaTableRegistry.OptionSession; Вопросы: - Кто и в какой момент будет создавать эти схемы-файлы?
- Получается нужно обыгрывать такой сценарий: клиент запустил PlazaTrader, создал подписку на таблицу 1 с 3 колонками, вышел из программы. Мы должны запомнить, что его подписка состоит из 3 колонок. Он снова запустил PlazaTrader, добавил в подписку еще одну колонку, вышел из программы. Мы опять сохранили состояние. В таком случае нужно иметь в виду, что 1) родной формат схем-файлов Плазы не поддерживает сохранение параметров фильтрации и 2) название потока (FORTS_OPTINFO_REPL и т.д.) не указывается в файле, его нужно передавать в коде отдельно (кстати, почему так сделано, больше всего меня удивляет). Придется либо запихивать и 1) и 2) в комментарии, либо сохранять все внутри XML, то есть однозначно клиенту эти файлы показывать не стоит.
1. При первом обращении к PlazaTableRegistry они будут создаваться им, если файлов нет на диске. Если есть, то наоборот, их файлов будут считываться информация и заполняться PlazaTable.Columns тех таблиц, информация о которых присутствует на диске. 2. Предлагаю сохранять файлы не по выходу из программы, а когда меняется коллекция PlazaTable.Columns. 3. Фильтрацию (по инструменту) не нужно сохранять. Это динамическая информация и зависит от запущенных стратегий. Не запустил пользователь стратегию, данные не текут. Запустил, вызвал PlazaTrader.RegisterXXX - данные текут. 4. А как тогда потоки стартую если названия из не указывается? aspirant Mikhail Sukhov тоесть мы метаданные готовим до того, как будет создан PlazaTrader и вызван Connect. Почему это важно? Речь идет о создании одного-двух десятков маленьких текстовиков, причем делаться это будет один раз при подписке на поток. Потому что в реальном времени потоки же не изменить. Вроде как Plaza сканирует схемы и уже потом не поменять метаданные. Я ошибаюсь? aspirant Еще важный момент: ты можешь добавить в класс PlazaTrader событие тип Unloading или Disposing, которые будет вызываться при выгрузке. Это нужно для PlazaStreamManager: все потоки (plaza streams) вертятся в отдельных потоках (threads), и, если в клиентском коде явно не вызывать PlazaStreamManager.Dispose(), программа будет висеть в памяти, а данные по-прежнему будут сыпаться.
Сейчас просто создавай потоки с Thread.IsBackground = true.
|
|
Спасибо:
|
|
|
|
|
aspirant
|
Дата: 22.03.2011
|
|
|
|
Mikhail Sukhov aspirant Сама Плаза дает, тем более что для каждого потока создается отдельное подключение (CP2ConnectionClass) с уникальным именем (в соответствии с рекомендациями разработчиков).
А стоит ли давать так делать? Вроде обсуждали про пул подключений для распараллеливания потоков. Я, когда писал PlazaStreamManager, сразу это и сделал. Mikhail Sukhov 4. А как тогда потоки стартую если названия из не указывается? Вот ini-файл для таблицы FORTS_OPTCOMMON_REPL\common (колонки не все) Код[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 А вот как инициализиурется поток в коде: Код _dataStream = new CP2DataStreamClass(); _dataStream.StreamName = "FORTS_OPTCOMMON_REPL"; // название потока указывается в этой строчке.
Меняем название потока, и с той же схемой инициализируем таблицу с таким же именем из другого потока: Код _dataStream = new CP2DataStreamClass(); _dataStream.StreamName = "FORTS_FUTCOMMON_REPL";
Конечно, эти две таблицах не полностью соответствуют друг другу, но при желании (что я и сделал), можно создать выборочную схему с одинаковым набором колоннок. По поводу остального напишу вечером. Кстати, позавчера вечером начал мапить объекты из потоков (см. метод PlazaTrader.OnNewDataFromOptionSessionContents())
|
|
Спасибо:
|
|
|
|