Привет,
осваиваю Stocksharp, очень нравится :)
Нужно использовать индикатор ATR, нигде примеров не нашел, только на кодеплексе в тест кейсе.
Соответственно, пытаюсь его рассчитать:
var atr = new AverageTrueRange { Length = 15 };
...
TimeFrameCandle cdl = _candleManager.GetTimeFrameCandle(_candleToken, 1);
try {
atr.Process((CandleIndicatorValue)cdl);
} catch (Exception ex) {
Error(ex.Message + " stacktrace: " + ex.StackTrace);
}
В результате на строке atr.Process происходит следующее исключение:
Invalid cast from 'System.Decimal' to 'StockSharp.Algo.Candles.Candle'.
stacktrace: at System.Convert.DefaultToType(IConvertible value, Type targetType, IFormatProvider provider)
at System.Decimal.System.IConvertible.ToType(Type type, IFormatProvider provider)
at System.Convert.ChangeType(Object value, Type conversionType, IFormatProvider provider)
at Ecng.Common.Converter.To(Object value, Type destinationType)
at Ecng.Common.Converter.To[T](Object value)
at StockSharp.Algo.Indicators.CandleIndicatorValue.SetValue[T](T value)
at StockSharp.Algo.Indicators.BaseIndicator`1.Process(IIndicatorValue input)
at StockSharp.Algo.Indicators.Oscillator.AverageTrueRange.OnProcess(IIndicatorValue input)
at StockSharp.Algo.Indicators.BaseIndicator`1.Process(IIndicatorValue input)
at test.stocksharp.IndicatorTest.newCandle()
Версия стокшарпа: 4.0.3.
Подскажите куда копать, как побороть? В тесте вроде тоже производится просто каст свечи к CandleIndicatorValue
Комментарии (18)
Вход или Создать аккаунт, Войдите или зарегистрируйтесь, чтобы оставить комментарий
Тест для ATR валится с такой же ошибкой:
Не могли бы вы привести пример? Пробую так
Значение "((AverageTrueRange)ATRToken.Indicator).isFormed" всегда false Как правильно инициализировать?
Подтверждаю тоже самое что говорит pehas: обновил стокшарп до последней версии. Создаю indicatorManager однако индикатор никогда не строится. isFormed всегда false + IndicatorToken.Indicator.OnChanged ни разу не вызывается.
Попробую взять проект с кодекплекса и посмотреть дебагом что там в индикаторе творится :)
Значит так, я нашел две проблемы и сделал хотфиксы, однако мне нужен ревью от кого нибудь кто больше понимает в проекте.
Проблема №1. Если использовать индикатор AverageTrueRange через IndicatorManager то он никогда не расчитывается. Проблема в файле AverageTrueRange.cs строчка 92:
Тут проверяется может ли индикатор обработать входящее значение. ATR построили как комбинацию TrueRange (который принимает параметр Candle а результатом вычисления является double) и SMA (вход double и выход double). Вообщем это условие будет всегда ложно, т.к. в функцию передается свечка а MA ее не может обработать. Поэтому просто меняем ее на:
Проблема №2. После этого изменения у нас будет опять выбрасываться старый эксепшн, из-за которого я открыл этот топик. Ищем откуда растут ноги, смотрим на файл BaseIndicator.cs в районе строки 129 функция Process:
Экспешн происходит на строчке
Пытаемся понять что тут происходит. Ага, получается так: мы вычисляем значение индикатор через своего потомка (нас ведь создадут наследовав от BaseIndicator), но вот незадача: что бы быть type safe нам нужно вернуть значение IIndicatorValue, а что может вернуть наша текущая реализация мы не знаем. Поэтому мы смотрим: если то что вернул process является IIndicatorValue то, возвращаем его, иначе, мы считаем что значение должно быть того же типа что было входящее!
Вот тут то и приходит пушной зверек сверкая глазками. Дело в том что TrueRange принимает на вход Candle а возвращает Double. Здесь и происходит класс каст эксепшн.
К сожалению, я пока еще не знаю всю структуру проекта, поэтому не придумал ничего лучшего как сделать такой хотфикс, который поидее ничего не должен сломать, но починить этот эксепшн. Заменяем строку 135 на:
После этого atr начинает работать :)
Но я думаю это стоит починить по-правильному.
По поводу ATR, он работает без фиксов, если его инициализировать вот так:
То что там используется BaseCandleIndicatorSource.ByClose реального значения не имеет, так как исходный индикатор будет получать свечу целиком, но источник будет передавать в индикатор класс CandlePartIndicatorValue, который поддерживает тип decimal.
Наверное это не очень красиво, но работает. По поводу правильного решения, может следует сделать реализацию IIndicatorValue подобную той, которая в тесте, что бы она могла содержать любые значения и обучить текущие реализации содавать такие классы? Тогда выходные значения полностью развяжутся с входными, что, как мне кажется, логично. На эту тему нужно еще подумать.
Я так понял был еще и коммит. Не плохо бы отписывать в таких случаях. Я сделал небольшой фикс на коммит. Но не могу понять следующую ситуацию. Почему в SetValue null не является ошибочной ситуацией? Мне кажется это всегда ошибка. Нельзя передавать Candle == null.
IndicatorManager.RegisterIndicator(new AverageTrueRange(), new CandleTokenIndicatorSource(candleToken, BaseCandleIndicatorSource.ByClose));
Спасибо, буду знать что можно так инициализировать.
Аналогичная проблема, борюсь с фракталами
Выдает ошибку
Недопустимое приведение "System.Int32" к "StockSharp.Algo.Candles.Candle".
Что не так делаю?
Посмотрел дебагом индиктор фракталов, падает в
в
[left]try { _strategy.FractalsValues.Process((CandleIndicatorValue)candle); } catch (System.Exception ex) { MessageBox.Show(ex.Message); }[/left]
return base.OnProcess(new ShiftedIndicatorValue(0, input.SetValue(0)));
[left]try { _strategy.FractalsValues.Process((CandleIndicatorValue)candle); } catch (System.Exception ex) { MessageBox.Show(ex.Message); }[/left]
return base.OnProcess(new ShiftedIndicatorValue(0, input.SetValue(0)));
[left]try { _strategy.FractalsValues.Process((CandleIndicatorValue)candle); } catch (System.Exception ex) { MessageBox.Show(ex.Message); }[/left]
return base.OnProcess(new ShiftedIndicatorValue(0, input.SetValue(0)));
Это ваш код, следовательно, ошибка у вас, а не в S#. Вы приводите Int32 к CandleIndicatorValue, а не S#, разве нет?
Да, это мой код, но candle у меня это объект типа TimeFrameCandle. Если посмотреть OnProcess индикатора фракталов, который идет в библиотеке индикаторов, то:
Насколько я понял, на вход он получает свечу ```csharp input.GetValue<Candle>();
а ошибка происходит в том же OnProcess в строке
и ошибка понятна, потому-что input у нас типа Candle а мы задаем ему Int32. Поэтому тут два варианта, либо на вход нужно подавать не свечу, а что-то другое, либо в input.SetValue(0) задавать не 0, а какую-то свечу. Я только начал разбираться, поэтому еще не до конца понял логику этих индикаторов, подскажите плз.
Это ваш код, следовательно, ошибка у вас, а не в S#. Вы приводите Int32 к CandleIndicatorValue, а не S#, разве нет?
Да, это мой код, но candle у меня это объект типа TimeFrameCandle. Если посмотреть OnProcess индикатора фракталов, который идет в библиотеке индикаторов, то:
Насколько я понял, на вход он получает свечу ```csharp input.GetValue<Candle>();
а ошибка происходит в том же OnProcess в строке
и ошибка понятна, потому-что input у нас типа Candle а мы задаем ему Int32. Поэтому тут два варианта, либо на вход нужно подавать не свечу, а что-то другое, либо в input.SetValue(0) задавать не 0, а какую-то свечу. Я только начал разбираться, поэтому еще не до конца понял логику этих индикаторов, подскажите плз.
Если на входе свеча, а на выходе число, то там используется CandlePartIndicatorValue, а не CandleIndicatorValue. Весь исходный код индикаторов открыт, так что если есть возможность посмотреть самому - вполне логично этой возможностью воспользоваться.
Никак. Но если возникла такая необходимость, то можно отнаследоваться от BaseCandleIndicatorSource и вызывать у него NewCandles(candles)