понедельник, 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 можно написать логику лучше заявки (например, основываясь на ценовом или количественном объеме впереди в стакане).

25 комментариев:

  1. Да, закралась ошибка. Библиотека должна отделять тейк от стоп-лимита по цене (та, которая Order.Price но не Order.Condition.StopPrice). Если указана, то лимит, иначе тейк. Но не определяет. Выложу новую версию через несколько часов в тот же архив.

    ОтветитьУдалить
  2. Обновил архив с версией 1.3. Попутно сделал некоторые небольшие и большие изменения. Напишу о них по позднее.

    ОтветитьУдалить
  3. Здравствуйте, а можно посмотреть реализацию дде сервера... никак понять не могу как с ним работать) Спасибо

    ОтветитьУдалить
  4. В строке транзакции должны быть и STOPPRICE=7191; и PRICE=7193;
    А не лудше програмисту решать какой тип сделки он хочет и самому выбирать STOP_ORDER_KIND?

    ОтветитьУдалить
  5. HaMMeR,

    Возьмите еще раз послед. версию. Накладка получилась в спешке - перезалил старые dll. Теперь все работает, в частности Ваш примерно у меня прошел.

    ОтветитьУдалить
  6. Serg,

    В примере этого поста я как раз и показал, как с ним работать.

    ОтветитьУдалить
  7. HaMMeR,

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

    ОтветитьУдалить
  8. Доброе время суток!
    Попробовал запустить пример с экспортом всех сделок и получил такую ошибку
    Не удалось привести тип объекта "System.Double" к типу "System.String".
    Ecng.Trading.QuikWrapper
    в Ecng.Trading.QuikWrapper.QuikTrader.☻(String ☻, IList`1 ♥)
    в ☻.♥()

    Что можно сделать?
    Запускаю с версией quik 5.14, Vista, Framework 3.5

    ОтветитьУдалить
  9. Leonandr, Андрей Леонтьев,

    Видимо, таблицы в Квике настроены не так, как в нужно. Посмотрите скриншоты, которые идут в архиве. Все ли у вас колонки? В правильно ли порядке?

    ОтветитьУдалить
  10. да, загрузил файл info.wnd и все заработало. А в чем секрет? только в наличии таблиц и нужных колонок или еще где-то есть какие-то важные настройки квика?

    ОтветитьУдалить
  11. только в наличии таблиц и нужных колонок

    ОтветитьУдалить
  12. А что пишет, если подписаться на DdeError?

    ОтветитьУдалить
  13. все работает, прошу прощения.

    ОтветитьУдалить
  14. Добрый вечер.
    Теперь другая проблема. Экспортирую стакан котировок, а при чтении его в программе, в поле Volume, если OrderDirection = Sell, всегда стоит 0.
    Наверное неправильно настроил таблицу стакана, но непонятно как сделать это правильно.

    ОтветитьУдалить
  15. Экспортирую через ITrader.GetQuotes. Но все равно поле volume равно 0 для продажи. А для покупки все нормально. Очень странно.
    К тому же, мне кажется, что перепутаны sell и buy.
    Вот как у меня выводится.

    Price Volume Direction
    1696,16 0 Sell
    1696,17 0 Sell
    1696,18 0 Sell
    1697 0 Sell
    1697,2 0 Sell
    1697,57 0 Sell
    1698 0 Sell
    1698,22 0 Sell
    1698,36 0 Sell
    1699 0 Sell
    1699,02 13 Buy
    1699,33 1 Buy
    1700 11 Buy
    1700,06 1 Buy
    1700,13 25 Buy
    1700,14 133 Buy
    1700,15 73 Buy
    1700,21 12 Buy
    1700,26 66 Buy
    1700,27 18 Buy

    ОтветитьУдалить
  16. А стакан настроен как на картинке?

    ОтветитьУдалить
  17. А когда будет полная поддержка Стоп-заявок?

    ОтветитьУдалить
  18. HaMMeR, выложил. Описание будет чуть позже. В DDE поменялась таблица Заявки и появилась новая Стоп-Заявки. Все отражено на скриншотах.

    ОтветитьУдалить
  19. Leonandr,

    Попробуйте с теми стаканами, что уже созданы в моем wnd файле.

    ОтветитьУдалить
  20. Gazrvs,

    WPF - это граф. библиотека. Дополнительно использую использую WPF Toolkit. Последнее никокого оотношения к привязке данных (binding) не имеет, только новые контролы. В новом примере я использую из WPF Toolkit DatePicket контрол для выбора срока действия стоп-заявки.

    ОтветитьУдалить
  21. Mika,

    К сожалению не объемы с Sell не выводятся ни с какими стаканами (даже с теми, что присутствуют в вашем файле). Уже какими только способами не пробовал, ничего не помогает. Жаль, что в примере нет окна с котировками, очень помогло бы. Во всяком случае я поверил бы, что проблема именно в моем коде.

    ОтветитьУдалить
  22. Leonandr,

    пришлите скриншот с настройками таблицы (не ДДЕ, а там где настраиваются какие колонки должны присутствовать, название и т.д.)

    ОтветитьУдалить