Mikhail Sukhov Соответственно, при регистрации индикатора мне кажется имеет смысл передавать туда object. Object будет или CandleToken, или MarketDepth (или Security).
Начал я реализовывать это дело и понял, что не клеется. Дело в том, что одного объекта не достаточно для однозначной идентификации источника. Так как очень много индикаторов строится не на свечах, а просто на числовом ряде, то нужно из свечей уметь делать числа. По текущей концепции эта задача ложится на BaseCandleIndicatorSource, от которого унаследован CandleTokenIndicatorSource. Таким образом, получаем, что клиентский код должен сообщить менеджеру 3 параметра: индикатор, токен свечи, функцию преобразования. Если же индикатор строится целиком на свече, то 2 параметра. Может есть случаи, когда нужно и больше параметров для однозначной идентификации источника. Получается передавать object не достаточно.
Вижу следующие варианты решения:
Вариант 1. Передавать не object, а массив object[]. Все остальное как и было. Единственный минус - коряво это как-то. Из сигнатуры метода не ясно как им пользоваться, проверка корректности только во время выполнения, нужно знать как заполнять этот массив для каждого типа индикаторов. Пытались упростить использование менеджера, а получилась совершенно не прозрачная структура.
Вариант 2. Ввести новую абстракцию IIndicatorSourceIdentifier, сделать несколько реализаций для свечей, частей свечей и т.д. По сути, для каждого источника своя реализация IIndicatorSourceIdentifier. Клиентский код будет создавать соответствующий класс, заполнять параметрами и вперед.
Вариант 3. Помыслив над вторым вариантом не увидил большой разницы с тем что уже есть. Клиентский код передает IIndicatorSource. Если посмотреть на вариант 2, то абстракция IIndicatorSourceIdentifier служит только для одной функции: идентифицировать источник, для создания этого идентификатора нужны те же параметры, что и для самого источника. Соответственно, если аккуратно переопределить Equals у источников, то клиентский код останется одинаковым. Отсюда вопрос стоит ли плодить новые сущности в данном случае?
Хочу еще заметить, что для 3его варианта не нужно хранить список источников в клиентском коде. Можно просто при регистрации индикатора создавать новый источник, IndicatorManager сам найдет соответсвующий ему источник в своей коллекции и будет использовать его. Предварительная регистрация источников не нужна как в том так и в другом случае.
Для этих вариантов клиентский код будет выглядеть примерно так (на мой взгляд это где-то в инициализации стратегии):
Вариант 1.
Код
var candleToken = candleManager.RegisterTimeFrameCandles(security, timeFrame);
var indicatorToken = indicatorManager.RegisterIndicator(new SimpleMovingAverage { Length = 80 },
new object[] {candleToken, BaseCandleIndicatorSource.ByOpen});
Вариант 2.
Код
var candleToken = candleManager.RegisterTimeFrameCandles(security, timeFrame);
var indicatorToken = indicatorManager.RegisterIndicator(new SimpleMovingAverage { Length = 80 },
new CandleTokenSourceIdentifier (candleToken, BaseCandleIndicatorSource.ByOpen));
Вариант 3.
Код
var candleToken = candleManager.RegisterTimeFrameCandles(security, timeFrame);
var indicatorToken = indicatorManager.RegisterIndicator(new SimpleMovingAverage { Length = 80 },
new CandleTokenIndicatorSource (candleToken, BaseCandleIndicatorSource.ByOpen));
Вариант 1 мне не нравится. Варианты 2 и 3 считаю приемлемыми, пока наиболее склоняюсь к варианту 3, так как сущность IIndicatorSourceIdentifier не несет большой нагрузки и вполне может быть объеденина с сущностью IIndicatorSource.
Оставляем 3й варианта, может есть новые идеи?