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

Stock# 2.2.1

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

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

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

вторник, 27 июля 2010 г.

Standart vs Plaza II

Честно признаюсь не знаю как называется подключение которое использовалось ранее, поэтому обозвал просто -  Standart.
Два видео ниже сняты с интервалом в одну минуту. В первом случае квик подключался через обычный сервер брокера, во втором через Плазу. Разница, как говорится, видна невооруженным глазом.
Standart

Plaza II

понедельник, 26 июля 2010 г.

Stock# 2.2

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


Стратегии:

  1. Добавил событийную модель для стратегий. Уж больно часто начал возникать вопрос на форумах, как не проверять по интервалу определенные значения в теле стратегии, а подписаться на события изменений. В добавок в моих проектах я осознал, что такая модель предоставила бы сокращения кода и сделала бы его понятнее... Вообщем, прошу всех встречать - ActionStrategy. Подробнее в документации.
  2. Добавил тейк-профит и стоп-лосс стратегии. Фактически, кросс-платформенные стоп заявки, не зависящие от торгового терминала. Плюс, в стоп-лосс добавил опцию слежения. Что характерно, все эти вещи я сделал на базе котирования, что еще раз доказывает мощный потенциал подобной стратегии (жаль, судя по форуму, никто не пошел дальше ее простой функции - выставить по рынку). Подробнее в документации.
  3. Переделал документацию в разделе Торговые алгоритмы. Очень много поменялось, читайте.
  4. Дочерние стратегии сделал параллельными (при указании опции IsParallel). Также, добавил BatchStrategy, которая указывает критерий завершения стратегий. Подробнее в документации.
  5. Новая концепция - конструктор у стратегий должен быть без параметров. Две причины. Первая, когда создается дочерняя стратегия выглядит несколько странно указывать у нее инструмент и порфтель. Они в любом случае должны быть как у родительской стратегии. Вторая причина. Я добавил в StrategyManager методы Load и Save, которые теперь умеют сохранять и восстанавливать стратегии из xml файла. А восстанавливать из файла можно только стратегии без параметров в конструкторе.
  6. StrategyManager теперь в конструкторе принимает ITrader, отслеживая его события соединения и потери связи (ошибочно или планово). В случае потери связи StrategyManager больше не вызывает Strategy.OnProcess до тех пор, пока не придет событие ITrader.Connected.
  7. В Strategy.ReRegisterOrder добавил параметр getNewVolume для логического единообразия с getNewPrice.
  8. Добавил методы Strategy.CancelActiveOrders и Strategy.ClosePosition. Использовать рекомендуется в случаях остановки стратегии.
  9. Котирование теперь учитывает значение Strategy.Volume. Так что, теперь можно котировать большие объемы, не боясь "собрать" стакан.
  10. Появилось свойство QuotingStrategy.MaxReRegisterCount, которое ограничивает котирование на максимальное количество изменений заявки. Если он превышен, то стратегия останавливается.
  11. Strategy теперь поддерживает стоп-заявки.
  12. У Strategy появились новые события: NewStopOrder, OrderChanged, StopOrderChanged,
    OrderFailed, StopOrderFailed. Из-за появления данных событий я скрыл от использования многие виртуальные методы.
  13. Все свойства дочерних стратегий котирования сделал доступных для записи, как просили здесь.

Свечки:

  1. Добавил событие CandleManager.CandlesFinished, которое однозначно означает конец формирования свечки. Не нужно больше шаманить в коде и дожидаться самому окончанию свечек.
  2. Ввел понятие CandleFactory. Во-первых, теперь все стандартные свечки реализуют подобную фабрику. Во-вторых, появилось понятие "нестандартная" свечка. Тоесть, если понадобилась какая-то своя реализация (например, кресты-нули или кластер), то можно реализовать свой CandleFactory, и начать получать свои типы свечек.
  3. Для свечек добавил методы распознования паттернов: цвет, надгробье, стрекоза, молот и многое другое.
  4. Добавил TraderHelper.GetCandleTime для получения времени текущей TimeFrameCandle.

SmartCOM:

  1. SmartTrader , наконец-то, подружил с ReConnectionManager. Фу, насколько же не стабилен этот SmartCOM! Постоянно приходится вставлять экзотический код. Хорошо, что в SmartTrader, чтобы не портил красоту кода в роботе.
  2. Из-за предыдущего пункта добавил ReConnectionManager.IsReStartExport. Потому как в случае с переподключением к SmartCOM экспорт так же необходимо запускать.
  3. Добавил SmartTrader.RegisterRealTimeCandles. Отличается от SmartTrader.RegisterCandles тем, что возвращает не только исторические свечки, но и real-time свечки. И причем последние приходят постоянно по окончанию тайм-фрейма (тоесть, нет необходимости обращатся за ними на сервер из кода робота). Подробнее.

Quik:
  1. Изменил Verifier так, что он теперь может проверять правильность настроек таблиц в зависимости от торговой площадки, с которой идет работа. Поддерживаются РТС, ММВБ и ММВБ Срочный рынок.
  2. Для QuikTrader реализовал возможность перезапуска только активных DDE потоков. Например, когда в программе экспортируются все таблицы + дополнительно несколько стаканов. QuikTrader.ReStartExport сможет отследить экспорт для запущенных стаканов, и перезапустит их на равне со стандартными таблицами. Такое поведение справедливо и для ситуации, когда экспорт запущен только по нескольким таблицам (например, по таблице инструментов и заявок). Перезапуск экспорта запустит только эти несколько таблиц, не трогая другие (стоп заявки, сделки и т.д.).
  3. Появилась возможность посмотреть строку транзакции по ее номеру или по самой заявке. Это удобно для отладки, когда нужно посмотреть, какая транзакция был ассоциирована с заявкой, и детально углубиться в решение проблемы.
Общее:
  1. 1. Добавил новое состояние для заявок - Failed. Заявка переходит в этой состояние, когда произошла какая-то ошибка при ее регистрации (в роботе, в шлюзе или не приняла биржа). Собственно, это как раз те заявки, которые приходят в событиях OrdersFailed и StopOrdersFailed. Подробнее, о состояниях заявок.
  2. Order.Account объявлен как устаревшим. Он все еще используется для обратной совместимости, но надо уже переходить на Order.Portfolio. Причина отмены Account банальна - не объектно-ориентированно. Как следствие, можно засунуть в счет все, что угодно.
  3. Из-за предыдущего пункта изменился и ITrader.CancelOrders, который раньше принимал номер счета.
  4. Из-за устаревания Account были переименованы и переделаны следующие менеджеры:

  5. Добавил новый менеджер PositionPnLManager
  6. Переименовал свойства у базовых классов менеджеров в интуитивно понятные (нет больше Value или TotalValue, есть PnL и Position). Учтите при компилировании проектов.
  7. Добавил методы ITrader.GetOrders(Portfolio) и ITrader.GetMyTrades(Portfolio).
  8. TraderHelper.IsTradeTime теперь учитывает и дни недели. В субботу и воскресенье выдает, что время вне торгового диапазона.
  9. Добавил TraderHelper.GetPosition(ITrader trader, Portfolio portfolio), который возврашает целое число, означающее позицию по всему портфелю.
  10. Убрал QuikTrader.IsFullDdeExport. Теперь таблицы с позициями обязательны всегда (фактически, предыдущее введение этого свойства было сделано специально для облегчения миграции).
  11. Добавил TraderHelper.GetRealizedVolume для получения реализованного объема по заявке.
  12. Переименовал SyncTrader и SyncCandleManager в GuiTrader и GuiCandleManager.
  13. Удалил класс TraderManager. Даже не знаю, зачем его вообще вводил.
  14. Обсуждения несостоявшейся баги привело к тому, что я исправил IncrementTransactionIdGenerator (CurrentTransactionId по умолчанию равно количеству миллисекунд с начала дня) и MillisecondTransactionIdGenerator (разница в миллисекундах теперь учитывается не с начала дня, а с момента создания генератора).
  15. Как просили здесь добавил генерацию события при изменении ExntensionInfo (для всех сущностей, а не только для Security, о чем там говорилось).

Баги:

  1. MarketQuotingStrategy не передает управление?
  2. Стоп заявки, Срок 'До отмены', тип DateTime

Продведем итог. 13 + 4 + 3 + 3 + 15 = 38 новых фич. Рекорд.

воскресенье, 25 июля 2010 г.

Марафон трейдера Дмитрия Барановского

Прочитал заметку создателя портала 2stocks.ru (бывший stockportal.ru) Барановский Дмитрий.

Заметка интересная, хотя жизненные истории таких людей всегда интересно читать. Некоторые моменты, конечно, не совсем правильны на мой взгляд. Но, что самое для меня главное было написано - это заключение. Дмитрий решил податься в роботоводы. Из заметки это видится как внезапное решение. И, я думаю, это не совсем так. Все же был какой-то длинный путь, чтобы точно прийти к моменту создания робота. Например, советники, индикаторы и т.д. Потому что, если решение было молниеносно... Чтож, я уже писал достаточно про негативные стороны торговых роботов. А пока можно только поздравить с правильным, на мой взгляд, решением трейдера такого уровня.

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

Язык программирования для роботов

Прислали мне ссылки - http://www.quik.ru/forum/expert/57093/57093/ и http://quik.ru/forum/expert/57323/57323/. Прочитал, местами было интересно.

Я уже писал до этого о целесообразности в роботах вообще.
Теперь напишу, какой язык бы я выбрал вообще.

Понятно, что для себя я этот вопрос решил давно. Но для тех, кто только начинает разработку роботов, могу дать совет:

  1. Если давно используете какую-то систему Тех Анализа, то продолжайте писать на том языке, что там присутствует.
  2. Если решили написать робота в виде отдельной программы, выбирайте тот, что популярнее для алго трейдинга. А понять, какой именно язык самый-самый на российском рынке очень просто - по поддержке от вендоров. Возьмем китов: Quik, ИТ Инвест, Алор, Альфа Директ и NetInvestor:

    • Quik - для TRANS2QUIK.dll имеет два примера: один на C#, другой на C++.
    • ИТ Инвест - для SmartCOM имеет один пример на C#, документация так же написана с применением этого языка.
    • Алор - для Алор Трейд с COM объектами имеет один пример на C++, другой на C#.
    • Альфа Директ - для API имеет один пример на C#, один на Dephi, один на C++. Документация на C++, C#, VB, Delphi.
    • NetInvestor - для NIAPI имеет два примера: один на C#, другой на C++. Руководство пользователя - на C#.

    Итого (один бал за документацию, один за пример):

    • C# - 8 = 1 + 2 + 1 + 2 + 2
    • C++ - 5 = 1 + 1 + 2 + 1
    • Dephi - 2 = 2
    • VB - 1


Теперь о быстроте C++, которая была упомянута в тех ссылках. Как правильно заметили в той переписке, быстрота необходима для High Frequency Trading. Ни один из выше приведенных вендоров не дает такую пропускную способность, которые бы удовлетворяла подобному типу роботостроения. Дополнительно, это масштаб крупных игроков, которые могут позволить не только прямой доступ к бирже, но так же хостинг своих серверов на биржевых площадках. Для частников, в скорости С++ не даст никаких преимуществ. Минусов, особенной не для программистов (а трейдеры не занимаются программирование углубленно), очень много. И сложность языка, и чувствительность к ошибкам, и сложность в отладке и поиске ошибок... Море. Я писал на этом языке. Ничуть не огорчен, что ушел от разработки на С++. А как показывает тенденция софтверных гигантов, от C++ отказываются все больше и больше компаний.

К чему ведет популярность? Популярность ведет к тому, что данный язык становиться основным для разработки, под него увеличивается комьюнити, появляются решения сторонних разработчиков... Вообщем, бенефитов много.

А теперь вопрос, как же на западе? А на западе все давно решено: WealthLab, QuantDevelop, OpenQuant, RightEdge - все они поддерживают C#.

Остались вопросы с тем, какой язык необходимо выбирать?

вторник, 6 июля 2010 г.

Вольные разработчики

На форумах ИТ Инвест, где недавно поменялся движок, я получил статус Вольного Разработчика - http://www.itinvest.ru/forum/index.php?showuser=37693. Приятно видеть отметку. Но если задуматься о смысле, то получается следущее: Волен - хочу - делаю новую версию, не хочу - не делаю. А это не так. Сейчас уже ощущается некое бремя ответственности, которое не позволяет расслабиться.

Кстати, насчет нового движка форума. Первое впечатление не очень, уж больно все блекло и глаза напрягаются. Но прогресс на лицо, и это не может не радовать. Ребятам надо развивать веб сервисы. Это очень модно и повышает автоматизацию бизнес процессов.

понедельник, 5 июля 2010 г.

Stock# 2.1

И так, вышла новая версия - Stock# 2.1. Это не просто фикс предыдущей версии 2.0.1, а значительное расширение функциональности, как можно судить по списку ниже. Но обо все по-порядку.

Фичи:
  1. Я решил полностью пересмотреть подход с экспортом произвольных таблиц. В ранних версиях принцип работы строился на использовании события 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());
    };
    
    
    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];
        }
      }
    }
    


    Результат, как говорится, не лицо.

  2. Переделал и ProcessWellKnownDdeDataa. Теперь вообще не нужно использовать данное событие. Достаточно лишь расширить таблицу в Quik и задать необходимые колонки в коде. Все будет экспортироваться само. Подробное описание.

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

  4. Для предыдущего пункта добавил DdeSecurityColumns.LastTradeVolume2.

  5. Внимание! Колонка DdeSecurityColumns.LastChangeTime по умолчанию выключена для экспорта. Это важное изменения я сделал из-за двух причин. Первая, не все торгую на нескольких рынках одновременно. Вторая, из-за пункта 4 (для единообразия, если кто-то торгует на нескольких рынках, то он должен включать для себя необходимые колонки). Так что, теперь колонка с временем последней сделки только одна (по-умолчанию).

  6. В дистрибутиве теперь идут три файла настроек Quik: info_rts.wnd, info_micex.wnd и info_rts_micex.wnd (совмещает первое и второе). Названия говорят сами за себя. Подробнее, об этом я написал в переделанной документации.

  7. Теперь QuikTrader умеет экспортировать позиции (Position). Ранее это был внутренний класс для SmartTrader. Теперь и для Quik. Соответственно, добавил и функционал для работы с позициями - ITrader.Positions, ITrader.NewPositions и Trader.PositionsChanged. Подробнее, как включать экспорт по позициям, описал в документации.

  8. Делая предыдущий пункт, я дополнительно реализовал экспорт портфелей и для QuikTrader. Сам по себе экспорт данных не идет (для этого все также нужно делать экспорт самостоятельно, как я показал в примере SampleDdeCustomTable), но сама сущность с номером счета создается и выводится через ITrader.NewPortfolios.

  9. Для Position и для Portfolio создал методы расчета PnL TraderHelper.GetPnL.

  10. Дополнительно, для удобства получения позиций добавил возможность получать их по инструменту или портфелю через метод ITrader.GetPositions.

  11. Убрал событие MarketDepth.Changed и заменил его двумя: MarketDepth.QuotesChanged, которое показывает, какие именно котировки внутри стакана изменились, и MarketDepth.DepthChanged, которое говорит об изменении глубины стакана.

  12. Добавил возможность сохранять и загружать настройки таблиц через методы DdeTable.Save и DdeTable.Load. Это удобно в тех случаях, если программа распространяется среди пользователей.

  13. Внедрил код получения времени сервера как написали здесь. В принципе, теперь необходимость для QuikTrader в MarketTimeOffset отпала. Спасибо HaMMeR-у!

  14. Сделал возможность менять у уже созданного QuikTrader путь к Quik - QuikTrader.Path. Аналогично сделал и для SmartTrader с Address, Login и Password. Одно но. Перед изменениями необходимо сделать Disconnect(если было произведено соединение). Иначе, будет выбрасываться исключение.

  15. Добавил интерфейс IExtendableEntity, в которое есть только одной свойство ExtensionInfo. Сделал это для удобства работы в написании универсального кода, который работает с любой торговой сущностью.

  16. Для SmartTrader добавил специальное перечисление - Extensions. Это ключ, по которому можно получить специфичную для SmartCOM данные из ExtensionInfo.

  17. Опять по DDE. Теперь название категорий (в Quik это называется Рабочая книга) указывается такое же, как и DdeTable.Caption.

  18. Наконец-то доделал обещанное - сделал котирование по асинхронному режиму QuikTrader.IsAsyncMode (http://stockmarketdotnet.blogspot.com/2010/03/stock-18.html пункт 1). Автоматически, эта вещь заработала и для SmartTrader, потому что он умеет работать только в асинхронном режиме. Ура!

  19. Убрал метод Strategy.AddOrder и изменил логику регистрации заявок из стратегий. Теперь регистрировать заявки необходимо через метод Strategy.RegisterOrder, который автоматически после успешного принятия заявки биржей добавляет ее в стратегию. Собственно, в такому случае Strategy.AddOrder стал рудиментом, что и привело к его исчезновению. Замену заявок так же нужно производить через новый метод Strategy.ReRegisterOrder. Собственно, новое котирование как раз и основанно на этих новых методах.

  20. TraderHelper.ReRegisterOrder теперь исчез - перекочевал в Strategy.ReRegisterOrder.

  21. Сделал возможность работать с Currency как с обычными числами. Тоесть, можно складывать, вычитать, умножать и делить.

  22. Добавил в Order поле Portfolio. Пока это как опциональное поле. Но в дальнейшем планирую его сделать обязательным к заполнению, которое заменит собой поле Account (и, надеюсь, строковое представление счета исчезнет навсегда из S#).

  23. В документации добавил страницу с примерами. Показывает, какие вообще есть примеры, и что они делают (цель их обучения).

  24. Специально запрятал в самый конец, чтобы меньше сил на протесты осталось =). Переделал состояние заявок. Понятно, что изменение значительное (пожалуй, самое часто использующееся свойство). Но прогресс должен быть, и рудименты должны исправляться. Иначе библиотека зарастет архаизмами... Есть только три свойства - None, Active и Done. Все. Именно они однозначно говорят о состоянии заявки, жива или нет. Если нужно узнать, исполнена или отклонена, то пункт 25.

  25. Для отслеживания того, полностью ли исполнена заявка, или частично, или вообще не исполнена надо вызывать методы TraderHelper.IsMatched, TraderHelper.IsFilledPartially и TraderHelper.IsFilledEmpty соответственно. Если нужно узнать, отменена ли была заявка, то нужно вызывать метод TraderHelper.IsCanceled. С учетом пункта 24 у нас вместо прежних 4-ех состояний (напомню, было None, Active, Matched и Cancelled) теперь есть комбинации. Намного информативнее.


И, конечно же, фиксы:

  1. DDE экспорт не запускается, если открыта другая закладка с развернутым графиком во весь экран.

  2. Исправил старую "добрую" ошибку с запуском экспорта. Иногда он не запускался с первого раза. Причина - окно с запуском DDE в Quik не всегда быстро появляется. Теперь гарантированно дожидается появление данного окна. Экспорт стартует чуть дольше, зато гарантированно работает.

  3. Пофиксил в MarketDepth неправильный порядок вывода котировок.

  4. Исправил ошибку с отсутствием регистрации новой заявки в котировании.

  5. В том же топике, что и в пункте 4 была проблема с буферизацией вывода логов через StrategyLogger. Буферизацию убрал - теперь все выводится сразу.

  6. Снятие группу заявок в асинронном режиме не всегда работает.


Итого, 25 нововведений и 6 фиксов. Неплохо, неплохо.