mql5/Experts/AnotherTriBible/Chapter1_ChartDebug.mqh
younglubah-gmail 540d58914e
2026-03-15 02:46:38 +02:00

393 lines
14 KiB
MQL5

//+------------------------------------------------------------------+
//| SMC_BibleEA |
//| Copyright 2025, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property strict
class CChartDebug {
private:
long chartId;
string prefix;
bool enabled;
int zCounter;
string BuildName(string key) {
return prefix + key;
}
ENUM_LINE_STYLE GetStyle(int style) {
if(style == 1) return STYLE_DOT;
return STYLE_SOLID;
}
double RadToDeg(double rad) {
return rad * 180.0 / M_PI;
}
bool CalcLineAngleDeg(datetime t1, double p1, datetime t2, double p2, double &angleDeg) {
int x1, y1, x2, y2;
if(!ChartTimePriceToXY(chartId, 0, t1, p1, x1, y1)) return false;
if(!ChartTimePriceToXY(chartId, 0, t2, p2, x2, y2)) return false;
double dx = (double)(x2 - x1);
double dy = (double)(y1 - y2); // screen Y grows downward, so invert
if(MathAbs(dx) < 0.000001 && MathAbs(dy) < 0.000001) {
angleDeg = 0.0;
return true;
}
angleDeg = RadToDeg(MathArctan2(dy, dx));
return true;
}
color LighterColor(color base, double amount01, double alpha01 = 1.0) {
// Clamp inputs
if(amount01 < 0.0) amount01 = 0.0;
if(amount01 > 1.0) amount01 = 1.0;
if(alpha01 < 0.0) alpha01 = 0.0;
if(alpha01 > 1.0) alpha01 = 1.0;
// Extract original ARGB
uint argb = (uint)base;
int a = (int)((argb >> 24) & 255);
int r = (int)((argb >> 16) & 255);
int g = (int)((argb >> 8) & 255);
int b = (int)((argb >> 0) & 255);
// Lighten toward white
r = (int)(r + (255 - r) * amount01/4);
g = (int)(g + (255 - g) * amount01/2);
b = (int)(b + (255 - b) * amount01*8);
// Apply transparency (override alpha)
a = (int)(255.0 * alpha01);
// Clamp
if(r < 0) r = 0;
if(r > 255) r = 255;
if(g < 0) g = 0;
if(g > 255) g = 255;
if(b < 0) b = 0;
if(b > 255) b = 255;
if(a < 0) a = 0;
if(a > 255) a = 255;
return (color)((a << 24) | (r << 16) | (g << 8) | b);
}
void EnsureRect(string name, datetime t1, double p1, datetime t2, double p2, color c, bool back, int z, bool fill) {
if(ObjectFind(chartId, name) < 0) {
ObjectCreate(chartId, name, OBJ_RECTANGLE, 0, t1, p1, t2, p2);
ObjectSetInteger(chartId, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(chartId, name, OBJPROP_HIDDEN, true);
ObjectSetInteger(chartId, name, OBJPROP_BACK, back);
ObjectSetInteger(chartId, name, OBJPROP_ZORDER, z);
} else {
ObjectMove(chartId, name, 0, t1, p1);
ObjectMove(chartId, name, 1, t2, p2);
}
ObjectSetInteger(chartId, name, OBJPROP_COLOR, c);
ObjectSetInteger(chartId, name, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(chartId, name, OBJPROP_WIDTH, 1);
ObjectSetInteger(chartId, name, OBJPROP_FILL, fill);
}
void EnsureText(string name, datetime t, double price,
string text, int fontSize, color c, int z) {
if(ObjectFind(chartId, name) < 0) {
ObjectCreate(chartId, name, OBJ_TEXT, 0, t, price);
ObjectSetInteger(chartId, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(chartId, name, OBJPROP_HIDDEN, true);
ObjectSetInteger(chartId, name, OBJPROP_BACK, false);
ObjectSetInteger(chartId, name, OBJPROP_ANCHOR, ANCHOR_CENTER);
ObjectSetInteger(chartId, name, OBJPROP_ZORDER, z);
} else {
ObjectMove(chartId, name, 0, t, price);
}
ObjectSetInteger(chartId, name, OBJPROP_FONTSIZE, fontSize);
ObjectSetInteger(chartId, name, OBJPROP_COLOR, c);
ObjectSetString(chartId, name, OBJPROP_TEXT, text);
}
public:
void Init(long cid, string pfx, bool en) {
chartId = cid;
prefix = pfx;
enabled = en;
zCounter = 0;
}
void SetEnabled(bool en) {
enabled = en;
}
void ClearAll() {
if(!enabled) return;
int total = ObjectsTotal(chartId, 0, -1);
for(int i = total - 1; i >= 0; i--) {
string name = ObjectName(chartId, i, 0, -1);
if(StringFind(name, prefix) == 0)
ObjectDelete(chartId, name);
}
ChartRedraw(chartId);
}
// -------- HUD --------
void Hud(string key, string text) {
if(!enabled) return;
string name = BuildName("HUD_" + key);
if(ObjectFind(chartId, name) < 0) {
ObjectCreate(chartId, name, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(chartId, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(chartId, name, OBJPROP_XDISTANCE, 10);
ObjectSetInteger(chartId, name, OBJPROP_YDISTANCE, 10);
ObjectSetInteger(chartId, name, OBJPROP_FONTSIZE, 10);
ObjectSetInteger(chartId, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(chartId, name, OBJPROP_HIDDEN, true);
ObjectSetInteger(chartId, name, OBJPROP_ZORDER, 200 + zCounter++);
}
ObjectSetString(chartId, name, OBJPROP_TEXT, text);
}
// -------- Centered Screen Text --------
void CenteredText(string key, string text) {
if(!enabled) return;
string name = BuildName("CENTER_" + key);
int w = (int)ChartGetInteger(chartId, CHART_WIDTH_IN_PIXELS);
int h = (int)ChartGetInteger(chartId, CHART_HEIGHT_IN_PIXELS);
if(ObjectFind(chartId, name) < 0) {
ObjectCreate(chartId, name, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(chartId, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(chartId, name, OBJPROP_ANCHOR, ANCHOR_CENTER);
ObjectSetInteger(chartId, name, OBJPROP_FONTSIZE, 14);
ObjectSetInteger(chartId, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(chartId, name, OBJPROP_HIDDEN, true);
ObjectSetInteger(chartId, name, OBJPROP_ZORDER, 300 + zCounter++);
}
ObjectSetInteger(chartId, name, OBJPROP_XDISTANCE, w / 2);
ObjectSetInteger(chartId, name, OBJPROP_YDISTANCE, h / 2);
ObjectSetString(chartId, name, OBJPROP_TEXT, text);
}
// -------- Horizontal Line (0=solid,1=dotted) --------
void HLine(string key, double price, int style = 0) {
if(!enabled) return;
string name = BuildName("HL_" + key);
if(ObjectFind(chartId, name) < 0) {
ObjectCreate(chartId, name, OBJ_HLINE, 0, 0, price);
ObjectSetInteger(chartId, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(chartId, name, OBJPROP_HIDDEN, true);
ObjectSetInteger(chartId, name, OBJPROP_BACK, true);
ObjectSetInteger(chartId, name, OBJPROP_WIDTH, 1);
ObjectSetInteger(chartId, name, OBJPROP_ZORDER, 50 + zCounter++);
} else {
ObjectSetDouble(chartId, name, OBJPROP_PRICE, price);
}
ObjectSetInteger(chartId, name, OBJPROP_STYLE, GetStyle(style));
}
// -------- Trend Line (0=solid,1=dotted) --------
void TrendLine(string key,
datetime t1, double p1,
datetime t2, double p2,
int style = 0) {
if(!enabled) return;
string name = BuildName("TL_" + key);
if(ObjectFind(chartId, name) < 0) {
ObjectCreate(chartId, name, OBJ_TREND, 0, t1, p1, t2, p2);
ObjectSetInteger(chartId, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(chartId, name, OBJPROP_HIDDEN, true);
ObjectSetInteger(chartId, name, OBJPROP_WIDTH, 1);
ObjectSetInteger(chartId, name, OBJPROP_RAY_RIGHT, false);
ObjectSetInteger(chartId, name, OBJPROP_ZORDER, 60 + zCounter++);
} else {
ObjectMove(chartId, name, 0, t1, p1);
ObjectMove(chartId, name, 1, t2, p2);
}
ObjectSetInteger(chartId, name, OBJPROP_STYLE, GetStyle(style));
}
// -------- Text at price/time --------
void Text(string key, datetime t, double price, string label) {
if(!enabled) return;
string name = BuildName("TXT_" + key);
if(ObjectFind(chartId, name) < 0) {
ObjectCreate(chartId, name, OBJ_TEXT, 0, t, price);
ObjectSetInteger(chartId, name, OBJPROP_FONTSIZE, 9);
ObjectSetInteger(chartId, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(chartId, name, OBJPROP_HIDDEN, true);
ObjectSetInteger(chartId, name, OBJPROP_ZORDER, 100 + zCounter++);
} else {
ObjectMove(chartId, name, 0, t, price);
}
ObjectSetString(chartId, name, OBJPROP_TEXT, label);
}
// -------- Line + centered text that rotates with line (0=solid,1=dotted) --------
void LineWithCenteredText(string key,
datetime t1, double p1,
datetime t2, double p2,
string text,
int style = 0, color c = clrRed) {
if(!enabled) return;
string lineName = BuildName("TL_" + key);
string txtName = BuildName("TLTXT_" + key);
// --- create/update line ---
if(ObjectFind(chartId, lineName) < 0) {
ObjectCreate(chartId, lineName, OBJ_TREND, 0, t1, p1, t2, p2);
ObjectSetInteger(chartId, lineName, OBJPROP_SELECTABLE, false);
ObjectSetInteger(chartId, lineName, OBJPROP_HIDDEN, true);
ObjectSetInteger(chartId, lineName, OBJPROP_WIDTH, 1);
ObjectSetInteger(chartId, lineName, OBJPROP_RAY_RIGHT, false);
ObjectSetInteger(chartId, lineName, OBJPROP_ZORDER, 60 + zCounter++);
} else {
ObjectMove(chartId, lineName, 0, t1, p1);
ObjectMove(chartId, lineName, 1, t2, p2);
}
ObjectSetInteger(chartId, lineName, OBJPROP_STYLE, GetStyle(style));
ObjectSetInteger(chartId, lineName, OBJPROP_COLOR, c);
// --- midpoint ---
datetime tm = (datetime)((long)t1 + ((long)t2 - (long)t1) / 2);
double pm = (p1 + p2) * 0.5;
// --- create/update text ---
if(ObjectFind(chartId, txtName) < 0) {
ObjectCreate(chartId, txtName, OBJ_TEXT, 0, tm, pm);
ObjectSetInteger(chartId, txtName, OBJPROP_FONTSIZE, 10);
ObjectSetInteger(chartId, txtName, OBJPROP_SELECTABLE, false);
ObjectSetInteger(chartId, txtName, OBJPROP_HIDDEN, true);
ObjectSetInteger(chartId, txtName, OBJPROP_ANCHOR, ANCHOR_CENTER);
ObjectSetInteger(chartId, txtName, OBJPROP_BACK, false);
ObjectSetInteger(chartId, txtName, OBJPROP_ZORDER, 120 + zCounter++);
} else {
ObjectMove(chartId, txtName, 0, tm, pm);
}
ObjectSetString(chartId, txtName, OBJPROP_TEXT, text);
ObjectSetInteger(chartId, txtName, OBJPROP_COLOR, c);
// --- angle ---
double ang;
if(CalcLineAngleDeg(t1, p1, t2, p2, ang))
ObjectSetDouble(chartId, txtName, OBJPROP_ANGLE, ang);
}
// t1/pTop and t2/pBot can be in any order; function normalizes.
void RectWithCenteredText(string symbol, string key,
datetime t1, double pTop,
datetime t2, double pBot,
string text,
color borderColor = clrAqua,
double insetFrac = 0.06, // padding % for inner fill
int fontSize = 10,
bool drawOnTop = false) {
if(!enabled) return;
// Normalize time order
datetime leftT = t1;
datetime rightT = t2;
if(leftT > rightT) {
datetime tmp = leftT;
leftT = rightT;
rightT = tmp;
}
// Normalize price order (top > bottom)
double topP = pTop;
double botP = pBot;
if(topP < botP) {
double tmp = topP;
topP = botP;
botP = tmp;
}
long dt = (long)(rightT - leftT);
if(dt < 1) dt = 1;
double dp = (topP - botP);
if(dp <= 0.0) dp = SymbolInfoDouble(symbol, SYMBOL_POINT);
if(insetFrac < 0.0) insetFrac = 0.0;
if(insetFrac > 0.45) insetFrac = 0.45;
long insetT = (long)((double)dt * insetFrac);
double insetP = dp * insetFrac;
datetime innerL = (datetime)((long)leftT + insetT);
datetime innerR = (datetime)((long)rightT - insetT);
double innerTop = topP - insetP;
double innerBot = botP + insetP;
// Safety: if inset collapses, fallback to same
if(innerR <= innerL) {
innerL = leftT;
innerR = rightT;
}
if(innerTop <= innerBot) {
innerTop = topP;
innerBot = botP;
}
datetime midT = (datetime)((long)leftT + ((long)rightT - (long)leftT) / 2);
double midP = (topP + botP) * 0.5;
color fillColor = LighterColor(borderColor, 0.20, 0.505);
string outerName = BuildName("RBOX_OUT_" + key);
string innerName = BuildName("RBOX_IN_" + key);
string txtName = BuildName("RBOX_TXT_" + key);
bool back = true;
int z = 420 + zCounter++;
EnsureRect(innerName, leftT, topP, rightT, botP, fillColor, back, z + 1, true);
EnsureRect(outerName, leftT, topP, rightT, botP, borderColor, back, z, false);
EnsureText(txtName, midT, midP, text, fontSize, borderColor, z + 2);
}
// Call this on CHARTEVENT_CHART_CHANGE to keep angle correct when zoom/scroll changes
void RefreshLineText(string key, datetime t1, double p1, datetime t2, double p2) {
if(!enabled) return;
string txtName = BuildName("TLTXT_" + key);
if(ObjectFind(chartId, txtName) < 0) return;
datetime tm = (datetime)((long)t1 + ((long)t2 - (long)t1) / 2);
double pm = (p1 + p2) * 0.5;
ObjectMove(chartId, txtName, 0, tm, pm);
double ang;
if(CalcLineAngleDeg(t1, p1, t2, p2, ang))
ObjectSetDouble(chartId, txtName, OBJPROP_ANGLE, ang);
}
};
//+------------------------------------------------------------------+