101 lines
4.5 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| 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.entry<SymbolInfoDouble(_Symbol,SYMBOL_ASK) : c.entry>SymbolInfoDouble(_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
| |||
//+------------------------------------------------------------------+
|