For a native MQL5 environment, the object property handling is stricter than MQL4, particularly regarding how background fills are rendered and how object coordinate indexes (anchor points) are assigned.
This version is written strictly for .mq5. It utilizes MQL5’s OBJPROP_FILL to properly shade the risk/reward zones and maps the time/price coordinates using precise anchor indexing (0 and 1).
Code: Select all
//+------------------------------------------------------------------+
//| TradePlanVisualizer.mq5 |
//| Zero P&L Mindset Tracker |
//+------------------------------------------------------------------+
#property copyright "Zero P&L"
#property indicator_chart_window
#property indicator_plots 0
//--- Input parameters
input color InpEntryColor = clrGray; // Entry Line Color
input color InpSLColor = clrRed; // Stop Loss Line Color
input color InpTPColor = clrLimeGreen; // Take Profit Line Color
input color InpRiskColor = clrCrimson; // Risk Zone Color
input color InpRewardColor = clrMediumSeaGreen;// Reward Zone Color
//--- Global variables
string prefix = "ZeroPnL_";
string lineEntry = prefix + "Entry";
string lineSL = prefix + "SL";
string lineTP = prefix + "TP";
string boxRisk = prefix + "RiskBox";
string boxReward = prefix + "RewardBox";
string lblStats = prefix + "Stats";
string lblStatus = prefix + "Status";
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double point = SymbolInfoDouble(_Symbol, SYMBOL_POINT);
// Default separation of 200 points to make the lines visible on load
CreateHLine(lineTP, ask + 200 * point, InpTPColor);
CreateHLine(lineEntry, ask, InpEntryColor);
CreateHLine(lineSL, ask - 200 * point, InpSLColor);
CreateRectangle(boxRisk, InpRiskColor);
CreateRectangle(boxReward, InpRewardColor);
CreateLabel(lblStats, 10, 40, clrWhite, 12);
CreateLabel(lblStatus, 10, 20, clrYellow, 10);
UpdateVisuals();
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ObjectsDeleteAll(0, prefix);
ChartRedraw(0);
}
//+------------------------------------------------------------------+
//| ChartEvent function |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
// Recalculate and redraw the zones if any line is dragged by the user
if(id == CHARTEVENT_OBJECT_DRAG)
{
if(sparam == lineEntry || sparam == lineSL || sparam == lineTP)
{
UpdateVisuals();
ChartRedraw(0);
}
}
}
//+------------------------------------------------------------------+
//| Custom indicator iteration function |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
const int prev_calculated,
const datetime &time[],
const double &open[],
const double &high[],
const double &low[],
const double &close[],
const long &tick_volume[],
const long &volume[],
const int &spread[])
{
// Keeps the visual rectangles stretched to the far right as live ticks come in
UpdateVisuals();
return(rates_total);
}
//+------------------------------------------------------------------+
//| Helper Functions |
//+------------------------------------------------------------------+
void CreateHLine(string name, double price, color clr)
{
if(ObjectFind(0, name) < 0)
{
ObjectCreate(0, name, OBJ_HLINE, 0, 0, price);
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
ObjectSetInteger(0, name, OBJPROP_STYLE, STYLE_SOLID);
ObjectSetInteger(0, name, OBJPROP_WIDTH, 2);
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, true);
ObjectSetInteger(0, name, OBJPROP_SELECTED, false);
ObjectSetInteger(0, name, OBJPROP_HIDDEN, false);
}
}
void CreateRectangle(string name, color clr)
{
if(ObjectFind(0, name) < 0)
{
ObjectCreate(0, name, OBJ_RECTANGLE, 0, 0, 0, 0, 0);
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
ObjectSetInteger(0, name, OBJPROP_BACK, true); // Render behind candles
ObjectSetInteger(0, name, OBJPROP_FILL, true); // Required in MQL5 for solid coloring
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
}
}
void CreateLabel(string name, int x, int y, color clr, int fontSize)
{
if(ObjectFind(0, name) < 0)
{
ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0);
ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_RIGHT_LOWER);
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
ObjectSetInteger(0, name, OBJPROP_COLOR, clr);
ObjectSetString(0, name, OBJPROP_FONT, "Arial");
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, fontSize);
ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false);
ObjectSetInteger(0, name, OBJPROP_HIDDEN, true);
}
}
void UpdateVisuals()
{
// MQL5 requires property modifiers (0) to access the specific anchor point prices
double entry = ObjectGetDouble(0, lineEntry, OBJPROP_PRICE, 0);
double sl = ObjectGetDouble(0, lineSL, OBJPROP_PRICE, 0);
double tp = ObjectGetDouble(0, lineTP, OBJPROP_PRICE, 0);
double risk = MathAbs(entry - sl);
double reward = MathAbs(tp - entry);
double rrRatio = (risk > 0) ? (reward / risk) : 0;
// Stretch rectangles across the timeline
datetime t1 = 0;
// Extend right side into the future using the current chart's period in seconds
datetime t2 = TimeCurrent() + (PeriodSeconds(_Period) * 100);
// Risk Box Mapping (Anchor 0 and Anchor 1)
ObjectSetDouble(0, boxRisk, OBJPROP_PRICE, 0, entry);
ObjectSetInteger(0, boxRisk, OBJPROP_TIME, 0, t1);
ObjectSetDouble(0, boxRisk, OBJPROP_PRICE, 1, sl);
ObjectSetInteger(0, boxRisk, OBJPROP_TIME, 1, t2);
// Reward Box Mapping (Anchor 0 and Anchor 1)
ObjectSetDouble(0, boxReward, OBJPROP_PRICE, 0, entry);
ObjectSetInteger(0, boxReward, OBJPROP_TIME, 0, t1);
ObjectSetDouble(0, boxReward, OBJPROP_PRICE, 1, tp);
ObjectSetInteger(0, boxReward, OBJPROP_TIME, 1, t2);
// Text Updates
string rrText = "Risk : Reward = 1 : " + DoubleToString(rrRatio, 2);
ObjectSetString(0, lblStats, OBJPROP_TEXT, rrText);
ObjectSetString(0, lblStatus, OBJPROP_TEXT, "Trade The Chart");
}
//+------------------------------------------------------------------+