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; #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(); } } #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 (var i = 1; i <= s28; i++) list[(int) i] = -1000000; for (var i = s30; i <= 127; i++) list[(int) 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 // если буффер стал достаточно большим (стал больше длины) if (IsFormed) { // удаляем хвостовое значение Buffer.RemoveAt(0); } Buffer.Add(newValue); return lastValue; } /// /// Сбросить состояние индикатора на первоначальное. Метод вызывается каждый раз, когда меняются первоначальные настройки (например, длина периода). /// public override void Reset() { Initialize(); base.Reset(); } } }