risk-position-tool/mql5/Include/RiskManager/RiskBox.mqh
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
//+------------------------------------------------------------------+