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);
}