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 + shift < values.Length && startTime - timestamps[values.Length - i - shift] < TimeSpan.FromSeconds(window); i++) { var k = values.Length - i - shift; 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, TimeSpan timeForUptreandStart, decimal uptrendStartingDetectionMeanfullStep = 0m, decimal uptrendEndingDetectionMeanfullStep = 3m) { var res = TradingEvent.None; var bigWindowAv = 0m; var smallWindowAv = 0m; var s = 0; var pricesForFinalComparison = new decimal[size]; var twavss = new decimal[size]; var twavbs = new decimal[size]; var times = new DateTime[size]; var crossings = new List(); for (int shift = 0; shift < size - 1 && shift < prices.Length - 1; shift++) { s = shift; var i2 = size - 1 - shift; var i1 = size - 2 - shift; var twavs = CalcTimeWindowAverageValue(timestamps, prices, smallWindow, shift); var twavb = CalcTimeWindowAverageValue(timestamps, prices, bigWindow, shift); pricesForFinalComparison[i2] = prices[prices.Length - 1 - shift]; if (shift == 0) { bigWindowAv = twavb.value; smallWindowAv = twavs.value; } twavss[i2] = twavs.value; twavbs[i2] = twavb.value; times[i2] = twavb.time; if (shift > 0) { var isCrossing = Lines.IsLinesCrossing( times[i1 + 1], times[i2 + 1], twavss[i1 + 1], twavss[i2 + 1], twavbs[i1 + 1], twavbs[i2 + 1]); if (shift == 1 && !isCrossing.res) //если нет пересечения скользящих средний с окном 120 и 15 секунд между //текущей и предыдущей точкой - можно не продолжать выполнение. { break; } if (isCrossing.res) { crossings.Add(i2); if (crossings.Count == 6 || (shift + 1 == size - 1 || shift + 1 == prices.Length - 1)) { if ((shift + 1 == size - 1 || shift + 1 == prices.Length - 1)) { crossings.Add(shift); } var diffTotal = pricesForFinalComparison[crossings[0]] - pricesForFinalComparison[crossings[1]]; for (int crossingShift = 1; crossingShift < crossings.Count - 2; crossingShift++) { var diff = pricesForFinalComparison[crossings[crossingShift]] - pricesForFinalComparison[crossings[crossingShift + 1]]; if (diff >= -0.5m) { diffTotal += diff; } else { break; } } // если фильтрация окном 15 наползает на окно 120 сверху, потенциальное время закрытия лонга и возможно открытия шорта if (twavss[size - 1] <= twavbs[size - 1] && twavss[size - 2] > twavbs[size - 2]) { if (diffTotal >= uptrendEndingDetectionMeanfullStep && times[crossings[0]] - times[crossings[1]] >= timeForUptreandStart) { res |= TradingEvent.CloseLong; } break; } } if (crossings.Count == 2 || (shift + 1 == size - 1 || shift + 1 == prices.Length - 1)) { if ((shift + 1 == size - 1 || shift + 1 == prices.Length - 1)) { crossings.Add(shift); } // если фильтрация окном 120 наползает на окно 15 сверху, потенциальное время открытия лонга и закрытия шорта if (twavss[size - 1] >= twavbs[size - 1] && twavss[size - 2] < twavbs[size - 2]) { if (pricesForFinalComparison[crossings[0]] - pricesForFinalComparison[crossings[1]] <= uptrendStartingDetectionMeanfullStep && times[crossings[0]] - times[crossings[1]] >= timeForUptreandStart) { res |= TradingEvent.OpenLong; } break; } } } } } return (res, bigWindowAv, smallWindowAv); } public static (TradingEvent events, decimal bigWindowAv, decimal smallWindowAv) CheckByWindowAverageMean2(DateTime[] timestamps, decimal[] prices, int size, int smallWindow, int bigWindow, decimal? uptrendStartingDetectionMeanfullStep = null, decimal? uptrendEndingDetectionMeanfullStep = null) { var res = TradingEvent.None; var bigWindowAv = 0m; var smallWindowAv = 0m; var s = 0; var pricesForFinalComparison = new decimal[size]; var timesForFinalComparison = new DateTime[size]; var twavss = new decimal[size]; var twavbs = new decimal[size]; var times = new DateTime[size]; var crossings = new List(); var crossingValues = new List(); for (int shift = 0; shift < size - 1 && shift < prices.Length - 1; shift++) { s = shift; var i2 = size - 1 - shift; var i1 = size - 2 - shift; var twavs = CalcTimeWindowAverageValue(timestamps, prices, smallWindow, shift); var twavb = CalcTimeWindowAverageValue(timestamps, prices, bigWindow, shift); pricesForFinalComparison[i2] = prices[prices.Length - 1 - shift]; timesForFinalComparison[i2] = timestamps[prices.Length - 1 - shift]; if (shift == 0) { bigWindowAv = twavb.value; smallWindowAv = twavs.value; } twavss[i2] = twavs.value; twavbs[i2] = twavb.value; times[i2] = twavb.time; if (shift > 0) { var isCrossing = Lines.IsLinesCrossing( times[i1 + 1], times[i2 + 1], twavss[i1 + 1], twavss[i2 + 1], twavbs[i1 + 1], twavbs[i2 + 1]); if (shift == 1 && !isCrossing.res) //если нет пересечения скользящих средний с окном 120 и 15 секунд между //текущей и предыдущей точкой - можно не продолжать выполнение. { break; } if (isCrossing.res) { crossings.Add(i2); crossingValues.Add(isCrossing.y); if (crossings.Count == 2) { var dt = timesForFinalComparison[crossings[0]] - timesForFinalComparison[crossings[1]]; var d1 = pricesForFinalComparison[crossings[0]] - pricesForFinalComparison[crossings[1]]; var d2 = crossingValues[0] - crossingValues[1]; // если фильтрация окном 15 наползает на окно 120 сверху, потенциальное время закрытия лонга и возможно открытия шорта if (twavss[size - 1] <= twavbs[size - 1] && twavss[size - 2] > twavbs[size - 2]) { if (!uptrendEndingDetectionMeanfullStep.HasValue || ((d1 >= uptrendEndingDetectionMeanfullStep //|| d2 >= uptrendEndingDetectionMeanfullStep ) && dt > TimeSpan.FromSeconds(10))) { res |= TradingEvent.CloseLong; } break; } // если фильтрация окном 120 наползает на окно 15 сверху, потенциальное время открытия лонга и закрытия шорта if (twavss[size - 1] >= twavbs[size - 1] && twavss[size - 2] < twavbs[size - 2]) { if (!uptrendStartingDetectionMeanfullStep.HasValue || ((d1 <= uptrendStartingDetectionMeanfullStep // || d2 <= uptrendStartingDetectionMeanfullStep ) && dt > TimeSpan.FromSeconds(10))) { res |= TradingEvent.OpenLong; } break; } } } } } return (res, bigWindowAv, smallWindowAv); } } }