Общий вопрос по реализации Индикаторов
Atom Ответить
12.05.2012


Всем доброго дня )))

Вопрос такой: почему индикаторы сделаны через дженерики таким образом, что могут не отрабатывать контракт?

На примере кода:
Цитата:
var candle = new TimeFrameCandle()
{
Time = DateTime.Now,
OpenPrice = 1,
ClosePrice = 2,
HighPrice = 3,
LowPrice = 4,
CloseVolume = 100,
};
IIndicator indicator = new ExponentialMovingAverage();
var result = indicator.Process(new CandleIndicatorValue(candle));


Если же взять Peak индикатор, то код внезапно начинает работать.
Самое обидное, что контракт - всегда выполнен. Любой индикатор поддерживает интерфейс взаимодействия IIndicator, на вход Process подается IIndicatorValue.
Но в одном случае IIndicatorValue обрабатывается корректно, а в другом - дает сбой.


Расследование показало, что это происходит из за вызова var newValue = input.GetValue<decimal>(); в EMA. Т.е. EMA исходит из того, что input строго decimal, хотя контрактом на EMA это не регламентировано.

Что делать?

Теги:


Спасибо:




3 Ответов
Кот Матроскин

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


VoDA Перейти
Всем доброго дня )))

Вопрос такой: почему индикаторы сделаны через дженерики таким образом, что могут не отрабатывать контракт?

Расследование показало, что это происходит из за вызова var newValue = input.GetValue<decimal>(); в EMA. Т.е. EMA исходит из того, что input строго decimal, хотя контрактом на EMA это не регламентировано.

Что делать?

Поясни:
- что значит "могут не отрабатывать контракт"
- почему input не должен быть decimal
- каким "контрактом на EMA это не регламентировано"
Спасибо:

VoDA

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


Кот Матроскин Перейти

Поясни:
- что значит "могут не отрабатывать контракт"
- почему input не должен быть decimal
- каким "контрактом на EMA это не регламентировано"


Контракт это соглашение о том какие параметры должны обрабатываться методом или объектом. Все интерфейсы и базовые классы - это своего рода контракты для реализующих их классов. В данном случае линия наследования ExponentialMovingAverage:LengthIndicator, LengthIndicator:BaseIndicator, BaseIndicator:IIndicator показывает, что EMA должен отрабатывать все вызовы, которые присутствуют в IIndicator.

В IIndicator есть Process, который принимает IIndicatorValue. Т.е. любой потомок IIndicator должен обработать все, что есть IIndicatorValue.
Я создаю new CandleIndicatorValue(new TimeFrameCandle...), который по наследования является IIndicatorValue.

Почему при передаче валидного IIndicatorValue в метод Process летит Эксепшен?



Теперь по пунктам:
- при передаче IIndicatorValue в метод Process класса EMA вылетает Эксепшен. ИМХО если метод принимает параметер определенного типа (тип прописан в сигнатуре), то он должен его обработать.
- input может быть IIndicatorValue содержащим decimal, а может быть IIndicatorValue содержащим любой другой тип, который захотел программист.
- IIndicator разрешает любой IIndicatorValue.


Решения с точки зрения программирования:
Если IIndicatorValue должен как то приводиться к decimal, то ИМХО стоит сделать метод public decimal ConvertToDecimal(), где все типы должны приводиться самим создателем наследника от IIndicatorValue.
Если не все IIndicatorValue приводимы к decimal, то ИМХО стоит выделить приводимые к decimal в наследника IIndicatorValue. А методы типа IIndicatorValue Process(IIndicatorValue input); заменить на этого наследника для всех приводимых к decimal типов.


Вероятно, я не до конца понимаю объектную модель индикаторов BigGrin
Пока смотрел исходники появилась еще одна идея - типизировать сам IIndicator, а в наследниках указывать какие именно типа объектов может принимать Process. Возможно это тоже сможет упростить дело.
Автор топика
Спасибо:

VoDA

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


Кот Матроскин Перейти
В продолжение темы:
Как правильно кормить индикаторы?

Тот же ChaikinVolatility делает input.GetValue<Candle>();
А ExponentialMovingAverage - input.GetValue<decimal>();
Оба в момент обработки входных данных.


Рассмотрим пример IndicatorsManager.cs из IndicatorsXaml.

Если есть общий список индикторов, то в момент их вызова (функция public void AddPoint(TimeFrameCandle candle))
Придется проверять типы этих индикторов, чтобы понять в каком виде им нужно предоставить Сandle.

Именно поэтому часть кода закомментирована - тот же SimpleMovingAverage просто не работает с данным кодом.


Я правильно понимаю, что единственный выход в данной ситуации это вереница if с проверкой какого типа индикатор и конвертацией Candle в подходящий для индикатора тип?
Автор топика
Спасибо:


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

loading
clippy