Фичи:
- Я решил полностью пересмотреть подход с экспортом произвольных таблиц. В ранних версиях принцип работы строился на использовании события ProcessWellKnownDdeData, через которое в программу поступали массивы данных, представляющие собой строчки таблиц. Теперь, через специальное преобразование данных QuikTrader сам отдает готовые бизнес объекты. Вся магия заключается в методе QuikTrader.AddCustomTableMapping и событие QuikTrader.ProcessCustomTable. Подробнее в документации. В качестве демонстрации приведу два куска кода. Сверху новый подход, снизу старый. Решение задачи одно и тоже - экспорт портфеля:
this.Trader.AddCustomTableMapping(typeof(CustomPortfolio)); this.Trader.ProcessCustomTables += (type, objects) => { // нас интересует только CustomPortfolio if (type == typeof(CustomPortfolio)) _portfolioWindow.Portfolios.AddRange(objects.Cast<CustomPortfolio>()); };
this.Trader.ProcessUnknownDdeData += (name, rows) => { // узнаем, что пришедшие данные отвечают за портфель if (string.Compare(name, "portfolio", true) == 0) { foreach (var row in rows) { var client = (string)row[0]; var portfolio = _portfolioWindow.Portfolios.FirstOrDefault(p => p.Client == client); if (portfolio == null) { portfolio = new Portfolio { Client = client }; _portfolioWindow.Portfolios.Add(portfolio); } portfolio.Shorts = (double)row[1]; portfolio.Longs = (double)row[2]; portfolio.Collateral = (double)row[3]; portfolio.Margin = (double)row[4]; portfolio.Money = (double)row[5]; portfolio.PnL = (double)row[6]; } } }
Результат, как говорится, не лицо.
- Переделал и ProcessWellKnownDdeDataa. Теперь вообще не нужно использовать данное событие. Достаточно лишь расширить таблицу в Quik и задать необходимые колонки в коде. Все будет экспортироваться само. Подробное описание.
- По следам этого топика переделал процесс обработки данных. Теперь, если на какой-то строчке таблицы происходит затык (например, как часто это бывает, появился инструмент, у которого отсутствует что-то необходимое), то это не приводит к остановке всего экспорта. Вместо этого такая строчка просто пропускается, а ошибка выводится через ProcessDataError.
- Для предыдущего пункта добавил DdeSecurityColumns.LastTradeVolume2.
- Внимание! Колонка DdeSecurityColumns.LastChangeTime по умолчанию выключена для экспорта. Это важное изменения я сделал из-за двух причин. Первая, не все торгую на нескольких рынках одновременно. Вторая, из-за пункта 4 (для единообразия, если кто-то торгует на нескольких рынках, то он должен включать для себя необходимые колонки). Так что, теперь колонка с временем последней сделки только одна (по-умолчанию).
- В дистрибутиве теперь идут три файла настроек Quik: info_rts.wnd, info_micex.wnd и info_rts_micex.wnd (совмещает первое и второе). Названия говорят сами за себя. Подробнее, об этом я написал в переделанной документации.
- Теперь QuikTrader умеет экспортировать позиции (Position). Ранее это был внутренний класс для SmartTrader. Теперь и для Quik. Соответственно, добавил и функционал для работы с позициями - ITrader.Positions, ITrader.NewPositions и Trader.PositionsChanged. Подробнее, как включать экспорт по позициям, описал в документации.
- Делая предыдущий пункт, я дополнительно реализовал экспорт портфелей и для QuikTrader. Сам по себе экспорт данных не идет (для этого все также нужно делать экспорт самостоятельно, как я показал в примере SampleDdeCustomTable), но сама сущность с номером счета создается и выводится через ITrader.NewPortfolios.
- Для Position и для Portfolio создал методы расчета PnL TraderHelper.GetPnL.
- Дополнительно, для удобства получения позиций добавил возможность получать их по инструменту или портфелю через метод ITrader.GetPositions.
- Убрал событие MarketDepth.Changed и заменил его двумя: MarketDepth.QuotesChanged, которое показывает, какие именно котировки внутри стакана изменились, и MarketDepth.DepthChanged, которое говорит об изменении глубины стакана.
- Добавил возможность сохранять и загружать настройки таблиц через методы DdeTable.Save и DdeTable.Load. Это удобно в тех случаях, если программа распространяется среди пользователей.
- Внедрил код получения времени сервера как написали здесь. В принципе, теперь необходимость для QuikTrader в MarketTimeOffset отпала. Спасибо HaMMeR-у!
- Сделал возможность менять у уже созданного QuikTrader путь к Quik - QuikTrader.Path. Аналогично сделал и для SmartTrader с Address, Login и Password. Одно но. Перед изменениями необходимо сделать Disconnect(если было произведено соединение). Иначе, будет выбрасываться исключение.
- Добавил интерфейс IExtendableEntity, в которое есть только одной свойство ExtensionInfo. Сделал это для удобства работы в написании универсального кода, который работает с любой торговой сущностью.
- Для SmartTrader добавил специальное перечисление - Extensions. Это ключ, по которому можно получить специфичную для SmartCOM данные из ExtensionInfo.
- Опять по DDE. Теперь название категорий (в Quik это называется Рабочая книга) указывается такое же, как и DdeTable.Caption.
- Наконец-то доделал обещанное - сделал котирование по асинхронному режиму QuikTrader.IsAsyncMode (http://stockmarketdotnet.blogspot.com/2010/03/stock-18.html пункт 1). Автоматически, эта вещь заработала и для SmartTrader, потому что он умеет работать только в асинхронном режиме. Ура!
- Убрал метод Strategy.AddOrder и изменил логику регистрации заявок из стратегий. Теперь регистрировать заявки необходимо через метод Strategy.RegisterOrder, который автоматически после успешного принятия заявки биржей добавляет ее в стратегию. Собственно, в такому случае Strategy.AddOrder стал рудиментом, что и привело к его исчезновению. Замену заявок так же нужно производить через новый метод Strategy.ReRegisterOrder. Собственно, новое котирование как раз и основанно на этих новых методах.
- TraderHelper.ReRegisterOrder теперь исчез - перекочевал в Strategy.ReRegisterOrder.
- Сделал возможность работать с Currency как с обычными числами. Тоесть, можно складывать, вычитать, умножать и делить.
- Добавил в Order поле Portfolio. Пока это как опциональное поле. Но в дальнейшем планирую его сделать обязательным к заполнению, которое заменит собой поле Account (и, надеюсь, строковое представление счета исчезнет навсегда из S#).
- В документации добавил страницу с примерами. Показывает, какие вообще есть примеры, и что они делают (цель их обучения).
- Специально запрятал в самый конец, чтобы меньше сил на протесты осталось =). Переделал состояние заявок. Понятно, что изменение значительное (пожалуй, самое часто использующееся свойство). Но прогресс должен быть, и рудименты должны исправляться. Иначе библиотека зарастет архаизмами... Есть только три свойства - None, Active и Done. Все. Именно они однозначно говорят о состоянии заявки, жива или нет. Если нужно узнать, исполнена или отклонена, то пункт 25.
- Для отслеживания того, полностью ли исполнена заявка, или частично, или вообще не исполнена надо вызывать методы TraderHelper.IsMatched, TraderHelper.IsFilledPartially и TraderHelper.IsFilledEmpty соответственно. Если нужно узнать, отменена ли была заявка, то нужно вызывать метод TraderHelper.IsCanceled. С учетом пункта 24 у нас вместо прежних 4-ех состояний (напомню, было None, Active, Matched и Cancelled) теперь есть комбинации. Намного информативнее.
И, конечно же, фиксы:
- DDE экспорт не запускается, если открыта другая закладка с развернутым графиком во весь экран.
- Исправил старую "добрую" ошибку с запуском экспорта. Иногда он не запускался с первого раза. Причина - окно с запуском DDE в Quik не всегда быстро появляется. Теперь гарантированно дожидается появление данного окна. Экспорт стартует чуть дольше, зато гарантированно работает.
- Пофиксил в MarketDepth неправильный порядок вывода котировок.
- Исправил ошибку с отсутствием регистрации новой заявки в котировании.
- В том же топике, что и в пункте 4 была проблема с буферизацией вывода логов через StrategyLogger. Буферизацию убрал - теперь все выводится сразу.
- Снятие группу заявок в асинронном режиме не всегда работает.
Итого, 25 нововведений и 6 фиксов. Неплохо, неплохо.
отлично!
ОтветитьУдалитьЗаставляете Вами восхищаться! :)
ОтветитьУдалитьПостоянно слежу за развитием.
Пока еще не пользуюсь возможностями Вашего проекта но все больше этого хочу.
Спасибо!
Вопрос 1: есть ли возможность с помощью Вашего проекта реализовать приложение с набором роботов (примерно так как это сделано в ЛивТрейд СДК)? либо как заставить несколько роботов работать с одним квиком?
Вопрос 2: как можно помочь проекту?
Большое спасибо. Ваша библиотека просто жизнь спасла )
ОтветитьУдалить