483 lines
23 KiB
MQL5
483 lines
23 KiB
MQL5
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| AF_Engine3_Render.mqh |
|
||
|
|
//| Project : Algo Forge (refactor total) |
|
||
|
|
//| Sumber inspirasi: SniperGold SMC Pro+ (c) Waseem Shahrukh |
|
||
|
|
//| https://www.mql5.com/en/code/75466 |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
//| Engine 3 - RENDER DISPLAY (murni menggambar, TIDAK menghitung) |
|
||
|
|
//| |
|
||
|
|
//| - HANYA membaca output Engine 1 (AFEngine1MTF) dan Engine 2 |
|
||
|
|
//| (AFSignalOut, AFAggOut, AFDisplayData). |
|
||
|
|
//| - Tidak ada perhitungan analisis di sini: semua struktur, zona, |
|
||
|
|
//| level, bias sudah disiapkan oleh Engine 2 (AF_BuildDisplayData |
|
||
|
|
//| di AF_Engine2_Display.mqh). |
|
||
|
|
//| - Meniru tampilan kode asli 75466: garis struktur (BOS/CHoCH), |
|
||
|
|
//| swing point (HH/HL/LH/LL), Order Block, FVG, premium/discount, |
|
||
|
|
//| level MTF (PDH/PDL/PWH/PWL), sinyal (entry/SL/TP + panah), |
|
||
|
|
//| dan dashboard (bias, ringkasan struktur, likuiditas, konteks, |
|
||
|
|
//| level kunci, alignment N/C/E/P, trade setup, legenda). |
|
||
|
|
//| - Non-repaint: renderer dipanggil konsumen HANYA saat bar |
|
||
|
|
//| tertutup baru (lihat AF_Engine3_Display.mq5). |
|
||
|
|
//+------------------------------------------------------------------+
|
||
|
|
#ifndef AF_ENGINE3_RENDER_MQH
|
||
|
|
#define AF_ENGINE3_RENDER_MQH
|
||
|
|
|
||
|
|
#include "AF_Engine2_Display.mqh"
|
||
|
|
|
||
|
|
//------------------------------------------------------------------
|
||
|
|
// Konfigurasi render (diisi konsumen: indikator / EA uji)
|
||
|
|
//------------------------------------------------------------------
|
||
|
|
struct AFRenderCfg
|
||
|
|
{
|
||
|
|
string prefix;
|
||
|
|
bool showStructure;
|
||
|
|
bool showSwingPoints;
|
||
|
|
bool showOB;
|
||
|
|
int obCount;
|
||
|
|
bool showFVG;
|
||
|
|
int fvgCount;
|
||
|
|
bool showPD;
|
||
|
|
bool showLevels;
|
||
|
|
bool showSignals;
|
||
|
|
bool showDashboard;
|
||
|
|
int fontSize;
|
||
|
|
string fontName;
|
||
|
|
color bull, bear;
|
||
|
|
color obLineBull, obLineBear, obFillBull, obFillBear;
|
||
|
|
color fvgLineBull, fvgLineBear, fvgFillBull, fvgFillBear;
|
||
|
|
color premiumLine, premiumFill;
|
||
|
|
color equilLine, equilFill;
|
||
|
|
color discountLine, discountFill;
|
||
|
|
color mtfLevel;
|
||
|
|
color textCol, accent, panelBG, panelBorder;
|
||
|
|
bool panelTransparent;
|
||
|
|
color sigEntry, sigSL, sigTP;
|
||
|
|
};
|
||
|
|
|
||
|
|
// Default (warna LuxAlgo-style, sama dengan kode asli 75466)
|
||
|
|
void AFR_DefaultCfg(AFRenderCfg &cfg)
|
||
|
|
{
|
||
|
|
cfg.prefix=AF_E3_PFX;
|
||
|
|
cfg.showStructure=true;
|
||
|
|
cfg.showSwingPoints=true;
|
||
|
|
cfg.showOB=true; cfg.obCount=AF_E3_OB_DEFAULT;
|
||
|
|
cfg.showFVG=true; cfg.fvgCount=AF_E3_FVG_DEFAULT;
|
||
|
|
cfg.showPD=true;
|
||
|
|
cfg.showLevels=true;
|
||
|
|
cfg.showSignals=true;
|
||
|
|
cfg.showDashboard=true;
|
||
|
|
cfg.fontSize=9;
|
||
|
|
cfg.fontName="Segoe UI";
|
||
|
|
cfg.bull=C'8,153,129';
|
||
|
|
cfg.bear=C'242,54,69';
|
||
|
|
cfg.obLineBull=C'91,156,246';
|
||
|
|
cfg.obLineBear=C'247,124,128';
|
||
|
|
cfg.obFillBull=C'9,15,28';
|
||
|
|
cfg.obFillBear=C'28,13,15';
|
||
|
|
cfg.fvgLineBull=C'0,255,104';
|
||
|
|
cfg.fvgLineBear=C'255,0,8';
|
||
|
|
cfg.fvgFillBull=C'7,26,16';
|
||
|
|
cfg.fvgFillBear=C'27,8,10';
|
||
|
|
cfg.premiumLine=C'242,54,69';
|
||
|
|
cfg.premiumFill=C'27,10,12';
|
||
|
|
cfg.equilLine=C'178,181,190';
|
||
|
|
cfg.equilFill=C'20,21,24';
|
||
|
|
cfg.discountLine=C'8,153,129';
|
||
|
|
cfg.discountFill=C'7,24,16';
|
||
|
|
cfg.mtfLevel=C'33,87,243';
|
||
|
|
cfg.textCol=clrGainsboro;
|
||
|
|
cfg.accent=C'33,87,243';
|
||
|
|
cfg.panelBG=C'12,16,22';
|
||
|
|
cfg.panelBorder=C'40,50,62';
|
||
|
|
cfg.panelTransparent=true;
|
||
|
|
cfg.sigEntry=C'8,153,129';
|
||
|
|
cfg.sigSL=clrTomato;
|
||
|
|
cfg.sigTP=clrLimeGreen;
|
||
|
|
}
|
||
|
|
|
||
|
|
//------------------------------------------------------------------
|
||
|
|
// Helper gambar
|
||
|
|
//------------------------------------------------------------------
|
||
|
|
void AFR_TrendLine(string name,datetime t1,double p1,datetime t2,double p2,
|
||
|
|
color c,int width,ENUM_LINE_STYLE style)
|
||
|
|
{
|
||
|
|
if(ObjectFind(0,name)<0) ObjectCreate(0,name,OBJ_TREND,0,t1,p1,t2,p2);
|
||
|
|
else { ObjectMove(0,name,0,t1,p1); ObjectMove(0,name,1,t2,p2); }
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_COLOR,c);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_WIDTH,width);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_STYLE,style);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_RAY_RIGHT,false);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_BACK,false);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_HIDDEN,true);
|
||
|
|
}
|
||
|
|
|
||
|
|
void AFR_Text(string name,datetime t,double price,string text,color c,int fs,
|
||
|
|
ENUM_ANCHOR_POINT anchor=ANCHOR_LEFT)
|
||
|
|
{
|
||
|
|
if(ObjectFind(0,name)<0) ObjectCreate(0,name,OBJ_TEXT,0,t,price);
|
||
|
|
else ObjectMove(0,name,0,t,price);
|
||
|
|
ObjectSetString(0,name,OBJPROP_TEXT,text);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_FONTSIZE,fs);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_COLOR,c);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_ANCHOR,anchor);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_BACK,false);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_HIDDEN,true);
|
||
|
|
}
|
||
|
|
|
||
|
|
void AFR_Box(string name,datetime t1,double p1,datetime t2,double p2,
|
||
|
|
color fill,color border,bool back)
|
||
|
|
{
|
||
|
|
if(ObjectFind(0,name)<0) ObjectCreate(0,name,OBJ_RECTANGLE,0,t1,p1,t2,p2);
|
||
|
|
else { ObjectMove(0,name,0,t1,p1); ObjectMove(0,name,1,t2,p2); }
|
||
|
|
// OBJ_RECTANGLE: border = OBJPROP_COLOR, fill = OBJPROP_BGCOLOR + FILL
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_COLOR,border);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_BGCOLOR,fill);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_FILL,true);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_BACK,back);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
|
||
|
|
}
|
||
|
|
|
||
|
|
void AFR_Panel(const AFRenderCfg &cfg,string name,ENUM_BASE_CORNER corner,
|
||
|
|
int x,int y,int w,int h)
|
||
|
|
{
|
||
|
|
if(ObjectFind(0,name)<0) ObjectCreate(0,name,OBJ_RECTANGLE_LABEL,0,0,0);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_CORNER,corner);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_XDISTANCE,x);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_YDISTANCE,y);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_XSIZE,w);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_YSIZE,h);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_BGCOLOR,cfg.panelTransparent? clrNONE : cfg.panelBG);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_BORDER_TYPE,BORDER_FLAT);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_COLOR,cfg.panelBorder);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_BACK,false);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_HIDDEN,true);
|
||
|
|
}
|
||
|
|
|
||
|
|
void AFR_PanelLabel(const AFRenderCfg &cfg,string name,ENUM_BASE_CORNER corner,
|
||
|
|
int x,int y,string text,color c,int fs,bool bold=false,
|
||
|
|
ENUM_ANCHOR_POINT anchor=ANCHOR_LEFT_UPPER)
|
||
|
|
{
|
||
|
|
if(ObjectFind(0,name)<0) ObjectCreate(0,name,OBJ_LABEL,0,0,0);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_CORNER,corner);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_XDISTANCE,x);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_YDISTANCE,y);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_ANCHOR,anchor);
|
||
|
|
ObjectSetString(0,name,OBJPROP_TEXT,text);
|
||
|
|
ObjectSetString(0,name,OBJPROP_FONT,bold? cfg.fontName+" Bold" : cfg.fontName);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_FONTSIZE,fs);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_COLOR,c);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_BACK,false);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_SELECTABLE,false);
|
||
|
|
ObjectSetInteger(0,name,OBJPROP_HIDDEN,true);
|
||
|
|
}
|
||
|
|
|
||
|
|
//------------------------------------------------------------------
|
||
|
|
// Dashboard (meniru layout kode asli 75466)
|
||
|
|
//------------------------------------------------------------------
|
||
|
|
void AFR_DrawDashboard(const AFRenderCfg &cfg,const AFDisplayData &dd,const AFAggOut &agg)
|
||
|
|
{
|
||
|
|
string P=cfg.prefix;
|
||
|
|
int fs=cfg.fontSize;
|
||
|
|
color bc=(dd.structure=="Bullish")? cfg.bull :
|
||
|
|
(dd.structure=="Bearish")? cfg.bear : clrSilver;
|
||
|
|
|
||
|
|
// ---- panel bias (kiri-atas) ----
|
||
|
|
AFR_Panel(cfg,P+"P_BIAS",CORNER_LEFT_UPPER,12,30,252,180);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_bt",CORNER_LEFT_UPPER,24,40,
|
||
|
|
"AF BIAS: "+(dd.structure=="Range"? "RANGE" : dd.structure),
|
||
|
|
bc,fs+2,true);
|
||
|
|
int y=72, dy=22, xk=24, xv=132;
|
||
|
|
AFR_PanelLabel(cfg,P+"L_b1k",CORNER_LEFT_UPPER,xk,y,"Structure:",cfg.textCol,fs);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_b1v",CORNER_LEFT_UPPER,xv,y,dd.structure,bc,fs); y+=dy;
|
||
|
|
AFR_PanelLabel(cfg,P+"L_b2k",CORNER_LEFT_UPPER,xk,y,"EQ Pos:",cfg.textCol,fs);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_b2v",CORNER_LEFT_UPPER,xv,y,dd.eqPos,
|
||
|
|
dd.eqPos=="Discount"? cfg.bull :
|
||
|
|
(dd.eqPos=="Premium"? cfg.bear : clrSilver),fs); y+=dy;
|
||
|
|
AFR_PanelLabel(cfg,P+"L_b3k",CORNER_LEFT_UPPER,xk,y,"Liquidity:",cfg.textCol,fs);
|
||
|
|
string liq=(dd.eqhSwept||dd.eqlSwept)? "Swept" : "Intact";
|
||
|
|
AFR_PanelLabel(cfg,P+"L_b3v",CORNER_LEFT_UPPER,xv,y,liq,
|
||
|
|
(dd.eqhSwept||dd.eqlSwept)? cfg.accent : clrSilver,fs); y+=dy;
|
||
|
|
AFR_PanelLabel(cfg,P+"L_b4k",CORNER_LEFT_UPPER,xk,y,"Signal:",cfg.textCol,fs);
|
||
|
|
string sig=(agg.dir>0)? "BUY" : (agg.dir<0)? "SELL" : "WAIT";
|
||
|
|
color sc=(agg.dir>0)? cfg.bull : (agg.dir<0)? cfg.bear : clrSilver;
|
||
|
|
AFR_PanelLabel(cfg,P+"L_b4v",CORNER_LEFT_UPPER,xv,y,sig,sc,fs); y+=dy;
|
||
|
|
AFR_PanelLabel(cfg,P+"L_b5k",CORNER_LEFT_UPPER,xk,y,"Score:",cfg.textCol,fs);
|
||
|
|
int pct=(int)(agg.score*100.0);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_b5v",CORNER_LEFT_UPPER,xv,y,IntegerToString(pct)+"%",
|
||
|
|
pct>=60? cfg.bull : (pct>=30? clrGold : cfg.bear),fs);
|
||
|
|
|
||
|
|
// ---- panel bawah-kiri: ringkasan struktur / likuiditas / konteks / level / alignment ----
|
||
|
|
int bw=180, bh=78, gap=10, bx=14, by=14;
|
||
|
|
AFR_Panel(cfg,P+"P_d1",CORNER_LEFT_LOWER,bx,by+bh,bw,bh);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d1t",CORNER_LEFT_LOWER,bx+12,by+bh-12,"STRUCTURE SUMMARY",cfg.textCol,fs,true);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d1a",CORNER_LEFT_LOWER,bx+12,by+bh-34,"HH: "+IntegerToString(dd.HH),cfg.bull,fs);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d1b",CORNER_LEFT_LOWER,bx+95,by+bh-34,"HL: "+IntegerToString(dd.HL),cfg.bull,fs);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d1c",CORNER_LEFT_LOWER,bx+12,by+bh-56,"LH: "+IntegerToString(dd.LH),cfg.bear,fs);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d1d",CORNER_LEFT_LOWER,bx+95,by+bh-56,"LL: "+IntegerToString(dd.LL),cfg.bear,fs);
|
||
|
|
|
||
|
|
int x2=bx+bw+gap;
|
||
|
|
AFR_Panel(cfg,P+"P_d2",CORNER_LEFT_LOWER,x2,by+bh,bw,bh);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d2t",CORNER_LEFT_LOWER,x2+12,by+bh-12,"LIQUIDITY STATUS",cfg.textCol,fs,true);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d2a",CORNER_LEFT_LOWER,x2+12,by+bh-40,"EQH Swept:",cfg.textCol,fs);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d2av",CORNER_LEFT_LOWER,x2+108,by+bh-40,
|
||
|
|
dd.eqhSwept? "Yes":"No", dd.eqhSwept? cfg.accent : clrGray,fs);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d2b",CORNER_LEFT_LOWER,x2+12,by+bh-62,"EQL Swept:",cfg.textCol,fs);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d2bv",CORNER_LEFT_LOWER,x2+108,by+bh-62,
|
||
|
|
dd.eqlSwept? "Yes":"No", dd.eqlSwept? cfg.accent : clrGray,fs);
|
||
|
|
|
||
|
|
int x3=x2+bw+gap;
|
||
|
|
AFR_Panel(cfg,P+"P_d3",CORNER_LEFT_LOWER,x3,by+bh,bw,bh);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d3t",CORNER_LEFT_LOWER,x3+12,by+bh-12,"MARKET CONTEXT",cfg.textCol,fs,true);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d3a",CORNER_LEFT_LOWER,x3+12,by+bh-40,"Price in:",cfg.textCol,fs);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d3av",CORNER_LEFT_LOWER,x3+95,by+bh-40,dd.eqPos,
|
||
|
|
dd.eqPos=="Discount"? cfg.bull :
|
||
|
|
(dd.eqPos=="Premium"? cfg.bear : clrSilver),fs);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d3b",CORNER_LEFT_LOWER,x3+12,by+bh-62,"Bias:",cfg.textCol,fs);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d3bv",CORNER_LEFT_LOWER,x3+95,by+bh-62,dd.structure,bc,fs);
|
||
|
|
|
||
|
|
int x4=x3+bw+gap;
|
||
|
|
AFR_Panel(cfg,P+"P_d4",CORNER_LEFT_LOWER,x4,by+bh,bw+30,bh);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d4t",CORNER_LEFT_LOWER,x4+12,by+bh-12,"KEY LEVELS",cfg.textCol,fs,true);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d4a",CORNER_LEFT_LOWER,x4+12,by+bh-40,
|
||
|
|
"PWH: "+(dd.pwh>0? DoubleToString(dd.pwh,_Digits) : "-"),cfg.accent,fs);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d4b",CORNER_LEFT_LOWER,x4+118,by+bh-40,
|
||
|
|
"PDL: "+(dd.pdl>0? DoubleToString(dd.pdl,_Digits) : "-"),cfg.accent,fs);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d4c",CORNER_LEFT_LOWER,x4+12,by+bh-62,
|
||
|
|
"PDH: "+(dd.pdh>0? DoubleToString(dd.pdh,_Digits) : "-"),cfg.accent,fs);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d4d",CORNER_LEFT_LOWER,x4+118,by+bh-62,
|
||
|
|
"PWL: "+(dd.pwl>0? DoubleToString(dd.pwl,_Digits) : "-"),cfg.accent,fs);
|
||
|
|
|
||
|
|
int x5=x4+bw+30+gap;
|
||
|
|
int bh5=bh+22;
|
||
|
|
AFR_Panel(cfg,P+"P_d5",CORNER_LEFT_LOWER,x5,by+bh5,bw,bh5);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d5t",CORNER_LEFT_LOWER,x5+12,by+bh5-12,"ALIGNMENT (N/C/E/P)",cfg.textCol,fs,true);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d5a",CORNER_LEFT_LOWER,x5+12,by+bh5-36,"Narr:",cfg.textCol,fs);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d5av",CORNER_LEFT_LOWER,x5+95,by+bh5-36,dd.nBias,
|
||
|
|
dd.nBias=="Bullish"? cfg.bull : (dd.nBias=="Bearish"? cfg.bear : clrSilver),fs);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d5b",CORNER_LEFT_LOWER,x5+12,by+bh5-58,"Cont:",cfg.textCol,fs);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d5bv",CORNER_LEFT_LOWER,x5+95,by+bh5-58,dd.cBias,
|
||
|
|
dd.cBias=="Bullish"? cfg.bull : (dd.cBias=="Bearish"? cfg.bear : clrSilver),fs);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d5c",CORNER_LEFT_LOWER,x5+12,by+bh5-80,"Entry:",cfg.textCol,fs);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d5cv",CORNER_LEFT_LOWER,x5+95,by+bh5-80,dd.eBias,
|
||
|
|
dd.eBias=="Bullish"? cfg.bull : (dd.eBias=="Bearish"? cfg.bear : clrSilver),fs);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d5d",CORNER_LEFT_LOWER,x5+12,by+bh5-102,"PA:",cfg.textCol,fs);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_d5dv",CORNER_LEFT_LOWER,x5+95,by+bh5-102,dd.pBias,
|
||
|
|
dd.pBias=="Bullish"? cfg.bull : (dd.pBias=="Bearish"? cfg.bear : clrSilver),fs);
|
||
|
|
|
||
|
|
// ---- trade setup (kanan-atas) ----
|
||
|
|
bool active=(agg.dir>0 || agg.dir<0);
|
||
|
|
int rows=active? 5 : 1;
|
||
|
|
int pw=212, px=14, py=30, sdy=21;
|
||
|
|
int ph=64+rows*sdy+8;
|
||
|
|
AFR_Panel(cfg,P+"P_sig",CORNER_RIGHT_UPPER,px,py,pw,ph);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_st",CORNER_RIGHT_UPPER,px+pw-14,py+10,"TRADE SETUP",cfg.textCol,fs,true,ANCHOR_RIGHT_UPPER);
|
||
|
|
int sy=py+38, kx=px+pw-14, vx=px+12;
|
||
|
|
AFR_PanelLabel(cfg,P+"L_s0",CORNER_RIGHT_UPPER,kx,sy,"Signal:",cfg.textCol,fs+1,true,ANCHOR_RIGHT_UPPER);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_s0v",CORNER_RIGHT_UPPER,vx,sy,sig,sc,fs+1,true,ANCHOR_RIGHT_UPPER);
|
||
|
|
sy+=sdy+6;
|
||
|
|
if(active)
|
||
|
|
{
|
||
|
|
AFR_PanelLabel(cfg,P+"SR_2k",CORNER_RIGHT_UPPER,kx,sy,"Entry:",cfg.textCol,fs,false,ANCHOR_RIGHT_UPPER);
|
||
|
|
AFR_PanelLabel(cfg,P+"SR_2v",CORNER_RIGHT_UPPER,vx,sy,DoubleToString(agg.entry,_Digits),cfg.textCol,fs,false,ANCHOR_RIGHT_UPPER); sy+=sdy;
|
||
|
|
AFR_PanelLabel(cfg,P+"SR_3k",CORNER_RIGHT_UPPER,kx,sy,"SL:",cfg.textCol,fs,false,ANCHOR_RIGHT_UPPER);
|
||
|
|
AFR_PanelLabel(cfg,P+"SR_3v",CORNER_RIGHT_UPPER,vx,sy,DoubleToString(agg.sl,_Digits),cfg.sigSL,fs,false,ANCHOR_RIGHT_UPPER); sy+=sdy;
|
||
|
|
AFR_PanelLabel(cfg,P+"SR_4k",CORNER_RIGHT_UPPER,kx,sy,"TP:",cfg.textCol,fs,false,ANCHOR_RIGHT_UPPER);
|
||
|
|
AFR_PanelLabel(cfg,P+"SR_4v",CORNER_RIGHT_UPPER,vx,sy,DoubleToString(agg.tp,_Digits),cfg.sigTP,fs,false,ANCHOR_RIGHT_UPPER); sy+=sdy;
|
||
|
|
double rr=0.0;
|
||
|
|
if(agg.dir>0 && agg.entry>agg.sl && agg.sl>0) rr=(agg.tp-agg.entry)/(agg.entry-agg.sl);
|
||
|
|
if(agg.dir<0 && agg.sl>agg.entry && agg.entry>0) rr=(agg.entry-agg.tp)/(agg.sl-agg.entry);
|
||
|
|
AFR_PanelLabel(cfg,P+"SR_5k",CORNER_RIGHT_UPPER,kx,sy,"R:R:",cfg.textCol,fs,false,ANCHOR_RIGHT_UPPER);
|
||
|
|
AFR_PanelLabel(cfg,P+"SR_5v",CORNER_RIGHT_UPPER,vx,sy,"1 : "+DoubleToString(rr,1),
|
||
|
|
rr>=2.0? cfg.bull : clrGold,fs,false,ANCHOR_RIGHT_UPPER);
|
||
|
|
}
|
||
|
|
else
|
||
|
|
{
|
||
|
|
string note=agg.reason;
|
||
|
|
if(StringLen(note)>60) note=StringSubstr(note,0,57)+"...";
|
||
|
|
AFR_PanelLabel(cfg,P+"SR_w",CORNER_RIGHT_UPPER,kx,sy,note,clrSilver,fs-1,false,ANCHOR_RIGHT_UPPER);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ---- legenda (kanan-bawah) ----
|
||
|
|
int lw=185, lh=140, lx=14, ly=14+bh+gap;
|
||
|
|
AFR_Panel(cfg,P+"P_leg",CORNER_RIGHT_LOWER,lx,ly+lh,lw,lh);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_legt",CORNER_RIGHT_LOWER,lx+lw-12,ly+lh-12,"LEGEND STATUS",cfg.textCol,fs,true,ANCHOR_RIGHT_UPPER);
|
||
|
|
string it[5]={"Structure","Order Blocks","FVG","Premium/Discount","Liquidity"};
|
||
|
|
bool on[5]={cfg.showStructure||cfg.showSwingPoints,cfg.showOB,cfg.showFVG,cfg.showPD,cfg.showLevels};
|
||
|
|
int yy=ly+lh-36;
|
||
|
|
for(int i=0;i<5;i++)
|
||
|
|
{
|
||
|
|
AFR_PanelLabel(cfg,P+"L_le"+IntegerToString(i)+"a",CORNER_RIGHT_LOWER,lx+lw-12,yy,it[i],cfg.textCol,fs,false,ANCHOR_RIGHT_UPPER);
|
||
|
|
AFR_PanelLabel(cfg,P+"L_le"+IntegerToString(i)+"b",CORNER_RIGHT_LOWER,lx+12,yy,on[i]? "On":"Off",
|
||
|
|
on[i]? cfg.bull : clrGray,fs,false,ANCHOR_RIGHT_UPPER);
|
||
|
|
yy-=22;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//------------------------------------------------------------------
|
||
|
|
// Gambar SEMUA elemen display (dipanggil konsumen per bar tertutup)
|
||
|
|
//------------------------------------------------------------------
|
||
|
|
void AFR_DrawAll(const AFRenderCfg &cfg,const AFEngine1MTF &e1,int sDisp,
|
||
|
|
const AFDisplayData &dd,const AFSignalOut &n,const AFSignalOut &c,
|
||
|
|
const AFSignalOut &e,const AFSignalOut &p,const AFAggOut &agg)
|
||
|
|
{
|
||
|
|
string P=cfg.prefix;
|
||
|
|
datetime tR=dd.dispEnd;
|
||
|
|
if(tR<=0) tR=TimeCurrent();
|
||
|
|
|
||
|
|
// ---- struktur (BOS/CHoCH) ----
|
||
|
|
if(cfg.showStructure)
|
||
|
|
{
|
||
|
|
int nL=ArraySize(dd.structLines);
|
||
|
|
for(int i=0;i<nL;i++)
|
||
|
|
{
|
||
|
|
string nm=P+"ST_"+IntegerToString(i);
|
||
|
|
color col=(dd.structLines[i].dir>0)? cfg.bull : cfg.bear;
|
||
|
|
AFR_TrendLine(nm,dd.structLines[i].t1,dd.structLines[i].price,
|
||
|
|
dd.structLines[i].t2,dd.structLines[i].price,col,2,STYLE_SOLID);
|
||
|
|
AFR_Text(nm+"_t",(datetime)((dd.structLines[i].t1+dd.structLines[i].t2)/2),
|
||
|
|
dd.structLines[i].price+20*_Point,dd.structLines[i].lbl,col,
|
||
|
|
cfg.fontSize-1,ANCHOR_LOWER);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ---- swing points (HH/HL/LH/LL) ----
|
||
|
|
if(cfg.showSwingPoints)
|
||
|
|
{
|
||
|
|
int nP=ArraySize(dd.pivots);
|
||
|
|
for(int i=0;i<nP;i++)
|
||
|
|
{
|
||
|
|
string nm=P+"SP_"+IntegerToString(i);
|
||
|
|
color col=(dd.pivots[i].tag=="HH"||dd.pivots[i].tag=="HL")? cfg.bull : cfg.bear;
|
||
|
|
double y=dd.pivots[i].isHigh? dd.pivots[i].price+28*_Point : dd.pivots[i].price-28*_Point;
|
||
|
|
AFR_Text(nm,dd.pivots[i].time,y,dd.pivots[i].tag,col,cfg.fontSize,
|
||
|
|
dd.pivots[i].isHigh? ANCHOR_LOWER : ANCHOR_UPPER);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ---- order blocks ----
|
||
|
|
if(cfg.showOB)
|
||
|
|
{
|
||
|
|
int nZ=ArraySize(dd.ob);
|
||
|
|
int nDraw=MathMin(nZ,cfg.obCount);
|
||
|
|
for(int i=0;i<nDraw;i++)
|
||
|
|
{
|
||
|
|
string nm=P+"OB_"+IntegerToString(i);
|
||
|
|
color line=dd.ob[i].bull? cfg.obLineBull : cfg.obLineBear;
|
||
|
|
color fill=dd.ob[i].bull? cfg.obFillBull : cfg.obFillBear;
|
||
|
|
AFR_Box(nm,dd.ob[i].t,dd.ob[i].top,tR,dd.ob[i].bot,fill,line,true);
|
||
|
|
AFR_Text(nm+"_t",dd.ob[i].t,(dd.ob[i].top+dd.ob[i].bot)/2.0,
|
||
|
|
(dd.ob[i].bull? "Bullish OB " : "Bearish OB ")+
|
||
|
|
AF_E2_TfName(e1.TfOf(sDisp)),line,cfg.fontSize-1,ANCHOR_LEFT);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ---- FVG ----
|
||
|
|
if(cfg.showFVG)
|
||
|
|
{
|
||
|
|
int nZ=ArraySize(dd.fvg);
|
||
|
|
int nDraw=MathMin(nZ,cfg.fvgCount);
|
||
|
|
for(int i=0;i<nDraw;i++)
|
||
|
|
{
|
||
|
|
string nm=P+"FVG_"+IntegerToString(i);
|
||
|
|
color line=dd.fvg[i].bull? cfg.fvgLineBull : cfg.fvgLineBear;
|
||
|
|
color fill=dd.fvg[i].bull? cfg.fvgFillBull : cfg.fvgFillBear;
|
||
|
|
AFR_Box(nm,dd.fvg[i].t,dd.fvg[i].top,tR,dd.fvg[i].bot,fill,line,true);
|
||
|
|
AFR_Text(nm+"_t",dd.fvg[i].t,(dd.fvg[i].top+dd.fvg[i].bot)/2.0,
|
||
|
|
(dd.fvg[i].bull? "Bullish FVG " : "Bearish FVG ")+
|
||
|
|
AF_E2_TfName(e1.TfOf(sDisp)),line,cfg.fontSize-1,ANCHOR_LEFT);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ---- premium / discount ----
|
||
|
|
if(cfg.showPD && dd.swHigh>dd.swLow)
|
||
|
|
{
|
||
|
|
double rng=dd.swHigh-dd.swLow;
|
||
|
|
double pp=AF_E3_PD_PREMIUM_PCT/100.0;
|
||
|
|
double eqh=AF_E3_PD_EQUIL_PCT/2.0/100.0;
|
||
|
|
datetime t1=dd.dispStart;
|
||
|
|
if(t1<=0) t1=(datetime)((long)tR-86400);
|
||
|
|
AFR_Box(P+"PD_PR",t1,dd.swHigh,tR,dd.swLow+(1.0-pp)*rng,cfg.premiumFill,cfg.premiumLine,true);
|
||
|
|
AFR_Box(P+"PD_EQ",t1,dd.swLow+(0.5+eqh)*rng,tR,dd.swLow+(0.5-eqh)*rng,cfg.equilFill,cfg.equilLine,true);
|
||
|
|
AFR_Box(P+"PD_DC",t1,dd.swLow+pp*rng,tR,dd.swLow,cfg.discountFill,cfg.discountLine,true);
|
||
|
|
}
|
||
|
|
|
||
|
|
// ---- level MTF (PDH/PDL/PWH/PWL) ----
|
||
|
|
if(cfg.showLevels)
|
||
|
|
{
|
||
|
|
datetime t1=dd.dispStart;
|
||
|
|
if(t1<=0) t1=(datetime)((long)tR-86400);
|
||
|
|
if(dd.pdh>0.0)
|
||
|
|
{
|
||
|
|
AFR_TrendLine(P+"LV_PDH",t1,dd.pdh,tR,dd.pdh,cfg.mtfLevel,1,STYLE_SOLID);
|
||
|
|
AFR_Text(P+"LV_PDH_t",tR,dd.pdh,"PDH "+DoubleToString(dd.pdh,_Digits),cfg.mtfLevel,cfg.fontSize-1,ANCHOR_LEFT);
|
||
|
|
}
|
||
|
|
if(dd.pdl>0.0)
|
||
|
|
{
|
||
|
|
AFR_TrendLine(P+"LV_PDL",t1,dd.pdl,tR,dd.pdl,cfg.mtfLevel,1,STYLE_SOLID);
|
||
|
|
AFR_Text(P+"LV_PDL_t",tR,dd.pdl,"PDL "+DoubleToString(dd.pdl,_Digits),cfg.mtfLevel,cfg.fontSize-1,ANCHOR_LEFT);
|
||
|
|
}
|
||
|
|
if(dd.pwh>0.0)
|
||
|
|
{
|
||
|
|
AFR_TrendLine(P+"LV_PWH",t1,dd.pwh,tR,dd.pwh,cfg.mtfLevel,1,STYLE_DASH);
|
||
|
|
AFR_Text(P+"LV_PWH_t",tR,dd.pwh,"PWH "+DoubleToString(dd.pwh,_Digits),cfg.mtfLevel,cfg.fontSize-1,ANCHOR_LEFT);
|
||
|
|
}
|
||
|
|
if(dd.pwl>0.0)
|
||
|
|
{
|
||
|
|
AFR_TrendLine(P+"LV_PWL",t1,dd.pwl,tR,dd.pwl,cfg.mtfLevel,1,STYLE_DASH);
|
||
|
|
AFR_Text(P+"LV_PWL_t",tR,dd.pwl,"PWL "+DoubleToString(dd.pwl,_Digits),cfg.mtfLevel,cfg.fontSize-1,ANCHOR_LEFT);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ---- sinyal (entry/SL/TP + panah) ----
|
||
|
|
if(cfg.showSignals)
|
||
|
|
{
|
||
|
|
datetime t1=dd.dispStart;
|
||
|
|
if(t1<=0) t1=(datetime)((long)tR-86400);
|
||
|
|
if(agg.dir>0 || agg.dir<0)
|
||
|
|
{
|
||
|
|
bool buy=(agg.dir>0);
|
||
|
|
color cE=buy? cfg.sigEntry : cfg.bear;
|
||
|
|
AFR_TrendLine(P+"SIG_E",t1,agg.entry,tR,agg.entry,cE,2,STYLE_SOLID);
|
||
|
|
AFR_Text(P+"SIG_E_t",tR,agg.entry,
|
||
|
|
(buy? "BUY @ " : "SELL @ ")+DoubleToString(agg.entry,_Digits),
|
||
|
|
cE,cfg.fontSize-1,ANCHOR_LEFT);
|
||
|
|
if(agg.sl>0.0)
|
||
|
|
{
|
||
|
|
AFR_TrendLine(P+"SIG_SL",t1,agg.sl,tR,agg.sl,cfg.sigSL,1,STYLE_DASH);
|
||
|
|
AFR_Text(P+"SIG_SL_t",tR,agg.sl,"SL "+DoubleToString(agg.sl,_Digits),cfg.sigSL,cfg.fontSize-1,ANCHOR_LEFT);
|
||
|
|
}
|
||
|
|
if(agg.tp>0.0)
|
||
|
|
{
|
||
|
|
AFR_TrendLine(P+"SIG_TP",t1,agg.tp,tR,agg.tp,cfg.sigTP,1,STYLE_DOT);
|
||
|
|
AFR_Text(P+"SIG_TP_t",tR,agg.tp,"TP "+DoubleToString(agg.tp,_Digits),cfg.sigTP,cfg.fontSize-1,ANCHOR_LEFT);
|
||
|
|
}
|
||
|
|
datetime tSig=(e1.IsReady(sDisp))? e1.Time(sDisp,0) : tR;
|
||
|
|
string nm=P+"SIG_AR";
|
||
|
|
if(ObjectFind(0,nm)<0) ObjectCreate(0,nm,OBJ_ARROW,0,tSig,agg.entry);
|
||
|
|
else ObjectMove(0,nm,0,tSig,agg.entry);
|
||
|
|
ObjectSetInteger(0,nm,OBJPROP_ARROWCODE,buy? 233 : 234);
|
||
|
|
ObjectSetInteger(0,nm,OBJPROP_COLOR,cE);
|
||
|
|
ObjectSetInteger(0,nm,OBJPROP_WIDTH,2);
|
||
|
|
ObjectSetInteger(0,nm,OBJPROP_ANCHOR,buy? ANCHOR_TOP : ANCHOR_BOTTOM);
|
||
|
|
ObjectSetInteger(0,nm,OBJPROP_SELECTABLE,false);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// ---- dashboard ----
|
||
|
|
if(cfg.showDashboard) AFR_DrawDashboard(cfg,dd,agg);
|
||
|
|
}
|
||
|
|
|
||
|
|
//------------------------------------------------------------------
|
||
|
|
// Bersihkan semua objek Engine 3 dari chart
|
||
|
|
//------------------------------------------------------------------
|
||
|
|
void AFR_Clear(const AFRenderCfg &cfg)
|
||
|
|
{
|
||
|
|
ObjectsDeleteAll(0,cfg.prefix);
|
||
|
|
}
|
||
|
|
|
||
|
|
#endif // AF_ENGINE3_RENDER_MQH
|