/// <summary> Основная функция, выполняющая поиск всех боковиков в глобальном списке свечей </summary> public void FindAllFlats() { // Как правило, globalIterator хранит в себе индекс начала окна во всём датасете for (int globalIterator = 0; globalIterator < globalCandles.Count - _Constants.NAperture * 2;) { FlatIdentifier flat = new FlatIdentifier(); flat.AssignAperture(aperture); flat.Identify(); // Определяем начальное окно // Если не определили боковик сходу if (!flat.isFlat) { Printer printer = new Printer(flat); printer.PrintReasonsApertureIsNotFlat(); globalIterator++; MoveAperture(ref globalIterator); continue; } while (flat.isFlat) { // ExpansionRate раз... for (int j = 0; j < _Constants.ExpansionRate; j++) { // ЕСЛИ не конец данных if (globalIterator + aperture.Count + 1 != globalCandles[globalCandles.Count - 1].index) { // ... расширяем окно на 1 свечу ExtendAperture(globalIterator, ref aperture); } else { flatList.Add(flat); flatsFound++; return; } } flat.AssignAperture(aperture); flat.Identify(); // Identify() вызывает SetBounds(), если isFlat == true if (flat.isFlat) { continue; } Printer printer = new Printer(flat); printer.PrintReasonsApertureIsNotFlat(); flatList.Add(flat); flatsFound++; globalIterator += aperture.Count; // Переместить итератор на следующую после найденного окна свечу MoveAperture(ref globalIterator); } } }
/// <summary> /// Функция склеивает находящиеся близко друг к другу боковики /// </summary> public void UniteFlats() { for (int i = 1; i < flatsFound; i++) { FlatIdentifier currentFlat = flatList[i]; FlatIdentifier prevFlat = flatList[i - 1]; bool areFlatsInTheSameDay = currentFlat.bounds.left.date == prevFlat.bounds.left.date; bool areFlatsTooClose = currentFlat.bounds.left.index - prevFlat.bounds.right.index <= _Constants.MinFlatGap; bool areFlatsMeansRoughlyEqual = Math.Abs(currentFlat.mean - prevFlat.mean) <= _Constants.FlatsMeanOffset * (currentFlat.mean + prevFlat.mean) * 0.5; bool isPrevFlatHasClosing = prevFlat.bounds.left.time != currentFlat.leavingCandle.time; logger.Trace($"{prevFlat.candles[0].date}: [{prevFlat.bounds.left.time} {prevFlat.bounds.right.time}] " + $"and [{currentFlat.bounds.left.time} {currentFlat.bounds.right.time}] " + $"Day = {areFlatsInTheSameDay} Distance = {areFlatsTooClose} Means = {areFlatsMeansRoughlyEqual} PrevFlatCloseAtCurr = {isPrevFlatHasClosing}"); // ЕСЛИ левая граница предыдущего и левая граница текущего находятся в пределах одного дня // И ЕСЛИ разница в свечах между левой границей текущего и правой границей предыдущего меьше ГАПА // И ЕСЛИ разница в цене между мат. ожиданиями текущего и предыдущего <= (ОФФСЕТ * среднее между мат. ожиданиями обоих боковиков) if (!areFlatsInTheSameDay || !areFlatsTooClose || !areFlatsMeansRoughlyEqual || !isPrevFlatHasClosing) { continue; } logger.Trace("Uniting"); List <_CandleStruct> newAperture = new List <_CandleStruct>(currentFlat.bounds.right.index - prevFlat.bounds.left.index); for (int j = prevFlat.bounds.left.index; j <= currentFlat.bounds.right.index; j++) { newAperture.Add(globalCandles[j]); } FlatIdentifier newFlat = new FlatIdentifier(); newFlat.AssignAperture(newAperture); newFlat.CalculateFlatProperties(); newFlat.bounds = newFlat.SetBounds(newFlat.candles[0], newFlat.candles[newFlat.candles.Count - 1]); newFlat.SetBounds(newFlat.candles[0], newFlat.candles[newFlat.candles.Count - 1]); flatList.RemoveRange(i - 1, 2); flatList.Insert(i - 1, newFlat); flatsFound--; i++; flatUnions++; } }