using KLHZ.Trader.Core.Declisions.Models; namespace KLHZ.Trader.Core.Declisions.Utils { internal static class HistoryProcessingInstruments { internal static PeriodPricesInfo GetPriceDiffForTimeSpan(this PriceHistoryCacheUnit unit, TimeSpan timeShift, TimeSpan timeSpan, int? pointsShift = null) { var res = new PeriodPricesInfo(false, 0, 0, 0, 0, 0, timeSpan, 0, 0); var data = unit.GetData(); var times = data.timestamps; var prices = data.prices; if (times.Length < 2) return res; var lastPriceTime = times[times.Length - 1]; var intervalEnd = lastPriceTime - timeShift; var intervalStart = intervalEnd - timeSpan; var max = float.MinValue; var min = float.MaxValue; var intervaEndIndex = -1; var intervaStartIndex = -1; int count = 0; for (int i = times.Length - 1; i > -1; i--) { if ((times[i] <= intervalEnd || (pointsShift.HasValue && count < pointsShift.Value)) && intervaEndIndex < 0) { intervaEndIndex = i; } if (prices[i] > max && intervaEndIndex >= 0) { max = prices[i]; } if (prices[i] < min && intervaEndIndex >= 0) { min = prices[i]; } if (times[i] <= intervalStart && intervaStartIndex < 0) { intervaStartIndex = i; if (intervaStartIndex != intervaEndIndex && intervaEndIndex >= 0) break; } count++; } if (intervaStartIndex >= 0 && intervaEndIndex >= 0) { res = new PeriodPricesInfo( true, prices[intervaStartIndex], prices[intervaEndIndex], prices[intervaEndIndex] - prices[intervaStartIndex], min, max, timeSpan, intervaStartIndex, intervaEndIndex); } return res; } internal static bool CheckStable(this PeriodPricesInfo data, float meanfullDiff) { meanfullDiff = Math.Abs(meanfullDiff); return data.Success && Math.Abs(data.PeriodDiff) < 1.5 * meanfullDiff && Math.Abs(data.PeriodMax - data.PeriodMin) < 2 * meanfullDiff; } internal static bool CheckGrowing(this PeriodPricesInfo data, float meanfullDiff) { return meanfullDiff > 0 && data.Success && data.PeriodDiff > meanfullDiff && Math.Abs(data.PeriodMax - data.PeriodMin) < 3 * Math.Abs(data.PeriodDiff); } internal static bool CheckFalling(this PeriodPricesInfo data, float meanfullDiff) { meanfullDiff = -meanfullDiff; return meanfullDiff < 0 && data.Success && data.PeriodDiff < meanfullDiff && Math.Abs(data.PeriodMax - data.PeriodMin) < 3 * Math.Abs(data.PeriodDiff); } internal static float CalcTrendRelationAbs(PeriodPricesInfo first, PeriodPricesInfo second) { var k1 = Math.Abs(first.PeriodDiff) / Math.Abs(first.Period.TotalSeconds); var k2 = Math.Abs(second.PeriodDiff) / Math.Abs(second.Period.TotalSeconds); if (k2 == 0 && k1 != 0) return 1000; return (float)(k1 / k2); } internal static float CalcTrendRelationAbs(TwoPeriodsProcessingData data) { var k1 = Math.Abs(data.DiffStart) / Math.Abs(data.PeriodStart.TotalSeconds); var k2 = Math.Abs(data.DiffEnd) / Math.Abs(data.PeriodEnd.TotalSeconds); if (k2 == 0 && k1 != 0) return 1000; return (float)(k1 / k2); } internal static bool CheckDowntrendEnding(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff) { var totalDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, firstPeriod + secondPeriod); var startDiff = unit.GetPriceDiffForTimeSpan(secondPeriod, firstPeriod); var endDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, secondPeriod); var isEndStable = endDiff.CheckStable(meanfullDiff); var isEndGrown = endDiff.CheckGrowing(meanfullDiff); var isStartFalls = startDiff.CheckFalling(meanfullDiff); var isTotalFalls = totalDiff.CheckFalling(meanfullDiff); var trendRelation = CalcTrendRelationAbs(startDiff, endDiff); var res = totalDiff.Success && isStartFalls && (isEndStable || isEndGrown) && trendRelation >= 2; if (startDiff.Success) { } return res; } internal static bool CheckUptrendEnding(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff) { var totalDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, firstPeriod + secondPeriod); var startDiff = unit.GetPriceDiffForTimeSpan(secondPeriod, firstPeriod); var endDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, secondPeriod); var isEndStable = endDiff.CheckStable(meanfullDiff); var isEndFalls = endDiff.CheckFalling(meanfullDiff); var isStartGrows = startDiff.CheckGrowing(meanfullDiff); var trendRelation = CalcTrendRelationAbs(startDiff, endDiff); var isEndLocal = endDiff.PeriodDiff == 0; var res = totalDiff.Success && isStartGrows && (isEndStable || isEndFalls) && (trendRelation >= 2 && !isEndLocal); if (res) { } return res; } internal static bool CheckDowntrendStarting(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff) { var totalDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, firstPeriod + secondPeriod); var startDiff = unit.GetPriceDiffForTimeSpan(secondPeriod, firstPeriod); var endDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, secondPeriod); var isEndFalls = endDiff.CheckFalling(meanfullDiff); var isStartStable = startDiff.CheckStable(meanfullDiff); var isStartGrows = startDiff.CheckGrowing(meanfullDiff); var trendRelation = CalcTrendRelationAbs(endDiff, startDiff); return totalDiff.Success && (isStartStable || isStartGrows) && isEndFalls && trendRelation >= 2; } internal static bool CheckUptrendStarting(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff) { var totalDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, firstPeriod + secondPeriod); var startDiff = unit.GetPriceDiffForTimeSpan(secondPeriod, firstPeriod); var endDiff = unit.GetPriceDiffForTimeSpan(TimeSpan.Zero, secondPeriod); var isEndGrows = endDiff.CheckGrowing(meanfullDiff); var isStartStable = startDiff.CheckStable(meanfullDiff); var isStartFalls = startDiff.CheckStable(meanfullDiff); var trendRelation = CalcTrendRelationAbs(endDiff, startDiff); var res = totalDiff.Success && (isStartStable || isStartFalls) && isEndGrows && endDiff.PeriodDiff > meanfullDiff; if (isStartStable) { res &= trendRelation >= 2; } else { } if (res) { } return res; } internal static TwoPeriodsProcessingData GetTwoPeriodsProcessingData(this (DateTime[] timestamps, float[] prices) data, TimeSpan shift, int shiftPointsStart, int shiftPointsEnd, TimeSpan firstPeriod, float meanfullDiff) { var res = new TwoPeriodsProcessingData(success: false, 0, 0, 0, 0, 0, TimeSpan.Zero, TimeSpan.Zero); var time = data.timestamps; var prices = data.prices; int count = -1; var lastTime = time[time.Length - 1]; var bound = -1; var start = -1; var end = time.Length - 1; for (int i = time.Length - 1; i > -1; i--) { if (count > 0 && bound < 0 && (count == shiftPointsEnd || lastTime - time[i] >= shift)) { bound = i; shift = lastTime - time[i]; } if (((lastTime - time[i]) >= shift + 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 TwoPeriodsProcessingData(true, diff1, diff2, start, bound, end, time[bound] - time[start], time[end] - time[bound]); } return res; } internal static bool CheckLongClose(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff, int pointsStart, int pointsEnd) { var data = unit.GetData(); var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, pointsStart, pointsEnd, firstPeriod, meanfullDiff); var trendRelation = CalcTrendRelationAbs(periodStat); var isStartOk = periodStat.Success && periodStat.DiffStart > 0 && periodStat.DiffStart > 1.5 * meanfullDiff; var isEndOk = periodStat.Success && periodStat.DiffEnd < meanfullDiff; if (isEndOk) { } if (isStartOk) { } if (isEndOk && isStartOk) { } return isStartOk && isEndOk && (data.prices[periodStat.End] - data.prices[periodStat.Start] >= meanfullDiff); } internal static bool CheckUptrendStarting2(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff) { var data = unit.GetData(); var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, 15, 2, firstPeriod, meanfullDiff); var trendRelation = CalcTrendRelationAbs(periodStat); var isStartOk = periodStat.Success && periodStat.DiffStart < -meanfullDiff; var isEndOk = periodStat.Success && periodStat.DiffEnd >= meanfullDiff; if (isEndOk) { } if (isStartOk) { } if (isEndOk && isStartOk) { } return isStartOk && isEndOk; } internal static bool _CheckUptrendStarting2(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff) { var data = unit.GetData(); var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, 15, 1, firstPeriod, meanfullDiff); var trendRelation = CalcTrendRelationAbs(periodStat); var isStartOk = periodStat.Success && periodStat.DiffStart < -meanfullDiff; var isEndOk = periodStat.Success && periodStat.DiffEnd >= meanfullDiff; if (isEndOk) { } if (isStartOk) { } if (isEndOk && isStartOk) { } return isStartOk && isEndOk; } internal static bool CheckLongOpen(this PriceHistoryCacheUnit unit, TimeSpan firstPeriod, TimeSpan secondPeriod, float meanfullDiff, int pointsStart, int pointsEnd) { var data = unit.GetData(); var periodStat = data.GetTwoPeriodsProcessingData(secondPeriod, pointsStart, pointsEnd, firstPeriod, meanfullDiff); var trendRelation = CalcTrendRelationAbs(periodStat); var isStartOk = periodStat.Success && periodStat.DiffStart < -meanfullDiff; var isEndOk = periodStat.Success && periodStat.DiffEnd >= meanfullDiff; if (isEndOk) { } if (isStartOk) { } if (isEndOk && isStartOk) { } return isStartOk && isEndOk && (data.prices[periodStat.Start] - data.prices[periodStat.End] >= meanfullDiff); } } }