//+------------------------------------------------------------------+ //| RiskBox.mqh | //| Copyright 2026, Allan NiƱal | //| https://www.allanninal.dev/mql5 | //+------------------------------------------------------------------+ //| 1.2: the lines drawn as a risk/reward box (Chart Kit): loss and | //| profit zones behind the candles, a tag on each line with its | //| price, money and R, live tooltips, theme colours (auto light or | //| dark from the chart, colour-blind friendly switch). The lines | //| stay the source of truth; the box only shows what they say. | //+------------------------------------------------------------------+ // SPDX-License-Identifier: LicenseRef-PolyForm-Noncommercial-1.0.0 (see LICENSE) #ifndef RTM_BOX_MQH #define RTM_BOX_MQH #include "RiskView.mqh" #include "../ChartKit/CkRiskBox.mqh" #include "../ChartKit/CkDebug.mqh" #define RTM_BOX "RTB_" // box objects (own prefix: the panel and the lines have theirs) CkTheme g_th; //--- theme tokens for the box, the lines and the panel void RTMTheme(const ENUM_CK_THEME mode,const bool cb) { CkThemeLoad(g_th,mode,cb); g_ui_light=g_th.light; g_ui_cb=cb; } //--- an input colour, or the theme's when the input is None color RTMColour(const color in,const color token) { return(in==clrNONE ? token : in); } //--- recolour lines that already exist (theme or chart background changed) void RTMLineColours(const color ce,const color cs,const color ct) { if(!CkCanDraw()) return; if(ObjectFind(0,L_ENTRY)>=0) CkSetI(L_ENTRY,OBJPROP_COLOR,ce); if(ObjectFind(0,L_SL)>=0) CkSetI(L_SL,OBJPROP_COLOR,cs); if(ObjectFind(0,L_TP)>=0) CkSetI(L_TP,OBJPROP_COLOR,ct); } string RTMKind(const RTMCalc &c) { if(g_entry_market) return("at market"); return((c.buy ? c.entrySymbolInfoDouble(_Symbol,SYMBOL_BID)) ? "limit" : "stop"); } //--- debug: one line when the plan's result changes (not every timer tick) string g_dbg_plan=""; void RTMDebugPlan(const RTMCalc &c) { if(!g_ck_dbg) return; //--- no money amounts: with risk in % they would give away the balance, and users paste these lines in public string k=(c.entry<=0 ? "no lines" : StringFormat("%s entry %s sl %s tp %s, %s, stop %.0f pts, lot %s (raw %.4f), loss per lot %.2f, risk %.2f%% of balance%s", c.buy ? "BUY" : "SELL",DoubleToString(c.entry,_Digits),DoubleToString(c.sl,_Digits),DoubleToString(c.tp,_Digits),RTMKind(c), c.stop_pts,DoubleToString(c.lots,RTMLotDigits()),c.lots_raw,c.loss_per_lot,c.real_risk_pct,c.why!="" ? ", note: "+c.why : "")); if(k==g_dbg_plan) return; g_dbg_plan=k; CkDbg("plan "+k); } void RTMDrawBox(const RTMCalc &c,const bool show) { RTMDebugPlan(c); if(!CkCanDraw()) return; if(!show || c.entry<=0 || c.sl<=0 || c.entry==c.sl) { CkRiskBoxDelete(RTM_BOX); return; } string cur=" "+AccountInfoString(ACCOUNT_CURRENCY); string lot=(c.lots>0 ? DoubleToString(c.lots,RTMLotDigits())+" lot" : "no lot"); CkBoxSpec b; CkBoxDefaults(b); b.entry=c.entry; b.sl=c.sl; b.tp=c.tp; b.tag_entry=(c.buy ? "BUY " : "SELL ")+lot+" "+RTMKind(c); b.tag_sl="SL "+DoubleToString(c.sl,_Digits)+(c.lots>0 ? " -"+Money(c.real_risk)+cur+" "+Pct(c.real_risk_pct,2) : StringFormat(" %.0f pts",c.stop_pts)); b.tag_tp=(c.tp>0 ? "TP "+DoubleToString(c.tp,_Digits)+(c.lots>0 ? " +"+Money(c.reward)+cur : "") +(c.rr>0 ? " "+DoubleToString(c.rr,1)+"R" : "") : ""); b.tip_sl=StringFormat("Loss zone: entry to stop, %.0f points",c.stop_pts)+(c.lots>0 ? ", -"+Money(c.real_risk)+cur+" at "+lot : ""); b.tip_tp=(c.tp>0 ? StringFormat("Profit zone: entry to target, %.0f points",c.target_pts)+(c.lots>0 ? ", +"+Money(c.reward)+cur : "") : ""); CkRiskBoxDraw(RTM_BOX,g_th,b); //--- the lines' own tooltips carry the same numbers while hovering if(ObjectFind(0,L_SL)>=0) CkSetS(L_SL,OBJPROP_TOOLTIP,b.tag_sl+"\nDrag the line to move the stop"); if(ObjectFind(0,L_TP)>=0) CkSetS(L_TP,OBJPROP_TOOLTIP,(b.tag_tp!="" ? b.tag_tp : "Take profit")+"\nDrag the line to move the target"); if(ObjectFind(0,L_ENTRY)>=0) CkSetS(L_ENTRY,OBJPROP_TOOLTIP,b.tag_entry+"\nDrag the line for a pending order price"); } #endif //+------------------------------------------------------------------+