NaN-арифметика

Ниже представлен код индикатора «Осциллятор бестрендовой цены» (Detrended Price Oscilator):

private MovingAverage movingAverage;
protected override void Initialize(){
  movingAverage = Indicators.SimpleMovingAverage(Source, Periods);
}
public override void Calculate(int index){
  Result[index] = Source[index] - movingAverage.Result[index - Periods / 2 - 1];
}

Как вы можете видеть, мы написали основной код для вычислений, но не определили никаких ограничений индикатора. Например, если мы используем среднюю скользящую с периодом 10, первые 9 значений не смогут быть точно просчитаны, и мы не сможем использовать эту формулу для параметра index менее 9. Более того, чтобы просчитать значение данного показателя, мы вводим значение средней скользящей index - Periods / 2 –1..В общем, нам следует добавить следующие условия:

public override void Calculate(int index){
  if (index >= Periods + Periods / 2 + 1) {
    Result[index] = Source[index] - movingAverage.Result[index - Periods / 2 - 1];
  }
}

Код простой средней скользящей также должен быть проверен параметром index >= Periods. Более того, если мы будем использовать другой вложенный индикатор, например, другой тип скользящей средней, данные условия должны быть другими. Исходные значения также могут быть результатом вычислений другого индикатора и состоять из не просчитанных значений, для начала. Все эти вещи делают процесс создания индикаторов более сложным, так как нам необходимо думать об автоматически настраиваемых параметрах индикаторов.

Для решения этой проблемы, можно использовать NaN-арифметику. Дело в том, что если значения индикатора не указаны, есть некоторые специальные значения, "Not a number" или NaN. Если мы используем эти значения в вычислениях, мы всегда получаем результат в виде NaN. Если мы используем не вычисленные значения или отрицательные значения серий данных, мы видим их как NaN. Плавающие цифры с типом double уже имеют данное значение: double.NaN , и необходимые параметры счета. Выполняя операции с NaN и обычными цифрами, вы всегда получаете NaN, т.е., double.NaN + 1.4 == double.NaN .Если вы запрашиваете негативный показатель, DataSeries выводит NaN, поэтому вы можете опустить все данные предварительные условия и ввести только основное правило счета индикатора. Если полученный результат будет содержать NaN в некоторых показателях, эти значения не будут наложены на график.

Рекурсивные индикаторы

Если вы подсчитываете рекурсивный индикатор, т.е., индикатор, значение которого зависит от предыдущего значения этого индикатора, вы должны ввести значение NaN «explicitly», как в примере ниже – для подсчета экспоненциальной средней скользящей:

public override void Calculate(int index) {
  var previousValue = Result[index - 1];
  if (double.IsNaN(previousValue)) {
    Result[index] = Source[index];
  } else {
    Result[index] = Source[index] * _exp + previousValue * (1 - _exp);
  }
}

В коде экспоненциальной средней скользящей, где текущее значение зависит от предыдущего, первым значением должно быть установлено «explicitly». Для проверки этого, мы используем метод double.IsNaN(previousValue) . Имейте в виду, что мы не можем использовать == данный оператор previousValue == double.IsNaN , потому что NaN == x всегда false, даже если x -это NaN.