Комментарии и предложения
Atom
11.03.2011
skuvv


Заметил пару нюансов по PlazaTrader:
1)
Код

_plazaStreamManager = new PlazaStreamManager(_plazaConnectionPool, TRequestType.RT_COMBINED_DYNAMIC, 1000);

Почему рекваест тайп фиксированный? надо конкретно задавать, например у меня так было:
Цитата:

"FORTS_FUTAGGR20_REPL" - RT_REMOTE_ONLINE
"FORTS_FUTTRADE_REPL" - RT_REMOTE_ONLINE
"FORTS_FUTINFO_REPL" - RT_COMBINED_DYNAMIC
"FORTS_FUTCOMMON_REPL" - RT_REMOTE_ONLINE
"FORTS_POS_REPL" - RT_COMBINED_DYNAMIC
"FORTS_PART_REPL" - RT_COMBINED_DYNAMIC
"FORTS_VM_REPL" - RT_COMBINED_DYNAMIC

Допустим если FORTS_FUTCOMMON_REPL задать в RT_COMBINED_DYNAMIC, то при реконнекте будет перекачиваться весь поток заново.
+Revision тоже надо указывать в некоторых потоках.
2) в PlazaStreamManager void Run()
Не обрабатывает состояния типа DS_STATE_ERROR или DS_STATE_CLOSE, те в случае чего будет затык и поток будет висеть закрытым или с ошибкой.
Я для себя брал реализацию с примера(могу выложить если что)
PS У меня несколько сместились приоритеты - придется задержаться на квике, но постораюсь не пропадать.

Теги:


Спасибо:


< 1 2 3 4 5  > >>
Mikhail Sukhov

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


aspirant
Dictionary отсортировал бы свои элементы по алфавиту (ключи ведь string).


Ты путаешь с SortedDictionary. И то там не по алфавиту... Это хеш алгоритм. Там сортировка не нужна. Группировка значения идет по хэшу ключа. Соответственно, когда обращаемся по ключу, сначала берется его хэш (PlazaColumn.GetHashCode) и получаются все значения, соответствующие хэшу. Операция O(1). И далее, если у нас коллизия, перебором всех ключей идет сравнение (PlazaColumn.Equals) и находится первый попавшийся (ага, уникальность там не проверяется).

Итого, в лучшем варианте O(1). В худшем O(n). Но чтобы добиться последнее, надо еще постараться.[smile]
Спасибо:

aspirant

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


Mikhail Sukhov
aspirant
Dictionary отсортировал бы свои элементы по алфавиту (ключи ведь string).


Ты путаешь с SortedDictionary. И то там не по алфавиту... Это хеш алгоритм. Там сортировка не нужна. Группировка значения идет по хэшу ключа. Соответственно, когда обращаемся по ключу, сначала берется его хэш (PlazaColumn.GetHashCode) и получаются все значения, соответствующие хэшу. Операция O(1). И далее, если у нас коллизия, перебором всех ключей идет сравнение (PlazaColumn.Equals) и находится первый попавшийся (ага, уникальность там не проверяется).

Итого, в лучшем варианте O(1). В худшем O(n). Но чтобы добиться последнее, надо еще постараться.[smile]


Да, насчет сортировки я был не прав.
Спасибо:

Mikhail Sukhov

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


aspirant
Я изменил класс PlazaListener. Посмотри, пожалуйста, нужны твои комментарии + желательно кусок псевдокода - твое видение, как пользователь создает таблицу с набором колонок для передачи ее в PlazaListener.


Посмотрел и доделал кое-что.

Рассмешило название PlazaPartColumns. Долго думал, что за "часть". Оказалось, это Партфэл, дарагой!

Что осталось до переделать:

  1. Сейчас PlazaListener создается в самом начале со всеми колонками. Как я уже писал, использовать надо только те колонки, что определены схемами PlazaTable.Columns.
  2. PlazaListener выглядит как лишний класс (возможно, что в него потом будет засунута еще какая-то логика, если да, то какая?). Что он делает сейчас. Берет данные из PlazaStream и передает их в PlazaTrader. Тоесть, такой бюрократически посредник, который бумажки из стола на стол несет.
  3. enum TableName лучше сделать статическим классом со строковыми константами. Я так понял, такие безобразные названия нужны лишь для того, чтобы ini файлы создавать? Если да, то по логике простой. Мы создаем текстовый файл, используем string. Вся логика в имени полей TableName - приведение в string... Так может тогда сразу сделать string?
  4. Давайте подумаем насчет фильтрации. Сейчас это выглядит как то не очень. Аспирант, ты же вроде как уже что-то делал по фильтрам?
  5. PlazaSchemaParser предлагаю упрятать в PlazaTableSerializer.

Спасибо:

skuvv

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


aspirant
skuvv

К примеру я сравнил проект со своей старой программой plaza2, данные в текущий s# проект поступают медленнее на 6-10мс(время снимал с OnNewSecurityChanged к примеру).


Получается, ты делал свою реализацию PlazaTrader?

Нет у меня не интерфейс как в s#, а напрямую работа c потоками и событиями
Спасибо:

Mikhail Sukhov

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


skuvv
aspirant
skuvv

К примеру я сравнил проект со своей старой программой plaza2, данные в текущий s# проект поступают медленнее на 6-10мс(время снимал с OnNewSecurityChanged к примеру).


Получается, ты делал свою реализацию PlazaTrader?

Нет у меня не интерфейс как в s#, а напрямую работа c потоками и событиями


Может выложить это ввиде отдельного теста для сравнения перфоманса? Насчет OnNewSecurityChanged - конечно. Если вместо поиска по словарю устраивать Exist Find и т.д., то я не удивлюсь и пол минутными задержками.[smile]
Спасибо:

aspirant

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


Mikhail Sukhov
Сейчас PlazaListener создается в самом начале со всеми колонками. Как я уже писал, использовать надо только те колонки, что определены схемами PlazaTable.Columns.

Как клиентский код создает таблицу с колонками и схемами? Твое видение с куском кода.

Mikhail Sukhov
enum TableName лучше сделать статическим классом со строковыми константами. Я так понял, такие безобразные названия нужны лишь для того, чтобы ini файлы создавать? Если да, то по логике простой. Мы создаем текстовый файл, используем string. Вся логика в имени полей TableName - приведение в string... Так может тогда сразу сделать string?

Этот enum был служебным, для внутреннего пользования. Клиенту его можно не показывать. Зачем я его сделал? Когда нужно набить пару десятков классов, enum + intellisense здорово помогает. Потом подстраховка от случайное опечатки в string. Сам я его не набивал: вместо этого пропарсил папку со всеми схемами.

Вообще PlazaTable сейчас и есть то, что ты предлагаешь. За исключением полей метаданных все остальные методы закомментены (причем, делал это не я). Можно сделать вот так:
Код
// вместо: public TableName SystemName { get; private set; }
public string SystemName { get{ _systemName.ToString(); }


Mikhail Sukhov
Давайте подумаем насчет фильтрации. Сейчас это выглядит как то не очень.

Я вообще собирался это делать внутри PlazaListener, но пока думал, skuvv успел привинтить свой фильтр[smile]. Что насчет методов RegisterSecurity/UnRegisterSecurity? С помощью них будем включать фильтрацию или они нужно для чего-то другого?

Mikhail Sukhov
PlazaSchemaParser предлагаю упрятать в PlazaTableSerializer

Сделаю, когда устаканится модель метаданных. С тех пор как я написал PlazaSchemaParser, модель уже раза-три менялась, и я решил отложить доделку этого класса на самый конец.
Спасибо:

skuvv

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


Mikhail Sukhov
skuvv
aspirant
skuvv

К примеру я сравнил проект со своей старой программой plaza2, данные в текущий s# проект поступают медленнее на 6-10мс(время снимал с OnNewSecurityChanged к примеру).


Получается, ты делал свою реализацию PlazaTrader?

Нет у меня не интерфейс как в s#, а напрямую работа c потоками и событиями


Может выложить это ввиде отдельного теста для сравнения перфоманса? Насчет OnNewSecurityChanged - конечно. Если вместо поиска по словарю устраивать Exist Find и т.д., то я не удивлюсь и пол минутными задержками.[smile]

Код

void m_conn4_StreamDataInserted(CP2DataStream stream, String tableName, CP2Record rec)
{
try
{
if (stream.StreamName == streamFutCommonID)
{
int index = instruments.GetIndex(rec.GetValAsLong("isin_id"));
if(index>=0)
{
double best_sell = Convert.ToDouble(rec.GetValAsVariant("best_sell"));
double best_buy = Convert.ToDouble(rec.GetValAsVariant("best_buy"));
if (best_buy != 0 && best_sell != 0)
{
instruments._bestask[index] = best_sell;
instruments._bestask_vol[index] = rec.GetValAsLong("amount_sell");
instruments._bestbid[index] = best_buy;
instruments._bestbid_vol[index] = rec.GetValAsLong("amount_buy");
instruments._lasttrade[index] = Convert.ToDouble(rec.GetValAsVariant("price"));
instruments._lasttrade_vol[index] = rec.GetValAsLong("amount");
instruments._lasttrade_time[index] = Convert.ToDateTime(rec.GetValAsString("deal_time"));
instruments._bidask_time[index] = DateTime.Now;

curr_rev_futcommon = rec.GetValAsLong("replRev");

log_buffer.Add(t4.Name, rec.GetValAsString("replID") + ";" + rec.GetValAsString("replRev") + ";" + instruments._isin_id[index] + ";" + instruments._bestask[index] + ";" + instruments._bestask_vol[index] + ";" +
instruments._bestbid[index] + ";" + instruments._bestbid_vol[index] + ";" + instruments._lasttrade[index] + ";" + instruments._lasttrade_vol[index] + ";" + instruments._lasttrade_time[index].ToString(timefmt) + ";" + rec.GetValAsString("deal_count") + ";" + rec.GetValAsString("pos"));
}
}
}
}
catch (Exception e)
{
log_buffer.Add("error", "[" + t4.Name + "] " + e.ToString());
}
}

Event datainserted
Все типы таблицы я получал в соответсвующих им win thread.
Событий никаких нет [biggrin], заполняется статик массив instruments,а роботы на каждом прогоне его чекают.
Ну и в конце запись в текстовики, через самописный логгер.
ps фильтрация опять же массиву instruments
Спасибо:

Mikhail Sukhov

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


aspirant
Mikhail Sukhov
Сейчас PlazaListener создается в самом начале со всеми колонками. Как я уже писал, использовать надо только те колонки, что определены схемами PlazaTable.Columns.

Как клиентский код создает таблицу с колонками и схемами? Твое видение с куском кода.


Взял за основу отсюда:

Код
PlazaTableRegistry.FutCommon.Columns.Add(PlazaColumnRegistry.FuturesCommon.CurKotir);

PlazaTableRegistry.FutAggr5.Columns.Add(PlazaColumnRegistry.FuturesAggregation5.Moment);


aspirant

Mikhail Sukhov
enum TableName лучше сделать статическим классом со строковыми константами. Я так понял, такие безобразные названия нужны лишь для того, чтобы ini файлы создавать? Если да, то по логике простой. Мы создаем текстовый файл, используем string. Вся логика в имени полей TableName - приведение в string... Так может тогда сразу сделать string?

Этот enum был служебным, для внутреннего пользования. Клиенту его можно не показывать. Зачем я его сделал? Когда нужно набить пару десятков классов, enum + intellisense здорово помогает. Потом подстраховка от случайное опечатки в string. Сам я его не набивал: вместо этого пропарсил папку со всеми схемами.


Ок, не поняли друг друга. Тогда ремарка и код. Если enum используется для задания строковых констант, то используется класс со строками:

Код
static class TableName
{
public const string BaseContractsParams = "base_contracts_params";
..
}

public static PlazaTable FutAggr50 = new PlazaTable(TableName.BaseContractsParams, ReplicationStream.FutAggr50, "Фьючерсы: стакан глубиной 50 котировок");


На этом примере сразу видно недостаток именования перечислений (не ReplicationStreams, а ReplicationStream). Сходу кажется, что идет работа с потоком. А на самом деле к потокам это имеет о посредственное значение.

aspirant

Вообще PlazaTable сейчас и есть то, что ты предлагаешь. За исключением полей метаданных все остальные методы закомментены (причем, делал это не я). Можно сделать вот так:
Код
// вместо: public TableName SystemName { get; private set; }
public string SystemName { get{ _systemName.ToString(); }



Не понял, что за рокировка.

aspirant

Mikhail Sukhov
Давайте подумаем насчет фильтрации. Сейчас это выглядит как то не очень.

Я вообще собирался это делать внутри PlazaListener, но пока думал, skuvv успел привинтить свой фильтр[smile]. Что насчет методов RegisterSecurity/UnRegisterSecurity? С помощью них будем включать фильтрацию или они нужно для чего-то другого?


Да, именно включение фильтра. Во всех АПИ (и я думаю в Плазе тоже рано или поздно сделают), фильтрация идет на серверной стороне и этот фильтра изменяется через методы, аналогичные Register Unregister.
Спасибо:

aspirant

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


Mikhail Sukhov
Код
PlazaTableRegistry.FutCommon.Columns.Add(PlazaColumnRegistry.FuturesCommon.CurKotir);

PlazaTableRegistry.FutAggr5.Columns.Add(PlazaColumnRegistry.FuturesAggregation5.Moment);


Вопросы:
  1. То есть мы исходим из того, что клиент подписывается на каждый поток только один раз? Напоминаю, у Плазы можно подписываться на один поток несколько раз. Клиенты не будут спрашивать? Когда проект будет зарелизен, изменить архитекутру будет сложно.
  2. Что делать с нашими стандартными потоками, которые нужны, чтобы мапить объекты. Мы договорились, что их скроем от клиента, чтобы гарантировать в них нужный набор колоннок. Придется все равно создавать какие-то отдельные таблицы.


Mikhail Sukhov
Если enum используется для задания строковых констант, то используется класс со строками:
Код
static class TableName...


OK, сделаю после фильтрации. Сейчас все работает, а это рефакторинг функционала не добавит, только эстетику.

Mikhail Sukhov
Не понял, что за рокировка.

Теперь она уже не нужна.

Mikhail Sukhov
На этом примере сразу видно недостаток именования перечислений (не ReplicationStreams, а ReplicationStream)


Не знаю, дело вкуса. Я уже привык к единственному числу. Вот, кстати, MSDN'овский guideline.
Спасибо:

Mikhail Sukhov

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


aspirant

Вопросы:
  1. То есть мы исходим из того, что клиент подписывается на каждый поток только один раз? Напоминаю, у Плазы можно подписываться на один поток несколько раз. Клиенты не будут спрашивать? Когда проект будет зарелизен, изменить архитекутру будет сложно.
  2. Что делать с нашими стандартными потоками, которые нужны, чтобы мапить объекты. Мы договорились, что их скроем от клиента, чтобы гарантировать в них нужный набор колоннок. Придется все равно создавать какие-то отдельные таблицы.



1. Давай еще раз обсудим. С точки зрения практики - зачем это нужно?
2. Хм, а почему бы просто не оставить как есть сейчас?
Спасибо:
< 1 2 3 4 5  > >>

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

loading
clippy