2026-10-21 16:07:46 +08:00 | | | //+------------------------------------------------------------------+
|
| | | //| RiskPositionTool.mq5 |
|
| | | //| Copyright 2026, Allan Niñal |
|
| | | //| https://www.allanninal.dev/mql5 |
|
| | | //+------------------------------------------------------------------+
|
| | | //| Free indicator: a position tool. Drag the entry, stop-loss and |
|
| | | //| take-profit lines; the panel shows the lot for your risk, the |
|
| | | //| money at the stop and at the target, the reward:risk ratio and |
|
| | | //| the margin. It never places or changes an order. |
|
| | | //| Shared code: Include/RiskManager/RiskCore.mqh, Panel.mqh. |
|
| | | //+------------------------------------------------------------------+
|
| | | // SPDX-License-Identifier: LicenseRef-PolyForm-Noncommercial-1.0.0 (see LICENSE)
|
| | | #property copyright "Copyright 2026, Allan Niñal <https://www.allanninal.dev/mql5>"
|
| | | #property link "https://www.allanninal.dev/mql5"
|
2026-10-31 14:29:00 +08:00 | | | #property version "1.2"
|
2026-10-21 16:07:46 +08:00 | | | #property description "Position size calculator on the chart: drag entry, stop and target lines; lot for your risk %, money at risk, reward:risk."
|
2026-10-31 14:29:00 +08:00 | | | #property description "Draws the plan as a risk/reward box with money and R on each line; colour-blind friendly option."
|
2026-10-21 16:07:46 +08:00 | | | #property description "Calculates only: it never places or changes an order."
|
| | | #property indicator_chart_window
|
| | | #property indicator_buffers 0
|
| | | #property indicator_plots 0
|
| | |
|
2026-10-31 14:29:00 +08:00 | | | #include <RiskManager/RiskBox.mqh>
|
2026-10-21 16:07:46 +08:00 | | |
|
| | | input group "Risk"
|
| | | input ENUM_RTM_RISK InpRiskMode = RTM_RISK_PCT_BAL; // Risk measured as
|
| | | input double InpRisk = 1.0; // Risk per trade (% or money)
|
| | | input group "Lines when placed"
|
| | | input double InpStopATR = 1.5; // Stop distance, x ATR(14)
|
| | | input double InpRR = 2.0; // Target, x the stop distance
|
2026-10-31 14:29:00 +08:00 | | | input color InpColEntry = clrNONE; // Entry line (None = theme colour)
|
| | | input color InpColSL = clrNONE; // Stop-loss line (None = theme colour)
|
| | | input color InpColTP = clrNONE; // Take-profit line (None = theme colour)
|
2026-10-21 16:07:46 +08:00 | | | input group "Display"
|
2026-10-31 14:29:00 +08:00 | | | input bool InpBox = true; // Risk/reward box on the chart
|
| | | input ENUM_CK_THEME InpTheme = CK_THEME_AUTO; // Colours
|
| | | input bool InpColourBlind = false; // Colour-blind friendly (blue/orange)
|
| | | input ENUM_PRG_CORNER InpCorner = PRG_RIGHT; // Panel position
|
2026-10-21 16:07:46 +08:00 | | | input int InpOffsetX = 10; // Panel margin from the side, px
|
| | | input int InpOffsetY = 26; // Panel margin from the top, px
|
| | | input int InpFontSize = 9; // Panel font size
|
2026-10-31 14:29:00 +08:00 | | | input group "Support"
|
| | | input bool InpDebug = false; // Debug log for bug reports (Experts tab)
|
2026-10-21 16:07:46 +08:00 | | |
|
| | | int g_panel_h=200;
|
| | |
|
2026-10-31 14:29:00 +08:00 | | | color ColEntry(void) { return(RTMColour(InpColEntry,g_th.acc)); }
|
| | | color ColSL(void) { return(RTMColour(InpColSL,g_th.neg)); }
|
| | | color ColTP(void) { return(RTMColour(InpColTP,g_th.pos)); }
|
| | |
|
2026-10-21 16:07:46 +08:00 | | | void Draw(void)
|
| | | {
|
2026-10-31 14:29:00 +08:00 | | | RTMTheme(InpTheme,InpColourBlind);
|
| | | RTMLineColours(ColEntry(),ColSL(),ColTP());
|
2026-10-21 16:07:46 +08:00 | | | RTMCalc c;
|
| | | RTMCompute(c,InpRiskMode,InpRisk);
|
| | | g_cursor=0;
|
| | | Box("bg",0,0,UI_W,g_panel_h+UI_PAD,UiBack(),UiRule());
|
| | | Box("hd",0,0,UI_W,UI_HEAD-4,g_ui_light ? C'240,241,244' : C'32,35,40',UiRule());
|
| | | Text("title",UI_PAD,5,"Risk Position Tool",UiText(),g_ui_font+1,"Segoe UI Semibold");
|
| | | int y=RTMDrawSetup(c,UI_HEAD,InpRiskMode,InpRisk);
|
| | | Button("b_buy",UI_PAD+0,y+6,70,"BUY");
|
| | | Button("b_sell",UI_PAD+78,y+6,70,"SELL");
|
| | | Button("b_mkt",UI_PAD+156,y+6,70,g_entry_market ? "MARKET" : "PENDING");
|
| | | Button("b_del",UI_PAD+234,y+6,64,"CLEAR");
|
| | | y+=30;
|
| | | if(y!=g_panel_h)
|
| | | {
|
| | | g_panel_h=y;
|
| | | CacheClear();
|
| | | Draw();
|
| | | return;
|
| | | }
|
2026-10-31 14:29:00 +08:00 | | | RTMDrawBox(c,InpBox);
|
| | | if(g_panel_dirty || g_ck_dirty)
|
2026-10-21 16:07:46 +08:00 | | | {
|
| | | ChartRedraw();
|
| | | g_panel_dirty=false;
|
2026-10-31 14:29:00 +08:00 | | | g_ck_dirty=false;
|
2026-10-21 16:07:46 +08:00 | | | }
|
| | | }
|
| | |
|
| | | int OnInit()
|
| | | {
|
| | | if(InpRisk<=0 || InpStopATR<=0 || InpRR<0)
|
| | | {
|
| | | Print("Risk Position Tool: risk and stop distance must be above 0");
|
| | | return(INIT_PARAMETERS_INCORRECT);
|
| | | }
|
| | | g_ui_corner=InpCorner;
|
| | | g_ui_x=InpOffsetX;
|
| | | g_ui_y=InpOffsetY;
|
| | | g_ui_font=MathMax(7,MathMin(14,InpFontSize));
|
| | | g_entry_market=(ObjectFind(0,L_ENTRY)<0); // lines kept from an earlier run stay where they were dragged
|
2026-10-31 14:29:00 +08:00 | | | CkDebugStart("Risk Position Tool","1.2",InpDebug,StringFormat("risk mode %d %.2f, stop %.2f ATR, target %.2f, box %d, theme %d, colour-blind %d, lines kept %d",
|
| | | InpRiskMode,InpRisk,InpStopATR,InpRR,InpBox,InpTheme,InpColourBlind,!g_entry_market));
|
2026-10-21 16:07:46 +08:00 | | | EventSetMillisecondTimer(300);
|
| | | Draw();
|
| | | return(INIT_SUCCEEDED);
|
| | | }
|
| | |
|
| | | void OnDeinit(const int reason)
|
| | | {
|
| | | EventKillTimer();
|
| | | PanelDelete();
|
2026-10-31 14:29:00 +08:00 | | | CkRiskBoxDelete(RTM_BOX);
|
2026-10-21 16:07:46 +08:00 | | | if(reason==REASON_REMOVE) // keep the lines over a timeframe change, remove them with the tool
|
| | | RTMDeleteLines();
|
| | | ChartRedraw();
|
| | | }
|
| | |
|
| | | void OnTimer()
|
| | | {
|
| | | RTMFollowMarket();
|
| | | Draw();
|
| | | }
|
| | |
|
| | | void OnChartEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
|
| | | {
|
| | | if(id==CHARTEVENT_OBJECT_DRAG && sparam==L_ENTRY)
|
| | | g_entry_market=false;
|
2026-10-31 14:29:00 +08:00 | | | if(id==CHARTEVENT_OBJECT_DRAG && (sparam==L_ENTRY || sparam==L_SL || sparam==L_TP))
|
| | | CkDbg("drag "+sparam+" to "+DoubleToString(ObjectGetDouble(0,sparam,OBJPROP_PRICE),_Digits));
|
| | | if(id==CHARTEVENT_OBJECT_CLICK && StringFind(sparam,PRG_PREFIX+"b_")==0)
|
| | | CkDbg("button "+StringSubstr(sparam,StringLen(PRG_PREFIX)));
|
2026-10-21 16:07:46 +08:00 | | | if(id==CHARTEVENT_OBJECT_CLICK)
|
| | | {
|
2026-10-31 14:29:00 +08:00 | | | if(sparam==PRG_PREFIX+"b_buy" || sparam==PRG_PREFIX+"b_sell")
|
| | | RTMResetLines(sparam==PRG_PREFIX+"b_buy",InpStopATR,InpRR,ColEntry(),ColSL(),ColTP());
|
2026-10-21 16:07:46 +08:00 | | | else
|
2026-10-31 14:29:00 +08:00 | | | if(sparam==PRG_PREFIX+"b_mkt")
|
2026-10-21 16:07:46 +08:00 | | | g_entry_market=!g_entry_market;
|
| | | else
|
2026-10-31 14:29:00 +08:00 | | | if(sparam==PRG_PREFIX+"b_del")
|
2026-10-21 16:07:46 +08:00 | | | RTMDeleteLines();
|
| | | }
|
| | | if(id==CHARTEVENT_OBJECT_DRAG || id==CHARTEVENT_OBJECT_CLICK)
|
| | | {
|
| | | CacheClear();
|
| | | Draw();
|
| | | }
|
| | | }
|
| | |
|
| | | int OnCalculate(const int rates_total,const int prev_calculated,const int begin,const double &price[])
|
| | | {
|
| | | return(rates_total);
|
| | | }
|
| | | //+------------------------------------------------------------------+
|