//+------------------------------------------------------------------+ //| CkRiskBox.mqh | //| Copyright 2026, Allan NiƱal | //| https://www.allanninal.dev/mql5 | //+------------------------------------------------------------------+ //| Chart kit risk/reward box: a loss zone (entry to stop) and a | //| profit zone (entry to target) behind the candles, and one tag | //| per line at the box's right end ("SL 1.08210 -50.00 USD 1R"). | //| The product's lines stay the source of truth: the box is redrawn | //| from their prices and never moves them. Draw only; it sends no | //| order and needs no trade permission. | //+------------------------------------------------------------------+ #ifndef CK_RISKBOX_MQH #define CK_RISKBOX_MQH #include "CkTheme.mqh" #include "CkObj.mqh" struct CkBoxSpec { double entry,sl,tp; // tp 0 = no target string tag_entry,tag_sl,tag_tp; // the line tags ("" = none) string tip_sl,tip_tp; // zone tooltips int bars_back,bars_ahead; // box width around the current bar }; void CkBoxDefaults(CkBoxSpec &b) { b.entry=0; b.sl=0; b.tp=0; b.tag_entry=""; b.tag_sl=""; b.tag_tp=""; b.tip_sl=""; b.tip_tp=""; b.bars_back=24; b.bars_ahead=10; } //--- bars visible to the right of the current bar: the chart-shift area (0 with chart shift off) int CkBarsAhead(void) { if(!ChartGetInteger(0,CHART_SHIFT)) return(0); double shift=ChartGetDouble(0,CHART_SHIFT_SIZE); // % of the chart width long wb=ChartGetInteger(0,CHART_WIDTH_IN_BARS); return((int)MathMax(0,MathFloor(wb*shift/100.0)-1)); } //--- the box's time span: from `bars_back` bars before the current bar to `bars_ahead` bars after it, cut to what the //--- chart shows to the right, so the tags at the right end stay on screen void CkBoxTimes(const CkBoxSpec &b,datetime &t1,datetime &t2) { int sec=PeriodSeconds(_Period); datetime t0=iTime(_Symbol,_Period,0); if(t0==0) t0=TimeCurrent(); t1=t0-(datetime)(b.bars_back*sec); t2=t0+(datetime)(MathMin(b.bars_ahead,CkBarsAhead())*sec); } void CkRiskBoxDelete(const string pfx) { CkDeleteAll(pfx); } void CkRiskBoxDraw(const string pfx,const CkTheme &th,const CkBoxSpec &b) { if(!CkCanDraw()) return; if(b.entry<=0 || b.sl<=0 || b.entry==b.sl) { CkRiskBoxDelete(pfx); return; } datetime t1,t2; CkBoxTimes(b,t1,t2); bool buy=b.sl0) CkRect(pfx+"gain",t1,b.entry,t2,b.tp,th.zone_pos,b.tip_tp); else CkDelete(pfx+"gain"); //--- the stop and target tags sit on the outer side of their lines, the entry tag inside the loss zone: no overlap if(b.tag_entry!="") CkText(pfx+"t_en",t2,b.entry,b.tag_entry,th.acc,buy ? ANCHOR_RIGHT_UPPER : ANCHOR_RIGHT_LOWER); else CkDelete(pfx+"t_en"); if(b.tag_sl!="") CkText(pfx+"t_sl",t2,b.sl,b.tag_sl,th.neg,buy ? ANCHOR_RIGHT_UPPER : ANCHOR_RIGHT_LOWER); else CkDelete(pfx+"t_sl"); if(b.tp>0 && b.tag_tp!="") CkText(pfx+"t_tp",t2,b.tp,b.tag_tp,th.pos,buy ? ANCHOR_RIGHT_LOWER : ANCHOR_RIGHT_UPPER); else CkDelete(pfx+"t_tp"); } #endif //+------------------------------------------------------------------+