// This Pine Script® code is subject to the terms of the Mozilla Public License 2.
0 at
https://mozilla.org/MPL/2.0/
// © YusufBay
//@version=6
#property indicator_chart_window
#property indicator_buffers 0
#property indicator_plots 0
#property version "1.0"
#property strict
// ---------- INPUTS ----------
input ENUM_TIMEFRAMES HTF = PERIOD_D; // Higher timeframe for trend (e.g. PERIOD_H4,
PERIOD_D1)
input int emaFastLen = 21; // HTF Fast EMA length
input int emaSlowLen = 89; // HTF Slow EMA length
input bool useVWAP = true; // Use session VWAP filter
input int atrLen = 14; // ATR length
input double atrMult = 1.6; // ATR stop multiplier
input int rsiLen = 14; // RSI length
input int rsiOversold = 35;
input int rsiOverbought = 65;
input int macdFast = 12;
input int macdSlow = 26;
input int macdSig = 9;
input int volSmaLen = 50;
input double volMult = 1.5;
input bool requireTrend = true;
input bool requireMomentum = true;
input bool requireVolume = true;
input bool labelSignals = true;
input bool showArrows = false;
input bool onlyLatestLabel = true;
input bool forceAllSignals = false; // Force signals regardless of HTF trend (testing)
// Label size option: "tiny","small","normal","large" mapped to font sizes
input string labelSizeOpt = "small"; // options: tiny, small, normal, large
// Visual object names prefix
#define OBJ_PREFIX "GWT_EDGE_"
// ---------- GLOBALS ----------
datetime lastProcessedBarTime = 0;
string lastLabelName = "";
string lastArrowBuy = "";
string lastArrowSell = "";
// utility: map label size string to font size (pixels)
int LabelFontSize()
if(StringCompare(labelSizeOpt,"tiny",FALSE) == 0) return 8;
if(StringCompare(labelSizeOpt,"small",FALSE) == 0) return 10;
if(StringCompare(labelSizeOpt,"normal",FALSE) == 0) return 12;
return 14; // large
// create/delete helpers
void DeleteObjectIfExists(string name)
if(ObjectFind(0,name) >= 0) ObjectDelete(0,name);
void CreateLabel(string name, datetime time, double price, string text, color bg, int fontSize, bool above)
DeleteObjectIfExists(name);
// use OBJ_LABEL — anchored at chart coordinates (x,y) relative to price
if(!ObjectCreate(0,name,OBJ_LABEL,0,time,price))
return;
ObjectSetInteger(0,name,OBJPROP_COLOR,clrWhite);
ObjectSetInteger(0,name,OBJPROP_BACK,true);
ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
ObjectSetInteger(0,name,OBJPROP_HIDDEN,true);
ObjectSetString(0,name,OBJPROP_TEXT,text);
ObjectSetInteger(0,name,OBJPROP_FONTSIZE,fontSize);
ObjectSetInteger(0,name,OBJPROP_CORNER,0);
ObjectSetInteger(0,name,OBJPROP_YDISTANCE,0);
// set background color
ObjectSetInteger(0,name,OBJPROP_BGCOLOR,bg);
// create arrow (triangles) for buy/sell
void CreateArrow(string name, datetime time, double price, bool isBuy)
DeleteObjectIfExists(name);
if(!ObjectCreate(0,name,OBJ_ARROW,0,time,price)) return;
ObjectSetInteger(0,name,OBJPROP_COLOR, isBuy ? clrLime : clrRed);
ObjectSetInteger(0,name,OBJPROP_WIDTH,2);
// set arrow code: up or down
int code = isBuy ? SYMBOL_ARROWUP : SYMBOL_ARROWDOWN;
ObjectSetInteger(0,name,OBJPROP_ARROWCODE,code);
ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
ObjectSetInteger(0,name,OBJPROP_HIDDEN,true);
// ---------- VWAP: compute session VWAP (daily session) ----------
bool GetSessionVWAP(datetime sessionStart, int tf, double &vwap_out)
// Compute VWAP from sessionStart to current bar (use chart timeframe)
// Sum(price*volume)/sum(volume) over bars from sessionStart time (inclusive) to current bar-1
int i = 0;
double num = 0.0;
double den = 0.0;
// ensure we have enough bars
for(i=0; i<Bars; i++)
datetime t = Time[i];
if(t < sessionStart) break; // older than session start; stop
double typical = (High[i] + Low[i] + Close[i]) / 3.0;
double vol = (double)Volume[i];
num += typical * vol;
den += vol;
if(den <= 0.0) { vwap_out = 0.0; return false; }
vwap_out = num / den;
return true;
// get today's session start (midnight server time)
datetime GetSessionStart()
// use chart server time midnight of current day
datetime t = TimeCurrent();
MqlDateTime tm;
TimeToStruct(t,tm);
tm.hour = 0; tm.min = 0; tm.sec = 0;
datetime sessionStart = StructToTime(tm);
return sessionStart;
// ---------- OnInit / OnDeinit ----------
int OnInit()
IndicatorShortName("GWT — Greatest Wall Trader Edge (MT4)");
lastProcessedBarTime = 0;
return(INIT_SUCCEEDED);
void OnDeinit(const int reason)
{
// cleanup objects
DeleteObjectIfExists(OBJ_PREFIX + "LABEL");
DeleteObjectIfExists(OBJ_PREFIX + "ARROW_BUY");
DeleteObjectIfExists(OBJ_PREFIX + "ARROW_SELL");
// ---------- Main calculation: execute once per new closed bar ----------
// OnCalculate signature — we don't use buffers; still must implement
int OnCalculate(const int rates_total,
const int prev_calculated,
const int begin,
const double &price[])
// safety
if(rates_total < 10) return(prev_calculated);
// Detect new closed bar: process when Time[1] != lastProcessedBarTime
datetime closedBarTime = Time[1]; // last closed bar (index 1)
if(closedBarTime == lastProcessedBarTime) return(rates_total);
lastProcessedBarTime = closedBarTime;
// Use shift=1 (last closed bar) to get values that won't repaint
int shift = 1;
// --- HTF EMA trend check ---
double htfEmaFast = iMA(NULL, (int)HTF, emaFastLen, 0, MODE_EMA, PRICE_CLOSE, shift);
double htfEmaSlow = iMA(NULL, (int)HTF, emaSlowLen, 0, MODE_EMA, PRICE_CLOSE, shift);
bool htfBull = (htfEmaFast > htfEmaSlow);
bool htfBear = (htfEmaFast < htfEmaSlow);
// --- VWAP ---
double sessionVWAP = 0.0;
bool haveVWAP = true;
if(useVWAP)
datetime sessStart = GetSessionStart();
haveVWAP = GetSessionVWAP(sessStart, PERIOD_CURRENT, sessionVWAP);
if(!haveVWAP) sessionVWAP = 0.0;
bool vwapFilterLong = (!useVWAP) || (Close[shift] > sessionVWAP);
bool vwapFilterShort = (!useVWAP) || (Close[shift] < sessionVWAP);
// --- ATR (global) ---
double atr = iATR(NULL,0,atrLen,shift);
double atrShort = iATR(NULL,0,5,shift); // short ATR for imbalance
// --- Volume spike ---
// compute vol SMA over volSmaLen on tick volume
double volSma = 0.0;
int startIdx = shift;
int maxVolLook = MathMin(Bars - 1, shift + volSmaLen - 1);
int cnt = 0;
for(int i = shift; i <= maxVolLook; i++)
volSma += (double)Volume[i];
cnt++;
}
if(cnt>0) volSma /= cnt;
bool volSpike = (double)Volume[shift] > volSma * volMult;
// --- Momentum: RSI + MACD ---
double rsi = iRSI(NULL,0,rsiLen,PRICE_CLOSE,shift);
double macdMain = 0.0, macdSignal = 0.0, macdHist = 0.0;
// MT4 macd uses iMA on two EMAs; use iMACD for values: the arrays are returned differently; we can
compute hist as difference
// iMACD returns main line; signal is handled by separate call using applied price
macdMain = iMACD(NULL,0,macdFast,macdSlow,macdSig,PRICE_CLOSE,MODE_MAIN,shift);
macdSignal = iMACD(NULL,0,macdFast,macdSlow,macdSig,PRICE_CLOSE,MODE_SIGNAL,shift);
macdHist = macdMain - macdSignal;
bool macdBull = (macdMain > macdSignal) && (macdHist > 0.0);
bool macdBear = (macdMain < macdSignal) && (macdHist < 0.0);
bool momentumLong = macdBull && (rsi > rsiOversold);
bool momentumShort = macdBear && (rsi < rsiOverbought);
// --- Imbalance / FVG proxy (loosened) ---
bool fvgUp = false;
bool fvgDown = false;
if(Bars > shift + 1)
fvgUp = (Close[shift] > High[shift+1]) && ((Close[shift] - High[shift+1]) > atrShort * 0.02);
fvgDown = (Close[shift] < Low[shift+1]) && ((Low[shift+1] - Close[shift]) > atrShort * 0.02);
// --- Trend allowed?
bool trendAllowedLong = forceAllSignals || (!requireTrend) || htfBull;
bool trendAllowedShort = forceAllSignals || (!requireTrend) || htfBear;
// --- Signal conditions (confirmed on close: shift=1)
bool longCondition = trendAllowedLong && vwapFilterLong && ((!requireMomentum) ||
momentumLong) && ((!requireVolume) || volSpike) && fvgUp;
bool shortCondition = trendAllowedShort && vwapFilterShort && ((!requireMomentum) ||
momentumShort) && ((!requireVolume) || volSpike) && fvgDown;
bool longSignal = longCondition;
bool shortSignal = shortCondition;
// ---------- VISUALS: arrows + single label ----------
int fontSize = LabelFontSize();
// If only latest label requested, delete previous label before creating new
if(labelSignals)
if(longSignal)
if(onlyLatestLabel && StringLen(lastLabelName) > 0) { DeleteObjectIfExists(lastLabelName);
lastLabelName=""; }
datetime t = Time[1];
double y = Low[1] - atr * 0.25;
string labelName = OBJ_PREFIX + "LABEL";
CreateLabel(labelName, t, y, "BUY", clrGreen, fontSize, false);
lastLabelName = labelName;
if(shortSignal)
if(onlyLatestLabel && StringLen(lastLabelName) > 0) { DeleteObjectIfExists(lastLabelName);
lastLabelName=""; }
datetime t = Time[1];
double y = High[1] + atr * 0.25;
string labelName = OBJ_PREFIX + "LABEL";
CreateLabel(labelName, t, y, "SELL", clrRed, fontSize, true);
lastLabelName = labelName;
// arrows
if(showArrows)
if(longSignal)
string aname = OBJ_PREFIX + "ARROW_BUY";
if(onlyLatestLabel) DeleteObjectIfExists(OBJ_PREFIX + "ARROW_SELL"); // keep only latest if desired
DeleteObjectIfExists(aname);
CreateArrow(aname, Time[1], Low[1] - atr * 0.5, true);
if(shortSignal)
string aname2 = OBJ_PREFIX + "ARROW_SELL";
if(onlyLatestLabel) DeleteObjectIfExists(OBJ_PREFIX + "ARROW_BUY");
DeleteObjectIfExists(aname2);
CreateArrow(aname2, Time[1], High[1] + atr * 0.5, false);
// Optional debug: update indicator short name with last signal & HTF trend
string s = "GWT Edge | HTF:" + (htfBull ? "Bull" : htfBear ? "Bear" : "Neutral");
if(longSignal) s += " | Last: BUY";
if(shortSignal) s += " | Last: SELL";
IndicatorShortName(s);
return(rates_total);