using KLHZ.Trader.Core.Contracts.Declisions.Dtos.Enums; using KLHZ.Trader.Core.Math.Common; namespace KLHZ.Trader.Core.Math.Declisions.Utils { public static class MovingAverage { internal static (DateTime time, decimal value) CalcTimeWindowAverageValue(DateTime[] timestamps, decimal[] values, int window, int shift = 0) { var sum = values[values.Length - 1 - shift]; var count = 1m; var startTime = timestamps[timestamps.Length - 1 - shift]; for (int i = 2; i < values.Length && startTime - timestamps[values.Length - i - shift] < TimeSpan.FromSeconds(window); i++) { sum += values[values.Length - i - shift]; count++; } return (startTime, sum / count); } public static (TradingEvent events, decimal bigWindowAv, decimal smallWindowAv) CheckByWindowAverageMean(DateTime[] timestamps, decimal[] prices, int size, int smallWindow, int bigWindow, decimal meanfullStep = 3m) { var res = TradingEvent.None; var bigWindowAv = 0m; var smallWindowAv = 0m; try { var pricesForFinalComparison = new decimal[size]; var twavss = new decimal[size]; var twavbs = new decimal[size]; var times = new DateTime[size]; for (int shift = 0; shift < size; shift++) { var twavs = CalcTimeWindowAverageValue(timestamps, prices, smallWindow, shift); var twavb = CalcTimeWindowAverageValue(timestamps, prices, bigWindow, shift); pricesForFinalComparison[size - 1 - shift] = prices[prices.Length - 1 - shift]; if (shift == 0) { bigWindowAv = twavb.value; smallWindowAv = twavs.value; } twavss[size - 1 - shift] = twavs.value; twavbs[size - 1 - shift] = twavb.value; times[size - 1 - shift] = twavb.time; if (System.Math.Abs(twavb.value - prices[prices.Length - 1]) > 2 * meanfullStep) { res |= TradingEvent.StopBuy; return (res, bigWindowAv, smallWindowAv); } if (shift > 0) { var i1 = size - 1 - shift; var i2 = size - shift; var isCrossing = Lines.IsLinesCrossing( times[i1], times[i2], twavss[i1], twavss[i2], twavbs[i1], twavbs[i2]); if (shift == 1 && !isCrossing) //если нет пересечения скользящих средний с окном 120 и 15 секунд между //текущей и предыдущей точкой - можно не продолжать выполнение. { break; } if (shift > 1 && isCrossing) { // если фильтрация окном 120 наползает на окно 15 сверху, потенциальное время открытия лонга и закрытия шорта if (twavbs[size - 1] <= twavss[size - 1] && twavbs[size - 2] > twavss[size - 2]) { if (pricesForFinalComparison[size - 1 - shift] - pricesForFinalComparison[size - 1] >= meanfullStep) { res |= TradingEvent.LongOpen; res |= TradingEvent.ShortClose; break; } } // если фильтрация окном 15 наползает на окно 120 сверху, потенциальное время закрытия лонга и возможно открытия шорта if (twavss[size - 1] <= twavbs[size - 1] && twavss[size - 2] > twavbs[size - 2]) { if (pricesForFinalComparison[size - 1 - shift] - pricesForFinalComparison[size - 1] <= -meanfullStep) { res |= TradingEvent.LongClose; res |= TradingEvent.ShortOpen; break; } } } } } } catch (Exception ex) { } return (res, bigWindowAv, smallWindowAv); } } }