Управление стаканом котировок
Atom Ответить
30.03.2010


Добрый день, Михаил! Как-то заметил, что стакан котировок отображается
не совсем правильно - цена почему-то не снижается сверху вниз по всей
глубине, а начинается с мимнимальной котировки и повышается сверху
вниз по "биду", а в месте где начинается "аск" "переворачивается и
снова начинается с самой маленькой котировки "аск" и так повышается до
самого низа. Думал отсортировать данные на этапе прихода данных:

this.Trader.ProcessWellKnownDdeData += (name, dict) =>
// узнаем, что пришедшие данные отвечают за стакан
if (name.Contains("stock"))
// первичная сортировка по цене
IEnumerable<Quote> _curquotes = (IEnumerable<Quote>)dict;
_curquotes = _curquotes.OrderBy(t => t.Price);
... и т.д.

но это ни к чему не привело. Подскажите, пожалуйста, как правильно
отсортировать данные?

Еще здесь был как-то уже вопрос про доступ к отдельным значениям
котировок в стакане, но объяснения я так и не нашел. Как же все-такии
это можно сделать (получить значение той или иной котировки в стакане
для анализа)?

Теги:


Спасибо:




82 Ответов
1 2 3  > >>
Mikhail Sukhov

Фотография
Автор статей Программист Трейдер
Дата: 30.03.2010
Ответить


Какой пример? Sample?

Насчет Вашей сортировки _curquotes. А дальше вы куда присваиваете
_curquotes?

Спасибо:

ddd888

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


Да, это в Sample. Собственно, на этом _curquotes и заканчиваются...
Т.е. Вы намекаете на то, что таким образом коллекция, которая затем
отображается в окне, осталась прежней? Как же перехватить исходные
данные?

Автор топика
Спасибо:

Mikhail Sukhov

Фотография
Автор статей Программист Трейдер
Дата: 30.03.2010
Ответить


Я думаю это нужно вставить в SecuritiesWindow.

pair.Value.Quotes.AddRange(MainWindow.Instance.Trader.GetMarketDepth(pair.ey).OrderBy(t
=> t.Price).Select

Манируляции над IEnumerable не изменяют коллекцию, а возвращают новое
значение. Собственно оно и содержит необходимые изменения.

Спасибо:

ddd888

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


Точно! Это сработало! Спасибо большое! :)

Автор топика
Спасибо:

ddd888

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


Интересно, а вот почему это работает - не понимаю. :) Ведь окно
котировок в момент открытия окна "инструменты" еще не
инициализировано. И экспорт "стакана" тоже еще не начал работать... А
данная манипуляция с сортировкой происходит в "конструкторе", т.е. в
момент создания экземпляра окна "инструменты". Как же это происходит?

Автор топика
Спасибо:

Mikhail Sukhov

Фотография
Автор статей Программист Трейдер
Дата: 30.03.2010
Ответить


А Вы посмотрите по-внимательнее. Там создается таймер, который из
коллекции вытаскивает данные. И посмотрите, в какой момент эта
коллекция заполняется.

Спасибо:

ddd888

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


Попытаюсь. Как мне кажется, что CreateTimer() запускается в
конструкторе "инструментов" и потом работает постоянно каждую
миллисекунду, правильно?

Автор топика
Спасибо:

ddd888

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


Определения CreateTimer() я нигде не нашел. В чем состоит его
функция?

Автор топика
Спасибо:

Mikhail Sukhov

Фотография
Автор статей Программист Трейдер
Дата: 01.04.2010
Ответить


Он находится в Ecng.Common, TimerHelper. Создание таймера по входящему
TimeSpan? Можно напрямую создавать через класс Timer, но через
TimerHelper запись короче.

Спасибо:

ddd888

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


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

Автор топика
Спасибо:

Mikhail Sukhov

Фотография
Автор статей Программист Трейдер
Дата: 01.04.2010
Ответить


При открытии стакана добавляет элемент в коллекцию. А в таймере идет
перечисление по коллекции. Поэтому, при ни одном открытом инструменте,
таймер выполняет холостую работу.

Спасибо:

ddd888

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


Спасибо, теперь все гораздо яснее стало.
Но при закрытии стакана, насколько я заметил, таймер продолжает
работать, да?

Автор топика
Спасибо:

Mikhail Sukhov

Фотография
Автор статей Программист Трейдер
Дата: 02.04.2010
Ответить


Конечно. Таймер на окно с инструментами. У него может быть несколько
стаканов, по одному на инструмент. Если бы он останавливался при
закрытие одного стакана, другие бы тоже переставали работать.

Спасибо:

ddd888

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


Т.е. в данном случае таймер выполняет ту же функцию для стакана
(импорт данных), что и подписка на события обновления котировок в
других окнах (типа "инструменты")?

Автор топика
Спасибо:

Mikhail Sukhov

Фотография
Автор статей Программист Трейдер
Дата: 02.04.2010
Ответить


Не понял утверждения, если честно.

Спасибо:

ddd888

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


Имел ввиду следующее. Обновление окна "инструменты" - это работа
this.Trader.NewSecurities += ...,
а обновление окна "стакана" - это работа таймера.

Автор топика
Спасибо:

Mikhail Sukhov

Фотография
Автор статей Программист Трейдер
Дата: 05.04.2010
Ответить


Верно, только лучше так: а обновление окон "стаканов" - это работа
таймера

Спасибо:

ddd888

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


Спасибо. С Вашей помощью туман успешно рассеивается. :)

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

private readonly SynchronizedDictionary<Security, QuotesWindow>
_quotesWindows = new SynchronizedDictionary<Security, QuotesWindow>();

а при открытии окна котировок в конструкторе создается новый экземпляр
но уже другой коллекции:

this.Quotes = new SynchronisedObservableList<SampleQuote>();

SynchronizedDictionary<Security, QuotesWindow> - заполняется
котировками, а в чем состоит работа
SynchronisedObservableList<SampleQuote>? Визуализация данных? И как
они связаны между собой?

Автор топика
Спасибо:

Mikhail Sukhov

Фотография
Автор статей Программист Трейдер
Дата: 06.04.2010
Ответить


SampleQuote - это тот же Quote, только еще содержащий собственный
объем.

SynchronisedObservableList<SampleQuote> сделал исключительно для
визуализации.

Вот тут написано как делать отображение данных в программе -

http://msdn.microsoft.com/ru-ru/library/ms752347.aspx


Спасибо:

ddd888

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


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

var _minprice =
MainWindow.Instance.Trader.GetMarketDepth(pair.Key).Min(q => q.Price);

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

Автор топика
Спасибо:

Mikhail Sukhov

Фотография
Автор статей Программист Трейдер
Дата: 06.04.2010
Ответить


GetMarketDepth - это стакан MarketDepth.

MarketDepth - это коллекция котировок. Ошибка говорит о том, что
коллекция пуста. Такое бывает, когда нет экспорта по стакану (или он
еще не стартанул).

Спасибо:

ddd888

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


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

<ListView ItemsSource="{Binding ElementName=quotesWindow,
Path=Quotes}"
GridViewColumnHeader.Click="GridViewColumnHeaderClickedHandler">
<ListView.View>
<GridView>
<GridViewColumn Width="70" Header="Bid"
DisplayMemberBinding="{Binding Path=Bid}" />

а вот эта (дополнительное текстовое поле в том же окне) нет:

<TextBox Name="AskBox" ... IsReadOnly="True" AcceptsTab="True"
Grid.Column="1" Text="{Binding Path=BestBid}"/>

и так тоже нет:

<TextBox Name="BidBox" ... AcceptsTab="True" IsReadOnly="True"
MinHeight="0" Grid.Column="1" Text="{Binding ElementName=quotesWindow,
Path=Quotes/BestBid/}">

Best Bid - это дополнительное поле в SampleQuote. Причем если Best Bid
загрузить в <GridViewColumn>, то данные нормально отображаются, а в
текстовом поле нет. Это можно легко объяснить?

Автор топика
Спасибо:

ddd888

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


Похоже, объяснить оказалось нелегко. :) По крайней мере, для меня. Но
после долгих "танцев с бубнами" удалось найти решение через обработку
событий в коллекции Quotes. Судя по похожим проблемам на многих
форумах. по-видимому, это был единственно возможный выход с данной
версией WPF.

Автор топика
Спасибо:

Mikhail Sukhov

Фотография
Автор статей Программист Трейдер
Дата: 13.04.2010
Ответить


Нет, просто был занят релизом.

Text="{Binding Path=BestBid}" не выводится скорее всего потому, что не
такого свойства. BestBid - это свойтство MarketDepth. А quotesWindow
работаео к коллекцией SampleQuotes.

Text="{Binding ElementName=quotesWindow, Path=Quotes/BestBid/}" - не
уверен что WPF понимает такие запросы. Я думаю, проще будет через
форумы программерские спрашивать такие вещи. Напримерhttp://rsdn.ru/forum/dotnet.gui/

. Так как я и сам не особо спец в визуальной технологии.

Спасибо:

ddd888

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


Сейчас уже не очень актуально, т.к. решение по привязке уже есть и
вроде как работает без сбоев. Как я это понял, проблема не в том, что
WPF не понимает запросы - он как раз многое понимает - но не
обновляет при обновлении коллекции - в этом я нашел причину и исправив
ее через подписку на событие измения коллекции, все заработало.

Возник вопрос другого плана. При отправке своей заявки с помощью
создания экземпляра класса NewOrderWindow возникает исключение от
"Ecng.Trading.Quik.ApiException: Код ошибки: WrongSyntax Сообщение
ACCOUNT=..." и т.д. При отправке из "Инструменты" заявка отправляется
нормально, а из моего метода - нет, хотя - я проверил - синтаксис
отправляемой заявки точно такой же! Отличие от отправки из окна
"Инструменты" лишь в том, что я создаю новый пустой экземпляр Security
и приписываю ему код бумаги и класс. В чем тут собака порылась?

Автор топика
Спасибо:
1 2 3  > >>

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

loading
clippy