But the source code is available to everyone. This is made with Grok4. Do you get it/like it? continue to refine
Code: Select all
// This work is licensed under a Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) https://creativecommons.org/licenses/by-nc-sa/4.0/
// © Zeiierman
#property copyright "Zeiierman"
#property link      ""
#property version   "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 10
#property indicator_plots 7
// Inputs
input double flipMult = 2.86; // Trigger Threshold
input double maxStepAtr = -0.034; // Max Step Size
input double bandMult = 2.02; // Band Multiplier
input int holdBars = 0; // Trend Hold
input color colorUp = clrLime;
input color colorDown = clrRed;
input bool showFill = true; // Channel Fill
input bool ChannelRetestSignal = true; // Retest Signals
input bool TrendFilter = true; // Filter by Trend
input color colorUp2 = clrLime;
input color colorDown2 = clrRed;
input bool TrendStepSignal = false; // Trend Step Signals
input color colorUp3 = clrLime;
input color colorDown3 = clrRed;
// Buffers
double TrendBuffer[];
double TrendColors[];
double UpperBuffer[];
double UpperColors[];
double LowerBuffer[];
double LowerColors[];
double LowerRetestBuf[];
double UpperRetestBuf[];
double BullStepBuf[];
double BearStepBuf[];
// Calculation arrays
double dirArray[];
double barsInTrendArray[];
double extensionArray[];
// ATR handle
int atrHandle;
// OnInit
int OnInit()
{
  IndicatorSetString(INDICATOR_SHORTNAME, "Trend Impulse Channels (Zeiierman)");
  SetIndexBuffer(0, TrendBuffer, INDICATOR_DATA);
  PlotIndexSetString(0, PLOT_LABEL, "Trend Line");
  PlotIndexSetInteger(0, PLOT_DRAW_TYPE, DRAW_COLOR_LINE);
  PlotIndexSetInteger(0, PLOT_LINE_WIDTH, 2);
  SetIndexBuffer(1, TrendColors, INDICATOR_COLOR_INDEX);
  PlotIndexSetInteger(0, PLOT_COLOR_INDEXES, 3);
  PlotIndexSetInteger(0, PLOT_LINE_COLOR, 0, colorUp);
  PlotIndexSetInteger(0, PLOT_LINE_COLOR, 1, colorDown);
  PlotIndexSetInteger(0, PLOT_LINE_COLOR, 2, clrGray);
  SetIndexBuffer(2, UpperBuffer, INDICATOR_DATA);
  PlotIndexSetString(1, PLOT_LABEL, "Upper Band");
  PlotIndexSetInteger(1, PLOT_DRAW_TYPE, DRAW_COLOR_LINE);
  PlotIndexSetInteger(1, PLOT_COLOR_INDEXES, 3);
  PlotIndexSetInteger(1, PLOT_LINE_COLOR, 0, colorUp);
  PlotIndexSetInteger(1, PLOT_LINE_COLOR, 1, colorDown);
  PlotIndexSetInteger(1, PLOT_LINE_COLOR, 2, clrGray);
  SetIndexBuffer(3, UpperColors, INDICATOR_COLOR_INDEX);
  SetIndexBuffer(4, LowerBuffer, INDICATOR_DATA);
  PlotIndexSetString(2, PLOT_LABEL, "Lower Band");
  PlotIndexSetInteger(2, PLOT_DRAW_TYPE, DRAW_COLOR_LINE);
  PlotIndexSetInteger(2, PLOT_COLOR_INDEXES, 3);
  PlotIndexSetInteger(2, PLOT_LINE_COLOR, 0, colorUp);
  PlotIndexSetInteger(2, PLOT_LINE_COLOR, 1, colorDown);
  PlotIndexSetInteger(2, PLOT_LINE_COLOR, 2, clrGray);
  SetIndexBuffer(5, LowerColors, INDICATOR_COLOR_INDEX);
  SetIndexBuffer(6, LowerRetestBuf, INDICATOR_DATA);
  PlotIndexSetString(3, PLOT_LABEL, "Lower Retest");
  PlotIndexSetInteger(3, PLOT_DRAW_TYPE, DRAW_ARROW);
  PlotIndexSetInteger(3, PLOT_LINE_COLOR, colorUp2);
  PlotIndexSetInteger(3, PLOT_ARROW, 225); // Triangle up
  SetIndexBuffer(7, UpperRetestBuf, INDICATOR_DATA);
  PlotIndexSetString(4, PLOT_LABEL, "Upper Retest");
  PlotIndexSetInteger(4, PLOT_DRAW_TYPE, DRAW_ARROW);
  PlotIndexSetInteger(4, PLOT_LINE_COLOR, colorDown2);
  PlotIndexSetInteger(4, PLOT_ARROW, 226); // Triangle down
  SetIndexBuffer(8, BullStepBuf, INDICATOR_DATA);
  PlotIndexSetString(5, PLOT_LABEL, "Bullish Step");
  PlotIndexSetInteger(5, PLOT_DRAW_TYPE, DRAW_ARROW);
  PlotIndexSetInteger(5, PLOT_LINE_COLOR, colorUp3);
  PlotIndexSetInteger(5, PLOT_ARROW, 159); // Circle
  SetIndexBuffer(9, BearStepBuf, INDICATOR_DATA);
  PlotIndexSetString(6, PLOT_LABEL, "Bearish Step");
  PlotIndexSetInteger(6, PLOT_DRAW_TYPE, DRAW_ARROW);
  PlotIndexSetInteger(6, PLOT_LINE_COLOR, colorDown3);
  PlotIndexSetInteger(6, PLOT_ARROW, 159); // Circle
  atrHandle = iATR(NULL, 0, 200);
  if (atrHandle == INVALID_HANDLE)
  {
    Print("Failed to create ATR handle");
    return(INIT_FAILED);
  }
  return(INIT_SUCCEEDED);
}
// OnDeinit
void OnDeinit(const int reason)
{
  IndicatorRelease(atrHandle);
}
// OnCalculate
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
{
  if (rates_total < 1) return(0);
  ArraySetAsSeries(TrendBuffer, false);
  ArraySetAsSeries(TrendColors, false);
  ArraySetAsSeries(UpperBuffer, false);
  ArraySetAsSeries(UpperColors, false);
  ArraySetAsSeries(LowerBuffer, false);
  ArraySetAsSeries(LowerColors, false);
  ArraySetAsSeries(LowerRetestBuf, false);
  ArraySetAsSeries(UpperRetestBuf, false);
  ArraySetAsSeries(BullStepBuf, false);
  ArraySetAsSeries(BearStepBuf, false);
  ArraySetAsSeries(high, false);
  ArraySetAsSeries(low, false);
  ArraySetAsSeries(close, false);
  ArraySetAsSeries(time, false);
  ArrayResize(dirArray, rates_total);
  ArrayResize(barsInTrendArray, rates_total);
  ArrayResize(extensionArray, rates_total);
  double atrBuffer[];
  ArraySetAsSeries(atrBuffer, false);
  if (CopyBuffer(atrHandle, 0, 0, rates_total, atrBuffer) != rates_total) return(0);
  int limit = (prev_calculated == 0) ? 0 : prev_calculated - 1;
  static datetime currentBarTime = 0;
  static bool alertedLowerRetest = false;
  static bool alertedUpperRetest = false;
  static bool alertedBullStep = false;
  static bool alertedBearStep = false;
  if (time[ rates_total - 1 ] != currentBarTime)
  {
    currentBarTime = time[ rates_total - 1 ];
    alertedLowerRetest = false;
    alertedUpperRetest = false;
    alertedBullStep = false;
    alertedBearStep = false;
  }
  for (int i = limit; i < rates_total; i++)
  {
    double atr = atrBuffer[i];
    double stepBase = atr * 2.52;
    double maxStep = atr * maxStepAtr;
    double trigger = atr * flipMult;
    double offset = atr * 0.1; // Offset for positioning shapes
    if (atr == 0)
    {
      stepBase = 0;
      maxStep = 0;
      trigger = 0; // But will force no flip
    }
    if (i == 0)
    {
      TrendBuffer[i] = close[i];
      dirArray[i] = 0;
      barsInTrendArray[i] = 0;
      extensionArray[i] = 0;
    }
    else
    {
      double prevTrend = TrendBuffer[i-1];
      int prevDir = (int)dirArray[i-1];
      int prevBarsInTrend = (int)barsInTrendArray[i-1];
      int prevExtension = (int)extensionArray[i-1];
      bool startLong = close[i] > prevTrend + trigger;
      bool startShort = close[i] < prevTrend - trigger;
      if (atr == 0)
      {
        startLong = false;
        startShort = false;
      }
      bool flip = (startLong || startShort) && prevBarsInTrend >= 0;
      double stepSize = MathMin(stepBase + 0.0093 * prevBarsInTrend * atr, maxStep);
      if (flip && prevExtension <= 0)
      {
        TrendBuffer[i] = close[i];
        dirArray[i] = startLong ? 1 : -1;
        barsInTrendArray[i] = 1;
        extensionArray[i] = holdBars;
      }
      else
      {
        double add = (prevDir == 1 ? stepSize : (prevDir == -1 ? -stepSize : 0));
        TrendBuffer[i] = prevTrend + add;
        dirArray[i] = prevDir;
        barsInTrendArray[i] = prevBarsInTrend + 1;
        extensionArray[i] = MathMax(prevExtension - 1, 0);
      }
    }
    int trendDirection = (int)dirArray[i] == 1 ? 1 : ((int)dirArray[i] == -1 ? -1 : 0);
    if (atr == 0 && showFill)
    {
      UpperBuffer[i] = EMPTY_VALUE;
      LowerBuffer[i] = EMPTY_VALUE;
    }
    else
    {
      UpperBuffer[i] = showFill ? TrendBuffer[i] + atr * bandMult : EMPTY_VALUE;
      LowerBuffer[i] = showFill ? TrendBuffer[i] - atr * bandMult : EMPTY_VALUE;
    }
    if ((int)dirArray[i] == 1) TrendColors[i] = 0;
    else if ((int)dirArray[i] == -1) TrendColors[i] = 1;
    else TrendColors[i] = 2;
    UpperColors[i] = TrendColors[i];
    LowerColors[i] = TrendColors[i];
    bool crossUnder = false;
    bool crossOver = false;
    if (i > 0)
    {
      bool cu = (low[i-1] >= LowerBuffer[i-1] && low[i] < LowerBuffer[i]);
      bool co = (high[i-1] <= UpperBuffer[i-1] && high[i] > UpperBuffer[i]);
      if (TrendFilter)
      {
        crossUnder = cu && trendDirection == 1;
        crossOver = co && trendDirection == -1;
      }
      else
      {
        crossUnder = cu;
        crossOver = co;
      }
    }
    LowerRetestBuf[i] = (crossUnder && ChannelRetestSignal) ? low[i] - offset : EMPTY_VALUE;
    UpperRetestBuf[i] = (crossOver && ChannelRetestSignal) ? high[i] + offset : EMPTY_VALUE;
    bool trendStep = false;
    if (i > 0)
    {
      trendStep = ((int)dirArray[i] != 0) && (TrendBuffer[i] != TrendBuffer[i-1]) &&
                  ((TrendBuffer[i] > TrendBuffer[i-1] && (int)dirArray[i] == 1) ||
                   (TrendBuffer[i] < TrendBuffer[i-1] && (int)dirArray[i] == -1));
    }
    BullStepBuf[i] = (trendStep && (int)dirArray[i] == 1 && TrendStepSignal) ? high[i] : EMPTY_VALUE;
    BearStepBuf[i] = (trendStep && (int)dirArray[i] == -1 && TrendStepSignal) ? low[i] : EMPTY_VALUE;
    // Alerts
    if (i == rates_total - 1)
    {
      if (crossUnder && !alertedLowerRetest)
      {
        Alert("Lower Retest");
        alertedLowerRetest = true;
      }
      if (crossOver && !alertedUpperRetest)
      {
        Alert("Upper Retest");
        alertedUpperRetest = true;
      }
      if (trendStep && (int)dirArray[i] == 1 && !alertedBullStep)
      {
        Alert("Bullish Step");
        alertedBullStep = true;
      }
      if (trendStep && (int)dirArray[i] == -1 && !alertedBearStep)
      {
        Alert("Bearish Step");
        alertedBearStep = true;
      }
    }
  }
  return(rates_total);
}