Mikhail Sukhov
|
Дата: 12.10.2011
worldexplorer очень хочу присоединиться. пожалуйста добавьте пользователя codeplex worldexplorer (меня), и скажите какие индикаторы остались не разобранными? хочу кружку за пять индикаторов!! и авось втянусь в S#, хочу цепляться к квику, возможно из wealth-lab 5... это будет один из моих "трёх вопросов которые я могу задать", а может вопрос уже и отпадёт по мере написания индикатора :)) жду!!! :) Нет кружки - нечем черпать желание.[laugh] Провел рефакторинг по индюкам. Преследуемые цели и фичи: 1. Сделать единого наследника. 2. Выделить комплексные индикаторы. 3. Сделать универсальный объект Значение (который бы работал как с decimal, так и со свечкой). 4. Более простое использование IndicatorManager. Возможно что-то поломал (вернее, скорее всего). Просьба к авторам проверить на предмет работоспособности.
|
|
Спасибо:
|
|
|
|
|
danl
|
Дата: 14.10.2011
|
|
|
|
Mikhail Sukhov Провел рефакторинг по индюкам. Преследуемые цели и фичи:
1. Сделать единого наследника. 2. Выделить комплексные индикаторы. 3. Сделать универсальный объект Значение (который бы работал как с decimal, так и со свечкой). 4. Более простое использование IndicatorManager.
Возможно что-то поломал (вернее, скорее всего). Просьба к авторам проверить на предмет работоспособности.
Добрый день. Михаил, посмотрел последние изменения в индикаторах. Есть несколько мыслей по развитию. Существенный момент в том, что источник данных для индикаторов BaseCandleManagerSource подписывается на событие менеджера формирования всех свечей. Таким образом, в каждый индикатор будут попадать данные всех свечей, то есть от всех инструментов, и всех тайм фрэймов (если TimeFrameCanles). Так как сами индикаторы ни на различение инструментов, ни параметров свечей не рассчитаны, то данные которые они вычисляют, не будут иметь смысла. Либо придется создавать по отдельному CandleManager для каждого инструмента и каждого типа свечей и отдавать соответствующий Manager в источник, что не удобно. В связи с этим предлагаю немного развить концепцию IndicatorManager’а, сделать его чем-то похожим на CandleManager. А именно: - Сделать класс CandleTokenIndocatorSource, который будет передавать в индикатор только события пришедшие по определенному CandleToken, так же добавить метод InitIndicator, который будет прогонять исторические свечи имеющиеся в CandleManager через индикатор.
- Сделать класс IndicatorToken, который будет хранить индикатор и источник, который ассоциирован с ним, переопределить ему процедуру сравнения так, что бы равными считались токены не с полностью одинаковым состоянием, а те которые содержат одинакоые индикаторы и источники (текущее значение индикатора не сравнивается).
- Переработать IndicatorManager, так что бы он позволял регистрировать индикаторы в связке с источниками, возвращая при этом IndicatorToken.
- При регистрации нового индикатора, не добавлять его, а возвращать существующй, если такой индикатор, с таким источником, уже имеется. Реализовать подсчет количество вызовов регистраци индикатора, что бы прекращать рассчет индикатора, после того, как все кому он был необходим от него отказались.
- Что бы все это корректно работало, в каждом индикаторе потребуется реализовать метод, который проверяет равенство индикаторов не по полному текущему состоянию, а только по параметрам влияющим на рассчет.
Такой подход позволит при реализации прогрммы создавать один IndicatorManager и передавать его в стратегию, стратегия будет регистрировать необходимые ей индикаторы. В случае, если несколько стратегий пользуются одними и теми-же индикаторами, то индикатор будет регистрироваться один раз, а остальные стратегии будут пользоваться тем же индикатором. Михаил, посмотри, пожалуйста, на предлагаемую концепцию IndicatorManager, если ты согласуешь такой подход, то я бы взялся за его реализацию (в любом случае, для себя буду что-то подобное делать, считаю, что и для остальных это может быть полезно). Маленькое замечаени. В классе LengthIndicator создан буфер типа List<TResult>. В наследниках, обычно, происходит удаление первого элементо буфера, каждый раз, когда приходит новое значение для рассчета. Мне кажется, что в данном случае имеет смысл использовать какую-нибудь другую коллекцию, которая обеспечивает константное время удаления первого элемента, а не копирует все последующие элементы при каждой такой операции. На сколько я понимаю в StockSharp есть ряд своих разработанных коллекций, к сожалению документацию к ним я не нашел, поэтому на что корректно заменить List не знаю. Из сторонних могу привести пример Wintellect.PowerCollections.Deque (видил PowerCollections.dll в папке References, видимо где-то в StockSharp эти коллекции уже используются). Прошу добавить меня к проекту разработкаи индикаторов, логин на codeplex: danl8
|
|
Спасибо:
|
|
|
|
|
Mikhail Sukhov
|
Дата: 14.10.2011
Добавил в группу.
По IndicatorManager абсолютно верное замечания. Я забыл поправить этот момент. Буду очень рад, если поможете.
По коллекции тоже правы, но я думаю имеет смысл прогнать построение индикаторов комплексно и посмотреть все узкие места. Кто касается типа коллекции, то думаю очередь не очень удачное решение, так как там работа только с одним концом. Лучше наверное LinkedList.
|
|
Спасибо:
|
|
|
|
|
danl
|
Дата: 17.10.2011
|
|
|
|
Выложил изменения по IndicatorManager, с реализацией того, о чем писал раньше. Сегодя-завтра вечером еще потестирую, поправлю баги. Михаил, метод IIndicatorContainer.GetValues в Вашей реализации возвращает обеъкт Dictionary, хотел узнать почему именно Dictionary? Боюсь с этим могут быть проблемы, так как в Dictionary нельзя добавить 2 одинаковых ключа, если строить индикатор от чего-нибудь вроде decimal, то при вызове данного метода будет exception. Может пока не поздно поменять на IList<RefPair>? Mikhail Sukhov очередь не очень удачное решение, так как там работа только с одним концом. Лучше наверное LinkedList. Почему его привел в пример, потому что там очередь реализована как круговой буфер, то есть добавление, как и удаление, элементов в начале и в конце это просто изменение начального или конечного индекса на 1, в остальном то же что и стандартный List<> (то есть доступ к произвольному элементу по индексу быстрый: O(1)). Можно и LinkedList, но у него доступ к произвольпому элементу меделенный.
|
|
Спасибо:
|
|
|
|
|
Mikhail Sukhov
|
Дата: 17.10.2011
|
|
|
|
danl Михаил, метод IIndicatorContainer.GetValues в Вашей реализации возвращает обеъкт Dictionary, хотел узнать почему именно Dictionary? Боюсь с этим могут быть проблемы, так как в Dictionary нельзя добавить 2 одинаковых ключа, если строить индикатор от чего-нибудь вроде decimal, то при вызове данного метода будет exception. Может пока не поздно поменять на IList<RefPair>?
Поэтому и существует такая вещь как IIndicatorValue, которая разруливает проблему с одинаковым входным значением. Неправильно ассоциировать с одним входящим значением несколько исходящих. Они (входящие) могут быть совершенно из разного диапазона времени. Другой вопрос, нужен ли именно словарь для последующей работы. Возможно, доступ по ключу тут как раз бесполезен. Тогда да, лучше IEnumerable (лист предполагает динамическое добавление, лучше следовать LINQ традициям). danl Почему его привел в пример, потому что там очередь реализована как круговой буфер, то есть добавление, как и удаление, элементов в начале и в конце это просто изменение начального или конечного индекса на 1, в остальном то же что и стандартный List<> (то есть доступ к произвольному элементу по индексу быстрый: O(1)). Можно и LinkedList, но у него доступ к произвольпому элементу меделенный.
Очередь вроде вообще не дает по индексу. Может создать свою уникальную коллекцию для организации автоматического удаления хвостовых значений? По коммиту ряд замечания. 1) Ставьте знаки препинания и точки в конце предложения. 2) Прописывайте все пункты в xml комментариях (некоторые ноды пустые). 3) this._privateField лучше заменять на _privateField 4) Устраняйте предупреждения через R#. 5) Код
RefPair<IndicatorToken, int> inDict;
if (_indicatorUsages.TryGetValue(indicatorToken, out inDict))
Заменяется на: Код
var inDict = _indicatorUsages.TryGetValue(indicatorToken);
if (inDict != null)
6) IIndicator.IndicatorEquals выглядит лишним. Цитата:В отличии от стандартного Equals не проверяет полное состояние индикатора Вот как стандартное проверяет просто ссылочную эквивалентность. Лучше IIndicator отнаследовать от IEquatable{T}, а класс BaseIndicator от Equatable{T}. 7) Если в xml комментарии написано с разделами, то можно использовать ноду para. 8) Рефакторинг решил одну проблему, но добавил другую (как всегда[biggrin]). Не нравится тот момент, что теперь прикладной код само должен выбирать, по какому источнику строить индикатор. А такую работу предполагалось нагрузить на IndicatorManager. Тоесть, он должен решать, откуда и куда передавать данные (предотвращать дублирование, склеивать при пробелах и т.д.). Мне кажется, тут лучше сделать как сделано в последней версии CandleManager, который оперирует с коллекцией источников ICandleSource. Соответственно, при регистрации индикатора мне кажется имеет смысл передавать туда object. Object будет или CandleToken, или MarketDepth (или Security). А уж IndicatorManager будет дальше смотреть, откуда по запрашиваемым признакам брать данные (из какого IIndicatorSource).
|
|
Спасибо:
|
|
|
|
|
esper
|
Дата: 17.10.2011
Mikhail Sukhov 3) this._privateField лучше заменять на _privateField
так решарпер при рефакторинге this сам добавляет, возможно это в настройках где-то задается
|
|
Спасибо:
|
|
|
|
|
Mikhail Sukhov
|
Дата: 17.10.2011
esper Mikhail Sukhov 3) this._privateField лучше заменять на _privateField
так решарпер при рефакторинге this сам добавляет, возможно это в настройках где-то задается Да, это в настройках.
|
|
Спасибо:
|
|
|
|
|
danl
|
Дата: 17.10.2011
|
|
|
|
Mikhail Sukhov Другой вопрос, нужен ли именно словарь для последующей работы. Возможно, доступ по ключу тут как раз бесполезен. Тогда да, лучше IEnumerable (лист предполагает динамическое добавление, лучше следовать LINQ традициям).
На мой взгляд IEnumerable првильнее. Mikhail Sukhov Очередь вроде вообще не дает по индексу. Может создать свою уникальную коллекцию для организации автоматического удаления хвостовых значений?
Честно говорю Deque реализует интерфейс IList<> и поддерживает доступ по индексу [smile] А что, кстати, за коллекция Ecng.Collections.FixedSynchronizedList, она, случайно, не подойдет? Mikhail Sukhov По коммиту ряд замечания. ...
Ок. Замечания 1-7 поправлю, в следующий раз буду внимательнее. Mikhail Sukhov 8) Рефакторинг решил одну проблему, но добавил другую (как всегдаBigGrin). Не нравится тот момент, что теперь прикладной код само должен выбирать, по какому источнику строить индикатор. А такую работу предполагалось нагрузить на IndicatorManager. Тоесть, он должен решать, откуда и куда передавать данные (предотвращать дублирование, склеивать при пробелах и т.д.). Мне кажется, тут лучше сделать как сделано в последней версии CandleManager, который оперирует с коллекцией источников ICandleSource. Соответственно, при регистрации индикатора мне кажется имеет смысл передавать туда object. Object будет или CandleToken, или MarketDepth (или Security). А уж IndicatorManager будет дальше смотреть, откуда по запрашиваемым признакам брать данные (из какого IIndicatorSource).
Да, вопрос интересный. Мысль о том, что нужно разнести регистрацию источников данных и самих индикаторов была, но имеет это смысл или нет, пока не осознал... Если есть понимание того, что это нужно, давайте делать. Если я провильно понял идею, то даем возможность пользователю регистрировать источники. Коллекцию источников в IndicatorManager я уже добавлял, просто делаем к ней public методы доступа. В методе регистрации индикатора просто добавляем поиск зарегистрированного источника по аргументу (методы для сравнения object'a и источников выносим в IndicatorSource, что бы все было расширяемо). И, собственно, всё. Клиентский код будет выглядить примерно так: Код
var candleToken = candleManager.RegisterTimeFrameCandles(security, timeFrame);
indicatorManager.RegisterSource(new CandleTokenIndicatorSource(candleToken));
...
var indicatorToken = indicatorManager.RegisterIndicator(new SimpleMovingAverage { Length = 80 }, candleToken);
Я правильно понял? Делать так?
|
|
Спасибо:
|
|
|
|
|
danl
|
Дата: 18.10.2011
Mikhail Sukhov Лучше IIndicator отнаследовать от IEquatable{T}, а класс BaseIndicator от Equatable{T}.
Сейчас посмотрел класс Equatable<T>, он, помимо всего прочего, реализует интерфейс IClonable, который потом придется тащить через всех наследников. Он нам точно нужен в BaseIndicator? Пока оставляю его с NotImplementedException, если что, потом поправим.
|
|
Спасибо:
|
|
|
|
|
Mikhail Sukhov
|
Дата: 18.10.2011
danl Сейчас посмотрел класс Equatable<T>, он, помимо всего прочего, реализует интерфейс IClonable, который потом придется тащить через всех наследников. Он нам точно нужен в BaseIndicator?
Еще как. Клон - это такой метод, который лучше иметь, чем не иметь. Вот например сейчас делаю редактирование индюков в проп Гриде. Приходится править на живом. Соответственно, Undo операция невозможно.
|
|
Спасибо:
|
|
|
|