Показаны сообщения с ярлыком C#. Показать все сообщения
Показаны сообщения с ярлыком C#. Показать все сообщения

среда, 4 мая 2011 г.

Stock# 3.1

Дамы и господа - новая версия! Бета тест был пройден успешно и давайте я расскажу вам о новых плюшках и исправленных сухарях.

Основная фича релиза - это поддержка опционной модели. В релизе представлены алгоритмы для работы с моделью Блэке-Шоулза, алгоритмы котирования по волатильности и дельта-хеджирование, а так же работа с синтетическими позициями. То, что предлагается за деньги в ряде программ, у нас бесплатно. =)

Помимо опционов были сделаны еще ряд интересных фич:
  1. S# теперь использует тип decimal. Он предотвращает ряд неприятных моментов с неправильным округлением, присущие использованию double.
  2. Пункто-цифровой график (крестики-нолики).
  3. Рассчет проскальзывания для стоп-заявок.
  4. Котирование теперь само решает, как переставлять заявку.
  5. Метод GuarantyCancelOrder объявлен устаревшим.
  6. Появились критерии остановки стратегии по ошибке (например, продолжать работу в случае возникновения ошибки в алгоритме). Для этого используются новые свойства Strategy.ErrorCount и Strategy.MaxErrorCount.
  7. Словообразование TimeShift заменено на Emulation в названиях некоторых классов. Для более четкого отражения смысла.
  8. Новые методы у Strategy для записи логов AddInfoLog, AddWarningLog и AddErrorLog.
  9. Добавлен SecurityIdGenerator для возможности изменения алгоритма генерации Security.Id. Напомню, сейчас для РТС идентификатор равен Код@RTS. Для ММВБ - Код@Класс.
  10. Возможность рассчета отрицательного проскальзывания.
  11. Новое свойство ActionRule.Name для удобства просмотра в логах какое именно правило была активировано.
  1. Новая струстура базы данных. Если уже работает Гидра версии 3.0, то нужно запустить скрипт миграции trading_diff.sql. Для тех, кто начнет пользоваться Гидрой впервые, этот скрипт не нужен, и нужно использовать trading.sql.
  2. Поддержка миллисекунд, что обеспечивает еще большую точность для тестирования на истории. Плюс к этому, теперь данные качаются аж с 2003-го года.
  3. Расширенная поддержка РТС Стандарт.
  4. Возможность редактирования инструментов.
  5. Фильтр для внесистемных сделок РТС.
Quik
  1. Увеличение скорости запуска и остановки DDE экспорта.
  2. Увеличение скорости метода запуска Quik.
  3. Изменены настройки экспорта стакана (рекомендуется из закрыть в Quik-е, потому что у них теперь новый заголовок).
SmartCOM
  1. Поддержка версии от 29.03.2011.
  2. События SmartComWrapper лучше задокументированы.
Исправленные баги:

Особо хочу отметить тот факт, что эту версию помогали делать Михаил Миткевич и Александр Shurik Муханчиков.

четверг, 17 марта 2011 г.

Stock# 3.0

После продолжительного тестирования бета версии 3.0 спешу всех обрадовать - релиз готов! Те, кто еще не решился сделать upgrade с предыдущих версий, можете смело брать.

Для тех, кто пока еще не знаком с Stock# и чем знаменательная эта версия.

Stock# - это бесплатная платформа для программирования на C# роботов, где максимально скрыты технические детали. Трейдер, программирующий на Stock#, сосредоточен только на ключевых моментах - самих торговых действиях. И не нужно в сотый раз спрашивать, как подключиться к Quik и как работает SmartCOM. А так же плюс в том, что код робота с минимальными изменениями можно перенести с одной платформы на другую.

Версия 3.0 теперь позволяет тестировать роботов, написанных на Stock#. То, что раньше требовало неповоротливых и дорогих программ в виде MetaStock, Ami, WealthLab, NinjaTrader и т.д., теперь бесплатно.

А теперь традиционный список изменений для тех, кто будет переходить на новую версию:

Стратегии и алгоритмы
  1. Собственно, тестирование стратегий через шлюзы HistoryTestTrader, RealTimeTestTrader и EmulationTestTrader. Подробнее, в документации.
  2. Гидра - программа для скачивания маркет-данных (сделки + стаканы) для последующего прогона стратегий по ним.
  3. API для работы с хранилищем данныхГидра его как раз использует. Позволяет сделки и стаканы сохранять во внутренний формат. Формат очень компактный и ориентирован как раз на маркер-данные. По сравнению с БД сжатие ~ в 15-20 раз.
  4. StrategyManager теперь имеет методы Start, Stop, Pause и Resume.
  5. Методы IsFullEmpty и IsHalfEmpty для определения наполненности стакана. 

Quik
  1. Сокращенная таблица инструментов. Теперь имеет всего несколько колонок. Поэтому, у Security значения BestBid и BestAsk теперь инициализируются только когда запущен экспорт стакана. Так же и с LastTrade - нужен экспорт по таблице всех сделок.
  2. Добавил экспорт портфелей.
  3. Код клиента в таблицах заявки и стоп-заявки.
  4. Возможность получить список адресов серверов, а так же указать, на какой конкретно адрес нужно произвести подключение.
  5. Переделал работа с экспортом произвольных таблиц.


SmartCOM

  1. SmartComWrapper.
  2. SmartExtensionInfoHelper для получения Smart-овской информации из торговых объектов.
  3. Вагон и маленькая тележка фиксов. Стало стабильнее работать благодаря фидбекам.


Общее
  1. Добавил свойство ITrader.OrderFails для получения всех ошибочных заявок.
  2. Класс WorkingTime для указания расписания работы.
  3. Метод ICandleManager.GetLastCandle для получения текущей свечки.
  4. Методы поиска торговых объектов по критериям переместил из ITrader в TraderHelper и называются теперь они Filter.
  5. Появилась возможность создавать свои собственные торговые объекты через IEntityFactory. Вместо того, чтобы писать такой код:

    var riXXX = base.Trader.Securities.First(s => s.Code == "...");
    var thPrice = (double)riXXX.ExtensionInfo[DdeSecurityColumns.TheorPrice];
    var thPrice = (double)riXXX.ExtensionInfo[DdeSecurityColumns.Volatility];

    Теперь можно написать более изящно:

    var riXXX = (Option)base.Trader.Securities.First(s => s.Code == "...");
    var thPrice = riXXX.TheorPrice;
    var thPrice = riXXX.Volatility;
  6. Переход на формат Excel 2007 в отчетах.
  7. Улучшенная работа Unit.
Всех исправлений и улучшений я не стал описывать, слишком уж много получилось. Но я думаю этого будет достаточно, чтобы для себя окончательно решить в пользу Stock# 3.0. Пользуйтесь!

вторник, 21 сентября 2010 г.

Quik2Quant 1.0 beta release!

Полнофункциональный адаптер, обеспечивающий абсолютную интеграцию ИТС QUIK и последней версии передовой программы квантового анализа OpenQuant 2.9.7. Такая связка позволяет обеспечить полный комплекс решений на фондовом рынке, включая, но не ограничиваясь:
  • тестирование торговых стратегий на исторических данных;
  • реализацию любых в том числе самых изощренных торговых стратегий;
  • мгновенное получение любой необходимой информации из ИТС QUIK;
  • накопление и хранение информации о состоянии стаканов, котировок и сделок по множеству инструментов в режиме реального времени;
  • исполнение ваших стратегий в режиме реального времени;
  • отсутствие задержек в выставлении/снятии заявок;
  • контроль текущей позиции, изменения позиции, частичного исполнения, снятия заявки, качества исполнения;
  • … 
Интеграция OpenQuant и QUIK основана на событийной модели рынка и обеспечивает возможности быстрого создания и изменения торговых роботов, работу на любом таймфрейме и инструменте.
Решение, в настоящее время, не имеет аналогов на российском рынке и предоставляет неоспоримые преимущества создателям механических торговых систем высокого уровня.

Главное окно программы выглядит следующим образом:

В этом окне мы можем получить любую необходимую рыночую информацию из терминала QUIK. Однако самую большую ценность представляют иные возможности OpenQuant, которые делают его практически универсальным продуктом для создания роботов. Итак
1. График сделок по SRZ0 (1min) - встроенная стратегия SMA Crossover:

2. Ордера по стратегии и результаты их исполнения:

3. Контроль состояния счета в режиме он-лайн:

И это еще малая толика всех возможностей OpenQuant и QUIK. Более подробно с программой и предлагаемыми решениями можно ознакомиться тут & там
Посмотреть обучающее видео, чтобы узнать еще больше можно тут
Поинтересоваться как начать использовать продукт можно здесь.

понедельник, 13 сентября 2010 г.

Сравнение TOP5 API для роботов.

Наконец, выпустил новый релиз S#, и настало время для написания беллетристики. Я уже писал подобные заметки о том, для чего нужен робот, чем он может пригодится вообще. Теперь я решил написать о том, какой API лучше выбрать для робота. Заметьте, именно для тех, кто пишет (+ собрался писать) на API, а не использует ТА программы. О последних и так достаточно написано и без меня.

Я сознательно не пишу данный пост для тех, кто программирует на S#. А для тех, кто любит самостоятельно вникнуть в проблемы системного программирования (именно системного, потому что разбираться, скажем, с TRANS2QUIK.dll это вовсе не программирование робота, как многие думают =) ). Конечно, мне до сих пор не понятно, как людям не жаль своего времени, но я хочу поделиться и с ними своим опытом работы (пусть даже с готовым решением).

И так, сравнение будет производиться между следующими API:
  1. Quik API
  2. SmartCOM
  3. Alfa Direct
  4. Alor COM
  5. Plaza2
.... и по следующим категориям:
  1. Сложность освоения
  2. Полнота данных
  3. Поддержка
  4. Распространенность
  5. Уровень документации
  6. Стабильность и ошибки
Все нижеописанное - мое личное мнение, основанное на использовании всех этих продуктов. Подчеркиваю, я не являюсь сторонником какой-то одной из API, и старался сделать вывод независимым.

И так, сначала опишу вкратце основные черты каждой из API.
  1. Quik API. По определению - это trans2quik.dll. По факту, это еще и собственный DDE сервер. Все потому, что обратная связь через API практически отсутствует. Приходится делать ну очень много работы. Поддержка отвечает стабильно, по плану. Документация сносная.
  2. SmartCOM. Ребята стараются, делают, но пока все плохо. Плохо в плане стабильности. Документация лучше, чем у Квика, да и использование много проще. Но вот данных - просто не достаточно. Если писать робота, нужно использовать внешние источники. Поддержка - самая лучшая.
  3. Alfa Direct. Похож на SmartCOM, только работает значительно стабильнее. Но. Поддержка отсутствует вообще как таковая. Я бы сказал, на любителей.
  4. Alor COM. Разобраться очень сложно. Пожалуй, сложнее только Plaza2. Документация нормальная (при таком запутанном API это большой плюс). Поддержка еле живая. Летом ее не было вообще.
  5. Plaza2. Такое же запутанное API как у Alor, только еще плюс к тому, что через данный API нужно посылать еще и специальные сообщения. Количество параметров компилятором не ограничивается, поэтому получается некий квест с разбором документаций (а их читать надо сразу как минимум две). Думаю, если нет хотя бы пару лет в программировании, можно даже в эту сторону не смотреть. Поддержка хорошая.

Получившаяся итоговая таблица (отмечал как с школе советских времен - от 1 до 5):

Quik SmartCOM Alfa Direct Alor COM Plaza2
Сложность освоения45321
Полнота данных51445
Поддержка45124
Распространенность53221
Уровень документации35432
Стабильность и ошибки41335
Итог2520171618

Я не удивлен полученным двум лидерам. Они вечно дышат друг другу в спину. Но и какого-то явного отрыва от других API не видно. Рынок постоянно будет модернизироваться, брокера предлагать все больше своих услуг, и все эти цифры будут стремиться к одному общему числу.

Вместо заключения хочу отметить, что в этой таблице все-таки нужно смотреть не на итоговые значение, а как конкретные цифры. Скажем, Alfa победила Alor. Но, если вы новичок, то из-за пункта "поддержка" вам путь заказан. Или другой вариант. Вы, наоборот, профи. Тогда при всей своей усредненности можно попробовать и Plaza2. Или, если взять мой жизненный пример, я не смог написать один из своих роботов на SmartCOM, потому что по нему невозможно было получить необходимые данные по опционным контрактам.

Дерзайте!

пятница, 3 сентября 2010 г.

Stock# 2.4

Вышла внеочередная версия S#. Внеочередная, потому, что перескочили 2.3, и в новость выходит 2.4. Получилось это в следствии непрерывных фидбеков и баг реквестов, за что отдельное спасибо Alexander и Tauler. Не успела зарелизиться версия 2.3, как поступили дополнительный запросы, и пришлось переделывать сразу на 2.4.

Очень хорошо, что поступает такое количество отзывов. Потому как это сильно помогает улучшать S#, делая его и быстрее и стабильнее. Тем более, что основная черта S# от тех технологий, что он оборачивает в себя (напомню, это и Trans2Quik.api и DDE и SmartCOM), это быстрая реакция. Согласитесь, на рынке ПО для трейдинга не так много подобных библиотек для роботов, которые развиваются такими же темпами, как S#.

Но у быстрого развития есть и обратная медаль - это ошибки, которые могут возникнуть (и возникают) при разработке. Поэтому, этот релиз посвящен именно стабильности S#, а не функциональному расширению. Все как в трейдинге, есть импульс, и есть коррекция. Сегодня у нас коррекция.

Поэтому, традиционный список изменений начинается именно с устраненных ошибок.
  1. Улучшена производительность StrategyLogger (который теперь называется FileStrategyLogger) и исправлена ошибка с параллельной записью в файл разными стратегиями.
    Огромная благодарность Иванову Андрею, который далее в топике расписал все особенности работы с файлами. Можно смело утверждать, что в S# завелся профи. Жаль, появляется только по ночам =).
  2. Переделан экспорт портфелей. Теперь информация о счетах берется не из таблиц с позициями, а напрямую из Quik в разделе управление счетами. Это предотвратило ошибку, когда при отсутствии позиций не экспортировалась информация по портфелям.
  3. Исправлена ошибка с необновлением нетокорых параметров Security. Теперь Security обновляется всегда.
  4. Исправлена ошибка при регистрации заявки через MultiTrader
  5. Исправлена ошибка в методе Strategy.CancelActiveOrders.
  6. Исправлена ошибка в определении времени задержки заявки (TraderHelper.GetLatency).
  7.  Исправлена ошибка в получении времени биржи через Quik при отсутствии соединения.
  8. Исправлена ошибка, когда исполненная заявка на время возврашалась в активное состояние.
  9. Исправлена ошибка в обработке стратегий, превыщающее количество потоков в StrategyManager.
  10. Исправлена ошибка, когда для исполненной заявки менялся баланс. Кстати, очень интересная ошибка, потому как она тянется своими корнями к некорректной передаче данных Quik. Когда он извещает о том, что заявка исполнена, но в то же самое время баланс отличен от 0. Поэтому, в QuikTrader была введена специальная проверка такой ситуации.
  11. Исправлена ошибка в дублировании тиков, получаемых через MultiTrader.Trades.
  12. Исправлена ошибка в ExcelStrategyReport при генерации отчета под Office 2010 (сейчас генерация файлов происходит без использования Excel API).

И, конечно же, есть и нововведения, которые привели к отдельной версии, а не фиксу 2.3.
  1. S# и его примеры переведены на VS 2010. Пока не осуществлен переход на .NET 4.0 по причине не совсем стабильной работы SmartCOM под этой новой версий .NET. Но использовать новое все равно необходимо. Да и скачивать бесплатную среду разработки VS 2008 Express теперь стало проблематичнее. Везде предлагают VS 2010 Exress.
  2. Удалено свойство Order.Account. Все, теперь оно в прошлом. И необходимо использовать Order.Portfolio.
  3. В QuikTrader реализованы методы RegisterTrades и UnRegisterTrades. Эти методы служат для фильтрации потока тиков по инструментам. Проблема в том, что Quik не дает программно управлять этим потоком. Поэтому, данные методы напрямую в Quik-е меняют фильтр инструментов. Сама по себе операция смены инструмента очень тяжелая, и Quik "просыпается" не быстро. Так что, настоятельно рекомендуется менять фильтр перед запуском торговых стратегий. Дополнительно, данные методы по-умолчанию не работают (ничего не делают). Чтобы они начали функционировать, необходимо включить флаг QuikTrader.EnableFiltering. Это специальная защита для тех ситуаций, если кто-то уже в своем роботе вызывал данные методы (например, сделал вызов и забыл про него).
  4. Добавлен метод TraderHelper.GetAveragePrice для вычисления средневзвешанной цены исполнения заявки как просили здесь.
  5. Как уже упомянуто выше, StrategyLogger стал базовым абстрактным классом, и вся его логика работы с текстовым файлом перенесена в FileStrategyLogger. По умомчанию, класс создает синхронизированный текстовый поток TextWriter. Если его скорости будет недостаточно, можно передавать не синхронизированный поток через конструктор FileStrategyLogger(TextWriter). Но это чревато ошибками вида.
  6. Добавлен GuiStrategyLogger, который записывает сообщения от стратегии в специальный класс LogWindow. Может работать в двух режимах: писать все сообщения в одно окно или создавать на каждую стратегию по отдельному LogWindow. Подробнее, в обновленной документации по логированию.
  7. Метод Strategy.Process сделан невидимым из вне, чтобы не было желания его вызвать.
  8. Убран у многих методов TraderHelper аргумент ITrader. Теперь передаваемых параметров стало меньше, и, значит, удобнее использовать.
  9. Метод StrategyLogger.WriteMessage сделан виртуальным, чтобы его можно было перегружать своей реализацией. Например, сейчас в файл не пишется информация о типе сообщения (StrategyErrorStates). Если вдруг кому-нибудь это потребуется, всегда будет возможность это сделать.
  10. Добавлен виртуальный метод StrategyReport.FormatTime для переопределения формата времени в отчетах.
  11. Добавлен адрес демо сервера SmartCOM - SmartAddresses.Demo.
  12. Для предыдущего пункта добавлен специальный визуальный контрол SmartAddressComboBox для выбора сервера. Он уже используется в примерах. Вот как выглядит теперь SmartSample:
  13. SmartTrader.RegisterPortfolio теперь вызывается автоматически при появлении в системе портфеля.
  14. Добавлена дополнительная проверка на Security.MinStepSize в метод TraderHelper.ShrinkPrice, чтобы предотвратить ситуацию, аналогичную этой.
  15. Добавлен метод QuikTrader.Initialize, который инициализирует соединение с окном Quik, чтобы позволить работать с экспорт DDE без подключения к серверу торгов. Такое соединение позволяет манипулировать Quik-ом, запуская, к примеру, экспорт DDE.
  16. Переделан метод QuikTrader.ReRegisterOrder, чтобы стало возможным перерегистрировать заявки на ММВБ через снятие и новую регистрацию.
  17. Переделано событие ITrader.QuotesChanged, чтобы он передавал коллекцию стаканов. Для аналогии с другими событиями, а так же для будущих систем, передающие потоком данные сразу по нескольким стаканам.
  18. Добавлены два события MarketDepth.UpdatingStarted и MarketDepth.UpdatingFinished для определения, когда стакан начал обновляться, и когда закончил. Имеет смысл использовать в работе с SmartTrader, так как там стакан обновляется построчно.  
Вот так, исправлена дюжина ошибок и 18 нововведений.

четверг, 29 июля 2010 г.

Stock# 2.2.1

Вышло обновление версии 2.2 до 2.2.1. В него вошли критические исправления работы стратегий, об ошибках которых писалось в группе после выхода 2.2.

В 2.2 было исправлено достаточно много в алгоритмическом части S#. Из-за этого могли случиться ошибки, и они случились. Хорошая новость, в 2.3 будут изменения в ширь, так что такого сложного перехода как на 2.2 ожидаться не должно.

Качаем, проверяем, сообщаем.

понедельник, 12 апреля 2010 г.

Stock# 1.8

Ага, опять не S# 2.0. Сам уже удивляюсь, что можно сделать в рамках одного Quik. Поистине, пределов для автоматизации не существует. Качаем-с.

  1. Главное нововведение в этой версии - асинхронные заявки. Я уже писал в своем посте о том, насколько они быстрее обычных. Поэтому, теперь QuikTrader умеет работать и в асинхронном режиме. Достаточно установить у него свойство IsAsyncMode в true. Более подробно, я написал в документации и показал в примере SampleAsyncTransaction. Кстати, последний выглядит как очень простой, но все же привод. Полезно будет посмотреть тем, кто хочет написать подобное. Но есть и ложечка дегтя. Котирование в асинхронном режиме работать не будет - проверено. Надо полностью переписывать стратегию. С большей вероятностью, это относится к тем стратегиям, которые уже написаны на базе S#.

  2. Добавил события ITrader.OrdersFailed и ITrader.StopOrdersFailed (опять же, для асинхронного режима). Как я уже написал, при синхронном режиме в случае неуспеха QuikTrader бросает исключение. Для асинхронного режима реализовать подобное невозможно, потому что информация по заявке может прийти в любое время. Поэтому, когда она придет, и будет означать не успешную регистрацию, будет вызвано данное событие.

  3. Для асинхронного режима было добавлено свойство QuikTrader.CurrentTransactionId. Первоначально, при создании QuikTrader, оно установлено в значение, равное количеству миллисекунд, прошедшее с начала дня. Для чего сделаны такие хитросплетения. Дело в том, что асинхронный режим, в отличие от синхронного режима, при определении заявки, переданной по DDE, основывается не на номере заявки (Order.Id), а на идентификаторе транзакции (Order.TransactionId). Чтобы обеспечить уникальность данного значение (а оно должно быть строго уникальным), то я сделал эту первоначальную инициализацию. Если у вас ведется какой-то собственный механизм генерации идентификаторов транзакции, то перед самым началом работы необходимо присвоить значение в QuikTrader.CurrentTransactionId. Если же ничего такого нет, то будет достаточно и стандартного поведения.

  4. В предыдущих версиях, в случае не успешной регистрации синхронным способом QuikTrader.RegisterOrder просто возвращал управление, и необходимо было проверять номер заявки (если он нулевой, значит регистрация не была произведена). Теперь, данный метод в синхронном режиме бросает исключение, которое содержит текстовое описание причины.

  5. Наконец-то пункт, не касающийся асинхронного режима... Для Strategy я сделал механизм генерации отчетов. Две реализации: XmlStrategyReport - генерация отчетов в формат Xml, и ExcelStrategyReport - генерация в Excel. Первый удобен, если нужно передавать данные между разными роботами. Или, к примеру, сохранять состояние между сессиями. Я уже писал об этом в пункте 6, что нужен механизм выставления первоначального состояния для стратегий, выходящих за границы интрадей трейдинга. Так вот, Xml формат - это идеальное решение.

    ExcelStrategyReport необходим тогда, когда нужно в конце дня посмотреть, что же робот наторговал, и как именно. Построить графики, проанализировать результат. Особенность ExcelStrategyReport в том, что он умеет работать с файлом-шаблоном. Например, можно настроить в файле-шаблоне формулы, написать макросы, построить графики. А ExcelStrategyReport будет обновлять свежими данными, и весь отчет автоматически будет перестраиваться. Очень удобно.

  6. Добавил давно необходимый метод - ITrader.CancelOrders. Отменяет все активные заявки по определенной маске (инструмент, направление, счет и т.д.). Пригодился, к слову, и в примере SampleAsyncTransactions.

  7. Очень важный пункт. Устранил проблему с ошибкой в конструкторе QuikTrader, когда больше невозможно было пересоздать QuikTrader. На самом деле, это ошибка, скорее следствие неправильного дизайна архитектуры. Не нужно делать автоматическое подключение в конструкторе. Поэтому, теперь метод Connect нужно вызывать отдельно, когда требуется произвести подключение к Квику.

  8. Расширил поддержку РТС Стандарт. Вкратце, проблема с этой площадкой в S# в том, что коды инструментов не уникальны. Но уникальна комбинация код инструмента + класс инструмента. Поэтому, теперь в таких таблицах как Все Сделки, Мои Сделки, Заявки, Стоп-Заявки передается класс инструмента. Более того, теперь и стакан должен иметь новый заголовок КОД-КЛАСС, что так же решает проблему получения стаканов для РТС Стандарт.

  9. Чуть модифицировал предыдущее нововведение (пункт 12). Я переименовал событие QuikTrader.FormatTransactionString в QuikTrader.FormatTransaction, и которое теперь передает не просто строку, а TransactionBuilder. С ним форматировать строку транзакции намного удобнее.

  10. Добавил свойство Strategy.TotalWorkingTime, которое показывает, сколько проработала стратегия. Именно проработала, то есть время простоя, когда стратегия не была запущена, или была приостановлена не учитываются. Только рабочее. Теперь можно следить за операторами (без них роботов пока еще опасно оставлять), сколько они реально наработали за день, и сколько они заработали гонорару.

  11. Добавил еще один тип менеджера - менеджер задержки LatencyManager. Учитывает, как быстро торговая система принимает заявки от робота. Вкратце, при создании заявки в свойство Order.InitializationTime записывается время создания заявки на клиенте (рассчитывается текущее время, так что те, кто находится вне временной зоны с биржей, нужно принудительно в коде изменять временной сдвиг). Как только придет подтверждение регистрации заявки по DDE, менеджер возьмет реальное время Order.Time, и рассчитает общее время задержки. Теперь можно следить и за брокерами, и за интернет-провайдерами, и за теми, кто из них родом из Эстонии.

  12. В предыдущей версии я начал направление кастомизации DDE метаданных. В этой версии я еще больше его расширил, сделал его объектно-ориентированным. Появились классы DdeColumn и DdeColumnList. Последний имеет очень интересное поведение. При добавлении, вставки или удалении колонки он автоматически пересчитывает индексы всех остальных колонок. Подробнее, показал в документации в разделе Модификация стандартных таблиц.

  13. Продолжив реализовывать предыдущий пункт, я сделал QuikTrader.QuotesTable. Аналогично таким настройкам, как QuikTrader.SecuritiesTable, позволяет изменять настройки стакана. Стакан - это довольно интимное место, и многие привыкли использовать допустим биды сверху, офера снизу, наоробот и т.д. Так что, сделал S# чуть дружелюбнее к стакану.

  14. Order.Direction теперь по умолчанию экспортируется. Раньше я думал о том, что это создаст лишнюю нагрузку, но открыв для себя опцию "Формальные названия" и произведя ряд тестов, я убедился - нужно включать по умолчанию экспорт направления заявки у сделки.

  15. Добавил возможность (забытую первоначально мною, но о которой вспомнили здесь) возможность задавать комментарий при регистрации. Свойство Order.Comment существовало, но оно заполнялось только при DDE экспорте, но не использовалось в ITrader.RegisterOrder.

  16. Логи в котирование QuotingStrategy теперь пишутся на русском языке. Просто небольшое улучшение.

  17. К слову о логах. Появился стандартный класс-логгер, который пишет в файл. Называется StrategyLogger. Давно пора было его вынести из своих роботов в S#. Не было бы таких вопросов.

  18. Сделал класс Strategy наследником класса Disposable. Вот тут описано, что такое очищение ресурсов в рамках .NET. Не забывайте их подчищать, если хотите, чтобы робот "жил" долго.

  19. Переделал метод Order.Message в Order.Messages, который теперь есть не просто строка, а коллекция строк. Дело в том, что торговая система в течении жизни заявки может посылать несколько сообщений относительно одной и той же заявки (при регистрации, при снятии, при неудавшемся снятии и т.д.). Логично не перетирать старое значение, а добавлять при этом новое, что и было сделано.

  20. Буквально в самый последний момент исправил ошибку с датами, которая обсуждалась здесь. В кратце. Квик оставляет с таблице всех сделок (да и не только в ней) сделки с предыдущего дня - вечерней сессии. Экспорт DDE, реализованный в S#, не предоставлял возможность получения даты, и учитывал лишь время. Из-за этого, записи вчерашнего дня интерпретировались как сегодняшние. Например, сделка от "1 апреля 19:30" 2-го апреля имела бы дату "2 апреля 19:30". Не очень хорошо. Поэтому, теперь таблицы Все Сделки, Мои Сделки, Заявки, Стоп-Заявки теперь содержат колонку Дата.
Два десятка изменений. S# бурлит.

четверг, 11 марта 2010 г.

Асинхронные заявки

Поделились со мною программой, которая четка показала - асинхронные заявки через Квик быстрее асихнронных заявок через .NET. Поясню, что значит последнее. Допустим, в программе необходимо заложить логику, которая бы мгновенно отправляла заявки на регистрацию, не дожидаясь подтверждения. Такое может потребоваться при написании привода, когда нужно максимально быстро послать запрос и возвратить пользователю управление (иначе GUI будет подтормаживать). Вот как это делается сейчас:
new Action(() => _trader.RegisterOrder(order)).BeginInvoke(null, null);

Довольно быстро. Но одному из пользователей S# потребовалась еще более быстрая скорость, и он попросил добавить поддержку асинхронных заявок в QuikTrader именно через механизм Quik API. Да не просто попросил, а аргументированно-программно доказал всю мою неправоту, прислав тестовую программу. Так как я раньше думал, что регистрация заявок через асинхронный механизм .NET имеет такую же скорость, что и через квиковский. Вот показатель разных способов:

1. Синхронный способ (QuikTrader.RegisterOrder) - 2-3 заявки в секунду.

2. Асинхронный способ .NET (Delegate.BeginInvoke) - 4-5 заявок в секунду.

3. Асинхронный способ Квик - 7-8 заявок в секунду.

Ну что же, придется добавлять асинхронный способ, раз такая разница в скорости, и такой
подход к аргументированию.

среда, 20 января 2010 г.

O Stock# (Ecng.Trading)

Программная библиотека Stock# (старое название Ecng.Trading) предназначена для создания торговых роботов на платформе .NET с использованием программ Quik и SmartCOM. Скачать дистрибутив. Обсуждение ведется по адресу http://groups.google.ru/group/stocksharp.

Преимущества библиотеки:
  • Используется современная платформа .NET с мощным набором функциональности. Нет ограничения в кодировании, которые присутствуют в скриптовых языках.
  • Быстрое обработка алгоритма стратегий. Программа компилируется в машинные инструкции (что дает большой прирост в производительности). Нет синтетических секундных задержек при выполнении алгоритма. Основное ограничение практически всех встроенных языков в таких программах как WealthLab, AmiBroker и т.д.
  • Нет необходимости использовать дополнительное программное обеспечение. Библиотека полностью автономна от сторонних программ.
  • Возможность запуска нескольких сотен одновременно работающих алгоритмов по различным инструментам и тайм-фреймам (скорость зависит только от мощности компьютера, а не от ограничения внешней программы).
  • Возможность реализации скальперских стратегий, с тайм-фреймом менее секунды.

воскресенье, 10 января 2010 г.

Excel4Net.Com - программирование на C# .NET под Excel

В поисках необычного в процессе серфинга по инету наткнулся на интересный проект: Excel4Net. Я уже писал ранее, как ведущие роботоводы разрабатывают свои прораммы в нынешнее время. И программирование под Excel меня не привело в восторг. После ознакомления с данным проектом, я решил пересмотреть свое мнение на Excel, причем в значительно лучшую сторону.

Excel - очень распространенная среда, и конкурентам (по крайней мере из российского сектора) до массовости Excel как пешком до Поднебеной. Тем не менее, повторю основные минусы Excel:
К этому стоит добавить еще то, что на Excel не так уж тривиально интегрироваться с торговой программой, что для предыдущего пункта делать вообще не нужно. Отдельно можно выделить стабильность - всего один поток, и если он зависнет, зависнут как другие скрипты, так и не будет возможности перезапустить алгоритм (а Excel еще не научился вытаскивать себя из болота за волосы как Мюнхаузен), или даже перезапустить соединение с торгующей программой.

Excel4Net позволяет как раз решить главный недостаток - интеграция. С использованием .NET у Excel появляется просто огромный потенциал в работе с другими программами. Например, библиотеку Ecng.Trading можно на раз-два-три начать использовать как раз из Excel. Это отчетливый сигнал тем, у кого торговые алгоритмы написаны на VBA, и их не устраивает стабильность и скорость. Excel4Net позволяет переписать ряд алгоритмов со скриптов на C# (или VB.NET, кому что нравится), что увеличит скорость в разы. Я переписал один свой макрос на C#, и у него прирост в производительности был равен 1600%. В 16 раз!. Вот здесь показано, как реализовать формулу Блэка-Шоулза.

После выпуска версии Ecng.Trading 1.5 (в текущий момент заканчиваю документацию, которой теперь будет много), обязательно сделаю что-нибудь торговое под Excel4Net. Такой проект трейдерам пройти мимо нельзя.

суббота, 12 декабря 2009 г.

Ecng.Trading 1.4

Обновление! Выложил новую версию 1.4.1

В новой версии (скачивать отсюда) появились стоп-заявки. Вернее, они были и до этого, но не существовала их полная поддержка: отсутствовал функционал по экспорту через DDE, не было возможности отменять и снимать стоп-заявки. Теперь все это есть:

1. Стоп-заявки регистрируются, изменяются и снимаются через те же методы (здесь и далее будет идти речь об интерфейсе ITrader), что и обычные: RegisterOrder, ReRegisterOrder и CancelOrder.
2. Чтобы получить все стоп-заявки, можно вызвать свойство StopOrders. В принципе, можно это сделать и через свойство Orders, где хранятся как обычные, так и стоп-заявки. Но в этом случае придется отфильтровывать самостоятельно.
3. События NewStopOrders и ChangedStopOrders вызываются при появлении новых стоп-заявок, или когда они изменяются (активизируются, снимаются).
4. Метод GetDerivedOrder позволяет получить заявку, которая была создана стоп-заявкой (вызывать можно только для тех стоп-заявок, для которых Order.DerivedOrderId не равен null). Производная заявка появляется в системе тогда, когда активизируется стоп. Метод полезен тогда, когда необходимо узнать, какие из сделок были созданы в рамках стоп-заявки. Напрямую это узнать невозможно, так как стоп-заявки не существуют физически на биржах, и есть только связь между обычной заявкой и сделкой.

Традиционно, скриншоты с изменениями DDE (коснулось не только таблицы стоп-заявок, но и обычных):



Обновленный info.wnd файл лежит в архиве.

Как создавать и работать со стоп-заявками, я показал с своем примере, который расширил функционально:



Изменения коснулись и алгоритма котирования, который появился в версии 1.3 под названием MarketOrderRegistry. Идея мне понравилась, а вот реализация нет. Да так, что хотелось вырвать из блога пост и бросить его в печку. Что не понравилось и что переделал:

1. Название MarketOrderRegistry не отражает саму идею котирование. Поэтому теперь класс называется QuotingAlgo.
2. Котирование происходило только в одном режиме - рыночная цена. Теперь их четыре: по рыночной цене (причем эта опция так же разбивается на три под-опции), по последней сделке, по лучше цене, по лучшему объему. За подробностями в документацию по QuotingTypes.
3. Не была сделана парадигма торговых заданий, которую я придерживаюсь с самого начала. Теперь все задания котирования выделены отдельным классом QuotingTask. И этих самых тасков (=заданий) можно создавать неограниченное количество.

понедельник, 30 ноября 2009 г.

Ecng.Trading 1.3

Выложил новую версию Ecng.Trading v1.3. Скачивать отсюда. Теперь по этой ссылке я буду выкладывать все новые релизы.

В новой версии я добавил два, на мой взгляд, главных изменения.

Первое касается того, как экспортировать произвольные таблицы из Квика. В QuikTrader появилось событие ProcessDdeData. Данное событие вызывается тогда, когда Квик послал DDE данные, которые QuikTrader не умеет обрабатывать. В качестве демонстрации я добавил в свое приложением-пример отображение данных по портфелю. Сначала я настроил Квик, добавив в него соответствующую таблицу:



Обновленные info.wld файл идет вместе с архивом.

Затем, добавил в него код обработки и отображения данных:

_trader.ProcessDdeData += (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];
}
}
};

Так как QuikTrader уже содержит методы по запуску и остановке DDE экспорта (StartDde и StopDde), то для удобства я перегрузил этим методы, чтобы они могли принимать имя экспортируемой таблицы (имя отображается в заголовке таблицы в Квике). Это позволит не только управлять своим потоком данных, но еще и запускать и останавливать его. Так что, если кто-то еще разрабатывает роботов под Excel, руководствуясь тем, что в него можно передавать данные как угодно, знайте, теперь это можно делать и в Ecng.Trading. Ну, а про преимущества разработки роботов на C# по сравнению с Excel я уже писал здесь.

Второе изменение знаковое. Наконец-то, в Ecng.Trading появился первый торговый алгоритм - котирование заявок. Например, необходимо срочно закрыть позицию, продав или купив по рынку (при минимуме потере профита). При высоколиквидном инструменте посланная из Квика или робота заявка может дойти до рынка уже "неактуальной" (в принципе, можно выставлять и из Квика рыночную заявку, но она работает не на всех биржах). Чтобы решить эту проблему, я написал класс MarketOrderRegistry, в который добавляется заявка. Заявка может быть и как уже ранее зарегистрированная, так и "пустая" (только что созданная и еще не выпущенная на биржу). И уже этот класс двигает эту заявку в стакане так, чтобы продать ее по выгодной рыночной цене. Рыночная цена опирается на текущий BestBid и BestAsk инструмента. Если же задана MarketDelta (передается в метод AddOrder), то цена заявки будет высчитываться как смещение цены последней сделки на эту самую MarketDelta.

Другое применения MarketOrderRegistry - это скальперская стратегия. Класс может сам создавать заявки и контролировать их в стакане.

Сам по себе класс MarketOrderRegistry построен на основе методов из класса TraderHelper:

1. GuarantyCancelOrder - гарантированно отменить заявку. В цикле посылает команду CancelOrder до тех пор, пока заявка не снимется (или не исполниться, если робот не успел снять).
2. ReRegisterOrder - перерегистрировать заявку. Удобен тем, что умеет подстраиваться под особенности биржи. Например, FORTS умеет изменять заявки одной транзакцией. Тогда в метод нужно передавать параметр isForts равный true. Если биржа не поддерживает изменения заявки одной транзакцией, то метод последовательно сначала снимает заявку через GuarantyCancelOrder, а затем регистрирует новую.

В принципе, можно реализовать своего собственного котировщика, вызывая методы TraderHelper. Как я уже упоминал, для той же скальперской стратегии. Сам по себе MarketOrderRegistry не смотрит на то, действительно ли нужно переставлять заявку. Он лишь старается выставить ее на край спреда. Поэтому, низкоуровневый класс TraderHelper для тех, кто реализует скальпинг, будет более полезен, чем сам MarketOrderRegistry. Используя TraderHelper можно написать логику лучше заявки (например, основываясь на ценовом или количественном объеме впереди в стакане).

воскресенье, 15 ноября 2009 г.

Ecng.Trading v1.2

Обновление! Рекомендую после данного сообщения прочитать это.

Руки окончательно дошли не только до Ecng.Trading, чтобы его расширить, но и выложить в общий доступ. Качайте. Самое главное изменение в этой версии - появились новые свечки. Раньше были свечки, основанные только на тайм-фрейме, причем, жестко определенном: минутка, пяти-, и т.д.. Теперь тайм-фрейм можно задавать любой, через .NET класс TimeSpan (например, TimeSpan.FromMinutes(2) создает двухминутку). И свечки стали вида:

1. TimeFrameCandle - старая добрая тайм-фрейм свечка.
2. TickCandle - свечка, строящаяся на основе количества сделок.
3. VolumeCandle - свечка, строящаяся на основе допустимого объема.
4. RangeCandle - свечка, строящаяся на основе максимального отклонения цены сделки от открытия свечки.

Для свечек я добавил два события в ITrader: NewCandle (вызывается для свечек, которые только что начали формировать), CandlesChanged (вызывается для измененных свечек).

В предыдущей версии свечки сразу формировались по мере поступления новых сделок из Квика, что в свою очередь приводило к проблеме с производительностью. Так как, даже, если робот не использует какой-либо инструмент, все равно для этого инструмента строились свечки по всем тайм-фреймам (напоминаю, раньше тайм-фреймы были жестко заданы размерами, которые нельзя было изменить). Проблема еще острее вставала, когда таких инструментов набиралось с десяток и более. Теперь формирование свечек начнется как только робот вызовет метод регистрации, передав в него конкретный инструмент и параметры свечки. Вот эти методы:

1. RegisterTimeFrameCandles - передается инструмент, и нужный тайм-фрейм. После вызова этого метода, робот начнет получать события NewCandle и CandlesChanged с объектами TimeFrameCandle.
2. RegisterTickCandles - то же самое, что и RegisterTimeFrameCandles, только уже для свечек TickCandle.
3. RegisterVolumeCandles - аналогично.
4. RegisterRangeCandles - аналогично.

И последнее, немаловажное изменение, касается времени последней сделки (я уже писал об этом, пункт 2). Теперь, QuikWrapper принимает по DDE сразу два параметра, "Время последней сделки" и "Время изменения". Вот как выглядит теперь таблица инструментов:



Все скриншоты настроек DDE и файл с настройка окон в Квике я выложил в том же архиве.

пятница, 6 ноября 2009 г.

Особенность построения МТС под Quik, использую Ecng.Trading

Довольно много пришло писем на почту (как-то народ не очень любит писать в комменты, вопрос - почему) с разного рода ошибками. Об ошибках, в которых повинен я, писать не буду, потому как я их буду устранять по мере появления. А вот о тех, которые я устранить не могу (например, особенности работы Квика), я напишу.

1. "System.BadImageFormatException was unhandled" (если установлен .NET Framework русской версии то сообщение будет такое "Была сделана попытка загрузить программу, имеющую неверный формат."). Эта ошибка говорит о том, что запускается программа как 64 битовое приложение. Библиотека же Trans2Quik.dll написана только под 32 битовые приложения. А на дворе уже 21 век, и найти не 64 битовые компьютеры все сложнее и сложнее. Поэтому и возникает подобная путаница. Поэтому, преждем чем начать создавать своего робота на .NET под Квик, нужно зайти в свойства проекта, раздел Build и выставить Platform target в x86:


2. При торговле на FORTS у Security всегда нулевое значение свойства LastTrade. Это происходит потому, что в таблице инструментов Квик для FORST не показывает время последней сделки. Но он умеет показывать время последнего изменения. Ecng.Trading не опирается на названия колонок в таблице при экспорте через DDE, но учитывает порядковый номер. Поэтому, чтобы получать значение последней сделки в Security, нужно заменить колонку "Время последней сделки" на "Время последнего изменения".

3. Неправильно настроены таблицы в Квике. Под пример, который идет в архиве вместе с Ecng.Trading, я выкладываю файл с настройками для Квика скачать. В нем есть различные фильтры, наподобие того, что показаны только A1 ММВБ и пара фьючерсов, но я думаю, отменить этот фильтр в Квике не составит труда.

4. Когда запускается экспорт Всех сделок через DDE, компьютер может подтормаживать. Это связанно с количеством сделок, которое грузится в первый раз (актуально, когда робот запускается не в начале торговой сессии). Так вот, в программе лучше прописать алгоритм так, чтобы он ждал пока все сделки не подгрузятся. Например, брать тот же Security.LastTrade и ждать, пока он не придет через событие ITrader.NewTrades. Или же заставить пользователя смотреть за процессором в Task Manager.

5. "Что умеет моя программа?". Ничего! Потому что у меня не программа. У меня библиотека с API для разработки этих самых программ. Скриншоты с мой якобы программой являются скриншотами примера, которого я создал специально продемонстрировать, что умеет моя библиотека.

пятница, 23 октября 2009 г.

Ecng.Trading - новое название проекта QuikWrapper

Обновление! Рекомендую после данного сообщения прочитать это.

Вот с такого названия пишу новое сообщение в блоге. Потому как вторая версия (качать отсюда) QuikWrapper-а получилась с настолько большим изменением, и настолько много я запрограммировал вспомогательных программ (утилит) с этой библиотекой, что по мере разработок новых и новых программ, я стал больше понимать, что нужно разделять мух от котлет. А именно, я решил разделить все, что относится к интернет-трейдингу и МТС, и конкретно Quik реализацию на разные библиотеки.

В последствии, я даже удивился, насколько это стало удобным. Например, у меня дома есть сервис с историческими данными. Эти данные я использую в программе тестирования стратегий. Так вот, очень удобно использовать Ecng.Trading для тестирования, но не очень удобно тянуть при этом Quik обертку. Зачем она, ведь я пока не торгую!? Вот и получилось, что написал я на C# с помощью библиотеки стратегию, подключил исторические данные, потестировал, подключил QuikWrapper, и уже начал торговать. И все эти шаги без переписывания кода. Я думаю, многие меня поймут, когда начинают писать прототип своей торговой системы сначала на одном языке, например на AmiBroker скрипте (или еще хуже, на Excel VBA), а затем переписывают на Delphi или .NET, так как нужна большая скорость и гибкость. Как в рекламе, зачем платить в два раза больше, если есть Ecng.Trading!

Изменение номер раз. Термины интернет-трейдинга (классы Security, Order, Trade и т.д.) перекочевали в сборку Ecng.Trading.BusinessEntities. Это полностью независимая сборка, и ее можно использовать везде, назависимо, разрабатывается ли программа под Quik или нет.

Изменение номер два. Добавились новые термины Candle, который представляет собой свечку, и Unit. Последнее собой представляет значения для хранения абсолютного или процентного значения. Поддерживаются базовые арифметически операции (+/-/*/:).

Изменение номер три. Появился интерфейс ITrader. Сам я создал только одну реализацию - QuikTrader, но если кто-то программирует под другие системы (например, Smart), пишите, попробуем добавить еще одну реализацию.

Изменение номер четыре. Базовые классы BaseTask и BaseTradeProcess для создания стратегий выделил в отдельную сборку - Ecng.Trading.Algo.

Изменение номер пять. В QuikTrader (который раньше назывался Trader) я добавил, во-первых, функционал по получению свечек, во-вторых, обработка стакана котировок, в-третьих, работа с DDE (запуск из своей программы DDE экспорт в Quik-e, которые, что важно отметить, само правильно выставляет найтроки в DDE окна Quik-а):

/// <summary>
/// Реализация интерфейса <see cref="ITrader"/>, предоставляющая шлюз взаимодействия с системой Quik.
/// </summary>
public class QuikTrader
{
/// <summary>
/// Инициализация класса <see cref="QuikTrader"/>.
/// </summary>
/// <param name="path">Путь к директории, где установлен Quik.</param>
/// <param name="ddeServer">Название DDE сервера.</param>
/// <param name="ddeWindowCaption">Заголовок окна экспорта через DDE в 
/// Quik-е. В русской версии окно имеет заголовок "Вывод через DDE сервер".</param>
/// <param name="securitiesTableCaption">Названия таблицы инструментов в Quik-е (в русской версии имеет название "Инструменты").
/// Необходимо DDE экспорту для поиска окон по заголовкам.</param>
/// <param name="tradesTableCaption">То же самое, что и securitiesTableCaption, только для всех сделок.</param>
/// <param name="ordersTableCaption">То же самое, что и securitiesTableCaption, только для заявок.</param>
/// <param name="myTradesTableCaption">То же самое, что и securitiesTableCaption, только для моих сделок.</param>
/// <param name="stockTableCaptionFormat">Формат заголовка онка с котировнками.</param>
public QuikTrader(string path, string ddeServer, string ddeWindowCaption,
string securitiesTableCaption, string tradesTableCaption,
string ordersTableCaption, string myTradesTableCaption,
string stockTableCaptionFormat);

/// <summary>
/// Запустить экспорт через DDE по всем таблицам (инструменты, сделки, заявки, мои сделки).
/// </summary>
public void StartDde();

/// <summary>
/// Запустить экспорт через DDE по таблицам, указанных параметром ddeTables.
/// </summary>
/// <example>
/// // запускаем экспорт по таблице инструментов и заявкам.
/// _trader.StartDde(DdeTables.Securities | DdeTables.Orders);
/// </example>
/// <param name="ddeTables">Таблицы, для которых необходимо запустить экспорт через DDE.</param>
public void StartDde(DdeTables ddeTables);

/// <summary>
/// Запустить для заданного инструмента экспорт через DDE стакана котировок.
/// </summary>
/// <param name="security">Инструмент, котировки которого необходимо выводить.</param>
public void StartDde(Security security);

/// <summary>
/// Остановить экспорт  DDE по всем таблицам (инструменты, сделки, заявки, мои сделки).
/// </summary>
public void StopDde();

/// <summary>
/// Остановить экспорт DDE по таблицам, указанных параметром ddeTables.
/// </summary>
/// <param name="ddeTables">Таблицы, для которых необходимо остановить экспорт через DDE.</param>
public void StopDde(DdeTables ddeTables);


/// <summary>
/// Остановить для заданного инструмента экспорт DDE стакана котировок.
/// </summary>
/// <param name="security">Инструмент, для которого необходимо остановить экспорт котировок.</param>
public void StopDde(Security security);
}


Изменение номер шесть, последнее. QuikTrader теперь поддерживает обработку по DDE стакана котировок, и получить эти котировки можно через метод GetQuotes.

Для всех нововведений приведу еще раз скриншотами настройки для DDE (новые, старые, изменившиеся):

Инструменты


Все сделки


Заявки


Мои сделки


Стакан (на примере, для LKOH)

Для закрепления того, о чем я писал выше, я создал программу-пример. На этот раз это визуальное приложение под Windows, которые представляет собой простейший привод для торговли:

пятница, 18 сентября 2009 г.

QuikWrapper

Обновление! Данный проект был полностью переделан. Описание нового проекта с документацией и дистрибутивом находиться по адресу http://stocksharp.com.

На днях я, наконец-то, разобрался с системой экспорта данных из Quik по DDE (результаты качать отсюда). Парадокс построения МТС на базе Quik таков, что довольно легко отправить в него данные (заявки), но сложно получить что-то обратно (информацию по инструментам, тикам и т.д.). Стандартно механизм отдачи данных внешней программе построен на специальных адаптерах (для AmiBroker и Wealth-Lab идут стандартно в поставке), но если нужно действительно автономное решение (программирование роботов на C#, Java или Delphi), то начинаются танцы с бубном. Для сведения, протокол DDE - это старая технология. Настолько старая, что мало того, на данный момент в новых средах программирования (.NET или Java) не существует стандартных компонентов для работы с DDE, так еще и описаний в инете практически не найти.

В принципе, экспорт данных из Quik можно настроить через ODBC. Но у него есть ряд своих недостатков. Во-первых, на компьютере должна быть установлена база данных (мой выбор, MS Sql Server 2008 Express - быстр, стабилен, много возможностей, и, конечно же, бесплатен). Во-вторых, это медленная передача данных. В отличие от DDE, где данные передаются напрямую от Quik к сторонней программе, использование промежуточной базы данных сильно затормаживает и скорость самой МТС.

Есть еще последний вариант, когда можно написать МТС внутри Quik-а на языке QPile, но я его не рассматривал, так как это очень медленное решение, вдобавок и ограниченное возможностями самого языка (на дворе 21-ый век, и нужно использовать компьютеризированные возможности по максимуму).

Собственно, для того, чтобы каждый раз новичкам не проходить тернистый путь написания МТС на языке C# (или любом другом под платформу .NET), я и написал библиотеку QuikWraper. За основу был взят пример работы с Quik API (скачать можно отсюда http://www.quik.ru/user/download/, называется "API импорта транзакций"). В итоге получился следующий функционал:

/// <summary>
/// Основной класс, предоставляющий шлюз взаимодействия с Quik.
/// </summary>
public class Trader
{
/// <summary>
/// Инициализация класса Trader.
/// </summary>
/// <param name="path">Путь к директории, где установлен Quik.</param>
/// <param name="ddeServer">Название DDE сервера.</param>
public Trader(string path, string ddeServer);

/// <summary>
/// Событие изменения состояния подключения. Срабатывает при первом подключении программы к Quik-у,
/// сигнализирую о том, что соединение установлено.
/// </summary>
public event Action<Codes, QuikApiException> ConnectionChanged;

/// <summary>
/// Ошибка при обработке DDE данных, посланых Quik-ом.
/// </summary>
public event Action<Exception> DdeError;

/// <summary>
/// Событие появления собственных новых сделок.
/// </summary>
public event Action<IEnumerable<Trade>> NewMyTrades;

/// <summary>
/// Событие появления всех новых сделок.
/// </summary>
public event Action<IEnumerable<Trade>> NewTrades;

/// <summary>
/// Событие появления новых заявок.
/// </summary>
public event Action<IEnumerable<Order>> NewOrders;

/// <summary>
/// Событие изменения состояния заявки (снята, удовлетворена).
/// </summary>
public event Action<IEnumerable<Order>> OrdersChanged;

/// <summary>
/// Событие загрузки данных по инструментам.
/// </summary>
public event Action SecuritiesLoaded;

/// <summary>
/// Список всех загруженных инструментов.
/// Вызывать только после того, как пришло событие <see cref="SecuritiesLoaded" />.
/// </summary>
public IEnumerable<Security> Securities;

/// <summary>
/// Получить биржевое время.
/// </summary>
public DateTime StockTime;

/// <summary>
/// Получить все зявки, которые были зарегистрированный программой через метод <see cref="RegisterOrder" />.
/// </summary>
public IEnumerable<Order> Orders;

/// <summary>
/// Получить мои сделки.
/// </summary>
/// <param name="security">Инструмент, по которому нужно найти сделки.</param>
/// <param name="from">Дата, с которой нужно искать сделки.</param>
/// <param name="to">Дата, до которой нужно искать сделки.</param>
/// <returns>Найденные сделки.</returns>
public IEnumerable<Trade> GetMyTrades(Security security, DateTime from, DateTime to);

/// <summary>
/// Получить все сделки.
/// </summary>
/// <param name="security">Инструмент, по которому нужно найти сделки.</param>
/// <param name="from">Дата, с которой нужно искать сделки.</param>
/// <param name="to">Дата, до которой нужно искать сделки.</param>
/// <returns>Найденные сделки.</returns>
public IEnumerable<Trade> GetTrades(Security security, DateTime from, DateTime to);


/// <summary>
/// Получить стакан котировок.
/// </summary>
/// <param name="security">Инструмент, по которому нужно получить котировки.</param>
/// <returns>Найденные котировки. Если для инструмента нет котировок, то возвращается пустой список.</returns>
public IEnumerable<Quote> GetStock(Security security);

/// <summary>
/// Зарегистрировать заявку на бирже.
/// </summary>
/// <param name="order">Заявка, содержащая информацию для регистрации.</param>
public void RegisterOrder(Order order);

/// <summary>
/// Отменить заявку на бирже.
/// </summary>
/// <param name="order">Заявка, которую нужно отменять.</param>
public void CancelOrder(Order order)

/// <summary>
/// Получить заявку по сделке.
/// </summary>
/// <param name="trade">Сделка, по которой нужно искать заявку.</param>
/// <returns>Найденная заявка.</returns>
public Order GetOrder(Trade trade);
}

В качестве теста я создал консольное приложение. Программа находит бумагу Лукойл, запоминает первоначальное значение середины спреда равное (bid + ask) / 2. Далее, как только значение спреда отклониться на 0.1 %, то выставляется заявка на покупку объемом 1 и ценой текущего спреда. Далее, если произойдет сделка по выставленной заявке, то программа выведет информацию по этой сделке. Вот текст программы:

// для теста выбираем бумагу Лукойл
var secCode = "LKOH";
Security lkoh = null;

// номер счета
var account = "XXX";

var waitHandle = new ManualResetEvent(false);

// создаем соединение с Quik-ом
using (var trader = new Trader(@"D:\QUIK5", "wrapper"))
{
// подписываемся на событие появление инструментов
trader.SecuritiesLoaded += () =>
{
// находим Лукойл и присваиваем ее переменной lkoh
lkoh = trader.Securities.First(sec => sec.Code == secCode);

Console.WriteLine("Инструмент Лукойл появился");
waitHandle.Set();
};

// подписываемся на событие появления моих новых сделок
trader.NewMyTrades += trades =>
{
foreach (var trade in trades)
Console.WriteLine("Сделка {0} по цене {1} по бумаге {2} по объему {3} в {4}", trade.Id, trade.Price, trade.Security.Code, trade.Volume, trade.Time);
};

Console.WriteLine("Дожидаемся появления в программе инструмента Лукойл");
waitHandle.WaitOne();

if (lkoh != null)
{
// 0.1% от изменения цены
var delta = 0.001;

// запоминаем первоначальное значение спреда
var firstMid = lkoh.BidAsk.Mid;
Console.WriteLine("Первоначальное значение спреда {0}", firstMid);

while (true)
{
// если спред вышел за пределы нашего диапазона
if (
((firstMid + firstMid * delta) <= lkoh.BidAsk.Mid) ||
((firstMid - firstMid * delta) >= lkoh.BidAsk.Mid)
)
{
var order = new Order
{
Account = account,
Price = lkoh.BidAsk.Mid,
Security = lkoh,
Volume = 1,
Direction = OrderDirections.Buy,
};
trader.RegisterOrder(order);
Console.WriteLine("Заявка {0} зарегистрирована", order.Id);
break;
}
else
Console.WriteLine("Текущее значение спреда {0}", lkoh.BidAsk.Mid);
// ждем 1 секунду
Thread.Sleep(1000);
}
}
else
Console.WriteLine("Инструмент Лукойл не появился");

Console.WriteLine("Заканчиваем работу. Нажмите кнопку чтобы продолжить");
Console.Read();
}


Последнее, о чем необходимо еще упомянуть - это настройка самого Quik. Процесс несколько нудный, но, к счастью, делать нужно один раз. Самое первое, включить поддержку Внешних Транзакций. Пункт меню Торговля -> Внешние Транзакции и сделать так, как показано на рисунке:

И теперь DDE:
Инструменты


Все сделки


Заявки


Мои сделки


Важно! Колонки в таблицах должны идти так, как показаны на рисунках. Можно добавлять свои собственные колонки в конец, но никак не перемешивать с нужными. Запускать вывод через DDE тоже необходимо делать в строго определенном порядке. Сначала инструменты, затем все сделки, затем заявки, затем мои сделки.

Исходники примера, а так же сама библиотека с документацией располагается здесь:
http://www.box.net/shared/o7et6ac56x.