using System;
namespace StockSharp.Algo.Indicators.Trend
{
using System.ComponentModel;
///
/// Юриковская (Jurik's) скользящая средняя.
///
[DisplayName("JMA")]
[Description("Юриковская (Jurik's) скользящая средняя.")]
public class JurikMovingAverage : LengthIndicator
{
private int phase = 0;
private int direction = 0;
#region Описание переменных
int jj = 0;
int ii = 0;
double series = 0;
double vv = 0;
double v1 = 0;
double v2 = 0;
double v3 = 0;
double v4 = 0;
double s8 = 0;
double s10 = 0;
double s18 = 0;
double s20 = 0;
int v5 = 0;
int v6 = 0;
double s28 = 0;
double s30 = 0;
int s38 = 0;
int s40 = 0;
int s48 = 0;
int s50 = 0;
int s58 = 0;
int s60 = 0;
double s68 = 0;
double s70 = 0;
double f8 = 0;
double f10 = 0;
double f18 = 0;
double f20 = 0;
double f28 = 0;
double f30 = 0;
double f38 = 0;
double f40 = 0;
double f48 = 0;
double f50 = 0;
double f58 = 0;
double f60 = 0;
double f68 = 0;
double f70 = 0;
double f78 = 0;
double f80 = 0;
double f88 = 0;
double f90 = 0;
double f98 = 0;
double fA0 = 0;
double fA8 = 0;
double fB0 = 0;
double fB8 = 0;
double fC0 = 0;
double fC8 = 0;
double fD0 = 0;
int f0 = 0;
int fD8 = 0;
int fE0 = 0;
int fE8 = 0;
int fF0 = 0;
int fF8 = 0;
int value2 = 0;
double[] list = new double[128];
double[] ring1 = new double[128];
double[] ring2 = new double[11];
double[] buffer = new double[62];
#endregion
#region Свойства
///
/// Фаза
///
public int Phase
{
get
{
return phase;
}
set
{
phase = value;
if (phase > 100)
phase = 100;
else if (phase < -100)
phase = -100;
Reset();
}
}
///
/// Текущее направление тренда
///
public int LastDirection
{
get
{
return this.direction;
}
}
#endregion
///
/// Создать .
///
public JurikMovingAverage()
: base(typeof(decimal))
{
Initialize();
}
///
/// Начальная инициализация переменных
///
public void Initialize()
{
jj = 0;
ii = 0;
series = 0;
vv = 0;
v1 = 0;
v2 = 0;
v3 = 0;
v4 = 0;
s8 = 0;
s10 = 0;
s18 = 0;
s20 = 0;
v5 = 0;
v6 = 0;
s28 = 0;
s30 = 0;
s38 = 0;
s40 = 0;
s48 = 0;
s50 = 0;
s58 = 0;
s60 = 0;
s68 = 0;
s70 = 0;
f8 = 0;
f10 = 0;
f18 = 0;
f20 = 0;
f28 = 0;
f30 = 0;
f38 = 0;
f40 = 0;
f48 = 0;
f50 = 0;
f58 = 0;
f60 = 0;
f68 = 0;
f70 = 0;
f78 = 0;
f80 = 0;
f88 = 0;
f90 = 0;
f98 = 0;
fA0 = 0;
fA8 = 0;
fB0 = 0;
fB8 = 0;
fC0 = 0;
fC8 = 0;
fD0 = 0;
f0 = 0;
fD8 = 0;
fE0 = 0;
fE8 = 0;
fF0 = 0;
fF8 = 0;
value2 = 0;
list = new double[128];
ring1 = new double[128];
ring2 = new double[11];
buffer = new double[62];
s28 = 63;
s30 = 64;
for (int i = 1; i <= (int)s28; i++)
list[i] = -1000000;
for (int i = (int)s30; i <= 127; i++)
list[i] = 1000000;
f0 = 1;
}
///
/// Обработать входное значение.
///
/// Входное значение.
/// Результирующее значение.
public override decimal OnProcess(IIndicatorValue input)
{
var lastValue = LastValue;
var newValue = input.GetValue();
#region Расчет JMA
series = (double)newValue;
if (fF0 < 61)
{
fF0 = fF0 + 1;
buffer[fF0] = series;
}
//{ main cycle }
if (fF0 > 30)
{
if (Length < 1.0000000002)
{
f80 = 0.0000000001; //{1.0e-10}
}
else
{
f80 = (Length - 1) / 2.0;
}
if (phase < -100)
{
f10 = 0.5;
}
else
{
if (phase > 100)
{
f10 = 2.5;
}
else
{
f10 = (double)phase / 100 + 1.5;
}
}
v1 = Math.Log(Math.Sqrt(f80));
v2 = v1;
if (v1 / Math.Log(2.0) + 2.0 < 0.0)
{
v3 = 0;
}
else
{
v3 = v2 / Math.Log(2.0) + 2.0;
}
f98 = v3;
//----
if (0.5 <= f98 - 2.0)
{
f88 = f98 - 2.0;
}
else
{
f88 = 0.5;
}
f78 = Math.Sqrt(f80) * f98;
f90 = f78 / (f78 + 1.0);
f80 = f80 * 0.9;
f50 = f80 / (f80 + 2.0);
//----
if (f0 != 0)
{
f0 = 0;
v5 = 0;
for (ii = 1; ii <= 29; ii++)
{
if (buffer[ii + 1] != buffer[ii])
{
v5 = 1;
}
}
fD8 = v5 * 30;
if (fD8 == 0)
{
f38 = series;
}
else
{
f38 = buffer[1];
}
f18 = f38;
if (fD8 > 29)
fD8 = 29;
}
else
fD8 = 0;
//----
for (ii = fD8; ii >= 0; ii--)
{
//{ another bigcycle...}
value2 = 31 - ii;
if (ii == 0)
{
f8 = series;
}
else
{
f8 = buffer[value2];
}
f28 = f8 - f18;
f48 = f8 - f38;
if (Math.Abs(f28) > Math.Abs(f48))
{
v2 = Math.Abs(f28);
}
else
{
v2 = Math.Abs(f48);
}
fA0 = v2;
vv = fA0 + 0.0000000001; //{1.0e-10;}
//----
if (s48 <= 1)
{
s48 = 127;
}
else
{
s48 = s48 - 1;
}
if (s50 <= 1)
{
s50 = 10;
}
else
{
s50 = s50 - 1;
}
if (s70 < 128)
s70 = s70 + 1;
s8 = s8 + vv - ring2[s50];
ring2[s50] = vv;
if (s70 > 10)
{
s20 = s8 / 10;
}
else
s20 = s8 / s70;
//----
if (s70 > 127)
{
s10 = ring1[s48];
ring1[s48] = s20;
s68 = 64;
s58 = Convert.ToInt32(s68);
while (s68 > 1)
{
if (list[s58] < s10)
{
s68 = s68 * 0.5;
s58 = s58 + Convert.ToInt32(s68);
}
else
if (list[s58] <= s10)
{
s68 = 1;
}
else
{
s68 = s68 * 0.5;
s58 = s58 - Convert.ToInt32(s68);
}
}
}
else
{
ring1[s48] = s20;
if (s28 + s30 > 127)
{
s30 = s30 - 1;
s58 = Convert.ToInt32(s30);
}
else
{
s28 = s28 + 1;
s58 = Convert.ToInt32(s28);
}
if (s28 > 96)
{
s38 = 96;
}
else
s38 = Convert.ToInt32(s28);
if (s30 < 32)
{
s40 = 32;
}
else
s40 = Convert.ToInt32(s30);
}
//----
s68 = 64;
s60 = Convert.ToInt32(s68);
while (s68 > 1)
{
if (list[s60] >= s20)
{
if (list[s60 - 1] <= s20)
{
s68 = 1;
}
else
{
s68 = s68 * 0.5;
s60 = s60 - Convert.ToInt32(s68);
}
}
else
{
s68 = s68 * 0.5;
s60 = s60 + Convert.ToInt32(s68);
}
if ((s60 == 127) && (s20 > list[127]))
s60 = 128;
}
if (s70 > 127)
{
if (s58 >= s60)
{
if ((s38 + 1 > s60) && (s40 - 1 < s60))
{
s18 = s18 + s20;
}
else
if ((s40 > s60) && (s40 - 1 < s58))
s18 = s18 + list[s40 - 1];
}
else
if (s40 >= s60)
{
if ((s38 + 1 < s60) && (s38 + 1 > s58))
s18 = s18 + list[s38 + 1];
}
else
if (s38 + 2 > s60)
{
s18 = s18 + s20;
}
else
if ((s38 + 1 < s60) && (s38 + 1 > s58))
s18 = s18 + list[s38 + 1];
if (s58 > s60)
{
if ((s40 - 1 < s58) && (s38 + 1 > s58))
{
s18 = s18 - list[s58];
}
else
if ((s38 < s58) && (s38 + 1 > s60))
s18 = s18 - list[s38];
}
else
{
if ((s38 + 1 > s58) && (s40 - 1 < s58))
{
s18 = s18 - list[s58];
}
else
if ((s40 > s58) && (s40 < s60))
s18 = s18 - list[s40];
}
}
if (s58 <= s60)
{
if (s58 >= s60)
{
list[s60] = s20;
}
else
{
for (jj = s58 + 1; jj <= s60 - 1; jj++)
{
list[jj - 1] = list[jj];
}
list[s60 - 1] = s20;
}
}
else
{
for (jj = s58 - 1; jj >= s60; jj--)
{
list[jj + 1] = list[jj];
}
list[s60] = s20;
}
if (s70 <= 127)
{
s18 = 0;
for (jj = s40; jj <= s38; jj++)
{
s18 = s18 + list[jj];
}
}
f60 = s18 / (s38 - s40 + 1);
if (fF8 + 1 > 31)
{
fF8 = 31;
}
else
fF8 = fF8 + 1;
//----
if (fF8 <= 30)
{
if (f28 > 0)
{
f18 = f8;
}
else
f18 = f8 - f28 * f90;
if (f48 < 0)
{
f38 = f8;
}
else
f38 = f8 - f48 * f90;
fB8 = series;
if (fF8 != 30)
{
continue;
}
if (fF8 == 30)
{
fC0 = series;
if (Math.Ceiling(f78) >= 1)
{
v4 = Math.Ceiling(f78);
}
else
v4 = 1;
fE8 = (int)Math.Ceiling(v4);
if (Math.Floor(f78) >= 1)
{
v2 = Math.Floor(f78);
}
else
v2 = 1;
fE0 = (int)Math.Ceiling(v2);
if (fE8 == fE0)
{
f68 = 1;
}
else
{
v4 = fE8 - fE0;
f68 = (f78 - fE0) / v4;
}
if (fE0 <= 29)
{
v5 = Convert.ToInt32(fE0);
}
else
v5 = 29;
if (fE8 <= 29)
{
v6 = Convert.ToInt32(fE8);
}
else
v6 = 29;
fA8 = (series - buffer[fF0 - v5]) * (1 - f68) / fE0 + (series - buffer[fF0 - v6]) * f68 / fE8;
}
}
else
{
if (f98 >= Math.Pow(fA0 / f60, f88))
{
v1 = Math.Pow(fA0 / f60, f88);
}
else
v1 = f98;
if (v1 < 1)
{
v2 = 1;
}
else
{
if (f98 >= Math.Pow(fA0 / f60, f88))
{
v3 = Math.Pow(fA0 / f60, f88);
}
else
v3 = f98;
v2 = v3;
}
f58 = v2;
f70 = Math.Pow(f90, Math.Sqrt(f58));
if (f28 > 0)
{
f18 = f8;
}
else
{
f18 = f8 - f28 * f70;
}
if (f48 < 0)
{
f38 = f8;
}
else
{
f38 = f8 - f48 * f70;
}
}
}
if (fF8 > 30)
{
f30 = Math.Pow(f50, f58);
fC0 = (1 - f30) * series + f30 * fC0;
fC8 = (series - fC0) * (1 - f50) + f50 * fC8;
fD0 = f10 * fC8 + fC0;
f20 = -f30 * 2;
f40 = f30 * f30;
fB0 = f20 + f40 + 1;
fA8 = (fD0 - fB8) * fB0 + f40 * fA8;
fB8 = fB8 + fA8;
}
lastValue = (decimal)fB8;
}
if (fF0 <= 30)
{
lastValue = newValue;
}
#endregion
// Добавляем направление тренда
direction = 0;
// Сравниваем новое получившееся значение индикатора со старым
if (lastValue > LastValue)
direction = 1;
else if (lastValue < LastValue)
direction = -1;
// если буффер стал достаточно большим (стал больше длины)
if (IsFormed)
{
// удаляем хвостовое значение
Buffer.RemoveAt(0);
}
Buffer.Add(newValue);
return lastValue;
}
///
/// Сбросить состояние индикатора на первоначальное. Метод вызывается каждый раз, когда меняются первоначальные настройки (например, длина периода).
///
public override void Reset()
{
Initialize();
base.Reset();
}
}
}