Как правильно рассчитать индикатор Fisher Transform - PullRequest
13 голосов
/ 12 мая 2019

Я пишу небольшую библиотеку технического анализа, которая состоит из элементов, которые недоступны в TA-lib. Я начал с примера, обнаруженного в cTrader , и сопоставил его с кодом, найденным в версии TradingView.

Вот код Pine Script из TradingView:

len = input(9, minval=1, title="Length")

high_ = highest(hl2, len)
low_ = lowest(hl2, len)

round_(val) => val > .99 ? .999 : val < -.99 ? -.999 : val

value = 0.0
value := round_(.66 * ((hl2 - low_) / max(high_ - low_, .001) - .5) + .67 * nz(value[1]))

fish1 = 0.0
fish1 := .5 * log((1 + value) / max(1 - value, .001)) + .5 * nz(fish1[1])

fish2 = fish1[1]

Вот моя попытка реализовать индикатор:

    public class FisherTransform : IndicatorBase
    {
        public int Length = 9;

        public decimal[] Fish { get; set; }
        public decimal[] Trigger { get; set; }

        decimal _maxHigh;
        decimal _minLow;

        private decimal _value1;
        private decimal _lastValue1;

        public FisherTransform(IEnumerable<Candle> candles, int length) 
            : base(candles)
        {
            Length = length;
            RequiredCount = Length;
            _lastValue1 = 1;
        }

        protected override void Initialize()
        {
            Fish = new decimal[Series.Length];
            Trigger = new decimal[Series.Length];
        }

        public override void Compute(int startIndex = 0, int? endIndex = null)
        {
            if (endIndex == null)
                endIndex = Series.Length;

            for (int index = 0; index < endIndex; index++)
            {
                if (index == 1)
                {
                    Fish[index - 1] = 1;
                }

                _minLow = Series.Average.Lowest(Length, index);
                _maxHigh = Series.Average.Highest(Length, index);

                _value1 = Maths.Normalize(0.66m * ((Maths.Divide(Series.Average[index] - _minLow, Math.Max(_maxHigh - _minLow, 0.001m)) - 0.5m) + 0.67m * _lastValue1));

                _lastValue1 = _value1;

                Fish[index] = 0.5m * Maths.Log(Maths.Divide(1 + _value1, Math.Max(1 - _value1, .001m))) + 0.5m * Fish[index - 1];
                Trigger[index] = Fish[index - 1];
            }
        }
    }

Класс IndicatorBase и класс CandleSeries

Помощники по математике

Проблема

Выходные значения находятся в ожидаемом диапазоне, однако мои перекрестные переходы Fisher Transform не совпадают с тем, что я вижу в версии индикатора TradingView.

Вопрос

Как правильно реализовать индикатор преобразования Фишера в C #? Я бы хотел, чтобы это соответствовало выводу TradingView в Fisher Transform.

Что я знаю

Я сверяю свои данные с другими индикаторами, которые я лично написал, и индикаторами из TA-Lib, и эти индикаторы проходят мои юнит-тесты. Я также проверил свои данные по свече данных TradingView за свечой и обнаружил, что мои данные соответствуют ожидаемым. Поэтому я не подозреваю, что мои данные - это проблема.

Особенности

Данные CSV - NFLX 5 минут агг

На рисунке ниже показан вышеупомянутый код преобразования Фишера, примененный к графику TradingView. Моя цель - максимально приблизить этот результат.

enter image description here

Фишер Голубой Триггер Пурпурный

Ожидаемые результаты:

Кроссовер завершен в 15:30 ET

  • Приблизительное значение Фишера составляет 2,86

  • Приблизительное значение триггера составляет 1,79

Кроссовер завершен в 10:45 ET

  • Приблизительное значение Фишера -3,67

  • Приблизительное значение триггера составляет -3,10

Мои фактические выводы:

Кроссовер завершен в 15:30 ET

  • Значение моего Фишера составляет 1,64

  • Значение моего триггера составляет 1,99

Кроссовер завершен в 10:45 ET

  • Значение моего Фишера -1,63

  • Значение моего триггера -2,00

Bounty

Чтобы сделать вашу жизнь проще, я включаю небольшое консольное приложение в комплекте с прохождением и провалом юнит-тестов. Все юнит-тесты проводится против того же набора данных. Проходящие юнит-тесты взяты из проверено работает индикатор простой скользящей средней . Отказавший блок тесты проводятся против рассматриваемого индикатора Fisher Transform .

Файлы проекта (обновлено 5/14)

Помогите сдать мои тесты FisherTransform, и я назначу награду.

enter image description here

Просто прокомментируйте, если вам нужны дополнительные ресурсы или информация.

Альтернативные ответы, которые я рассмотрю

  • Отправьте свой собственный рабочий FisherTransform в C #

  • Объясните, почему мой FisherTransform действительно работает как положено

1 Ответ

5 голосов
/ 14 мая 2019

Код содержит две ошибки.

1) неправильные дополнительные скобки.Правильная строка:

_value1 = Maths.Normalize(0.66m * (Maths.Divide(Series.Average[index] - _minLow, Math.Max(_maxHigh - _minLow, 0.001m)) - 0.5m) + 0.67m * _lastValue1);

2) Минимальные и максимальные функции должны быть:

public static decimal Highest(this decimal[] series, int length, int index)
{
    var maxVal = series[index]; // <----- HERE WAS AN ERROR!

    var lookback = Math.Max(index - length, 0);

    for (int i = index; i-- > lookback;)
        maxVal = Math.Max(series[i], maxVal);

    return maxVal;
}

public static decimal Lowest(this decimal[] series, int length, int index)
{
    var minVal = series[index]; // <----- HERE WAS AN ERROR!

    var lookback = Math.Max(index - length, 0);

    for (int i = index; i-- > lookback;)
    {
        //if (series[i] != 0) // <----- HERE WAS AN ERROR!
            minVal = Math.Min(series[i], minVal);
    }

    return minVal;
}

3) сбивающие с толку тестовые параметры.Пожалуйста, перепроверьте свои значения юнит-теста.ПОСЛЕ ОБНОВЛЕНИЯ ИСПЫТАНИЙ ВСЕ ЕЩЕ НЕ ИСПРАВЛЕНО.Например, первый FisherTransforms_ValuesAreReasonablyClose_First() имеет смешанные значения

var fish = result.Fish.Last(); //is equal to -3.1113144510775780365063063706
var trig = result.Trigger.Last(); //is equal to -3.6057793808025449204415435710

// TradingView Values for NFLX 5m chart at 10:45 ET
var fisherValue = -3.67m;
var triggerValue = -3.10m;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...