using KLHZ.Trader.Core.Contracts.Declisions.Dtos.Enums; using KLHZ.Trader.Core.Contracts.Declisions.Interfaces; using KLHZ.Trader.Core.Math.Declisions.Dtos; namespace KLHZ.Trader.Core.Math.Declisions.Utils { /// /// Обработка последних интервалов истории изменения цен. /// public static class LocalTrends { public static TradingEvent CheckByLocalTrends(DateTime[] times, decimal[] prices, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff, int boundIndex) { var res = TradingEvent.None; res |= CheckUptrendStart(times, prices, firstPeriod, secondPeriod, meanfullDiff, boundIndex); res |= CheckUptrendEnd(times, prices, firstPeriod, secondPeriod, meanfullDiff, boundIndex); return res; } internal static TradingEvent CheckUptrendStart(DateTime[] times, decimal[] prices, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff, int boundIndex) { var periodStat = GetTwoPeriodsProcessingData(times, prices, firstPeriod, secondPeriod, boundIndex, meanfullDiff); var isStartOk = periodStat.Success && periodStat.DiffStart < -meanfullDiff; var isEndOk = periodStat.Success && periodStat.DiffEnd >= meanfullDiff; return isStartOk && isEndOk && prices[periodStat.Start] - prices[periodStat.End] >= meanfullDiff ? TradingEvent.UptrendStart : TradingEvent.None; } internal static TradingEvent CheckUptrendEnd(DateTime[] times, decimal[] prices, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff, int boundIndex) { var periodStat = GetTwoPeriodsProcessingData(times, prices, firstPeriod, secondPeriod, boundIndex, meanfullDiff); var isStartOk = periodStat.Success && periodStat.DiffStart > 0 && periodStat.DiffStart > 1.5m * meanfullDiff; var isEndOk = periodStat.Success && periodStat.DiffEnd < meanfullDiff; return isStartOk && isEndOk && prices[periodStat.End] - prices[periodStat.Start] >= meanfullDiff ? TradingEvent.UptrendEnd : TradingEvent.None; ; } internal static TwoLocalTrendsResultDto GetTwoPeriodsProcessingData(DateTime[] times, decimal[] prices, TimeSpan firstPeriod, TimeSpan lastPeriod, int boundIndex, decimal meanfullDiff) { var res = new TwoLocalTrendsResultDto(success: false, 0, 0, 0, 0, 0, TimeSpan.Zero, TimeSpan.Zero); int count = -1; var lastTime = times[times.Length - 1]; var bound = -1; var start = -1; var end = times.Length - 1; for (int i = times.Length - 1; i > -1; i--) { if (count > 0 && bound < 0 && (count == boundIndex || lastTime - times[i] >= lastPeriod)) { bound = i; lastPeriod = lastTime - times[i]; } if (lastTime - times[i] >= lastPeriod + firstPeriod) { start = i; break; } count++; } if (start < bound && start >= 0 && bound > 0) { var diff1 = prices[bound] - prices[start]; var diff2 = prices[end] - prices[bound]; res = new TwoLocalTrendsResultDto(true, diff1, diff2, start, bound, end, times[bound] - times[start], times[end] - times[bound]); } return res; } internal static bool CheckLongOpen(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff, int boundIndex) { var data = unit.GetData().Result; var periodStat = GetTwoPeriodsProcessingData(data.timestamps, data.prices, firstPeriod, secondPeriod, boundIndex, meanfullDiff); var isStartOk = periodStat.Success && periodStat.DiffStart < -meanfullDiff; var isEndOk = periodStat.Success && periodStat.DiffEnd >= meanfullDiff; return isStartOk && isEndOk && data.prices[periodStat.Start] - data.prices[periodStat.End] >= meanfullDiff; } internal static bool CheckLongClose(this IPriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, decimal meanfullDiff, int boundIndex) { var data = unit.GetData().Result; var periodStat = GetTwoPeriodsProcessingData(data.timestamps, data.prices, firstPeriod, secondPeriod, boundIndex, meanfullDiff); var isStartOk = periodStat.Success && periodStat.DiffStart > 0 && periodStat.DiffStart > 1.5m * meanfullDiff; var isEndOk = periodStat.Success && periodStat.DiffEnd < meanfullDiff; return isStartOk && isEndOk && data.prices[periodStat.End] - data.prices[periodStat.Start] >= meanfullDiff; } internal static TradingEvent Detect(IPriceHistoryCacheUnit data) { decimal meanfullDiff = 1m; var res = TradingEvent.None; //var downtrendStarts = data.CheckDowntrendStarting(TimeSpan.FromSeconds(30), TimeSpan.FromSeconds(7), meanfullDiff); var uptrendStarts = data.CheckLongOpen(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(7), meanfullDiff, 3); var uptrendStarts2 = data.CheckLongOpen(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(3), meanfullDiff, 2); var downtrendEnds = data.CheckLongOpen(TimeSpan.FromSeconds(120), TimeSpan.FromSeconds(10), meanfullDiff, 5); uptrendStarts |= downtrendEnds; uptrendStarts |= uptrendStarts2; if (uptrendStarts) { res |= TradingEvent.LongClose; } //var downtrendEnds = data.CheckDowntrendEnding(TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(15), meanfullDiff); var uptrendEnds = data.CheckLongClose(TimeSpan.FromSeconds(15), TimeSpan.FromSeconds(20), meanfullDiff * 1.5m, 8); var uptrendEnds2 = data.CheckLongClose(TimeSpan.FromSeconds(120), TimeSpan.FromSeconds(30), meanfullDiff, 8); uptrendEnds |= uptrendEnds2; if (uptrendEnds) { res |= TradingEvent.LongOpen; } return res; } } }