using SignalsTest; public static class Confirmations { public static int GetTWSConfirmation(List reports, int i) { int TWSHeightIncrement = 0; if (i > 22) { bool hasCrossedST = false; bool hasCrossedMA = false; for (int z = 0; z < 20; z++) { if (!reports[i - z].STUp && reports[i].STUp) { hasCrossedST = true; } if (reports[i - z].SMA20 < reports[i - z].Open && reports[i].SMA20 > reports[i].Open) { hasCrossedMA = true; } } if (hasCrossedMA) TWSHeightIncrement += 1; if (hasCrossedST) TWSHeightIncrement += 1; } return TWSHeightIncrement; } public static int GetTBCConfirmation(List reports, int i) { int HeightIncrement = 0; if (i > 22) { bool hasCrossedST = false; bool hasCrossedMA = false; for (int z = 0; z < 20; z++) { if (reports[i - z].STUp && !reports[i].STUp) { hasCrossedST = true; } if (reports[i - z].SMA20 > reports[i - z].Open && reports[i].SMA20 < reports[i].Open) { hasCrossedMA = true; } } if (hasCrossedMA) HeightIncrement += 1; if (hasCrossedST) HeightIncrement += 1; } return HeightIncrement; } public static List GetSupportiveLevels(List reports, float tolerance = 0.1f, int steps = 5, string SMA="SMA20"){ List allSups = new List(); decimal highest = 0; decimal lowest = 1000000000000000; int lastMACross = 0; for(int k =0; k < reports.Count; k++){ if(highest < reports[k].candle.High){ highest = reports[k].candle.High; } if(lowest > reports[k].candle.Low){ lowest = reports[k].candle.Low; } if(k reports[k].candle.High; bool MATopBefore = decimal.Parse(Utils.GetPropByName(reports[k-1], SMA).ToString() ?? "0") > reports[k-1].candle.High; bool MACrossed = MATopBefore!=MATopNow; if(!MACrossed){continue;}//No cross if(lastMACross == 0){ lastMACross = k; continue; //First Cross } //Get lowest point between this and last cross decimal lowestInPeriod = 1000000; for(int i=lastMACross; i < k; i++ ){ if(reports[i].candle.Low < lowestInPeriod){ decimal candleBot = reports[i].candle.Open < reports[i].candle.Close ? reports[i].candle.Open : reports[i].candle.Close; lowestInPeriod=candleBot; } } allSups.Add(lowestInPeriod); } List formattedSups = new List(); decimal range = highest-lowest; foreach(decimal sup in allSups){ formattedSups.Add(sup); } return formattedSups; } public static List GetResistanceLevels(List reports, float tolerance = 0.1f, int steps = 5, string SMA="SMA20"){ List allResistances = new List(); decimal highest = 0; decimal lowest = 1000000000000000; int lastMACross = 0; for(int k =0; k < reports.Count; k++){ if(highest < reports[k].candle.High){ highest = reports[k].candle.High; } if(lowest > reports[k].candle.Low){ lowest = reports[k].candle.Low; } if(k reports[k].candle.High; bool MATopBefore = decimal.Parse(Utils.GetPropByName(reports[k-1], SMA).ToString() ?? "0") > reports[k-1].candle.High; bool MACrossed = MATopBefore!=MATopNow; if(!MACrossed){continue;}//No cross if(lastMACross == 0){ lastMACross = k; continue; //First Cross } //Get lowest point between this and last cross decimal highestInPeriod = 0; for(int i=lastMACross; i < k; i++ ){ if(reports[i].candle.High > highestInPeriod){ decimal candleTop = reports[i].candle.Open > reports[i].candle.Close ? reports[i].candle.Open : reports[i].candle.Close; highestInPeriod=candleTop; } } allResistances.Add(highestInPeriod); } List formattedResistances = new List(); decimal range = highest-lowest; foreach(decimal resistance in allResistances){ formattedResistances.Add(resistance); } return formattedResistances; } public static float GetRelativeVolumeIndex(List reports, int currentIndex){ decimal totalVolume = 0; foreach(TAReport report in reports){ totalVolume+=report.candle.Volume; } float avgVol = (float)totalVolume/(float)reports.Count; return (float)reports[currentIndex].candle.Volume / avgVol; } public static bool IsBullFlag(List reports, int currentIndex, int lookbackPeriod = 20) { if (currentIndex < lookbackPeriod) return false; // Find the flagpole decimal highestPoint = 0; decimal lowestPoint = decimal.MaxValue; int highestPointIndex = 0; // Look for a sharp upward move (flagpole) for (int i = currentIndex - lookbackPeriod; i <= currentIndex; i++) { if (reports[i].candle.High > highestPoint) { highestPoint = reports[i].candle.High; highestPointIndex = i; } if (reports[i].candle.Low < lowestPoint) { lowestPoint = reports[i].candle.Low; } } // Calculate flagpole height decimal flagpoleHeight = highestPoint - lowestPoint; if (flagpoleHeight / lowestPoint < 0.03m) return false; // Minimum 3% move // Check for consolidation pattern after flagpole decimal upperTrendStart = highestPoint; decimal lowerTrendStart = reports[highestPointIndex].candle.Low; decimal upperTrendEnd = reports[currentIndex].candle.High; decimal lowerTrendEnd = reports[currentIndex].candle.Low; // Verify parallel downward sloping trend lines bool isDownwardSloping = upperTrendEnd < upperTrendStart && lowerTrendEnd < lowerTrendStart; bool isParallel = Math.Abs((upperTrendEnd - upperTrendStart) - (lowerTrendEnd - lowerTrendStart)) / flagpoleHeight < 0.2m; // Volume should typically decrease during flag formation bool isVolumeDecreasing = reports[currentIndex].candle.Volume < reports[highestPointIndex].candle.Volume; return isDownwardSloping && isParallel && isVolumeDecreasing; } }